+
{renderSlot('tool.view.cordis', {
pluginId: card.pluginId,
packageId: card.packageId,
pluginRunId: card.pluginRunId,
}, {
- entryKey: key ?? undefined,
+ entryKey: key,
fallback: card.output === null ? null :
{card.output},
})}
diff --git a/packages/extensions/ui-cordis/src/client/card-model.ts b/packages/extensions/ui-cordis/src/client/card-model.ts
index 1974b457a1..535deca66b 100644
--- a/packages/extensions/ui-cordis/src/client/card-model.ts
+++ b/packages/extensions/ui-cordis/src/client/card-model.ts
@@ -79,7 +79,11 @@ function metaObject(block: Block): Record
| null {
return block.meta as Record
}
-/** Derive one Define card from its frozen call/result slice. */
+/**
+ * Derive one Define card from its frozen call/result slice.
+ * @param block - active or settled tool-call block.
+ * @returns normalized Define card fields.
+ */
export function cordisDefineCard(block: Block): CordisDefineCard {
const settled = 'kind' in block
const argsRaw = (settled ? block.call?.argsRaw : block.argsRaw) ?? ''
@@ -102,7 +106,11 @@ export function cordisDefineCard(block: Block): CordisDefineCard {
}
}
-/** Derive one Run card and its successful activation metadata. */
+/**
+ * Derive one Run card and its successful activation metadata.
+ * @param block - active or settled tool-call block.
+ * @returns normalized Run card fields.
+ */
export function cordisRunCard(block: Block): CordisRunCard {
const settled = 'kind' in block
const argsRaw = (settled ? block.call?.argsRaw : block.argsRaw) ?? ''
diff --git a/packages/extensions/ui-cordis/src/client/index.ts b/packages/extensions/ui-cordis/src/client/index.ts
index dde77d08cd..719c804b2c 100644
--- a/packages/extensions/ui-cordis/src/client/index.ts
+++ b/packages/extensions/ui-cordis/src/client/index.ts
@@ -126,7 +126,7 @@ export function apply(ctx: ClientContext): void {
const store = runCards.forSession(sessionId)
return {
hooks: { inventory, loaded, runCards: store, activeRuns: runner.activeRuns },
- onObserveRunCard: pointer => { store.observe(pointer) },
+ onObserveRunCard: (pointer) => { store.observe(pointer) },
}
},
}, CordisRunRow))
@@ -139,7 +139,7 @@ export function apply(ctx: ClientContext): void {
order: 1,
candidates(session, { query }) {
const rows = rowsOf(session.sessionId, query)
- return Promise.resolve(rows.map(row => {
+ return Promise.resolve(rows.map((row) => {
const packageId = row.nextPackageId ?? row.currentPackageId ?? row.packages.at(-1)?.packageId
const pkg = packageId === undefined ? undefined : row.packages.find(candidate => candidate.packageId === packageId)
return {
diff --git a/packages/extensions/ui-cordis/src/client/locales.ts b/packages/extensions/ui-cordis/src/client/locales.ts
index 9c3fb2d8b2..e16526b50f 100644
--- a/packages/extensions/ui-cordis/src/client/locales.ts
+++ b/packages/extensions/ui-cordis/src/client/locales.ts
@@ -2,6 +2,7 @@
export const NS = 'cordis'
+/** Simplified Chinese Cordis UI messages. */
export const zh = {
'row.defineTitle': '注册 Cordis 插件',
'row.runTitle': '运行 Cordis 插件',
@@ -52,6 +53,7 @@ export const zh = {
'body.copied': '已复制',
} satisfies Record
+/** Translation keys owned by the Cordis UI namespace. */
export type CordisKey = keyof typeof zh
declare module '@deepseek-ai/dsh-client-ui-slots' {
@@ -61,6 +63,7 @@ declare module '@deepseek-ai/dsh-client-ui-slots' {
}
}
+/** English Cordis UI messages. */
export const en = {
'row.defineTitle': 'Define Cordis Plugin',
'row.runTitle': 'Run Cordis Plugin',
diff --git a/packages/extensions/ui-cordis/src/client/run-card-index.ts b/packages/extensions/ui-cordis/src/client/run-card-index.ts
index abca572a30..995d81b29b 100644
--- a/packages/extensions/ui-cordis/src/client/run-card-index.ts
+++ b/packages/extensions/ui-cordis/src/client/run-card-index.ts
@@ -47,7 +47,11 @@ function createStore(): CordisRunCardStore {
export class CordisRunCardRegistry {
private readonly sessions = new Map()
- /** Return the persistent page-local Store for a session. */
+ /**
+ * Return the persistent page-local Store for a session.
+ * @param sessionId - session whose cards share supersession state.
+ * @returns the page-local Store retained for that session.
+ */
forSession(sessionId: SessionId): CordisRunCardStore {
let store = this.sessions.get(sessionId)
if (store === undefined) {
@@ -58,7 +62,12 @@ export class CordisRunCardRegistry {
}
}
-/** Build the Package business-view key shared by registrations and Run cards. */
+/**
+ * Build the Package business-view key shared by registrations and Run cards.
+ * @param pluginId - stable Plugin identity.
+ * @param packageId - immutable Package identity.
+ * @returns the shared business-view key.
+ */
export function cordisToolViewKey(
pluginId: CordisDynamicPluginId,
packageId: CordisDynamicPackageId,
diff --git a/packages/extensions/ui-cordis/src/client/status.ts b/packages/extensions/ui-cordis/src/client/status.ts
index 052c6fc3b1..19f64d4355 100644
--- a/packages/extensions/ui-cordis/src/client/status.ts
+++ b/packages/extensions/ui-cordis/src/client/status.ts
@@ -8,8 +8,16 @@ import type {
/** The three product-visible lifecycle readings. */
export type CordisVisibleStatus = 'idle' | 'client-pending' | 'running'
-/** Locate one immutable Package inside a Plugin row. */
-export function packageOf(row: DynamicCordisInventoryRow, packageId: CordisDynamicPackageId) {
+/**
+ * Locate one immutable Package inside a Plugin row.
+ * @param row - owning Plugin inventory row.
+ * @param packageId - immutable Package identity to locate.
+ * @returns the matching Package metadata, or `undefined` when absent.
+ */
+export function packageOf(
+ row: DynamicCordisInventoryRow,
+ packageId: CordisDynamicPackageId,
+): DynamicCordisInventoryRow['packages'][number] | undefined {
return row.packages.find(pkg => pkg.packageId === packageId)
}
diff --git a/packages/typert/generator/src/cordis-catalog.ts b/packages/typert/generator/src/cordis-catalog.ts
index 079ca7217d..2d8f139085 100644
--- a/packages/typert/generator/src/cordis-catalog.ts
+++ b/packages/typert/generator/src/cordis-catalog.ts
@@ -74,6 +74,8 @@ export interface EventEntry {
/** One public service method and the source contract attached to it. */
export interface ServiceMethodEntry {
+ /** Compiler member category; policy-supplied methods may omit it. */
+ kind?: 'method' | 'property'
/** Public method signature (body stripped). */
signature: string
/** Original method JSDoc, dedented from its containing class. */
@@ -293,7 +295,7 @@ export class CordisCatalogProjector {
if (parsed.deprecated) continue
if (member.kind === 'property') {
if (member.jsDoc === undefined) continue
- methods.push({ signature: member.text, jsDoc: member.jsDoc })
+ methods.push({ kind: 'property', signature: member.text, jsDoc: member.jsDoc })
continue
}
if (member.kind !== 'method') continue
@@ -301,7 +303,7 @@ export class CordisCatalogProjector {
if (this.face.face === 'host') {
checkTypeLinks(where, signatureTypeNames(this.renderer, member.signature), this.policy, typeLinkViolations)
}
- methods.push({ signature: member.text, jsDoc: member.jsDoc ?? '' })
+ methods.push({ kind: 'method', signature: member.text, jsDoc: member.jsDoc ?? '' })
if (member.jsDoc === undefined) {
violations.push(`${where} has no JSDoc.`)
continue
@@ -357,6 +359,7 @@ export class CordisCatalogProjector {
* Analyze the host project once and return both the model and its projection.
* @param scanRoot - workspace root containing `tsconfig.host.json`.
* @param policy - caller-owned type classifications and inherited Cordis data.
+ * @param targetFace - Host or Client Typert face to project.
* @returns the configured projector and its validated catalog model.
*/
export function projectCordisCatalog(scanRoot: string, policy: CordisCatalogPolicy, targetFace: TypertFace = 'host'): {
@@ -617,6 +620,19 @@ function quote(value: string): string {
return `'${value.replaceAll('\\', '\\\\').replaceAll("'", "\\'").replaceAll('\n', '\\n')}'`
}
+/** Render a compact TypeScript string-array literal. */
+function quoteList(values: readonly string[]): string {
+ return `[${values.map(quote).join(', ')}]`
+}
+
+/** Render structured parameter documentation as a compact TypeScript literal. */
+function renderParameters(parameters: ReadonlyMap): string {
+ const values = [...parameters].map(([name, description]) => (
+ `{ name: ${quote(name)}, description: ${quote(description)} }`
+ ))
+ return `[${values.join(', ')}]`
+}
+
/** Resolve and sort the word-bounded transitive type closure referenced by seed text. */
function referencedTypes(
seeds: readonly string[],
@@ -752,9 +768,9 @@ function renderRuntimeApi(
lines.push(' {')
lines.push(` signature: ${quote(method.signature)},`)
lines.push(` description: ${quote(contract.doc)},`)
- lines.push(` parameters: ${JSON.stringify([...contract.params].map(([name, description]) => ({ name, description })))},`)
+ lines.push(` parameters: ${renderParameters(contract.params)},`)
if (contract.returns !== null) lines.push(` returns: ${quote(contract.returns)},`)
- if (contract.throws.length > 0) lines.push(` throws: ${JSON.stringify(contract.throws)},`)
+ if (contract.throws.length > 0) lines.push(` throws: ${quoteList(contract.throws)},`)
lines.push(' },')
}
lines.push(' ],')
@@ -775,7 +791,7 @@ function renderRuntimeApi(
lines.push(` signature: ${quote(event.signature)},`)
lines.push(` summary: ${quote(firstSentence(event.doc))},`)
lines.push(` description: ${quote(event.doc)},`)
- lines.push(` parameters: ${JSON.stringify([...contract.params].map(([name, description]) => ({ name, description })))},`)
+ lines.push(` parameters: ${renderParameters(contract.params)},`)
lines.push(' },')
}
lines.push(
@@ -949,14 +965,15 @@ function renderService(s: ServiceEntry, onPage: string, linkedTypePages: Readonl
const kind = s.abstract ? ' (abstract seam)' : ''
const out = [...anchorFor(`ctx.${s.key} — ${s.type}${kind}`), `### \`ctx.${s.key}\` — \`${s.type}\`${kind}`, '']
if (s.doc) out.push(s.doc, '')
- if (s.methods.length) {
- const declarations = s.methods.flatMap((method, index) => [
+ const methods = s.methods.filter(member => member.kind !== 'property')
+ if (methods.length) {
+ const declarations = methods.flatMap((method, index) => [
...(index > 0 ? [''] : []),
method.jsDoc,
method.signature,
])
out.push('```' + FENCE, ...declarations, '```', '')
- const links = typeLinks(s.methods.map(method => method.signature).join('\n'), onPage, linkedTypePages)
+ const links = typeLinks(methods.map(method => method.signature).join('\n'), onPage, linkedTypePages)
if (links) out.push(links, '')
}
out.push(`Source: [\`${s.source}\`](../../${s.source.split(':')[0]})`, '')
diff --git a/python/sdk-runtime/package.json b/python/sdk-runtime/package.json
index 984cedeee6..89d4b81b22 100644
--- a/python/sdk-runtime/package.json
+++ b/python/sdk-runtime/package.json
@@ -27,6 +27,7 @@
"@deepseek-ai/dsh-compaction": "workspace:^",
"@deepseek-ai/dsh-compaction-basic": "workspace:^",
"@deepseek-ai/dsh-compaction-tool-result-pruner": "workspace:^",
+ "@deepseek-ai/dsh-cordis-host-runner": "workspace:^",
"@deepseek-ai/dsh-credentials": "workspace:^",
"@deepseek-ai/dsh-launch-environment": "workspace:^",
"@deepseek-ai/dsh-fs": "workspace:^",
diff --git a/scripts/gen-cordis-catalog.ts b/scripts/gen-cordis-catalog.ts
index c468d70b7c..a69b4a4995 100644
--- a/scripts/gen-cordis-catalog.ts
+++ b/scripts/gen-cordis-catalog.ts
@@ -63,6 +63,7 @@ export const SERVICE_PAGE: Record = {
codeRuntime: 'code-runtime.md',
commands: 'commands.md',
compaction: 'compaction.md',
+ cordisInspect: 'self-modification.md',
credentials: 'credentials.md',
directoryPicker: 'workspace.md',
dynamicCordisRunner: 'self-modification.md',
@@ -149,6 +150,7 @@ export const SERVICE_WALK_EXEMPTIONS: Record = {
remote: 'client-side interface-typed gateway accessor (ClientRemote) — packages/api/gateway/README.md owns the API',
sessionLogDownload: 'client-side browser download controller — packages/session-query/session-log-download/README.md owns the API',
inputTriggers: 'client-side interface-typed browser service — packages/client/ui-input-trigger/README.md owns the API',
+ timer: 'client-side dynamic-package timer service — packages/extensions/cordis-client-runner/README.md owns the API',
slots: 'client-side interface-typed browser service — packages/client/runtime/README.md owns the API',
theme: 'client-side interface-typed browser service — packages/client/ui-theme/README.md owns the API',
workspaces: 'client-side interface-typed browser service — packages/client/runtime/README.md owns the API',
@@ -584,7 +586,7 @@ export const CORDIS_CATALOG_POLICY: CordisCatalogPolicy = {
linkedTypePages: LINK_MAP,
foundationTypeNames: FOUNDATION_TYPE_NAMES,
typeLinkExemptions: TYPE_LINK_EXEMPTIONS,
- runtimeServiceExclusions: new Set(['dynamicCordisRunner']),
+ runtimeServiceExclusions: new Set(['cordisInspect', 'dynamicCordisRunner']),
runtimeServices: [{
key: 'timer',
type: 'TimerService',
diff --git a/scripts/gen-doc-graphs.ts b/scripts/gen-doc-graphs.ts
index 1795c66dd1..0ee6ae5a13 100644
--- a/scripts/gen-doc-graphs.ts
+++ b/scripts/gen-doc-graphs.ts
@@ -555,6 +555,14 @@ const SERVICE_ROLES: ServiceRole[] = [
consumers: ['tool-cordis'],
note: 'Owns the in-memory definition registry, the vm sandbox for host halves, and the request-run round trip; browser pages reach the same service over the wire through its remote namespace.',
},
+ {
+ key: 'cordisInspect',
+ pkg: 'cordis-host-runner',
+ title: 'Dynamic Cordis inspect registry',
+ mode: 'core',
+ consumers: ['tool-cordis'],
+ note: 'Registers host inspect providers, mirrors the client provider manifest, and routes client queries through the dynamic Cordis transport.',
+ },
]
function generatedHeader(title: string): string[] {