fix: ci and static

This commit is contained in:
imccyu
2026-08-13 01:00:49 +08:00
parent a7d4cd8e1b
commit 5a0283b04f
23 changed files with 260 additions and 207 deletions

View File

@@ -12,6 +12,7 @@
* @module @deepseek-ai/dsh-cordis-client-runner/client/api-catalog
*/
/* jscpd:ignore-start */
/** One named parameter in a Service method or Event listener. */
export interface ApiParameter {
/** Parameter name from the exact signature. */
@@ -967,3 +968,4 @@ export function queryEventApi(name?: string, events: readonly EventApiEntry[] =
referencedTypes: referencedTypeClosure([event.signature]),
}
}
/* jscpd:ignore-end */

View File

@@ -279,7 +279,7 @@ export function apply(ctx: Context): void {
activeRuns: orchestrator.activeRuns,
lastRunError: orchestrator.lastRunError,
renderFailures: runner.renderFailures,
reconcileApprovals: rows => { orchestrator.reconcileApprovals(rows) },
reconcileApprovals: (rows) => { orchestrator.reconcileApprovals(rows) },
approve: (requestId, approveFutureVersions) => orchestrator.approve(requestId, approveFutureVersions),
decline: requestId => orchestrator.decline(requestId),
startUserRun: request => orchestrator.startUserRun(request),

View File

@@ -3,12 +3,13 @@
import type { Context } from '@deepseek-ai/cordis'
import type { JsonValue } from '@deepseek-ai/dsh-api-remotes/client'
import type { SlotsService } from '@deepseek-ai/dsh-client-runtime/client'
import type { ThemeService } from '@deepseek-ai/dsh-client-ui-theme/client'
import type {} from '@deepseek-ai/dsh-client-ui-theme/client'
import { queryEventApi, queryServiceApi } from './api-catalog.ts'
import type { ClientCordisInspectProviderRegistration } from './inspect-registry.ts'
import { CLIENT_SLOT_API } from './slot-catalog.ts'
import type { ClientSlotEntry } from './slot-catalog.ts'
/* jscpd:ignore-start */
const EMPTY_INPUT = { type: 'object', properties: {}, additionalProperties: false } as const
const ANY_OUTPUT = { description: 'JSON data owned by this inspect provider.' } as const
const SERVICE_INPUT = exactInput('service', 'Exact Service key. Omit it for the compact Service and method-signature directory.')
@@ -19,6 +20,7 @@ const SERVICE_OUTPUT = {
const EVENT_OUTPUT = {
description: 'Compact Event directory, or one exact Event contract with only its referenced type declarations.',
} as const
/* jscpd:ignore-end */
const SUBTREE_OUTPUT = {
description: 'Compact purpose/topology trees. With root, selected also contains that Slot\'s full contract and live occupants.',
} as const
@@ -78,7 +80,7 @@ export function clientInspectProviders(ctx: Context): ClientCordisInspectProvide
'Service',
'Progressive Client Service discovery: compact capability/signature directory, then one exact coding contract.',
'listService',
async input => queryServiceApi(readExact(input, 'service')) as unknown as JsonValue,
input => queryServiceApi(readExact(input, 'service')) as unknown as JsonValue,
SERVICE_INPUT,
SERVICE_OUTPUT,
),
@@ -86,11 +88,11 @@ export function clientInspectProviders(ctx: Context): ClientCordisInspectProvide
'Event',
'Progressive Client Event discovery: compact listener directory, then one exact event contract.',
'listEvents',
async input => queryEventApi(readExact(input, 'event')) as unknown as JsonValue,
input => queryEventApi(readExact(input, 'event')) as unknown as JsonValue,
EVENT_INPUT,
EVENT_OUTPUT,
),
registration('Builtin', 'Plain-JavaScript symbols available to a dynamic Client half.', 'listBuiltins', async () => ({
registration('Builtin', 'Plain-JavaScript symbols available to a dynamic Client half.', 'listBuiltins', () => ({
builtins: [...CLIENT_BUILTIN_INSPECTION],
referencedTypes: [],
})),
@@ -105,35 +107,36 @@ export function clientInspectProviders(ctx: Context): ClientCordisInspectProvide
outputSchema: SUBTREE_OUTPUT,
}],
},
async query(method, input) {
query(method, input) {
if (method !== 'listSubTree') throw new Error(`unknown Slots inspect method "${method}"`)
const slots = ctx.get('slots') as SlotsService | undefined
const slots = ctx.get('slots')
if (slots === undefined) throw new Error('Client Slots service is not running')
const root = typeof input === 'object' && input !== null && !Array.isArray(input)
&& typeof input.root === 'string' ? input.root : undefined
const trees = slots.snapshot(root)
const selected = trees[0]
return {
return Promise.resolve({
...root === undefined ? {} : { requestedRoot: { name: root, available: trees.length > 0 } },
trees: trees.map(compactSlotTree),
...root === undefined || selected === undefined ? {} : { selected: inspectLiveSlot(selected) },
referencedTypes: [],
} as unknown as JsonValue
})
},
},
registration('Theme', 'Current theme token names and light/dark override requirements.', 'listTokens', async () => {
const theme = ctx.get('theme') as ThemeService | undefined
registration('Theme', 'Current theme token names and light/dark override requirements.', 'listTokens', () => {
const theme = ctx.get('theme')
if (theme === undefined) throw new Error('Client Theme service is not running')
return { tokens: theme.exportInspectTokens(), referencedTypes: [] } as unknown as JsonValue
}),
]
}
/* jscpd:ignore-start */
function registration(
id: string,
description: string,
method: string,
query: (input: JsonValue | undefined) => Promise<JsonValue>,
query: (input: JsonValue | undefined) => JsonValue | Promise<JsonValue>,
inputSchema: JsonValue = EMPTY_INPUT,
outputSchema: JsonValue = ANY_OUTPUT,
): ClientCordisInspectProviderRegistration {
@@ -164,6 +167,7 @@ function readExact(input: JsonValue | undefined, field: string): string | undefi
const value = input[field]
return typeof value === 'string' ? value : undefined
}
/* jscpd:ignore-end */
type LiveSlotNode = ReturnType<SlotsService['snapshot']>[number]
@@ -188,7 +192,7 @@ function compactSlotTree(node: LiveSlotNode): JsonValue {
...catalog.keyDomain === '' ? {} : { keyDomain: catalog.keyDomain },
},
children: node.children.map(compactSlotTree),
} as unknown as JsonValue
}
}
function inspectLiveSlot(node: LiveSlotNode): JsonValue {
@@ -200,7 +204,7 @@ function inspectLiveSlot(node: LiveSlotNode): JsonValue {
...node.declaredBy === undefined ? {} : { declaredBy: node.declaredBy },
occupants: node.occupants.map(occupant => ({ ...occupant })),
...catalog === undefined ? {} : { catalog: inspectSlotCatalog(catalog) },
} as unknown as JsonValue
}
}
function inspectSlotCatalog(entry: ClientSlotEntry): JsonValue {
@@ -219,5 +223,5 @@ function inspectSlotCatalog(entry: ClientSlotEntry): JsonValue {
hookContext: entry.hookContext,
slotInject: entry.slotInject,
replaceRisk: entry.replaceRisk,
} as unknown as JsonValue
}
}

