feat(invariants): add package-owned service seam

This commit is contained in:
Tianyi Cui
2026-07-19 19:19:57 +08:00
parent 38b7275eb1
commit 9d310ecc27
83 changed files with 2225 additions and 1557 deletions

View File

@@ -15,8 +15,19 @@ import type {
PackageScriptResource,
} from '../resources.ts'
/** Return the installable package name for a bare package or package subpath. */
function installablePackageName(specifier: string): string {
const segments = specifier.split('/')
const expectedSegments = specifier.startsWith('@') ? 2 : 1
if (segments.length < expectedSegments || segments.slice(0, expectedSegments).some(segment => segment.length === 0)) {
throw new Error(`invalid bare package specifier: ${JSON.stringify(specifier)}`)
}
return segments.slice(0, expectedSegments).join('/')
}
/** Create a runtime NPM dependency resource. */
function npmDependency(_owner: string, name: string): NpmDependencyResource {
function npmDependency(_owner: string, specifier: string): NpmDependencyResource {
const name = installablePackageName(specifier)
return {
kind: 'npm-dependency',
key: resourceKey(`npm-dependency:${name}`),
@@ -52,7 +63,7 @@ export function cordisConfigEntry(
}
}
/** Couple one bare-package Cordis config entry to its mandatory runtime NPM dependency. */
/** Couple one bare-package or subpath Cordis entry to its installable NPM package. */
export function npmCordisConfigEntry(
owner: string,
value: CordisConfigEntry,

View File

@@ -9,7 +9,7 @@ import type { ProjectProfile } from '../../project/types.ts'
import { loadHelperTemplate } from '../../templates/template-assets.ts'
import { FeatureOption, FixedFeature } from '../feature.ts'
import { ProjectContribution } from '../resources.ts'
import { npmCordisConfigEntry, requiredString } from './helpers.ts'
import { cordisConfigEntry, npmCordisConfigEntry, requiredString } from './helpers.ts'
const ID = featureId('spine')
const PERSONA = loadHelperTemplate<Record<string, never>>('persona.txt.tpl').render({}).trimEnd()
@@ -37,6 +37,10 @@ class SpineOption extends FeatureOption {
...npmCordisConfigEntry(ID, { id: 'tools', name: '@deepseek-ai/dsh-tools' }, []),
...npmCordisConfigEntry(ID, { id: 'agent', name: '@deepseek-ai/dsh-agent' }),
...npmCordisConfigEntry(ID, { id: 'invariants', name: '@deepseek-ai/dsh-invariants' }),
cordisConfigEntry(ID, { id: 'session-invariant', name: '@deepseek-ai/dsh-session/invariant' }),
cordisConfigEntry(ID, { id: 'agent-invariant', name: '@deepseek-ai/dsh-agent/invariant' }),
...npmCordisConfigEntry(ID, { id: 'scope-invariant', name: '@deepseek-ai/dsh-scope/invariant' }),
cordisConfigEntry(ID, { id: 'agent-loop-invariant', name: '@deepseek-ai/dsh-agent-loop/invariant' }),
...npmCordisConfigEntry(ID, {
id: 'agent-loop',
name: '@deepseek-ai/dsh-agent-loop',

View File

@@ -188,9 +188,15 @@ describe('SdkProject and ProjectEditSession', () => {
.toContain('sessionId: !!js process.env.DSH_SDK_SESSION_ID')
expect(project.cordis.entry('stdio')?.config).not.toHaveProperty('model')
expect(project.cordis.entry('agent-loop')?.config).toEqual({ agents: [] })
expect(project.cordis.entry('session-invariant')?.name).toBe('@deepseek-ai/dsh-session/invariant')
expect(project.cordis.entry('agent-invariant')?.name).toBe('@deepseek-ai/dsh-agent/invariant')
expect(project.cordis.entry('scope-invariant')?.name).toBe('@deepseek-ai/dsh-scope/invariant')
expect(project.cordis.entry('agent-loop-invariant')?.name).toBe('@deepseek-ai/dsh-agent-loop/invariant')
expect(project.cordis.entry('system-prompt')?.config?.persona).toContain('{{cwd}}')
expect(project.packageManifest().dependencies?.['@cordisjs/plugin-timer']).toBe('^1.1.2')
expect(project.packageManifest().dependencies?.['@cordisjs/plugin-hmr']).toBe('^1.0.15')
expect(project.packageManifest().dependencies?.['@deepseek-ai/dsh-scope']).toBe('^0.0.1')
expect(project.packageManifest().dependencies).not.toHaveProperty('@deepseek-ai/dsh-scope/invariant')
expect(project.packageManifest().dependencies).not.toHaveProperty('node-addon-require-builtin')
expect(project.cordis.entry('hmr')).toMatchObject({ name: '@cordisjs/plugin-hmr' })
expect(project.cordis.entry('llm-deepseek')?.config).not.toHaveProperty('baseURL')
@@ -865,6 +871,11 @@ describe('extension points', () => {
expect(stringArray({ value: [1] }, 'value')).toHaveLength(1)
expect(cordisConfigEntry('owner', { id: 'entry', name: 'pkg' }).ownedConfigKeys).toEqual([])
expect(npmCordisConfigEntry('owner', { id: 'entry', name: 'pkg' })[1].ownedConfigKeys).toEqual([])
expect(npmCordisConfigEntry('owner', { id: 'entry', name: '@scope/pkg/subpath' })[0].name).toBe('@scope/pkg')
expect(npmCordisConfigEntry('owner', { id: 'entry', name: 'pkg/subpath' })[0].name).toBe('pkg')
for (const invalid of ['', '@scope', '@scope/']) {
expect(() => npmCordisConfigEntry('owner', { id: 'entry', name: invalid })).toThrow('invalid bare package specifier')
}
expect(environmentResource('owner', 'EMPTY', undefined)).not.toHaveProperty('value')
const builtins = createBuiltinRegistry(profile)
expect(builtins.get(featureId('app')).defaultOptions(profile)).toEqual(['embed'])