View File

@@ -422,12 +422,9 @@ export class DynamicCordisPackageRunner {
ledger,
claim,
allocatePriority: () => --this.nextPriority,
reportFailure: error => this.env.reportGuardFailure(
agentId,
pkg.pluginId,
pkg.pluginRunId,
errorDetails(error),
),
reportFailure: (error) => {
this.env.reportGuardFailure(agentId, pkg.pluginId, pkg.pluginRunId, errorDetails(error))
},
})
if (typeof plugin === 'function') {
return { name: moduleIdOf(pkg.pluginId), apply: (ctx: unknown) => plugin(guarded(ctx)) }
@@ -485,12 +482,16 @@ function indexable(component: unknown): component is object {
* @param error - original thrown value.
* @returns its message and original string stack, when present.
*/
/* jscpd:ignore-start */
export function errorDetails(error: unknown): CordisErrorDetails {
if (typeof error !== 'object' || error === null) return { message: String(error) }
const message = 'message' in error && typeof error.message === 'string' ? error.message : String(error)
const message = 'message' in error && typeof error.message === 'string'
? error.message
: Object.prototype.toString.call(error)
const stack = 'stack' in error && typeof error.stack === 'string' ? error.stack : undefined
return { message, ...stack === undefined ? {} : { stack } }
}
/* jscpd:ignore-end */
/**
* What the authoring session reads about one render crash. The slot says where it

View File

@@ -13,6 +13,7 @@
* @module @deepseek-ai/dsh-cordis-client-runner/client/slot-catalog
*/
/* jscpd:ignore-start */
/** One option a register call passes for a given slot cardinality. */
export interface ClientSlotOption {
/** Option name as written in the register options object. */
@@ -77,7 +78,6 @@ export const CLIENT_NOTES: readonly string[] = [
// Seats of one cardinality repeat their register options and framework props
// verbatim; that sameness IS the contract a registrant reads, so clone
// detection is told to skip the data rather than the file.
/* jscpd:ignore-start */
export const CLIENT_SLOT_API: readonly ClientSlotEntry[] = [
{
key: 'conversation',

View File

@@ -3,6 +3,17 @@
import { Service } from '@deepseek-ai/cordis'
import type { Context } from '@deepseek-ai/cordis'
/*
* The browser Service preserves the vendored Host TimerService's erased callback tuples and arbitrary
* async-iterator return and rejection values, so narrowing these positions would change the public API.
*/
/* oxlint-disable typescript/no-explicit-any -- Exact Host TimerService API compatibility; see above. */
/* oxlint-disable typescript/no-unsafe-argument -- The erased callback tuples pass through unchanged. */
/* oxlint-disable typescript/no-unsafe-assignment -- The erased callback tuples pass through unchanged. */
/* oxlint-disable typescript/no-unsafe-member-access -- The returned wrapper retains its dispose property. */
/* oxlint-disable typescript/no-unsafe-return -- The erased generic return values pass through unchanged. */
/* oxlint-disable typescript/prefer-promise-reject-errors -- Async iterators preserve arbitrary throw reasons. */
declare module '@deepseek-ai/cordis' {
interface Context extends Pick<ClientTimerService, 'interval' | 'timeout' | 'throttle' | 'debounce' | 'setTimeout' | 'setInterval'> {
/** Browser timer Service used by the mixed-in Context helpers. */
@@ -64,7 +75,7 @@ export class ClientTimerService extends Service {
if (callback !== undefined) {
const dispose = this.ctx.effect(() => {
const timer = globalThis.setTimeout(() => {
dispose()
void dispose()
callback()
}, delay)
return () => { globalThis.clearTimeout(timer) }
@@ -80,7 +91,7 @@ export class ClientTimerService extends Service {
reject(new Error('Context has been disposed'))
}
}, 'ctx.timeout()')
return promise.finally(dispose)
return promise.finally(() => { void dispose() })
}
/**
@@ -128,13 +139,13 @@ export class ClientTimerService extends Service {
return: (value: any) => {
if (done === undefined) done = { kind: 'return', value }
nextTask?.resolve({ done: true, value })
dispose()
void dispose()
return Promise.resolve({ done: true, value })
},
throw: (reason: any) => {
if (done === undefined) done = { kind: 'throw', reason }
nextTask?.reject(reason)
dispose()
void dispose()
return Promise.resolve({ done: true, value: undefined })
},
[Symbol.asyncIterator]() {