From 3cd9f3c5af73114770550cf398721b5f58ce2ef0 Mon Sep 17 00:00:00 2001 From: code-new-bie <245316967+code-new-bie@users.noreply.github.com> Date: Tue, 25 Aug 2026 21:20:06 +0800 Subject: [PATCH 01/60] refactor: flatten three-layer adapter chain into one presentation adapter Merge app-server-adapter -> product-adapter -> release-adapter inheritance into a single DshxPresentationAdapter. Method bodies stay verbatim per layer; base/product seams survive as explicit helpers so the former super.* call order remains auditable, and the merged dispatch table keeps release-layer routing first. The ownership guard now forbids shadow fork/seed state on the unified adapter while requiring subagent interruption to delegate through ctx.subagents.interrupt (reading DSH's durable parentSession header stays the sanctioned authority path). Ignore local .build/ and .upstream/ materialization workspaces. --- .gitignore | 2 + scripts/verify-ownership-boundary.mjs | 15 +- scripts/verify-slash-contract.mjs | 4 +- src/dsh/app-server-adapter.mjs | 502 ------- src/dsh/local-server.mjs | 4 +- src/dsh/presentation-adapter.mjs | 1302 ++++++++++++++++++ src/dsh/product-adapter.mjs | 415 ------ src/dsh/release-adapter.mjs | 437 ------ test/dsh-app-server-adapter.test.mjs | 11 +- test/dsh-compaction-projection.test.mjs | 6 +- test/dsh-domain-delegation.test.mjs | 4 +- test/dsh-product-adapter.test.mjs | 4 +- test/dsh-product-fork.test.mjs | 4 +- test/dsh-product-resume.test.mjs | 4 +- test/dsh-rc5-acceptance-regressions.test.mjs | 36 +- test/dsh-release-title.test.mjs | 36 +- test/dsh-subagent-authority.test.mjs | 4 +- test/dsh-subagent-presentation.test.mjs | 4 +- 18 files changed, 1371 insertions(+), 1423 deletions(-) delete mode 100644 src/dsh/app-server-adapter.mjs create mode 100644 src/dsh/presentation-adapter.mjs delete mode 100644 src/dsh/product-adapter.mjs delete mode 100644 src/dsh/release-adapter.mjs diff --git a/.gitignore b/.gitignore index e24ae544..86fca400 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,5 @@ coverage/ !.env.example .vscode/ .idea/ +.build/ +.upstream/ diff --git a/scripts/verify-ownership-boundary.mjs b/scripts/verify-ownership-boundary.mjs index b6b0c11a..3bd8840b 100644 --- a/scripts/verify-ownership-boundary.mjs +++ b/scripts/verify-ownership-boundary.mjs @@ -46,16 +46,19 @@ for (const path of ['src/dsh/user-shell.mjs', 'src/dsh/workspace-command.mjs']) } requireText('src/dsh/user-shell.mjs', 'agent: controller.agent'); requireText('src/dsh/workspace-command.mjs', 'agent'); -requireText('src/dsh/release-adapter.mjs', "case 'command/exec'"); +requireText('src/dsh/presentation-adapter.mjs', "case 'command/exec'"); requireText('src/dsh/host-api.mjs', '@deepseek-ai/dsh-host-apiproxy'); requireText('src/dsh/host-api.mjs', 'api.sessions.fork'); -requireText('src/dsh/product-adapter.mjs', 'executeDshCommand'); +requireText('src/dsh/presentation-adapter.mjs', 'executeDshCommand'); requireText('src/dsh/commands.mjs', 'commands.execute'); -forbidText('src/dsh/product-adapter.mjs', 'compactNow'); -for (const path of ['src/dsh/agent-driver.mjs', 'src/dsh/product-adapter.mjs']) { - forbidText(path, /seedLength|parentSession|dshForkSeed/, 'shadow fork/session seed state'); -} +forbidText('src/dsh/presentation-adapter.mjs', 'compactNow'); +forbidText('src/dsh/agent-driver.mjs', /seedLength|parentSession|dshForkSeed/, 'shadow fork/session seed state'); +// The unified adapter may read DSH's durable `parentSession` header field to +// delegate subagent interruption back to ctx.subagents, but it must never +// keep shadow fork/session seed state of its own. +forbidText('src/dsh/presentation-adapter.mjs', /seedLength|dshForkSeed/, 'shadow fork/session seed state'); +requireText('src/dsh/presentation-adapter.mjs', 'subagents.interrupt'); forbidText('src/dsh/agent-driver.mjs', 'fork(sourceAgent'); forbidText('src/dsh/local-server.mjs', 'WebSocketServer', 'production TCP WebSocket server'); diff --git a/scripts/verify-slash-contract.mjs b/scripts/verify-slash-contract.mjs index e299ce81..17ed6258 100644 --- a/scripts/verify-slash-contract.mjs +++ b/scripts/verify-slash-contract.mjs @@ -72,9 +72,7 @@ for (const hidden of dshxHidden) { } const adapterSources = [ - 'src/dsh/app-server-adapter.mjs', - 'src/dsh/product-adapter.mjs', - 'src/dsh/release-adapter.mjs' + 'src/dsh/presentation-adapter.mjs' ].map((relative) => fs.readFileSync(path.join(ROOT, relative), 'utf8')).join('\n'); for (const [command, methods] of runtimeBacked) { for (const method of methods) { diff --git a/src/dsh/app-server-adapter.mjs b/src/dsh/app-server-adapter.mjs deleted file mode 100644 index ffa13754..00000000 --- a/src/dsh/app-server-adapter.mjs +++ /dev/null @@ -1,502 +0,0 @@ -import crypto from 'node:crypto'; -import os from 'node:os'; -import path from 'node:path'; -import { DshAgentDriver } from './agent-driver.mjs'; -import { DshApprovalBridge } from './approval-bridge.mjs'; -import { - codexModelsFromDsh, - decodeDshModel, - dshThreadFromSnapshot, - dshTurnsFromSession, - encodeDshModel, - normalizeCodexEffort, - normalizeSessionHeaders -} from './codex-shapes.mjs'; -import { DshPermissionView } from './permissions.mjs'; -import { DshThreadController } from './thread-controller.mjs'; -import { DshUserQuestionBridge } from './user-question-bridge.mjs'; -import { UiRequestBroker } from '../protocol/request-broker.mjs'; - -const INVALID_REQUEST = -32600; -const METHOD_NOT_FOUND = -32601; -const INVALID_PARAMS = -32602; -const INTERNAL_ERROR = -32603; - -function platformFamily() { - return process.platform === 'win32' ? 'windows' : 'unix'; -} - -function platformOs() { - if (process.platform === 'darwin') return 'macos'; - if (process.platform === 'win32') return 'windows'; - if (process.platform === 'linux') return 'linux'; - return process.platform; -} - -function codexApprovalToDsh(value) { - if (value == null) return undefined; - if (value === 'on-request') return 'ask'; - if (value === 'never') return 'never'; - throw new Error(`DSHX cannot map Codex approval policy ${JSON.stringify(value)} to DSH`); -} - -function textInput(params) { - const inputs = Array.isArray(params?.input) ? params.input : []; - const unsupported = inputs.filter((item) => item?.type !== 'text'); - if (unsupported.length > 0) { - throw new Error(`DSHX turn input currently supports Codex text items only; got ${unsupported.map((item) => item?.type).join(', ')}`); - } - return inputs.map((item) => item.text ?? '').join('\n').trim(); -} - -function pagination(value, total, defaultLimit = 50) { - const cursor = value?.cursor == null ? 0 : Number(value.cursor); - if (!Number.isSafeInteger(cursor) || cursor < 0) throw new Error('invalid pagination cursor'); - const requested = value?.limit == null ? defaultLimit : Number(value.limit); - if (!Number.isSafeInteger(requested) || requested <= 0) throw new Error('limit must be a positive integer'); - const end = Math.min(total, cursor + requested); - return { start: cursor, end, nextCursor: end < total ? String(end) : null }; -} - -function sandboxMatchesCurrent(sandbox, permission) { - if (sandbox == null) return true; - if (sandbox.type === 'dangerFullAccess') return permission.dsh.sandboxMode === 'danger-full-access'; - if (sandbox.type === 'externalSandbox') { - return permission.dsh.sandboxMode === 'read-only' || permission.dsh.sandboxMode === 'workspace-write'; - } - return false; -} - -function fullThreadSnapshot(agent, { includeTurns = false, cliVersion = 'dshx' } = {}) { - const turns = includeTurns ? dshTurnsFromSession({ ctx: agent.ctx, agent }) : []; - return dshThreadFromSnapshot({ - meta: agent.session.header, - events: agent.session.events, - model: agent.session.requestHeader?.()?.config, - turns, - loaded: true, - cliVersion - }); -} - -/** - * Presentation adapter from pinned Codex app-server JSON-RPC to official DSH - * public services. It owns no Agent loop, provider routing, tool dispatch, - * persistence, sandbox enforcement, approval policy or user-question semantics. - */ -export class DshAppServerAdapter { - constructor({ - ctx, - send, - cwd = process.cwd(), - home = path.join(os.homedir(), '.dshx'), - version = '0.1.0-dev', - diagnostics = () => {} - }) { - if (!ctx || typeof ctx.get !== 'function') throw new Error('DshAppServerAdapter requires a Cordis Context'); - if (typeof send !== 'function') throw new Error('DshAppServerAdapter requires send(message)'); - this.ctx = ctx; - this.send = send; - this.cwd = path.resolve(cwd); - this.home = path.resolve(home); - this.version = version; - this.diagnostics = diagnostics; - this.driver = new DshAgentDriver(ctx); - this.permissions = new DshPermissionView(ctx); - this.broker = new UiRequestBroker({ send }); - this.controllers = new Map(); - this.approvals = new Map(); - this.syntheticInteractions = new Map(); - this.readyPromise = null; - this.userQuestions = null; - this.closed = false; - } - - async ensureReady() { - if (this.readyPromise) return this.readyPromise; - this.readyPromise = (async () => { - const loader = this.ctx.get('loader'); - if (loader?.await) await loader.await(); - if (!this.userQuestions && this.ctx.get('userQuestions')) { - this.userQuestions = new DshUserQuestionBridge({ - ctx: this.ctx, - broker: this.broker, - locate: (request) => this.openSyntheticInteraction(request), - complete: (location, outcome) => this.completeSyntheticInteraction(location, outcome), - diagnostics: this.diagnostics - }); - } - })(); - return this.readyPromise; - } - - async handle(message) { - if (this.broker.handleResponse(message)) return null; - if (!message || message.id === undefined || typeof message.method !== 'string') { - if (message?.id === undefined && typeof message?.method === 'string') return null; - return { response: this.error(message?.id ?? null, INVALID_REQUEST, 'Invalid Request') }; - } - try { - await this.ensureReady(); - const dispatched = await this.dispatch(message.method, message.params ?? {}); - return { - response: { id: message.id, result: dispatched?.result }, - afterResponse: dispatched?.afterResponse - }; - } catch (error) { - const code = error?.code === METHOD_NOT_FOUND ? METHOD_NOT_FOUND - : error?.code === INVALID_PARAMS ? INVALID_PARAMS - : INTERNAL_ERROR; - return { - response: this.error(message.id, code, error instanceof Error ? error.message : String(error)) - }; - } - } - - async dispatch(method, params) { - switch (method) { - case 'initialize': - return { - result: { - userAgent: `dshx/${this.version}`, - codexHome: this.home, - platformFamily: platformFamily(), - platformOs: platformOs() - } - }; - case 'account/read': - return { result: { account: null, requiresOpenaiAuth: false } }; - case 'configRequirements/read': - return { result: { requirements: null } }; - case 'skills/list': - // DSH skills remain upstream-owned. Until their public catalog is - // mapped, claiming none is safer than synthesizing Codex skill paths. - return { result: { data: [] } }; - case 'model/list': - return this.modelList(params); - case 'thread/list': - return this.threadList(params); - case 'thread/loaded/list': - return this.loadedThreadList(); - case 'thread/start': - return this.threadStart(params); - case 'thread/resume': - return this.threadResume(params); - case 'thread/read': - return this.threadRead(params); - case 'thread/unsubscribe': - return this.threadUnsubscribe(params); - case 'turn/start': - return this.turnStart(params); - case 'turn/interrupt': - return this.turnInterrupt(params); - default: { - const error = new Error(`Method not found: ${method}`); - error.code = METHOD_NOT_FOUND; - throw error; - } - } - } - - async modelList(params) { - const directory = await this.driver.modelDirectory(); - for (const failure of directory.failures ?? []) { - this.diagnostics(`DSH model catalog ${failure.provider}: ${failure.message}`); - } - const active = this.driver.listRootAgents()[0]; - const current = active - ? this.driver.currentModel(active) - : this.ctx.get('agentDefaultModel')?.currentSelection?.(); - const all = codexModelsFromDsh(directory, current); - const visible = params.includeHidden ? all : all.filter((model) => !model.hidden); - const page = pagination(params, visible.length); - return { result: { data: visible.slice(page.start, page.end), nextCursor: page.nextCursor } }; - } - - async threadList(params) { - const headers = normalizeSessionHeaders(await this.driver.listSessions()); - const snapshots = await Promise.all(headers.map(async (header) => { - try { - const inspected = await this.driver.inspectSession(String(header.id)); - const meta = inspected?.meta ?? header; - const events = inspected?.events ?? []; - return dshThreadFromSnapshot({ - meta, - events, - loaded: Boolean(this.controllers.has(String(meta.id)) || this.driver.getLive(String(meta.id))), - cliVersion: this.version - }); - } catch (error) { - this.diagnostics(`inspect ${String(header.id)}: ${error instanceof Error ? error.message : error}`); - return undefined; - } - })); - let threads = snapshots.filter(Boolean); - if (params.cwd != null) { - const wanted = new Set((Array.isArray(params.cwd) ? params.cwd : [params.cwd]).map((entry) => path.resolve(entry))); - threads = threads.filter((thread) => wanted.has(path.resolve(thread.cwd))); - } - if (params.searchTerm) { - const needle = String(params.searchTerm).toLowerCase(); - threads = threads.filter((thread) => `${thread.name ?? ''}\n${thread.preview}`.toLowerCase().includes(needle)); - } - if (Array.isArray(params.modelProviders) && params.modelProviders.length > 0) { - const providers = new Set(params.modelProviders); - threads = threads.filter((thread) => providers.has(thread.modelProvider)); - } - threads.sort((a, b) => (params.sortDirection === 'asc' ? 1 : -1) * (a.recencyAt - b.recencyAt)); - const page = pagination(params, threads.length); - return { - result: { - data: threads.slice(page.start, page.end).map((thread) => ({ ...thread, turns: [] })), - nextCursor: page.nextCursor, - backwardsCursor: null - } - }; - } - - loadedThreadList() { - const data = [...this.controllers.values()].map((controller) => fullThreadSnapshot(controller.agent, { - includeTurns: false, - cliVersion: this.version - })); - return { result: { data } }; - } - - async applyStartPermissions(agent, params) { - const desiredSandbox = params.sandbox; - const desiredApproval = codexApprovalToDsh(params.approvalPolicy); - if (desiredSandbox == null && desiredApproval == null) return this.permissions.current(agent); - - const current = this.permissions.current(agent); - const sandboxMode = desiredSandbox ?? current.dsh.sandboxMode; - const approvalPolicy = desiredApproval ?? current.dsh.approvalPolicy; - const presets = this.ctx.get('permissionPresets'); - const match = presets?.names?.find((name) => { - const preset = presets.resolve(name); - return preset.sandbox === sandboxMode && preset.approval === approvalPolicy; - }); - if (!match) { - throw new Error(`DSHX refuses to synthesize a DSH custom permission bundle (${sandboxMode}, ${approvalPolicy})`); - } - this.permissions.set(agent, match); - return this.permissions.current(agent); - } - - async applyModelOverride(agent, { model, modelProvider, effort } = {}) { - if (model == null && effort == null) return this.driver.currentModel(agent); - let selection; - if (model != null) { - selection = decodeDshModel(model); - if (!selection && modelProvider) selection = { provider: modelProvider, model }; - if (!selection) throw new Error('DSHX accepts model switches only from its DSH-backed model catalog'); - } else { - selection = this.driver.currentModel(agent); - } - const normalizedEffort = normalizeCodexEffort(effort); - if (normalizedEffort !== undefined) selection = { ...selection, reasoningEffort: normalizedEffort }; - return this.driver.selectModel(agent, selection); - } - - installController(handle) { - const threadId = String(handle.agent.id); - const existing = this.controllers.get(threadId); - if (existing) return existing; - const controller = new DshThreadController({ - handle, - driver: this.driver, - emit: this.send, - diagnostics: this.diagnostics - }); - this.controllers.set(threadId, controller); - const approval = new DshApprovalBridge({ - agent: handle.agent, - broker: this.broker, - classify: (req) => req.callId == null ? null : controller.toolCorrelation(req.callId), - diagnostics: this.diagnostics - }); - this.approvals.set(threadId, approval); - return controller; - } - - threadResponse(agent, { includeTurns = false } = {}) { - const selection = this.driver.currentModel(agent); - const permission = this.permissions.current(agent); - const thread = fullThreadSnapshot(agent, { includeTurns, cliVersion: this.version }); - return { - thread, - model: encodeDshModel(selection), - modelProvider: selection.provider, - serviceTier: null, - cwd: thread.cwd, - instructionSources: [], - approvalPolicy: permission.codex.approvalPolicy, - approvalsReviewer: permission.codex.approvalsReviewer, - sandbox: permission.codex.sandbox, - reasoningEffort: selection.reasoningEffort ?? null - }; - } - - async threadStart(params) { - const sessionId = crypto.randomUUID(); - const cwd = path.resolve(params.cwd ?? this.cwd); - const handle = await this.driver.create({ cwd, sessionId }); - try { - await this.applyModelOverride(handle.agent, params); - await this.applyStartPermissions(handle.agent, params); - this.installController(handle); - const result = this.threadResponse(handle.agent); - return { - result, - afterResponse: () => this.send({ method: 'thread/started', params: { thread: result.thread } }) - }; - } catch (error) { - await handle.dispose?.(); - throw error; - } - } - - async threadResume(params) { - if (!params.threadId) throw new Error('thread/resume requires threadId'); - let controller = this.controllers.get(String(params.threadId)); - if (!controller) { - const live = this.driver.getLive(String(params.threadId)); - const handle = live - ? { agent: live, dispose: async () => {} } - : await this.driver.resume(String(params.threadId)); - controller = this.installController(handle); - } - const agent = controller.agent; - if (params.cwd != null && path.resolve(params.cwd) !== path.resolve(agent.session.header?.cwd ?? this.cwd)) { - throw new Error('DSHX does not override a persisted DSH session cwd during resume'); - } - await this.applyModelOverride(agent, params); - await this.applyStartPermissions(agent, params); - return { result: this.threadResponse(agent, { includeTurns: true }) }; - } - - async threadRead(params) { - if (!params.threadId) throw new Error('thread/read requires threadId'); - const live = this.driver.getLive(String(params.threadId)); - if (live) { - return { result: { thread: fullThreadSnapshot(live, { includeTurns: Boolean(params.includeTurns), cliVersion: this.version }) } }; - } - const inspected = await this.driver.inspectSession(String(params.threadId)); - if (!inspected) throw new Error(`Unknown DSH session: ${String(params.threadId)}`); - return { - result: { - thread: dshThreadFromSnapshot({ - meta: inspected.meta, - events: inspected.events, - loaded: false, - cliVersion: this.version, - // A cold persisted session cannot faithfully use tool presenters - // without a composed Agent. The TUI resumes before requesting rich - // history; avoid fabricating tool semantics on a cold read. - turns: [] - }) - } - }; - } - - async turnStart(params) { - const controller = this.controllers.get(String(params.threadId)); - if (!controller) throw new Error(`Thread is not resumed in DSHX: ${String(params.threadId)}`); - if (params.cwd != null && path.resolve(params.cwd) !== path.resolve(controller.agent.session.header?.cwd ?? this.cwd)) { - throw new Error('DSHX does not own per-turn cwd mutation; resume/start the DSH session in the desired cwd'); - } - if (params.outputSchema != null) throw new Error('DSHX has no faithful public DSH mapping for Codex outputSchema yet'); - - await this.applyModelOverride(controller.agent, { model: params.model, effort: params.effort }); - const permission = this.permissions.current(controller.agent); - const desiredApproval = codexApprovalToDsh(params.approvalPolicy); - if (desiredApproval != null && desiredApproval !== permission.dsh.approvalPolicy) { - throw new Error('Turn-level approval changes must use a DSH permission preset'); - } - if (!sandboxMatchesCurrent(params.sandboxPolicy, permission)) { - throw new Error('Turn-level sandbox changes must use a DSH permission preset'); - } - - const started = await controller.startTurn(textInput(params)); - return { result: { turn: started.turn }, afterResponse: started.release }; - } - - turnInterrupt(params) { - const controller = this.controllers.get(String(params.threadId)); - if (!controller) return { result: {} }; - controller.interrupt({ keepInbox: true }); - return { result: {} }; - } - - async threadUnsubscribe(params) { - const threadId = String(params.threadId ?? ''); - const controller = this.controllers.get(threadId); - if (controller) { - this.approvals.get(threadId)?.dispose(); - this.approvals.delete(threadId); - this.controllers.delete(threadId); - await controller.close(); - } - return { result: {} }; - } - - openSyntheticInteraction(request) { - const agentId = request?.agent?.id; - if (!agentId) return undefined; - const controller = this.controllers.get(String(agentId)); - const location = controller?.currentLocation(); - if (!location) return undefined; - const itemId = `dshx-interaction-${crypto.randomUUID()}`; - const startedAtMs = Date.now(); - const item = { - type: 'dynamicToolCall', - id: itemId, - namespace: 'dshx', - tool: 'userInteraction', - arguments: { questionCount: request.questions?.length ?? 0 }, - status: 'inProgress', - contentItems: null, - success: null, - durationMs: null - }; - this.syntheticInteractions.set(itemId, { ...location, item, startedAtMs }); - this.send({ - method: 'item/started', - params: { ...location, item, startedAtMs } - }); - return { ...location, itemId }; - } - - completeSyntheticInteraction(location, outcome) { - const state = this.syntheticInteractions.get(location.itemId); - if (!state) return; - this.syntheticInteractions.delete(location.itemId); - const completedAtMs = Date.now(); - const item = { - ...state.item, - status: outcome.status === 'completed' ? 'completed' : 'failed', - success: outcome.status === 'completed', - durationMs: Math.max(0, completedAtMs - state.startedAtMs) - }; - this.send({ - method: 'item/completed', - params: { threadId: state.threadId, turnId: state.turnId, item, completedAtMs } - }); - } - - error(id, code, message, data = undefined) { - const error = { code, message }; - if (data !== undefined) error.data = data; - return { id, error }; - } - - async close() { - if (this.closed) return; - this.closed = true; - this.userQuestions?.dispose(); - this.userQuestions = null; - this.broker.close(); - const ids = [...this.controllers.keys()]; - for (const id of ids) await this.threadUnsubscribe({ threadId: id }); - } -} diff --git a/src/dsh/local-server.mjs b/src/dsh/local-server.mjs index 22d4ccca..35b8239e 100644 --- a/src/dsh/local-server.mjs +++ b/src/dsh/local-server.mjs @@ -4,7 +4,7 @@ import path from 'node:path'; import { spawn } from 'node:child_process'; import { createInterface } from 'node:readline'; import { fileURLToPath } from 'node:url'; -import { DshxReleaseAdapter } from './release-adapter.mjs'; +import { DshxPresentationAdapter } from './presentation-adapter.mjs'; import { bootDshxRuntime } from './runtime-boot.mjs'; const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../..'); @@ -186,7 +186,7 @@ export async function startDshxLocalServer({ version = '0.1.0-dev', runtime, bootRuntime = bootDshxRuntime, - Adapter = DshxReleaseAdapter, + Adapter = DshxPresentationAdapter, log = () => {}, bridgeCommand = packagedBridgeBinary(), bridgeArgs, diff --git a/src/dsh/presentation-adapter.mjs b/src/dsh/presentation-adapter.mjs new file mode 100644 index 00000000..5c6fca15 --- /dev/null +++ b/src/dsh/presentation-adapter.mjs @@ -0,0 +1,1302 @@ +import crypto from 'node:crypto'; +import os from 'node:os'; +import path from 'node:path'; +import { DshAgentDriver } from './agent-driver.mjs'; +import { DshApprovalBridge } from './approval-bridge.mjs'; +import { + codexModelsFromDsh, + decodeDshModel, + dshThreadFromSnapshot, + dshTurnsFromSession, + encodeDshModel, + normalizeCodexEffort, + normalizeSessionHeaders +} from './codex-shapes.mjs'; +import { executeDshCommand } from './commands.mjs'; +import { dshThreadItemsPage, dshThreadTurnsPage } from './history-pages.mjs'; +import { DshHostApi } from './host-api.mjs'; +import { codexPlanTarget, threadSettingsUpdatedNotification } from './plan-presentation.mjs'; +import { DshPermissionView } from './permissions.mjs'; +import { codexForkAtSeq } from './session-fork.mjs'; +import { dshSkillsListEntry } from './skills.mjs'; +import { foldDshSessionTitle, threadNameUpdatedNotification } from './thread-title.mjs'; +import { DshThreadController } from './thread-controller.mjs'; +import { codexInputToDshContent, dshContentText } from './user-input.mjs'; +import { DshUserQuestionBridge } from './user-question-bridge.mjs'; +import { DshUserShellBridge } from './user-shell.mjs'; +import { persistedTokenUsageNotification } from './token-usage.mjs'; +import { DshWorkspaceCommandBridge } from './workspace-command.mjs'; +import { UiRequestBroker } from '../protocol/request-broker.mjs'; + +const INVALID_REQUEST = -32600; +const METHOD_NOT_FOUND = -32601; +const INVALID_PARAMS = -32602; +const INTERNAL_ERROR = -32603; + +function platformFamily() { + return process.platform === 'win32' ? 'windows' : 'unix'; +} + +function platformOs() { + if (process.platform === 'darwin') return 'macos'; + if (process.platform === 'win32') return 'windows'; + if (process.platform === 'linux') return 'linux'; + return process.platform; +} + +function codexApprovalToDsh(value) { + if (value == null) return undefined; + if (value === 'on-request') return 'ask'; + if (value === 'never') return 'never'; + throw new Error(`DSHX cannot map Codex approval policy ${JSON.stringify(value)} to DSH`); +} + +// Base turn input validation. Distinct from the steer variant below because +// the two historically reported different unsupported-input messages. +function turnTextInput(params) { + const inputs = Array.isArray(params?.input) ? params.input : []; + const unsupported = inputs.filter((item) => item?.type !== 'text'); + if (unsupported.length > 0) { + throw new Error(`DSHX turn input currently supports Codex text items only; got ${unsupported.map((item) => item?.type).join(', ')}`); + } + return inputs.map((item) => item.text ?? '').join('\n').trim(); +} + +function steerTextInput(params) { + const inputs = Array.isArray(params?.input) ? params.input : []; + const unsupported = inputs.filter((item) => item?.type !== 'text'); + if (unsupported.length > 0) { + throw new Error(`DSHX steer currently supports Codex text items only; got ${unsupported.map((item) => item?.type).join(', ')}`); + } + return inputs.map((item) => item.text ?? '').join('\n').trim(); +} + +function pagination(value, total, defaultLimit = 50) { + const cursor = value?.cursor == null ? 0 : Number(value.cursor); + if (!Number.isSafeInteger(cursor) || cursor < 0) throw new Error('invalid pagination cursor'); + const requested = value?.limit == null ? defaultLimit : Number(value.limit); + if (!Number.isSafeInteger(requested) || requested <= 0) throw new Error('limit must be a positive integer'); + const end = Math.min(total, cursor + requested); + return { start: cursor, end, nextCursor: end < total ? String(end) : null }; +} + +function sandboxMatchesCurrent(sandbox, permission) { + if (sandbox == null) return true; + if (sandbox.type === 'dangerFullAccess') return permission.dsh.sandboxMode === 'danger-full-access'; + if (sandbox.type === 'externalSandbox') { + return permission.dsh.sandboxMode === 'read-only' || permission.dsh.sandboxMode === 'workspace-write'; + } + return false; +} + +function fullThreadSnapshot(agent, { includeTurns = false, cliVersion = 'dshx' } = {}) { + const turns = includeTurns ? dshTurnsFromSession({ ctx: agent.ctx, agent }) : []; + return dshThreadFromSnapshot({ + meta: agent.session.header, + events: agent.session.events, + model: agent.session.requestHeader?.()?.config, + turns, + loaded: true, + cliVersion + }); +} + +function dshPermissionPreset(ctx, codexId) { + const presets = ctx.get('permissionPresets'); + if (!presets) throw new Error('DSHX requires DSH service: permissionPresets'); + const mapped = codexId === ':workspace' + ? 'workspace-write' + : codexId === ':danger-full-access' + ? 'danger-full-access' + : codexId === ':read-only' + ? 'read-only' + : codexId; + if (!presets.names.includes(mapped)) { + throw new Error(`DSH has no permission preset corresponding to Codex profile ${JSON.stringify(codexId)}`); + } + return mapped; +} + +function codexPermissionProfileId(preset) { + if (preset === 'workspace-write') return ':workspace'; + if (preset === 'danger-full-access') return ':danger-full-access'; + if (preset === 'read-only') return ':read-only'; + if (preset === 'custom' || preset == null) return null; + return preset; +} + +function hasSupportedThreadSetting(params) { + return params.model != null + || params.effort != null + || params.permissions != null + || params.approvalPolicy != null; +} + +function snapshotTitle(snapshot) { + return typeof snapshot?.title === 'string' && snapshot.title.length > 0 ? snapshot.title : null; +} + +function isDshSubagent(agent) { + return agent?.session?.header?.origin === 'subagent'; +} + +/** + * Single presentation adapter from pinned Codex app-server JSON-RPC to + * official DSH public services. + * + * This class is the linearization of the former three-layer inheritance chain + * (app-server-adapter -> product-adapter -> release-adapter). Method bodies + * are kept verbatim per layer; `_Base` / `_ProductLayer` + * helpers preserve the exact call order the old `super.*` chain executed, so + * behavior is unchanged while "which dispatch actually runs" no longer spans + * three files. It owns no Agent loop, provider routing, tool dispatch, + * persistence, sandbox enforcement, approval policy or user-question semantics. + */ +export class DshxPresentationAdapter { + constructor({ + ctx, + send, + cwd = process.cwd(), + home = path.join(os.homedir(), '.dshx'), + version = '0.1.0-dev', + diagnostics = () => {} + }) { + if (!ctx || typeof ctx.get !== 'function') throw new Error('DshAppServerAdapter requires a Cordis Context'); + if (typeof send !== 'function') throw new Error('DshAppServerAdapter requires send(message)'); + this.ctx = ctx; + this.send = send; + this.cwd = path.resolve(cwd); + this.home = path.resolve(home); + this.version = version; + this.diagnostics = diagnostics; + this.driver = new DshAgentDriver(ctx); + this.permissions = new DshPermissionView(ctx); + this.broker = new UiRequestBroker({ send }); + this.controllers = new Map(); + this.approvals = new Map(); + this.syntheticInteractions = new Map(); + this.readyPromise = null; + this.userQuestions = null; + this.closed = false; + } + + // ── readiness ──────────────────────────────────────────────────────────── + + async ensureReady() { + await this.ensureReadyBase(); + if (this._agentPresentationDisposers) return; + this._agentPresentationDisposers = [ + this.ctx.on('agent/created', ({ agent }) => { + if (!isDshSubagent(agent)) return; + try { + this.send({ method: 'thread/started', params: { thread: this.liveAgentThread(agent) } }); + } catch (error) { + this.diagnostics(`subagent thread/started projection failed for ${String(agent?.id ?? '')}: ${error instanceof Error ? error.message : error}`); + } + }), + this.ctx.on('agent/status', ({ agent, status }) => { + try { + this.send({ + method: 'thread/status/changed', + params: { + threadId: String(agent.id), + status: status === 'running' ? { type: 'active', activeFlags: [] } : { type: 'idle' } + } + }); + } catch (error) { + this.diagnostics(`agent status projection failed for ${String(agent?.id ?? '')}: ${error instanceof Error ? error.message : error}`); + } + }), + this.ctx.on('agent/disposed', ({ agent }) => { + try { + this.send({ + method: 'thread/status/changed', + params: { threadId: String(agent.id), status: { type: 'notLoaded' } } + }); + } catch (error) { + this.diagnostics(`agent disposal projection failed for ${String(agent?.id ?? '')}: ${error instanceof Error ? error.message : error}`); + } + }) + ]; + } + + async ensureReadyBase() { + if (this.readyPromise) return this.readyPromise; + this.readyPromise = (async () => { + const loader = this.ctx.get('loader'); + if (loader?.await) await loader.await(); + if (!this.userQuestions && this.ctx.get('userQuestions')) { + this.userQuestions = new DshUserQuestionBridge({ + ctx: this.ctx, + broker: this.broker, + locate: (request) => this.openSyntheticInteraction(request), + complete: (location, outcome) => this.completeSyntheticInteraction(location, outcome), + diagnostics: this.diagnostics + }); + } + })(); + return this.readyPromise; + } + + // ── protocol entry ─────────────────────────────────────────────────────── + + async handle(message) { + if (this.broker.handleResponse(message)) return null; + if (!message || message.id === undefined || typeof message.method !== 'string') { + if (message?.id === undefined && typeof message?.method === 'string') return null; + return { response: this.error(message?.id ?? null, INVALID_REQUEST, 'Invalid Request') }; + } + try { + await this.ensureReady(); + const dispatched = await this.dispatch(message.method, message.params ?? {}); + return { + response: { id: message.id, result: dispatched?.result }, + afterResponse: dispatched?.afterResponse + }; + } catch (error) { + const code = error?.code === METHOD_NOT_FOUND ? METHOD_NOT_FOUND + : error?.code === INVALID_PARAMS ? INVALID_PARAMS + : INTERNAL_ERROR; + return { + response: this.error(message.id, code, error instanceof Error ? error.message : String(error)) + }; + } + } + + /** + * Merged dispatch table. Case order mirrors the former inheritance + * linearization: release-layer routing first, then product-layer routing, + * then the base protocol surface. The base layer's dead `skills/list` stub + * (empty data) is gone — the product layer's DSH-backed skillsList owns it. + */ + async dispatch(method, params) { + switch (method) { + // release-layer routing + case 'command/exec': + return this.commandExec(params); + case 'config/batchWrite': + return this.configBatchWrite(params); + case 'thread/name/set': + return this.threadNameSet(params); + case 'thread/shellCommand': + return this.threadShellCommand(params); + case 'thread/fork': + return this.threadForkPresentation(params); + case 'thread/settings/update': + return this.threadSettingsUpdatePresentation(params); + case 'thread/compact/start': + this.directController(params?.threadId, 'direct compaction'); + return this.threadCompactStart(params); + case 'turn/start': + case 'turn/steer': + return this.richUserTurn(method, params); + case 'turn/interrupt': { + if (this.userShell().interrupt(params?.threadId, params?.turnId)) return { result: {} }; + const controller = this.controllers.get(String(params?.threadId ?? '')); + if (controller && isDshSubagent(controller.agent)) return this.interruptSubagent(controller); + return this.turnInterruptProduct(params); + } + case 'thread/unsubscribe': { + const threadId = String(params?.threadId ?? ''); + this.userShell().abortThread(threadId, 'thread unsubscribed'); + this.planListeners().get(threadId)?.(); + this.planListeners().delete(threadId); + this.planMutationSuppressed().delete(threadId); + return this.threadUnsubscribeWithStatus(params); + } + // product-layer routing + case 'account/usage/read': + return this.accountUsageRead(params); + case 'skills/list': + return this.skillsList(params); + case 'thread/turns/list': + return this.threadTurnsList(params); + case 'thread/items/list': + return this.threadItemsList(params); + // base-layer routing (most-derived implementations win at call time) + case 'initialize': + return { + result: { + userAgent: `dshx/${this.version}`, + codexHome: this.home, + platformFamily: platformFamily(), + platformOs: platformOs() + } + }; + case 'account/read': + return { result: { account: null, requiresOpenaiAuth: false } }; + case 'configRequirements/read': + return { result: { requirements: null } }; + case 'model/list': + return this.modelList(params); + case 'thread/list': + return this.threadList(params); + case 'thread/loaded/list': + return this.loadedThreadList(); + case 'thread/start': + return this.threadStart(params); + case 'thread/resume': + return this.threadResume(params); + case 'thread/read': + return this.threadRead(params); + default: { + const error = new Error(`Method not found: ${method}`); + error.code = METHOD_NOT_FOUND; + throw error; + } + } + } + + // ── models and listings ────────────────────────────────────────────────── + + async modelList(params) { + const directory = await this.driver.modelDirectory(); + for (const failure of directory.failures ?? []) { + this.diagnostics(`DSH model catalog ${failure.provider}: ${failure.message}`); + } + const active = this.driver.listRootAgents()[0]; + const current = active + ? this.driver.currentModel(active) + : this.ctx.get('agentDefaultModel')?.currentSelection?.(); + const all = codexModelsFromDsh(directory, current); + const visible = params.includeHidden ? all : all.filter((model) => !model.hidden); + const page = pagination(params, visible.length); + return { result: { data: visible.slice(page.start, page.end), nextCursor: page.nextCursor } }; + } + + async threadList(params = {}) { + const response = await this.threadListBase(params); + const data = await Promise.all(response.result.data.map(async (thread) => { + try { + const snapshot = await this.driver.readTitle(thread.id); + return { ...thread, name: snapshotTitle(snapshot) ?? thread.name ?? null }; + } catch (error) { + this.diagnostics(`title read ${thread.id}: ${error instanceof Error ? error.message : error}`); + return thread; + } + })); + return { result: { ...response.result, data } }; + } + + async threadListBase(params) { + const headers = normalizeSessionHeaders(await this.driver.listSessions()); + const snapshots = await Promise.all(headers.map(async (header) => { + try { + const inspected = await this.driver.inspectSession(String(header.id)); + const meta = inspected?.meta ?? header; + const events = inspected?.events ?? []; + return dshThreadFromSnapshot({ + meta, + events, + loaded: Boolean(this.controllers.has(String(meta.id)) || this.driver.getLive(String(meta.id))), + cliVersion: this.version + }); + } catch (error) { + this.diagnostics(`inspect ${String(header.id)}: ${error instanceof Error ? error.message : error}`); + return undefined; + } + })); + let threads = snapshots.filter(Boolean); + if (params.cwd != null) { + const wanted = new Set((Array.isArray(params.cwd) ? params.cwd : [params.cwd]).map((entry) => path.resolve(entry))); + threads = threads.filter((thread) => wanted.has(path.resolve(thread.cwd))); + } + if (params.searchTerm) { + const needle = String(params.searchTerm).toLowerCase(); + threads = threads.filter((thread) => `${thread.name ?? ''}\n${thread.preview}`.toLowerCase().includes(needle)); + } + if (Array.isArray(params.modelProviders) && params.modelProviders.length > 0) { + const providers = new Set(params.modelProviders); + threads = threads.filter((thread) => providers.has(thread.modelProvider)); + } + threads.sort((a, b) => (params.sortDirection === 'asc' ? 1 : -1) * (a.recencyAt - b.recencyAt)); + const page = pagination(params, threads.length); + return { + result: { + data: threads.slice(page.start, page.end).map((thread) => ({ ...thread, turns: [] })), + nextCursor: page.nextCursor, + backwardsCursor: null + } + }; + } + + loadedThreadList() { + // Pinned Codex ThreadLoadedListResponse.data is Array. Keep rich + // thread metadata on thread/list/read/started and expose only live IDs here. + return { + result: { + data: this.driver.listLive().map((agent) => String(agent.id)) + } + }; + } + + // ── permissions ────────────────────────────────────────────────────────── + + async applyStartPermissions(agent, params = {}) { + if (params.permissions == null) return this.applyStartPermissionsBase(agent, params); + if (params.sandbox != null) { + throw new Error('Codex thread/start permissions and sandbox cannot both be selected for DSHX'); + } + const preset = dshPermissionPreset(this.ctx, String(params.permissions)); + this.permissions.set(agent, preset); + const current = this.permissions.current(agent); + if (params.approvalPolicy != null && current.codex.approvalPolicy !== params.approvalPolicy) { + throw new Error( + `DSH preset ${preset} does not match requested Codex approval policy ${JSON.stringify(params.approvalPolicy)}` + ); + } + return current; + } + + async applyStartPermissionsBase(agent, params) { + const desiredSandbox = params.sandbox; + const desiredApproval = codexApprovalToDsh(params.approvalPolicy); + if (desiredSandbox == null && desiredApproval == null) return this.permissions.current(agent); + + const current = this.permissions.current(agent); + const sandboxMode = desiredSandbox ?? current.dsh.sandboxMode; + const approvalPolicy = desiredApproval ?? current.dsh.approvalPolicy; + const presets = this.ctx.get('permissionPresets'); + const match = presets?.names?.find((name) => { + const preset = presets.resolve(name); + return preset.sandbox === sandboxMode && preset.approval === approvalPolicy; + }); + if (!match) { + throw new Error(`DSHX refuses to synthesize a DSH custom permission bundle (${sandboxMode}, ${approvalPolicy})`); + } + this.permissions.set(agent, match); + return this.permissions.current(agent); + } + + async applyModelOverride(agent, { model, modelProvider, effort } = {}) { + if (model == null && effort == null) return this.driver.currentModel(agent); + let selection; + if (model != null) { + selection = decodeDshModel(model); + if (!selection && modelProvider) selection = { provider: modelProvider, model }; + if (!selection) throw new Error('DSHX accepts model switches only from its DSH-backed model catalog'); + } else { + selection = this.driver.currentModel(agent); + } + const normalizedEffort = normalizeCodexEffort(effort); + if (normalizedEffort !== undefined) selection = { ...selection, reasoningEffort: normalizedEffort }; + return this.driver.selectModel(agent, selection); + } + + installController(handle) { + const controller = this.installControllerBase(handle); + const threadId = String(controller.agent.id); + if (!this.planListeners().has(threadId)) { + const dispose = controller.agent.ctx.on('session/event', (session, event) => { + if (session !== controller.agent.session || event?.type !== 'plan/mode') return; + if (this.planMutationSuppressed().has(threadId)) return; + try { + this.send(this.planSettingsNotification(controller.agent)); + } catch (error) { + this.diagnostics(`plan settings projection failed for ${threadId}: ${error instanceof Error ? error.message : error}`); + } + }); + this.planListeners().set(threadId, dispose); + } + return controller; + } + + installControllerBase(handle) { + const threadId = String(handle.agent.id); + const existing = this.controllers.get(threadId); + if (existing) return existing; + const controller = new DshThreadController({ + handle, + driver: this.driver, + emit: this.send, + diagnostics: this.diagnostics + }); + this.controllers.set(threadId, controller); + const approval = new DshApprovalBridge({ + agent: handle.agent, + broker: this.broker, + classify: (req) => req.callId == null ? null : controller.toolCorrelation(req.callId), + diagnostics: this.diagnostics + }); + this.approvals.set(threadId, approval); + return controller; + } + + // ── thread responses ──────────────────────────────────────────────────── + + threadResponse(agent, options = {}) { + const response = this.threadResponseProductLayer(agent, options); + const folded = this.driver.currentTitle(agent); + const name = snapshotTitle(folded) ?? foldDshSessionTitle(agent.session?.events ?? []); + return { + ...response, + thread: { ...response.thread, name } + }; + } + + threadResponseProductLayer(agent, options = {}) { + const response = this.threadResponseCore(agent, options); + const permission = this.permissions.current(agent); + const id = codexPermissionProfileId(permission.preset); + return { + ...response, + runtimeWorkspaceRoots: [], + activePermissionProfile: id == null ? null : { id, extends: null }, + multiAgentMode: 'explicitRequestOnly', + initialTurnsPage: null, + turnsBackwardsCursor: null, + itemsBackwardsCursor: null + }; + } + + threadResponseCore(agent, { includeTurns = false } = {}) { + const selection = this.driver.currentModel(agent); + const permission = this.permissions.current(agent); + const thread = fullThreadSnapshot(agent, { includeTurns, cliVersion: this.version }); + return { + thread, + model: encodeDshModel(selection), + modelProvider: selection.provider, + serviceTier: null, + cwd: thread.cwd, + instructionSources: [], + approvalPolicy: permission.codex.approvalPolicy, + approvalsReviewer: permission.codex.approvalsReviewer, + sandbox: permission.codex.sandbox, + reasoningEffort: selection.reasoningEffort ?? null + }; + } + + // ── thread lifecycle ───────────────────────────────────────────────────── + + async threadStart(params) { + const sessionId = crypto.randomUUID(); + const cwd = path.resolve(params.cwd ?? this.cwd); + const handle = await this.driver.create({ cwd, sessionId }); + try { + await this.applyModelOverride(handle.agent, params); + await this.applyStartPermissions(handle.agent, params); + this.installController(handle); + const result = this.threadResponse(handle.agent); + return { + result, + afterResponse: () => this.send({ method: 'thread/started', params: { thread: result.thread } }) + }; + } catch (error) { + await handle.dispose?.(); + throw error; + } + } + + async threadResume(params = {}) { + const response = await this.threadResumeProduct(params); + const threadId = String(params.threadId ?? response.result.thread?.id ?? ''); + const agent = this.controllers.get(threadId)?.agent; + const prior = response.afterResponse; + return { + ...response, + afterResponse: () => { + prior?.(); + if (agent) this.send(this.planSettingsNotification(agent)); + } + }; + } + + async threadResumeProduct(params = {}) { + if (!params.threadId) throw new Error('thread/resume requires threadId'); + const threadId = String(params.threadId); + let controller = this.controllers.get(threadId); + if (!controller) { + const live = this.driver.getLive(threadId); + const handle = live + ? { agent: live, dispose: async () => {} } + : await this.driver.resume(threadId); + controller = this.installController(handle); + } + const agent = controller.agent; + if (params.cwd != null && path.resolve(params.cwd) !== path.resolve(agent.session.header?.cwd ?? this.cwd)) { + throw new Error('DSHX does not override a persisted DSH session cwd during resume'); + } + await this.applyModelOverride(agent, params); + await this.applyStartPermissions(agent, params); + const result = this.threadResponse(agent, { + includeTurns: params.excludeTurns !== true + }); + const replay = persistedTokenUsageNotification({ + ctx: this.ctx, + session: agent.session, + threadId + }); + return { + result, + afterResponse: replay ? () => this.send(replay) : undefined + }; + } + + async threadRead(params = {}) { + const response = await this.threadReadBase(params); + const thread = response.result.thread; + try { + const snapshot = await this.driver.readTitle(thread.id); + return { + result: { + ...response.result, + thread: { ...thread, name: snapshotTitle(snapshot) ?? thread.name ?? null } + } + }; + } catch (error) { + this.diagnostics(`title read ${thread.id}: ${error instanceof Error ? error.message : error}`); + return response; + } + } + + async threadReadBase(params) { + if (!params.threadId) throw new Error('thread/read requires threadId'); + const live = this.driver.getLive(String(params.threadId)); + if (live) { + return { result: { thread: fullThreadSnapshot(live, { includeTurns: Boolean(params.includeTurns), cliVersion: this.version }) } }; + } + const inspected = await this.driver.inspectSession(String(params.threadId)); + if (!inspected) throw new Error(`Unknown DSH session: ${String(params.threadId)}`); + return { + result: { + thread: dshThreadFromSnapshot({ + meta: inspected.meta, + events: inspected.events, + loaded: false, + cliVersion: this.version, + // A cold persisted session cannot faithfully use tool presenters + // without a composed Agent. The TUI resumes before requesting rich + // history; avoid fabricating tool semantics on a cold read. + turns: [] + }) + } + }; + } + + async turnStart(params) { + const controller = this.controllers.get(String(params.threadId)); + if (!controller) throw new Error(`Thread is not resumed in DSHX: ${String(params.threadId)}`); + if (params.cwd != null && path.resolve(params.cwd) !== path.resolve(controller.agent.session.header?.cwd ?? this.cwd)) { + throw new Error('DSHX does not own per-turn cwd mutation; resume/start the DSH session in the desired cwd'); + } + if (params.outputSchema != null) throw new Error('DSHX has no faithful public DSH mapping for Codex outputSchema yet'); + + await this.applyModelOverride(controller.agent, { model: params.model, effort: params.effort }); + const permission = this.permissions.current(controller.agent); + const desiredApproval = codexApprovalToDsh(params.approvalPolicy); + if (desiredApproval != null && desiredApproval !== permission.dsh.approvalPolicy) { + throw new Error('Turn-level approval changes must use a DSH permission preset'); + } + if (!sandboxMatchesCurrent(params.sandboxPolicy, permission)) { + throw new Error('Turn-level sandbox changes must use a DSH permission preset'); + } + + const started = await controller.startTurn(turnTextInput(params)); + return { result: { turn: started.turn }, afterResponse: started.release }; + } + + turnInterrupt(params) { + const controller = this.controllers.get(String(params.threadId)); + if (!controller) return { result: {} }; + controller.interrupt({ keepInbox: true }); + return { result: {} }; + } + + async threadUnsubscribe(params) { + const threadId = String(params.threadId ?? ''); + const controller = this.controllers.get(threadId); + if (controller) { + this.approvals.get(threadId)?.dispose(); + this.approvals.delete(threadId); + this.controllers.delete(threadId); + await controller.close(); + } + return { result: {} }; + } + + async threadUnsubscribeWithStatus(params = {}) { + const threadId = String(params.threadId ?? ''); + this.manualCompactions().get(threadId)?.abort(new Error('thread unsubscribed')); + const subscribed = this.controllers.has(threadId); + const loaded = Boolean(this.driver.getLive(threadId)); + await this.threadUnsubscribe(params); + return { + result: { + status: subscribed ? 'unsubscribed' : loaded ? 'notSubscribed' : 'notLoaded' + } + }; + } + + // ── product-layer features ─────────────────────────────────────────────── + + accountUsageRead(_params = {}) { + return { + result: { + summary: { + lifetimeTokens: null, + peakDailyTokens: null, + longestRunningTurnSec: null, + currentStreakDays: null, + longestStreakDays: null + }, + dailyUsageBuckets: null, + threadUsage: null + } + }; + } + + manualCompactions() { + return this._manualCompactions ??= new Map(); + } + + hostApi() { + return this._hostApi ??= new DshHostApi(this.ctx, { cwd: this.cwd }); + } + + warnThread(threadId, message) { + this.send({ method: 'warning', params: { threadId, message } }); + } + + async skillsList(params = {}) { + if (params.forceReload === true) { + this.diagnostics('Codex requested skills forceReload; DSHX is reading the current DSH registry snapshot without overriding provider-owned cache policy'); + } + const cwds = Array.isArray(params.cwds) && params.cwds.length > 0 + ? params.cwds.map((cwd) => path.resolve(cwd)) + : [this.cwd]; + const data = await Promise.all(cwds.map((cwd) => dshSkillsListEntry({ + ctx: this.ctx, + cwd, + diagnostics: this.diagnostics + }))); + return { result: { data } }; + } + + threadCompactStart(params = {}) { + const threadId = String(params.threadId ?? ''); + const controller = this.controllers.get(threadId); + if (!controller) throw new Error(`Thread is not resumed in DSHX: ${threadId}`); + const active = this.manualCompactions(); + if (active.has(threadId)) { + throw new Error('Compaction is unavailable because this thread already has an active manual compaction'); + } + const abortController = new AbortController(); + active.set(threadId, abortController); + return { + result: {}, + afterResponse: () => { + void this.runManualCompaction({ threadId, controller, abortController }); + } + }; + } + + async runManualCompaction({ threadId, controller, abortController }) { + try { + const execution = await executeDshCommand({ + ctx: controller.agent.ctx ?? this.ctx, + agent: controller.agent, + line: '/compact', + signal: abortController.signal + }); + if (execution.result?.sourceEventSeq == null && execution.result?.text) { + this.warnThread(threadId, execution.result.text); + } + } catch (error) { + if (abortController.signal.aborted) { + this.warnThread(threadId, 'Compaction cancelled.'); + } else { + const message = error instanceof Error ? error.message : String(error); + this.warnThread(threadId, message); + this.diagnostics(`manual compaction failed for ${threadId}: ${message}`); + } + } finally { + if (this.manualCompactions().get(threadId) === abortController) { + this.manualCompactions().delete(threadId); + } + } + } + + turnInterruptProduct(params = {}) { + const threadId = String(params.threadId ?? ''); + if (String(params.turnId ?? '').startsWith('dsh-maintenance-compaction-')) { + const active = this.manualCompactions().get(threadId); + if (active) { + active.abort(new Error('user cancelled DSH compaction')); + return { result: {} }; + } + } + return this.turnInterrupt(params); + } + + async forkSourceEvents(sourceId) { + const live = this.controllers.get(sourceId)?.agent ?? this.driver.getLive(sourceId); + if (live?.session) return live.session.events ?? []; + const inspected = await this.driver.inspectSession(sourceId); + if (!inspected) throw new Error(`Unknown DSH session: ${sourceId}`); + return inspected.events ?? []; + } + + async threadFork(params = {}) { + const sourceId = String(params.threadId ?? ''); + if (!sourceId) throw new Error('thread/fork requires threadId'); + if (params.path != null) throw new Error('DSHX forks DSH sessions by threadId, not Codex rollout paths'); + if (params.deferGoalContinuation === true) { + throw new Error('DSH has no Codex thread-goal continuation state for DSHX to defer'); + } + if (params.ephemeral === true) { + throw new Error('DSHX does not expose ephemeral Codex forks over durable DSH sessions'); + } + + const events = await this.forkSourceEvents(sourceId); + const atSeq = codexForkAtSeq(events, { + lastTurnId: params.lastTurnId, + beforeTurnId: params.beforeTurnId + }); + const forked = await this.hostApi().forkSession({ sessionId: sourceId, atSeq }); + const childId = String(forked?.sessionId ?? ''); + if (!childId) throw new Error('DSH Host fork returned no child session id'); + + const childAgent = this.driver.getLive(childId); + if (!childAgent) throw new Error(`DSH Host fork did not publish child Agent ${childId}`); + this.driver.adoptExternalSelection(childAgent, { + select: (selection) => this.hostApi().selectModel({ sessionId: childId, ...selection }) + }); + const controller = this.installController({ agent: childAgent, dispose: async () => {} }); + const result = this.threadResponse(controller.agent, { + includeTurns: params.excludeTurns !== true + }); + return { + result, + afterResponse: () => this.send({ method: 'thread/started', params: { thread: result.thread } }) + }; + } + + historyController(threadId) { + const controller = this.controllers.get(String(threadId ?? '')); + if (!controller) { + throw new Error(`Thread must be resumed before paginated DSH history is rendered: ${String(threadId ?? '')}`); + } + return controller; + } + + threadTurnsList(params = {}) { + const controller = this.historyController(params.threadId); + return { + result: dshThreadTurnsPage({ + controller, + params, + diagnostics: this.diagnostics + }) + }; + } + + threadItemsList(params = {}) { + const controller = this.historyController(params.threadId); + return { + result: dshThreadItemsPage({ + controller, + params, + diagnostics: this.diagnostics + }) + }; + } + + async saveDefaultModelSelection(selection) { + const defaults = this.ctx.get('agentDefaultModel'); + if (!defaults?.saveSelection) { + this.diagnostics('DSH agentDefaultModel service has no saveSelection(); current session selection remains valid but deployment default was not persisted'); + return; + } + await defaults.saveSelection({ + provider: selection.provider, + model: selection.model, + ...(selection.reasoningEffort == null ? {} : { reasoningEffort: selection.reasoningEffort }) + }); + } + + async threadSettingsUpdate(params = {}) { + const threadId = String(params.threadId ?? ''); + const controller = this.controllers.get(threadId); + if (!controller) throw new Error(`Thread is not resumed in DSHX: ${threadId}`); + const agent = controller.agent; + + if (params.cwd != null) { + const currentCwd = path.resolve(agent.session.header?.cwd ?? this.cwd); + if (path.resolve(params.cwd) !== currentCwd) { + throw new Error('DSHX does not retarget a live DSH session cwd from the TUI'); + } + } + if (params.sandboxPolicy != null) { + throw new Error('DSHX changes permissions through DSH named permission presets, not Codex legacy sandboxPolicy'); + } + if (params.serviceTier !== undefined) { + throw new Error('DSH has no public thread service-tier setter for DSHX to project'); + } + if (params.summary != null) { + throw new Error('DSH has no equivalent public reasoning-summary thread setting'); + } + if (params.personality != null) { + throw new Error('DSH has no equivalent public personality thread setting'); + } + if (params.approvalsReviewer != null && params.approvalsReviewer !== 'user') { + throw new Error('DSH approval review is user-owned; DSHX cannot select a Codex-specific reviewer'); + } + + const supported = hasSupportedThreadSetting(params); + if (params.collaborationMode != null && !supported) { + throw new Error('DSH has no equivalent public collaboration-mode thread setting'); + } + + if (params.permissions != null || params.approvalPolicy != null) { + await this.applyStartPermissions(agent, { + permissions: params.permissions, + approvalPolicy: params.approvalPolicy + }); + } + if (params.model != null || params.effort != null) { + const selection = await this.applyModelOverride(agent, { + model: params.model, + effort: params.effort + }); + await this.saveDefaultModelSelection(selection); + } + + return { result: {} }; + } + + turnSteer(params = {}) { + const threadId = String(params.threadId ?? ''); + const controller = this.controllers.get(threadId); + if (!controller) throw new Error(`Thread is not resumed in DSHX: ${threadId}`); + const location = controller.currentLocation(); + if (!location) throw new Error(`Thread has no active DSH turn to steer: ${threadId}`); + if (typeof params.expectedTurnId !== 'string' || params.expectedTurnId !== location.turnId) { + throw new Error( + `DSHX steer expectedTurnId ${JSON.stringify(params.expectedTurnId)} does not match active DSH turn ${location.turnId}` + ); + } + controller.steer(steerTextInput(params)); + return { result: { turnId: location.turnId } }; + } + + // ── release-layer presentation surfaces ────────────────────────────────── + + userShell() { + return this._userShell ??= new DshUserShellBridge({ + send: this.send, + diagnostics: this.diagnostics + }); + } + + workspaceCommands() { + return this._workspaceCommands ??= new DshWorkspaceCommandBridge({ driver: this.driver }); + } + + planListeners() { + return this._planListeners ??= new Map(); + } + + planMutationSuppressed() { + return this._planMutationSuppressed ??= new Set(); + } + + planMode(agent) { + const service = agent?.ctx?.get?.('planMode') ?? this.ctx.get('planMode'); + if (!service?.set || !service?.get) throw new Error('DSHX requires DSH service: planMode'); + return service; + } + + planSettingsNotification(agent) { + const response = this.threadResponse(agent); + return threadSettingsUpdatedNotification({ + threadId: String(agent.id), + response, + planState: this.planMode(agent).get(agent) + }); + } + + liveAgentThread(agent) { + const thread = dshThreadFromSnapshot({ + meta: agent.session.header, + events: agent.session.events ?? [], + model: agent.session.requestHeader?.()?.config, + loaded: true, + cliVersion: this.version + }); + const title = snapshotTitle(this.driver.currentTitle(agent)) ?? foldDshSessionTitle(agent.session.events ?? []); + return { + ...thread, + status: agent.status === 'running' ? { type: 'active', activeFlags: [] } : { type: 'idle' }, + name: title, + turns: [] + }; + } + + directController(threadId, operation) { + const controller = this.controllers.get(String(threadId ?? '')); + if (!controller) throw new Error(`Thread is not resumed in DSHX: ${String(threadId ?? '')}`); + if (isDshSubagent(controller.agent)) { + throw new Error(`DSHX refuses ${operation} on a DSH subagent; child runtime control remains owned by ctx.subagents`); + } + return controller; + } + + async interruptSubagent(controller) { + const parentSessionId = controller.agent.session.header?.parentSession; + if (parentSessionId == null) throw new Error('DSH subagent is missing durable parentSession authority'); + const subagents = this.ctx.get('subagents'); + if (!subagents?.interrupt) throw new Error('DSHX requires DSH service: subagents.interrupt'); + await subagents.interrupt(String(controller.agent.id), { + kind: 'user', + parentSessionId: String(parentSessionId) + }); + return { result: {} }; + } + + async commandExec(params = {}) { + return { result: await this.workspaceCommands().execute(params) }; + } + + async configBatchWrite(params = {}) { + const edits = Array.isArray(params.edits) ? params.edits : []; + if (edits.length === 0) throw new Error('DSHX config/batchWrite requires at least one model-selection edit'); + + const supported = new Set(['model', 'model_reasoning_effort']); + for (const edit of edits) { + if (!supported.has(edit?.keyPath)) { + throw new Error(`DSHX config/batchWrite refuses Codex-owned setting: ${String(edit?.keyPath ?? '')}`); + } + if (edit?.mergeStrategy != null && edit.mergeStrategy !== 'replace') { + throw new Error(`DSHX config/batchWrite supports replace semantics only: ${String(edit.keyPath)}`); + } + } + + const defaults = this.ctx.get('agentDefaultModel'); + const llm = this.ctx.get('llm'); + if (!defaults?.currentSelection || !defaults?.saveSelection) { + throw new Error('DSHX requires DSH service: agentDefaultModel.saveSelection'); + } + if (!llm?.resolveCallConfig) throw new Error('DSHX requires DSH service: llm.resolveCallConfig'); + + const current = defaults.currentSelection(); + let requested = { provider: current.provider, model: current.model }; + if (current.reasoningEffort !== undefined) requested.reasoningEffort = current.reasoningEffort; + + const modelEdit = edits.find((edit) => edit.keyPath === 'model'); + if (modelEdit) { + const decoded = decodeDshModel(modelEdit.value); + if (!decoded) throw new Error('DSHX persists default models only from its DSH-backed opaque model catalog'); + requested = { ...decoded }; + } + + const effortEdit = edits.find((edit) => edit.keyPath === 'model_reasoning_effort'); + if (effortEdit) { + const effort = effortEdit.value == null ? undefined : normalizeCodexEffort(effortEdit.value); + requested = { provider: requested.provider, model: requested.model }; + if (effort !== undefined) requested.reasoningEffort = effort; + } + + const resolved = await llm.resolveCallConfig(requested); + const persisted = { provider: resolved.provider, model: resolved.model }; + // Preserve provider-default semantics when the TUI clears its reasoning + // setting; otherwise persist the DSH-resolved explicit effort. + if (requested.reasoningEffort !== undefined) { + persisted.reasoningEffort = resolved.reasoningEffort ?? requested.reasoningEffort; + } + await defaults.saveSelection(persisted); + + this._configRevision = (this._configRevision ?? 0) + 1; + return { + result: { + status: 'ok', + version: `dshx-${this._configRevision}`, + // Codex requires an absolute path in ConfigWriteResponse. Persistence is + // actually owned by DSH settings; this marker stays inside presentation home. + filePath: path.join(this.home, 'dsh-settings'), + overriddenMetadata: null + } + }; + } + + async richUserTurn(method, params = {}) { + const threadId = String(params.threadId ?? ''); + const controller = this.controllers.get(threadId); + if (!controller) { + // Formerly `super.dispatch(method, params)`: the inherited tail routed + // turn/start to the base turnStart and turn/steer to the product + // turnSteer validator. Route directly to those most-derived methods. + return method === 'turn/steer' ? this.turnSteer(params) : this.turnStart(params); + } + if (isDshSubagent(controller.agent)) { + throw new Error(`DSHX refuses ${method} on a DSH subagent; send/steer authority remains owned by ctx.subagents`); + } + const content = await codexInputToDshContent(this.ctx, params.input ?? []); + const clear = controller.prepareUserContent(content); + try { + // Pinned Codex serializes an unset reasoning effort as JSON null. DSH + // interprets absence as provider default, so never forward null as an + // explicit provider effort. + const normalizedParams = params.effort == null ? { ...params, effort: undefined } : params; + // Preserve the original base/product validation path. The fallback text is + // consumed only if no prepared rich content exists; it also keeps the + // base adapter's expected text-only parameter shape intact. + const forwarded = { ...normalizedParams, input: [{ type: 'text', text: dshContentText(content) }] }; + return method === 'turn/steer' ? this.turnSteer(forwarded) : this.turnStart(forwarded); + } finally { + clear(); + } + } + + async threadForkPresentation(params = {}) { + const response = await this.threadFork(params); + const startedThread = { ...response.result.thread, turns: [] }; + const agent = this.controllers.get(String(response.result.thread.id))?.agent; + return { + ...response, + // Pinned Codex emits copied history only in the fork response. The + // thread/started notification introduces metadata/live state and must not + // replay those copied turns a second time before paginated hydration. + afterResponse: () => { + this.send({ + method: 'thread/started', + params: { thread: startedThread } + }); + if (agent) this.send(this.planSettingsNotification(agent)); + } + }; + } + + async threadSettingsUpdatePresentation(params = {}) { + const threadId = String(params.threadId ?? ''); + const controller = this.controllers.get(threadId); + if (controller && isDshSubagent(controller.agent)) { + throw new Error('DSHX refuses direct model/permission/plan changes on a DSH subagent; composition remains DSH-owned'); + } + if (params.collaborationMode == null) return this.threadSettingsUpdate(params); + if (!controller) throw new Error(`Thread is not resumed in DSHX: ${threadId}`); + const active = codexPlanTarget(params.collaborationMode); + const { collaborationMode: _ignored, ...ordinary } = params; + + // Let the existing DSH-backed settings adapter validate/apply every other + // supported field. The collaboration payload's model/reasoning/instructions + // are intentionally not treated as DSH model or prompt configuration. + await this.threadSettingsUpdate(ordinary); + + this.planMutationSuppressed().add(threadId); + try { + await this.planMode(controller.agent).set(controller.agent, active); + } finally { + this.planMutationSuppressed().delete(threadId); + } + + return { + result: {}, + afterResponse: () => this.send(this.planSettingsNotification(controller.agent)) + }; + } + + threadShellCommand(params = {}) { + const controller = this.directController(params.threadId, 'direct shell execution'); + return this.userShell().start(controller, params.command); + } + + async threadNameSet(params = {}) { + const threadId = String(params.threadId ?? ''); + if (!threadId) throw new Error('thread/name/set requires threadId'); + if (typeof params.name !== 'string') throw new Error('thread/name/set requires name'); + + let temporaryHandle; + let agent = this.controllers.get(threadId)?.agent ?? this.driver.getLive(threadId); + if (!agent) { + temporaryHandle = await this.driver.resume(threadId); + agent = temporaryHandle.agent; + } + + try { + const snapshot = this.driver.renameTitle(agent, params.name); + const threadName = snapshotTitle(snapshot); + if (threadName == null) throw new Error('DSH sessionTitle.rename returned no accepted title'); + return { + result: {}, + afterResponse: () => this.send(threadNameUpdatedNotification(threadId, threadName)) + }; + } finally { + await temporaryHandle?.dispose?.(); + } + } + + // ── synthetic interactions (base) ──────────────────────────────────────── + + openSyntheticInteraction(request) { + const agentId = request?.agent?.id; + if (!agentId) return undefined; + const controller = this.controllers.get(String(agentId)); + const location = controller?.currentLocation(); + if (!location) return undefined; + const itemId = `dshx-interaction-${crypto.randomUUID()}`; + const startedAtMs = Date.now(); + const item = { + type: 'dynamicToolCall', + id: itemId, + namespace: 'dshx', + tool: 'userInteraction', + arguments: { questionCount: request.questions?.length ?? 0 }, + status: 'inProgress', + contentItems: null, + success: null, + durationMs: null + }; + this.syntheticInteractions.set(itemId, { ...location, item, startedAtMs }); + this.send({ + method: 'item/started', + params: { ...location, item, startedAtMs } + }); + return { ...location, itemId }; + } + + completeSyntheticInteraction(location, outcome) { + const state = this.syntheticInteractions.get(location.itemId); + if (!state) return; + this.syntheticInteractions.delete(location.itemId); + const completedAtMs = Date.now(); + const item = { + ...state.item, + status: outcome.status === 'completed' ? 'completed' : 'failed', + success: outcome.status === 'completed', + durationMs: Math.max(0, completedAtMs - state.startedAtMs) + }; + this.send({ + method: 'item/completed', + params: { threadId: state.threadId, turnId: state.turnId, item, completedAtMs } + }); + } + + error(id, code, message, data = undefined) { + const error = { code, message }; + if (data !== undefined) error.data = data; + return { id, error }; + } + + // ── teardown (linearized release → product → base) ────────────────────── + + async close() { + this._userShell?.close(); + for (const dispose of this._agentPresentationDisposers ?? []) dispose?.(); + this._agentPresentationDisposers = []; + for (const dispose of this.planListeners().values()) dispose?.(); + this.planListeners().clear(); + this.planMutationSuppressed().clear(); + for (const controller of this.manualCompactions().values()) { + controller.abort(new Error('DSHX adapter closing')); + } + this.manualCompactions().clear(); + this.userQuestions?.dispose(); + this.userQuestions = null; + this.broker.close(); + const ids = [...this.controllers.keys()]; + for (const id of ids) await this.threadUnsubscribe({ threadId: id }); + } +} + +export const releaseAdapterInternals = { snapshotTitle, isDshSubagent }; diff --git a/src/dsh/product-adapter.mjs b/src/dsh/product-adapter.mjs deleted file mode 100644 index 2f8a089f..00000000 --- a/src/dsh/product-adapter.mjs +++ /dev/null @@ -1,415 +0,0 @@ -import path from 'node:path'; -import { DshAppServerAdapter } from './app-server-adapter.mjs'; -import { executeDshCommand } from './commands.mjs'; -import { dshThreadItemsPage, dshThreadTurnsPage } from './history-pages.mjs'; -import { DshHostApi } from './host-api.mjs'; -import { codexForkAtSeq } from './session-fork.mjs'; -import { dshSkillsListEntry } from './skills.mjs'; -import { persistedTokenUsageNotification } from './token-usage.mjs'; - -function textInput(params) { - const inputs = Array.isArray(params?.input) ? params.input : []; - const unsupported = inputs.filter((item) => item?.type !== 'text'); - if (unsupported.length > 0) { - throw new Error(`DSHX steer currently supports Codex text items only; got ${unsupported.map((item) => item?.type).join(', ')}`); - } - return inputs.map((item) => item.text ?? '').join('\n').trim(); -} - -function dshPermissionPreset(ctx, codexId) { - const presets = ctx.get('permissionPresets'); - if (!presets) throw new Error('DSHX requires DSH service: permissionPresets'); - const mapped = codexId === ':workspace' - ? 'workspace-write' - : codexId === ':danger-full-access' - ? 'danger-full-access' - : codexId === ':read-only' - ? 'read-only' - : codexId; - if (!presets.names.includes(mapped)) { - throw new Error(`DSH has no permission preset corresponding to Codex profile ${JSON.stringify(codexId)}`); - } - return mapped; -} - -function codexPermissionProfileId(preset) { - if (preset === 'workspace-write') return ':workspace'; - if (preset === 'danger-full-access') return ':danger-full-access'; - if (preset === 'read-only') return ':read-only'; - if (preset === 'custom' || preset == null) return null; - return preset; -} - -function hasSupportedThreadSetting(params) { - return params.model != null - || params.effort != null - || params.permissions != null - || params.approvalPolicy != null; -} - -/** - * Product-level protocol tail on top of the stable DSH public API adapter. - * Keep feature-specific compatibility decisions here instead of widening the - * runtime-owning base: every method still delegates to official DSH services. - */ -export class DshxProductAdapter extends DshAppServerAdapter { - async dispatch(method, params) { - switch (method) { - case 'account/usage/read': - return this.accountUsageRead(params); - case 'skills/list': - return this.skillsList(params); - case 'thread/compact/start': - return this.threadCompactStart(params); - case 'thread/fork': - return this.threadFork(params); - case 'thread/turns/list': - return this.threadTurnsList(params); - case 'thread/items/list': - return this.threadItemsList(params); - case 'thread/settings/update': - return this.threadSettingsUpdate(params); - case 'thread/unsubscribe': - return this.threadUnsubscribeWithStatus(params); - case 'turn/interrupt': - return this.turnInterruptProduct(params); - case 'turn/steer': - return this.turnSteer(params); - default: - return super.dispatch(method, params); - } - } - - accountUsageRead(_params = {}) { - return { - result: { - summary: { - lifetimeTokens: null, - peakDailyTokens: null, - longestRunningTurnSec: null, - currentStreakDays: null, - longestStreakDays: null - }, - dailyUsageBuckets: null, - threadUsage: null - } - }; - } - - manualCompactions() { - return this._manualCompactions ??= new Map(); - } - - hostApi() { - return this._hostApi ??= new DshHostApi(this.ctx, { cwd: this.cwd }); - } - - warnThread(threadId, message) { - this.send({ method: 'warning', params: { threadId, message } }); - } - - threadResponse(agent, options = {}) { - const response = super.threadResponse(agent, options); - const permission = this.permissions.current(agent); - const id = codexPermissionProfileId(permission.preset); - return { - ...response, - runtimeWorkspaceRoots: [], - activePermissionProfile: id == null ? null : { id, extends: null }, - multiAgentMode: 'explicitRequestOnly', - initialTurnsPage: null, - turnsBackwardsCursor: null, - itemsBackwardsCursor: null - }; - } - - async applyStartPermissions(agent, params = {}) { - if (params.permissions == null) return super.applyStartPermissions(agent, params); - if (params.sandbox != null) { - throw new Error('Codex thread/start permissions and sandbox cannot both be selected for DSHX'); - } - const preset = dshPermissionPreset(this.ctx, String(params.permissions)); - this.permissions.set(agent, preset); - const current = this.permissions.current(agent); - if (params.approvalPolicy != null && current.codex.approvalPolicy !== params.approvalPolicy) { - throw new Error( - `DSH preset ${preset} does not match requested Codex approval policy ${JSON.stringify(params.approvalPolicy)}` - ); - } - return current; - } - - async skillsList(params = {}) { - if (params.forceReload === true) { - this.diagnostics('Codex requested skills forceReload; DSHX is reading the current DSH registry snapshot without overriding provider-owned cache policy'); - } - const cwds = Array.isArray(params.cwds) && params.cwds.length > 0 - ? params.cwds.map((cwd) => path.resolve(cwd)) - : [this.cwd]; - const data = await Promise.all(cwds.map((cwd) => dshSkillsListEntry({ - ctx: this.ctx, - cwd, - diagnostics: this.diagnostics - }))); - return { result: { data } }; - } - - threadCompactStart(params = {}) { - const threadId = String(params.threadId ?? ''); - const controller = this.controllers.get(threadId); - if (!controller) throw new Error(`Thread is not resumed in DSHX: ${threadId}`); - const active = this.manualCompactions(); - if (active.has(threadId)) { - throw new Error('Compaction is unavailable because this thread already has an active manual compaction'); - } - const abortController = new AbortController(); - active.set(threadId, abortController); - return { - result: {}, - afterResponse: () => { - void this.runManualCompaction({ threadId, controller, abortController }); - } - }; - } - - async runManualCompaction({ threadId, controller, abortController }) { - try { - const execution = await executeDshCommand({ - ctx: controller.agent.ctx ?? this.ctx, - agent: controller.agent, - line: '/compact', - signal: abortController.signal - }); - if (execution.result?.sourceEventSeq == null && execution.result?.text) { - this.warnThread(threadId, execution.result.text); - } - } catch (error) { - if (abortController.signal.aborted) { - this.warnThread(threadId, 'Compaction cancelled.'); - } else { - const message = error instanceof Error ? error.message : String(error); - this.warnThread(threadId, message); - this.diagnostics(`manual compaction failed for ${threadId}: ${message}`); - } - } finally { - if (this.manualCompactions().get(threadId) === abortController) { - this.manualCompactions().delete(threadId); - } - } - } - - turnInterruptProduct(params = {}) { - const threadId = String(params.threadId ?? ''); - if (String(params.turnId ?? '').startsWith('dsh-maintenance-compaction-')) { - const active = this.manualCompactions().get(threadId); - if (active) { - active.abort(new Error('user cancelled DSH compaction')); - return { result: {} }; - } - } - return super.turnInterrupt(params); - } - - async threadResume(params = {}) { - if (!params.threadId) throw new Error('thread/resume requires threadId'); - const threadId = String(params.threadId); - let controller = this.controllers.get(threadId); - if (!controller) { - const live = this.driver.getLive(threadId); - const handle = live - ? { agent: live, dispose: async () => {} } - : await this.driver.resume(threadId); - controller = this.installController(handle); - } - const agent = controller.agent; - if (params.cwd != null && path.resolve(params.cwd) !== path.resolve(agent.session.header?.cwd ?? this.cwd)) { - throw new Error('DSHX does not override a persisted DSH session cwd during resume'); - } - await this.applyModelOverride(agent, params); - await this.applyStartPermissions(agent, params); - const result = this.threadResponse(agent, { - includeTurns: params.excludeTurns !== true - }); - const replay = persistedTokenUsageNotification({ - ctx: this.ctx, - session: agent.session, - threadId - }); - return { - result, - afterResponse: replay ? () => this.send(replay) : undefined - }; - } - - async forkSourceEvents(sourceId) { - const live = this.controllers.get(sourceId)?.agent ?? this.driver.getLive(sourceId); - if (live?.session) return live.session.events ?? []; - const inspected = await this.driver.inspectSession(sourceId); - if (!inspected) throw new Error(`Unknown DSH session: ${sourceId}`); - return inspected.events ?? []; - } - - async threadFork(params = {}) { - const sourceId = String(params.threadId ?? ''); - if (!sourceId) throw new Error('thread/fork requires threadId'); - if (params.path != null) throw new Error('DSHX forks DSH sessions by threadId, not Codex rollout paths'); - if (params.deferGoalContinuation === true) { - throw new Error('DSH has no Codex thread-goal continuation state for DSHX to defer'); - } - if (params.ephemeral === true) { - throw new Error('DSHX does not expose ephemeral Codex forks over durable DSH sessions'); - } - - const events = await this.forkSourceEvents(sourceId); - const atSeq = codexForkAtSeq(events, { - lastTurnId: params.lastTurnId, - beforeTurnId: params.beforeTurnId - }); - const forked = await this.hostApi().forkSession({ sessionId: sourceId, atSeq }); - const childId = String(forked?.sessionId ?? ''); - if (!childId) throw new Error('DSH Host fork returned no child session id'); - - const childAgent = this.driver.getLive(childId); - if (!childAgent) throw new Error(`DSH Host fork did not publish child Agent ${childId}`); - this.driver.adoptExternalSelection(childAgent, { - select: (selection) => this.hostApi().selectModel({ sessionId: childId, ...selection }) - }); - const controller = this.installController({ agent: childAgent, dispose: async () => {} }); - const result = this.threadResponse(controller.agent, { - includeTurns: params.excludeTurns !== true - }); - return { - result, - afterResponse: () => this.send({ method: 'thread/started', params: { thread: result.thread } }) - }; - } - - historyController(threadId) { - const controller = this.controllers.get(String(threadId ?? '')); - if (!controller) { - throw new Error(`Thread must be resumed before paginated DSH history is rendered: ${String(threadId ?? '')}`); - } - return controller; - } - - threadTurnsList(params = {}) { - const controller = this.historyController(params.threadId); - return { - result: dshThreadTurnsPage({ - controller, - params, - diagnostics: this.diagnostics - }) - }; - } - - threadItemsList(params = {}) { - const controller = this.historyController(params.threadId); - return { - result: dshThreadItemsPage({ - controller, - params, - diagnostics: this.diagnostics - }) - }; - } - - async threadUnsubscribeWithStatus(params = {}) { - const threadId = String(params.threadId ?? ''); - this.manualCompactions().get(threadId)?.abort(new Error('thread unsubscribed')); - const subscribed = this.controllers.has(threadId); - const loaded = Boolean(this.driver.getLive(threadId)); - await super.threadUnsubscribe(params); - return { - result: { - status: subscribed ? 'unsubscribed' : loaded ? 'notSubscribed' : 'notLoaded' - } - }; - } - - async saveDefaultModelSelection(selection) { - const defaults = this.ctx.get('agentDefaultModel'); - if (!defaults?.saveSelection) { - this.diagnostics('DSH agentDefaultModel service has no saveSelection(); current session selection remains valid but deployment default was not persisted'); - return; - } - await defaults.saveSelection({ - provider: selection.provider, - model: selection.model, - ...(selection.reasoningEffort == null ? {} : { reasoningEffort: selection.reasoningEffort }) - }); - } - - async threadSettingsUpdate(params = {}) { - const threadId = String(params.threadId ?? ''); - const controller = this.controllers.get(threadId); - if (!controller) throw new Error(`Thread is not resumed in DSHX: ${threadId}`); - const agent = controller.agent; - - if (params.cwd != null) { - const currentCwd = path.resolve(agent.session.header?.cwd ?? this.cwd); - if (path.resolve(params.cwd) !== currentCwd) { - throw new Error('DSHX does not retarget a live DSH session cwd from the TUI'); - } - } - if (params.sandboxPolicy != null) { - throw new Error('DSHX changes permissions through DSH named permission presets, not Codex legacy sandboxPolicy'); - } - if (params.serviceTier !== undefined) { - throw new Error('DSH has no public thread service-tier setter for DSHX to project'); - } - if (params.summary != null) { - throw new Error('DSH has no equivalent public reasoning-summary thread setting'); - } - if (params.personality != null) { - throw new Error('DSH has no equivalent public personality thread setting'); - } - if (params.approvalsReviewer != null && params.approvalsReviewer !== 'user') { - throw new Error('DSH approval review is user-owned; DSHX cannot select a Codex-specific reviewer'); - } - - const supported = hasSupportedThreadSetting(params); - if (params.collaborationMode != null && !supported) { - throw new Error('DSH has no equivalent public collaboration-mode thread setting'); - } - - if (params.permissions != null || params.approvalPolicy != null) { - await this.applyStartPermissions(agent, { - permissions: params.permissions, - approvalPolicy: params.approvalPolicy - }); - } - if (params.model != null || params.effort != null) { - const selection = await this.applyModelOverride(agent, { - model: params.model, - effort: params.effort - }); - await this.saveDefaultModelSelection(selection); - } - - return { result: {} }; - } - - turnSteer(params = {}) { - const threadId = String(params.threadId ?? ''); - const controller = this.controllers.get(threadId); - if (!controller) throw new Error(`Thread is not resumed in DSHX: ${threadId}`); - const location = controller.currentLocation(); - if (!location) throw new Error(`Thread has no active DSH turn to steer: ${threadId}`); - if (typeof params.expectedTurnId !== 'string' || params.expectedTurnId !== location.turnId) { - throw new Error( - `DSHX steer expectedTurnId ${JSON.stringify(params.expectedTurnId)} does not match active DSH turn ${location.turnId}` - ); - } - controller.steer(textInput(params)); - return { result: { turnId: location.turnId } }; - } - - async close() { - for (const controller of this.manualCompactions().values()) { - controller.abort(new Error('DSHX adapter closing')); - } - this.manualCompactions().clear(); - await super.close(); - } -} diff --git a/src/dsh/release-adapter.mjs b/src/dsh/release-adapter.mjs deleted file mode 100644 index 3694a17e..00000000 --- a/src/dsh/release-adapter.mjs +++ /dev/null @@ -1,437 +0,0 @@ -import path from 'node:path'; -import { decodeDshModel, dshThreadFromSnapshot, normalizeCodexEffort } from './codex-shapes.mjs'; -import { DshxProductAdapter } from './product-adapter.mjs'; -import { codexPlanTarget, threadSettingsUpdatedNotification } from './plan-presentation.mjs'; -import { foldDshSessionTitle, threadNameUpdatedNotification } from './thread-title.mjs'; -import { codexInputToDshContent, dshContentText } from './user-input.mjs'; -import { DshUserShellBridge } from './user-shell.mjs'; -import { DshWorkspaceCommandBridge } from './workspace-command.mjs'; - -function snapshotTitle(snapshot) { - return typeof snapshot?.title === 'string' && snapshot.title.length > 0 ? snapshot.title : null; -} - -function isDshSubagent(agent) { - return agent?.session?.header?.origin === 'subagent'; -} - -/** - * Final product-facing protocol tail. Keep small metadata/UI compatibility - * extensions here so the core DSH public adapter remains stable and auditable. - */ -export class DshxReleaseAdapter extends DshxProductAdapter { - async ensureReady() { - await super.ensureReady(); - if (this._agentPresentationDisposers) return; - this._agentPresentationDisposers = [ - this.ctx.on('agent/created', ({ agent }) => { - if (!isDshSubagent(agent)) return; - try { - this.send({ method: 'thread/started', params: { thread: this.liveAgentThread(agent) } }); - } catch (error) { - this.diagnostics(`subagent thread/started projection failed for ${String(agent?.id ?? '')}: ${error instanceof Error ? error.message : error}`); - } - }), - this.ctx.on('agent/status', ({ agent, status }) => { - try { - this.send({ - method: 'thread/status/changed', - params: { - threadId: String(agent.id), - status: status === 'running' ? { type: 'active', activeFlags: [] } : { type: 'idle' } - } - }); - } catch (error) { - this.diagnostics(`agent status projection failed for ${String(agent?.id ?? '')}: ${error instanceof Error ? error.message : error}`); - } - }), - this.ctx.on('agent/disposed', ({ agent }) => { - try { - this.send({ - method: 'thread/status/changed', - params: { threadId: String(agent.id), status: { type: 'notLoaded' } } - }); - } catch (error) { - this.diagnostics(`agent disposal projection failed for ${String(agent?.id ?? '')}: ${error instanceof Error ? error.message : error}`); - } - }) - ]; - } - - userShell() { - return this._userShell ??= new DshUserShellBridge({ - send: this.send, - diagnostics: this.diagnostics - }); - } - - workspaceCommands() { - return this._workspaceCommands ??= new DshWorkspaceCommandBridge({ driver: this.driver }); - } - - planListeners() { - return this._planListeners ??= new Map(); - } - - planMutationSuppressed() { - return this._planMutationSuppressed ??= new Set(); - } - - planMode(agent) { - const service = agent?.ctx?.get?.('planMode') ?? this.ctx.get('planMode'); - if (!service?.set || !service?.get) throw new Error('DSHX requires DSH service: planMode'); - return service; - } - - planSettingsNotification(agent) { - const response = this.threadResponse(agent); - return threadSettingsUpdatedNotification({ - threadId: String(agent.id), - response, - planState: this.planMode(agent).get(agent) - }); - } - - liveAgentThread(agent) { - const thread = dshThreadFromSnapshot({ - meta: agent.session.header, - events: agent.session.events ?? [], - model: agent.session.requestHeader?.()?.config, - loaded: true, - cliVersion: this.version - }); - const title = snapshotTitle(this.driver.currentTitle(agent)) ?? foldDshSessionTitle(agent.session.events ?? []); - return { - ...thread, - status: agent.status === 'running' ? { type: 'active', activeFlags: [] } : { type: 'idle' }, - name: title, - turns: [] - }; - } - - loadedThreadList() { - // Pinned Codex ThreadLoadedListResponse.data is Array. Keep rich - // thread metadata on thread/list/read/started and expose only live IDs here. - return { - result: { - data: this.driver.listLive().map((agent) => String(agent.id)) - } - }; - } - - directController(threadId, operation) { - const controller = this.controllers.get(String(threadId ?? '')); - if (!controller) throw new Error(`Thread is not resumed in DSHX: ${String(threadId ?? '')}`); - if (isDshSubagent(controller.agent)) { - throw new Error(`DSHX refuses ${operation} on a DSH subagent; child runtime control remains owned by ctx.subagents`); - } - return controller; - } - - async interruptSubagent(controller) { - const parentSessionId = controller.agent.session.header?.parentSession; - if (parentSessionId == null) throw new Error('DSH subagent is missing durable parentSession authority'); - const subagents = this.ctx.get('subagents'); - if (!subagents?.interrupt) throw new Error('DSHX requires DSH service: subagents.interrupt'); - await subagents.interrupt(String(controller.agent.id), { - kind: 'user', - parentSessionId: String(parentSessionId) - }); - return { result: {} }; - } - - installController(handle) { - const controller = super.installController(handle); - const threadId = String(controller.agent.id); - if (!this.planListeners().has(threadId)) { - const dispose = controller.agent.ctx.on('session/event', (session, event) => { - if (session !== controller.agent.session || event?.type !== 'plan/mode') return; - if (this.planMutationSuppressed().has(threadId)) return; - try { - this.send(this.planSettingsNotification(controller.agent)); - } catch (error) { - this.diagnostics(`plan settings projection failed for ${threadId}: ${error instanceof Error ? error.message : error}`); - } - }); - this.planListeners().set(threadId, dispose); - } - return controller; - } - - async dispatch(method, params) { - switch (method) { - case 'command/exec': - return this.commandExec(params); - case 'config/batchWrite': - return this.configBatchWrite(params); - case 'thread/loaded/list': - return this.loadedThreadList(); - case 'thread/fork': - return this.threadForkPresentation(params); - case 'thread/name/set': - return this.threadNameSet(params); - case 'thread/settings/update': - return this.threadSettingsUpdatePresentation(params); - case 'thread/shellCommand': - return this.threadShellCommand(params); - case 'thread/compact/start': - this.directController(params?.threadId, 'direct compaction'); - return super.dispatch(method, params); - case 'turn/start': - case 'turn/steer': - return this.richUserTurn(method, params); - case 'turn/interrupt': { - if (this.userShell().interrupt(params?.threadId, params?.turnId)) return { result: {} }; - const controller = this.controllers.get(String(params?.threadId ?? '')); - if (controller && isDshSubagent(controller.agent)) return this.interruptSubagent(controller); - return super.dispatch(method, params); - } - case 'thread/unsubscribe': { - const threadId = String(params?.threadId ?? ''); - this.userShell().abortThread(threadId, 'thread unsubscribed'); - this.planListeners().get(threadId)?.(); - this.planListeners().delete(threadId); - this.planMutationSuppressed().delete(threadId); - return super.dispatch(method, params); - } - default: - return super.dispatch(method, params); - } - } - - async commandExec(params = {}) { - return { result: await this.workspaceCommands().execute(params) }; - } - - async configBatchWrite(params = {}) { - const edits = Array.isArray(params.edits) ? params.edits : []; - if (edits.length === 0) throw new Error('DSHX config/batchWrite requires at least one model-selection edit'); - - const supported = new Set(['model', 'model_reasoning_effort']); - for (const edit of edits) { - if (!supported.has(edit?.keyPath)) { - throw new Error(`DSHX config/batchWrite refuses Codex-owned setting: ${String(edit?.keyPath ?? '')}`); - } - if (edit?.mergeStrategy != null && edit.mergeStrategy !== 'replace') { - throw new Error(`DSHX config/batchWrite supports replace semantics only: ${String(edit.keyPath)}`); - } - } - - const defaults = this.ctx.get('agentDefaultModel'); - const llm = this.ctx.get('llm'); - if (!defaults?.currentSelection || !defaults?.saveSelection) { - throw new Error('DSHX requires DSH service: agentDefaultModel.saveSelection'); - } - if (!llm?.resolveCallConfig) throw new Error('DSHX requires DSH service: llm.resolveCallConfig'); - - const current = defaults.currentSelection(); - let requested = { provider: current.provider, model: current.model }; - if (current.reasoningEffort !== undefined) requested.reasoningEffort = current.reasoningEffort; - - const modelEdit = edits.find((edit) => edit.keyPath === 'model'); - if (modelEdit) { - const decoded = decodeDshModel(modelEdit.value); - if (!decoded) throw new Error('DSHX persists default models only from its DSH-backed opaque model catalog'); - requested = { ...decoded }; - } - - const effortEdit = edits.find((edit) => edit.keyPath === 'model_reasoning_effort'); - if (effortEdit) { - const effort = effortEdit.value == null ? undefined : normalizeCodexEffort(effortEdit.value); - requested = { provider: requested.provider, model: requested.model }; - if (effort !== undefined) requested.reasoningEffort = effort; - } - - const resolved = await llm.resolveCallConfig(requested); - const persisted = { provider: resolved.provider, model: resolved.model }; - // Preserve provider-default semantics when the TUI clears its reasoning - // setting; otherwise persist the DSH-resolved explicit effort. - if (requested.reasoningEffort !== undefined) { - persisted.reasoningEffort = resolved.reasoningEffort ?? requested.reasoningEffort; - } - await defaults.saveSelection(persisted); - - this._configRevision = (this._configRevision ?? 0) + 1; - return { - result: { - status: 'ok', - version: `dshx-${this._configRevision}`, - // Codex requires an absolute path in ConfigWriteResponse. Persistence is - // actually owned by DSH settings; this marker stays inside presentation home. - filePath: path.join(this.home, 'dsh-settings'), - overriddenMetadata: null - } - }; - } - - async richUserTurn(method, params = {}) { - const threadId = String(params.threadId ?? ''); - const controller = this.controllers.get(threadId); - if (!controller) return super.dispatch(method, params); - if (isDshSubagent(controller.agent)) { - throw new Error(`DSHX refuses ${method} on a DSH subagent; send/steer authority remains owned by ctx.subagents`); - } - const content = await codexInputToDshContent(this.ctx, params.input ?? []); - const clear = controller.prepareUserContent(content); - try { - // Pinned Codex serializes an unset reasoning effort as JSON null. DSH - // interprets absence as provider default, so never forward null as an - // explicit provider effort. - const normalizedParams = params.effort == null ? { ...params, effort: undefined } : params; - // Preserve the original base/product validation path. The fallback text is - // consumed only if no prepared rich content exists; it also keeps the - // base adapter's expected text-only parameter shape intact. - return await super.dispatch(method, { - ...normalizedParams, - input: [{ type: 'text', text: dshContentText(content) }] - }); - } finally { - clear(); - } - } - - threadResponse(agent, options = {}) { - const response = super.threadResponse(agent, options); - const folded = this.driver.currentTitle(agent); - const name = snapshotTitle(folded) ?? foldDshSessionTitle(agent.session?.events ?? []); - return { - ...response, - thread: { ...response.thread, name } - }; - } - - async threadResume(params = {}) { - const response = await super.threadResume(params); - const threadId = String(params.threadId ?? response.result.thread?.id ?? ''); - const agent = this.controllers.get(threadId)?.agent; - const prior = response.afterResponse; - return { - ...response, - afterResponse: () => { - prior?.(); - if (agent) this.send(this.planSettingsNotification(agent)); - } - }; - } - - async threadForkPresentation(params = {}) { - const response = await super.threadFork(params); - const startedThread = { ...response.result.thread, turns: [] }; - const agent = this.controllers.get(String(response.result.thread.id))?.agent; - return { - ...response, - // Pinned Codex emits copied history only in the fork response. The - // thread/started notification introduces metadata/live state and must not - // replay those copied turns a second time before paginated hydration. - afterResponse: () => { - this.send({ - method: 'thread/started', - params: { thread: startedThread } - }); - if (agent) this.send(this.planSettingsNotification(agent)); - } - }; - } - - async threadSettingsUpdatePresentation(params = {}) { - const threadId = String(params.threadId ?? ''); - const controller = this.controllers.get(threadId); - if (controller && isDshSubagent(controller.agent)) { - throw new Error('DSHX refuses direct model/permission/plan changes on a DSH subagent; composition remains DSH-owned'); - } - if (params.collaborationMode == null) return super.threadSettingsUpdate(params); - if (!controller) throw new Error(`Thread is not resumed in DSHX: ${threadId}`); - const active = codexPlanTarget(params.collaborationMode); - const { collaborationMode: _ignored, ...ordinary } = params; - - // Let the existing DSH-backed settings adapter validate/apply every other - // supported field. The collaboration payload's model/reasoning/instructions - // are intentionally not treated as DSH model or prompt configuration. - await super.threadSettingsUpdate(ordinary); - - this.planMutationSuppressed().add(threadId); - try { - await this.planMode(controller.agent).set(controller.agent, active); - } finally { - this.planMutationSuppressed().delete(threadId); - } - - return { - result: {}, - afterResponse: () => this.send(this.planSettingsNotification(controller.agent)) - }; - } - - async threadList(params = {}) { - const response = await super.threadList(params); - const data = await Promise.all(response.result.data.map(async (thread) => { - try { - const snapshot = await this.driver.readTitle(thread.id); - return { ...thread, name: snapshotTitle(snapshot) ?? thread.name ?? null }; - } catch (error) { - this.diagnostics(`title read ${thread.id}: ${error instanceof Error ? error.message : error}`); - return thread; - } - })); - return { result: { ...response.result, data } }; - } - - async threadRead(params = {}) { - const response = await super.threadRead(params); - const thread = response.result.thread; - try { - const snapshot = await this.driver.readTitle(thread.id); - return { - result: { - ...response.result, - thread: { ...thread, name: snapshotTitle(snapshot) ?? thread.name ?? null } - } - }; - } catch (error) { - this.diagnostics(`title read ${thread.id}: ${error instanceof Error ? error.message : error}`); - return response; - } - } - - threadShellCommand(params = {}) { - const controller = this.directController(params.threadId, 'direct shell execution'); - return this.userShell().start(controller, params.command); - } - - async threadNameSet(params = {}) { - const threadId = String(params.threadId ?? ''); - if (!threadId) throw new Error('thread/name/set requires threadId'); - if (typeof params.name !== 'string') throw new Error('thread/name/set requires name'); - - let temporaryHandle; - let agent = this.controllers.get(threadId)?.agent ?? this.driver.getLive(threadId); - if (!agent) { - temporaryHandle = await this.driver.resume(threadId); - agent = temporaryHandle.agent; - } - - try { - const snapshot = this.driver.renameTitle(agent, params.name); - const threadName = snapshotTitle(snapshot); - if (threadName == null) throw new Error('DSH sessionTitle.rename returned no accepted title'); - return { - result: {}, - afterResponse: () => this.send(threadNameUpdatedNotification(threadId, threadName)) - }; - } finally { - await temporaryHandle?.dispose?.(); - } - } - - async close() { - this._userShell?.close(); - for (const dispose of this._agentPresentationDisposers ?? []) dispose?.(); - this._agentPresentationDisposers = []; - for (const dispose of this.planListeners().values()) dispose?.(); - this.planListeners().clear(); - this.planMutationSuppressed().clear(); - await super.close(); - } -} - -export const releaseAdapterInternals = { snapshotTitle, isDshSubagent }; \ No newline at end of file diff --git a/test/dsh-app-server-adapter.test.mjs b/test/dsh-app-server-adapter.test.mjs index 0717e4de..18ea26cb 100644 --- a/test/dsh-app-server-adapter.test.mjs +++ b/test/dsh-app-server-adapter.test.mjs @@ -1,6 +1,6 @@ import assert from 'node:assert/strict'; import test from 'node:test'; -import { DshAppServerAdapter } from '../src/dsh/app-server-adapter.mjs'; +import { DshxPresentationAdapter } from '../src/dsh/presentation-adapter.mjs'; import { decodeDshModel } from '../src/dsh/codex-shapes.mjs'; function fixture() { @@ -17,7 +17,12 @@ function fixture() { }; const services = {}; - const rootCtx = { get(name) { return services[name]; } }; + // The unified presentation adapter registers release-layer agent lifecycle + // listeners during ensureReady, so the fake context must accept `on`. + const rootCtx = { + get(name) { return services[name]; }, + on() { return () => {}; } + }; function requestHeader(session) { for (let index = session.events.length - 1; index >= 0; index -= 1) { @@ -206,7 +211,7 @@ function fixture() { roots() { return [...live.values()]; } }; - const adapter = new DshAppServerAdapter({ + const adapter = new DshxPresentationAdapter({ ctx: rootCtx, send: (message) => sent.push(message), cwd: '/workspace', diff --git a/test/dsh-compaction-projection.test.mjs b/test/dsh-compaction-projection.test.mjs index 459945e8..028881cf 100644 --- a/test/dsh-compaction-projection.test.mjs +++ b/test/dsh-compaction-projection.test.mjs @@ -1,7 +1,7 @@ import assert from 'node:assert/strict'; import test from 'node:test'; import { dshTurnsFromSession } from '../src/dsh/codex-shapes.mjs'; -import { DshxProductAdapter } from '../src/dsh/product-adapter.mjs'; +import { DshxPresentationAdapter } from '../src/dsh/presentation-adapter.mjs'; import { DshSessionProjector } from '../src/dsh/session-projector.mjs'; const event = (type, data, time, seq = 0) => ({ type, data, time, seq }); @@ -79,7 +79,7 @@ test('resumed human transcript keeps shadowed history and adds one compaction ma }); test('thread/compact/start delegates to the official DSH command plane and reports a no-op result', async () => { - const adapter = Object.create(DshxProductAdapter.prototype); + const adapter = Object.create(DshxPresentationAdapter.prototype); const warnings = []; adapter.send = (message) => warnings.push(message); adapter.diagnostics = () => {}; @@ -114,7 +114,7 @@ test('thread/compact/start delegates to the official DSH command plane and repor }); test('synthetic compaction turn interrupt aborts only the tracked official DSH operation', () => { - const adapter = Object.create(DshxProductAdapter.prototype); + const adapter = Object.create(DshxPresentationAdapter.prototype); const abort = new AbortController(); adapter._manualCompactions = new Map([['session-1', abort]]); const result = adapter.turnInterruptProduct({ diff --git a/test/dsh-domain-delegation.test.mjs b/test/dsh-domain-delegation.test.mjs index 5e1b8902..5b6db0bc 100644 --- a/test/dsh-domain-delegation.test.mjs +++ b/test/dsh-domain-delegation.test.mjs @@ -1,9 +1,9 @@ import assert from 'node:assert/strict'; import test from 'node:test'; -import { DshxProductAdapter } from '../src/dsh/product-adapter.mjs'; +import { DshxPresentationAdapter } from '../src/dsh/presentation-adapter.mjs'; function bareAdapter() { - const adapter = Object.create(DshxProductAdapter.prototype); + const adapter = Object.create(DshxPresentationAdapter.prototype); adapter.cwd = '/workspace'; adapter.controllers = new Map(); adapter.diagnostics = () => {}; diff --git a/test/dsh-product-adapter.test.mjs b/test/dsh-product-adapter.test.mjs index d748a81d..bfdb80b4 100644 --- a/test/dsh-product-adapter.test.mjs +++ b/test/dsh-product-adapter.test.mjs @@ -1,10 +1,10 @@ import assert from 'node:assert/strict'; import path from 'node:path'; import test from 'node:test'; -import { DshxProductAdapter } from '../src/dsh/product-adapter.mjs'; +import { DshxPresentationAdapter } from '../src/dsh/presentation-adapter.mjs'; function bareAdapter() { - const adapter = Object.create(DshxProductAdapter.prototype); + const adapter = Object.create(DshxPresentationAdapter.prototype); adapter.cwd = path.resolve('/workspace'); adapter.diagnostics = () => {}; adapter.controllers = new Map(); diff --git a/test/dsh-product-fork.test.mjs b/test/dsh-product-fork.test.mjs index e6271e92..18d56770 100644 --- a/test/dsh-product-fork.test.mjs +++ b/test/dsh-product-fork.test.mjs @@ -1,6 +1,6 @@ import assert from 'node:assert/strict'; import test from 'node:test'; -import { DshxProductAdapter } from '../src/dsh/product-adapter.mjs'; +import { DshxPresentationAdapter } from '../src/dsh/presentation-adapter.mjs'; function sourceAgent() { return { @@ -16,7 +16,7 @@ function sourceAgent() { } function adapterFixture({ cold = false } = {}) { - const adapter = Object.create(DshxProductAdapter.prototype); + const adapter = Object.create(DshxPresentationAdapter.prototype); adapter.controllers = new Map(); adapter.send = () => {}; const source = sourceAgent(); diff --git a/test/dsh-product-resume.test.mjs b/test/dsh-product-resume.test.mjs index 4e2e115f..654e5fe3 100644 --- a/test/dsh-product-resume.test.mjs +++ b/test/dsh-product-resume.test.mjs @@ -1,9 +1,9 @@ import assert from 'node:assert/strict'; import test from 'node:test'; -import { DshxProductAdapter } from '../src/dsh/product-adapter.mjs'; +import { DshxPresentationAdapter } from '../src/dsh/presentation-adapter.mjs'; function adapterFixture() { - const adapter = Object.create(DshxProductAdapter.prototype); + const adapter = Object.create(DshxPresentationAdapter.prototype); adapter.cwd = process.cwd(); adapter.controllers = new Map(); adapter.driver = { getLive() { return undefined; } }; diff --git a/test/dsh-rc5-acceptance-regressions.test.mjs b/test/dsh-rc5-acceptance-regressions.test.mjs index 1a4321f3..89c0c007 100644 --- a/test/dsh-rc5-acceptance-regressions.test.mjs +++ b/test/dsh-rc5-acceptance-regressions.test.mjs @@ -1,10 +1,10 @@ import assert from 'node:assert/strict'; import test from 'node:test'; import { encodeDshModel } from '../src/dsh/codex-shapes.mjs'; -import { DshxReleaseAdapter } from '../src/dsh/release-adapter.mjs'; +import { DshxPresentationAdapter } from '../src/dsh/presentation-adapter.mjs'; test('thread/loaded/list returns thread ids rather than thread maps', () => { - const adapter = Object.create(DshxReleaseAdapter.prototype); + const adapter = Object.create(DshxPresentationAdapter.prototype); adapter.driver = { listLive() { return [{ id: 'root-1' }, { id: 'child-2' }]; } }; @@ -16,7 +16,7 @@ test('thread/loaded/list returns thread ids rather than thread maps', () => { test('config/batchWrite delegates model defaults to official DSH persistence', async () => { const saved = []; const resolved = []; - const adapter = Object.create(DshxReleaseAdapter.prototype); + const adapter = Object.create(DshxPresentationAdapter.prototype); adapter.home = '/tmp/dshx-presentation'; adapter.ctx = { get(name) { @@ -61,7 +61,7 @@ test('config/batchWrite delegates model defaults to official DSH persistence', a }); test('rich user turn strips Codex null effort before the DSH-owned base path', async () => { - const adapter = Object.create(DshxReleaseAdapter.prototype); + const adapter = Object.create(DshxPresentationAdapter.prototype); const agent = { session: { header: { origin: 'user' } } }; adapter.controllers = new Map([['thread-1', { agent, @@ -69,29 +69,25 @@ test('rich user turn strips Codex null effort before the DSH-owned base path', a }]]); adapter.ctx = { get() { return undefined; } }; - const product = Object.getPrototypeOf(DshxReleaseAdapter.prototype); - const originalDispatch = product.dispatch; + // The flattened richUserTurn routes the DSH-owned base path directly to the + // most-derived turnStart; stub that seam to observe what gets forwarded. let forwarded; - product.dispatch = async (method, params) => { - forwarded = { method, params }; + adapter.turnStart = async (params) => { + forwarded = params; return { result: {} }; }; - try { - await adapter.richUserTurn('turn/start', { - threadId: 'thread-1', - effort: null, - input: [{ type: 'text', text: 'hello', text_elements: [] }] - }); - } finally { - product.dispatch = originalDispatch; - } + await adapter.richUserTurn('turn/start', { + threadId: 'thread-1', + effort: null, + input: [{ type: 'text', text: 'hello', text_elements: [] }] + }); - assert.equal(forwarded.method, 'turn/start'); - assert.equal(forwarded.params.effort, undefined); + assert.equal(forwarded.effort, undefined); + assert.deepEqual(forwarded.input, [{ type: 'text', text: 'hello' }]); }); test('config/batchWrite fails closed on Codex-owned settings', async () => { - const adapter = Object.create(DshxReleaseAdapter.prototype); + const adapter = Object.create(DshxPresentationAdapter.prototype); adapter.home = '/tmp/dshx-presentation'; adapter.ctx = { get() { return undefined; } }; await assert.rejects( diff --git a/test/dsh-release-title.test.mjs b/test/dsh-release-title.test.mjs index b0dd5a3d..4e47edde 100644 --- a/test/dsh-release-title.test.mjs +++ b/test/dsh-release-title.test.mjs @@ -1,6 +1,6 @@ import assert from 'node:assert/strict'; import test from 'node:test'; -import { DshxReleaseAdapter } from '../src/dsh/release-adapter.mjs'; +import { DshxPresentationAdapter } from '../src/dsh/presentation-adapter.mjs'; import { foldDshSessionTitle } from '../src/dsh/thread-title.mjs'; test('durable title fold is latest-wins over DSH session/title events', () => { @@ -13,7 +13,7 @@ test('durable title fold is latest-wins over DSH session/title events', () => { }); test('thread/name/set delegates loaded rename to DSH and notifies only after RPC response', async () => { - const adapter = Object.create(DshxReleaseAdapter.prototype); + const adapter = Object.create(DshxPresentationAdapter.prototype); const sent = []; const agent = { id: 'session-1', session: { events: [] } }; adapter.controllers = new Map([['session-1', { agent }]]); @@ -38,7 +38,7 @@ test('thread/name/set delegates loaded rename to DSH and notifies only after RPC }); test('cold thread/name/set uses official DSH resume only for mutation lifetime', async () => { - const adapter = Object.create(DshxReleaseAdapter.prototype); + const adapter = Object.create(DshxPresentationAdapter.prototype); const agent = { id: 'session-2', session: { events: [] } }; let disposed = 0; adapter.controllers = new Map(); @@ -61,7 +61,7 @@ test('cold thread/name/set uses official DSH resume only for mutation lifetime', }); test('live thread response always carries latest DSH title', () => { - const adapter = Object.create(DshxReleaseAdapter.prototype); + const adapter = Object.create(DshxPresentationAdapter.prototype); const agent = { id: 'session-1', session: { events: [{ type: 'session/title', data: { title: 'Log title' } }] } @@ -73,41 +73,37 @@ test('live thread response always carries latest DSH title', () => { } }; adapter.permissions = { current() { return { preset: 'workspace-write' }; } }; - Object.getPrototypeOf(DshxReleaseAdapter.prototype).threadResponse = () => { - throw new Error('test should stub through product prototype explicitly'); - }; - - const product = Object.getPrototypeOf(DshxReleaseAdapter.prototype); - const original = product.threadResponse; - product.threadResponse = () => ({ thread: { id: 'session-1', name: null } }); + // Stub the product-layer seam so only the release-layer title fold under + // test runs on top of a controlled response. + const originalProductLayer = DshxPresentationAdapter.prototype.threadResponseProductLayer; + DshxPresentationAdapter.prototype.threadResponseProductLayer = () => ({ thread: { id: 'session-1', name: null } }); try { const response = adapter.threadResponse(agent); assert.equal(response.thread.name, 'Folded service title'); } finally { - product.threadResponse = original; + DshxPresentationAdapter.prototype.threadResponseProductLayer = originalProductLayer; } }); test('thread list and read enrich cold metadata with sessionQuery title snapshots', async () => { - const adapter = Object.create(DshxReleaseAdapter.prototype); + const adapter = Object.create(DshxPresentationAdapter.prototype); adapter.diagnostics = () => {}; adapter.driver = { async readTitle(id) { return { title: `Title ${id}` }; } }; - const product = Object.getPrototypeOf(DshxReleaseAdapter.prototype); - const originalList = product.threadList; - const originalRead = product.threadRead; - product.threadList = async () => ({ + const baseList = DshxPresentationAdapter.prototype.threadListBase; + const baseRead = DshxPresentationAdapter.prototype.threadReadBase; + DshxPresentationAdapter.prototype.threadListBase = async () => ({ result: { data: [{ id: 'a', name: null }, { id: 'b', name: null }], nextCursor: null, backwardsCursor: null } }); - product.threadRead = async () => ({ result: { thread: { id: 'a', name: null } } }); + DshxPresentationAdapter.prototype.threadReadBase = async () => ({ result: { thread: { id: 'a', name: null } } }); try { const listed = await adapter.threadList({}); assert.deepEqual(listed.result.data.map((thread) => thread.name), ['Title a', 'Title b']); const read = await adapter.threadRead({ threadId: 'a' }); assert.equal(read.result.thread.name, 'Title a'); } finally { - product.threadList = originalList; - product.threadRead = originalRead; + DshxPresentationAdapter.prototype.threadListBase = baseList; + DshxPresentationAdapter.prototype.threadReadBase = baseRead; } }); diff --git a/test/dsh-subagent-authority.test.mjs b/test/dsh-subagent-authority.test.mjs index a48b1538..624327b7 100644 --- a/test/dsh-subagent-authority.test.mjs +++ b/test/dsh-subagent-authority.test.mjs @@ -1,6 +1,6 @@ import assert from 'node:assert/strict'; import test from 'node:test'; -import { DshxReleaseAdapter } from '../src/dsh/release-adapter.mjs'; +import { DshxPresentationAdapter } from '../src/dsh/presentation-adapter.mjs'; function childController() { let cancelled = 0; @@ -21,7 +21,7 @@ function childController() { function adapterWithChild() { const { controller, cancelled } = childController(); - const adapter = Object.create(DshxReleaseAdapter.prototype); + const adapter = Object.create(DshxPresentationAdapter.prototype); adapter.controllers = new Map([['child-1', controller]]); adapter.diagnostics = () => {}; return { adapter, controller, cancelled }; diff --git a/test/dsh-subagent-presentation.test.mjs b/test/dsh-subagent-presentation.test.mjs index 3555ffa6..5ed6bd24 100644 --- a/test/dsh-subagent-presentation.test.mjs +++ b/test/dsh-subagent-presentation.test.mjs @@ -1,7 +1,7 @@ import assert from 'node:assert/strict'; import test from 'node:test'; import { dshThreadFromSnapshot } from '../src/dsh/codex-shapes.mjs'; -import { DshxReleaseAdapter } from '../src/dsh/release-adapter.mjs'; +import { DshxPresentationAdapter } from '../src/dsh/presentation-adapter.mjs'; function childAgent() { return { @@ -66,7 +66,7 @@ test('release loaded-thread wire response lists official DSH live ids while rich } }; const child = childAgent(); - const adapter = Object.create(DshxReleaseAdapter.prototype); + const adapter = Object.create(DshxPresentationAdapter.prototype); adapter.version = 'test'; adapter.driver = { listLive() { return [root, child]; }, From 1cccbde4da0474cb4eccb898e1070cb2e880f4f5 Mon Sep 17 00:00:00 2001 From: code-new-bie <245316967+code-new-bie@users.noreply.github.com> Date: Tue, 25 Aug 2026 21:24:53 +0800 Subject: [PATCH 02/60] refactor: move development-only PoC transport into devtools/ src/protocol.mjs (deterministic protocol PoC), src/server.mjs (TCP WebSocket stub) and the TCP stub entry leave the production source tree for devtools/. bin/dshx-stub-local.mjs stays: it drives real-TUI smoke through the production local-IPC topology. Packaging already shipped only bin/dshx.mjs + src/cli + src/dsh + src/protocol(dir), so artifacts are unchanged; the production src tree no longer carries dead protocol code. --- bin/dshx-stub-local.mjs | 2 +- {bin => devtools}/dshx-stub-server.mjs | 2 +- src/protocol.mjs => devtools/protocol-poc.mjs | 0 src/server.mjs => devtools/stub-server.mjs | 2 +- package.json | 2 +- test/protocol.test.mjs | 2 +- test/wire.test.mjs | 2 +- 7 files changed, 6 insertions(+), 6 deletions(-) rename {bin => devtools}/dshx-stub-server.mjs (87%) rename src/protocol.mjs => devtools/protocol-poc.mjs (100%) rename src/server.mjs => devtools/stub-server.mjs (99%) diff --git a/bin/dshx-stub-local.mjs b/bin/dshx-stub-local.mjs index 5750a9c4..a43b56a2 100644 --- a/bin/dshx-stub-local.mjs +++ b/bin/dshx-stub-local.mjs @@ -1,7 +1,7 @@ #!/usr/bin/env node import fs from 'node:fs'; import { startDshxLocalServer } from '../src/dsh/local-server.mjs'; -import { ProtocolStub, normalizeDispatchResult } from '../src/protocol.mjs'; +import { ProtocolStub, normalizeDispatchResult } from '../devtools/protocol-poc.mjs'; const delayMs = Number(process.env.DSHX_STUB_EVENT_DELAY_MS || 18); const traceFile = process.env.DSHX_STUB_TRACE_FILE; diff --git a/bin/dshx-stub-server.mjs b/devtools/dshx-stub-server.mjs similarity index 87% rename from bin/dshx-stub-server.mjs rename to devtools/dshx-stub-server.mjs index 0ae2602a..1870e9f1 100644 --- a/bin/dshx-stub-server.mjs +++ b/devtools/dshx-stub-server.mjs @@ -1,5 +1,5 @@ #!/usr/bin/env node -import { startProtocolStubServer } from '../src/server.mjs'; +import { startProtocolStubServer } from './stub-server.mjs'; const token = process.env.DSHX_STUB_TOKEN || undefined; const server = await startProtocolStubServer({ diff --git a/src/protocol.mjs b/devtools/protocol-poc.mjs similarity index 100% rename from src/protocol.mjs rename to devtools/protocol-poc.mjs diff --git a/src/server.mjs b/devtools/stub-server.mjs similarity index 99% rename from src/server.mjs rename to devtools/stub-server.mjs index ad4b3fdf..20231389 100644 --- a/src/server.mjs +++ b/devtools/stub-server.mjs @@ -1,6 +1,6 @@ import crypto from 'node:crypto'; import { WebSocketServer } from 'ws'; -import { ProtocolStub, normalizeDispatchResult } from './protocol.mjs'; +import { ProtocolStub, normalizeDispatchResult } from './protocol-poc.mjs'; const DEFAULT_HOST = '127.0.0.1'; const DEFAULT_EVENT_DELAY_MS = 18; diff --git a/package.json b/package.json index 12a63b79..4a2df68e 100644 --- a/package.json +++ b/package.json @@ -15,7 +15,7 @@ "test:dsh": "node --test --test-force-exit \"test/dsh-*.test.mjs\"", "freeze:deps": "node scripts/freeze-deps.mjs", "verify:release-deps": "node scripts/verify-dsh-closure.mjs . package-lock.json", - "stub": "node ./bin/dshx-stub-server.mjs", + "stub": "node ./devtools/dshx-stub-server.mjs", "dev": "node ./bin/dshx.mjs" }, "dependencies": { diff --git a/test/protocol.test.mjs b/test/protocol.test.mjs index af88e639..0bc6a245 100644 --- a/test/protocol.test.mjs +++ b/test/protocol.test.mjs @@ -1,7 +1,7 @@ import assert from 'node:assert/strict'; import path from 'node:path'; import test from 'node:test'; -import { ProtocolStub, normalizeDispatchResult } from '../src/protocol.mjs'; +import { ProtocolStub, normalizeDispatchResult } from '../devtools/protocol-poc.mjs'; function request(stub, id, method, params = {}) { return normalizeDispatchResult(stub, { id, method, params }); diff --git a/test/wire.test.mjs b/test/wire.test.mjs index 9ced428a..40d2e52f 100644 --- a/test/wire.test.mjs +++ b/test/wire.test.mjs @@ -1,7 +1,7 @@ import assert from 'node:assert/strict'; import test from 'node:test'; import { WebSocket } from 'ws'; -import { startProtocolStubServer } from '../src/server.mjs'; +import { startProtocolStubServer } from '../devtools/stub-server.mjs'; function openSocket(url) { return new Promise((resolve, reject) => { From b93f74caf961804a0edf065b3f4536a3c7b6da65 Mon Sep 17 00:00:00 2001 From: code-new-bie <245316967+code-new-bie@users.noreply.github.com> Date: Tue, 25 Aug 2026 21:37:39 +0800 Subject: [PATCH 03/60] feat: mount the presentation lifetime as a Cordis-contract plugin Add src/dsh/presentation-plugin.mjs exporting the official plugin shape (name / inject / Config / apply, named exports only): it starts the packaged bridge + adapter transport against the already-booted composition Context, publishes the endpoint as the dshxPresentation service, and returns transport disposal to the Cordis root Fiber. bootDshxPresentationRuntime() mounts that plugin through the Cordis dynamic-plugin API; bin/dshx now consumes the provided service instead of driving local-server imperatively, and root-fiber disposal stays the sole teardown authority (transport close no longer disposes the runtime when mounted as a plugin). The surface lock moves from hardcoded arrays in runtime-boot to the declarative cordis.patch.yml bundle patch, loaded through DSH's own optional-patch loader and failing closed when missing. --- bin/dshx.mjs | 45 ++++++++++++--- cordis.patch.yml | 19 +++++++ scripts/verify-ownership-boundary.mjs | 12 +++- src/dsh/local-server.mjs | 16 ++++-- src/dsh/presentation-plugin.mjs | 73 ++++++++++++++++++++++++ src/dsh/runtime-boot.mjs | 78 ++++++++++++++++++++++---- test/dshx-presentation-plugin.test.mjs | 66 ++++++++++++++++++++++ 7 files changed, 283 insertions(+), 26 deletions(-) create mode 100644 cordis.patch.yml create mode 100644 src/dsh/presentation-plugin.mjs create mode 100644 test/dshx-presentation-plugin.test.mjs diff --git a/bin/dshx.mjs b/bin/dshx.mjs index 518bc714..6d512736 100755 --- a/bin/dshx.mjs +++ b/bin/dshx.mjs @@ -247,9 +247,9 @@ async function run() { return; } - let startDshxLocalServer; + let bootDshxPresentationRuntime; try { - ({ startDshxLocalServer } = await import('../src/dsh/local-server.mjs')); + ({ bootDshxPresentationRuntime } = await import('../src/dsh/runtime-boot.mjs')); } catch (error) { process.stderr.write(`dshx: failed to load official DeepSeek Harness runtime: ${error instanceof Error ? error.message : error}\n`); process.exitCode = 1; @@ -282,20 +282,47 @@ async function run() { const debug = process.env.DSHX_DEBUG === '1'; const log = debug ? (message) => process.stderr.write(`[dshx] ${message}\n`) : () => {}; - let local; + let ctx; try { - local = await startDshxLocalServer({ + // The official composition mounts the dshx-presentation Cordis plugin, + // which owns the bridge + adapter transport and publishes the endpoint + // as the `dshxPresentation` service. + ctx = await bootDshxPresentationRuntime({ cwd: process.cwd(), - home: tuiHome, + presentationHome: tuiHome, version: VERSION, bridgeCommand: bridge, - log + debug }); } catch (error) { process.stderr.write(`dshx: failed to boot DeepSeek Harness/local IPC: ${error instanceof Error ? error.message : error}\n`); process.exitCode = 1; return; } + const presentation = ctx.get('dshxPresentation'); + if (!presentation || typeof presentation.close !== 'function') { + process.stderr.write('dshx: presentation composition mounted without the dshxPresentation service\n'); + try { await ctx.dispose?.(); } catch { /* primary failure already reported */ } + process.exitCode = 1; + return; + } + + // Transport teardown first, then the official root Fiber (which unwinds the + // plugin whose disposer re-enters the memoized transport close as a no-op). + const closePresentation = async () => { + let primaryError; + try { + await presentation.close(); + } catch (error) { + primaryError = error; + } + try { + await ctx.dispose?.(); + } catch (error) { + primaryError ??= error; + } + if (primaryError) throw primaryError; + }; let child; try { @@ -307,7 +334,7 @@ async function run() { // component only and must not read/write the user's ordinary Codex state. CODEX_HOME: tuiHome, ...invocation.resumeEnv, - DSHX_APP_SERVER_ENDPOINT: local.url + DSHX_APP_SERVER_ENDPOINT: presentation.url }, stdio: 'inherit', windowsHide: false @@ -315,7 +342,7 @@ async function run() { } catch (error) { process.stderr.write(`dshx: failed to launch pinned Codex TUI: ${error instanceof Error ? error.message : error}\n`); try { - await local.close(); + await closePresentation(); } catch (cleanupError) { if (debug) process.stderr.write(`[dshx] startup cleanup: ${cleanupError instanceof Error ? cleanupError.message : cleanupError}\n`); } @@ -328,7 +355,7 @@ async function run() { if (closing) return; closing = true; try { - await local.close(); + await closePresentation(); } catch (error) { process.stderr.write(`dshx: shutdown cleanup failed: ${error instanceof Error ? error.message : error}\n`); if (exitCode === 0) exitCode = 1; diff --git a/cordis.patch.yml b/cordis.patch.yml new file mode 100644 index 00000000..300ea95d --- /dev/null +++ b/cordis.patch.yml @@ -0,0 +1,19 @@ +# The DSHX surface bundle patch, riding over the official DSH headless +# profile. Loaded through DSH's own optional-patch loader by +# src/dsh/runtime-boot.mjs, after the profile bundle layers and both +# user-owned patch layers. +# +# Only the competing presentation rows are locked off; every runtime +# capability row remains user-authoritative. The presentation runner itself +# mounts in-process through bootDshxPresentationRuntime() using the Cordis +# dynamic plugin API (see src/dsh/presentation-plugin.mjs). Once this package +# resolves from a profile node_modules under its scoped npm name, the +# documented insert row below becomes the canonical declaration: +# +# - insert: +# - id: dshx-presentation +# name: '@code-new-bie/dshx-tui/presentation' +- id: headless-startup + disabled: true +- id: headless-runner + disabled: true diff --git a/scripts/verify-ownership-boundary.mjs b/scripts/verify-ownership-boundary.mjs index 3bd8840b..cf30e748 100644 --- a/scripts/verify-ownership-boundary.mjs +++ b/scripts/verify-ownership-boundary.mjs @@ -29,12 +29,20 @@ requireText('src/dsh/runtime-boot.mjs', "from '@deepseek-ai/dsh-app-boot'"); requireText('src/dsh/runtime-boot.mjs', "const DEFAULT_PROFILE = 'headless'"); requireText('src/dsh/runtime-boot.mjs', 'loadProfile('); requireText('src/dsh/runtime-boot.mjs', 'composeEntries('); -requireText('src/dsh/runtime-boot.mjs', "{ id: 'headless-startup', disabled: true }"); -requireText('src/dsh/runtime-boot.mjs', "{ id: 'headless-runner', disabled: true }"); requireText('src/dsh/runtime-boot.mjs', 'ctx = await boot('); requireText('src/dsh/runtime-boot.mjs', 'profile.layers.flatMap((layer) => layer.patches)'); requireText('src/dsh/runtime-boot.mjs', 'profile.patches'); requireText('src/dsh/runtime-boot.mjs', 'homePatches'); +// The surface lock lives in a declarative bundle patch loaded through DSH's +// own optional-patch loader; a missing lock set must fail closed. +requireText('cordis.patch.yml', 'id: headless-startup'); +requireText('cordis.patch.yml', 'id: headless-runner'); +requireText('src/dsh/runtime-boot.mjs', 'loadOptionalPatches('); +requireText('src/dsh/runtime-boot.mjs', 'refusing to boot with competing presentation surfaces'); +// The presentation lifetime mounts as a Cordis-contract plugin row. +requireText('src/dsh/presentation-plugin.mjs', 'export const name'); +requireText('src/dsh/presentation-plugin.mjs', 'ctx.provide(SERVICE_KEY'); +requireText('src/dsh/runtime-boot.mjs', 'bootDshxPresentationRuntime'); // Presentation lifetime may adapt the Context shape, but teardown must remain // delegated to Cordis/DSH root-fiber ownership rather than a DSHX runtime. requireText('src/dsh/runtime-boot.mjs', 'ctx.fiber.dispose()'); diff --git a/src/dsh/local-server.mjs b/src/dsh/local-server.mjs index 35b8239e..d66153b3 100644 --- a/src/dsh/local-server.mjs +++ b/src/dsh/local-server.mjs @@ -191,7 +191,8 @@ export async function startDshxLocalServer({ bridgeCommand = packagedBridgeBinary(), bridgeArgs, spawnBridge = spawn, - socketRoot + socketRoot, + disposeRuntimeOnClose = true } = {}) { const rendezvousRoot = path.resolve(socketRoot ?? defaultSocketRoot({ home })); let socketDirectory; @@ -320,10 +321,15 @@ export async function startDshxLocalServer({ capture('bridge cleanup failed', error); } - try { - await ctx?.dispose?.(); - } catch (error) { - capture('DSH dispose failed', error); + // When mounted as the dshx-presentation Cordis plugin, root-fiber + // disposal stays owned by the composition; only the transport closes + // here and the Fiber unwinds the plugin afterwards. + if (disposeRuntimeOnClose) { + try { + await ctx?.dispose?.(); + } catch (error) { + capture('DSH dispose failed', error); + } } if (socketDirectory) { diff --git a/src/dsh/presentation-plugin.mjs b/src/dsh/presentation-plugin.mjs new file mode 100644 index 00000000..d9f2d570 --- /dev/null +++ b/src/dsh/presentation-plugin.mjs @@ -0,0 +1,73 @@ +import z from '@deepseek-ai/schemastery'; +import { startDshxLocalServer } from './local-server.mjs'; + +/** + * Cordis plugin wrapping the DSHX presentation lifetime. + * + * The plugin owns the production local-IPC transport: it boots nothing itself + * (the official DSH composition is already mounted on the injected Context), + * starts the packaged bridge + JSONL stdio relay against that Context, and + * publishes the resulting endpoint as the `dshxPresentation` service. Disposal + * returns the transport closer; teardown authority remains the Cordis root + * Fiber, matching the official plugin contract (name / inject / Config / + * apply, named exports only). + */ + +/** Stable Cordis plugin name. */ +export const name = 'dshx-presentation'; + +/** + * No hard service injections on purpose: every DSH capability is consumed + * lazily through ctx.get so an absent optional service degrades the matching + * UI instead of blocking the whole composition. + */ +export const inject = []; + +/** Serializable launch configuration for the presentation transport. */ +export const Config = z.object({ + cwd: z.string(), + home: z.string(), + version: z.string(), + bridgeCommand: z.string(), + socketRoot: z.string(), + debug: z.boolean() +}); + +/** Service key published on the Context after the endpoint is ready. */ +export const SERVICE_KEY = 'dshxPresentation'; + +/** Test seam mirroring the official packages' `internals` convention. */ +export const internals = { start: startDshxLocalServer }; + +export async function apply(ctx, config = {}) { + if (!ctx || typeof ctx.provide !== 'function') { + throw new Error('dshx-presentation requires a Cordis Context with provide()'); + } + const debug = config.debug === true; + const log = debug ? (message) => process.stderr.write(`[dshx] ${message}\n`) : () => {}; + + const server = await internals.start({ + cwd: config.cwd, + home: config.home, + version: config.version, + bridgeCommand: config.bridgeCommand, + socketRoot: config.socketRoot, + // The composition Context already exists; never double-boot. Root-fiber + // disposal stays owned by the caller/fiber, so the transport must not + // dispose the runtime it lives in (double teardown would re-enter the + // Fiber from inside its own disposer). + runtime: ctx, + disposeRuntimeOnClose: false, + log + }); + + ctx.provide(SERVICE_KEY, { + path: server.path, + url: server.url, + close: server.close + }); + return server.close; +} + +/** Bundle-shaped export consumed by runtime-boot's dynamic mount. */ +export const plugin = { name, inject, Config, apply }; diff --git a/src/dsh/runtime-boot.mjs b/src/dsh/runtime-boot.mjs index 44ad800b..a4c5a9a4 100644 --- a/src/dsh/runtime-boot.mjs +++ b/src/dsh/runtime-boot.mjs @@ -1,7 +1,7 @@ import { writeFileSync } from 'node:fs'; import { createRequire } from 'node:module'; import { dirname, join } from 'node:path'; -import { pathToFileURL } from 'node:url'; +import { fileURLToPath, pathToFileURL } from 'node:url'; import { boot, composeEntries, @@ -13,6 +13,7 @@ import { watchUserPatches } from '@deepseek-ai/dsh-app-boot'; import { DSH_LAUNCH_ENVIRONMENT_KEY } from '@deepseek-ai/dsh-launch-environment'; +import { plugin as dshxPresentationPlugin } from './presentation-plugin.mjs'; const NAME = 'dshx'; const DSH_PROFILE_BIN_NAME = 'dsh'; @@ -24,13 +25,33 @@ const PROFILE_ROOT_FILENAME = 'cordis.yml'; // Rewriting this empty root on every boot is intentional DSH behavior and // prevents Loader tree write-back from becoming a second persisted config. const PROFILE_ROOT_CONFIG = `# DSHX uses the same empty profile root contract as the official dsh launcher.\n# The effective tree is composed from DSH bundle and patch layers.\n# Edit cordis.patch.yml, not this file.\n[]\n`; -const DSHX_SURFACE_PATCHES = [ - // The official headless profile is the default because it is the DSH runtime - // without a browser surface. Its one-shot CLI startup/runner are themselves - // presentation rows, so DSHX replaces only those two rows with Codex TUI. - { id: 'headless-startup', disabled: true }, - { id: 'headless-runner', disabled: true } -]; +// The DSHX surface bundle patch rides over the official profile layers as a +// declarative artifact loaded through DSH's own optional-patch loader. +const DSHX_PATCH_FILENAME = 'cordis.patch.yml'; + +function ownPackageRoot() { + // /src/dsh/runtime-boot.mjs → . The depth matches both the + // source checkout and the staged release layout. + return dirname(dirname(dirname(fileURLToPath(import.meta.url)))); +} + +function bundlePatchPath() { + return join(ownPackageRoot(), DSHX_PATCH_FILENAME); +} + +/** + * Load the declarative DSHX surface locks from the shipped cordis.patch.yml. + * The file is the single source of truth for which official presentation rows + * this surface replaces; a missing or empty lock set fails closed so a broken + * package can never boot with a competing runner still enabled. + */ +function bundleSurfacePatches() { + const patches = loadOptionalPatches(DSH_PROFILE_BIN_NAME, bundlePatchPath()); + if (!patches || patches.length === 0) { + throw new Error('dshx: cordis.patch.yml is missing or empty; refusing to boot with competing presentation surfaces enabled'); + } + return patches; +} function installationAnchor() { return createRequire(import.meta.url).resolve('@deepseek-ai/dsh/package.json'); @@ -102,7 +123,7 @@ export function dshxRuntimeProfile({ ...structuredClone(overlays), // Last on purpose: DSH user/profile configuration owns capabilities, but // cannot re-enable a competing presentation runner in the DSHX process. - ...structuredClone(DSHX_SURFACE_PATCHES) + ...structuredClone(bundleSurfacePatches()) ]; return { @@ -217,13 +238,50 @@ export async function bootDshxRuntime({ } } +/** + * Boot the official composition and mount the DSHX presentation plugin on it. + * Production `dshx` entry path: once the packaged bridge reports readiness, + * the transport endpoint is available as the ctx service `dshxPresentation`. + */ +export async function bootDshxPresentationRuntime({ + cwd = process.cwd(), + presentationHome, + version, + bridgeCommand, + socketRoot, + debug = false, + ...bootOptions +} = {}) { + const ctx = await bootDshxRuntime({ cwd, ...bootOptions }); + let mounted = false; + try { + await ctx.plugin(dshxPresentationPlugin, { + cwd, + home: presentationHome, + version, + bridgeCommand, + socketRoot, + debug + }); + mounted = true; + } finally { + if (!mounted) { + try { + await disposeOfficialContext(ctx); + } catch {} + } + } + return ctx; +} + export const runtimeInternals = { NAME, DSH_PROFILE_BIN_NAME, DEFAULT_PROFILE, PROFILE_ROOT_FILENAME, PROFILE_ROOT_CONFIG, - DSHX_SURFACE_PATCHES, + DSHX_SURFACE_PATCHES: bundleSurfacePatches(), + bundlePatchPath, installationAnchor, selectedProfile, profileHome, diff --git a/test/dshx-presentation-plugin.test.mjs b/test/dshx-presentation-plugin.test.mjs new file mode 100644 index 00000000..9916f8b2 --- /dev/null +++ b/test/dshx-presentation-plugin.test.mjs @@ -0,0 +1,66 @@ +import assert from 'node:assert/strict'; +import { readFileSync } from 'node:fs'; +import test from 'node:test'; +import { fileURLToPath } from 'node:url'; +import { name, inject, Config, plugin, internals, SERVICE_KEY } from '../src/dsh/presentation-plugin.mjs'; + +test('exports the Cordis plugin contract with named exports only', () => { + assert.equal(name, 'dshx-presentation'); + assert.deepEqual(inject, []); + // Schemastery schemas are callable validators. + assert.equal(typeof Config, 'function'); + assert.equal(plugin.name, name); + assert.deepEqual(plugin.inject, inject); + assert.equal(plugin.Config, Config); + assert.equal(typeof plugin.apply, 'function'); + assert.equal(typeof SERVICE_KEY, 'string'); + + const source = readFileSync(fileURLToPath(new URL('../src/dsh/presentation-plugin.mjs', import.meta.url)), 'utf8'); + assert.match(source, /export const name/); + assert.match(source, /export const inject/); + assert.match(source, /export const Config/); + assert.match(source, /export async function apply/); + // A stray default export would collapse the module via unwrapExports and + // drop the named contract (see dsh-tool-todo postmortem 0001). + assert.doesNotMatch(source, /export default/); +}); + +test('apply starts the transport against the booted context and provides the service', async () => { + const provided = new Map(); + const ctx = { provide: (key, value) => provided.set(key, value), get: () => undefined }; + const started = []; + let closed = 0; + const originalStart = internals.start; + internals.start = async (options) => { + started.push(options); + return { path: '/tmp/dshx-i/d-XXXX/s', url: 'unix:///tmp/dshx-i/d-XXXX/s', close: async () => { closed += 1; } }; + }; + try { + const dispose = await plugin.apply(ctx, { + cwd: '/workspace', + home: '/home/test/.dshx/codex-tui', + version: 'test', + debug: true + }); + assert.equal(started.length, 1); + assert.equal(started[0].runtime, ctx, 'plugin must never boot a second runtime'); + assert.equal(started[0].disposeRuntimeOnClose, false, 'root-fiber disposal stays owned by the composition'); + assert.equal(started[0].cwd, '/workspace'); + + const service = provided.get(SERVICE_KEY); + assert.equal(service.url, 'unix:///tmp/dshx-i/d-XXXX/s'); + assert.equal(typeof service.close, 'function'); + + await dispose(); + assert.equal(closed, 1, 'the returned disposer closes the transport exactly once'); + } finally { + internals.start = originalStart; + } +}); + +test('apply refuses contexts without the Cordis provide() service seam', async () => { + await assert.rejects( + () => plugin.apply({ get: () => undefined }, {}), + /requires a Cordis Context with provide/ + ); +}); From 5158d731fe90efd6dd23a0d5253e1c94ecb68b7d Mon Sep 17 00:00:00 2001 From: code-new-bie <245316967+code-new-bie@users.noreply.github.com> Date: Tue, 25 Aug 2026 21:40:32 +0800 Subject: [PATCH 04/60] docs: sync runtime integration with the plugin-mounted surface Topology and launcher lifecycle now describe the dshx-presentation Cordis plugin row, the declarative cordis.patch.yml surface lock, and the devtools/ location of the development-only protocol fixtures. --- docs/RUNTIME-INTEGRATION.md | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/docs/RUNTIME-INTEGRATION.md b/docs/RUNTIME-INTEGRATION.md index f095a383..fbcf01a4 100644 --- a/docs/RUNTIME-INTEGRATION.md +++ b/docs/RUNTIME-INTEGRATION.md @@ -17,6 +17,7 @@ The official runtime owns Agent creation/resume, Session persistence, model sele ┌──────────────────────────────────────────┐ │ dshx Node launcher │ │ - boots official DSH composition │ +│ - mounts dshx-presentation plugin row │ │ - owns child-process lifetime only │ └────────────────────┬─────────────────────┘ │ @@ -25,6 +26,9 @@ The official runtime owns Agent creation/resume, Session persistence, model sele ┌──────────────────────────────────────────┐ │ DSHX presentation adapter │ │ - Codex protocol projection only │ +│ - mounted as the dshx-presentation │ +│ Cordis plugin (name/inject/Config/ │ +│ apply), disposed by the root Fiber │ └────────────────────┬─────────────────────┘ │ JSONL / child stdio ▼ @@ -59,12 +63,12 @@ Therefore production does not depend on Codex's experimental TCP WebSocket remot 1. Resolve and validate the packaged `dshx-tui` and `dshx-ipc-bridge` binaries. 2. Create an isolated presentation-only `CODEX_HOME` under `~/.dshx/codex-tui` (or the development override). -3. Boot the supported official DSH composition in Node. +3. Boot the official DSH composition in Node and mount the `dshx-presentation` Cordis plugin on it; the plugin starts the local transport and publishes the endpoint as the `dshxPresentation` service. Surface locks load from the declarative `cordis.patch.yml` bundle patch through DSH's own patch loader. 4. Create a private temporary socket directory. 5. Spawn `dshx-ipc-bridge`, wait for its readiness control message, and expose the resulting `unix://` endpoint to the TUI. 6. Spawn the pinned Codex TUI with `DSHX_APP_SERVER_ENDPOINT` set to that local endpoint. 7. Relay app-server JSON between the TUI and the DSH presentation adapter while DSH remains authoritative for all runtime state. -8. On TUI exit or process shutdown, close presentation state, dispose DSH, terminate the bridge and remove the temporary socket directory. +8. On TUI exit or process shutdown, close the transport, then dispose the official Context whose root Fiber unwinds the presentation plugin and removes the temporary socket directory. Ctrl+C is intentionally not intercepted by the Node launcher because it is an in-TUI interaction used to interrupt/steer the active DSH turn. Process `SIGTERM` is propagated for lifecycle shutdown. @@ -93,7 +97,7 @@ The test suite contains ownership guards for these boundaries. Missing official ## Development-only transport -The historical deterministic protocol PoC and TCP/WebSocket stub remain useful test fixtures for protocol work, but they are not copied into the installable production package. The `ws` dependency is development-only. +The historical deterministic protocol PoC (`devtools/protocol-poc.mjs`) and TCP/WebSocket stub (`devtools/stub-server.mjs`) remain useful test fixtures for protocol work, but they live outside the production `src/` tree and are not copied into the installable production package. The `ws` dependency is development-only. The real TUI smoke test uses `bin/dshx-stub-local.mjs`, which drives the deterministic fixture through the same packaged local-IPC bridge as production. From 82a7dad64726d521ec077c62f9df41cbb154ac44 Mon Sep 17 00:00:00 2001 From: code-new-bie <245316967+code-new-bie@users.noreply.github.com> Date: Wed, 26 Aug 2026 11:19:23 +0800 Subject: [PATCH 05/60] test: make runtime-smoke timeouts environment-overridable CI-grade disks boot the composition well inside the hardcoded 20s/10s; slow checkouts such as a WSL /mnt/c mount do not. DSHX_SMOKE_BOOT_TIMEOUT_MS and DSHX_SMOKE_DISPOSE_TIMEOUT_MS now raise the bounds without touching the script; defaults are unchanged. --- scripts/runtime-smoke.mjs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/scripts/runtime-smoke.mjs b/scripts/runtime-smoke.mjs index 0c1e3f1c..75b931be 100644 --- a/scripts/runtime-smoke.mjs +++ b/scripts/runtime-smoke.mjs @@ -23,6 +23,11 @@ const REQUIRED_SERVICES = [ 'planMode' ]; +// CI-grade disks boot well inside these defaults; slow checkouts (for example +// a WSL /mnt/c mount) can raise them without touching the script. +const BOOT_TIMEOUT_MS = Number(process.env.DSHX_SMOKE_BOOT_TIMEOUT_MS ?? 20_000); +const DISPOSE_TIMEOUT_MS = Number(process.env.DSHX_SMOKE_DISPOSE_TIMEOUT_MS ?? 10_000); + function withTimeout(promise, timeoutMs, label) { let timer; return Promise.race([ @@ -39,7 +44,7 @@ try { process.stdout.write('booting official DSH composition with production patch watchers enabled\n'); ctx = await withTimeout( bootDshxRuntime({ cwd: process.cwd(), watch: true }), - 20_000, + BOOT_TIMEOUT_MS, 'official DSH composition boot' ); process.stdout.write('official DSH composition boot completed\n'); @@ -59,7 +64,7 @@ try { if (ctx) { process.stdout.write('disposing official DSH composition\n'); try { - await withTimeout(Promise.resolve(ctx.dispose?.()), 10_000, 'official DSH composition disposal'); + await withTimeout(Promise.resolve(ctx.dispose?.()), DISPOSE_TIMEOUT_MS, 'official DSH composition disposal'); process.stdout.write('official DSH composition disposed\n'); } catch (disposeError) { if (!primaryError) primaryError = disposeError; From a75582396be9fcaff9ea85ec8a66ca382735d4c0 Mon Sep 17 00:00:00 2001 From: code-new-bie <245316967+code-new-bie@users.noreply.github.com> Date: Wed, 26 Aug 2026 12:36:12 +0800 Subject: [PATCH 06/60] feat!: deliver DSHX as a real DSH profile bundle (@code-new-bie/dshx-tui) The package now declares dsh.bundle.patch -> ./cordis.patch.yml, whose insert rows mount the surface through the official loader: - dshx-startup resolves env/packaged defaults, provides dshxStartup - dshx-presentation injects dshxStartup, hosts the local IPC transport, publishes dshxPresentation, returns the disposer The imperative mounting channel is gone: no ctx.plugin() call, no launcher-owned patch file, and boot() drops its bareModuleBaseUrl anchor so row names resolve from the profile directory exactly like the official CLI (the healed profiles/node_modules fallback covers in-box packages). bin/dshx becomes a thin bootstrap over official machinery: it ensures the selected profile carries this exact package version via 'dsh plugin --profile

add ' (idempotent), boots the composition, and spawns the TUI against the provided endpoint; root-fiber disposal owns teardown. doctor gains a 'Surface profile' gate and counts the two row services among its required services. Runtime host services move to peerDependencies (dual-listed for dev); only leaf parser libs stay dependencies, preserving the single-instance rule that keeps profile installs from shadowing healed symlinks. scripts/verify-bundle-install.mjs proves the full chain end to end with real tooling: npm pack -> dsh plugin add into a temp DSH_HOME -> --dump-config row assertions -> loader activation with live transport -> no stateful-runtime shadowing. --- bin/dshx.mjs | 259 +- cordis.patch.yml | 29 +- package-lock.json | 16098 ++++++++++++----------- package.json | 35 +- scripts/package-platform.mjs | 15 +- scripts/verify-bundle-install.mjs | 210 + scripts/verify-dsh-closure.mjs | 6 +- scripts/verify-ownership-boundary.mjs | 35 +- src/dsh/index.mjs | 25 + src/dsh/presentation-plugin.mjs | 56 +- src/dsh/runtime-boot.mjs | 94 +- src/dsh/startup-plugin.mjs | 72 + test/dsh-runtime-boot.test.mjs | 105 +- test/dshx-presentation-plugin.test.mjs | 101 +- 14 files changed, 9033 insertions(+), 8107 deletions(-) create mode 100644 scripts/verify-bundle-install.mjs create mode 100644 src/dsh/index.mjs create mode 100644 src/dsh/startup-plugin.mjs diff --git a/bin/dshx.mjs b/bin/dshx.mjs index 6d512736..a0b0e5d2 100755 --- a/bin/dshx.mjs +++ b/bin/dshx.mjs @@ -33,35 +33,15 @@ const REQUIRED_RUNTIME_SERVICES = [ 'approval', 'userQuestions', 'skills', - 'planMode' + 'planMode', + // The surface rows themselves: their services exist only when the loader + // activated the bundle patch (dshx-startup / dshx-presentation). + 'dshxStartup', + 'dshxPresentation' ]; function usage() { - return `DSHX ${VERSION}\n\nUsage:\n dshx Start DSHX in the current project\n dshx Start with an initial prompt\n dshx resume Open the Codex-style DSH session picker\n dshx resume --last Resume the most recent DSH session\n dshx resume Resume a specific DSH session\n dshx doctor Check packaged TUI, local IPC and official DSH composition\n dshx --version Print version\n dshx --help Show this help\n\nEnvironment:\n DSHX_TUI_BIN Override the packaged DSHX TUI binary (development only)\n DSHX_IPC_BRIDGE_BIN Override the packaged local IPC bridge (development only)\n DSHX_TUI_HOME Override DSHX presentation-only Codex home (development only)\n DSHX_DEBUG=1 Print DSHX adapter diagnostics\n\nProduct boundary:\n DSHX owns only the launcher, Codex TUI thin fork and presentation adapter.\n DeepSeek Harness remains the authoritative Agent/Session/Tool runtime.\n DSHX never reads or writes the user's ordinary CODEX_HOME.\n`; -} - -function packagedTuiBinary() { - const name = process.platform === 'win32' ? 'dshx-tui.exe' : 'dshx-tui'; - const candidates = [ - process.env.DSHX_TUI_BIN, - path.join(ROOT, 'dist', 'bin', name), - path.join(ROOT, '.build', 'codex', 'release', process.platform === 'win32' ? 'codex-tui.exe' : 'codex-tui') - ].filter(Boolean); - return candidates.find((candidate) => fs.existsSync(candidate)) ?? candidates[0]; -} - -function packagedIpcBridgeBinary() { - const name = process.platform === 'win32' ? 'dshx-ipc-bridge.exe' : 'dshx-ipc-bridge'; - const candidates = [ - process.env.DSHX_IPC_BRIDGE_BIN, - path.join(ROOT, 'dist', 'bin', name), - path.join(ROOT, '.build', 'codex', 'release', name) - ].filter(Boolean); - return candidates.find((candidate) => fs.existsSync(candidate)) ?? candidates[0]; -} - -function dshxTuiHome() { - return path.resolve(process.env.DSHX_TUI_HOME || path.join(os.homedir(), '.dshx', 'codex-tui')); + return `DSHX ${VERSION}\n\nUsage:\n dshx Start DSHX in the current project\n dshx Start with an initial prompt\n dshx resume Open the Codex-style DSH session picker\n dshx resume --last Resume the most recent DSH session\n dshx resume Resume a specific DSH session\n dshx doctor Check packaged TUI, local IPC and official DSH composition\n dshx --version Print version\n dshx --help Show this help\n\nEnvironment:\n DSHX_TUI_BIN Override the packaged DSHX TUI binary (development only)\n DSHX_IPC_BRIDGE_BIN Override the packaged local IPC bridge (development only)\n DSHX_TUI_HOME Override DSHX presentation-only Codex home (development only)\n DSHX_PROFILE Override the DSH profile surface (default: tui)\n DSHX_DEBUG=1 Print DSHX adapter diagnostics\n\nPlugin usage:\n The DSHX surface ships as a standard DSH profile bundle. Manage it through\n the official machinery, e.g.:\n dsh plugin --profile tui add ${PACKAGE.name}\n The zero-argument launcher only bootstraps the same profile via the same\n command, then hands control to the official DSH composition.\n\nProduct boundary:\n DSHX owns only the launcher, Codex TUI thin fork and presentation adapter.\n DeepSeek Harness remains the authoritative Agent/Session/Tool runtime.\n DSHX never reads or writes the user's ordinary CODEX_HOME.\n`; } function commandDetail(command, result) { @@ -80,15 +60,79 @@ function withTimeout(promise, timeoutMs, label) { ]).finally(() => clearTimeout(timer)); } -function presentationHomeCheck(localServerInternals, loadError) { - const home = dshxTuiHome(); +function binaryCandidate(baseName) { + const fileName = process.platform === 'win32' ? `${baseName}.exe` : baseName; + return process.env[baseName === 'dshx-tui' ? 'DSHX_TUI_BIN' : 'DSHX_IPC_BRIDGE_BIN'] + || path.join(ROOT, 'dist', 'bin', fileName); +} + +function dshHome() { + return process.env.DSH_HOME || path.join(os.homedir(), '.dsh'); +} + +/** + * Ensure the selected profile exists and carries this exact package version + * as an activated bundle layer. Uses the official `dsh plugin add` machinery + * (profile auto-init + pnpm forward + bundles reconcile); idempotent. + */ +function ensureProfileInstalled(profileName, runtimeBoot) { + const selected = runtimeBoot.runtimeInternals.selectedProfile(profileName); + const manifestPath = path.join(dshHome(), 'profiles', selected, 'package.json'); + let satisfied = false; + try { + const manifest = JSON.parse(fs.readFileSync(manifestPath, 'utf8')); + const bundles = manifest.dsh?.profile?.bundles ?? []; + const dependencies = manifest.dependencies ?? {}; + satisfied = + dependencies[PACKAGE.name] === VERSION && bundles.includes(PACKAGE.name); + } catch { + // Missing or unreadable manifest: the official command initializes it. + } + if (satisfied) return { profile: selected, action: 'already-installed' }; + + if (process.env.DSHX_SKIP_PROFILE_BOOTSTRAP === '1') { + return { profile: selected, action: 'skipped' }; + } + const result = spawnSync( + 'dsh', + ['plugin', '--profile', selected, 'add', ROOT], + { stdio: 'inherit', shell: process.platform === 'win32' } + ); + if (result.error?.code === 'ENOENT') { + throw new Error( + "official 'dsh' CLI not found on PATH; install DeepSeek Harness to manage the DSHX surface profile" + ); + } + if (result.status !== 0) { + throw new Error(`failed to install ${PACKAGE.name} into profile '${selected}' via dsh plugin add (exit ${result.status})`); + } + return { profile: selected, action: 'installed' }; +} + +async function loadRuntimeModules() { + try { + const runtimeBoot = await import('../src/dsh/runtime-boot.mjs'); + let localServerInternals; + try { + ({ localServerInternals } = await import('../src/dsh/local-server.mjs')); + } catch { + localServerInternals = undefined; + } + return { runtimeBoot, localServerInternals }; + } catch (error) { + return { loadError: error instanceof Error ? error.message : String(error) }; + } +} + +function presentationHomeCheck(localServerInternals) { + const home = path.resolve(process.env.DSHX_TUI_HOME || path.join(os.homedir(), '.dshx', 'codex-tui')); try { fs.mkdirSync(home, { recursive: true, mode: 0o700 }); const stat = fs.statSync(home); if (!stat.isDirectory()) throw new Error('path exists but is not a directory'); fs.accessSync(home, fs.constants.R_OK | fs.constants.W_OK); if (!localServerInternals) { - throw new Error(`IPC policy unavailable because DSH modules failed to load: ${loadError}`); + throw new Error('IPC policy unavailable because DSH modules failed to load'); } // On Windows this also enforces that a custom DSHX_TUI_HOME stays below @@ -104,20 +148,18 @@ function presentationHomeCheck(localServerInternals, loadError) { } } -async function officialRuntimeCheck(runtimeBoot, loadError) { - if (typeof runtimeBoot?.bootDshxRuntime !== 'function') { - return { ok: false, detail: `official DSH modules failed to load: ${loadError ?? 'unknown error'}` }; - } - +async function officialRuntimeCheck(runtimeBoot) { let ctx; let primaryError; let cleanupError; try { // Doctor deliberately exercises the same official composition and profile - // watcher path as production startup. This catches missing native optional - // dependencies (for example sharp/koffi) that a static bundle-entry check - // cannot detect. The bounded timeout is intentionally generous enough for - // first-run Windows module/native initialization on supported hardware. + // watcher path as production startup, including the loader-mounted surface + // rows (their services double as row-activation evidence). This catches + // missing native optional dependencies (for example sharp/koffi) that a + // static bundle-entry check cannot detect. The bounded timeout is + // intentionally generous enough for first-run Windows module/native + // initialization on supported hardware. ctx = await withTimeout( runtimeBoot.bootDshxRuntime({ cwd: process.cwd(), watch: true }), DSHX_DOCTOR_BOOT_TIMEOUT_MS, @@ -158,35 +200,34 @@ async function officialRuntimeCheck(runtimeBoot, loadError) { } return { ok: true, - detail: `official DSH composition boot/dispose (${REQUIRED_RUNTIME_SERVICES.length} required services)` + detail: `official DSH composition boot/dispose (${REQUIRED_RUNTIME_SERVICES.length} required services, surface rows active)` }; } -async function doctor() { - const executable = packagedTuiBinary(); - const tuiCheck = executable && fs.existsSync(executable) +async function doctor(runtimeBoot) { + const executable = binaryCandidate('dshx-tui'); + const tuiCheck = fs.existsSync(executable) ? spawnSync(executable, ['--version'], { encoding: 'utf8' }) : { status: 127, stdout: '', stderr: '', error: null }; - const bridge = packagedIpcBridgeBinary(); - const bridgeCheck = bridge && fs.existsSync(bridge) + const bridge = binaryCandidate('dshx-ipc-bridge'); + const bridgeCheck = fs.existsSync(bridge) ? spawnSync(bridge, ['--check'], { encoding: 'utf8' }) : { status: 127, stdout: '', stderr: '', error: null }; - let localServerInternals; - let runtimeBoot; - let runtimeLoadError; + const { localServerInternals } = await loadRuntimeModules(); + const homeCheck = presentationHomeCheck(localServerInternals); + let profileDetail = ''; + let profileOk = true; try { - const [localServer, loadedRuntimeBoot] = await Promise.all([ - import('../src/dsh/local-server.mjs'), - import('../src/dsh/runtime-boot.mjs') - ]); - localServerInternals = localServer.localServerInternals; - runtimeBoot = loadedRuntimeBoot; + const ensured = ensureProfileInstalled(undefined, runtimeBoot); + profileDetail = `profile '${ensured.profile}' (${ensured.action})`; } catch (error) { - runtimeLoadError = error instanceof Error ? error.message : String(error); + profileOk = false; + profileDetail = error instanceof Error ? error.message : String(error); } - const homeCheck = presentationHomeCheck(localServerInternals, runtimeLoadError); - const runtimeCheck = await officialRuntimeCheck(runtimeBoot, runtimeLoadError); + const runtimeCheck = profileOk + ? await officialRuntimeCheck(runtimeBoot) + : { ok: false, detail: `skipped: ${profileDetail}` }; const rows = [ ['Node', `${process.version} (required: ${PACKAGE.engines.node})`, isSupportedNodeVersion(process.versions.node)], @@ -200,6 +241,7 @@ async function doctor() { bridgeCheck.status === 0 ? `${bridge} (cross-platform Codex UDS)` : (bridge ? commandDetail(bridge, bridgeCheck) : 'not found'), bridgeCheck.status === 0 ], + ['Surface profile', profileDetail, profileOk], ['DeepSeek Harness', runtimeCheck.detail, runtimeCheck.ok], ['Presentation home / IPC path', homeCheck.detail, homeCheck.ok] ]; @@ -219,6 +261,7 @@ async function doctor() { async function run() { const args = process.argv.slice(2); let invocation; + try { invocation = parseCliInvocation(args); } catch (error) { @@ -236,7 +279,13 @@ async function run() { return; } if (invocation.kind === 'doctor') { - await doctor(); + const [, runtimeBoot] = await loadRuntimeModules().then((m) => [m.loadError ? undefined : m.runtimeBoot, m.runtimeBoot]); + if (!runtimeBoot) { + process.stderr.write('dshx: failed to load official DeepSeek Harness runtime modules\n'); + process.exitCode = 1; + return; + } + await doctor(runtimeBoot); return; } @@ -247,83 +296,56 @@ async function run() { return; } - let bootDshxPresentationRuntime; + const [, runtimeBoot] = await loadRuntimeModules().then((m) => [m.loadError ? undefined : m.runtimeBoot, m.runtimeBoot]); + if (!runtimeBoot) { + process.stderr.write('dshx: failed to load official DeepSeek Harness runtime modules\n'); + process.exitCode = 1; + return; + } + + const debug = process.env.DSHX_DEBUG === '1'; + let ctx; try { - ({ bootDshxPresentationRuntime } = await import('../src/dsh/runtime-boot.mjs')); + // Bootstrap the surface profile through the official plugin machinery, + // then hand control entirely to the official composition: the loader + // mounts the dshx-startup / dshx-presentation rows declared by the bundle + // patch, and the transport endpoint arrives as a provided service. + ensureProfileInstalled(undefined, runtimeBoot); + ctx = await runtimeBoot.bootDshxRuntime({ cwd: process.cwd(), watch: true }); } catch (error) { - process.stderr.write(`dshx: failed to load official DeepSeek Harness runtime: ${error instanceof Error ? error.message : error}\n`); + process.stderr.write(`dshx: failed to boot DeepSeek Harness surface profile: ${error instanceof Error ? error.message : error}\n`); process.exitCode = 1; return; } - const executable = packagedTuiBinary(); - if (!executable || !fs.existsSync(executable)) { - process.stderr.write(`dshx: packaged TUI binary not found (${executable ?? 'unknown path'})\n`); - process.stderr.write('Run `dshx doctor` for build/install guidance.\n'); - process.exitCode = 127; + const startup = ctx.get('dshxStartup'); + const presentation = ctx.get('dshxPresentation'); + if (!startup || !presentation || typeof presentation.close !== 'function') { + process.stderr.write('dshx: surface rows did not publish dshxStartup/dshxPresentation services\n'); + try { await ctx.dispose?.(); } catch { /* primary failure already reported */ } + process.exitCode = 1; return; } - const bridge = packagedIpcBridgeBinary(); - if (!bridge || !fs.existsSync(bridge)) { - process.stderr.write(`dshx: packaged local IPC bridge not found (${bridge ?? 'unknown path'})\n`); + + const executable = startup.tuiCommand; + if (!executable || !fs.existsSync(executable)) { + process.stderr.write(`dshx: packaged TUI binary not found (${executable ?? 'unknown path'})\n`); process.stderr.write('Run `dshx doctor` for build/install guidance.\n'); + try { await ctx.dispose?.(); } catch { /* ignore secondary */ } process.exitCode = 127; return; } - const tuiHome = dshxTuiHome(); + const tuiHome = startup.home; try { fs.mkdirSync(tuiHome, { recursive: true, mode: 0o700 }); } catch (error) { process.stderr.write(`dshx: cannot create presentation home ${tuiHome}: ${error instanceof Error ? error.message : error}\n`); + try { await ctx.dispose?.(); } catch { /* ignore secondary */ } process.exitCode = 1; return; } - const debug = process.env.DSHX_DEBUG === '1'; - const log = debug ? (message) => process.stderr.write(`[dshx] ${message}\n`) : () => {}; - let ctx; - try { - // The official composition mounts the dshx-presentation Cordis plugin, - // which owns the bridge + adapter transport and publishes the endpoint - // as the `dshxPresentation` service. - ctx = await bootDshxPresentationRuntime({ - cwd: process.cwd(), - presentationHome: tuiHome, - version: VERSION, - bridgeCommand: bridge, - debug - }); - } catch (error) { - process.stderr.write(`dshx: failed to boot DeepSeek Harness/local IPC: ${error instanceof Error ? error.message : error}\n`); - process.exitCode = 1; - return; - } - const presentation = ctx.get('dshxPresentation'); - if (!presentation || typeof presentation.close !== 'function') { - process.stderr.write('dshx: presentation composition mounted without the dshxPresentation service\n'); - try { await ctx.dispose?.(); } catch { /* primary failure already reported */ } - process.exitCode = 1; - return; - } - - // Transport teardown first, then the official root Fiber (which unwinds the - // plugin whose disposer re-enters the memoized transport close as a no-op). - const closePresentation = async () => { - let primaryError; - try { - await presentation.close(); - } catch (error) { - primaryError = error; - } - try { - await ctx.dispose?.(); - } catch (error) { - primaryError ??= error; - } - if (primaryError) throw primaryError; - }; - let child; try { child = spawn(executable, invocation.tuiArgs, { @@ -341,11 +363,7 @@ async function run() { }); } catch (error) { process.stderr.write(`dshx: failed to launch pinned Codex TUI: ${error instanceof Error ? error.message : error}\n`); - try { - await closePresentation(); - } catch (cleanupError) { - if (debug) process.stderr.write(`[dshx] startup cleanup: ${cleanupError instanceof Error ? cleanupError.message : cleanupError}\n`); - } + try { await ctx.dispose?.(); } catch { /* ignore secondary */ } process.exitCode = 127; return; } @@ -355,7 +373,10 @@ async function run() { if (closing) return; closing = true; try { - await closePresentation(); + // Root-fiber disposal unwinds the dshx-presentation plugin, whose + // disposer closes the transport; the Fiber remains the sole teardown + // authority. + await ctx.dispose?.(); } catch (error) { process.stderr.write(`dshx: shutdown cleanup failed: ${error instanceof Error ? error.message : error}\n`); if (exitCode === 0) exitCode = 1; diff --git a/cordis.patch.yml b/cordis.patch.yml index 300ea95d..207743f4 100644 --- a/cordis.patch.yml +++ b/cordis.patch.yml @@ -1,19 +1,24 @@ -# The DSHX surface bundle patch, riding over the official DSH headless -# profile. Loaded through DSH's own optional-patch loader by -# src/dsh/runtime-boot.mjs, after the profile bundle layers and both -# user-owned patch layers. +# The DSHX surface bundle patch, riding over this profile's dsh-base layer. +# Loaded automatically because the package manifest declares +# `dsh.bundle.patch`; the loader applies it in `dsh.profile.bundles` order. # # Only the competing presentation rows are locked off; every runtime -# capability row remains user-authoritative. The presentation runner itself -# mounts in-process through bootDshxPresentationRuntime() using the Cordis -# dynamic plugin API (see src/dsh/presentation-plugin.mjs). Once this package -# resolves from a profile node_modules under its scoped npm name, the -# documented insert row below becomes the canonical declaration: +# capability row remains user-authoritative (a targeted patch replaces a +# row's whole config, and these two carry no config of their own). # -# - insert: -# - id: dshx-presentation -# name: '@code-new-bie/dshx-tui/presentation' +# Launch inputs flow through the official three-stage pattern: the +# dshx-startup row resolves the launcher/environment descriptor and provides +# the `dshxStartup` service; the dshx-presentation row injects it to start +# the local IPC transport and publish the `dshxPresentation` endpoint. - id: headless-startup disabled: true - id: headless-runner disabled: true + +- insert: + - id: dshx-startup + name: '@code-new-bie/dshx-tui/startup' + + - id: dshx-presentation + name: '@code-new-bie/dshx-tui/presentation' + inject: [dshxStartup] diff --git a/package-lock.json b/package-lock.json index 003dc24c..3230e417 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,7796 +1,8302 @@ -{ - "name": "dsh-codex", - "version": "0.0.0-m1", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "dsh-codex", - "version": "0.0.0-m1", - "dependencies": { - "@deepseek-ai/dsh": "0.1.0-rc.8", - "@deepseek-ai/dsh-agent": "0.1.0-rc.8", - "@deepseek-ai/dsh-app-boot": "0.1.0-rc.8", - "@deepseek-ai/dsh-host-apiproxy": "0.1.0-rc.8", - "@deepseek-ai/dsh-launch-environment": "0.1.0-rc.8", - "@deepseek-ai/dsh-llm": "0.1.0-rc.8", - "@deepseek-ai/dsh-session": "0.1.0-rc.8" - }, - "bin": { - "dshx": "bin/dshx.mjs" - }, - "devDependencies": { - "ws": "^8.18.0" - }, - "engines": { - "node": "^22.19.0 || >=24.0.0" - } - }, - "node_modules/@anthropic-ai/sdk": { - "version": "0.91.1", - "resolved": "https://registry.npmmirror.com/@anthropic-ai/sdk/-/sdk-0.91.1.tgz", - "integrity": "sha512-LAmu761tSN9r66ixvmciswUj/ZC+1Q4iAfpedTfSVLeswRwnY3n2Nb6Tsk+cLPP28aLOPWeMgIuTuCcMC6W/iw==", - "license": "MIT", - "dependencies": { - "json-schema-to-ts": "^3.1.1" - }, - "bin": { - "anthropic-ai-sdk": "bin/cli" - }, - "peerDependencies": { - "zod": "^3.25.0 || ^4.0.0" - }, - "peerDependenciesMeta": { - "zod": { - "optional": true - } - } - }, - "node_modules/@aws-crypto/sha256-browser": { - "version": "5.2.0", - "resolved": "https://registry.npmmirror.com/@aws-crypto/sha256-browser/-/sha256-browser-5.2.0.tgz", - "integrity": "sha512-AXfN/lGotSQwu6HNcEsIASo7kWXZ5HYWvfOmSNKDsEqC4OashTp8alTmaz+F7TC2L083SFv5RdB+qU3Vs1kZqw==", - "license": "Apache-2.0", - "dependencies": { - "@aws-crypto/sha256-js": "^5.2.0", - "@aws-crypto/supports-web-crypto": "^5.2.0", - "@aws-crypto/util": "^5.2.0", - "@aws-sdk/types": "^3.222.0", - "@aws-sdk/util-locate-window": "^3.0.0", - "@smithy/util-utf8": "^2.0.0", - "tslib": "^2.6.2" - } - }, - "node_modules/@aws-crypto/sha256-js": { - "version": "5.2.0", - "resolved": "https://registry.npmmirror.com/@aws-crypto/sha256-js/-/sha256-js-5.2.0.tgz", - "integrity": "sha512-FFQQyu7edu4ufvIZ+OadFpHHOt+eSTBaYaki44c+akjg7qZg9oOQeLlk77F6tSYqjDAFClrHJk9tMf0HdVyOvA==", - "license": "Apache-2.0", - "dependencies": { - "@aws-crypto/util": "^5.2.0", - "@aws-sdk/types": "^3.222.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-crypto/supports-web-crypto": { - "version": "5.2.0", - "resolved": "https://registry.npmmirror.com/@aws-crypto/supports-web-crypto/-/supports-web-crypto-5.2.0.tgz", - "integrity": "sha512-iAvUotm021kM33eCdNfwIN//F77/IADDSs58i+MDaOqFrVjZo9bAal0NK7HurRuWLLpF1iLX7gbWrjHjeo+YFg==", - "license": "Apache-2.0", - "dependencies": { - "tslib": "^2.6.2" - } - }, - "node_modules/@aws-crypto/util": { - "version": "5.2.0", - "resolved": "https://registry.npmmirror.com/@aws-crypto/util/-/util-5.2.0.tgz", - "integrity": "sha512-4RkU9EsI6ZpBve5fseQlGNUWKMa1RLPQ1dnjnQoe07ldfIzcsGb5hC5W0Dm7u423KWzawlrpbjXBrXCEv9zazQ==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/types": "^3.222.0", - "@smithy/util-utf8": "^2.0.0", - "tslib": "^2.6.2" - } - }, - "node_modules/@aws-sdk/client-bedrock-runtime": { - "version": "3.1048.0", - "resolved": "https://registry.npmmirror.com/@aws-sdk/client-bedrock-runtime/-/client-bedrock-runtime-3.1048.0.tgz", - "integrity": "sha512-u+NT61JZEkRFtpL0CAw1N1dwxnaLgwVXQl/zjJxTGgLyS/jTIdg2SdoEoCTHxgDyCnqa1HEi9QOoE9/pYRNpOQ==", - "license": "Apache-2.0", - "dependencies": { - "@aws-crypto/sha256-browser": "5.2.0", - "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/core": "^3.974.11", - "@aws-sdk/credential-provider-node": "^3.972.42", - "@aws-sdk/eventstream-handler-node": "^3.972.16", - "@aws-sdk/middleware-eventstream": "^3.972.12", - "@aws-sdk/middleware-websocket": "^3.972.19", - "@aws-sdk/token-providers": "3.1048.0", - "@aws-sdk/types": "^3.973.8", - "@smithy/core": "^3.24.2", - "@smithy/fetch-http-handler": "^5.4.2", - "@smithy/node-http-handler": "^4.7.2", - "@smithy/types": "^4.14.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/core": { - "version": "3.977.8", - "resolved": "https://registry.npmmirror.com/@aws-sdk/core/-/core-3.977.8.tgz", - "integrity": "sha512-7+Kcrkvrk9lM/m7jRhHpT4jCdvzGHsuaSRbF8TdzzkY1mRzp/Ogwf9c7H29k4gGhey0BBWhCWr16+t0J61gwmg==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/types": "^3.974.4", - "@aws-sdk/xml-builder": "^3.972.39", - "@aws/lambda-invoke-store": "^0.3.0", - "@smithy/core": "^3.31.1", - "@smithy/signature-v4": "^5.6.12", - "@smithy/types": "^4.16.1", - "bowser": "^2.11.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-env": { - "version": "3.972.69", - "resolved": "https://registry.npmmirror.com/@aws-sdk/credential-provider-env/-/credential-provider-env-3.972.69.tgz", - "integrity": "sha512-AreCFzcB4kH2HF9031Ot0jSJr3KXvRg6e8uDeub20JEVdZU3Bv0sTq1plc7VsT3KiqutlzH7l0j50UcCWHUioA==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "^3.977.8", - "@aws-sdk/types": "^3.974.4", - "@smithy/core": "^3.31.1", - "@smithy/types": "^4.16.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-http": { - "version": "3.972.71", - "resolved": "https://registry.npmmirror.com/@aws-sdk/credential-provider-http/-/credential-provider-http-3.972.71.tgz", - "integrity": "sha512-A8ObcqVmDMnk4F9NozZ7JwmUu9Q4xyBJkmyq1C5U+wNM9ht9J7+EuuyabsLWXZnOoTqFaJuYBYTKf5CTipkEjA==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "^3.977.8", - "@aws-sdk/types": "^3.974.4", - "@smithy/core": "^3.31.1", - "@smithy/fetch-http-handler": "^5.6.13", - "@smithy/node-http-handler": "^4.9.13", - "@smithy/types": "^4.16.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-http/node_modules/@smithy/node-http-handler": { - "version": "4.11.2", - "resolved": "https://registry.npmmirror.com/@smithy/node-http-handler/-/node-http-handler-4.11.2.tgz", - "integrity": "sha512-avwAh9HM3h2lcfjvP3zYIZGf+XVgLQ91wOJ2qoFbNpW1UZeZb33aGlhTZvtkANHfcGhJroRY64525OjfgOg30g==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/core": "^3.33.2", - "@smithy/types": "^4.17.2", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-ini": { - "version": "3.973.14", - "resolved": "https://registry.npmmirror.com/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.973.14.tgz", - "integrity": "sha512-7c+Wti2LsERNWMfm7ySz3/6RPopFW3Nmn7s63Xpcq6R/tRuY5hpvkHA2xVgi5ukJbvok9l0IDtVEvqTtg+X7dw==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "^3.977.8", - "@aws-sdk/credential-provider-env": "^3.972.69", - "@aws-sdk/credential-provider-http": "^3.972.71", - "@aws-sdk/credential-provider-login": "^3.972.76", - "@aws-sdk/credential-provider-process": "^3.972.69", - "@aws-sdk/credential-provider-sso": "^3.973.13", - "@aws-sdk/credential-provider-web-identity": "^3.972.75", - "@aws-sdk/nested-clients": "^3.997.43", - "@aws-sdk/types": "^3.974.4", - "@smithy/core": "^3.31.1", - "@smithy/credential-provider-imds": "^4.4.16", - "@smithy/types": "^4.16.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-login": { - "version": "3.972.76", - "resolved": "https://registry.npmmirror.com/@aws-sdk/credential-provider-login/-/credential-provider-login-3.972.76.tgz", - "integrity": "sha512-LVixwOnEJfrrfKHeZjBA8pIMTZjNDq8ak8VpcoWUuCJDrSnBNU8POJksULMgvN089P0MXtQYH2Zs627/MK1K0g==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "^3.977.8", - "@aws-sdk/nested-clients": "^3.997.43", - "@aws-sdk/types": "^3.974.4", - "@smithy/core": "^3.31.1", - "@smithy/types": "^4.16.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-node": { - "version": "3.972.80", - "resolved": "https://registry.npmmirror.com/@aws-sdk/credential-provider-node/-/credential-provider-node-3.972.80.tgz", - "integrity": "sha512-bE2qh8ww4iClO1jHsBXdOE8FUgzDbdxbyorNjSCoPSkQd51k3jODItuPZfuwcLHZqDXsH+bI4AMHhqtuyR7mSg==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/credential-provider-env": "^3.972.69", - "@aws-sdk/credential-provider-http": "^3.972.71", - "@aws-sdk/credential-provider-ini": "^3.973.14", - "@aws-sdk/credential-provider-process": "^3.972.69", - "@aws-sdk/credential-provider-sso": "^3.973.13", - "@aws-sdk/credential-provider-web-identity": "^3.972.75", - "@aws-sdk/types": "^3.974.4", - "@smithy/core": "^3.31.1", - "@smithy/credential-provider-imds": "^4.4.16", - "@smithy/types": "^4.16.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-process": { - "version": "3.972.69", - "resolved": "https://registry.npmmirror.com/@aws-sdk/credential-provider-process/-/credential-provider-process-3.972.69.tgz", - "integrity": "sha512-9kpTNdZTrcqXTfhxM7fgl9Z68ek3Fu5oe3Yf+A/pJGibEqpgZxz2tSY7SinmyCIU2PJ+ygY4FPoBBnLpocMtrQ==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "^3.977.8", - "@aws-sdk/types": "^3.974.4", - "@smithy/core": "^3.31.1", - "@smithy/types": "^4.16.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-sso": { - "version": "3.973.13", - "resolved": "https://registry.npmmirror.com/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.973.13.tgz", - "integrity": "sha512-Oc81qauMPzUoTnAS2YKpNwY6sY/LUyQTEeaf6yP197WMxkEBQfcKLR1MFpD7+pNTubXnfkH6gwpji+Gc7iyD2Q==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "^3.977.8", - "@aws-sdk/nested-clients": "^3.997.43", - "@aws-sdk/token-providers": "3.1111.0", - "@aws-sdk/types": "^3.974.4", - "@smithy/core": "^3.31.1", - "@smithy/types": "^4.16.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-sso/node_modules/@aws-sdk/token-providers": { - "version": "3.1111.0", - "resolved": "https://registry.npmmirror.com/@aws-sdk/token-providers/-/token-providers-3.1111.0.tgz", - "integrity": "sha512-JfljgoVtl+s3Qy21n9a7Z48uCQaOXcN74KJ3TEQfPoB293GrXFSt6HSQJF1sTZ8c/5QedEvd3NjJQMO4u9qa5A==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "^3.977.8", - "@aws-sdk/nested-clients": "^3.997.43", - "@aws-sdk/types": "^3.974.4", - "@smithy/core": "^3.31.1", - "@smithy/types": "^4.16.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-web-identity": { - "version": "3.972.75", - "resolved": "https://registry.npmmirror.com/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.972.75.tgz", - "integrity": "sha512-YPN6uoGDgjjjeVFZrcOeCJqmB6zpXoeeNgIjqe+DexJaWqdjVfCCe+VAZwli9Z2h8KhFW8oxkO39emQ1tyz/Mw==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "^3.977.8", - "@aws-sdk/nested-clients": "^3.997.43", - "@aws-sdk/types": "^3.974.4", - "@smithy/core": "^3.31.1", - "@smithy/types": "^4.16.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/eventstream-handler-node": { - "version": "3.972.33", - "resolved": "https://registry.npmmirror.com/@aws-sdk/eventstream-handler-node/-/eventstream-handler-node-3.972.33.tgz", - "integrity": "sha512-1Dd5WyEE2Kb3HvY44u7Ob16ST2W6iutOqsQ8Y2hUmsL2mAH/STlGS1dS9h3IOE6L7Ld3AR2HzKJ6XeCMOw8Peg==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/types": "^3.974.4", - "@smithy/core": "^3.31.1", - "@smithy/types": "^4.16.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/middleware-eventstream": { - "version": "3.972.28", - "resolved": "https://registry.npmmirror.com/@aws-sdk/middleware-eventstream/-/middleware-eventstream-3.972.28.tgz", - "integrity": "sha512-Z1EDXnS01P7H5jVrUx+/dBqV0m7dta7bSxLclkOuDuS93pNNQm0IcT4YLUbuvWKPYNxbI8aTG0p5Br30GSKDgA==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/types": "^3.974.4", - "@smithy/core": "^3.31.1", - "@smithy/types": "^4.16.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/middleware-websocket": { - "version": "3.972.51", - "resolved": "https://registry.npmmirror.com/@aws-sdk/middleware-websocket/-/middleware-websocket-3.972.51.tgz", - "integrity": "sha512-jdgP3jR5Q96j1jjZ98GGwpGg1CBNFIO2YE+vXg8cg8PvNY4NvgQNYJsqDaRX2PYv5gSUX/+C0D58Fhspj9ELMQ==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "^3.977.8", - "@aws-sdk/types": "^3.974.4", - "@smithy/core": "^3.31.1", - "@smithy/fetch-http-handler": "^5.6.13", - "@smithy/signature-v4": "^5.6.12", - "@smithy/types": "^4.16.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">= 14.0.0" - } - }, - "node_modules/@aws-sdk/nested-clients": { - "version": "3.997.43", - "resolved": "https://registry.npmmirror.com/@aws-sdk/nested-clients/-/nested-clients-3.997.43.tgz", - "integrity": "sha512-bit+VpqWNyi3wHxFoTsTliNXimCSL2r2OeDTm7ZrG+YsTZ2D7ofDJ6r/t9PVBn80i6/v0X2h9Tgw6QP2MAKfPw==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "^3.977.8", - "@aws-sdk/signature-v4-multi-region": "^3.996.45", - "@aws-sdk/types": "^3.974.4", - "@smithy/core": "^3.31.1", - "@smithy/fetch-http-handler": "^5.6.13", - "@smithy/node-http-handler": "^4.9.13", - "@smithy/types": "^4.16.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/nested-clients/node_modules/@smithy/node-http-handler": { - "version": "4.11.2", - "resolved": "https://registry.npmmirror.com/@smithy/node-http-handler/-/node-http-handler-4.11.2.tgz", - "integrity": "sha512-avwAh9HM3h2lcfjvP3zYIZGf+XVgLQ91wOJ2qoFbNpW1UZeZb33aGlhTZvtkANHfcGhJroRY64525OjfgOg30g==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/core": "^3.33.2", - "@smithy/types": "^4.17.2", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@aws-sdk/signature-v4-multi-region": { - "version": "3.996.45", - "resolved": "https://registry.npmmirror.com/@aws-sdk/signature-v4-multi-region/-/signature-v4-multi-region-3.996.45.tgz", - "integrity": "sha512-bBuyztukzXq6plzFGHAWiQt0QXo+HL8b8lX5cFTzkez/74PtS1c0qPFCIVuHkyoT+miH2qOjAcm1/yoro2ESPA==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/types": "^3.974.4", - "@smithy/signature-v4": "^5.6.12", - "@smithy/types": "^4.16.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/token-providers": { - "version": "3.1048.0", - "resolved": "https://registry.npmmirror.com/@aws-sdk/token-providers/-/token-providers-3.1048.0.tgz", - "integrity": "sha512-k0y/GcuesuSfWyUM0WamrGyeZmltRYaPbHO82UDA6mZ/doB+FOHKutikPAtSXMn/hDz970cF+iRuuiYO9VEbAA==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "^3.974.11", - "@aws-sdk/nested-clients": "^3.997.9", - "@aws-sdk/types": "^3.973.8", - "@smithy/core": "^3.24.2", - "@smithy/types": "^4.14.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/types": { - "version": "3.974.4", - "resolved": "https://registry.npmmirror.com/@aws-sdk/types/-/types-3.974.4.tgz", - "integrity": "sha512-dSFDNG00MEz0/xl5gxL62giLd1iYyJsTxZ1I1DOj6lC+bbgLB4TRsYClJg3b62dhXT1uATzsTNXPnC+33EJV3A==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/types": "^4.16.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/util-locate-window": { - "version": "3.965.10", - "resolved": "https://registry.npmmirror.com/@aws-sdk/util-locate-window/-/util-locate-window-3.965.10.tgz", - "integrity": "sha512-ycwH6Zd2GhuSqdXX9ihbCjeGTB6xOJs+O3+Jb8/zDG9978XU80qs75dfkPJRMNKe5MvBZPuNeFpd4JZKPoUF4g==", - "license": "Apache-2.0", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/xml-builder": { - "version": "3.972.39", - "resolved": "https://registry.npmmirror.com/@aws-sdk/xml-builder/-/xml-builder-3.972.39.tgz", - "integrity": "sha512-FTti8DS5MMWXNUWiRwXAJeYS+0GHHiMy0+7XOhcwk63ILHmfS2UFy2z/HNpZCSOJJ3P3dnWY6hfYNW3DF0nXUA==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/types": "^4.16.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws/lambda-invoke-store": { - "version": "0.3.0", - "resolved": "https://registry.npmmirror.com/@aws/lambda-invoke-store/-/lambda-invoke-store-0.3.0.tgz", - "integrity": "sha512-sl4Bm6yiMNYrZKkqqDFWN0UfnWhlS8ivKxrYl+6t0gCLrqr8y3B2IqZZbFRkfaVVp7C/baApyh71P+LeE1A2sQ==", - "license": "Apache-2.0", - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@babel/code-frame": { - "version": "7.29.7", - "resolved": "https://registry.npmmirror.com/@babel/code-frame/-/code-frame-7.29.7.tgz", - "integrity": "sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==", - "license": "MIT", - "dependencies": { - "@babel/helper-validator-identifier": "^7.29.7", - "js-tokens": "^4.0.0", - "picocolors": "^1.1.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-identifier": { - "version": "7.29.7", - "resolved": "https://registry.npmmirror.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz", - "integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==", - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/runtime": { - "version": "7.29.7", - "resolved": "https://registry.npmmirror.com/@babel/runtime/-/runtime-7.29.7.tgz", - "integrity": "sha512-Nq8OhGWiZIZGV6hLHoyAKLLcJihP/xFeBMGJoUrxTX2psI8dCifzLhZISFb+VWS3wFMRDmCGw5R+dOySCqPLhw==", - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@deepseek-ai/cordis": { - "version": "4.0.1", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/cordis/-/cordis-4.0.1.tgz", - "integrity": "sha512-YBdskTU2Po1kru3GgcUWUbkTsPMA9LkSQDAY8rBkFJeajdgcQad3QPJZE26JyK99Xb6HaASvoXg2DSUTeN/0Nw==", - "license": "MIT", - "dependencies": { - "@deepseek-ai/cosmokit": "^1.8.2", - "@standard-schema/spec": "^1.1.0" - }, - "bin": { - "cordis": "bin.js" - }, - "peerDependencies": { - "@deepseek-ai/cordis-plugin-include": "^1.0.6", - "@deepseek-ai/cordis-plugin-loader": "^1.0.2" - }, - "peerDependenciesMeta": { - "@deepseek-ai/cordis-plugin-include": { - "optional": true - }, - "@deepseek-ai/cordis-plugin-loader": { - "optional": true - } - } - }, - "node_modules/@deepseek-ai/cordis-plugin-group": { - "version": "1.0.1", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/cordis-plugin-group/-/cordis-plugin-group-1.0.1.tgz", - "integrity": "sha512-E1NThkFB3jn3TCqa6Oc++1zQHqLejF3W2wDwv2BlL3UEmgtBXL1K1j1koc+j676RuiOXtJkUJlPcOntRGKLWBQ==", - "license": "MIT", - "peer": true, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/cordis-plugin-loader": "^1.0.2" - } - }, - "node_modules/@deepseek-ai/cordis-plugin-hmr": { - "version": "1.0.16", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/cordis-plugin-hmr/-/cordis-plugin-hmr-1.0.16.tgz", - "integrity": "sha512-S7VHfylDg1+Y5O6fdYYZu0KFRAj/snHywcFPnX3KmQYa/qv2Q8IXi4zAt9ABq0BJYqhNoqRlbpGMfIjabgXjKA==", - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.29.0", - "@deepseek-ai/cosmokit": "^1.8.2", - "@deepseek-ai/schemastery": "^3.18.1", - "chokidar": "^4.0.3", - "picomatch": "^4.0.3" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/cordis-plugin-timer": "^1.1.3" - } - }, - "node_modules/@deepseek-ai/cordis-plugin-include": { - "version": "1.0.6", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/cordis-plugin-include/-/cordis-plugin-include-1.0.6.tgz", - "integrity": "sha512-i1VXrZCbv6tk/iUgedCNjrxxArbWT3IvRZGB5sdqJ3ectnihivXXQbRZ8JJ73DSmAPvlMGmrbtjFAfm10yvXRg==", - "license": "MIT", - "dependencies": { - "@deepseek-ai/cosmokit": "^1.8.2", - "js-yaml": "^4.1.0" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/cordis-plugin-loader": "^1.0.2" - } - }, - "node_modules/@deepseek-ai/cordis-plugin-loader": { - "version": "1.0.2", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/cordis-plugin-loader/-/cordis-plugin-loader-1.0.2.tgz", - "integrity": "sha512-RIW9hoVyhYDWdCI9BsvtZccPde1ECLC4OAxupwowGTak78vwVTVdb3HezTSOK1Y1/Ax3Ru0LA1pYOB04CnTxIQ==", - "license": "MIT", - "dependencies": { - "@deepseek-ai/cosmokit": "^1.8.2" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "node-addon-require-builtin": "^0.1.4" - }, - "peerDependenciesMeta": { - "node-addon-require-builtin": { - "optional": true - } - } - }, - "node_modules/@deepseek-ai/cordis-plugin-timer": { - "version": "1.1.3", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/cordis-plugin-timer/-/cordis-plugin-timer-1.1.3.tgz", - "integrity": "sha512-IOkey1VNmJwYa5U8bksyMOnM7mtirqjjbWLr3xA8QybLMK0sMooG3a6iJwtvd8P3MFwo3FQibEg+JPixp37MEw==", - "license": "MIT", - "dependencies": { - "@deepseek-ai/cosmokit": "^1.8.2" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1" - } - }, - "node_modules/@deepseek-ai/cosmokit": { - "version": "1.8.2", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/cosmokit/-/cosmokit-1.8.2.tgz", - "integrity": "sha512-muBOKtSrUKU5m/xpq8ZXWL6hQ/jgd4PhU2PqH97bcxIiLEJfNwZOGQEx4t/aS/GgxRAR+ra9pMHPMtTHU4sqqA==", - "license": "MIT" - }, - "node_modules/@deepseek-ai/dsh": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh/-/dsh-0.1.0-rc.8.tgz", - "integrity": "sha512-VQU5NlomrKLRgcXuOf+sxWFvqxPA8q9vMhrKPlPPXiOJEhGlGlAdiyxZvZxkCVI+v0zbhe21cY3/luLyxpSzzA==", - "license": "MIT", - "dependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/cordis-plugin-hmr": "^1.0.16", - "@deepseek-ai/cordis-plugin-include": "^1.0.6", - "@deepseek-ai/cordis-plugin-loader": "^1.0.2", - "@deepseek-ai/cordis-plugin-timer": "^1.1.3", - "@deepseek-ai/dsh-agent-instructions": "^0.1.0-rc.8", - "@deepseek-ai/dsh-agent-tool-presentation": "^0.1.0-rc.8", - "@deepseek-ai/dsh-app-boot": "^0.1.0-rc.8", - "@deepseek-ai/dsh-base": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-ui-agent-preset": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-ui-cordis": "^0.1.0-rc.8", - "@deepseek-ai/dsh-cmdline": "^0.1.0-rc.8", - "@deepseek-ai/dsh-command-compact": "^0.1.0-rc.8", - "@deepseek-ai/dsh-command-goal": "^0.1.0-rc.8", - "@deepseek-ai/dsh-compaction-basic": "^0.1.0-rc.8", - "@deepseek-ai/dsh-compaction-tool-result-pruner": "^0.1.0-rc.8", - "@deepseek-ai/dsh-cordis-client-runner": "^0.1.0-rc.8", - "@deepseek-ai/dsh-fs-local": "^0.1.0-rc.8", - "@deepseek-ai/dsh-goal": "^0.1.0-rc.8", - "@deepseek-ai/dsh-goal-round-driver": "^0.1.0-rc.8", - "@deepseek-ai/dsh-headless": "^0.1.0-rc.8", - "@deepseek-ai/dsh-home-paths": "^0.1.0-rc.8", - "@deepseek-ai/dsh-jobs-local": "^0.1.0-rc.8", - "@deepseek-ai/dsh-launch-environment": "^0.1.0-rc.8", - "@deepseek-ai/dsh-mcp-client": "^0.1.0-rc.8", - "@deepseek-ai/dsh-persona": "^0.1.0-rc.8", - "@deepseek-ai/dsh-plan-mode": "^0.1.0-rc.8", - "@deepseek-ai/dsh-pwsh-local": "^0.1.0-rc.8", - "@deepseek-ai/dsh-pwsh-sandbox": "^0.1.0-rc.8", - "@deepseek-ai/dsh-schedule": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session-projection": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session-reference": "^0.1.0-rc.8", - "@deepseek-ai/dsh-skill": "^0.1.0-rc.8", - "@deepseek-ai/dsh-skill-filesystem": "^0.1.0-rc.8", - "@deepseek-ai/dsh-terminal": "^0.1.0-rc.8", - "@deepseek-ai/dsh-terminal-bash": "^0.1.0-rc.8", - "@deepseek-ai/dsh-time-context": "^0.1.0-rc.8", - "@deepseek-ai/dsh-tmux-context": "^0.1.0-rc.8", - "@deepseek-ai/dsh-token-meter": "^0.1.0-rc.8", - "@deepseek-ai/dsh-tool-ask-user": "^0.1.0-rc.8", - "@deepseek-ai/dsh-tool-bash": "^0.1.0-rc.8", - "@deepseek-ai/dsh-tool-bash-persistent": "^0.1.0-rc.8", - "@deepseek-ai/dsh-tool-cordis": "^0.1.0-rc.8", - "@deepseek-ai/dsh-tool-fs": "^0.1.0-rc.8", - "@deepseek-ai/dsh-tool-fs-search": "^0.1.0-rc.8", - "@deepseek-ai/dsh-tool-goal": "^0.1.0-rc.8", - "@deepseek-ai/dsh-tool-jobs": "^0.1.0-rc.8", - "@deepseek-ai/dsh-tool-pwsh": "^0.1.0-rc.8", - "@deepseek-ai/dsh-tool-pwsh-persistent": "^0.1.0-rc.8", - "@deepseek-ai/dsh-tool-ralph": "^0.1.0-rc.8", - "@deepseek-ai/dsh-tool-skill": "^0.1.0-rc.8", - "@deepseek-ai/dsh-tool-str-replace-editor": "^0.1.0-rc.8", - "@deepseek-ai/dsh-tool-subagent": "^0.1.0-rc.8", - "@deepseek-ai/dsh-tool-subagent-control": "^0.1.0-rc.8", - "@deepseek-ai/dsh-tool-todo": "^0.1.0-rc.8", - "@deepseek-ai/dsh-tool-web": "^0.1.0-rc.8", - "@deepseek-ai/dsh-tool-workflow": "^0.1.0-rc.8", - "@deepseek-ai/dsh-web-app": "^0.1.0-rc.8", - "@deepseek-ai/dsh-workflow-worker-thread": "^0.1.0-rc.8", - "commander": "^15.0.0", - "js-yaml": "^4.2.0", - "node-addon-require-builtin": "^0.1.4" - }, - "bin": { - "dsh": "lib/bin.js" - } - }, - "node_modules/@deepseek-ai/dsh-agent": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-agent/-/dsh-agent-0.1.0-rc.8.tgz", - "integrity": "sha512-fOl46ZvzoYHalrlyfOJAHNhzyKeVDTUnZZKNSJEr9GY/98WJTjcV21agVEofTXldkJ7a/ws2HpJkVNJVFMtslg==", - "license": "MIT", - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", - "@deepseek-ai/dsh-scope": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session": "^0.1.0-rc.8", - "@deepseek-ai/dsh-system-prompt": "^0.1.0-rc.8", - "@deepseek-ai/dsh-typert-protocol": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-agent-default-model": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-agent-default-model/-/dsh-agent-default-model-0.1.0-rc.8.tgz", - "integrity": "sha512-FSmgVy8yeVYx3krUwfWZR3JokLD202FSuEd/ZfGdxA+BhOKAOfhNv539kujatVqXyzCG3XiRNda7zWxCh2h7/A==", - "license": "MIT", - "dependencies": { - "@deepseek-ai/schemastery": "^3.18.1" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", - "@deepseek-ai/dsh-settings": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-agent-instructions": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-agent-instructions/-/dsh-agent-instructions-0.1.0-rc.8.tgz", - "integrity": "sha512-T+JER2gUZbopOxNeHKUE7EfNof30yihsi7GXKB/lOLoy1XMvd5mlzjSHA/OzqjLxiZyyN4V7XAGURApVD3Z7sw==", - "license": "MIT", - "dependencies": { - "@deepseek-ai/schemastery": "^3.18.1" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", - "@deepseek-ai/dsh-fs": "^0.1.0-rc.8", - "@deepseek-ai/dsh-home-paths": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session": "^0.1.0-rc.8", - "@deepseek-ai/dsh-tools": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-agent-loop": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-agent-loop/-/dsh-agent-loop-0.1.0-rc.8.tgz", - "integrity": "sha512-6Vg5oLy3UZ6lJKMPxldqqBylKSMOpbV/FRrqzDqn3hGdksYBzt9K2hUJm/rE2RyguYKUKFPm2hExs0nn4HKmWA==", - "license": "MIT", - "dependencies": { - "@deepseek-ai/schemastery": "^3.18.1" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", - "@deepseek-ai/dsh-scope": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session-persistence": "^0.1.0-rc.8", - "@deepseek-ai/dsh-settings": "^0.1.0-rc.8", - "@deepseek-ai/dsh-system-prompt": "^0.1.0-rc.8", - "@deepseek-ai/dsh-tools": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-agent-presets": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-agent-presets/-/dsh-agent-presets-0.1.0-rc.8.tgz", - "integrity": "sha512-7h+kE0KDrJCk2Y8GAqF4fu4YqZmFi5U8/AarFkGUqRI3HDugD6oYf05c7ZWNF7lQXh1OmwmrSbuPhT/YXJapOg==", - "license": "MIT", - "dependencies": { - "@deepseek-ai/schemastery": "^3.18.1", - "js-yaml": "^4.1.0" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/cordis-plugin-include": "^1.0.6", - "@deepseek-ai/cordis-plugin-loader": "^1.0.2", - "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", - "@deepseek-ai/dsh-atomic-write": "^0.1.0-rc.8", - "@deepseek-ai/dsh-home-paths": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-scope": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session": "^0.1.0-rc.8", - "@deepseek-ai/dsh-settings": "^0.1.0-rc.8", - "@deepseek-ai/dsh-system-prompt": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-agent-tool-presentation": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-agent-tool-presentation/-/dsh-agent-tool-presentation-0.1.0-rc.8.tgz", - "integrity": "sha512-DQouZBh0yjKy8bi0EHQZrZ1B0E+Sc321o5oIyrrmL3hh1sbBsWVrnTvwKPP+SU7J6gnIzyITJ7qEV7pcCGOB2w==", - "license": "MIT", - "dependencies": { - "@deepseek-ai/schemastery": "^3.18.1" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-tools": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-anonymous-user-id": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-anonymous-user-id/-/dsh-anonymous-user-id-0.1.0-rc.8.tgz", - "integrity": "sha512-vUESbXtDdqIyelCNqX3ijOfqNfw65iSaJaqzfiqQhmSd9ZrNJ1fPUHl8FoW1BdfK8FjrDyh32R6BtuVpI7Zdhw==", - "license": "MIT", - "peer": true, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-brand": "^0.1.0-rc.8", - "@deepseek-ai/dsh-home-paths": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-api-gateway": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-api-gateway/-/dsh-api-gateway-0.1.0-rc.8.tgz", - "integrity": "sha512-rNA9+Sq3lXFDmyoFLpXNbcuWg7iFeepCwDi+jt1oGjwZTdZJ2nEWpU6GKlOiqadQjHYzfwEbCqmcuJy32qke/A==", - "license": "MIT", - "dependencies": { - "@deepseek-ai/dsh-typert-protocol": "^0.1.0-rc.8" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-client-connection": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-typert-registry": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-api-remotes": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-api-remotes/-/dsh-api-remotes-0.1.0-rc.8.tgz", - "integrity": "sha512-s/zmFmU6R+dDxUWbHucIyfVgJG4v8kXa3YRjwjMO+Bu871ZG5Zsht6cvRqeSyu0A/Gs06ZfKYeKE0sdbCZ1NiA==", - "license": "MIT", - "dependencies": { - "@deepseek-ai/dsh-typert-protocol": "^0.1.0-rc.8" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", - "@deepseek-ai/dsh-agent-presets": "^0.1.0-rc.8", - "@deepseek-ai/dsh-api-gateway": "^0.1.0-rc.8", - "@deepseek-ai/dsh-commands": "^0.1.0-rc.8", - "@deepseek-ai/dsh-cordis-host-runner": "^0.1.0-rc.8", - "@deepseek-ai/dsh-credentials": "^0.1.0-rc.8", - "@deepseek-ai/dsh-file-reference": "^0.1.0-rc.8", - "@deepseek-ai/dsh-goal": "^0.1.0-rc.8", - "@deepseek-ai/dsh-host-plugin-inventory": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", - "@deepseek-ai/dsh-message-feedback": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session-persistence": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session-reference": "^0.1.0-rc.8", - "@deepseek-ai/dsh-settings": "^0.1.0-rc.8", - "@deepseek-ai/dsh-typert-registry": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-app-boot": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-app-boot/-/dsh-app-boot-0.1.0-rc.8.tgz", - "integrity": "sha512-DS63o1PhX2Gvqdgl6Wd8vZnLl0qo8gJ9LpSHXeJBJL9HITpLPhdVYE3X6S0icIYdbGO2plNyhxVJOSN6ibO7VA==", - "license": "MIT", - "dependencies": { - "js-yaml": "^4.2.0" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/cordis-plugin-group": "^1.0.1", - "@deepseek-ai/cordis-plugin-hmr": "^1.0.16", - "@deepseek-ai/cordis-plugin-include": "^1.0.6", - "@deepseek-ai/cordis-plugin-loader": "^1.0.2", - "@deepseek-ai/dsh-home-paths": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-launch-environment": "^0.1.0-rc.8", - "@deepseek-ai/dsh-system-prompt": "^0.1.0-rc.8" - }, - "peerDependenciesMeta": { - "@deepseek-ai/cordis-plugin-hmr": { - "optional": true - } - } - }, - "node_modules/@deepseek-ai/dsh-atomic-write": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-atomic-write/-/dsh-atomic-write-0.1.0-rc.8.tgz", - "integrity": "sha512-SWP+NAat3oteaPi47zLPz4vxeYCHNVmFpN1aeKDuPHpe/ouNTl+WcyIONAJ+1MbZ+8APWhSaJIVu6ORJEUhVGw==", - "license": "MIT", - "peer": true, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-attachment": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-attachment/-/dsh-attachment-0.1.0-rc.8.tgz", - "integrity": "sha512-cCrg4WWiav7pGtbdU8dJTpAG28cPnkWVB2YPOrlBCgBbhQziGcG9Dv67Ti6L3PI4OQKC55gYBFinQghFO/7FGg==", - "license": "MIT", - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-brand": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-attachment-local": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-attachment-local/-/dsh-attachment-local-0.1.0-rc.8.tgz", - "integrity": "sha512-TPsDbDPA8yoE3hw1MtrW61AMh72oMiCY+rkO3bDnvc4MtGwKvXcHWtbNPeVpLgMeznaXsnTU3GUp9Fa6PXdp8A==", - "license": "MIT", - "dependencies": { - "@deepseek-ai/schemastery": "^3.18.1", - "sharp": "^0.35.3" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-attachment": "^0.1.0-rc.8", - "@deepseek-ai/dsh-home-paths": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-base": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-base/-/dsh-base-0.1.0-rc.8.tgz", - "integrity": "sha512-aMjXT6d5t8SGQg24geOSX6O0ky+hJLijhzZklDcICrBvGSKXvuS8jxLOcL5u4s4pFCODXhuOpvTfFuUhN2RK3Q==", - "license": "MIT", - "dependencies": { - "@deepseek-ai/cordis-plugin-hmr": "^1.0.16", - "@deepseek-ai/cordis-plugin-timer": "^1.1.3", - "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", - "@deepseek-ai/dsh-agent-default-model": "^0.1.0-rc.8", - "@deepseek-ai/dsh-agent-instructions": "^0.1.0-rc.8", - "@deepseek-ai/dsh-agent-loop": "^0.1.0-rc.8", - "@deepseek-ai/dsh-api-gateway": "^0.1.0-rc.8", - "@deepseek-ai/dsh-attachment-local": "^0.1.0-rc.8", - "@deepseek-ai/dsh-bash-sandbox": "^0.1.0-rc.8", - "@deepseek-ai/dsh-command-compact": "^0.1.0-rc.8", - "@deepseek-ai/dsh-command-feedback": "^0.1.0-rc.8", - "@deepseek-ai/dsh-command-goal": "^0.1.0-rc.8", - "@deepseek-ai/dsh-commands": "^0.1.0-rc.8", - "@deepseek-ai/dsh-compaction-basic": "^0.1.0-rc.8", - "@deepseek-ai/dsh-compaction-tool-result-pruner": "^0.1.0-rc.8", - "@deepseek-ai/dsh-credentials-local": "^0.1.0-rc.8", - "@deepseek-ai/dsh-fs-local": "^0.1.0-rc.8", - "@deepseek-ai/dsh-fs-observation-policy": "^0.1.0-rc.8", - "@deepseek-ai/dsh-fs-sandbox": "^0.1.0-rc.8", - "@deepseek-ai/dsh-goal": "^0.1.0-rc.8", - "@deepseek-ai/dsh-goal-round-driver": "^0.1.0-rc.8", - "@deepseek-ai/dsh-jobs-local": "^0.1.0-rc.8", - "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", - "@deepseek-ai/dsh-llm-deepseek": "^0.1.0-rc.8", - "@deepseek-ai/dsh-llm-pi-ai": "^0.1.0-rc.8", - "@deepseek-ai/dsh-llm-retry": "^0.1.0-rc.8", - "@deepseek-ai/dsh-permission-presets": "^0.1.0-rc.8", - "@deepseek-ai/dsh-plan-mode": "^0.1.0-rc.8", - "@deepseek-ai/dsh-pwsh-sandbox": "^0.1.0-rc.8", - "@deepseek-ai/dsh-repeat-tool-reminder": "^0.1.0-rc.8", - "@deepseek-ai/dsh-sandbox-local": "^0.1.0-rc.8", - "@deepseek-ai/dsh-sandbox-policy": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session-checkpoint-policy": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session-persistence-jsonl": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session-projection": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session-query-sqlite": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session-telemetry-otel": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session-title": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session-title-first-prompt-llm": "^0.1.0-rc.8", - "@deepseek-ai/dsh-settings-file": "^0.1.0-rc.8", - "@deepseek-ai/dsh-shell-env": "^0.1.0-rc.8", - "@deepseek-ai/dsh-skill": "^0.1.0-rc.8", - "@deepseek-ai/dsh-skill-badge": "^0.1.0-rc.8", - "@deepseek-ai/dsh-skill-filesystem": "^0.1.0-rc.8", - "@deepseek-ai/dsh-spill-local": "^0.1.0-rc.8", - "@deepseek-ai/dsh-spill-policy": "^0.1.0-rc.8", - "@deepseek-ai/dsh-subagent": "^0.1.0-rc.8", - "@deepseek-ai/dsh-subagent-fork-in-process": "^0.1.0-rc.8", - "@deepseek-ai/dsh-subagent-spawn-in-process": "^0.1.0-rc.8", - "@deepseek-ai/dsh-subprocess-local": "^0.1.0-rc.8", - "@deepseek-ai/dsh-system-prompt": "^0.1.0-rc.8", - "@deepseek-ai/dsh-token-meter": "^0.1.0-rc.8", - "@deepseek-ai/dsh-tool-bash": "^0.1.0-rc.8", - "@deepseek-ai/dsh-tool-call-timeout-policy": "^0.1.0-rc.8", - "@deepseek-ai/dsh-tool-fs": "^0.1.0-rc.8", - "@deepseek-ai/dsh-tool-fs-search": "^0.1.0-rc.8", - "@deepseek-ai/dsh-tool-goal": "^0.1.0-rc.8", - "@deepseek-ai/dsh-tool-jobs": "^0.1.0-rc.8", - "@deepseek-ai/dsh-tool-pwsh": "^0.1.0-rc.8", - "@deepseek-ai/dsh-tool-ralph": "^0.1.0-rc.8", - "@deepseek-ai/dsh-tool-skill": "^0.1.0-rc.8", - "@deepseek-ai/dsh-tool-str-replace-editor": "^0.1.0-rc.8", - "@deepseek-ai/dsh-tool-subagent": "^0.1.0-rc.8", - "@deepseek-ai/dsh-tool-subagent-control": "^0.1.0-rc.8", - "@deepseek-ai/dsh-tool-subagent-report": "^0.1.0-rc.8", - "@deepseek-ai/dsh-tool-todo": "^0.1.0-rc.8", - "@deepseek-ai/dsh-tool-web": "^0.1.0-rc.8", - "@deepseek-ai/dsh-tool-workflow": "^0.1.0-rc.8", - "@deepseek-ai/dsh-tools": "^0.1.0-rc.8", - "@deepseek-ai/dsh-typert-loader": "^0.1.0-rc.8", - "@deepseek-ai/dsh-typert-registry": "^0.1.0-rc.8", - "@deepseek-ai/dsh-user-approval": "^0.1.0-rc.8", - "@deepseek-ai/dsh-user-questions": "^0.1.0-rc.8", - "@deepseek-ai/dsh-web": "^0.1.0-rc.8", - "@deepseek-ai/dsh-web-search-deepseek": "^0.1.0-rc.8", - "@deepseek-ai/dsh-workflow-worker-thread": "^0.1.0-rc.8" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-bash-local": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-bash-local/-/dsh-bash-local-0.1.0-rc.8.tgz", - "integrity": "sha512-vMf3dMRrvVvwWCLJxobYONSebPtWqy2ZZKpRZ6o5fBrZbM88irbvL6F/6r/mu4ADTIDigUtpoxlRpOEQKbSuTg==", - "license": "MIT", - "peer": true, - "dependencies": { - "@deepseek-ai/schemastery": "^3.18.1" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-settings": "^0.1.0-rc.8", - "@deepseek-ai/dsh-shell": "^0.1.0-rc.8", - "@deepseek-ai/dsh-subprocess": "^0.1.0-rc.8", - "@deepseek-ai/dsh-timeout": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-bash-sandbox": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-bash-sandbox/-/dsh-bash-sandbox-0.1.0-rc.8.tgz", - "integrity": "sha512-gCFrmFwYyxjXJsSRrzs5RbvCli0I0Tn9JAJEHCWSskE8x9iCVU7ljtmrKvgRYr0J4YeXwzteNSfNhlJqasu/QQ==", - "license": "MIT", - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-bash-local": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-sandbox": "^0.1.0-rc.8", - "@deepseek-ai/dsh-sandbox-policy": "^0.1.0-rc.8", - "@deepseek-ai/dsh-shell": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-brand": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-brand/-/dsh-brand-0.1.0-rc.8.tgz", - "integrity": "sha512-402aUAfHxIZJrArBV4gDf0I/A/69A/By26FX6HTIOyFmCnB4wUBKh8jnglz1CorKWdZy8AKldAhh8HQhQEbGOQ==", - "license": "MIT", - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-client-connection": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-client-connection/-/dsh-client-connection-0.1.0-rc.8.tgz", - "integrity": "sha512-O1Y1NmkvJjpR/rCYkzulRrKbFwUbpMlINR4G6fbpGXaLy0VzTqN+ptk0b3wJ4RrnKPi4WWLKNNdV647Fg/1sCw==", - "license": "MIT", - "dependencies": { - "@deepseek-ai/schemastery": "^3.18.1", - "ws": "^8.21.0" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-attachment": "^0.1.0-rc.8", - "@deepseek-ai/dsh-commands": "^0.1.0-rc.8", - "@deepseek-ai/dsh-host-apiproxy": "^0.1.0-rc.8", - "@deepseek-ai/dsh-host-webserver": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session": "^0.1.0-rc.8", - "@deepseek-ai/dsh-tools": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-client-hmr": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-client-hmr/-/dsh-client-hmr-0.1.0-rc.8.tgz", - "integrity": "sha512-Olzlpiw+2VIhNOZVEgi22b2U0jSv6HciAQpKj41TggI7oV+jhRDC2GuYFJoRQ8XBs3mcJCLG0DZtAcGrRP8n9Q==", - "license": "MIT", - "dependencies": { - "@deepseek-ai/schemastery": "^3.18.1" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/cordis-plugin-loader": "^1.0.2", - "@deepseek-ai/dsh-client-modules": "^0.1.0-rc.8", - "@deepseek-ai/dsh-host-webserver": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-client-locale": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-client-locale/-/dsh-client-locale-0.1.0-rc.8.tgz", - "integrity": "sha512-S8ztym/oFU1aWPDtSZLTGWfprUBIuhfOrRNlw/qMAwhavJiQU/Ag0plg19JffGiOMAQuz2BU2n2mW/xhbpA5Vw==", - "license": "MIT", - "dependencies": { - "@deepseek-ai/schemastery": "^3.18.1" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-api-remotes": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-connection": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-runtime": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-ui-settings": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-settings": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-client-modules": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-client-modules/-/dsh-client-modules-0.1.0-rc.8.tgz", - "integrity": "sha512-K+uDZSmSbpmHFpvrKkdctHHDIjimv1NWDZoc7CYy7QIk0Vuis4jShDau6H5L0B9TScWBDyXAz/R7rXttFlwseA==", - "license": "MIT", - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/cordis-plugin-loader": "^1.0.2", - "@deepseek-ai/dsh-host-webserver": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-client-runtime": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-client-runtime/-/dsh-client-runtime-0.1.0-rc.8.tgz", - "integrity": "sha512-wW/nktO/GVbGO/k163NlyJab/rK4D6xS5EL0bhYw4ojF1mxmWfrb3RUEYR5LcEUpFx/yXUHsUSgeO1ezmgIrvw==", - "license": "MIT", - "dependencies": { - "immer": "^10.1.1", - "zustand": "~4.4.7" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", - "@deepseek-ai/dsh-api-remotes": "^0.1.0-rc.8", - "@deepseek-ai/dsh-attachment": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-connection": "^0.1.0-rc.8", - "@deepseek-ai/dsh-commands": "^0.1.0-rc.8", - "@deepseek-ai/dsh-host-apiproxy": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", - "@deepseek-ai/dsh-llm-retry": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session-projection": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session-title": "^0.1.0-rc.8", - "@deepseek-ai/dsh-tools": "^0.1.0-rc.8", - "@deepseek-ai/dsh-typert-protocol": "^0.1.0-rc.8", - "@deepseek-ai/dsh-typert-registry": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-client-ui-agent-preset": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-client-ui-agent-preset/-/dsh-client-ui-agent-preset-0.1.0-rc.8.tgz", - "integrity": "sha512-z+okJSOT2/uAA4oomx1WNNl/2k9HsoNDmtewOeQVfSy9C8Ey9YBoVoiSQDsYyDHhesxxlBI8RMLU44Pj/w1uug==", - "license": "MIT", - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-api-remotes": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-connection": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-locale": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-runtime": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-ui-conversation": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-ui-settings": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-client-ui-attachment": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-client-ui-attachment/-/dsh-client-ui-attachment-0.1.0-rc.8.tgz", - "integrity": "sha512-TiKZEUGd22AFxkWpgQCLW9VmuSgWQ11RlIQd0941wPAc4RDZxtkjQWDMOlvRS/m8Oqod/5oKr3U6WRCZKS81vA==", - "license": "MIT", - "dependencies": { - "clsx": "^2.0.0" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-attachment": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-runtime": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-ui-conversation": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-client-ui-brand-official": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-client-ui-brand-official/-/dsh-client-ui-brand-official-0.1.0-rc.8.tgz", - "integrity": "sha512-eHzJkJGOKlQpap6uYaAZSh62MyJFEoPX8EvIp/kV3YHFDr4bZNc7Yg+ZLMaEXfIjPXKp26FhPiCIia9SP56n8A==", - "license": "MIT", - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-client-runtime": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-ui-conversation": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-ui-sidebar": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-client-ui-commands": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-client-ui-commands/-/dsh-client-ui-commands-0.1.0-rc.8.tgz", - "integrity": "sha512-nMDF0MbRM03AEmQJzXCbXQWZxSfVPHBO0z+9DqR6LgGXshYLkzVMp1zkfvqLs5QwFAwDSci4vi/GONJOBSL5WA==", - "license": "MIT", - "dependencies": { - "clsx": "^2.0.0" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-api-remotes": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-locale": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-runtime": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-ui-conversation": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-ui-input-trigger": "^0.1.0-rc.8", - "@deepseek-ai/dsh-commands": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-client-ui-conversation": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-client-ui-conversation/-/dsh-client-ui-conversation-0.1.0-rc.8.tgz", - "integrity": "sha512-GnQSE47/goSm1UzxQpYQrQnMJLyTmYFH6NENdrOxrVJxQnB55ruactgM1kVwfFnc/WUQVYy0599AK7pxjbxjMg==", - "license": "MIT", - "dependencies": { - "@deepseek-ai/schemastery": "^3.18.1", - "clsx": "^2.0.0" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", - "@deepseek-ai/dsh-api-remotes": "^0.1.0-rc.8", - "@deepseek-ai/dsh-attachment": "^0.1.0-rc.8", - "@deepseek-ai/dsh-brand": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-connection": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-locale": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-runtime": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-ui-input-trigger": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-ui-layout": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-ui-settings": "^0.1.0-rc.8", - "@deepseek-ai/dsh-commands": "^0.1.0-rc.8", - "@deepseek-ai/dsh-compaction": "^0.1.0-rc.8", - "@deepseek-ai/dsh-goal": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-llm-retry": "^0.1.0-rc.8", - "@deepseek-ai/dsh-permission-presets": "^0.1.0-rc.8", - "@deepseek-ai/dsh-plan-mode": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session-stats": "^0.1.0-rc.8", - "@deepseek-ai/dsh-settings": "^0.1.0-rc.8", - "@deepseek-ai/dsh-token-meter": "^0.1.0-rc.8", - "@deepseek-ai/dsh-tool-todo": "^0.1.0-rc.8", - "@deepseek-ai/dsh-tools": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-client-ui-cordis": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-client-ui-cordis/-/dsh-client-ui-cordis-0.1.0-rc.8.tgz", - "integrity": "sha512-NvaSJxqC+HNPLPYPINHzJGRHI427mHSB2aaTGoyc9EFrYVJjvKpNu1QusWwObae5Y/Tx43I2NpFKTAcNVPXkOw==", - "license": "MIT", - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-api-remotes": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-connection": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-locale": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-runtime": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-ui-input-trigger": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-ui-sidebar": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-ui-tool": "^0.1.0-rc.8", - "@deepseek-ai/dsh-cordis-client-runner": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-client-ui-deliverables": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-client-ui-deliverables/-/dsh-client-ui-deliverables-0.1.0-rc.8.tgz", - "integrity": "sha512-b0XZ/V7FPpTTtmHoKNEVOgl9bJGXGqktzMNNJgifHGl/Us1nNnQVDhM9XDbuUV5iXFPnRrKsR29OTnuTB+txZA==", - "license": "MIT", - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-client-connection": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-locale": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-runtime": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-ui-conversation": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-system-prompt": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-client-ui-directory-picker-browse": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-client-ui-directory-picker-browse/-/dsh-client-ui-directory-picker-browse-0.1.0-rc.8.tgz", - "integrity": "sha512-sjQcMuut8CRjqnFZHzX1Zzs1zISDlp/gYQVM9Wkyt9KF+XJfV5pHP0KTHZHwOslAqt2OJMnE38uW2yVncLg3sA==", - "license": "MIT", - "dependencies": { - "clsx": "^2.0.0" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-client-locale": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-runtime": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-ui-workspace": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-client-ui-directory-picker-native": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-client-ui-directory-picker-native/-/dsh-client-ui-directory-picker-native-0.1.0-rc.8.tgz", - "integrity": "sha512-UPR5kSjfMGjLpO41fXXVxcen9Bq9eCzonStnhqMMk/6zC2EQUDkRs+KhYmaInkHI/CMjdTBBqBPRwjFG2iEsYQ==", - "license": "MIT", - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-client-runtime": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-ui-workspace": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-client-ui-goal": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-client-ui-goal/-/dsh-client-ui-goal-0.1.0-rc.8.tgz", - "integrity": "sha512-kAs6DktlELshs27S3nnjzciK9bGhL2b6RXmZ/mUNYwgiYxeYY4/QYynSNbD0ZQINe0VeGy6yQTv9dbqDBArndA==", - "license": "MIT", - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-api-remotes": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-locale": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-runtime": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-ui-conversation": "^0.1.0-rc.8", - "@deepseek-ai/dsh-commands": "^0.1.0-rc.8", - "@deepseek-ai/dsh-goal": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session": "^0.1.0-rc.8", - "@deepseek-ai/dsh-typert-protocol": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-client-ui-input-trigger": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-client-ui-input-trigger/-/dsh-client-ui-input-trigger-0.1.0-rc.8.tgz", - "integrity": "sha512-uVJEZ1ftUdMemLvNf17gzB6ThYw0DL4k+0kcQrUPc6LHNQ2ZeuuvOz/931OlqzzUKMtlAGZgy0LvWyJ62LlSog==", - "license": "MIT", - "dependencies": { - "clsx": "^2.0.0" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-client-locale": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-runtime": "^0.1.0-rc.8", - "@deepseek-ai/dsh-file-reference": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-client-ui-jobs": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-client-ui-jobs/-/dsh-client-ui-jobs-0.1.0-rc.8.tgz", - "integrity": "sha512-gCJR9ymswAZa8OiyZQUKa9GpxRT2sP76tfqBGcF5pRN0xOKudlREM6xD3as2knY5EZELW5qQMVKlVVJZ2Uu7fA==", - "license": "MIT", - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-client-locale": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-runtime": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-ui-conversation": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-client-ui-layout": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-client-ui-layout/-/dsh-client-ui-layout-0.1.0-rc.8.tgz", - "integrity": "sha512-tbHawbf8FsJqdwnXrU46V8u13bfAFVQQf0hA0OXH4k0PiLiThdZgQFn/T94+56JMUzD1QLqe7DLmNz29cwmjvQ==", - "license": "MIT", - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-client-runtime": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-ui-theme": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-client-ui-message-feedback": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-client-ui-message-feedback/-/dsh-client-ui-message-feedback-0.1.0-rc.8.tgz", - "integrity": "sha512-tzm/vvhysNa3+1BlTnuj3WJit5+u8U1NDecLqMPTm6U1P2s2bjKtvUpmMNqk+AdeYGYcJjXPadLEuWSNsIWFlQ==", - "license": "MIT", - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-api-remotes": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-connection": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-locale": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-runtime": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-ui-conversation": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-message-feedback": "^0.1.0-rc.8", - "@deepseek-ai/dsh-typert-protocol": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-client-ui-model-selection": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-client-ui-model-selection/-/dsh-client-ui-model-selection-0.1.0-rc.8.tgz", - "integrity": "sha512-ODRo7IX4VKkgy6C0ibElP5p1Ek6NBm6Qz6S95cZQH2J+PXWTb57/6UvNfxqyst8nFh1wll4oRb1m4fm6MU/fqA==", - "license": "MIT", - "dependencies": { - "clsx": "^2.1.1" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-api-remotes": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-connection": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-locale": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-runtime": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-ui-commands": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-ui-conversation": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-ui-input-trigger": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-client-ui-permission-presets": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-client-ui-permission-presets/-/dsh-client-ui-permission-presets-0.1.0-rc.8.tgz", - "integrity": "sha512-mYF/TX4GVJgRxDYPIk/iQKkGXz8qHkfFJE3GqIw5E27g+Msfg8AEGqfWEPp4CZeIK/3zcgpMLzgjMLOliWZ2dA==", - "license": "MIT", - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-api-remotes": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-connection": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-locale": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-runtime": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-ui-commands": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-ui-input-trigger": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-ui-settings": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-permission-presets": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-client-ui-plan": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-client-ui-plan/-/dsh-client-ui-plan-0.1.0-rc.8.tgz", - "integrity": "sha512-OmCuuYCqSlbYqd4s781WipQNKWdHGUn8TPIxrKrcbe94vJacuBtIUIJkDi48dy0IimI+ln/eHxD9WC/9+bJEmA==", - "license": "MIT", - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-api-remotes": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-locale": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-runtime": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-ui-conversation": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-plan-mode": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-client-ui-reference": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-client-ui-reference/-/dsh-client-ui-reference-0.1.0-rc.8.tgz", - "integrity": "sha512-9qQYmOqG58qlsYNipOMsrL+Ay5Imx8lHJk9GV1rW++LGl6HMb6V1qZBHGIAwO/KOOInnJSEZE65DYB54r+z1Fw==", - "license": "MIT", - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-api-remotes": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-locale": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-runtime": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-ui-input-trigger": "^0.1.0-rc.8", - "@deepseek-ai/dsh-file-reference": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session-reference": "^0.1.0-rc.8", - "@deepseek-ai/dsh-typert-protocol": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-client-ui-renderer": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-client-ui-renderer/-/dsh-client-ui-renderer-0.1.0-rc.8.tgz", - "integrity": "sha512-/MpR9i++feUFNzJgCChLfct1RphTPJ1WKfZrIsczjyOAZNBzAM5LRjpvM0ZO5Vg7rs7id+PLJYuUKy2e2V5aAA==", - "license": "MIT", - "dependencies": { - "use-sync-external-store": "1.2.0" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-client-runtime": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-client-ui-settings": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-client-ui-settings/-/dsh-client-ui-settings-0.1.0-rc.8.tgz", - "integrity": "sha512-qSOjpmglOPsLzx6Q5yysrU4c4W6QWFOkyVyqePA5lNPOdny2MH19qbuNleQHbiBo4Zadh/dtBn/SuNRfSp+pjw==", - "license": "MIT", - "dependencies": { - "@deepseek-ai/schemastery": "^3.18.1" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-api-remotes": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-connection": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-runtime": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-settings": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-client-ui-settings-general": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-client-ui-settings-general/-/dsh-client-ui-settings-general-0.1.0-rc.8.tgz", - "integrity": "sha512-lGGLCV17yUhKTHFAL+LWNY6LICLHmL614TbgaTFC80HWqeduURKzHU7a2PoySyMC2AOvYGpKjIRNUfifhv3aZw==", - "license": "MIT", - "dependencies": { - "@deepseek-ai/schemastery": "^3.18.1", - "clsx": "^2.0.0" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-api-remotes": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-connection": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-locale": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-runtime": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-ui-settings": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-ui-sidebar": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-settings": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-client-ui-settings-models": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-client-ui-settings-models/-/dsh-client-ui-settings-models-0.1.0-rc.8.tgz", - "integrity": "sha512-6iTLiQ4+4ErqV2e0Lxeunr1Q0JLFJ3EcJ1KcxvT0mEy5xzZuilX7KJxsBWq11q3Wy/I0MYhbHZzZC+d42mFM4g==", - "license": "MIT", - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-api-remotes": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-connection": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-locale": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-runtime": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-ui-settings": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-client-ui-settings-plugin-inventory": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-client-ui-settings-plugin-inventory/-/dsh-client-ui-settings-plugin-inventory-0.1.0-rc.8.tgz", - "integrity": "sha512-IiixKrJbNqn4D8kvpSIRbxsfetEEbYN5Z3Uz209UWLOiY8Ja9VdQaVbh6BZlecO9BXX1Lgo8l8q+tXlC0IpifA==", - "license": "MIT", - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-api-remotes": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-locale": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-runtime": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-ui-settings": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-client-ui-settings-plugins": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-client-ui-settings-plugins/-/dsh-client-ui-settings-plugins-0.1.0-rc.8.tgz", - "integrity": "sha512-BLLFFxBz4TmnXXsR5bnQaLMboXBOvCfhoqSbdPFqkqrmJSD+3KGbg4SQJZPcfLL19Kq7qeDraPCXwxo3wpIULg==", - "license": "MIT", - "dependencies": { - "clsx": "^2.0.0" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-api-remotes": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-connection": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-locale": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-runtime": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-ui-settings": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-client-ui-sidebar": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-client-ui-sidebar/-/dsh-client-ui-sidebar-0.1.0-rc.8.tgz", - "integrity": "sha512-7wcBnS27j8iIVDuai8BVifxcDZd5DIjlHgNHQKx8xQM+x92VKhiFOoMccjhXNaE6sExCUsER1OWRVp65MJvjqg==", - "license": "MIT", - "dependencies": { - "clsx": "^2.0.0" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-client-locale": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-runtime": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-ui-layout": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-client-ui-skill": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-client-ui-skill/-/dsh-client-ui-skill-0.1.0-rc.8.tgz", - "integrity": "sha512-s9tW3tDQ/82TzZcUHC/dZy5zmPppFKbSXnBotQDvjAU+rkS3/4k4Y6u9LffyZ813OjCoCfs7GOfWHAyZ0VmBag==", - "license": "MIT", - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-api-remotes": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-connection": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-locale": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-runtime": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-ui-input-trigger": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-ui-tool": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-client-ui-subagent": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-client-ui-subagent/-/dsh-client-ui-subagent-0.1.0-rc.8.tgz", - "integrity": "sha512-uK23jWwzFXbAELsnqS+7A4jL3Q/Ft8AI1hPrJE1ssldq535znexgdGAguZFC17fG+L0OWUtqwAKdXHmjyzqLiQ==", - "license": "MIT", - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-client-locale": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-runtime": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-ui-conversation": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-ui-input-trigger": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-subagent": "^0.1.0-rc.8", - "@deepseek-ai/dsh-token-meter": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-client-ui-theme": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-client-ui-theme/-/dsh-client-ui-theme-0.1.0-rc.8.tgz", - "integrity": "sha512-orLl5eoWOnvjj76lI6xucE+lT+o+ouniRMSFsuYwF1DNH2pbyfVPQYJWL3iM55gE28yyZJGgmtmABnQBiEF5iA==", - "license": "MIT", - "dependencies": { - "@deepseek-ai/schemastery": "^3.18.1", - "clsx": "^2.0.0" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-api-remotes": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-connection": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-locale": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-runtime": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-ui-settings": "^0.1.0-rc.8", - "@deepseek-ai/dsh-host-webserver": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-settings": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-client-ui-tool": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-client-ui-tool/-/dsh-client-ui-tool-0.1.0-rc.8.tgz", - "integrity": "sha512-+Mtgx56PptrtoN4Q36yISe3u0lnVazdqV9s+1cLU2C2sAw7bB7o2Y/J9PBPiuBSsK8rmCLbUPYK6QefenwFE7Q==", - "license": "MIT", - "dependencies": { - "clsx": "^2.0.0" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-api-remotes": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-connection": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-locale": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-runtime": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-ui-conversation": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-client-ui-trajectory": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-client-ui-trajectory/-/dsh-client-ui-trajectory-0.1.0-rc.8.tgz", - "integrity": "sha512-nEKtvkbNhk1Qau8jpyvGfcGLCL2Tfmw6Oi72i2oiZ/DHIcsBaeD0JVWOraEmQp3jYVjuuLSdjdCiPkuNU9nwgw==", - "license": "MIT", - "dependencies": { - "@tanstack/react-virtual": "^3.14.9", - "diff": "^9.0.0" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-locale": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-runtime": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-ui-conversation": "^0.1.0-rc.8", - "@deepseek-ai/dsh-compaction": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-tools": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-client-ui-trajectory/node_modules/@tanstack/react-virtual": { - "version": "3.14.10", - "resolved": "https://registry.npmmirror.com/@tanstack/react-virtual/-/react-virtual-3.14.10.tgz", - "integrity": "sha512-SRyoUbdFMRHuYXMijV5H4ZarQWpXkj3iANq8OFre+pybeVap8ZJjZ3Nz9bVjx4d8PfobVUQUdKyyyHYk3E+djw==", - "license": "MIT", - "dependencies": { - "@tanstack/virtual-core": "3.17.8" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/tannerlinsley" - }, - "peerDependencies": { - "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", - "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" - } - }, - "node_modules/@deepseek-ai/dsh-client-ui-trajectory/node_modules/react": { - "version": "19.2.8", - "resolved": "https://registry.npmmirror.com/react/-/react-19.2.8.tgz", - "integrity": "sha512-PWaYA1L/q9u2u7xYQi+Y3L3Yfnie7XyLeaJICV1MGD6LprsBxcAqGjYyr0eY3p+QdsA+x/Irkt4Qif8D63+Sbw==", - "license": "MIT", - "peer": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/@deepseek-ai/dsh-client-ui-trajectory/node_modules/react-dom": { - "version": "19.2.8", - "resolved": "https://registry.npmmirror.com/react-dom/-/react-dom-19.2.8.tgz", - "integrity": "sha512-rVprimfGBG3DR+Tq0IQG2DT5PxKth1WIGDmj5yPmlzr4YBe7uyE+Du4oVqTDXZSHGGGXRtTJEGSSePyQCMBglQ==", - "license": "MIT", - "peer": true, - "dependencies": { - "scheduler": "^0.27.0" - }, - "peerDependencies": { - "react": "^19.2.8" - } - }, - "node_modules/@deepseek-ai/dsh-client-ui-user-questions": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-client-ui-user-questions/-/dsh-client-ui-user-questions-0.1.0-rc.8.tgz", - "integrity": "sha512-zv2U7Ur1ovGSU7j5mwsiCHUK/L20IXRcSFBis3kDZ9nMMl9m0N+56bXrZtJD1U9kTU7gtJ4Xat+rDpr3uTn0JA==", - "license": "MIT", - "dependencies": { - "clsx": "^2.0.0" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-api-remotes": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-locale": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-runtime": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-ui-conversation": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-client-ui-workflow-run": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-client-ui-workflow-run/-/dsh-client-ui-workflow-run-0.1.0-rc.8.tgz", - "integrity": "sha512-lVvzaR66JwR2lgdURooLEyinUFu5cSaJLWBgdLetw0Z1B6N4RzBNwiIZxmIEZKwaVS7vhO9w6mphGV+4ujiypA==", - "license": "MIT", - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-client-locale": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-runtime": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-ui-conversation": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session": "^0.1.0-rc.8", - "@deepseek-ai/dsh-tool-workflow": "^0.1.0-rc.8", - "@deepseek-ai/dsh-workflow": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-client-ui-workspace": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-client-ui-workspace/-/dsh-client-ui-workspace-0.1.0-rc.8.tgz", - "integrity": "sha512-Il4hRRV9cDXyZptVC/OKHHOPNd84SwtflHCJ6RP97+OYxnENftdKgHENX7Kqf1RsSXF8RwmOtEvZoHljvYD79A==", - "license": "MIT", - "dependencies": { - "clsx": "^2.0.0" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-client-connection": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-locale": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-runtime": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-ui-conversation": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-ui-sidebar": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-cmdline": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-cmdline/-/dsh-cmdline-0.1.0-rc.8.tgz", - "integrity": "sha512-xsnNFm2XpMD9wpBBLq80x8yXTi664DHywkLwxgAhDsWyp9tB2aSWaWVKxugPWSWwrB3F4nfloWqaeUfgXRFtBQ==", - "license": "MIT", - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/cordis-plugin-loader": "^1.0.2", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-code-runtime": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-code-runtime/-/dsh-code-runtime-0.1.0-rc.8.tgz", - "integrity": "sha512-6ZKyEE7dHH1UkKe5b0lg18Byww/7ocZyrNMVjAoUWEWp5i96Brf9Eavu9q3zepBMDMZJErCfV0pyt7KDhBJSig==", - "license": "MIT", - "peer": true, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-code-runtime-worker-thread": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-code-runtime-worker-thread/-/dsh-code-runtime-worker-thread-0.1.0-rc.8.tgz", - "integrity": "sha512-l9fsKYZN2qthnR8fbH8LrTbhWman8rjFCumIttahOKvQEjFMWImY1p8ypM3QtreAtUF8jyHdDnlV8xWQLfanmA==", - "license": "MIT", - "dependencies": { - "@deepseek-ai/schemastery": "^3.18.1" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-code-runtime": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session": "^0.1.0-rc.8", - "@deepseek-ai/dsh-timeout": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-command-compact": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-command-compact/-/dsh-command-compact-0.1.0-rc.8.tgz", - "integrity": "sha512-3Zlgw9ghDvj2/22/O7V4kvkxKRfknQw4t9ks5GtBEEVRuU9ullpFElAwq/EZ049zeCnmHnyskyJmwYZRIGaiRA==", - "license": "MIT", - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-commands": "^0.1.0-rc.8", - "@deepseek-ai/dsh-compaction": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-command-feedback": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-command-feedback/-/dsh-command-feedback-0.1.0-rc.8.tgz", - "integrity": "sha512-RqEcutd+nHVGND/JobUybb8HsgRigr5iEowDk0D7aZeXFJ3tN/0pW67w7DOxdhAVnODIpWg5tSnFpCT8fS78kQ==", - "license": "MIT", - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-anonymous-user-id": "^0.1.0-rc.8", - "@deepseek-ai/dsh-commands": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session-telemetry": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-command-goal": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-command-goal/-/dsh-command-goal-0.1.0-rc.8.tgz", - "integrity": "sha512-kMjRuGJA79czVNzx//JEMrjAqDvYpiaOSH95NUu+Mome76S34jmnhCnIyzcg02GcXelDbk9epELAz5HR1Yti/Q==", - "license": "MIT", - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-commands": "^0.1.0-rc.8", - "@deepseek-ai/dsh-goal": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-llm": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-commands": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-commands/-/dsh-commands-0.1.0-rc.8.tgz", - "integrity": "sha512-/i99EDLrUyd4bUVn4d7XS46vg09ZE0ervbE/aQaVUWLjDYKrarb7hPx9slADAg5/cUlJsN6L6CP544h9qlUo4g==", - "license": "MIT", - "dependencies": { - "zod": "^4.4.3" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", - "@deepseek-ai/dsh-attachment": "^0.1.0-rc.8", - "@deepseek-ai/dsh-brand": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", - "@deepseek-ai/dsh-scope": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session": "^0.1.0-rc.8", - "@deepseek-ai/dsh-typert-protocol": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-compaction": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-compaction/-/dsh-compaction-0.1.0-rc.8.tgz", - "integrity": "sha512-sWNqZqejzpKsnEMPsNVA/WYK4S59XlYJtnWw8wCPushzQdUt5zhf+g7LVx0cStSozEfwurxRvaZdOmNaa4WhNQ==", - "license": "MIT", - "peer": true, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-brand": "^0.1.0-rc.8", - "@deepseek-ai/dsh-commands": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-compaction-basic": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-compaction-basic/-/dsh-compaction-basic-0.1.0-rc.8.tgz", - "integrity": "sha512-UWAUbJbxFQTI3m4LnwZDlcYOfzWNFN1WLjy0qNONNcz3BBa5Nu9kcz4C9jioSp6pg3KMfUNUOtbBRySigTIt7g==", - "license": "MIT", - "dependencies": { - "@deepseek-ai/schemastery": "^3.18.1" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", - "@deepseek-ai/dsh-commands": "^0.1.0-rc.8", - "@deepseek-ai/dsh-compaction": "^0.1.0-rc.8", - "@deepseek-ai/dsh-compaction-tool-result-pruner": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session": "^0.1.0-rc.8", - "@deepseek-ai/dsh-token-meter": "^0.1.0-rc.8" - }, - "peerDependenciesMeta": { - "@deepseek-ai/dsh-compaction-tool-result-pruner": { - "optional": true - } - } - }, - "node_modules/@deepseek-ai/dsh-compaction-tool-result-pruner": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-compaction-tool-result-pruner/-/dsh-compaction-tool-result-pruner-0.1.0-rc.8.tgz", - "integrity": "sha512-Mk1QE57HxCMScgQ9ury0o7AM14h6g41cDg1G2kiNqD4Z2LBwFTlZJJAgipyhts4mcr1hz2WZTc8Xgbl9067ONA==", - "license": "MIT", - "dependencies": { - "@deepseek-ai/schemastery": "^3.18.1" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-compaction": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session": "^0.1.0-rc.8", - "@deepseek-ai/dsh-token-meter": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-cordis-client-runner": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-cordis-client-runner/-/dsh-cordis-client-runner-0.1.0-rc.8.tgz", - "integrity": "sha512-UbV2zFdOCubLAjQkmYi+6aPxxDfFTSshiyL4EHRbZyqQTdhrnDMfkY48SiVz8s026+E8xxGRPU4kNf3lg5DGeA==", - "license": "MIT", - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/cordis-plugin-loader": "^1.0.2", - "@deepseek-ai/dsh-api-remotes": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-connection": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-modules": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-runtime": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-ui-theme": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-cordis-host-runner": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-cordis-host-runner/-/dsh-cordis-host-runner-0.1.0-rc.8.tgz", - "integrity": "sha512-DCJr6INHCI0Dypr1JAJj/BnvN31tpIt3Y8+KQ3GDfHW6pUBsc9GnXHpKsuQ4sK/fTj80GjaDYPGdWeB/uKMMdw==", - "license": "MIT", - "dependencies": { - "@deepseek-ai/schemastery": "^3.18.1", - "zod": "^4.4.3" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", - "@deepseek-ai/dsh-brand": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", - "@deepseek-ai/dsh-scope": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session": "^0.1.0-rc.8", - "@deepseek-ai/dsh-tools": "^0.1.0-rc.8", - "@deepseek-ai/dsh-typert-protocol": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-credentials": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-credentials/-/dsh-credentials-0.1.0-rc.8.tgz", - "integrity": "sha512-VopOhtUEa/fSmJr3fyKbsEG043kX1oGuBrmELAbkhmuDigl1cN88g0VPb9rMG2/dJ1h08wg+h0RJP+Ex4LjRWw==", - "license": "MIT", - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-brand": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-credentials-local": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-credentials-local/-/dsh-credentials-local-0.1.0-rc.8.tgz", - "integrity": "sha512-Msbz/+xNIHFXLjcDy2hZFpfV1qduuyjLl35BJOUqNz9eCEYv8b0lfKDI7nirv5E/TdxzLkO75WQ4f+8nifeUpQ==", - "license": "MIT", - "dependencies": { - "@deepseek-ai/schemastery": "^3.18.1", - "chokidar": "^4.0.3", - "yaml": "^2.9.0" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-atomic-write": "^0.1.0-rc.8", - "@deepseek-ai/dsh-credentials": "^0.1.0-rc.8", - "@deepseek-ai/dsh-home-paths": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-launch-environment": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-file-reference": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-file-reference/-/dsh-file-reference-0.1.0-rc.8.tgz", - "integrity": "sha512-SoU4Zm7L8E9ud5nTs1tVAINFrgKvIKypCdOOMLBjJkjLUvXMYmKFxfCM7xaJjOmK/C5suEVUtpukZhZZvZALNA==", - "license": "MIT", - "dependencies": { - "zod": "^4.4.3" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-typert-protocol": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-file-reference-local": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-file-reference-local/-/dsh-file-reference-local-0.1.0-rc.8.tgz", - "integrity": "sha512-dw3p1NmuDgJkse1J2RuLwgfiySEFiyRL40o3mo1ireGxXt85JfLns1FR2mdN6v7z6pBpIogGPKV//0U31BWTfg==", - "license": "MIT", - "dependencies": { - "@deepseek-ai/schemastery": "^3.18.1" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", - "@deepseek-ai/dsh-file-reference": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-system-prompt": "^0.1.0-rc.8", - "@deepseek-ai/dsh-tools": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-fs": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-fs/-/dsh-fs-0.1.0-rc.8.tgz", - "integrity": "sha512-ge5GW56+z20vYACQ2jqtevusdgMXa64laeU/Chql+VIA3+6xyJ8gLX+oj/1O5TlzhvmZ7ZPfZGBFBEVsEZzTQw==", - "license": "MIT", - "peer": true, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-brand": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", - "@deepseek-ai/dsh-sandbox": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-fs-local": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-fs-local/-/dsh-fs-local-0.1.0-rc.8.tgz", - "integrity": "sha512-yWk6WrAHs8b6395XnZZOCf3wY90xYKjh/tyU3/rwFy4oU8zq9gzn/x8rdaZD0zUp+wE0XqfBf2AS4Jo03SKHyQ==", - "license": "MIT", - "dependencies": { - "@deepseek-ai/schemastery": "^3.18.1", - "koffi": "^3.1.0" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-fs": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-fs-observation-policy": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-fs-observation-policy/-/dsh-fs-observation-policy-0.1.0-rc.8.tgz", - "integrity": "sha512-iarNlz2QoEROJUOHPjy7OKOwXuGeEhzk6nWj95F+UHNvKKaquagBE8YE1gzFqbg2U1wFVmPGoHBYl8q7hb5Z8Q==", - "license": "MIT", - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-fs": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-fs-sandbox": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-fs-sandbox/-/dsh-fs-sandbox-0.1.0-rc.8.tgz", - "integrity": "sha512-JfNgZHFyUyqO5XV/KQ2msO9OQ+98WrGCyfQp34yqCbIXSGS2r471C35Sub+OyTlpCkavGFUjsxo3iT7PLGyVVw==", - "license": "MIT", - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-fs": "^0.1.0-rc.8", - "@deepseek-ai/dsh-fs-local": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-sandbox": "^0.1.0-rc.8", - "@deepseek-ai/dsh-sandbox-policy": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-goal": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-goal/-/dsh-goal-0.1.0-rc.8.tgz", - "integrity": "sha512-PR/9JjRn2H/33eyAVbtYBxzRWQhFO5N0S/188eAV9gjUTtHe5oSOnPxYy8iNkkMXxr+VE8Nno25Sun8WYmS8lQ==", - "license": "MIT", - "dependencies": { - "@deepseek-ai/schemastery": "^3.18.1", - "zod": "^4.4.3" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", - "@deepseek-ai/dsh-brand": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", - "@deepseek-ai/dsh-scope": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session-projection": "^0.1.0-rc.8", - "@deepseek-ai/dsh-typert-protocol": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-goal-round-driver": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-goal-round-driver/-/dsh-goal-round-driver-0.1.0-rc.8.tgz", - "integrity": "sha512-hCOOofSuqYxWo+Zc/vcF1C+qk38JEgzJ2ya4bBisWYiRwVFygHODquQllK5ffDjFM+SnX+CdmA+l2piiwCkzcA==", - "license": "MIT", - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", - "@deepseek-ai/dsh-goal": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-headless": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-headless/-/dsh-headless-0.1.0-rc.8.tgz", - "integrity": "sha512-SfjPjyLeno7iScndgFI3s9s8focqXADLNgIxkFbsL0BdAY7v3A6TOe+iSxnYX0fMhDqFC1jT3FVYlEzbJBg0Kg==", - "license": "MIT", - "dependencies": { - "@deepseek-ai/dsh-cmdline": "^0.1.0-rc.8", - "@deepseek-ai/dsh-code-runtime-worker-thread": "^0.1.0-rc.8", - "@deepseek-ai/schemastery": "^3.18.1", - "commander": "^15.0.0" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/cordis-plugin-loader": "^1.0.2", - "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", - "@deepseek-ai/dsh-agent-default-model": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-home-paths": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-home-paths/-/dsh-home-paths-0.1.0-rc.8.tgz", - "integrity": "sha512-9cQhH9CZsw7Zi73VnZk7CcuEVA6yR/Ox+7lp3VHq53fFYSPi0RL+kMWmh5XCrZB4U1OM3+PVsWsA5II9tB+t0Q==", - "license": "MIT", - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-host-apiproxy": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-host-apiproxy/-/dsh-host-apiproxy-0.1.0-rc.8.tgz", - "integrity": "sha512-viq2CoS6bRavSe1t9sLjgunykO+Vn/m83uSgONMH8O7QN0Pk3+FnZGHlPZ1lQ4auNJTwQjxFG6w372cGq9usWw==", - "license": "MIT", - "dependencies": { - "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", - "@deepseek-ai/dsh-agent-default-model": "^0.1.0-rc.8", - "@deepseek-ai/dsh-api-remotes": "^0.1.0-rc.8", - "@deepseek-ai/dsh-attachment": "^0.1.0-rc.8", - "@deepseek-ai/dsh-brand": "^0.1.0-rc.8", - "@deepseek-ai/dsh-commands": "^0.1.0-rc.8", - "@deepseek-ai/dsh-credentials": "^0.1.0-rc.8", - "@deepseek-ai/dsh-goal": "^0.1.0-rc.8", - "@deepseek-ai/dsh-host-directory-picker": "^0.1.0-rc.8", - "@deepseek-ai/dsh-jobs": "^0.1.0-rc.8", - "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", - "@deepseek-ai/dsh-native-command": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session-persistence": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session-projection": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session-projection-cache": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session-query": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session-title": "^0.1.0-rc.8", - "@deepseek-ai/dsh-settings": "^0.1.0-rc.8", - "@deepseek-ai/dsh-skill": "^0.1.0-rc.8", - "@deepseek-ai/dsh-subagent": "^0.1.0-rc.8", - "@deepseek-ai/dsh-tools": "^0.1.0-rc.8", - "@deepseek-ai/dsh-user-approval": "^0.1.0-rc.8", - "@deepseek-ai/dsh-user-questions": "^0.1.0-rc.8", - "@deepseek-ai/dsh-workspace": "^0.1.0-rc.8", - "@deepseek-ai/schemastery": "^3.18.1", - "fflate": "^0.8.2", - "zod": "^4.4.3" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-agent-presets": "^0.1.0-rc.8", - "@deepseek-ai/dsh-cordis-host-runner": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-host-directory-picker": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-host-directory-picker/-/dsh-host-directory-picker-0.1.0-rc.8.tgz", - "integrity": "sha512-aOUaUX0MTl8oLIuL27OkATMm+x2oTANuhhHpeGizn7+kfOX5bRKB3tyi7h6lGZ9O7WDiDLl2JajRqzBXlIPAAg==", - "license": "MIT", - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-host-directory-picker-auto": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-host-directory-picker-auto/-/dsh-host-directory-picker-auto-0.1.0-rc.8.tgz", - "integrity": "sha512-t6sn3AlcAARVCOgYMNZS/Yneiw+/2mDM6QOGxR6bu5E7DYTT/tllHe0PlHF1Wgh/LtfOTeDtcSPPfXjmrd+Lqw==", - "license": "MIT", - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/cordis-plugin-loader": "^1.0.2", - "@deepseek-ai/dsh-client-ui-directory-picker-browse": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-ui-directory-picker-native": "^0.1.0-rc.8", - "@deepseek-ai/dsh-host-directory-picker-browse": "^0.1.0-rc.8", - "@deepseek-ai/dsh-host-directory-picker-native": "^0.1.0-rc.8", - "@deepseek-ai/dsh-host-webserver": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-host-directory-picker-browse": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-host-directory-picker-browse/-/dsh-host-directory-picker-browse-0.1.0-rc.8.tgz", - "integrity": "sha512-zEQ7Wnz953GWiR3Y9GaqPGmhntEdjmcD+x6cbYKXWyeOtMHvv7Lu9EWGNneFHXFt50nMinDBT5kyGzElZ+cajA==", - "license": "MIT", - "dependencies": { - "@deepseek-ai/dsh-host-directory-picker": "^0.1.0-rc.8", - "@deepseek-ai/schemastery": "^3.18.1" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-host-directory-picker-native": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-host-directory-picker-native/-/dsh-host-directory-picker-native-0.1.0-rc.8.tgz", - "integrity": "sha512-WUB4lW+ZmR743uH9LpFK0JrJU88601E7zvevffa93n7Bl4X7C5Y2yhbDK337H8W/brVlLNVgD2Fw2H/nIPZkDg==", - "license": "MIT", - "dependencies": { - "@deepseek-ai/dsh-host-directory-picker": "^0.1.0-rc.8", - "@deepseek-ai/dsh-native-command": "^0.1.0-rc.8", - "koffi": "^3.1.0" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-host-frontend-static": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-host-frontend-static/-/dsh-host-frontend-static-0.1.0-rc.8.tgz", - "integrity": "sha512-/ef1xAygNL9hyGtSDzJ04nM5WSNzSxsloSUD2MQfM0FU3Y6b/CbHkUNFYaS0MnhS1YVSulDAGRQvXSgES8vZkg==", - "license": "MIT", - "dependencies": { - "@deepseek-ai/schemastery": "^3.18.1" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-host-webserver": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-host-plugin-inventory": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-host-plugin-inventory/-/dsh-host-plugin-inventory-0.1.0-rc.8.tgz", - "integrity": "sha512-knPtxCDZn1jbwRfOUnskjaj8hSXUCfBcjD9LPFXnKffsM6TFOeQrFGhkNKlZteXAMSChtY6pV9bpJj17y3SPNg==", - "license": "MIT", - "dependencies": { - "zod": "^4.4.3" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/cordis-plugin-loader": "^1.0.2", - "@deepseek-ai/dsh-brand": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-typert-protocol": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-host-webserver": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-host-webserver/-/dsh-host-webserver-0.1.0-rc.8.tgz", - "integrity": "sha512-MEKFrhvsYfj970QHLaKPpF/sIBpCe8NuSA0HGiWYJctX6TM9N3rLRhXx5p3zATDmXZclu1rbYhIbsqWw/twPig==", - "license": "MIT", - "dependencies": { - "@deepseek-ai/schemastery": "^3.18.1" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-invariants": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-invariants/-/dsh-invariants-0.1.0-rc.8.tgz", - "integrity": "sha512-u0lYqyxOYwfsVnbsfGXZos5vFvA4cqFnBEW3/ezgljNwkYwzeUP/Y5wjPnQjP+ZzBn3CnVeIF6s2N2Vk3iA5mQ==", - "license": "MIT", - "peer": true, - "dependencies": { - "@deepseek-ai/schemastery": "^3.18.1" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1" - } - }, - "node_modules/@deepseek-ai/dsh-jobs": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-jobs/-/dsh-jobs-0.1.0-rc.8.tgz", - "integrity": "sha512-HqQudOA4VkjCMpxWiqTCMmuiTa/pehW6yG7dDsctO1vW5K48hWQ/h7czdJKgrh4SMuK4kchv3IipS1KaJmdaog==", - "license": "MIT", - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", - "@deepseek-ai/dsh-brand": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-jobs-local": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-jobs-local/-/dsh-jobs-local-0.1.0-rc.8.tgz", - "integrity": "sha512-8/cr4rYVS2sLB/Z4lL/ERUn14iBqT9T85rJFxxhEKuT3gMcAkiJuKP7t+ZFWPYSSmcNqDPmMI1ExG+GzjxsLVQ==", - "license": "MIT", - "dependencies": { - "@deepseek-ai/schemastery": "^3.18.1" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-jobs": "^0.1.0-rc.8", - "@deepseek-ai/dsh-scope": "^0.1.0-rc.8", - "@deepseek-ai/dsh-timeout": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-launch-environment": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-launch-environment/-/dsh-launch-environment-0.1.0-rc.8.tgz", - "integrity": "sha512-VvYo5R7tu4QhX/dsNpuBy3AaauizU6yPCeWQUNzI3ZjGA0VHkkZhInilcgxVJkPA1lwEXYB+OoCAo07PUy6D/w==", - "license": "MIT", - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-llm": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-llm/-/dsh-llm-0.1.0-rc.8.tgz", - "integrity": "sha512-hf6RmX2Stn1UtzpktSHQLkIktQkBm9i/3yFfJlbGSkwyw5Cv9sTYJbyoHzsSnnh6i8nRRcMcBhvMgm23I00oIw==", - "license": "MIT", - "dependencies": { - "@deepseek-ai/schemastery": "^3.18.1" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-attachment": "^0.1.0-rc.8", - "@deepseek-ai/dsh-brand": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-timeout": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-llm-deepseek": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-llm-deepseek/-/dsh-llm-deepseek-0.1.0-rc.8.tgz", - "integrity": "sha512-s4LatnGbHwPJhcWGulO/7RsJBPHHBDB+2+1iRTJEn6vYPB0lOSRWtr91qdmAkUxBZmK5mwrf21IbuW+kWwtAZQ==", - "license": "MIT", - "dependencies": { - "@deepseek-ai/schemastery": "^3.18.1", - "eventsource-parser": "^3.1.0" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-anonymous-user-id": "^0.1.0-rc.8", - "@deepseek-ai/dsh-attachment": "^0.1.0-rc.8", - "@deepseek-ai/dsh-credentials": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-launch-environment": "^0.1.0-rc.8", - "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", - "@deepseek-ai/dsh-settings": "^0.1.0-rc.8", - "@deepseek-ai/dsh-timeout": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-llm-pi-ai": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-llm-pi-ai/-/dsh-llm-pi-ai-0.1.0-rc.8.tgz", - "integrity": "sha512-r9dmHYy759gKtAG0S96wTCS6O8WFDqGLQu8t+zGY6LnfdT4qUJdmWtJ+GwCn+BGwq1AglBzjabvyRBp6BxXcMQ==", - "license": "MIT", - "dependencies": { - "@deepseek-ai/schemastery": "^3.18.1", - "@earendil-works/pi-ai": "^0.82.1" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-attachment": "^0.1.0-rc.8", - "@deepseek-ai/dsh-credentials": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-launch-environment": "^0.1.0-rc.8", - "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", - "@deepseek-ai/dsh-settings": "^0.1.0-rc.8", - "@deepseek-ai/dsh-timeout": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-llm-retry": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-llm-retry/-/dsh-llm-retry-0.1.0-rc.8.tgz", - "integrity": "sha512-DmcOajgiku5l7aa5hU9DtwnIZu+i/XCGdb+Wego5W9bAswYeBAwbceloRNE3O6+jdRzy+K5U7KQ9V+olBsNqRQ==", - "license": "MIT", - "dependencies": { - "@deepseek-ai/schemastery": "^3.18.1" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", - "@deepseek-ai/dsh-brand": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session": "^0.1.0-rc.8", - "@deepseek-ai/dsh-timeout": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-mcp-client": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-mcp-client/-/dsh-mcp-client-0.1.0-rc.8.tgz", - "integrity": "sha512-pcqXawjq9jRJQNHZTLN7pswJFMWjxCsEOdHUI9BdJqb9lRDsMi2cul1Hizfi51oKkcNo1u/K9Toqgh8o/ScAXg==", - "license": "MIT", - "dependencies": { - "@deepseek-ai/schemastery": "^3.18.1", - "@modelcontextprotocol/sdk": "^1.12.0", - "zod": "^4.4.3" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-attachment": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", - "@deepseek-ai/dsh-subprocess": "^0.1.0-rc.8", - "@deepseek-ai/dsh-timeout": "^0.1.0-rc.8", - "@deepseek-ai/dsh-tools": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-message-feedback": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-message-feedback/-/dsh-message-feedback-0.1.0-rc.8.tgz", - "integrity": "sha512-5DYXVLcnvTRs74Att52LGNR+x+RCf1X5s5+gOSUddsjnQ0wn4f3pzfc0o4F+91aE2zX3xzQ3/LhlW5UOJdkB0Q==", - "license": "MIT", - "dependencies": { - "@deepseek-ai/schemastery": "^3.18.1", - "zod": "^4.4.3" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-brand": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session-persistence": "^0.1.0-rc.8", - "@deepseek-ai/dsh-storage-domain": "^0.1.0-rc.8", - "@deepseek-ai/dsh-typert-protocol": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-native-command": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-native-command/-/dsh-native-command-0.1.0-rc.8.tgz", - "integrity": "sha512-bRaT8LOb2xmWQ88oSzM4+Y3N4Yy4J0tf15/kQTP53PY1FnOA5hGYWoRglQgfxIcJCrw4fEdUPie8Fff0dCOwdQ==", - "license": "MIT", - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-output-retention": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-output-retention/-/dsh-output-retention-0.1.0-rc.8.tgz", - "integrity": "sha512-DeVjqZ9TtH2AEG57GBsHYT68274VygzuP9EqQLL01Ht1TrdK75xlVet1l3jdEbA7Eik4aSGDjAZD9/MsnlUIXg==", - "license": "MIT", - "peer": true, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-permission-presets": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-permission-presets/-/dsh-permission-presets-0.1.0-rc.8.tgz", - "integrity": "sha512-EeTn8Av5kmb1Qj53D7myRnKcNQrrupGrM2m9LVUO8ieWvlIaYX7n2g0y8kg14SUpcD2YzaT40oGJ6VeDuhTZAA==", - "license": "MIT", - "dependencies": { - "@deepseek-ai/schemastery": "^3.18.1", - "zod": "^4.4.3" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-commands": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-sandbox": "^0.1.0-rc.8", - "@deepseek-ai/dsh-sandbox-policy": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session-projection": "^0.1.0-rc.8", - "@deepseek-ai/dsh-settings": "^0.1.0-rc.8", - "@deepseek-ai/dsh-shell": "^0.1.0-rc.8", - "@deepseek-ai/dsh-user-approval": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-persona": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-persona/-/dsh-persona-0.1.0-rc.8.tgz", - "integrity": "sha512-3COzIzZ5kBd+txuH418h9HG4feuVFyhdh02HWvzsWgaPsxjatuFS0OfS6qsejUTZrFDODQSr1WIOeSt80bDBtA==", - "license": "MIT", - "dependencies": { - "@deepseek-ai/schemastery": "^3.18.1" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-system-prompt": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-plan-mode": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-plan-mode/-/dsh-plan-mode-0.1.0-rc.8.tgz", - "integrity": "sha512-/SY/iil7KLDvveqKRUZxO4HiADwDlOX9u3xyG/93h785mWSfRXooiv4Zp2tiBjU+pJB0tJXMsQNAXDdg7DWtwA==", - "license": "MIT", - "dependencies": { - "zod": "^4.4.3" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", - "@deepseek-ai/dsh-commands": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session-projection": "^0.1.0-rc.8", - "@deepseek-ai/dsh-system-prompt": "^0.1.0-rc.8", - "@deepseek-ai/dsh-tools": "^0.1.0-rc.8", - "@deepseek-ai/dsh-user-questions": "^0.1.0-rc.8" - }, - "peerDependenciesMeta": { - "@deepseek-ai/dsh-commands": { - "optional": true - } - } - }, - "node_modules/@deepseek-ai/dsh-pwsh-local": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-pwsh-local/-/dsh-pwsh-local-0.1.0-rc.8.tgz", - "integrity": "sha512-lHAEwC4pL5bVSKgwaeO2dMM9s/jnpDBRuTeVD2HkunpFfT1Kq4lFi+/YXj00L7mW9DBP6FMfwRRV/0Wgo1FtdA==", - "license": "MIT", - "dependencies": { - "@deepseek-ai/schemastery": "^3.18.1" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-settings": "^0.1.0-rc.8", - "@deepseek-ai/dsh-shell": "^0.1.0-rc.8", - "@deepseek-ai/dsh-subprocess": "^0.1.0-rc.8", - "@deepseek-ai/dsh-timeout": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-pwsh-sandbox": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-pwsh-sandbox/-/dsh-pwsh-sandbox-0.1.0-rc.8.tgz", - "integrity": "sha512-GVvj4zqpC/lwCGaRmIXIhFqOqewgoGOuokGFuv0QcjQUY3v9FnPor2dqDZr5pav8KFGb5GeGUzLoUbedmsWyZg==", - "license": "MIT", - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-pwsh-local": "^0.1.0-rc.8", - "@deepseek-ai/dsh-sandbox": "^0.1.0-rc.8", - "@deepseek-ai/dsh-sandbox-policy": "^0.1.0-rc.8", - "@deepseek-ai/dsh-shell": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-repeat-tool-reminder": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-repeat-tool-reminder/-/dsh-repeat-tool-reminder-0.1.0-rc.8.tgz", - "integrity": "sha512-p7/g+NH6JJ0BnLx2V5o0hCm4wZr+dXQ9/Ev8LU6YyFRlcnma8TJuATL0wsA01xWfvvGLRxbe/tH41TRS1NVrJg==", - "license": "MIT", - "dependencies": { - "@deepseek-ai/schemastery": "^3.18.1" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-tools": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-sandbox": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-sandbox/-/dsh-sandbox-0.1.0-rc.8.tgz", - "integrity": "sha512-dJpy5p/KjKkHG9AnMKU4+/ilj/4DCglsq3kof/jhIwtsZJCix07TEXP9vV8LCv4fU8af7cK3antXw4eVMqkwuQ==", - "license": "MIT", - "peer": true, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-sandbox-local": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-sandbox-local/-/dsh-sandbox-local-0.1.0-rc.8.tgz", - "integrity": "sha512-sTrKDXD74yG6B24uhCyN9DuGSpX0SCelN4o5DZylKxt56WRRyywAGdLN0Xt8enqiKCxrq+PJBi+hDh2GtXBj6w==", - "license": "MIT", - "dependencies": { - "@deepseek-ai/dsh-sandbox-windows-acl": "^0.1.0-rc.8", - "@deepseek-ai/node-addon-landlock-run": "^0.1.1", - "@deepseek-ai/schemastery": "^3.18.1" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", - "@deepseek-ai/dsh-sandbox": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-sandbox-policy": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-sandbox-policy/-/dsh-sandbox-policy-0.1.0-rc.8.tgz", - "integrity": "sha512-xQOlYWbUr1Oj6cnRd5aHZIz52EOEAdSO1HJIfeDkQrVaOgohFsiiCIp6PNFumuGNWdCEnf4Q18ebafLNtazYlA==", - "license": "MIT", - "dependencies": { - "@deepseek-ai/schemastery": "^3.18.1" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-sandbox": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session": "^0.1.0-rc.8", - "@deepseek-ai/dsh-system-prompt": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-sandbox-windows-acl": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-sandbox-windows-acl/-/dsh-sandbox-windows-acl-0.1.0-rc.8.tgz", - "integrity": "sha512-3DeFPD+laUbXrzVpEJ0FrF5pMQCqeu7YCJAWgORGj1aju7sIjpineEnKpE6EXhbc8C9Jqu2y5S7B9z6ydOL/Zg==", - "license": "MIT", - "dependencies": { - "koffi": "^3.1.0" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-schedule": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-schedule/-/dsh-schedule-0.1.0-rc.8.tgz", - "integrity": "sha512-L4GO1Bv3+SHIXafjGQcf0sJI9eTf9whxVmYlBxYHw7h7StOZJPMhG9HpsKz4mO9FZ7J4zhBtpYlFbhOQaJheqA==", - "license": "MIT", - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", - "@deepseek-ai/dsh-brand": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session-persistence": "^0.1.0-rc.8", - "@deepseek-ai/dsh-tools": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-scope": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-scope/-/dsh-scope-0.1.0-rc.8.tgz", - "integrity": "sha512-/o+PxkVV2zUy9lYlMFr4TWSb+ESW4DE+fI891yIbsLzOJdFgfbmmLpGrlWgnz8/unIGJZxjeXdwyppV04Z277Q==", - "license": "MIT", - "peer": true, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-session": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-session/-/dsh-session-0.1.0-rc.8.tgz", - "integrity": "sha512-Qs5Mgn32WPPVB4rKHjsZBgLOkh0TQurUAcc9GaDVudK4dUkpno2HDh++qu/PrwRA3CZ/iwPAoFHCpB3AMMaoLg==", - "license": "MIT", - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-brand": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", - "@deepseek-ai/dsh-scope": "^0.1.0-rc.8", - "@deepseek-ai/dsh-typert-protocol": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-session-checkpoint-policy": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-session-checkpoint-policy/-/dsh-session-checkpoint-policy-0.1.0-rc.8.tgz", - "integrity": "sha512-9DpZhQN4MExSjbjBSmaH08DmFS/GHRrsVhO5e3WgTVuH13ugdl5yxc4MEb8qvOhEJUUtOx3fXHuMpSTa0Dxa7w==", - "license": "MIT", - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session-persistence": "^0.1.0-rc.8", - "@deepseek-ai/dsh-tools": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-session-log-export": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-session-log-export/-/dsh-session-log-export-0.1.0-rc.8.tgz", - "integrity": "sha512-6vDC7uH0WZkwmlj/iql6AmSL9Uifiqi28OIZSDIi8/KRHDHnt5hvjobJecuIxhV9hQSDmNsstErHGx4ng2GJFQ==", - "license": "MIT", - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-client-locale": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-runtime": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-ui-commands": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-ui-conversation": "^0.1.0-rc.8", - "@deepseek-ai/dsh-commands": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-session-persistence": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-session-persistence/-/dsh-session-persistence-0.1.0-rc.8.tgz", - "integrity": "sha512-JujorG/UCern0+zxJzNswyWl2tFG9sLzfVNvA5YkTLaRLZt7ZsEhxG4DxWZ6uj+3RJ8sf4bqdKqvpIn9t1pwUw==", - "license": "MIT", - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-brand": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session": "^0.1.0-rc.8", - "@deepseek-ai/dsh-timeout": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-session-persistence-jsonl": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-session-persistence-jsonl/-/dsh-session-persistence-jsonl-0.1.0-rc.8.tgz", - "integrity": "sha512-T/Lvh76O2tpVw04FAhgLF3Qovq3SrUnzaywIbB+Uw67a2DD63Qg+cJY9WO6Pu/UowPxbpuUOd12c6iPY5x8d7Q==", - "license": "MIT", - "dependencies": { - "@deepseek-ai/schemastery": "^3.18.1", - "koffi": "^3.1.0" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session-persistence": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-session-projection": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-session-projection/-/dsh-session-projection-0.1.0-rc.8.tgz", - "integrity": "sha512-q00B+rl7WAuK0Bgh93SY2+ZpqaH2kJhfJ9n6Jg6R/m4plnH0Ip4oCAHl6u8rBzDgb1mniQGEQDz/7BN5Q3It8Q==", - "license": "MIT", - "dependencies": { - "zod": "^4.4.3" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-session-projection-cache": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-session-projection-cache/-/dsh-session-projection-cache-0.1.0-rc.8.tgz", - "integrity": "sha512-IPvO7k9FlekOJXn4XLWUwU5+JDQn7khu8Oa04GFDystU3c1CnOwoa7SGMHOfJau3r177M4ncXApwN5Ra6uhyXw==", - "license": "MIT", - "dependencies": { - "@deepseek-ai/schemastery": "^3.18.1", - "zod": "^4.4.3" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session-persistence": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session-projection": "^0.1.0-rc.8", - "@deepseek-ai/dsh-storage-domain": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-session-query": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-session-query/-/dsh-session-query-0.1.0-rc.8.tgz", - "integrity": "sha512-q8eyfpgPuJx24l1fEevDkc3Dux3lNp/yDzVkDL4nSTGNaDx/h9Y6iG7SZdqWM5nxOET3iwxi4AkPM7lYyLg3cQ==", - "license": "MIT", - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-brand": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session-persistence": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session-title": "^0.1.0-rc.8" - }, - "peerDependenciesMeta": { - "@deepseek-ai/dsh-session-persistence": { - "optional": true - } - } - }, - "node_modules/@deepseek-ai/dsh-session-query-sqlite": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-session-query-sqlite/-/dsh-session-query-sqlite-0.1.0-rc.8.tgz", - "integrity": "sha512-jrNq2vgWIH7OzNMHXrKEjEMwy86I36I94a8X5u937xo2B2JD8ZIWfuWHC9YyLqabRwNf7VcQ6VZ6ruSgESRE7A==", - "license": "MIT", - "dependencies": { - "@deepseek-ai/schemastery": "^3.18.1" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session-persistence": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session-query": "^0.1.0-rc.8" - }, - "peerDependenciesMeta": { - "@deepseek-ai/dsh-session-persistence": { - "optional": true - } - } - }, - "node_modules/@deepseek-ai/dsh-session-reference": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-session-reference/-/dsh-session-reference-0.1.0-rc.8.tgz", - "integrity": "sha512-meNS02BOkLc2SnF2qWvl5X1Psk59t0Q1vvwjfCkczD29g4nm7Y02EZ089HJKii0VAsSB39RYA2rf6MCSl6vhow==", - "license": "MIT", - "dependencies": { - "@deepseek-ai/schemastery": "^3.18.1", - "zod": "^4.4.3" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", - "@deepseek-ai/dsh-compaction": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", - "@deepseek-ai/dsh-output-retention": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session-query": "^0.1.0-rc.8", - "@deepseek-ai/dsh-typert-protocol": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-session-stats": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-session-stats/-/dsh-session-stats-0.1.0-rc.8.tgz", - "integrity": "sha512-T+SEzBkMxZpQ31MaeJCjaLN3/xu8yyZ3Va5u6osfq0nsJz1tvuZ53MHMbApdwERHVV0t/1eILTUo1J6XdksUEA==", - "license": "MIT", - "dependencies": { - "zod": "^4.4.3" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session-projection": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-session-telemetry": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-session-telemetry/-/dsh-session-telemetry-0.1.0-rc.8.tgz", - "integrity": "sha512-Rs7w+PP/uuOaa34RFY4q6Xjes/C32H0gPvZe/gV9M87y1EcJs+mFBzhnc/zyKeaAdT25RWIwO3KATmKlT/D0Dg==", - "license": "MIT", - "peer": true, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-session-telemetry-otel": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-session-telemetry-otel/-/dsh-session-telemetry-otel-0.1.0-rc.8.tgz", - "integrity": "sha512-rpPwidBwKV53WM2bYW/eYOZ6j5U9VHOIVrITQkQtGDMAzD9UaqfAXfXfUlsw9vsfjED2gKmSf7vn+bVfy8Tjaw==", - "license": "MIT", - "dependencies": { - "@deepseek-ai/schemastery": "^3.18.1", - "@opentelemetry/api": "^1.9.1", - "@opentelemetry/api-logs": "^0.220.0", - "@opentelemetry/exporter-logs-otlp-http": "^0.220.0", - "@opentelemetry/otlp-exporter-base": "^0.220.0", - "@opentelemetry/resources": "^2.9.0", - "@opentelemetry/sdk-logs": "^0.220.0" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-anonymous-user-id": "^0.1.0-rc.8", - "@deepseek-ai/dsh-command-feedback": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session-telemetry": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-session-title": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-session-title/-/dsh-session-title-0.1.0-rc.8.tgz", - "integrity": "sha512-OFG9kHFGnM5ND4LCkqg8oZr57qgF6xMkBxR/4MRaJJ42QrPI9QKzoZVRpNpXEl3v3uw8oR7Jj0jbc7WClNl3ow==", - "license": "MIT", - "dependencies": { - "@deepseek-ai/schemastery": "^3.18.1", - "zod": "^4.4.3" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-brand": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session-projection": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-session-title-first-prompt-llm": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-session-title-first-prompt-llm/-/dsh-session-title-first-prompt-llm-0.1.0-rc.8.tgz", - "integrity": "sha512-pFx2hPVYyRCRcbd4WJZVapVekLLEGMAG1KAcrixf3XOGDNaqVEPF8LWatx8iKQRfVSQlvIOwDO8uEsC0NZiPNA==", - "license": "MIT", - "dependencies": { - "@deepseek-ai/schemastery": "^3.18.1" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session-title": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session-title-llm": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-session-title-llm": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-session-title-llm/-/dsh-session-title-llm-0.1.0-rc.8.tgz", - "integrity": "sha512-6xz3umGBtGmM+t5O5wwlCwbH9gmBOlQBfg7qGnPJftWc4VWHG7l2VUYqd3DNTQVTHIA/hSN4qg/LXTm79rADGQ==", - "license": "MIT", - "peer": true, - "dependencies": { - "@deepseek-ai/schemastery": "^3.18.1" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session-title": "^0.1.0-rc.8", - "@deepseek-ai/dsh-timeout": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-settings": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-settings/-/dsh-settings-0.1.0-rc.8.tgz", - "integrity": "sha512-pqbMoiSP+Ieww9/4gcHYXcBCDlno1zYDu2OPq+5xdZ+McnK+5YBtHsiRpnR9cHQxGTH7lkfIv+adkOueQW0utg==", - "license": "MIT", - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-brand": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/schemastery": "^3.18.1" - } - }, - "node_modules/@deepseek-ai/dsh-settings-file": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-settings-file/-/dsh-settings-file-0.1.0-rc.8.tgz", - "integrity": "sha512-2mCyAPkxA5r7Ezgt41XtJxRBsj5Dkl21e5v7w+6YE3C8/n9zRRlN4X5oInHcUKEmgoTrNLCBCgOs5DNrl+pErw==", - "license": "MIT", - "dependencies": { - "@deepseek-ai/schemastery": "^3.18.1", - "chokidar": "^4.0.3", - "yaml": "^2.9.0" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-atomic-write": "^0.1.0-rc.8", - "@deepseek-ai/dsh-home-paths": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-settings": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-shell": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-shell/-/dsh-shell-0.1.0-rc.8.tgz", - "integrity": "sha512-RNhp7Y25DXUH7o36X4GcN0lnOLg6NXTlWZpYNURT7aDj3UHcLLajRsyddiAh1EbwQnl0GRKRZhLaZHrrG6gMIw==", - "license": "MIT", - "peer": true, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-sandbox": "^0.1.0-rc.8", - "@deepseek-ai/dsh-settings": "^0.1.0-rc.8", - "@deepseek-ai/dsh-subprocess": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-shell-env": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-shell-env/-/dsh-shell-env-0.1.0-rc.8.tgz", - "integrity": "sha512-E/Rlka8BnpB7GM67ZJPjvZyp0O9L5x28giyJhHWZcPHN4rsEQFVVqk0cH6iDT5STy+dMc9BAUW+im18kATIxsA==", - "license": "MIT", - "dependencies": { - "@deepseek-ai/schemastery": "^3.18.1" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-home-paths": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session-persistence": "^0.1.0-rc.8", - "@deepseek-ai/dsh-shell": "^0.1.0-rc.8", - "@deepseek-ai/dsh-tools": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-skill": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-skill/-/dsh-skill-0.1.0-rc.8.tgz", - "integrity": "sha512-MqcOzl4Y5pQEvFBNVAi5w0IZWH5kVbXmp1RYScrl+8HpVATZbgumDhztVnEc2kUrZu+o6LKb1hnbunK6JHUE5g==", - "license": "MIT", - "dependencies": { - "@deepseek-ai/schemastery": "^3.18.1" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", - "@deepseek-ai/dsh-scope": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-skill-badge": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-skill-badge/-/dsh-skill-badge-0.1.0-rc.8.tgz", - "integrity": "sha512-VjISwf5qDpkD+bxLuVXYL7IakhPoZudIOwWCFjTD++Tj8VQTN9ORCq1uCOatFLi5v/an8MzdZ91O2pXfQtb7dQ==", - "license": "MIT", - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-skill": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-skill-filesystem": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-skill-filesystem/-/dsh-skill-filesystem-0.1.0-rc.8.tgz", - "integrity": "sha512-A87t/1+wxPiMkUXWVdf4DfgxA8rp1eLmStMvzfdthR/WxtGPzuEv2L5oyNDzKiCBwIcxBN6Fy2THNa2Xba2kQQ==", - "license": "MIT", - "dependencies": { - "@deepseek-ai/schemastery": "^3.18.1", - "chokidar": "^5.0.0", - "yaml": "^2.4.2" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-fs": "^0.1.0-rc.8", - "@deepseek-ai/dsh-home-paths": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-skill": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-skill-filesystem/node_modules/chokidar": { - "version": "5.0.0", - "resolved": "https://registry.npmmirror.com/chokidar/-/chokidar-5.0.0.tgz", - "integrity": "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==", - "license": "MIT", - "dependencies": { - "readdirp": "^5.0.0" - }, - "engines": { - "node": ">= 20.19.0" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@deepseek-ai/dsh-skill-filesystem/node_modules/readdirp": { - "version": "5.1.1", - "resolved": "https://registry.npmmirror.com/readdirp/-/readdirp-5.1.1.tgz", - "integrity": "sha512-Kko+Y5XQ6fM+Ce3dq3m9YGxnacYZYl9cA1wZjaF3Vbry2L3i1qVg8+CAgNPsXRArPMUMCaOR7oa9Nqntc43JKA==", - "license": "MIT", - "engines": { - "node": ">= 20.19.0" - }, - "funding": { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@deepseek-ai/dsh-spill": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-spill/-/dsh-spill-0.1.0-rc.8.tgz", - "integrity": "sha512-LDfyBuRS/yfc+JYvSicEXYJDj5PFBfWN6vJ5G3wy14eMrq3OKoYip8lyIjEdR4qwCVh0s+oSi28AlcvkPuyOdw==", - "license": "MIT", - "peer": true, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-brand": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-spill-local": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-spill-local/-/dsh-spill-local-0.1.0-rc.8.tgz", - "integrity": "sha512-4Ew3cBOQxW6wA4U8svXCjUyhX00+h0W/bK9CzTy/HoYrNJhP85euJVV7SfNlq6OfTeQBWn3U0wKwNlcc3gAyAg==", - "license": "MIT", - "dependencies": { - "@deepseek-ai/schemastery": "^3.18.1" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-spill": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-spill-policy": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-spill-policy/-/dsh-spill-policy-0.1.0-rc.8.tgz", - "integrity": "sha512-9y2IHaKowtqGxhYd59R3OfWv1sonIDv2h9WX/jhxbagMvORfRkhjWJP4YAxp+l4Ba1LhVLcuG/nb2p8hqGdO4g==", - "license": "MIT", - "dependencies": { - "@deepseek-ai/schemastery": "^3.18.1" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", - "@deepseek-ai/dsh-output-retention": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session": "^0.1.0-rc.8", - "@deepseek-ai/dsh-spill": "^0.1.0-rc.8", - "@deepseek-ai/dsh-tools": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-storage": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-storage/-/dsh-storage-0.1.0-rc.8.tgz", - "integrity": "sha512-KcxiNFAC1X0GhbS9yWGo7FLARBNsxoyU9JatxQtA23MuqOZaN4Nzy3bsMViK4/snzpPGwm//I+wfUywSjM6uBA==", - "license": "MIT", - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-storage-domain": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-storage-domain/-/dsh-storage-domain-0.1.0-rc.8.tgz", - "integrity": "sha512-rHphQ0jveKoCurwh9TX+VAVFsMQivBgghQBOAsWdVDZ3W6boeXNhMZWuGWZ7WjMPD3iJKgiFCx+650hhsao+LQ==", - "license": "MIT", - "dependencies": { - "@deepseek-ai/schemastery": "^3.18.1", - "zod": "^4.4.3" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-storage": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-storage-json": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-storage-json/-/dsh-storage-json-0.1.0-rc.8.tgz", - "integrity": "sha512-cTlqy+5bQH7/UOFqRoWSaY9DaaDpcx4jmvWcwY8ciMUBse8BXcEtchVr5zqqss+xA/+Z/l9VraH+diwwRuAWbg==", - "license": "MIT", - "dependencies": { - "@deepseek-ai/schemastery": "^3.18.1" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-storage": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-subagent": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-subagent/-/dsh-subagent-0.1.0-rc.8.tgz", - "integrity": "sha512-EI94+hYMfAe8BQkkH/FTcciGxajFfAdQe66Jhy2/eyR3dssRAZ+oJsV6SzU20x3m2yd0gmMaXzO1iV3gwYhY+g==", - "license": "MIT", - "dependencies": { - "zod": "^4.4.3" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", - "@deepseek-ai/dsh-agent-presets": "^0.1.0-rc.8", - "@deepseek-ai/dsh-brand": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-jobs": "^0.1.0-rc.8", - "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", - "@deepseek-ai/dsh-sandbox": "^0.1.0-rc.8", - "@deepseek-ai/dsh-sandbox-policy": "^0.1.0-rc.8", - "@deepseek-ai/dsh-scope": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session-persistence": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session-projection": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session-projection-cache": "^0.1.0-rc.8", - "@deepseek-ai/dsh-tools": "^0.1.0-rc.8", - "@deepseek-ai/dsh-user-approval": "^0.1.0-rc.8" - }, - "peerDependenciesMeta": { - "@deepseek-ai/dsh-agent-presets": { - "optional": true - }, - "@deepseek-ai/dsh-jobs": { - "optional": true - }, - "@deepseek-ai/dsh-sandbox": { - "optional": true - }, - "@deepseek-ai/dsh-sandbox-policy": { - "optional": true - }, - "@deepseek-ai/dsh-session-persistence": { - "optional": true - }, - "@deepseek-ai/dsh-session-projection": { - "optional": true - }, - "@deepseek-ai/dsh-session-projection-cache": { - "optional": true - }, - "@deepseek-ai/dsh-user-approval": { - "optional": true - } - } - }, - "node_modules/@deepseek-ai/dsh-subagent-fork-in-process": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-subagent-fork-in-process/-/dsh-subagent-fork-in-process-0.1.0-rc.8.tgz", - "integrity": "sha512-CVen9Fu0TwiwuyTHmZeankN/v0EwdMwOAcq8fSTIyFGPG4ngtqQNSRMxwYTrz39kKyHv0VBW+r8tRd1LBdTAWA==", - "license": "MIT", - "dependencies": { - "@deepseek-ai/schemastery": "^3.18.1" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session": "^0.1.0-rc.8", - "@deepseek-ai/dsh-subagent": "^0.1.0-rc.8", - "@deepseek-ai/dsh-subagent-in-process-driver": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-subagent-in-process-driver": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-subagent-in-process-driver/-/dsh-subagent-in-process-driver-0.1.0-rc.8.tgz", - "integrity": "sha512-UJXwh484V/rEmRrvf5l0IWg2ceVOaSOU7Z6DEBq++bKOuFQ2BVkMm+Uj3dk4qFngeb10+/GXlRkbe3mqPwQDSA==", - "license": "MIT", - "peer": true, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session": "^0.1.0-rc.8", - "@deepseek-ai/dsh-subagent": "^0.1.0-rc.8", - "@deepseek-ai/dsh-system-prompt": "^0.1.0-rc.8", - "@deepseek-ai/dsh-tools": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-subagent-spawn-in-process": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-subagent-spawn-in-process/-/dsh-subagent-spawn-in-process-0.1.0-rc.8.tgz", - "integrity": "sha512-+ZratMZJiNg0vDmaEauJpiNI9IzVwCWisbidow6AV8O5CLC9/XlcMTjFGxmxcbnPdNlVM9i8OLK8gY7/kZ7tTA==", - "license": "MIT", - "dependencies": { - "@deepseek-ai/schemastery": "^3.18.1" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-subagent": "^0.1.0-rc.8", - "@deepseek-ai/dsh-subagent-in-process-driver": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-subprocess": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-subprocess/-/dsh-subprocess-0.1.0-rc.8.tgz", - "integrity": "sha512-rTWwWCq/WrBTjaXhApu7gaho6UHwMZq0+l7nZ06YMUreNZoCHfg67pAXopMqTgr/iotphmXQdChrLgBabzL1gA==", - "license": "MIT", - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-subprocess-local": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-subprocess-local/-/dsh-subprocess-local-0.1.0-rc.8.tgz", - "integrity": "sha512-2QMd6Nwjd+ARor4g+GSZ3dNyTvEf2IPOje47nQwa3UCmltLxn8K8gjDAN/5sGr/IF56P14FeF4xFag7tMK+Zdg==", - "hasInstallScript": true, - "license": "MIT", - "dependencies": { - "koffi": "^3.1.0", - "node-pty": "1.2.0-beta.15" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-subprocess": "^0.1.0-rc.8", - "@deepseek-ai/dsh-timeout": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-system-prompt": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-system-prompt/-/dsh-system-prompt-0.1.0-rc.8.tgz", - "integrity": "sha512-yk8Z85rzX2EwpKNWA5i+K3I3mqsIIUc9niwbDpXO8vlHvpC2qR3RNHjJIJN2EZYDqfSzTVtkbxHFsuMzDXIbew==", - "license": "MIT", - "dependencies": { - "@deepseek-ai/schemastery": "^3.18.1" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", - "@deepseek-ai/dsh-scope": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-terminal": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-terminal/-/dsh-terminal-0.1.0-rc.8.tgz", - "integrity": "sha512-Vu73FrQGx8h7Mqq0QdKtzAiZ3xgVM4fB9wmf3fEl6OiJTcqfc8t4lgug3gE7uBeDVRaLn+aq7kHbEUOY0fsm1Q==", - "license": "MIT", - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", - "@deepseek-ai/dsh-brand": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-terminal-bash": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-terminal-bash/-/dsh-terminal-bash-0.1.0-rc.8.tgz", - "integrity": "sha512-ehBMVr/0kZ15Vud7uE6PLobukwJi/BqGDbI1oonPPTOoTjDvuCqlKotNEQtS/G4NsvGshEABv+m5X5ELcRCWUA==", - "license": "MIT", - "dependencies": { - "@deepseek-ai/dsh-pwsh-local": "^0.1.0-rc.8", - "@deepseek-ai/schemastery": "^3.18.1" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-sandbox": "^0.1.0-rc.8", - "@deepseek-ai/dsh-sandbox-policy": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session": "^0.1.0-rc.8", - "@deepseek-ai/dsh-subprocess": "^0.1.0-rc.8", - "@deepseek-ai/dsh-terminal": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-time-context": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-time-context/-/dsh-time-context-0.1.0-rc.8.tgz", - "integrity": "sha512-9Rdse95S6Uk8OAHf78AQN/pxV6+29fCkIbF4ONP/F/6YBciKDORypRyMbHNSY81fBMHQPhW1xvZecGISdIHHiQ==", - "license": "MIT", - "dependencies": { - "@deepseek-ai/schemastery": "^3.18.1" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-timeout": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-timeout/-/dsh-timeout-0.1.0-rc.8.tgz", - "integrity": "sha512-RwOC/qHribE6b+LStAO7aAgweefLE5sqDO7Uz6/mnTDyJxCt7HNQnE/Op8sAvRa33d752aUkPfO9S0mgzVAoFQ==", - "license": "MIT", - "peer": true, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-tmux-context": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-tmux-context/-/dsh-tmux-context-0.1.0-rc.8.tgz", - "integrity": "sha512-ezhL3Wjpn4TqqvgSuKrJgNVG7jrWGekEWRYimqD1SvmAHQAS+Xr9q7DBl1uSFfJDWUOAPlAB8VAuo3k/CLUwKA==", - "license": "MIT", - "dependencies": { - "@deepseek-ai/schemastery": "^3.18.1" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session": "^0.1.0-rc.8", - "@deepseek-ai/dsh-shell": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-token-meter": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-token-meter/-/dsh-token-meter-0.1.0-rc.8.tgz", - "integrity": "sha512-ZcS6vuuJhoqjUrbyROuiiYk4nrvChkkYEfIoj7CjGbNArWOhbStmBaiPyahtcB1kThcnUKdu7vv7DaZJdLw8Lg==", - "license": "MIT", - "dependencies": { - "@deepseek-ai/schemastery": "^3.18.1", - "zod": "^4.4.3" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-compaction": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session-projection": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-tool-ask-user": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-tool-ask-user/-/dsh-tool-ask-user-0.1.0-rc.8.tgz", - "integrity": "sha512-PQVcuvNvTI18B2jSvgS20wX0GRnpom+6X6iNBL/WPLiicJeoxvDYj+M7SjdSsqBNv5t0i9VlYhO4NYicmluy+g==", - "license": "MIT", - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-tools": "^0.1.0-rc.8", - "@deepseek-ai/dsh-user-questions": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-tool-bash": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-tool-bash/-/dsh-tool-bash-0.1.0-rc.8.tgz", - "integrity": "sha512-VvP8Ky8ifqS7Iy7XUxc6cWB7sse3X6gqr92m0hBuodwQblzrZq2b6IyzfTzXKZKLqt5mMUaLRt7IPIDOOG+WEQ==", - "license": "MIT", - "dependencies": { - "@deepseek-ai/schemastery": "^3.18.1" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-jobs": "^0.1.0-rc.8", - "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", - "@deepseek-ai/dsh-sandbox": "^0.1.0-rc.8", - "@deepseek-ai/dsh-sandbox-policy": "^0.1.0-rc.8", - "@deepseek-ai/dsh-shell": "^0.1.0-rc.8", - "@deepseek-ai/dsh-shell-env": "^0.1.0-rc.8", - "@deepseek-ai/dsh-system-prompt": "^0.1.0-rc.8", - "@deepseek-ai/dsh-tools": "^0.1.0-rc.8", - "@deepseek-ai/dsh-user-approval": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-tool-bash-persistent": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-tool-bash-persistent/-/dsh-tool-bash-persistent-0.1.0-rc.8.tgz", - "integrity": "sha512-GySj2Nr7y4ewYTH0miD5DzfLEZNxAmWfSyJ5oOYVtzIbqkcU5WOjpsjQvDg0kuERXAq4MYcdc2QfrPet1/MkIQ==", - "license": "MIT", - "dependencies": { - "@deepseek-ai/schemastery": "^3.18.1" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-terminal": "^0.1.0-rc.8", - "@deepseek-ai/dsh-timeout": "^0.1.0-rc.8", - "@deepseek-ai/dsh-tools": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-tool-call-timeout-policy": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-tool-call-timeout-policy/-/dsh-tool-call-timeout-policy-0.1.0-rc.8.tgz", - "integrity": "sha512-Z6M/nkcz40DisaOIHqUOjjjW4wCi+JqQNoUhOu+VAoBDWHl7SDmEvdWSQUwkyOETjcfdRSG4RTJ5z/rBUVCPHQ==", - "license": "MIT", - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", - "@deepseek-ai/dsh-timeout": "^0.1.0-rc.8", - "@deepseek-ai/dsh-tools": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-tool-cordis": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-tool-cordis/-/dsh-tool-cordis-0.1.0-rc.8.tgz", - "integrity": "sha512-bIbkazp5xasqtJBFljOGVIdxyAAWIcKoxMuhDoUpfPFuEqZaXJumYJJ9+ugqr+KKkddjuf2SvlpE5XB4zWcNvg==", - "license": "MIT", - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", - "@deepseek-ai/dsh-cordis-host-runner": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", - "@deepseek-ai/dsh-scope": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session": "^0.1.0-rc.8", - "@deepseek-ai/dsh-system-prompt": "^0.1.0-rc.8", - "@deepseek-ai/dsh-tools": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-tool-fs": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-tool-fs/-/dsh-tool-fs-0.1.0-rc.8.tgz", - "integrity": "sha512-pxo2YfVlqcw0sCA2+4DtqaaYsuxkx1QfvjT3VO+ckZMWn/UnGOUuzjJtKhVynwjm8prttGqK2LBXUTBZPlKTWg==", - "license": "MIT", - "dependencies": { - "@deepseek-ai/schemastery": "^3.18.1", - "diff": "^9.0.0" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-attachment": "^0.1.0-rc.8", - "@deepseek-ai/dsh-fs": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", - "@deepseek-ai/dsh-sandbox": "^0.1.0-rc.8", - "@deepseek-ai/dsh-sandbox-policy": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session": "^0.1.0-rc.8", - "@deepseek-ai/dsh-system-prompt": "^0.1.0-rc.8", - "@deepseek-ai/dsh-tools": "^0.1.0-rc.8", - "@deepseek-ai/dsh-user-approval": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-tool-fs-search": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-tool-fs-search/-/dsh-tool-fs-search-0.1.0-rc.8.tgz", - "integrity": "sha512-AZvESByrPbBIYIGDoTgVOHH48antHy2ZSaLfsVfz1Rw/jQIeiBKwt2LYIPhRGGvev6TXw95qWKt5cyv6WDXHlg==", - "license": "MIT", - "dependencies": { - "@deepseek-ai/schemastery": "^3.18.1", - "@vscode/ripgrep": "^1.18.0" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", - "@deepseek-ai/dsh-output-retention": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session": "^0.1.0-rc.8", - "@deepseek-ai/dsh-spill": "^0.1.0-rc.8", - "@deepseek-ai/dsh-subprocess": "^0.1.0-rc.8", - "@deepseek-ai/dsh-system-prompt": "^0.1.0-rc.8", - "@deepseek-ai/dsh-timeout": "^0.1.0-rc.8", - "@deepseek-ai/dsh-tools": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-tool-goal": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-tool-goal/-/dsh-tool-goal-0.1.0-rc.8.tgz", - "integrity": "sha512-EO8iqRV3R8YgdMGUVAp/20XCKbegdwZ7fqr7+oSg11lGHuTnXDz4im4HBXri/wmL9XHeBjmcAQ0BXESbhX2VOQ==", - "license": "MIT", - "dependencies": { - "@deepseek-ai/schemastery": "^3.18.1" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", - "@deepseek-ai/dsh-goal": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session": "^0.1.0-rc.8", - "@deepseek-ai/dsh-system-prompt": "^0.1.0-rc.8", - "@deepseek-ai/dsh-tools": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-tool-jobs": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-tool-jobs/-/dsh-tool-jobs-0.1.0-rc.8.tgz", - "integrity": "sha512-p3gWi38ryJFRes1lTAdVkdZrUBB8RYPpy4XqZ9DgC2qcrLOJZnnsprIUxyDDmhbyargOgTGc3hEeRU5g8OQAIA==", - "license": "MIT", - "dependencies": { - "@deepseek-ai/schemastery": "^3.18.1" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-jobs": "^0.1.0-rc.8", - "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", - "@deepseek-ai/dsh-output-retention": "^0.1.0-rc.8", - "@deepseek-ai/dsh-system-prompt": "^0.1.0-rc.8", - "@deepseek-ai/dsh-tools": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-tool-pwsh": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-tool-pwsh/-/dsh-tool-pwsh-0.1.0-rc.8.tgz", - "integrity": "sha512-B5F08tsSD7DHqXDXjn/Q11FavHw1U8/WAEqp8AC47vDRymPJIgTM8zSlJ0Lx7aZaKPTW4zQYtSmwUhy93q6zfw==", - "license": "MIT", - "dependencies": { - "@deepseek-ai/schemastery": "^3.18.1" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-jobs": "^0.1.0-rc.8", - "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", - "@deepseek-ai/dsh-sandbox": "^0.1.0-rc.8", - "@deepseek-ai/dsh-sandbox-policy": "^0.1.0-rc.8", - "@deepseek-ai/dsh-shell": "^0.1.0-rc.8", - "@deepseek-ai/dsh-shell-env": "^0.1.0-rc.8", - "@deepseek-ai/dsh-system-prompt": "^0.1.0-rc.8", - "@deepseek-ai/dsh-tools": "^0.1.0-rc.8", - "@deepseek-ai/dsh-user-approval": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-tool-pwsh-persistent": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-tool-pwsh-persistent/-/dsh-tool-pwsh-persistent-0.1.0-rc.8.tgz", - "integrity": "sha512-OxQhywkvUTuGj26yaE1LyoADsCKttaIdiq2dJd+Xcbjc+tnI1gfoVrBj+Sta3/uT7x66kKjXZ1+gnw6gK5qISQ==", - "license": "MIT", - "dependencies": { - "@deepseek-ai/schemastery": "^3.18.1" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-terminal": "^0.1.0-rc.8", - "@deepseek-ai/dsh-timeout": "^0.1.0-rc.8", - "@deepseek-ai/dsh-tools": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-tool-ralph": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-tool-ralph/-/dsh-tool-ralph-0.1.0-rc.8.tgz", - "integrity": "sha512-+kVCbLEBDxOCCHPdR5+hgQFbkTvTaJ3D7zTNxNEtS5Tr/7eGAU7/VmwNMMSZ4Z+eyHQQEm4vgT+O1pMTvLmb7g==", - "license": "MIT", - "dependencies": { - "@deepseek-ai/schemastery": "^3.18.1" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", - "@deepseek-ai/dsh-subagent": "^0.1.0-rc.8", - "@deepseek-ai/dsh-system-prompt": "^0.1.0-rc.8", - "@deepseek-ai/dsh-tools": "^0.1.0-rc.8", - "@deepseek-ai/dsh-workflow": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-tool-skill": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-tool-skill/-/dsh-tool-skill-0.1.0-rc.8.tgz", - "integrity": "sha512-oQAPyXiQDDZ73rZwST7KqwUAr0Al3U1dxWdtzETsMzvNSQE9fmMBz5jUObFIEjxxJcA07Pp1DFzuJdpkCIDeCw==", - "license": "MIT", - "dependencies": { - "@deepseek-ai/schemastery": "^3.18.1" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", - "@deepseek-ai/dsh-skill": "^0.1.0-rc.8", - "@deepseek-ai/dsh-tools": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-tool-str-replace-editor": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-tool-str-replace-editor/-/dsh-tool-str-replace-editor-0.1.0-rc.8.tgz", - "integrity": "sha512-2gyO5a5xNvBo9I5vmVSvgXRfxUfKGDu3WjjdK0aDWx/Y+C1r1mGVC7R5mN/oJstcUCIyKm483ux1pT9/O1QD8w==", - "license": "MIT", - "dependencies": { - "@deepseek-ai/schemastery": "^3.18.1" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-fs": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-sandbox": "^0.1.0-rc.8", - "@deepseek-ai/dsh-sandbox-policy": "^0.1.0-rc.8", - "@deepseek-ai/dsh-tools": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-tool-subagent": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-tool-subagent/-/dsh-tool-subagent-0.1.0-rc.8.tgz", - "integrity": "sha512-mwNV8M7hsy9+OsSFCluv87FiDHaXO91m83xF/o34Ip9xrgkGs7LOCjvUdCpwjxFTJenWEcvEU90aa7vv3aT/Iw==", - "license": "MIT", - "dependencies": { - "@deepseek-ai/schemastery": "^3.18.1" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-jobs": "^0.1.0-rc.8", - "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", - "@deepseek-ai/dsh-subagent": "^0.1.0-rc.8", - "@deepseek-ai/dsh-system-prompt": "^0.1.0-rc.8", - "@deepseek-ai/dsh-tools": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-tool-subagent-control": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-tool-subagent-control/-/dsh-tool-subagent-control-0.1.0-rc.8.tgz", - "integrity": "sha512-zXF9iIzr96w/S3jNxkRcyV1ouwA1eUCSmvqhlSDkkcA8RH5jt5vWkTia8fwRs1pFS9m7OpbLtvbDxjC8D3nedw==", - "license": "MIT", - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session": "^0.1.0-rc.8", - "@deepseek-ai/dsh-subagent": "^0.1.0-rc.8", - "@deepseek-ai/dsh-tools": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-tool-subagent-report": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-tool-subagent-report/-/dsh-tool-subagent-report-0.1.0-rc.8.tgz", - "integrity": "sha512-u0CzoSu7O1YyOpGyHfmT/P2hCfnepSzVKrs6MHFrzjbuiRFEcVme6/iLrc7QdLtg484Q1kcnqG2z0OZS24AnWQ==", - "license": "MIT", - "dependencies": { - "@deepseek-ai/schemastery": "^3.18.1" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", - "@deepseek-ai/dsh-subagent": "^0.1.0-rc.8", - "@deepseek-ai/dsh-system-prompt": "^0.1.0-rc.8", - "@deepseek-ai/dsh-tools": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-tool-todo": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-tool-todo/-/dsh-tool-todo-0.1.0-rc.8.tgz", - "integrity": "sha512-eWxwTeX5WsQPSsz1qyJq+UMiASYB5UHLdObVd4vFLYKbFOoglUK0X+Ie5OjlAkFTP+OzCQMAzUl2gJMwJPWKig==", - "license": "MIT", - "dependencies": { - "@deepseek-ai/schemastery": "^3.18.1", - "zod": "^4.4.3" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session-projection": "^0.1.0-rc.8", - "@deepseek-ai/dsh-tools": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-tool-web": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-tool-web/-/dsh-tool-web-0.1.0-rc.8.tgz", - "integrity": "sha512-MrTkQ2L52A13ysTM94bSW+5sXq3AyVNoo5q3bK47bsl+hg9Kga5gDgGAZ+SGVSQZAUEHXfuYGHaErdUp50bncw==", - "license": "MIT", - "dependencies": { - "@deepseek-ai/schemastery": "^3.18.1", - "@joplin/turndown-plugin-gfm": "^1.0.67", - "turndown": "^7.2.4" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", - "@deepseek-ai/dsh-system-prompt": "^0.1.0-rc.8", - "@deepseek-ai/dsh-tools": "^0.1.0-rc.8", - "@deepseek-ai/dsh-web": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-tool-workflow": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-tool-workflow/-/dsh-tool-workflow-0.1.0-rc.8.tgz", - "integrity": "sha512-Z3MCCLM28J/nqiqwHG9roGVUzwMKEADRsSNLPYNemXq5vVEYjm5sBwC+QcWtiQ7NxKXf5ViUu3eKXTe1Fh5TNg==", - "license": "MIT", - "dependencies": { - "@deepseek-ai/schemastery": "^3.18.1" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session": "^0.1.0-rc.8", - "@deepseek-ai/dsh-system-prompt": "^0.1.0-rc.8", - "@deepseek-ai/dsh-tools": "^0.1.0-rc.8", - "@deepseek-ai/dsh-workflow": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-tools": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-tools/-/dsh-tools-0.1.0-rc.8.tgz", - "integrity": "sha512-tvuGAVUS4yoPW9zH7CGWJgMlAzGjfu2UlRiricldlcwSKAaJZPZx/K/YfTivUyDTER6aK1DJUnIpVG7RD/DoHQ==", - "license": "MIT", - "dependencies": { - "@deepseek-ai/schemastery": "^3.18.1" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", - "@deepseek-ai/dsh-code-runtime": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", - "@deepseek-ai/dsh-scope": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session": "^0.1.0-rc.8", - "@deepseek-ai/dsh-system-prompt": "^0.1.0-rc.8", - "@deepseek-ai/dsh-user-approval": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-typert-loader": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-typert-loader/-/dsh-typert-loader-0.1.0-rc.8.tgz", - "integrity": "sha512-IB2Bkv7UglS0y/Dt7buFq87bbUkD/njvuCp4/bRxlbb/8U02b7v18UXnYFoZjCusfzeYxaCBZihImv7aDMBhCA==", - "license": "MIT", - "dependencies": { - "@deepseek-ai/schemastery": "^3.18.1" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/cordis-plugin-loader": "^1.0.2", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-typert-registry": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-typert-protocol": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-typert-protocol/-/dsh-typert-protocol-0.1.0-rc.8.tgz", - "integrity": "sha512-scwEAefRBL7gRpaXiEdiHRMvlr8dLmUbiEvy0LOAX/8X3FZBd/5tHQ/8lCppAQNTDZMI/LSiSMpu5XrFId+7cQ==", - "license": "MIT", - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-typert-registry": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-typert-registry/-/dsh-typert-registry-0.1.0-rc.8.tgz", - "integrity": "sha512-pxfRE5f1y81h2lNqj0uooYrErTVgpzKfYm4W+ppRafN5s/+1jlLIYWiG3wWD3bnxyoD2NLcTEhi/GXoaqiwdaw==", - "license": "MIT", - "dependencies": { - "@deepseek-ai/dsh-typert-protocol": "^0.1.0-rc.8", - "zod": "^4.4.3" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-user-approval": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-user-approval/-/dsh-user-approval-0.1.0-rc.8.tgz", - "integrity": "sha512-6SFCxp7dgNFEyzQIcs5i9C+5djgXsAeV0iKmZUCLlcIeVM1chcCMHyGcoXlw8yyB14qFMrMs+TPvhvpu2WWxAw==", - "license": "MIT", - "dependencies": { - "@deepseek-ai/schemastery": "^3.18.1" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", - "@deepseek-ai/dsh-brand": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", - "@deepseek-ai/dsh-scope": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session": "^0.1.0-rc.8", - "@deepseek-ai/dsh-system-prompt": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-user-questions": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-user-questions/-/dsh-user-questions-0.1.0-rc.8.tgz", - "integrity": "sha512-kiOAlpKKfB89iObWiiVpueD4XCaday203LGUs7+eGb2isolY6VppoGb7ZmcJQqsW63bjbAA7wZeJuN3CoxcvSQ==", - "license": "MIT", - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-llm": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-web": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-web/-/dsh-web-0.1.0-rc.8.tgz", - "integrity": "sha512-YLraDwZTx0Y3Jqw2cu4eClv9ZgEJYoeSFzTe7c9JZ4Z3ThaNCCwEaXWEPMBiPKU6QlR8ahkPPj6xoU9+nPO66g==", - "license": "MIT", - "dependencies": { - "@deepseek-ai/schemastery": "^3.18.1" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-llm": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-web-app": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-web-app/-/dsh-web-app-0.1.0-rc.8.tgz", - "integrity": "sha512-Te/N+AxFmQF2267yMqama5Lp2evsBJeFsqhnEZPfvFhquLBBWgtO5DNZ2cxto5NhGGNNCk/JV25vHRxd7bZl8g==", - "license": "MIT", - "dependencies": { - "@deepseek-ai/dsh-agent-presets": "^0.1.0-rc.8", - "@deepseek-ai/dsh-api-remotes": "^0.1.0-rc.8", - "@deepseek-ai/dsh-app-boot": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-connection": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-hmr": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-locale": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-modules": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-runtime": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-ui-agent-preset": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-ui-attachment": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-ui-brand-official": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-ui-commands": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-ui-conversation": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-ui-cordis": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-ui-deliverables": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-ui-directory-picker-browse": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-ui-directory-picker-native": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-ui-goal": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-ui-input-trigger": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-ui-jobs": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-ui-layout": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-ui-message-feedback": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-ui-model-selection": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-ui-permission-presets": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-ui-plan": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-ui-reference": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-ui-renderer": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-ui-settings": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-ui-settings-general": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-ui-settings-models": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-ui-settings-plugin-inventory": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-ui-settings-plugins": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-ui-sidebar": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-ui-skill": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-ui-subagent": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-ui-theme": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-ui-tool": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-ui-trajectory": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-ui-user-questions": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-ui-workflow-run": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-ui-workspace": "^0.1.0-rc.8", - "@deepseek-ai/dsh-cmdline": "^0.1.0-rc.8", - "@deepseek-ai/dsh-code-runtime-worker-thread": "^0.1.0-rc.8", - "@deepseek-ai/dsh-cordis-client-runner": "^0.1.0-rc.8", - "@deepseek-ai/dsh-cordis-host-runner": "^0.1.0-rc.8", - "@deepseek-ai/dsh-file-reference": "^0.1.0-rc.8", - "@deepseek-ai/dsh-file-reference-local": "^0.1.0-rc.8", - "@deepseek-ai/dsh-host-apiproxy": "^0.1.0-rc.8", - "@deepseek-ai/dsh-host-directory-picker-auto": "^0.1.0-rc.8", - "@deepseek-ai/dsh-host-directory-picker-browse": "^0.1.0-rc.8", - "@deepseek-ai/dsh-host-directory-picker-native": "^0.1.0-rc.8", - "@deepseek-ai/dsh-host-frontend-static": "^0.1.0-rc.8", - "@deepseek-ai/dsh-host-plugin-inventory": "^0.1.0-rc.8", - "@deepseek-ai/dsh-host-webserver": "^0.1.0-rc.8", - "@deepseek-ai/dsh-launch-environment": "^0.1.0-rc.8", - "@deepseek-ai/dsh-message-feedback": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session-log-export": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session-projection-cache": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session-reference": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session-stats": "^0.1.0-rc.8", - "@deepseek-ai/dsh-storage": "^0.1.0-rc.8", - "@deepseek-ai/dsh-storage-domain": "^0.1.0-rc.8", - "@deepseek-ai/dsh-storage-json": "^0.1.0-rc.8", - "@deepseek-ai/dsh-subprocess": "^0.1.0-rc.8", - "@deepseek-ai/dsh-web-frontend": "^0.1.0-rc.8", - "@deepseek-ai/dsh-workspace": "^0.1.0-rc.8", - "@deepseek-ai/schemastery": "^3.18.1", - "commander": "^15.0.0", - "open": "^11.0.0" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/cordis-plugin-loader": "^1.0.2", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-shell-env": "^0.1.0-rc.8", - "@deepseek-ai/dsh-system-prompt": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-web-frontend": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-web-frontend/-/dsh-web-frontend-0.1.0-rc.8.tgz", - "integrity": "sha512-GxWJtkNEniYtSH19XWIJvMO2RSP2bMAZvs3Z6m9cEr9OFbngCY5XCXwqsJMYqOJIao0eSePp/eRCPeXNvqeGXA==", - "license": "MIT" - }, - "node_modules/@deepseek-ai/dsh-web-search-deepseek": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-web-search-deepseek/-/dsh-web-search-deepseek-0.1.0-rc.8.tgz", - "integrity": "sha512-ifaFw+Cil3yte/9r//3wwMWWPIMuYhvYAB0Hk56IVf+8RDbnRkTJY2foFNNgD91dq1ZL2gBijkdxv1c7wDt+EA==", - "license": "MIT", - "dependencies": { - "@deepseek-ai/schemastery": "^3.18.1" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", - "@deepseek-ai/dsh-credentials": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-launch-environment": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session": "^0.1.0-rc.8", - "@deepseek-ai/dsh-settings": "^0.1.0-rc.8", - "@deepseek-ai/dsh-web": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-workflow": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-workflow/-/dsh-workflow-0.1.0-rc.8.tgz", - "integrity": "sha512-a4UJKJAFOPQgVaWegk8MIh8BQjqerkGhHu2+uGF4wyGanzI7FHHY/OUmH4hHTVEx2qFcWh732Od/T8LgL6gcbg==", - "license": "MIT", - "peer": true, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", - "@deepseek-ai/dsh-brand": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-workflow-worker-thread": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-workflow-worker-thread/-/dsh-workflow-worker-thread-0.1.0-rc.8.tgz", - "integrity": "sha512-QBkHJ8l174U3VqHRi2KyJIFey+Uxzo/OOFbTFx7TP5f761lPvqYiXlILuQJ9QvT7WJTyZO3QRLIIU6ZEBwxTIA==", - "license": "MIT", - "dependencies": { - "@deepseek-ai/schemastery": "^3.18.1" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", - "@deepseek-ai/dsh-brand": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session": "^0.1.0-rc.8", - "@deepseek-ai/dsh-subagent": "^0.1.0-rc.8", - "@deepseek-ai/dsh-tools": "^0.1.0-rc.8", - "@deepseek-ai/dsh-workflow": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-workspace": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-workspace/-/dsh-workspace-0.1.0-rc.8.tgz", - "integrity": "sha512-Uyw44WcYvXRQjb0kUstTEJmL83hkGQbWnJzglaGWcAvsZBjQHeBgKuLzOZin1yc/dRX2pKuk1InFwxKXpaHjBA==", - "license": "MIT", - "dependencies": { - "zod": "^4.4.3" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-brand": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session-persistence": "^0.1.0-rc.8", - "@deepseek-ai/dsh-storage": "^0.1.0-rc.8", - "@deepseek-ai/dsh-storage-domain": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/node-addon-landlock-run": { - "version": "0.1.1", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/node-addon-landlock-run/-/node-addon-landlock-run-0.1.1.tgz", - "integrity": "sha512-aHGhlQJEutfobKM/4K59SERbT7RmQdD2oMKzD8Bne/Ps7TeT8AweCN+dpdfuxQhMNbFcJMymrgPnID0WYQ30Tw==", - "license": "BSD-3-Clause", - "engines": { - "node": ">=20" - }, - "optionalDependencies": { - "@deepseek-ai/node-addon-landlock-run-linux-arm64": "0.1.1", - "@deepseek-ai/node-addon-landlock-run-linux-x64": "0.1.1" - } - }, - "node_modules/@deepseek-ai/node-addon-landlock-run-linux-arm64": { - "version": "0.1.1", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/node-addon-landlock-run-linux-arm64/-/node-addon-landlock-run-linux-arm64-0.1.1.tgz", - "integrity": "sha512-lYY2RbcPW4rGRM5hVJbrXlvLqyBxeJBjBqvt+QTHTU+GtfUVVjTODKa4e3CRwMQoCEpOjoARdQBHbN7HvE72WQ==", - "cpu": [ - "arm64" - ], - "license": "BSD-3-Clause", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=20" - } - }, - "node_modules/@deepseek-ai/node-addon-landlock-run-linux-x64": { - "version": "0.1.1", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/node-addon-landlock-run-linux-x64/-/node-addon-landlock-run-linux-x64-0.1.1.tgz", - "integrity": "sha512-OHAzPW2Coe/iYobAJAAA8CeVrBoKV4BnNHsgwvXwOfishxkUVSWSvdyxrZPiwYRXutpIGVrSo9zV3WOQy2euBA==", - "cpu": [ - "x64" - ], - "license": "BSD-3-Clause", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=20" - } - }, - "node_modules/@deepseek-ai/schemastery": { - "version": "3.18.1", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/schemastery/-/schemastery-3.18.1.tgz", - "integrity": "sha512-Qn0FCSwCQnpnj6SB31I6i2sIKgKWnkbJM8O0EU91Gv2UsYVvtZTl6IA0sCwk2e2MZf5S8w5hpq9QkeVvK9qwxg==", - "license": "MIT", - "dependencies": { - "@deepseek-ai/cosmokit": "^1.8.2", - "@standard-schema/spec": "^1.1.0" - } - }, - "node_modules/@earendil-works/pi-ai": { - "version": "0.82.1", - "resolved": "https://registry.npmmirror.com/@earendil-works/pi-ai/-/pi-ai-0.82.1.tgz", - "integrity": "sha512-3WFYRhEp3lQB3444EhPMBcM7zSaEUE3eJgHOR7s4081NLqbw/FsWilIKWXSua0Gv3sRr7m9xMidR3pPDE7jI/A==", - "license": "MIT", - "dependencies": { - "@anthropic-ai/sdk": "0.91.1", - "@aws-sdk/client-bedrock-runtime": "3.1048.0", - "@google/genai": "1.52.0", - "@mistralai/mistralai": "2.2.6", - "@opentelemetry/api": "1.9.0", - "@smithy/node-http-handler": "4.7.3", - "http-proxy-agent": "7.0.2", - "https-proxy-agent": "7.0.6", - "openai": "6.26.0", - "partial-json": "0.1.7", - "typebox": "1.1.38" - }, - "bin": { - "pi-ai": "dist/cli.js" - }, - "engines": { - "node": ">=22.19.0" - } - }, - "node_modules/@earendil-works/pi-ai/node_modules/@opentelemetry/api": { - "version": "1.9.0", - "resolved": "https://registry.npmmirror.com/@opentelemetry/api/-/api-1.9.0.tgz", - "integrity": "sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg==", - "license": "Apache-2.0", - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/@emnapi/runtime": { - "version": "1.11.3", - "resolved": "https://registry.npmmirror.com/@emnapi/runtime/-/runtime-1.11.3.tgz", - "integrity": "sha512-Xz4Tpyki7XyrpbUK1jR1AhdAdaXyhhY4lZ3neLodmhpuWfy2PAQN5B46sAiU4liOXGLkHypn/qU+jvfWSCYYLA==", - "license": "MIT", - "optional": true, - "dependencies": { - "tslib": "^2.4.0" - } - }, - "node_modules/@google/genai": { - "version": "1.52.0", - "resolved": "https://registry.npmmirror.com/@google/genai/-/genai-1.52.0.tgz", - "integrity": "sha512-gwSvbpiN/17O9TbsqSsE/OzZcpv5Fo4RQjdngGgogtuB9RsyJ8ZHhX5KjHj1bp5N9snN2eK8LDGXSaWW2hof8Q==", - "hasInstallScript": true, - "license": "Apache-2.0", - "dependencies": { - "google-auth-library": "^10.3.0", - "p-retry": "^4.6.2", - "protobufjs": "^7.5.4", - "ws": "^8.18.0" - }, - "engines": { - "node": ">=20.0.0" - }, - "peerDependencies": { - "@modelcontextprotocol/sdk": "^1.25.2" - }, - "peerDependenciesMeta": { - "@modelcontextprotocol/sdk": { - "optional": true - } - } - }, - "node_modules/@hono/node-server": { - "version": "2.1.1", - "resolved": "https://registry.npmmirror.com/@hono/node-server/-/node-server-2.1.1.tgz", - "integrity": "sha512-ELuehkj5VCBdgEw9zs+ivkKwyzzUCSQuE96YmiPvn1ECBoZCczbFXJLeEGMTYjphP6gydh4pHMqEYPVMYUVgQg==", - "license": "MIT", - "engines": { - "node": ">=20" - }, - "peerDependencies": { - "hono": "^4" - } - }, - "node_modules/@img/colour": { - "version": "1.1.0", - "resolved": "https://registry.npmmirror.com/@img/colour/-/colour-1.1.0.tgz", - "integrity": "sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ==", - "license": "MIT", - "engines": { - "node": ">=18" - } - }, - "node_modules/@img/sharp-darwin-arm64": { - "version": "0.35.3", - "resolved": "https://registry.npmmirror.com/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.35.3.tgz", - "integrity": "sha512-RMnFX7YQsMoh7lWfcM4NEHHymBX/rLuKNPVM84XE9ONPcaSCDgE7CHIHpSgPcO2xcRthgBy1HfNO319mwhIAkg==", - "cpu": [ - "arm64" - ], - "license": "Apache-2.0", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=20.9.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-darwin-arm64": "1.3.2" - } - }, - "node_modules/@img/sharp-darwin-x64": { - "version": "0.35.3", - "resolved": "https://registry.npmmirror.com/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.35.3.tgz", - "integrity": "sha512-Xo+5uFBtLN0BKqieTxiFzFPQAUlBbbH5iBKyRX/z1JrbnYsHTfKJnUfL8+p2TPXr1pXqao4eeL4Rl144uDpK9w==", - "cpu": [ - "x64" - ], - "license": "Apache-2.0", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=20.9.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-darwin-x64": "1.3.2" - } - }, - "node_modules/@img/sharp-freebsd-wasm32": { - "version": "0.35.3", - "resolved": "https://registry.npmmirror.com/@img/sharp-freebsd-wasm32/-/sharp-freebsd-wasm32-0.35.3.tgz", - "integrity": "sha512-lUxcqWIj2wMQ9BrwNjngcr1gWUr5xgaGThBRqPPalIC2n67Cqj1uPh8NnA/ZhAg8hUbKl+kVHKwgUIwe6ZYPrg==", - "license": "Apache-2.0", - "optional": true, - "os": [ - "freebsd" - ], - "dependencies": { - "@img/sharp-wasm32": "0.35.3" - }, - "engines": { - "node": ">=20.9.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-darwin-arm64": { - "version": "1.3.2", - "resolved": "https://registry.npmmirror.com/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.3.2.tgz", - "integrity": "sha512-9J6ypZFpQBj4YnePGoq/S38w6nz+vqg5WZLrLGY4YuSemdMq47GMLBPO42MzwdGwpg/agZ7xzZcFHa48xlywfg==", - "cpu": [ - "arm64" - ], - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "darwin" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-darwin-x64": { - "version": "1.3.2", - "resolved": "https://registry.npmmirror.com/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.3.2.tgz", - "integrity": "sha512-m2pW1n6cns9VaubNwsZ+c3CRYjxNQWgJ5gPlnL1nbBcpkBvFm6SCFN5o0psFHI8w9n11NKhFkeEDns98tiqbEw==", - "cpu": [ - "x64" - ], - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "darwin" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-linux-arm": { - "version": "1.3.2", - "resolved": "https://registry.npmmirror.com/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.3.2.tgz", - "integrity": "sha512-1eMLzy92I4J6rmi4mAT8yC3HxOtniyGELlzGbNMLLeqe052ahFQ0h6LFq+lh5DsDIdYViIDst08abvSbcEdLXQ==", - "cpu": [ - "arm" - ], - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-linux-arm64": { - "version": "1.3.2", - "resolved": "https://registry.npmmirror.com/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.3.2.tgz", - "integrity": "sha512-dqVSFynCox4C/J8kT16V7SIFAns0IjgLwkvYT7p8LQVmJ5OS5b6tI9IGflxTeuBS//zXeFIUbwt5dwxyZ17cnA==", - "cpu": [ - "arm64" - ], - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-linux-ppc64": { - "version": "1.3.2", - "resolved": "https://registry.npmmirror.com/@img/sharp-libvips-linux-ppc64/-/sharp-libvips-linux-ppc64-1.3.2.tgz", - "integrity": "sha512-3z0NHDxD6n5I9gc05U1eW1AyRm+Gznzq3naMrthPNqE6oYykcogW0l/jfpJdjYnuNl8R7yI9pNbE1XiUeyq0Aw==", - "cpu": [ - "ppc64" - ], - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-linux-riscv64": { - "version": "1.3.2", - "resolved": "https://registry.npmmirror.com/@img/sharp-libvips-linux-riscv64/-/sharp-libvips-linux-riscv64-1.3.2.tgz", - "integrity": "sha512-bsb4rI+NldGOsXuej2r8OdSS8+zXDVaCWxyWrcv6kneTOlgAHtZABRzBBCwdsPiD90J4myNJuHpg6kA20ImW/w==", - "cpu": [ - "riscv64" - ], - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-linux-s390x": { - "version": "1.3.2", - "resolved": "https://registry.npmmirror.com/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.3.2.tgz", - "integrity": "sha512-/ABshyj8gCpyIrNXnHn4LorDJ0HHm1VhXPBlxZ8zAtfVPAaSafXPGn+sUSIRiwaSBy0mmFjSjiXI5mkcwdChKQ==", - "cpu": [ - "s390x" - ], - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-linux-x64": { - "version": "1.3.2", - "resolved": "https://registry.npmmirror.com/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.3.2.tgz", - "integrity": "sha512-ITPEtgffGJ0S6G9dRyw/366tJQqFRcHWPHhC+Stpg3Z8AEMrDrTr2lhdz4f/Y/HMbRh//7Z5mBzEpVdi62Oc3w==", - "cpu": [ - "x64" - ], - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-linuxmusl-arm64": { - "version": "1.3.2", - "resolved": "https://registry.npmmirror.com/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.3.2.tgz", - "integrity": "sha512-zE9EdiUzUmg5mDT5a1rk5fYJ6GWPloTwWBYDS14naqHsL+EaMpDj1AWnpLgh3u0YCORv2Tt50wrcrpYqkP97Kw==", - "cpu": [ - "arm64" - ], - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-linuxmusl-x64": { - "version": "1.3.2", - "resolved": "https://registry.npmmirror.com/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.3.2.tgz", - "integrity": "sha512-m0lrLiUt+lBYnCFr8qV/65yMR4E/c7/wf78I5eKTdkEakFAlZ9QlzEM3QIhhAwVeUhLAHLcCq7a7Vszq/oFNZQ==", - "cpu": [ - "x64" - ], - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-linux-arm": { - "version": "0.35.3", - "resolved": "https://registry.npmmirror.com/@img/sharp-linux-arm/-/sharp-linux-arm-0.35.3.tgz", - "integrity": "sha512-affVWCTLooy8TSxbDx2qkzuDeaWLNVBA+P//FNBirHsXpP2fuBhk5AuboYUnrDnzoXes8GFjpTx0SBFOCRg+FA==", - "cpu": [ - "arm" - ], - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=20.9.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linux-arm": "1.3.2" - } - }, - "node_modules/@img/sharp-linux-arm64": { - "version": "0.35.3", - "resolved": "https://registry.npmmirror.com/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.35.3.tgz", - "integrity": "sha512-QgKDspHPnrU+GQ55XPhGwyhC8acLVOOSyAvo1oVfFmrIXLkDNmGWzAfDZ4xK8oSA1qBQrALcHX0G5UZni/SuFQ==", - "cpu": [ - "arm64" - ], - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=20.9.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linux-arm64": "1.3.2" - } - }, - "node_modules/@img/sharp-linux-ppc64": { - "version": "0.35.3", - "resolved": "https://registry.npmmirror.com/@img/sharp-linux-ppc64/-/sharp-linux-ppc64-0.35.3.tgz", - "integrity": "sha512-sMd8rDxmpLOwv/7N44klFjOD5DUO7FLdjiXDI0hoxYaf7Ar262dQIEkosE98bps+5HPLtp/EvNqeqQtOycP/IA==", - "cpu": [ - "ppc64" - ], - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=20.9.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linux-ppc64": "1.3.2" - } - }, - "node_modules/@img/sharp-linux-riscv64": { - "version": "0.35.3", - "resolved": "https://registry.npmmirror.com/@img/sharp-linux-riscv64/-/sharp-linux-riscv64-0.35.3.tgz", - "integrity": "sha512-0Eob78yjlYPfL5vMNWAW55l3R9Y6BQS/gOfe0ZcP9mEz9ohhKSt4im1hayiknXgf8AWrFqMvJcKIdmLmEe7yeQ==", - "cpu": [ - "riscv64" - ], - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=20.9.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linux-riscv64": "1.3.2" - } - }, - "node_modules/@img/sharp-linux-s390x": { - "version": "0.35.3", - "resolved": "https://registry.npmmirror.com/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.35.3.tgz", - "integrity": "sha512-KgAxQ0DxpNOq1rG2t5cgTgShJFGSuU7XO45cqC+1NVOuZnP6tlgZRuSYOfNupGkHID0o3cJOsw4DVeJpMovcGw==", - "cpu": [ - "s390x" - ], - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=20.9.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linux-s390x": "1.3.2" - } - }, - "node_modules/@img/sharp-linux-x64": { - "version": "0.35.3", - "resolved": "https://registry.npmmirror.com/@img/sharp-linux-x64/-/sharp-linux-x64-0.35.3.tgz", - "integrity": "sha512-8pqvxubL2PGdhlPy6GLqzDYMUjyRmKAwKHYKixpdJYBUK7PJ0C029XdsnpFIdgRZG68fZiGdHVWcKPvtiPB4cA==", - "cpu": [ - "x64" - ], - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=20.9.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linux-x64": "1.3.2" - } - }, - "node_modules/@img/sharp-linuxmusl-arm64": { - "version": "0.35.3", - "resolved": "https://registry.npmmirror.com/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.35.3.tgz", - "integrity": "sha512-Vz0iQjzzcSX3HCbfwFfCSG/9SCIqyO0mH2sXyiHaAYfBk0cRsCWXRyQYX0ovCK/PAQBbTzQ0dsPQHh5MAFL59w==", - "cpu": [ - "arm64" - ], - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=20.9.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linuxmusl-arm64": "1.3.2" - } - }, - "node_modules/@img/sharp-linuxmusl-x64": { - "version": "0.35.3", - "resolved": "https://registry.npmmirror.com/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.35.3.tgz", - "integrity": "sha512-6O1NPKcDVj9QEdg7Hx549EX8U0rp6yXQERqru6yRN7fGBn32UvIRJUlWnk+8xDCiG76hXVBbX82NZ/ZKr0euIg==", - "cpu": [ - "x64" - ], - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=20.9.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linuxmusl-x64": "1.3.2" - } - }, - "node_modules/@img/sharp-wasm32": { - "version": "0.35.3", - "resolved": "https://registry.npmmirror.com/@img/sharp-wasm32/-/sharp-wasm32-0.35.3.tgz", - "integrity": "sha512-cZ0XkcYGpHZkqW6iCkqTcmUC0CD9DhD5d/qeZlZkfRBn6GnHniZXLUo5+9xw8Iv76YE6LQFN9YNBlKREcCG76w==", - "license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT", - "optional": true, - "dependencies": { - "@emnapi/runtime": "^1.11.1" - }, - "engines": { - "node": ">=20.9.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-webcontainers-wasm32": { - "version": "0.35.3", - "resolved": "https://registry.npmmirror.com/@img/sharp-webcontainers-wasm32/-/sharp-webcontainers-wasm32-0.35.3.tgz", - "integrity": "sha512-2rnq7bX3NzeR2T4YWgz8qiG4h3TSdMe+vN1iQXpJleSJ3SM5zQ8Fy2SyyXAWlbxpEZ2Y+Z4u1BePgJEYbSy80Q==", - "cpu": [ - "wasm32" - ], - "license": "Apache-2.0", - "optional": true, - "dependencies": { - "@img/sharp-wasm32": "0.35.3" - }, - "engines": { - "node": ">=20.9.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-win32-arm64": { - "version": "0.35.3", - "resolved": "https://registry.npmmirror.com/@img/sharp-win32-arm64/-/sharp-win32-arm64-0.35.3.tgz", - "integrity": "sha512-4bPwFdMbeC4JQ8L8LOyWp6nsHcboP5fxkp6iPOXz2Vg49R42TuMs2whkJ5OAP4/Ul035qOzy0AecOF9VOscn4w==", - "cpu": [ - "arm64" - ], - "license": "Apache-2.0 AND LGPL-3.0-or-later", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=20.9.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-win32-ia32": { - "version": "0.35.3", - "resolved": "https://registry.npmmirror.com/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.35.3.tgz", - "integrity": "sha512-r53mXsBN6lFUDiST764SvgwUdHAqM4rPAiDzAmf4fLoB6X/rkfyTrLCg6+g17wJJiCmB3JYgHuUldCWUIRFSXw==", - "cpu": [ - "ia32" - ], - "license": "Apache-2.0 AND LGPL-3.0-or-later", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": "^20.9.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-win32-x64": { - "version": "0.35.3", - "resolved": "https://registry.npmmirror.com/@img/sharp-win32-x64/-/sharp-win32-x64-0.35.3.tgz", - "integrity": "sha512-D4y1vNeZrIIJCN+uHaWVtH86B+aCrdMYYjicy9pXHvbGZeGYLLSd3wdVuC37FxVXlU1ARsk84eKWfWMXGYEqvA==", - "cpu": [ - "x64" - ], - "license": "Apache-2.0 AND LGPL-3.0-or-later", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=20.9.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@joplin/turndown-plugin-gfm": { - "version": "1.0.67", - "resolved": "https://registry.npmmirror.com/@joplin/turndown-plugin-gfm/-/turndown-plugin-gfm-1.0.67.tgz", - "integrity": "sha512-FZfW5EZfidhzd1IaY1uxHnIZPTVOxAdleMZ4/1U6Nt5b7+Qj5JThDnaIomuJtetnUBzuRNbe9FWMuqD4B3dlWA==", - "license": "MIT" - }, - "node_modules/@koromix/koffi-darwin-arm64": { - "version": "3.1.5", - "resolved": "https://registry.npmmirror.com/@koromix/koffi-darwin-arm64/-/koffi-darwin-arm64-3.1.5.tgz", - "integrity": "sha512-IpqITl2fJi3QN9bTtNnygWPdK7ScSjw3xtGu8e6feYGvimCysu+spgI5KyeslY2jTnqxGS9xr8pLAbLhGJ8edA==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "funding": { - "url": "https://liberapay.com/Koromix" - } - }, - "node_modules/@koromix/koffi-darwin-x64": { - "version": "3.1.5", - "resolved": "https://registry.npmmirror.com/@koromix/koffi-darwin-x64/-/koffi-darwin-x64-3.1.5.tgz", - "integrity": "sha512-4Tia4BS5EV/+vN9eIrdToanVe+U/2VqTZCBgOzoUbPKjgky51eqM+3J4qdRUvmYJohcJNPob5/hsxeItUZrl1g==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "funding": { - "url": "https://liberapay.com/Koromix" - } - }, - "node_modules/@koromix/koffi-freebsd-arm64": { - "version": "3.1.5", - "resolved": "https://registry.npmmirror.com/@koromix/koffi-freebsd-arm64/-/koffi-freebsd-arm64-3.1.5.tgz", - "integrity": "sha512-bP94uzseFO79NG3flpU3WxfyvltD+jzC/kN8FDZLi8J0VUZNW1Wmu8yq87KEzjX1qT9KyX4Y+elVbGqHXHTv2Q==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "funding": { - "url": "https://liberapay.com/Koromix" - } - }, - "node_modules/@koromix/koffi-freebsd-ia32": { - "version": "3.1.5", - "resolved": "https://registry.npmmirror.com/@koromix/koffi-freebsd-ia32/-/koffi-freebsd-ia32-3.1.5.tgz", - "integrity": "sha512-raFXXAPHzvCQWhaoMUF+Cc2ZWgg2UBU0RVoowHZhaw9nQYPC1pERcPRH+JA+SNIN6g4d2GFW6uPFc+QbUhsagA==", - "cpu": [ - "ia32" - ], - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "funding": { - "url": "https://liberapay.com/Koromix" - } - }, - "node_modules/@koromix/koffi-freebsd-x64": { - "version": "3.1.5", - "resolved": "https://registry.npmmirror.com/@koromix/koffi-freebsd-x64/-/koffi-freebsd-x64-3.1.5.tgz", - "integrity": "sha512-h6RyBZmPMBIDWTABkJIhzDdYwSnYAJvTacHpEjbT55Arkmw1H15Rl7CFtXuEuBrqh+uivoCrRgA6vszl9CsJ9g==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "funding": { - "url": "https://liberapay.com/Koromix" - } - }, - "node_modules/@koromix/koffi-linux-arm64": { - "version": "3.1.5", - "resolved": "https://registry.npmmirror.com/@koromix/koffi-linux-arm64/-/koffi-linux-arm64-3.1.5.tgz", - "integrity": "sha512-u0vCmKPu4yQDhl/ri1J6U3vDnvYtYjoZaIWb+oMbRXhVZeiqdE53MGPb+q2A7Dj2n9IbYloAfEICQbL6l0pmiQ==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://liberapay.com/Koromix" - } - }, - "node_modules/@koromix/koffi-linux-ia32": { - "version": "3.1.5", - "resolved": "https://registry.npmmirror.com/@koromix/koffi-linux-ia32/-/koffi-linux-ia32-3.1.5.tgz", - "integrity": "sha512-Xa5JbumWglwPVZgrJcLhqyC1wCWlfm7+C00p3FuOTNGp0qoYuf2/tOoAh0/q7+taVm30cMopu/6lRHwdmF6I/w==", - "cpu": [ - "ia32" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://liberapay.com/Koromix" - } - }, - "node_modules/@koromix/koffi-linux-loong64": { - "version": "3.1.5", - "resolved": "https://registry.npmmirror.com/@koromix/koffi-linux-loong64/-/koffi-linux-loong64-3.1.5.tgz", - "integrity": "sha512-F3i2CeTcqVBUQiSRUBSEzX1VgtXmLLiZb/ouZtXHkWpTLhJNd9TH7s3CizTofci0VRqlKdexGUYhK5vzPDAAHA==", - "cpu": [ - "loong64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://liberapay.com/Koromix" - } - }, - "node_modules/@koromix/koffi-linux-riscv64": { - "version": "3.1.5", - "resolved": "https://registry.npmmirror.com/@koromix/koffi-linux-riscv64/-/koffi-linux-riscv64-3.1.5.tgz", - "integrity": "sha512-2TgQuzy+4PfDg+rw3kOmN6lywEWdzKT3eaLPbOp0b/9DaN7CLBJ/QIR5GhGsMNpeI30zU0YzFeYFxoVoJ/LqFw==", - "cpu": [ - "riscv64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://liberapay.com/Koromix" - } - }, - "node_modules/@koromix/koffi-linux-x64": { - "version": "3.1.5", - "resolved": "https://registry.npmmirror.com/@koromix/koffi-linux-x64/-/koffi-linux-x64-3.1.5.tgz", - "integrity": "sha512-2yaIg/1V0m4CiAUMzG4CIlWmq1WJ+QBMlFfaGr9su+OH5fuIqC7V3BbMiB03IwIl1VofIZO5JA4Db4lID8tpbw==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://liberapay.com/Koromix" - } - }, - "node_modules/@koromix/koffi-openbsd-ia32": { - "version": "3.1.5", - "resolved": "https://registry.npmmirror.com/@koromix/koffi-openbsd-ia32/-/koffi-openbsd-ia32-3.1.5.tgz", - "integrity": "sha512-8/OXd+u9omMooykhvdJPEP7u6FFzzrrFo9gOmSHc9/DPt3XkVYOtSsE97PDk6zYaAzwIYHSKjHvIXsfFwFc7sg==", - "cpu": [ - "ia32" - ], - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], - "funding": { - "url": "https://liberapay.com/Koromix" - } - }, - "node_modules/@koromix/koffi-openbsd-x64": { - "version": "3.1.5", - "resolved": "https://registry.npmmirror.com/@koromix/koffi-openbsd-x64/-/koffi-openbsd-x64-3.1.5.tgz", - "integrity": "sha512-SpeqldKkuDk2aTj5PVWumy7eq6Tr2GtBPAOI1NiDHhg8xe433KraxrA9V9UjEd+1+kSGJQGR04nQByN3MPA9PQ==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], - "funding": { - "url": "https://liberapay.com/Koromix" - } - }, - "node_modules/@koromix/koffi-win32-arm64": { - "version": "3.1.5", - "resolved": "https://registry.npmmirror.com/@koromix/koffi-win32-arm64/-/koffi-win32-arm64-3.1.5.tgz", - "integrity": "sha512-uej3YAEKAhlfVPoIo5sOwtxhTLRVJ01LgtWrKGpnnAQU3C+Ilmaxdh+Oc2xc1G3NK30N5eCVJpyO9r3pjKC6Vw==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "funding": { - "url": "https://liberapay.com/Koromix" - } - }, - "node_modules/@koromix/koffi-win32-ia32": { - "version": "3.1.5", - "resolved": "https://registry.npmmirror.com/@koromix/koffi-win32-ia32/-/koffi-win32-ia32-3.1.5.tgz", - "integrity": "sha512-d42jv2f4PwtJGNJS19Xfn/BRtGsBNNVkw0O0K5tkIGI+yNq4MnPTSUsaGbDIkCLNsCgk/LFqAaE8BExyCdrujA==", - "cpu": [ - "ia32" - ], - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "funding": { - "url": "https://liberapay.com/Koromix" - } - }, - "node_modules/@koromix/koffi-win32-x64": { - "version": "3.1.5", - "resolved": "https://registry.npmmirror.com/@koromix/koffi-win32-x64/-/koffi-win32-x64-3.1.5.tgz", - "integrity": "sha512-Pyo1WEHEP6Ek2NEn2pquwJzSPLOdY4vymoPSz0an1DgvFWSkOyBYYkGVoxL1ajfj5I1pPdXysYqixtVTzAtOfQ==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "funding": { - "url": "https://liberapay.com/Koromix" - } - }, - "node_modules/@mistralai/mistralai": { - "version": "2.2.6", - "resolved": "https://registry.npmmirror.com/@mistralai/mistralai/-/mistralai-2.2.6.tgz", - "integrity": "sha512-W8pX7zHxjJvMIpw8JMxeJEleapXX0Q9NPszdNzqkM3MIEoIGPObdodujj+WHteXEvGfaP/AMwlNyRfEzSY6dQQ==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/semantic-conventions": "^1.40.0", - "ws": "^8.18.0", - "zod": "^3.25.0 || ^4.0.0", - "zod-to-json-schema": "^3.25.0" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.9.0" - }, - "peerDependenciesMeta": { - "@opentelemetry/api": { - "optional": true - } - } - }, - "node_modules/@mixmark-io/domino": { - "version": "2.2.0", - "resolved": "https://registry.npmmirror.com/@mixmark-io/domino/-/domino-2.2.0.tgz", - "integrity": "sha512-Y28PR25bHXUg88kCV7nivXrP2Nj2RueZ3/l/jdx6J9f8J4nsEGcgX0Qe6lt7Pa+J79+kPiJU3LguR6O/6zrLOw==", - "license": "BSD-2-Clause" - }, - "node_modules/@modelcontextprotocol/sdk": { - "version": "1.30.0", - "resolved": "https://registry.npmmirror.com/@modelcontextprotocol/sdk/-/sdk-1.30.0.tgz", - "integrity": "sha512-xKd8OIzlqNzcqcNumGAa6g+PW2kjD5vrpcKOnfldAUPP3j7lnqMPwlTXQm8gF+UwH72z0lqaRbjr9hqGz0eITA==", - "license": "MIT", - "dependencies": { - "@hono/node-server": "^1.19.9 || ^2.0.5", - "ajv": "^8.17.1", - "ajv-formats": "^3.0.1", - "content-type": "^1.0.5", - "cors": "^2.8.5", - "cross-spawn": "^7.0.5", - "eventsource": "^3.0.2", - "eventsource-parser": "^3.0.0", - "express": "^5.2.1", - "express-rate-limit": "^8.2.1", - "hono": "^4.11.4", - "jose": "^6.1.3", - "json-schema-typed": "^8.0.2", - "pkce-challenge": "^5.0.0", - "raw-body": "^3.0.0", - "zod": "^3.25 || ^4.0", - "zod-to-json-schema": "^3.25.1" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "@cfworker/json-schema": "^4.1.1", - "zod": "^3.25 || ^4.0" - }, - "peerDependenciesMeta": { - "@cfworker/json-schema": { - "optional": true - }, - "zod": { - "optional": false - } - } - }, - "node_modules/@opentelemetry/api": { - "version": "1.9.1", - "resolved": "https://registry.npmmirror.com/@opentelemetry/api/-/api-1.9.1.tgz", - "integrity": "sha512-gLyJlPHPZYdAk1JENA9LeHejZe1Ti77/pTeFm/nMXmQH/HFZlcS/O2XJB+L8fkbrNSqhdtlvjBVjxwUYanNH5Q==", - "license": "Apache-2.0", - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/@opentelemetry/api-logs": { - "version": "0.220.0", - "resolved": "https://registry.npmmirror.com/@opentelemetry/api-logs/-/api-logs-0.220.0.tgz", - "integrity": "sha512-CmVa4ImJ+ynfrPMNaAXHET6Bhb44SwzmfyVJFq9ni2jgXJR/l7C6gfVFddNmHP+ZOkP9cf4f9DBe68qVLTHc9w==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/api": "^1.3.0" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/@opentelemetry/core": { - "version": "2.9.0", - "resolved": "https://registry.npmmirror.com/@opentelemetry/core/-/core-2.9.0.tgz", - "integrity": "sha512-m2nckMT80NnmjTYSPjJQObBJ+8dgkoajEOUbznL8AHZ3T3yHRk2P7gI1PhEBc1+lOnrYE9UWrWHqJDsmqjmNbw==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/semantic-conventions": "^1.29.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.0.0 <1.10.0" - } - }, - "node_modules/@opentelemetry/exporter-logs-otlp-http": { - "version": "0.220.0", - "resolved": "https://registry.npmmirror.com/@opentelemetry/exporter-logs-otlp-http/-/exporter-logs-otlp-http-0.220.0.tgz", - "integrity": "sha512-8186thl+pTw64iz/qEEen5oJZoZ/gO73XruChdaGlYdWOdBIQ42r+vHLf6a7vIDqTD4b8ZOoMlyxptanECaI9A==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/api-logs": "0.220.0", - "@opentelemetry/core": "2.9.0", - "@opentelemetry/otlp-exporter-base": "0.220.0", - "@opentelemetry/otlp-transformer": "0.220.0", - "@opentelemetry/sdk-logs": "0.220.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - } - }, - "node_modules/@opentelemetry/otlp-exporter-base": { - "version": "0.220.0", - "resolved": "https://registry.npmmirror.com/@opentelemetry/otlp-exporter-base/-/otlp-exporter-base-0.220.0.tgz", - "integrity": "sha512-CXYo8UD5Mn9YbgebO2EL4wejtA+gxLmLiu6HCk2KH2BR7XhFN6/6p1UlCb23DYCjeYkndevLHuejCCN1yx4+OQ==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "2.9.0", - "@opentelemetry/otlp-transformer": "0.220.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - } - }, - "node_modules/@opentelemetry/otlp-transformer": { - "version": "0.220.0", - "resolved": "https://registry.npmmirror.com/@opentelemetry/otlp-transformer/-/otlp-transformer-0.220.0.tgz", - "integrity": "sha512-lXGrv7KXZ0gNH9SVNUaa6vv6phVYGvJxfXAlMbzbakiXru75f5MZl8Z7oqiMMQD77riVHJCFlQvbZs/VVN2/4A==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/api-logs": "0.220.0", - "@opentelemetry/core": "2.9.0", - "@opentelemetry/resources": "2.9.0", - "@opentelemetry/sdk-logs": "0.220.0", - "@opentelemetry/sdk-metrics": "2.9.0", - "@opentelemetry/sdk-trace": "2.9.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - } - }, - "node_modules/@opentelemetry/otlp-transformer/node_modules/@opentelemetry/resources": { - "version": "2.9.0", - "resolved": "https://registry.npmmirror.com/@opentelemetry/resources/-/resources-2.9.0.tgz", - "integrity": "sha512-jyA5MBLQ+Dkl3+JsZkUoUvL7yHvU64kLsvpXKarWm6347Sl1t1bXFTFykUePNpT5WH5pm9a2Qtt03iIYQhZ1Fg==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "2.9.0", - "@opentelemetry/semantic-conventions": "^1.29.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.3.0 <1.10.0" - } - }, - "node_modules/@opentelemetry/resources": { - "version": "2.10.0", - "resolved": "https://registry.npmmirror.com/@opentelemetry/resources/-/resources-2.10.0.tgz", - "integrity": "sha512-q6MMm2zhggzsHVNbabYwut+a6nbuQQe3URUoxaojM/8K1IBfwwPzvxIjNi2/lI1TFe+fMHMW9MWhrtDLEXEnkA==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "2.10.0", - "@opentelemetry/semantic-conventions": "^1.29.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.3.0 <1.10.0" - } - }, - "node_modules/@opentelemetry/resources/node_modules/@opentelemetry/core": { - "version": "2.10.0", - "resolved": "https://registry.npmmirror.com/@opentelemetry/core/-/core-2.10.0.tgz", - "integrity": "sha512-/wNZ8twnEQQA4HoHu22+vcsdru6pWPWxW+7w+FlxT6Id7PE/WIbZmVKkte+PF72e0F2dnImFeHD2syyE1Mw6MQ==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/semantic-conventions": "^1.29.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.0.0 <1.10.0" - } - }, - "node_modules/@opentelemetry/sdk-logs": { - "version": "0.220.0", - "resolved": "https://registry.npmmirror.com/@opentelemetry/sdk-logs/-/sdk-logs-0.220.0.tgz", - "integrity": "sha512-WywcTkQtv2iNmt+6y5Kcd4rzvx9bLVsBa2Nwcmg01IUaBTkTow3W4d9KE5vNBpEDtb9tp21WcRBY/lANRrApYA==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/api-logs": "0.220.0", - "@opentelemetry/core": "2.9.0", - "@opentelemetry/resources": "2.9.0", - "@opentelemetry/semantic-conventions": "^1.29.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.4.0 <1.10.0" - } - }, - "node_modules/@opentelemetry/sdk-logs/node_modules/@opentelemetry/resources": { - "version": "2.9.0", - "resolved": "https://registry.npmmirror.com/@opentelemetry/resources/-/resources-2.9.0.tgz", - "integrity": "sha512-jyA5MBLQ+Dkl3+JsZkUoUvL7yHvU64kLsvpXKarWm6347Sl1t1bXFTFykUePNpT5WH5pm9a2Qtt03iIYQhZ1Fg==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "2.9.0", - "@opentelemetry/semantic-conventions": "^1.29.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.3.0 <1.10.0" - } - }, - "node_modules/@opentelemetry/sdk-metrics": { - "version": "2.9.0", - "resolved": "https://registry.npmmirror.com/@opentelemetry/sdk-metrics/-/sdk-metrics-2.9.0.tgz", - "integrity": "sha512-Xx8RGS4H5XEBl01WuCreMIpiah9cCXMbSkeuIePPdD2cUpq/vUzYmj8E/MK1OsbOc93FuAD4jfn2WOacKwLn7Q==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "2.9.0", - "@opentelemetry/resources": "2.9.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.9.0 <1.10.0" - } - }, - "node_modules/@opentelemetry/sdk-metrics/node_modules/@opentelemetry/resources": { - "version": "2.9.0", - "resolved": "https://registry.npmmirror.com/@opentelemetry/resources/-/resources-2.9.0.tgz", - "integrity": "sha512-jyA5MBLQ+Dkl3+JsZkUoUvL7yHvU64kLsvpXKarWm6347Sl1t1bXFTFykUePNpT5WH5pm9a2Qtt03iIYQhZ1Fg==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "2.9.0", - "@opentelemetry/semantic-conventions": "^1.29.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.3.0 <1.10.0" - } - }, - "node_modules/@opentelemetry/sdk-trace": { - "version": "2.9.0", - "resolved": "https://registry.npmmirror.com/@opentelemetry/sdk-trace/-/sdk-trace-2.9.0.tgz", - "integrity": "sha512-sGA19HvtrrSKYsseHphluH6j3p6Xa3fqc7c7y8f/7mYWejc1lyDFcpSdD1kYa50HCLUeEo4zA5bW0pniaPszuw==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "2.9.0", - "@opentelemetry/resources": "2.9.0", - "@opentelemetry/semantic-conventions": "^1.29.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.3.0 <1.10.0" - } - }, - "node_modules/@opentelemetry/sdk-trace/node_modules/@opentelemetry/resources": { - "version": "2.9.0", - "resolved": "https://registry.npmmirror.com/@opentelemetry/resources/-/resources-2.9.0.tgz", - "integrity": "sha512-jyA5MBLQ+Dkl3+JsZkUoUvL7yHvU64kLsvpXKarWm6347Sl1t1bXFTFykUePNpT5WH5pm9a2Qtt03iIYQhZ1Fg==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "2.9.0", - "@opentelemetry/semantic-conventions": "^1.29.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.3.0 <1.10.0" - } - }, - "node_modules/@opentelemetry/semantic-conventions": { - "version": "1.43.0", - "resolved": "https://registry.npmmirror.com/@opentelemetry/semantic-conventions/-/semantic-conventions-1.43.0.tgz", - "integrity": "sha512-eSYWTm620tTk45EKSedaUL8MFYI8hW164hIXsgIHyxu3VobUB3fFCu5t0hQby6OoWRPsG1KkKUG2M5UadiLiVg==", - "license": "Apache-2.0", - "engines": { - "node": ">=14" - } - }, - "node_modules/@protobufjs/aspromise": { - "version": "1.1.2", - "resolved": "https://registry.npmmirror.com/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", - "integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==", - "license": "BSD-3-Clause" - }, - "node_modules/@protobufjs/base64": { - "version": "1.1.2", - "resolved": "https://registry.npmmirror.com/@protobufjs/base64/-/base64-1.1.2.tgz", - "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==", - "license": "BSD-3-Clause" - }, - "node_modules/@protobufjs/codegen": { - "version": "2.0.5", - "resolved": "https://registry.npmmirror.com/@protobufjs/codegen/-/codegen-2.0.5.tgz", - "integrity": "sha512-zgXFLzW3Ap33e6d0Wlj4MGIm6Ce8O89n/apUaGNB/jx+hw+ruWEp7EwGUshdLKVRCxZW12fp9r40E1mQrf/34g==", - "license": "BSD-3-Clause" - }, - "node_modules/@protobufjs/eventemitter": { - "version": "1.1.1", - "resolved": "https://registry.npmmirror.com/@protobufjs/eventemitter/-/eventemitter-1.1.1.tgz", - "integrity": "sha512-vW1GmwMZNnL+gMRaovlh9yZX74kc+TTU3FObkkurpMaRtBfLP3ldjS9KQWlwZgraRE0+dheEEoAxdzcJQ8eXZg==", - "license": "BSD-3-Clause" - }, - "node_modules/@protobufjs/fetch": { - "version": "1.1.1", - "resolved": "https://registry.npmmirror.com/@protobufjs/fetch/-/fetch-1.1.1.tgz", - "integrity": "sha512-GpptLrs57adMSuHi3VNj0mAF8dwh36LMaYF6XyJ6JMWlVsc+t42tm1HSEDmOs3A8fC9yyeisgLhsTVQokOZ0zw==", - "license": "BSD-3-Clause", - "dependencies": { - "@protobufjs/aspromise": "^1.1.1" - } - }, - "node_modules/@protobufjs/float": { - "version": "1.0.2", - "resolved": "https://registry.npmmirror.com/@protobufjs/float/-/float-1.0.2.tgz", - "integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==", - "license": "BSD-3-Clause" - }, - "node_modules/@protobufjs/path": { - "version": "1.1.2", - "resolved": "https://registry.npmmirror.com/@protobufjs/path/-/path-1.1.2.tgz", - "integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==", - "license": "BSD-3-Clause" - }, - "node_modules/@protobufjs/pool": { - "version": "1.1.0", - "resolved": "https://registry.npmmirror.com/@protobufjs/pool/-/pool-1.1.0.tgz", - "integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==", - "license": "BSD-3-Clause" - }, - "node_modules/@protobufjs/utf8": { - "version": "1.1.2", - "resolved": "https://registry.npmmirror.com/@protobufjs/utf8/-/utf8-1.1.2.tgz", - "integrity": "sha512-b1UQwcEZ4yCnMCD8DAL1VlbvBJE9/IX4FTIp7BG1xYpf29SLazLSrqUkj4w7Y5y7cCVP6E5tcqqcI0xemPkHug==", - "license": "BSD-3-Clause" - }, - "node_modules/@smithy/core": { - "version": "3.33.2", - "resolved": "https://registry.npmmirror.com/@smithy/core/-/core-3.33.2.tgz", - "integrity": "sha512-CUGXpnPkVdjUCbix+83sWLW9VFgQOm44MDOx/ihITJMAnOZKvL8YYIc7DR9pP/tZ8CIRvMiON/TucvygqbHO3w==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/types": "^4.17.2", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/credential-provider-imds": { - "version": "4.5.2", - "resolved": "https://registry.npmmirror.com/@smithy/credential-provider-imds/-/credential-provider-imds-4.5.2.tgz", - "integrity": "sha512-A9uSdn72ozbRUSit0eib0TW7nXuNPlaeM0zcGkJ+nE6tFcSDbnmtwoxbTCFBukVQcszDAyvsd7+rTduPTXpygg==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/core": "^3.33.2", - "@smithy/types": "^4.17.2", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/fetch-http-handler": { - "version": "5.7.2", - "resolved": "https://registry.npmmirror.com/@smithy/fetch-http-handler/-/fetch-http-handler-5.7.2.tgz", - "integrity": "sha512-nZyWTmSpJEXl6VtWVMBJve/7x12DZu6sIX1z1a+ZMaHlQQRs9Zpu6NbTe/gmxYXVRpkjxyDYpZ5gx2IM6f/Wkw==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/core": "^3.33.2", - "@smithy/types": "^4.17.2", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/is-array-buffer": { - "version": "2.2.0", - "resolved": "https://registry.npmmirror.com/@smithy/is-array-buffer/-/is-array-buffer-2.2.0.tgz", - "integrity": "sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA==", - "license": "Apache-2.0", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@smithy/node-http-handler": { - "version": "4.7.3", - "resolved": "https://registry.npmmirror.com/@smithy/node-http-handler/-/node-http-handler-4.7.3.tgz", - "integrity": "sha512-/jPhevcTFPMVl6KNjbaI47iOg1zxC7IsnX4PQDGVZKMFceOXtB8IEYaB7a9VvkP/3oC60WzTeKocvSI7vLT0vA==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/core": "^3.24.3", - "@smithy/types": "^4.14.2", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/signature-v4": { - "version": "5.7.2", - "resolved": "https://registry.npmmirror.com/@smithy/signature-v4/-/signature-v4-5.7.2.tgz", - "integrity": "sha512-P7Ki6px6OOrxVtx8K7nLmyx4SlXUW/uTKDdMG44UHefmPGSRMBKe2v+TM59WdLcpUIrBrnuCsIqiM2MbsZjmhw==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/core": "^3.33.2", - "@smithy/types": "^4.17.2", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/types": { - "version": "4.17.2", - "resolved": "https://registry.npmmirror.com/@smithy/types/-/types-4.17.2.tgz", - "integrity": "sha512-FOKpVZob9MPTn2znRzGrnsMHv7BOsKVw3XiP/cOyYLDVZ9qKp4nifIiSCuUU/fIj5Vu0UOAxCFr+qRAtG0NUkA==", - "license": "Apache-2.0", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/util-buffer-from": { - "version": "2.2.0", - "resolved": "https://registry.npmmirror.com/@smithy/util-buffer-from/-/util-buffer-from-2.2.0.tgz", - "integrity": "sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/is-array-buffer": "^2.2.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@smithy/util-utf8": { - "version": "2.3.0", - "resolved": "https://registry.npmmirror.com/@smithy/util-utf8/-/util-utf8-2.3.0.tgz", - "integrity": "sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/util-buffer-from": "^2.2.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@standard-schema/spec": { - "version": "1.1.0", - "resolved": "https://registry.npmmirror.com/@standard-schema/spec/-/spec-1.1.0.tgz", - "integrity": "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==", - "license": "MIT" - }, - "node_modules/@tanstack/virtual-core": { - "version": "3.17.8", - "resolved": "https://registry.npmmirror.com/@tanstack/virtual-core/-/virtual-core-3.17.8.tgz", - "integrity": "sha512-BfEvehNpOT75r5Ksc5xW6NZuXujTfb7nlSEyVu4XHG3gdxNg1KqXruWbDewXOUaUYIo4oRbSfkjIajz4MAT8tA==", - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/tannerlinsley" - } - }, - "node_modules/@types/node": { - "version": "26.2.0", - "resolved": "https://registry.npmmirror.com/@types/node/-/node-26.2.0.tgz", - "integrity": "sha512-5IviulTZeRNp2vAJ514cc/HUlY5nZ9fCbq9DMyC52BrhFZACo3nI0R7qBxhQmo/d27NFe96ur/b7Wwxklda+kg==", - "license": "MIT", - "dependencies": { - "undici-types": "~8.3.0" - } - }, - "node_modules/@types/retry": { - "version": "0.12.0", - "resolved": "https://registry.npmmirror.com/@types/retry/-/retry-0.12.0.tgz", - "integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==", - "license": "MIT" - }, - "node_modules/@vscode/ripgrep": { - "version": "1.18.0", - "resolved": "https://registry.npmmirror.com/@vscode/ripgrep/-/ripgrep-1.18.0.tgz", - "integrity": "sha512-ns5lWe44tSfbTMbVUsyB+I1819PVSw4AdpgK0RNkzfWfwy6+3IUNSxwSrfTno1/oWaS/hERNz+XLWVyga2aJBQ==", - "license": "MIT", - "optionalDependencies": { - "@vscode/ripgrep-darwin-arm64": "1.18.0", - "@vscode/ripgrep-darwin-x64": "1.18.0", - "@vscode/ripgrep-linux-arm": "1.18.0", - "@vscode/ripgrep-linux-arm64": "1.18.0", - "@vscode/ripgrep-linux-ia32": "1.18.0", - "@vscode/ripgrep-linux-ppc64": "1.18.0", - "@vscode/ripgrep-linux-riscv64": "1.18.0", - "@vscode/ripgrep-linux-s390x": "1.18.0", - "@vscode/ripgrep-linux-x64": "1.18.0", - "@vscode/ripgrep-win32-arm64": "1.18.0", - "@vscode/ripgrep-win32-ia32": "1.18.0", - "@vscode/ripgrep-win32-x64": "1.18.0" - } - }, - "node_modules/@vscode/ripgrep-darwin-arm64": { - "version": "1.18.0", - "resolved": "https://registry.npmmirror.com/@vscode/ripgrep-darwin-arm64/-/ripgrep-darwin-arm64-1.18.0.tgz", - "integrity": "sha512-r3ktHSvbFycQNF6sl7sNDPocpsI7J+mEzh1IaZFkY0spm3k2Z9t8hPAeOK7+p0l6p6/swkQC14XWX01low+94Q==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@vscode/ripgrep-darwin-x64": { - "version": "1.18.0", - "resolved": "https://registry.npmmirror.com/@vscode/ripgrep-darwin-x64/-/ripgrep-darwin-x64-1.18.0.tgz", - "integrity": "sha512-25b4gWbL138dGuQU244ebCKKc0q05ULBMoFSz9oAEUHNeqK/lOJViDS7DRvbDazzAzSEdan391Znks/R5mkaTQ==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@vscode/ripgrep-linux-arm": { - "version": "1.18.0", - "resolved": "https://registry.npmmirror.com/@vscode/ripgrep-linux-arm/-/ripgrep-linux-arm-1.18.0.tgz", - "integrity": "sha512-GDAvufNDHu8zqLEmXstalQF0Wh6wQvdsBi/Vg3Yi3CK4a8XoFXqqXVEHEZ9xQz3t0NfoSEc9JbvK9DDS6FxyxQ==", - "cpu": [ - "arm" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@vscode/ripgrep-linux-arm64": { - "version": "1.18.0", - "resolved": "https://registry.npmmirror.com/@vscode/ripgrep-linux-arm64/-/ripgrep-linux-arm64-1.18.0.tgz", - "integrity": "sha512-lQ/5zTG++U0E3IhVgS4EPTTn/U4okncaRMM5GOFfOYZywS4nuD31GhkHbNYlDk5CuDC68+hYJ0/eQeyCKJDA+g==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@vscode/ripgrep-linux-ia32": { - "version": "1.18.0", - "resolved": "https://registry.npmmirror.com/@vscode/ripgrep-linux-ia32/-/ripgrep-linux-ia32-1.18.0.tgz", - "integrity": "sha512-YWLkSUtFd4Jh5EepIhA9RJSfv3uMAVMo+2rBIGHPBnvgLrZciIs2cDKei1/p6Wc/aCzUoHyMAg2R6tw4ZCBKGg==", - "cpu": [ - "ia32" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@vscode/ripgrep-linux-ppc64": { - "version": "1.18.0", - "resolved": "https://registry.npmmirror.com/@vscode/ripgrep-linux-ppc64/-/ripgrep-linux-ppc64-1.18.0.tgz", - "integrity": "sha512-quXVY8fwQ8O/lvU1yrSqSl3jlUzysRSb+AfUfCL/tRtphxsKlFvPAejryZ6vg4Bgvn8XL74xb4qMCDmWgYrT5w==", - "cpu": [ - "ppc64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@vscode/ripgrep-linux-riscv64": { - "version": "1.18.0", - "resolved": "https://registry.npmmirror.com/@vscode/ripgrep-linux-riscv64/-/ripgrep-linux-riscv64-1.18.0.tgz", - "integrity": "sha512-f5kBQBrWfQt8Q7OhSORuNDei5dkYagBj3y4jImSUXGMy8B/Ke7SltSRcUtjPv166FAFfHCAmWuZp3+cWnX2/Vw==", - "cpu": [ - "riscv64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@vscode/ripgrep-linux-s390x": { - "version": "1.18.0", - "resolved": "https://registry.npmmirror.com/@vscode/ripgrep-linux-s390x/-/ripgrep-linux-s390x-1.18.0.tgz", - "integrity": "sha512-rTOcJFGGcl2c07RUOWUo4U1ndnemKhY6A9hnMB18uk7jSgJc0d/QLBGWMWpumdtoJtpizn/wIv5mXIisJukusQ==", - "cpu": [ - "s390x" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@vscode/ripgrep-linux-x64": { - "version": "1.18.0", - "resolved": "https://registry.npmmirror.com/@vscode/ripgrep-linux-x64/-/ripgrep-linux-x64-1.18.0.tgz", - "integrity": "sha512-mQ3bVrUpnD2vs7QT0vX90Lt0cnUq467uFtEktIdsJJmW296RoSULRGqWgzG1AKxyBpNDD6l4ZO4qKf6SgyC23Q==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@vscode/ripgrep-win32-arm64": { - "version": "1.18.0", - "resolved": "https://registry.npmmirror.com/@vscode/ripgrep-win32-arm64/-/ripgrep-win32-arm64-1.18.0.tgz", - "integrity": "sha512-vfTIjq1OHnzUjxZcHVQAMbnggp8dpGf+0QKFOZHwWPqFwXxQC8eCWM+5NUdoJ6yrElCeMzoUTXoK/LdZaniB+Q==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@vscode/ripgrep-win32-ia32": { - "version": "1.18.0", - "resolved": "https://registry.npmmirror.com/@vscode/ripgrep-win32-ia32/-/ripgrep-win32-ia32-1.18.0.tgz", - "integrity": "sha512-//rfAE+BOw5AC2EMmepmiE36jUuevtQYNQqqlw1s3m9FlRxjxEut97RkRPHAu9BG4mSojatZx+kXZXNdyI9caQ==", - "cpu": [ - "ia32" - ], - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@vscode/ripgrep-win32-x64": { - "version": "1.18.0", - "resolved": "https://registry.npmmirror.com/@vscode/ripgrep-win32-x64/-/ripgrep-win32-x64-1.18.0.tgz", - "integrity": "sha512-KNPvtElldqILHdnAetujPaowkNbpqJy3ssIGGN6F6Kve9Qi+nNLI2DN01O83JjCEVQbCzl8Ov3QZ9Eov3BR8Dg==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/accepts": { - "version": "2.0.0", - "resolved": "https://registry.npmmirror.com/accepts/-/accepts-2.0.0.tgz", - "integrity": "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==", - "license": "MIT", - "dependencies": { - "mime-types": "^3.0.0", - "negotiator": "^1.0.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/agent-base": { - "version": "7.1.4", - "resolved": "https://registry.npmmirror.com/agent-base/-/agent-base-7.1.4.tgz", - "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", - "license": "MIT", - "engines": { - "node": ">= 14" - } - }, - "node_modules/ajv": { - "version": "8.20.0", - "resolved": "https://registry.npmmirror.com/ajv/-/ajv-8.20.0.tgz", - "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==", - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.3", - "fast-uri": "^3.0.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/ajv-formats": { - "version": "3.0.1", - "resolved": "https://registry.npmmirror.com/ajv-formats/-/ajv-formats-3.0.1.tgz", - "integrity": "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==", - "license": "MIT", - "dependencies": { - "ajv": "^8.0.0" - }, - "peerDependencies": { - "ajv": "^8.0.0" - }, - "peerDependenciesMeta": { - "ajv": { - "optional": true - } - } - }, - "node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmmirror.com/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "license": "Python-2.0" - }, - "node_modules/base64-js": { - "version": "1.5.1", - "resolved": "https://registry.npmmirror.com/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, - "node_modules/bignumber.js": { - "version": "9.3.1", - "resolved": "https://registry.npmmirror.com/bignumber.js/-/bignumber.js-9.3.1.tgz", - "integrity": "sha512-Ko0uX15oIUS7wJ3Rb30Fs6SkVbLmPBAKdlm7q9+ak9bbIeFf0MwuBsQV6z7+X768/cHsfg+WlysDWJcmthjsjQ==", - "license": "MIT", - "engines": { - "node": "*" - } - }, - "node_modules/body-parser": { - "version": "2.3.0", - "resolved": "https://registry.npmmirror.com/body-parser/-/body-parser-2.3.0.tgz", - "integrity": "sha512-2cGmJupaNgg+QUwVLAucDuWuoMZ6EX9iHDRswZ5lsNYEmwPaRknMPCLZz07yTzVq/83p4o/wzbDZbBrTvGGTIw==", - "license": "MIT", - "dependencies": { - "bytes": "^3.1.2", - "content-type": "^2.0.0", - "debug": "^4.4.3", - "http-errors": "^2.0.1", - "iconv-lite": "^0.7.2", - "on-finished": "^2.4.1", - "qs": "^6.15.2", - "raw-body": "^3.0.2", - "type-is": "^2.1.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/body-parser/node_modules/content-type": { - "version": "2.1.0", - "resolved": "https://registry.npmmirror.com/content-type/-/content-type-2.1.0.tgz", - "integrity": "sha512-mj7UPXE0jaqaOsukNZRUEfEi2AcL7C/vwmwcHV0O97eO1E1pxBZuyjlZrx5seTaNBg1U6+o35wpa35Qfcc+7ag==", - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/bowser": { - "version": "2.14.1", - "resolved": "https://registry.npmmirror.com/bowser/-/bowser-2.14.1.tgz", - "integrity": "sha512-tzPjzCxygAKWFOJP011oxFHs57HzIhOEracIgAePE4pqB3LikALKnSzUyU4MGs9/iCEUuHlAJTjTc5M+u7YEGg==", - "license": "MIT" - }, - "node_modules/buffer-equal-constant-time": { - "version": "1.0.1", - "resolved": "https://registry.npmmirror.com/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", - "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==", - "license": "BSD-3-Clause" - }, - "node_modules/bundle-name": { - "version": "4.1.0", - "resolved": "https://registry.npmmirror.com/bundle-name/-/bundle-name-4.1.0.tgz", - "integrity": "sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==", - "license": "MIT", - "dependencies": { - "run-applescript": "^7.0.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/bytes": { - "version": "3.1.2", - "resolved": "https://registry.npmmirror.com/bytes/-/bytes-3.1.2.tgz", - "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/call-bind-apply-helpers": { - "version": "1.0.2", - "resolved": "https://registry.npmmirror.com/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", - "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "function-bind": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/call-bound": { - "version": "1.0.4", - "resolved": "https://registry.npmmirror.com/call-bound/-/call-bound-1.0.4.tgz", - "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", - "license": "MIT", - "dependencies": { - "call-bind-apply-helpers": "^1.0.2", - "get-intrinsic": "^1.3.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/chokidar": { - "version": "4.0.3", - "resolved": "https://registry.npmmirror.com/chokidar/-/chokidar-4.0.3.tgz", - "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", - "license": "MIT", - "dependencies": { - "readdirp": "^4.0.1" - }, - "engines": { - "node": ">= 14.16.0" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/clsx": { - "version": "2.1.1", - "resolved": "https://registry.npmmirror.com/clsx/-/clsx-2.1.1.tgz", - "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/commander": { - "version": "15.0.0", - "resolved": "https://registry.npmmirror.com/commander/-/commander-15.0.0.tgz", - "integrity": "sha512-z67u4ZhzCL/Tydu1lJARtEZYWbWaN7oYLHbsuzocr6y4N6WZAagG3RQ4FW61V1/0+jImpj293XfrcYnd1qxtPg==", - "license": "MIT", - "engines": { - "node": ">=22.12.0" - } - }, - "node_modules/content-disposition": { - "version": "1.1.0", - "resolved": "https://registry.npmmirror.com/content-disposition/-/content-disposition-1.1.0.tgz", - "integrity": "sha512-5jRCH9Z/+DRP7rkvY83B+yGIGX96OYdJmzngqnw2SBSxqCFPd0w2km3s5iawpGX8krnwSGmF0FW5Nhr0Hfai3g==", - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/content-type": { - "version": "1.0.5", - "resolved": "https://registry.npmmirror.com/content-type/-/content-type-1.0.5.tgz", - "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/cookie": { - "version": "0.7.2", - "resolved": "https://registry.npmmirror.com/cookie/-/cookie-0.7.2.tgz", - "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/cookie-signature": { - "version": "1.2.2", - "resolved": "https://registry.npmmirror.com/cookie-signature/-/cookie-signature-1.2.2.tgz", - "integrity": "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==", - "license": "MIT", - "engines": { - "node": ">=6.6.0" - } - }, - "node_modules/cors": { - "version": "2.8.6", - "resolved": "https://registry.npmmirror.com/cors/-/cors-2.8.6.tgz", - "integrity": "sha512-tJtZBBHA6vjIAaF6EnIaq6laBBP9aq/Y3ouVJjEfoHbRBcHBAHYcMh/w8LDrk2PvIMMq8gmopa5D4V8RmbrxGw==", - "license": "MIT", - "dependencies": { - "object-assign": "^4", - "vary": "^1" - }, - "engines": { - "node": ">= 0.10" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/cross-spawn": { - "version": "7.0.6", - "resolved": "https://registry.npmmirror.com/cross-spawn/-/cross-spawn-7.0.6.tgz", - "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", - "license": "MIT", - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/data-uri-to-buffer": { - "version": "4.0.1", - "resolved": "https://registry.npmmirror.com/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz", - "integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==", - "license": "MIT", - "engines": { - "node": ">= 12" - } - }, - "node_modules/debug": { - "version": "4.4.3", - "resolved": "https://registry.npmmirror.com/debug/-/debug-4.4.3.tgz", - "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", - "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/default-browser": { - "version": "5.5.1", - "resolved": "https://registry.npmmirror.com/default-browser/-/default-browser-5.5.1.tgz", - "integrity": "sha512-m1pAzaJgZ/gssEqlOhJkPJp8Xly7QyW6xcrkUa2KKcDeDSEMP7X8xipU3snUcfisTQx0w1AGae+9UtJSfVnXGw==", - "license": "MIT", - "dependencies": { - "bundle-name": "^4.1.0", - "default-browser-id": "^5.0.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/default-browser-id": { - "version": "5.0.1", - "resolved": "https://registry.npmmirror.com/default-browser-id/-/default-browser-id-5.0.1.tgz", - "integrity": "sha512-x1VCxdX4t+8wVfd1so/9w+vQ4vx7lKd2Qp5tDRutErwmR85OgmfX7RlLRMWafRMY7hbEiXIbudNrjOAPa/hL8Q==", - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/define-lazy-prop": { - "version": "3.0.0", - "resolved": "https://registry.npmmirror.com/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz", - "integrity": "sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==", - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/depd": { - "version": "2.0.0", - "resolved": "https://registry.npmmirror.com/depd/-/depd-2.0.0.tgz", - "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/detect-libc": { - "version": "2.1.2", - "resolved": "https://registry.npmmirror.com/detect-libc/-/detect-libc-2.1.2.tgz", - "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", - "license": "Apache-2.0", - "engines": { - "node": ">=8" - } - }, - "node_modules/diff": { - "version": "9.0.0", - "resolved": "https://registry.npmmirror.com/diff/-/diff-9.0.0.tgz", - "integrity": "sha512-svtcdpS8CgJyqAjEQIXdb3OjhFVVYjzGAPO8WGCmRbrml64SPw/jJD4GoE98aR7r25A0XcgrK3F02yw9R/vhQw==", - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.3.1" - } - }, - "node_modules/dunder-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmmirror.com/dunder-proto/-/dunder-proto-1.0.1.tgz", - "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", - "license": "MIT", - "dependencies": { - "call-bind-apply-helpers": "^1.0.1", - "es-errors": "^1.3.0", - "gopd": "^1.2.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/ecdsa-sig-formatter": { - "version": "1.0.11", - "resolved": "https://registry.npmmirror.com/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", - "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", - "license": "Apache-2.0", - "dependencies": { - "safe-buffer": "^5.0.1" - } - }, - "node_modules/ee-first": { - "version": "1.1.1", - "resolved": "https://registry.npmmirror.com/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", - "license": "MIT" - }, - "node_modules/encodeurl": { - "version": "2.0.0", - "resolved": "https://registry.npmmirror.com/encodeurl/-/encodeurl-2.0.0.tgz", - "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/es-define-property": { - "version": "1.0.1", - "resolved": "https://registry.npmmirror.com/es-define-property/-/es-define-property-1.0.1.tgz", - "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-errors": { - "version": "1.3.0", - "resolved": "https://registry.npmmirror.com/es-errors/-/es-errors-1.3.0.tgz", - "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-object-atoms": { - "version": "1.1.2", - "resolved": "https://registry.npmmirror.com/es-object-atoms/-/es-object-atoms-1.1.2.tgz", - "integrity": "sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw==", - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/escape-html": { - "version": "1.0.3", - "resolved": "https://registry.npmmirror.com/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", - "license": "MIT" - }, - "node_modules/etag": { - "version": "1.8.1", - "resolved": "https://registry.npmmirror.com/etag/-/etag-1.8.1.tgz", - "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/eventsource": { - "version": "3.0.7", - "resolved": "https://registry.npmmirror.com/eventsource/-/eventsource-3.0.7.tgz", - "integrity": "sha512-CRT1WTyuQoD771GW56XEZFQ/ZoSfWid1alKGDYMmkt2yl8UXrVR4pspqWNEcqKvVIzg6PAltWjxcSSPrboA4iA==", - "license": "MIT", - "dependencies": { - "eventsource-parser": "^3.0.1" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/eventsource-parser": { - "version": "3.1.1", - "resolved": "https://registry.npmmirror.com/eventsource-parser/-/eventsource-parser-3.1.1.tgz", - "integrity": "sha512-EKN1vKAMcZ8MlYMpaNuxN6R9yakzH6uajHcHVTqWJzvu5pWw9DyhbP35HH8MVBQ+dZjAfDxk+A8NiR9KWaXiyQ==", - "license": "MIT", - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/express": { - "version": "5.2.1", - "resolved": "https://registry.npmmirror.com/express/-/express-5.2.1.tgz", - "integrity": "sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==", - "license": "MIT", - "dependencies": { - "accepts": "^2.0.0", - "body-parser": "^2.2.1", - "content-disposition": "^1.0.0", - "content-type": "^1.0.5", - "cookie": "^0.7.1", - "cookie-signature": "^1.2.1", - "debug": "^4.4.0", - "depd": "^2.0.0", - "encodeurl": "^2.0.0", - "escape-html": "^1.0.3", - "etag": "^1.8.1", - "finalhandler": "^2.1.0", - "fresh": "^2.0.0", - "http-errors": "^2.0.0", - "merge-descriptors": "^2.0.0", - "mime-types": "^3.0.0", - "on-finished": "^2.4.1", - "once": "^1.4.0", - "parseurl": "^1.3.3", - "proxy-addr": "^2.0.7", - "qs": "^6.14.0", - "range-parser": "^1.2.1", - "router": "^2.2.0", - "send": "^1.1.0", - "serve-static": "^2.2.0", - "statuses": "^2.0.1", - "type-is": "^2.0.1", - "vary": "^1.1.2" - }, - "engines": { - "node": ">= 18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/express-rate-limit": { - "version": "8.6.2", - "resolved": "https://registry.npmmirror.com/express-rate-limit/-/express-rate-limit-8.6.2.tgz", - "integrity": "sha512-YH4ru+eOJxQABscKFfRCy9R7x9QFGdezclVMwwgFFndzS2Xnm0uo6B0ABZsLhcpeptGv2qvuJVWlQr9gQZoC3A==", - "license": "MIT", - "dependencies": { - "debug": "^4.4.3", - "ip-address": "^10.2.0" - }, - "engines": { - "node": ">= 16" - }, - "funding": { - "url": "https://github.com/sponsors/express-rate-limit" - }, - "peerDependencies": { - "express": ">= 4.11" - } - }, - "node_modules/extend": { - "version": "3.0.2", - "resolved": "https://registry.npmmirror.com/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", - "license": "MIT" - }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmmirror.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "license": "MIT" - }, - "node_modules/fast-uri": { - "version": "3.1.5", - "resolved": "https://registry.npmmirror.com/fast-uri/-/fast-uri-3.1.5.tgz", - "integrity": "sha512-gHwA1O9LDIcKunMKhObS/HimwtehO1nPUECKAu5TpKgaO19fcWEl4bliWe1jWxVFvIXztJjjQ4L8XQ1EU9f7Jw==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/fastify" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/fastify" - } - ], - "license": "BSD-3-Clause" - }, - "node_modules/fetch-blob": { - "version": "3.2.0", - "resolved": "https://registry.npmmirror.com/fetch-blob/-/fetch-blob-3.2.0.tgz", - "integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/jimmywarting" - }, - { - "type": "paypal", - "url": "https://paypal.me/jimmywarting" - } - ], - "license": "MIT", - "dependencies": { - "node-domexception": "^1.0.0", - "web-streams-polyfill": "^3.0.3" - }, - "engines": { - "node": "^12.20 || >= 14.13" - } - }, - "node_modules/fflate": { - "version": "0.8.3", - "resolved": "https://registry.npmmirror.com/fflate/-/fflate-0.8.3.tgz", - "integrity": "sha512-tbZNuJrLwGUp3zshBtdy4W+ORxZuIh8a5ilyIEQDC5rY1f3U20JMry0Ll3WBzU58EZKsEuJFXhb5gwv8CsPvgA==", - "license": "MIT" - }, - "node_modules/finalhandler": { - "version": "2.1.1", - "resolved": "https://registry.npmmirror.com/finalhandler/-/finalhandler-2.1.1.tgz", - "integrity": "sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA==", - "license": "MIT", - "dependencies": { - "debug": "^4.4.0", - "encodeurl": "^2.0.0", - "escape-html": "^1.0.3", - "on-finished": "^2.4.1", - "parseurl": "^1.3.3", - "statuses": "^2.0.1" - }, - "engines": { - "node": ">= 18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/formdata-polyfill": { - "version": "4.0.10", - "resolved": "https://registry.npmmirror.com/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz", - "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==", - "license": "MIT", - "dependencies": { - "fetch-blob": "^3.1.2" - }, - "engines": { - "node": ">=12.20.0" - } - }, - "node_modules/forwarded": { - "version": "0.2.0", - "resolved": "https://registry.npmmirror.com/forwarded/-/forwarded-0.2.0.tgz", - "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/fresh": { - "version": "2.0.0", - "resolved": "https://registry.npmmirror.com/fresh/-/fresh-2.0.0.tgz", - "integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/function-bind": { - "version": "1.1.2", - "resolved": "https://registry.npmmirror.com/function-bind/-/function-bind-1.1.2.tgz", - "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/gaxios": { - "version": "7.3.1", - "resolved": "https://registry.npmmirror.com/gaxios/-/gaxios-7.3.1.tgz", - "integrity": "sha512-kB3rzJV7d9juLZh8/56QTXCwQfxyhdOMdyYk1HdQKFtF8TJTDTZQJtixWIwXdE9Jji91mC41DUNpjleo4L4eAQ==", - "license": "Apache-2.0", - "dependencies": { - "extend": "^3.0.2", - "https-proxy-agent": "^7.0.1", - "node-fetch": "^3.3.2" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/gcp-metadata": { - "version": "8.1.2", - "resolved": "https://registry.npmmirror.com/gcp-metadata/-/gcp-metadata-8.1.2.tgz", - "integrity": "sha512-zV/5HKTfCeKWnxG0Dmrw51hEWFGfcF2xiXqcA3+J90WDuP0SvoiSO5ORvcBsifmx/FoIjgQN3oNOGaQ5PhLFkg==", - "license": "Apache-2.0", - "dependencies": { - "gaxios": "^7.0.0", - "google-logging-utils": "^1.0.0", - "json-bigint": "^1.0.0" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/get-intrinsic": { - "version": "1.3.0", - "resolved": "https://registry.npmmirror.com/get-intrinsic/-/get-intrinsic-1.3.0.tgz", - "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", - "license": "MIT", - "dependencies": { - "call-bind-apply-helpers": "^1.0.2", - "es-define-property": "^1.0.1", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.1.1", - "function-bind": "^1.1.2", - "get-proto": "^1.0.1", - "gopd": "^1.2.0", - "has-symbols": "^1.1.0", - "hasown": "^2.0.2", - "math-intrinsics": "^1.1.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/get-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmmirror.com/get-proto/-/get-proto-1.0.1.tgz", - "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", - "license": "MIT", - "dependencies": { - "dunder-proto": "^1.0.1", - "es-object-atoms": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/google-auth-library": { - "version": "10.9.1", - "resolved": "https://registry.npmmirror.com/google-auth-library/-/google-auth-library-10.9.1.tgz", - "integrity": "sha512-i1ydyHrqcIxXkWh/uBmVkzCvIuq5yiK2ATndIe5XxKholrG/MTYP9xGYka4sQhrbIAgGjL2B6NOE7rFaiF3fXw==", - "license": "Apache-2.0", - "dependencies": { - "base64-js": "^1.3.0", - "ecdsa-sig-formatter": "^1.0.11", - "gaxios": "^7.1.4", - "gcp-metadata": "8.1.2", - "google-logging-utils": "1.1.3", - "jws": "^4.0.0" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/google-logging-utils": { - "version": "1.1.3", - "resolved": "https://registry.npmmirror.com/google-logging-utils/-/google-logging-utils-1.1.3.tgz", - "integrity": "sha512-eAmLkjDjAFCVXg7A1unxHsLf961m6y17QFqXqAXGj/gVkKFrEICfStRfwUlGNfeCEjNRa32JEWOUTlYXPyyKvA==", - "license": "Apache-2.0", - "engines": { - "node": ">=14" - } - }, - "node_modules/gopd": { - "version": "1.2.0", - "resolved": "https://registry.npmmirror.com/gopd/-/gopd-1.2.0.tgz", - "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-symbols": { - "version": "1.1.0", - "resolved": "https://registry.npmmirror.com/has-symbols/-/has-symbols-1.1.0.tgz", - "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/hasown": { - "version": "2.0.4", - "resolved": "https://registry.npmmirror.com/hasown/-/hasown-2.0.4.tgz", - "integrity": "sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==", - "license": "MIT", - "dependencies": { - "function-bind": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/hono": { - "version": "4.13.3", - "resolved": "https://registry.npmmirror.com/hono/-/hono-4.13.3.tgz", - "integrity": "sha512-r8AO2mYHoLxSHkgafNeC/BXyb2vWRxD3jem4Ts+ptav8oTG5FIRifAjuJEmZI4bSvvc2ns0GxmIYiZnHqN3mMw==", - "license": "MIT", - "engines": { - "node": ">=16.9.0" - } - }, - "node_modules/http-errors": { - "version": "2.0.1", - "resolved": "https://registry.npmmirror.com/http-errors/-/http-errors-2.0.1.tgz", - "integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==", - "license": "MIT", - "dependencies": { - "depd": "~2.0.0", - "inherits": "~2.0.4", - "setprototypeof": "~1.2.0", - "statuses": "~2.0.2", - "toidentifier": "~1.0.1" - }, - "engines": { - "node": ">= 0.8" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/http-proxy-agent": { - "version": "7.0.2", - "resolved": "https://registry.npmmirror.com/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", - "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", - "license": "MIT", - "dependencies": { - "agent-base": "^7.1.0", - "debug": "^4.3.4" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/https-proxy-agent": { - "version": "7.0.6", - "resolved": "https://registry.npmmirror.com/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", - "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", - "license": "MIT", - "dependencies": { - "agent-base": "^7.1.2", - "debug": "4" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/iconv-lite": { - "version": "0.7.3", - "resolved": "https://registry.npmmirror.com/iconv-lite/-/iconv-lite-0.7.3.tgz", - "integrity": "sha512-IKXpvIzjnC9XTAUbVBcMfGS0EPaIXtW6v+zr+RRp+hqULEpo0owZax6wyRwPOJbWbzjYspQwusTsfVr0ifh4uQ==", - "license": "MIT", - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - }, - "engines": { - "node": ">=0.10.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/immer": { - "version": "10.2.0", - "resolved": "https://registry.npmmirror.com/immer/-/immer-10.2.0.tgz", - "integrity": "sha512-d/+XTN3zfODyjr89gM3mPq1WNX2B8pYsu7eORitdwyA2sBubnTl3laYlBk4sXY5FUa5qTZGBDPJICVbvqzjlbw==", - "license": "MIT", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/immer" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmmirror.com/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "license": "ISC" - }, - "node_modules/ip-address": { - "version": "10.5.0", - "resolved": "https://registry.npmmirror.com/ip-address/-/ip-address-10.5.0.tgz", - "integrity": "sha512-R5SnVLJmgYYvf2F2ZgwSBnelz5G4q5AxIC277GDfUaNbrZKNANcBC7RHqYYePlszf4kBolVkJauG0ZjHHFh55g==", - "license": "MIT", - "engines": { - "node": ">= 12" - } - }, - "node_modules/ipaddr.js": { - "version": "1.9.1", - "resolved": "https://registry.npmmirror.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz", - "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", - "license": "MIT", - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/is-docker": { - "version": "3.0.0", - "resolved": "https://registry.npmmirror.com/is-docker/-/is-docker-3.0.0.tgz", - "integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==", - "license": "MIT", - "bin": { - "is-docker": "cli.js" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-in-ssh": { - "version": "1.0.0", - "resolved": "https://registry.npmmirror.com/is-in-ssh/-/is-in-ssh-1.0.0.tgz", - "integrity": "sha512-jYa6Q9rH90kR1vKB6NM7qqd1mge3Fx4Dhw5TVlK1MUBqhEOuCagrEHMevNuCcbECmXZ0ThXkRm+Ymr51HwEPAw==", - "license": "MIT", - "engines": { - "node": ">=20" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-inside-container": { - "version": "1.0.0", - "resolved": "https://registry.npmmirror.com/is-inside-container/-/is-inside-container-1.0.0.tgz", - "integrity": "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==", - "license": "MIT", - "dependencies": { - "is-docker": "^3.0.0" - }, - "bin": { - "is-inside-container": "cli.js" - }, - "engines": { - "node": ">=14.16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-promise": { - "version": "4.0.0", - "resolved": "https://registry.npmmirror.com/is-promise/-/is-promise-4.0.0.tgz", - "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==", - "license": "MIT" - }, - "node_modules/is-wsl": { - "version": "3.1.1", - "resolved": "https://registry.npmmirror.com/is-wsl/-/is-wsl-3.1.1.tgz", - "integrity": "sha512-e6rvdUCiQCAuumZslxRJWR/Doq4VpPR82kqclvcS0efgt430SlGIk05vdCN58+VrzgtIcfNODjozVielycD4Sw==", - "license": "MIT", - "dependencies": { - "is-inside-container": "^1.0.0" - }, - "engines": { - "node": ">=16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmmirror.com/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "license": "ISC" - }, - "node_modules/jose": { - "version": "6.2.9", - "resolved": "https://registry.npmmirror.com/jose/-/jose-6.2.9.tgz", - "integrity": "sha512-XrchZOFZUl/T3vTwRe8XK+cJrGtMF4th1ARnDfwbBXFKThGhlsxEE4Zu03AD/bjJSt/9jT/mxrOCkJWOg77aPA==", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/panva" - } - }, - "node_modules/js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmmirror.com/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "license": "MIT" - }, - "node_modules/js-yaml": { - "version": "4.3.1", - "resolved": "https://registry.npmmirror.com/js-yaml/-/js-yaml-4.3.1.tgz", - "integrity": "sha512-CY6crGq313MX8GkwvB7tzgp99vjQxY1++5y10/BKN/GUfHqWaOGQMNZkBvqSzsZKWk/ijwHlWzzkLulsGHhjWQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/puzrin" - }, - { - "type": "github", - "url": "https://github.com/sponsors/nodeca" - } - ], - "license": "MIT", - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/json-bigint": { - "version": "1.0.0", - "resolved": "https://registry.npmmirror.com/json-bigint/-/json-bigint-1.0.0.tgz", - "integrity": "sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==", - "license": "MIT", - "dependencies": { - "bignumber.js": "^9.0.0" - } - }, - "node_modules/json-schema-to-ts": { - "version": "3.1.1", - "resolved": "https://registry.npmmirror.com/json-schema-to-ts/-/json-schema-to-ts-3.1.1.tgz", - "integrity": "sha512-+DWg8jCJG2TEnpy7kOm/7/AxaYoaRbjVB4LFZLySZlWn8exGs3A4OLJR966cVvU26N7X9TWxl+Jsw7dzAqKT6g==", - "license": "MIT", - "dependencies": { - "@babel/runtime": "^7.18.3", - "ts-algebra": "^2.0.0" - }, - "engines": { - "node": ">=16" - } - }, - "node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmmirror.com/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "license": "MIT" - }, - "node_modules/json-schema-typed": { - "version": "8.0.2", - "resolved": "https://registry.npmmirror.com/json-schema-typed/-/json-schema-typed-8.0.2.tgz", - "integrity": "sha512-fQhoXdcvc3V28x7C7BMs4P5+kNlgUURe2jmUT1T//oBRMDrqy1QPelJimwZGo7Hg9VPV3EQV5Bnq4hbFy2vetA==", - "license": "BSD-2-Clause" - }, - "node_modules/jwa": { - "version": "2.0.1", - "resolved": "https://registry.npmmirror.com/jwa/-/jwa-2.0.1.tgz", - "integrity": "sha512-hRF04fqJIP8Abbkq5NKGN0Bbr3JxlQ+qhZufXVr0DvujKy93ZCbXZMHDL4EOtodSbCWxOqR8MS1tXA5hwqCXDg==", - "license": "MIT", - "dependencies": { - "buffer-equal-constant-time": "^1.0.1", - "ecdsa-sig-formatter": "1.0.11", - "safe-buffer": "^5.0.1" - } - }, - "node_modules/jws": { - "version": "4.0.1", - "resolved": "https://registry.npmmirror.com/jws/-/jws-4.0.1.tgz", - "integrity": "sha512-EKI/M/yqPncGUUh44xz0PxSidXFr/+r0pA70+gIYhjv+et7yxM+s29Y+VGDkovRofQem0fs7Uvf4+YmAdyRduA==", - "license": "MIT", - "dependencies": { - "jwa": "^2.0.1", - "safe-buffer": "^5.0.1" - } - }, - "node_modules/koffi": { - "version": "3.1.5", - "resolved": "https://registry.npmmirror.com/koffi/-/koffi-3.1.5.tgz", - "integrity": "sha512-XVwwrxg0Ca6IEUQF4YtGIU4XN0LSselFYpYvgfhh8wafCunhEEx5hPr7LZhp5QyeFA/LcRsKHTqncCdjWjWAlg==", - "hasInstallScript": true, - "license": "MIT", - "funding": { - "url": "https://liberapay.com/Koromix" - }, - "optionalDependencies": { - "@koromix/koffi-darwin-arm64": "3.1.5", - "@koromix/koffi-darwin-x64": "3.1.5", - "@koromix/koffi-freebsd-arm64": "3.1.5", - "@koromix/koffi-freebsd-ia32": "3.1.5", - "@koromix/koffi-freebsd-x64": "3.1.5", - "@koromix/koffi-linux-arm64": "3.1.5", - "@koromix/koffi-linux-ia32": "3.1.5", - "@koromix/koffi-linux-loong64": "3.1.5", - "@koromix/koffi-linux-riscv64": "3.1.5", - "@koromix/koffi-linux-x64": "3.1.5", - "@koromix/koffi-openbsd-ia32": "3.1.5", - "@koromix/koffi-openbsd-x64": "3.1.5", - "@koromix/koffi-win32-arm64": "3.1.5", - "@koromix/koffi-win32-ia32": "3.1.5", - "@koromix/koffi-win32-x64": "3.1.5" - } - }, - "node_modules/long": { - "version": "5.3.2", - "resolved": "https://registry.npmmirror.com/long/-/long-5.3.2.tgz", - "integrity": "sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==", - "license": "Apache-2.0" - }, - "node_modules/loose-envify": { - "version": "1.4.0", - "resolved": "https://registry.npmmirror.com/loose-envify/-/loose-envify-1.4.0.tgz", - "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", - "license": "MIT", - "peer": true, - "dependencies": { - "js-tokens": "^3.0.0 || ^4.0.0" - }, - "bin": { - "loose-envify": "cli.js" - } - }, - "node_modules/math-intrinsics": { - "version": "1.1.0", - "resolved": "https://registry.npmmirror.com/math-intrinsics/-/math-intrinsics-1.1.0.tgz", - "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/media-typer": { - "version": "1.1.1", - "resolved": "https://registry.npmmirror.com/media-typer/-/media-typer-1.1.1.tgz", - "integrity": "sha512-yz3xRaG20c6/BOzvYoDaGtPmGscs7YivItZEEqe6GbwNfHuxu9YNmvnEkMzKldAGY4/80pRcQRZSEnhquk9XuQ==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/merge-descriptors": { - "version": "2.0.0", - "resolved": "https://registry.npmmirror.com/merge-descriptors/-/merge-descriptors-2.0.0.tgz", - "integrity": "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==", - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/mime-db": { - "version": "1.54.0", - "resolved": "https://registry.npmmirror.com/mime-db/-/mime-db-1.54.0.tgz", - "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mime-types": { - "version": "3.0.2", - "resolved": "https://registry.npmmirror.com/mime-types/-/mime-types-3.0.2.tgz", - "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==", - "license": "MIT", - "dependencies": { - "mime-db": "^1.54.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmmirror.com/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "license": "MIT" - }, - "node_modules/negotiator": { - "version": "1.0.0", - "resolved": "https://registry.npmmirror.com/negotiator/-/negotiator-1.0.0.tgz", - "integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/node-addon-api": { - "version": "7.1.1", - "resolved": "https://registry.npmmirror.com/node-addon-api/-/node-addon-api-7.1.1.tgz", - "integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==", - "license": "MIT" - }, - "node_modules/node-addon-native-custom-loader": { - "version": "0.1.5", - "resolved": "https://registry.npmmirror.com/node-addon-native-custom-loader/-/node-addon-native-custom-loader-0.1.5.tgz", - "integrity": "sha512-rL0XXRytayIChYf1xaG9/1NzGBRTyFkQTIpn+MDz/hpr0PZw1a9PZIoH9HlYfagNawhXU+jfN650EvoSIvR7Vw==", - "license": "MIT", - "engines": { - "node": ">=20" - } - }, - "node_modules/node-addon-require-builtin": { - "version": "0.1.5", - "resolved": "https://registry.npmmirror.com/node-addon-require-builtin/-/node-addon-require-builtin-0.1.5.tgz", - "integrity": "sha512-isaquiStlp7qdFpaffy+2ssJPUR/kLPRE5gqfeWbb0Ahph9H7O3BOFwThqkVaTrxfpnjrQauxlOEgvzD+snhUg==", - "license": "MIT", - "dependencies": { - "node-addon-native-custom-loader": "0.1.5" - }, - "engines": { - "node": ">=20" - }, - "optionalDependencies": { - "node-addon-require-builtin-darwin-arm64": "0.1.5", - "node-addon-require-builtin-darwin-x64": "0.1.5", - "node-addon-require-builtin-linux-arm64-gnu": "0.1.5", - "node-addon-require-builtin-linux-x64-gnu": "0.1.5", - "node-addon-require-builtin-win32-arm64-msvc": "0.1.5", - "node-addon-require-builtin-win32-ia32-msvc": "0.1.5", - "node-addon-require-builtin-win32-x64-msvc": "0.1.5" - } - }, - "node_modules/node-addon-require-builtin-darwin-arm64": { - "version": "0.1.5", - "resolved": "https://registry.npmmirror.com/node-addon-require-builtin-darwin-arm64/-/node-addon-require-builtin-darwin-arm64-0.1.5.tgz", - "integrity": "sha512-MZ5RyGhuU7DTbwuNpOQW81/ep8n5Yd5YlZa6dWiEfJEh+01Dl4cCKGmMCWNgb0VtqAImRtAOtmZIPtwngiemKQ==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "dependencies": { - "node-addon-native-custom-loader": "0.1.5" - }, - "engines": { - "node": ">=20" - } - }, - "node_modules/node-addon-require-builtin-darwin-x64": { - "version": "0.1.5", - "resolved": "https://registry.npmmirror.com/node-addon-require-builtin-darwin-x64/-/node-addon-require-builtin-darwin-x64-0.1.5.tgz", - "integrity": "sha512-wdCSPn49AdNZ2EXHQqswiXk1cROFe9zSRaAX8PwQLxmjdLt+xZF7vZP6VlqgXm+VAOHv98q8kp9m7mO9jY3OgQ==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "dependencies": { - "node-addon-native-custom-loader": "0.1.5" - }, - "engines": { - "node": ">=20" - } - }, - "node_modules/node-addon-require-builtin-linux-arm64-gnu": { - "version": "0.1.5", - "resolved": "https://registry.npmmirror.com/node-addon-require-builtin-linux-arm64-gnu/-/node-addon-require-builtin-linux-arm64-gnu-0.1.5.tgz", - "integrity": "sha512-hCqzKpQiknDDv6rUdZqrxCBXROg/uUruO0geUuZsdM9M/Lds45gSb4bDE958HlPaCvrDyR0wTHl3II8A7yQeew==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "dependencies": { - "node-addon-native-custom-loader": "0.1.5" - }, - "engines": { - "node": ">=20" - } - }, - "node_modules/node-addon-require-builtin-linux-x64-gnu": { - "version": "0.1.5", - "resolved": "https://registry.npmmirror.com/node-addon-require-builtin-linux-x64-gnu/-/node-addon-require-builtin-linux-x64-gnu-0.1.5.tgz", - "integrity": "sha512-lgP+ruwWXbcXDslhp5uIc+dFgzITEGPZ4E50WdHGt/OzcoVhN6y5z72pRRvxy8DE661//QxqmCLe72rS3SVg+w==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "dependencies": { - "node-addon-native-custom-loader": "0.1.5" - }, - "engines": { - "node": ">=20" - } - }, - "node_modules/node-addon-require-builtin-win32-arm64-msvc": { - "version": "0.1.5", - "resolved": "https://registry.npmmirror.com/node-addon-require-builtin-win32-arm64-msvc/-/node-addon-require-builtin-win32-arm64-msvc-0.1.5.tgz", - "integrity": "sha512-KEO2eWS4lvZg6JmPPz04OdI4Ojrc7YzOs++4r6VnvwsqYN2r6mjGSGpouQkk8J2eLXBzC7X/D9wYTbUuQS8u1Q==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "dependencies": { - "node-addon-native-custom-loader": "0.1.5" - }, - "engines": { - "node": ">=20" - } - }, - "node_modules/node-addon-require-builtin-win32-ia32-msvc": { - "version": "0.1.5", - "resolved": "https://registry.npmmirror.com/node-addon-require-builtin-win32-ia32-msvc/-/node-addon-require-builtin-win32-ia32-msvc-0.1.5.tgz", - "integrity": "sha512-iSC988EqZm5XbKWp/giW6K6EBRTrHt/YQbAkKsZLglt7PplmvvrZ7C3tUsyh1wVxUTYAaxFdE2xbqSdpw0rb6g==", - "cpu": [ - "ia32" - ], - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "dependencies": { - "node-addon-native-custom-loader": "0.1.5" - }, - "engines": { - "node": ">=20 <23" - } - }, - "node_modules/node-addon-require-builtin-win32-x64-msvc": { - "version": "0.1.5", - "resolved": "https://registry.npmmirror.com/node-addon-require-builtin-win32-x64-msvc/-/node-addon-require-builtin-win32-x64-msvc-0.1.5.tgz", - "integrity": "sha512-pjuco/ESU3ChIp7WwacWfY2ENu2K5rGAgqjcXedoiFcTrjTf5Ln/miKSuNfE6IiuJ7tfMTJH6VH5hq+C1Y8JMQ==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "dependencies": { - "node-addon-native-custom-loader": "0.1.5" - }, - "engines": { - "node": ">=20" - } - }, - "node_modules/node-domexception": { - "version": "1.0.0", - "resolved": "https://registry.npmmirror.com/node-domexception/-/node-domexception-1.0.0.tgz", - "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==", - "deprecated": "Use your platform's native DOMException instead", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/jimmywarting" - }, - { - "type": "github", - "url": "https://paypal.me/jimmywarting" - } - ], - "license": "MIT", - "engines": { - "node": ">=10.5.0" - } - }, - "node_modules/node-fetch": { - "version": "3.3.2", - "resolved": "https://registry.npmmirror.com/node-fetch/-/node-fetch-3.3.2.tgz", - "integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==", - "license": "MIT", - "dependencies": { - "data-uri-to-buffer": "^4.0.0", - "fetch-blob": "^3.1.4", - "formdata-polyfill": "^4.0.10" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/node-fetch" - } - }, - "node_modules/node-pty": { - "version": "1.2.0-beta.15", - "resolved": "https://registry.npmmirror.com/node-pty/-/node-pty-1.2.0-beta.15.tgz", - "integrity": "sha512-vORSzHXi4Ofl7HemVWpuudLqCPdaQb4LfpRCUpE5HPxhp4JYscl8zZwxh11p26v2wvW24WMwnMfLjhRLixrfxA==", - "hasInstallScript": true, - "license": "MIT", - "dependencies": { - "node-addon-api": "^7.1.0" - } - }, - "node_modules/object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmmirror.com/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object-inspect": { - "version": "1.13.4", - "resolved": "https://registry.npmmirror.com/object-inspect/-/object-inspect-1.13.4.tgz", - "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/on-finished": { - "version": "2.4.1", - "resolved": "https://registry.npmmirror.com/on-finished/-/on-finished-2.4.1.tgz", - "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", - "license": "MIT", - "dependencies": { - "ee-first": "1.1.1" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmmirror.com/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "license": "ISC", - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/open": { - "version": "11.0.1", - "resolved": "https://registry.npmmirror.com/open/-/open-11.0.1.tgz", - "integrity": "sha512-NzwMUB6C1D0+Kd+9iMS/H4k+Ck3cTX6Ckyfr/gAGlmvSE1LUQZnEZvWBi4PYmMwH/S5SMeTXnE+9uAz8uF+pWw==", - "license": "MIT", - "dependencies": { - "default-browser": "^5.4.0", - "define-lazy-prop": "^3.0.0", - "is-in-ssh": "^1.0.0", - "is-inside-container": "^1.0.0", - "powershell-utils": "^0.2.0", - "wsl-utils": "^1.0.0" - }, - "engines": { - "node": ">=20" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/openai": { - "version": "6.26.0", - "resolved": "https://registry.npmmirror.com/openai/-/openai-6.26.0.tgz", - "integrity": "sha512-zd23dbWTjiJ6sSAX6s0HrCZi41JwTA1bQVs0wLQPZ2/5o2gxOJA5wh7yOAUgwYybfhDXyhwlpeQf7Mlgx8EOCA==", - "license": "Apache-2.0", - "bin": { - "openai": "bin/cli" - }, - "peerDependencies": { - "ws": "^8.18.0", - "zod": "^3.25 || ^4.0" - }, - "peerDependenciesMeta": { - "ws": { - "optional": true - }, - "zod": { - "optional": true - } - } - }, - "node_modules/p-retry": { - "version": "4.6.2", - "resolved": "https://registry.npmmirror.com/p-retry/-/p-retry-4.6.2.tgz", - "integrity": "sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ==", - "license": "MIT", - "dependencies": { - "@types/retry": "0.12.0", - "retry": "^0.13.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/parseurl": { - "version": "1.3.3", - "resolved": "https://registry.npmmirror.com/parseurl/-/parseurl-1.3.3.tgz", - "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/partial-json": { - "version": "0.1.7", - "resolved": "https://registry.npmmirror.com/partial-json/-/partial-json-0.1.7.tgz", - "integrity": "sha512-Njv/59hHaokb/hRUjce3Hdv12wd60MtM9Z5Olmn+nehe0QDAsRtRbJPvJ0Z91TusF0SuZRIvnM+S4l6EIP8leA==", - "license": "MIT" - }, - "node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmmirror.com/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/path-to-regexp": { - "version": "8.4.2", - "resolved": "https://registry.npmmirror.com/path-to-regexp/-/path-to-regexp-8.4.2.tgz", - "integrity": "sha512-qRcuIdP69NPm4qbACK+aDogI5CBDMi1jKe0ry5rSQJz8JVLsC7jV8XpiJjGRLLol3N+R5ihGYcrPLTno6pAdBA==", - "license": "MIT", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/picocolors": { - "version": "1.1.1", - "resolved": "https://registry.npmmirror.com/picocolors/-/picocolors-1.1.1.tgz", - "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", - "license": "ISC" - }, - "node_modules/picomatch": { - "version": "4.0.5", - "resolved": "https://registry.npmmirror.com/picomatch/-/picomatch-4.0.5.tgz", - "integrity": "sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==", - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/pkce-challenge": { - "version": "5.0.1", - "resolved": "https://registry.npmmirror.com/pkce-challenge/-/pkce-challenge-5.0.1.tgz", - "integrity": "sha512-wQ0b/W4Fr01qtpHlqSqspcj3EhBvimsdh0KlHhH8HRZnMsEa0ea2fTULOXOS9ccQr3om+GcGRk4e+isrZWV8qQ==", - "license": "MIT", - "engines": { - "node": ">=16.20.0" - } - }, - "node_modules/powershell-utils": { - "version": "0.2.0", - "resolved": "https://registry.npmmirror.com/powershell-utils/-/powershell-utils-0.2.0.tgz", - "integrity": "sha512-ZlsFlG7MtSFCoc5xreOvBAozCJ6Pf06opgJjh9ONEv418xpZSAzNjstD36C6+JwOnfSqOW/9uDkqKjezTdxZhw==", - "license": "MIT", - "engines": { - "node": ">=20" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/protobufjs": { - "version": "7.6.5", - "resolved": "https://registry.npmmirror.com/protobufjs/-/protobufjs-7.6.5.tgz", - "integrity": "sha512-/FPD0nUc9jH6rfFjji9IBqOz4pcSE3CsT1m7Ep6Mdb0LxSUMj8hgl6GomOvZzpNpAqqGaXA0P3VSrZLFzIhQrw==", - "hasInstallScript": true, - "license": "BSD-3-Clause", - "dependencies": { - "@protobufjs/aspromise": "^1.1.2", - "@protobufjs/base64": "^1.1.2", - "@protobufjs/codegen": "^2.0.5", - "@protobufjs/eventemitter": "^1.1.1", - "@protobufjs/fetch": "^1.1.1", - "@protobufjs/float": "^1.0.2", - "@protobufjs/path": "^1.1.2", - "@protobufjs/pool": "^1.1.0", - "@protobufjs/utf8": "^1.1.1", - "@types/node": ">=13.7.0", - "long": "^5.3.2" - }, - "engines": { - "node": ">=12.0.0" - } - }, - "node_modules/proxy-addr": { - "version": "2.0.7", - "resolved": "https://registry.npmmirror.com/proxy-addr/-/proxy-addr-2.0.7.tgz", - "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", - "license": "MIT", - "dependencies": { - "forwarded": "0.2.0", - "ipaddr.js": "1.9.1" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/qs": { - "version": "6.15.3", - "resolved": "https://registry.npmmirror.com/qs/-/qs-6.15.3.tgz", - "integrity": "sha512-O9gl3zCl5h5blw1KGUzQKhA5oUXSl8rwUIM5o0S3nCXMliSvy5Dzx7/DJcI+SwgICv+IneSZwhBh1oSyEHA71A==", - "license": "BSD-3-Clause", - "dependencies": { - "es-define-property": "^1.0.1", - "side-channel": "^1.1.1" - }, - "engines": { - "node": ">=0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/range-parser": { - "version": "1.3.0", - "resolved": "https://registry.npmmirror.com/range-parser/-/range-parser-1.3.0.tgz", - "integrity": "sha512-hek2mFQpPuI4E1BBKrSto+BU3e3x4xuarsbiwr3+lf7p44juvFMV0XFWQAP3xUyqXA4RrXLIoaSUGbSt056ZMw==", - "license": "MIT", - "engines": { - "node": ">= 0.6" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/raw-body": { - "version": "3.0.2", - "resolved": "https://registry.npmmirror.com/raw-body/-/raw-body-3.0.2.tgz", - "integrity": "sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==", - "license": "MIT", - "dependencies": { - "bytes": "~3.1.2", - "http-errors": "~2.0.1", - "iconv-lite": "~0.7.0", - "unpipe": "~1.0.0" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/react": { - "version": "18.3.1", - "resolved": "https://registry.npmmirror.com/react/-/react-18.3.1.tgz", - "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", - "license": "MIT", - "peer": true, - "dependencies": { - "loose-envify": "^1.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/readdirp": { - "version": "4.1.2", - "resolved": "https://registry.npmmirror.com/readdirp/-/readdirp-4.1.2.tgz", - "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", - "license": "MIT", - "engines": { - "node": ">= 14.18.0" - }, - "funding": { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/require-from-string": { - "version": "2.0.2", - "resolved": "https://registry.npmmirror.com/require-from-string/-/require-from-string-2.0.2.tgz", - "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/retry": { - "version": "0.13.1", - "resolved": "https://registry.npmmirror.com/retry/-/retry-0.13.1.tgz", - "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", - "license": "MIT", - "engines": { - "node": ">= 4" - } - }, - "node_modules/router": { - "version": "2.2.0", - "resolved": "https://registry.npmmirror.com/router/-/router-2.2.0.tgz", - "integrity": "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==", - "license": "MIT", - "dependencies": { - "debug": "^4.4.0", - "depd": "^2.0.0", - "is-promise": "^4.0.0", - "parseurl": "^1.3.3", - "path-to-regexp": "^8.0.0" - }, - "engines": { - "node": ">= 18" - } - }, - "node_modules/run-applescript": { - "version": "7.1.0", - "resolved": "https://registry.npmmirror.com/run-applescript/-/run-applescript-7.1.0.tgz", - "integrity": "sha512-DPe5pVFaAsinSaV6QjQ6gdiedWDcRCbUuiQfQa2wmWV7+xC9bGulGI8+TdRmoFkAPaBXk8CrAbnlY2ISniJ47Q==", - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmmirror.com/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, - "node_modules/safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmmirror.com/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "license": "MIT" - }, - "node_modules/scheduler": { - "version": "0.27.0", - "resolved": "https://registry.npmmirror.com/scheduler/-/scheduler-0.27.0.tgz", - "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==", - "license": "MIT", - "peer": true - }, - "node_modules/semver": { - "version": "7.8.5", - "resolved": "https://registry.npmmirror.com/semver/-/semver-7.8.5.tgz", - "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/send": { - "version": "1.2.1", - "resolved": "https://registry.npmmirror.com/send/-/send-1.2.1.tgz", - "integrity": "sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ==", - "license": "MIT", - "dependencies": { - "debug": "^4.4.3", - "encodeurl": "^2.0.0", - "escape-html": "^1.0.3", - "etag": "^1.8.1", - "fresh": "^2.0.0", - "http-errors": "^2.0.1", - "mime-types": "^3.0.2", - "ms": "^2.1.3", - "on-finished": "^2.4.1", - "range-parser": "^1.2.1", - "statuses": "^2.0.2" - }, - "engines": { - "node": ">= 18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/serve-static": { - "version": "2.2.1", - "resolved": "https://registry.npmmirror.com/serve-static/-/serve-static-2.2.1.tgz", - "integrity": "sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw==", - "license": "MIT", - "dependencies": { - "encodeurl": "^2.0.0", - "escape-html": "^1.0.3", - "parseurl": "^1.3.3", - "send": "^1.2.0" - }, - "engines": { - "node": ">= 18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/setprototypeof": { - "version": "1.2.0", - "resolved": "https://registry.npmmirror.com/setprototypeof/-/setprototypeof-1.2.0.tgz", - "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", - "license": "ISC" - }, - "node_modules/sharp": { - "version": "0.35.3", - "resolved": "https://registry.npmmirror.com/sharp/-/sharp-0.35.3.tgz", - "integrity": "sha512-ej0zVHuZGHCiABXcNxeYhpRnPNPAcvbG8RMdBAhDAxLKkCRVSpK3Iyu7qbqw3JMzoj0REeM6f3tJLtVwl0023Q==", - "license": "Apache-2.0", - "dependencies": { - "@img/colour": "^1.1.0", - "detect-libc": "^2.1.2", - "semver": "^7.8.5" - }, - "engines": { - "node": ">=20.9.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-darwin-arm64": "0.35.3", - "@img/sharp-darwin-x64": "0.35.3", - "@img/sharp-freebsd-wasm32": "0.35.3", - "@img/sharp-libvips-darwin-arm64": "1.3.2", - "@img/sharp-libvips-darwin-x64": "1.3.2", - "@img/sharp-libvips-linux-arm": "1.3.2", - "@img/sharp-libvips-linux-arm64": "1.3.2", - "@img/sharp-libvips-linux-ppc64": "1.3.2", - "@img/sharp-libvips-linux-riscv64": "1.3.2", - "@img/sharp-libvips-linux-s390x": "1.3.2", - "@img/sharp-libvips-linux-x64": "1.3.2", - "@img/sharp-libvips-linuxmusl-arm64": "1.3.2", - "@img/sharp-libvips-linuxmusl-x64": "1.3.2", - "@img/sharp-linux-arm": "0.35.3", - "@img/sharp-linux-arm64": "0.35.3", - "@img/sharp-linux-ppc64": "0.35.3", - "@img/sharp-linux-riscv64": "0.35.3", - "@img/sharp-linux-s390x": "0.35.3", - "@img/sharp-linux-x64": "0.35.3", - "@img/sharp-linuxmusl-arm64": "0.35.3", - "@img/sharp-linuxmusl-x64": "0.35.3", - "@img/sharp-webcontainers-wasm32": "0.35.3", - "@img/sharp-win32-arm64": "0.35.3", - "@img/sharp-win32-ia32": "0.35.3", - "@img/sharp-win32-x64": "0.35.3" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - } - } - }, - "node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmmirror.com/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "license": "MIT", - "dependencies": { - "shebang-regex": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmmirror.com/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/side-channel": { - "version": "1.1.1", - "resolved": "https://registry.npmmirror.com/side-channel/-/side-channel-1.1.1.tgz", - "integrity": "sha512-6x6dK6zJdpTzF4sQeNYxwtvBzf6Eg4GtlesS94HOvTudUeyK2WXAaIfmDgsyslYrRBeFIlsi54AYsFGUuhmvrQ==", - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "object-inspect": "^1.13.4", - "side-channel-list": "^1.0.1", - "side-channel-map": "^1.0.1", - "side-channel-weakmap": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/side-channel-list": { - "version": "1.0.1", - "resolved": "https://registry.npmmirror.com/side-channel-list/-/side-channel-list-1.0.1.tgz", - "integrity": "sha512-mjn/0bi/oUURjc5Xl7IaWi/OJJJumuoJFQJfDDyO46+hBWsfaVM65TBHq2eoZBhzl9EchxOijpkbRC8SVBQU0w==", - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "object-inspect": "^1.13.4" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/side-channel-map": { - "version": "1.0.1", - "resolved": "https://registry.npmmirror.com/side-channel-map/-/side-channel-map-1.0.1.tgz", - "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.5", - "object-inspect": "^1.13.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/side-channel-weakmap": { - "version": "1.0.2", - "resolved": "https://registry.npmmirror.com/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", - "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.5", - "object-inspect": "^1.13.3", - "side-channel-map": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/statuses": { - "version": "2.0.2", - "resolved": "https://registry.npmmirror.com/statuses/-/statuses-2.0.2.tgz", - "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/toidentifier": { - "version": "1.0.1", - "resolved": "https://registry.npmmirror.com/toidentifier/-/toidentifier-1.0.1.tgz", - "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", - "license": "MIT", - "engines": { - "node": ">=0.6" - } - }, - "node_modules/ts-algebra": { - "version": "2.0.0", - "resolved": "https://registry.npmmirror.com/ts-algebra/-/ts-algebra-2.0.0.tgz", - "integrity": "sha512-FPAhNPFMrkwz76P7cdjdmiShwMynZYN6SgOujD1urY4oNm80Ou9oMdmbR45LotcKOXoy7wSmHkRFE6Mxbrhefw==", - "license": "MIT" - }, - "node_modules/tslib": { - "version": "2.8.1", - "resolved": "https://registry.npmmirror.com/tslib/-/tslib-2.8.1.tgz", - "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", - "license": "0BSD" - }, - "node_modules/turndown": { - "version": "7.2.4", - "resolved": "https://registry.npmmirror.com/turndown/-/turndown-7.2.4.tgz", - "integrity": "sha512-I8yFsfRzmzK0WV1pNNOA4A7y4RDfFxPRxb3t+e3ui14qSGOxGtiSP6GjeX+Y6CHb7HYaFj7ECUD7VE5kQMZWGQ==", - "license": "MIT", - "dependencies": { - "@mixmark-io/domino": "^2.2.0" - }, - "engines": { - "node": ">=18", - "npm": ">=9" - } - }, - "node_modules/type-is": { - "version": "2.1.0", - "resolved": "https://registry.npmmirror.com/type-is/-/type-is-2.1.0.tgz", - "integrity": "sha512-faYHw0anBbc/kWF3zFTEnxSFOAGUX9GFbOBthvDdLsIlEoWOFOtS0zgCiQYwIskL9iGXZL3kAXD8OoZ4GmMATA==", - "license": "MIT", - "dependencies": { - "content-type": "^2.0.0", - "media-typer": "^1.1.0", - "mime-types": "^3.0.0" - }, - "engines": { - "node": ">= 18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/type-is/node_modules/content-type": { - "version": "2.1.0", - "resolved": "https://registry.npmmirror.com/content-type/-/content-type-2.1.0.tgz", - "integrity": "sha512-mj7UPXE0jaqaOsukNZRUEfEi2AcL7C/vwmwcHV0O97eO1E1pxBZuyjlZrx5seTaNBg1U6+o35wpa35Qfcc+7ag==", - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/typebox": { - "version": "1.1.38", - "resolved": "https://registry.npmmirror.com/typebox/-/typebox-1.1.38.tgz", - "integrity": "sha512-pZ0aQPmMmXoUvSbeuWf/Hzsc+avNw/Zd6VeE8CFgkVGWyuHPJvqeJJDeJqLve+K70LvjYIoleGcoJHPT17cWoA==", - "license": "MIT" - }, - "node_modules/undici-types": { - "version": "8.3.0", - "resolved": "https://registry.npmmirror.com/undici-types/-/undici-types-8.3.0.tgz", - "integrity": "sha512-j375ScV60dom+YkPFIfTLcOiPxkN/buHz5GobjLhixFuANaNs3C9l4GmrWqejgXWJ7BbJcFYpTEUkS1Ge8bpZQ==", - "license": "MIT" - }, - "node_modules/unpipe": { - "version": "1.0.0", - "resolved": "https://registry.npmmirror.com/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/use-sync-external-store": { - "version": "1.2.0", - "resolved": "https://registry.npmmirror.com/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz", - "integrity": "sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==", - "license": "MIT", - "peerDependencies": { - "react": "^16.8.0 || ^17.0.0 || ^18.0.0" - } - }, - "node_modules/vary": { - "version": "1.1.2", - "resolved": "https://registry.npmmirror.com/vary/-/vary-1.1.2.tgz", - "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/web-streams-polyfill": { - "version": "3.3.3", - "resolved": "https://registry.npmmirror.com/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz", - "integrity": "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==", - "license": "MIT", - "engines": { - "node": ">= 8" - } - }, - "node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmmirror.com/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "license": "ISC", - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmmirror.com/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "license": "ISC" - }, - "node_modules/ws": { - "version": "8.21.3", - "resolved": "https://registry.npmmirror.com/ws/-/ws-8.21.3.tgz", - "integrity": "sha512-201TZ/kPWxoPr/OKWjquZR1SWKXcvxdH+e1xrx89b3YbmzLMFCLfnaG1HFIgWzJOEWZ7MvpK++odZufgYR50Rw==", - "license": "MIT", - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": ">=5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } - } - }, - "node_modules/wsl-utils": { - "version": "1.0.0", - "resolved": "https://registry.npmmirror.com/wsl-utils/-/wsl-utils-1.0.0.tgz", - "integrity": "sha512-Hl0ZOAs672vg+06kfujwRhoS6/jehvULrlFkuF2dRu6pHgA8U06h3xqNIqNNU1LTXPcedxByAR4GS6pwQK0mgA==", - "license": "MIT", - "dependencies": { - "is-wsl": "^3.1.0", - "powershell-utils": "^0.1.0" - }, - "engines": { - "node": ">=20" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/wsl-utils/node_modules/powershell-utils": { - "version": "0.1.0", - "resolved": "https://registry.npmmirror.com/powershell-utils/-/powershell-utils-0.1.0.tgz", - "integrity": "sha512-dM0jVuXJPsDN6DvRpea484tCUaMiXWjuCn++HGTqUWzGDjv5tZkEZldAJ/UMlqRYGFrD/etByo4/xOuC/snX2A==", - "license": "MIT", - "engines": { - "node": ">=20" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/yaml": { - "version": "2.9.0", - "resolved": "https://registry.npmmirror.com/yaml/-/yaml-2.9.0.tgz", - "integrity": "sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA==", - "license": "ISC", - "bin": { - "yaml": "bin.mjs" - }, - "engines": { - "node": ">= 14.6" - }, - "funding": { - "url": "https://github.com/sponsors/eemeli" - } - }, - "node_modules/zod": { - "version": "4.4.3", - "resolved": "https://registry.npmmirror.com/zod/-/zod-4.4.3.tgz", - "integrity": "sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/colinhacks" - } - }, - "node_modules/zod-to-json-schema": { - "version": "3.25.2", - "resolved": "https://registry.npmmirror.com/zod-to-json-schema/-/zod-to-json-schema-3.25.2.tgz", - "integrity": "sha512-O/PgfnpT1xKSDeQYSCfRI5Gy3hPf91mKVDuYLUHZJMiDFptvP41MSnWofm8dnCm0256ZNfZIM7DSzuSMAFnjHA==", - "license": "ISC", - "peerDependencies": { - "zod": "^3.25.28 || ^4" - } - }, - "node_modules/zustand": { - "version": "4.4.7", - "resolved": "https://registry.npmmirror.com/zustand/-/zustand-4.4.7.tgz", - "integrity": "sha512-QFJWJMdlETcI69paJwhSMJz7PPWjVP8Sjhclxmxmxv/RYI7ZOvR5BHX+ktH0we9gTWQMxcne8q1OY8xxz604gw==", - "license": "MIT", - "dependencies": { - "use-sync-external-store": "1.2.0" - }, - "engines": { - "node": ">=12.7.0" - }, - "peerDependencies": { - "@types/react": ">=16.8", - "immer": ">=9.0", - "react": ">=16.8" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "immer": { - "optional": true - }, - "react": { - "optional": true - } - } - } - } -} +{ + "name": "@code-new-bie/dshx-tui", + "version": "0.0.0-m1", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "@code-new-bie/dshx-tui", + "version": "0.0.0-m1", + "dependencies": { + "@deepseek-ai/dsh-cmdline": "0.1.0-rc.8", + "@deepseek-ai/schemastery": "3.18.1" + }, + "bin": { + "dshx": "bin/dshx.mjs" + }, + "devDependencies": { + "@deepseek-ai/dsh": "0.1.0-rc.8", + "@deepseek-ai/dsh-agent": "0.1.0-rc.8", + "@deepseek-ai/dsh-app-boot": "0.1.0-rc.8", + "@deepseek-ai/dsh-host-apiproxy": "0.1.0-rc.8", + "@deepseek-ai/dsh-launch-environment": "0.1.0-rc.8", + "@deepseek-ai/dsh-llm": "0.1.0-rc.8", + "@deepseek-ai/dsh-session": "0.1.0-rc.8", + "ws": "^8.18.0" + }, + "engines": { + "node": "^22.19.0 || >=24.0.0" + }, + "peerDependencies": { + "@deepseek-ai/dsh": "0.1.0-rc.8", + "@deepseek-ai/dsh-agent": "0.1.0-rc.8", + "@deepseek-ai/dsh-app-boot": "0.1.0-rc.8", + "@deepseek-ai/dsh-host-apiproxy": "0.1.0-rc.8", + "@deepseek-ai/dsh-launch-environment": "0.1.0-rc.8", + "@deepseek-ai/dsh-llm": "0.1.0-rc.8", + "@deepseek-ai/dsh-session": "0.1.0-rc.8" + } + }, + "node_modules/@anthropic-ai/sdk": { + "version": "0.91.1", + "resolved": "https://registry.npmmirror.com/@anthropic-ai/sdk/-/sdk-0.91.1.tgz", + "integrity": "sha512-LAmu761tSN9r66ixvmciswUj/ZC+1Q4iAfpedTfSVLeswRwnY3n2Nb6Tsk+cLPP28aLOPWeMgIuTuCcMC6W/iw==", + "dev": true, + "license": "MIT", + "dependencies": { + "json-schema-to-ts": "^3.1.1" + }, + "bin": { + "anthropic-ai-sdk": "bin/cli" + }, + "peerDependencies": { + "zod": "^3.25.0 || ^4.0.0" + }, + "peerDependenciesMeta": { + "zod": { + "optional": true + } + } + }, + "node_modules/@aws-crypto/sha256-browser": { + "version": "5.2.0", + "resolved": "https://registry.npmmirror.com/@aws-crypto/sha256-browser/-/sha256-browser-5.2.0.tgz", + "integrity": "sha512-AXfN/lGotSQwu6HNcEsIASo7kWXZ5HYWvfOmSNKDsEqC4OashTp8alTmaz+F7TC2L083SFv5RdB+qU3Vs1kZqw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/sha256-js": "^5.2.0", + "@aws-crypto/supports-web-crypto": "^5.2.0", + "@aws-crypto/util": "^5.2.0", + "@aws-sdk/types": "^3.222.0", + "@aws-sdk/util-locate-window": "^3.0.0", + "@smithy/util-utf8": "^2.0.0", + "tslib": "^2.6.2" + } + }, + "node_modules/@aws-crypto/sha256-js": { + "version": "5.2.0", + "resolved": "https://registry.npmmirror.com/@aws-crypto/sha256-js/-/sha256-js-5.2.0.tgz", + "integrity": "sha512-FFQQyu7edu4ufvIZ+OadFpHHOt+eSTBaYaki44c+akjg7qZg9oOQeLlk77F6tSYqjDAFClrHJk9tMf0HdVyOvA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/util": "^5.2.0", + "@aws-sdk/types": "^3.222.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-crypto/supports-web-crypto": { + "version": "5.2.0", + "resolved": "https://registry.npmmirror.com/@aws-crypto/supports-web-crypto/-/supports-web-crypto-5.2.0.tgz", + "integrity": "sha512-iAvUotm021kM33eCdNfwIN//F77/IADDSs58i+MDaOqFrVjZo9bAal0NK7HurRuWLLpF1iLX7gbWrjHjeo+YFg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + } + }, + "node_modules/@aws-crypto/util": { + "version": "5.2.0", + "resolved": "https://registry.npmmirror.com/@aws-crypto/util/-/util-5.2.0.tgz", + "integrity": "sha512-4RkU9EsI6ZpBve5fseQlGNUWKMa1RLPQ1dnjnQoe07ldfIzcsGb5hC5W0Dm7u423KWzawlrpbjXBrXCEv9zazQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "^3.222.0", + "@smithy/util-utf8": "^2.0.0", + "tslib": "^2.6.2" + } + }, + "node_modules/@aws-sdk/client-bedrock-runtime": { + "version": "3.1048.0", + "resolved": "https://registry.npmmirror.com/@aws-sdk/client-bedrock-runtime/-/client-bedrock-runtime-3.1048.0.tgz", + "integrity": "sha512-u+NT61JZEkRFtpL0CAw1N1dwxnaLgwVXQl/zjJxTGgLyS/jTIdg2SdoEoCTHxgDyCnqa1HEi9QOoE9/pYRNpOQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/core": "^3.974.11", + "@aws-sdk/credential-provider-node": "^3.972.42", + "@aws-sdk/eventstream-handler-node": "^3.972.16", + "@aws-sdk/middleware-eventstream": "^3.972.12", + "@aws-sdk/middleware-websocket": "^3.972.19", + "@aws-sdk/token-providers": "3.1048.0", + "@aws-sdk/types": "^3.973.8", + "@smithy/core": "^3.24.2", + "@smithy/fetch-http-handler": "^5.4.2", + "@smithy/node-http-handler": "^4.7.2", + "@smithy/types": "^4.14.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/core": { + "version": "3.977.8", + "resolved": "https://registry.npmmirror.com/@aws-sdk/core/-/core-3.977.8.tgz", + "integrity": "sha512-7+Kcrkvrk9lM/m7jRhHpT4jCdvzGHsuaSRbF8TdzzkY1mRzp/Ogwf9c7H29k4gGhey0BBWhCWr16+t0J61gwmg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "^3.974.4", + "@aws-sdk/xml-builder": "^3.972.39", + "@aws/lambda-invoke-store": "^0.3.0", + "@smithy/core": "^3.31.1", + "@smithy/signature-v4": "^5.6.12", + "@smithy/types": "^4.16.1", + "bowser": "^2.11.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-env": { + "version": "3.972.69", + "resolved": "https://registry.npmmirror.com/@aws-sdk/credential-provider-env/-/credential-provider-env-3.972.69.tgz", + "integrity": "sha512-AreCFzcB4kH2HF9031Ot0jSJr3KXvRg6e8uDeub20JEVdZU3Bv0sTq1plc7VsT3KiqutlzH7l0j50UcCWHUioA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "^3.977.8", + "@aws-sdk/types": "^3.974.4", + "@smithy/core": "^3.31.1", + "@smithy/types": "^4.16.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-http": { + "version": "3.972.71", + "resolved": "https://registry.npmmirror.com/@aws-sdk/credential-provider-http/-/credential-provider-http-3.972.71.tgz", + "integrity": "sha512-A8ObcqVmDMnk4F9NozZ7JwmUu9Q4xyBJkmyq1C5U+wNM9ht9J7+EuuyabsLWXZnOoTqFaJuYBYTKf5CTipkEjA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "^3.977.8", + "@aws-sdk/types": "^3.974.4", + "@smithy/core": "^3.31.1", + "@smithy/fetch-http-handler": "^5.6.13", + "@smithy/node-http-handler": "^4.9.13", + "@smithy/types": "^4.16.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-http/node_modules/@smithy/node-http-handler": { + "version": "4.11.2", + "resolved": "https://registry.npmmirror.com/@smithy/node-http-handler/-/node-http-handler-4.11.2.tgz", + "integrity": "sha512-avwAh9HM3h2lcfjvP3zYIZGf+XVgLQ91wOJ2qoFbNpW1UZeZb33aGlhTZvtkANHfcGhJroRY64525OjfgOg30g==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@smithy/core": "^3.33.2", + "@smithy/types": "^4.17.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-ini": { + "version": "3.973.14", + "resolved": "https://registry.npmmirror.com/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.973.14.tgz", + "integrity": "sha512-7c+Wti2LsERNWMfm7ySz3/6RPopFW3Nmn7s63Xpcq6R/tRuY5hpvkHA2xVgi5ukJbvok9l0IDtVEvqTtg+X7dw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "^3.977.8", + "@aws-sdk/credential-provider-env": "^3.972.69", + "@aws-sdk/credential-provider-http": "^3.972.71", + "@aws-sdk/credential-provider-login": "^3.972.76", + "@aws-sdk/credential-provider-process": "^3.972.69", + "@aws-sdk/credential-provider-sso": "^3.973.13", + "@aws-sdk/credential-provider-web-identity": "^3.972.75", + "@aws-sdk/nested-clients": "^3.997.43", + "@aws-sdk/types": "^3.974.4", + "@smithy/core": "^3.31.1", + "@smithy/credential-provider-imds": "^4.4.16", + "@smithy/types": "^4.16.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-login": { + "version": "3.972.76", + "resolved": "https://registry.npmmirror.com/@aws-sdk/credential-provider-login/-/credential-provider-login-3.972.76.tgz", + "integrity": "sha512-LVixwOnEJfrrfKHeZjBA8pIMTZjNDq8ak8VpcoWUuCJDrSnBNU8POJksULMgvN089P0MXtQYH2Zs627/MK1K0g==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "^3.977.8", + "@aws-sdk/nested-clients": "^3.997.43", + "@aws-sdk/types": "^3.974.4", + "@smithy/core": "^3.31.1", + "@smithy/types": "^4.16.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-node": { + "version": "3.972.80", + "resolved": "https://registry.npmmirror.com/@aws-sdk/credential-provider-node/-/credential-provider-node-3.972.80.tgz", + "integrity": "sha512-bE2qh8ww4iClO1jHsBXdOE8FUgzDbdxbyorNjSCoPSkQd51k3jODItuPZfuwcLHZqDXsH+bI4AMHhqtuyR7mSg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/credential-provider-env": "^3.972.69", + "@aws-sdk/credential-provider-http": "^3.972.71", + "@aws-sdk/credential-provider-ini": "^3.973.14", + "@aws-sdk/credential-provider-process": "^3.972.69", + "@aws-sdk/credential-provider-sso": "^3.973.13", + "@aws-sdk/credential-provider-web-identity": "^3.972.75", + "@aws-sdk/types": "^3.974.4", + "@smithy/core": "^3.31.1", + "@smithy/credential-provider-imds": "^4.4.16", + "@smithy/types": "^4.16.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-process": { + "version": "3.972.69", + "resolved": "https://registry.npmmirror.com/@aws-sdk/credential-provider-process/-/credential-provider-process-3.972.69.tgz", + "integrity": "sha512-9kpTNdZTrcqXTfhxM7fgl9Z68ek3Fu5oe3Yf+A/pJGibEqpgZxz2tSY7SinmyCIU2PJ+ygY4FPoBBnLpocMtrQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "^3.977.8", + "@aws-sdk/types": "^3.974.4", + "@smithy/core": "^3.31.1", + "@smithy/types": "^4.16.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-sso": { + "version": "3.973.13", + "resolved": "https://registry.npmmirror.com/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.973.13.tgz", + "integrity": "sha512-Oc81qauMPzUoTnAS2YKpNwY6sY/LUyQTEeaf6yP197WMxkEBQfcKLR1MFpD7+pNTubXnfkH6gwpji+Gc7iyD2Q==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "^3.977.8", + "@aws-sdk/nested-clients": "^3.997.43", + "@aws-sdk/token-providers": "3.1111.0", + "@aws-sdk/types": "^3.974.4", + "@smithy/core": "^3.31.1", + "@smithy/types": "^4.16.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-sso/node_modules/@aws-sdk/token-providers": { + "version": "3.1111.0", + "resolved": "https://registry.npmmirror.com/@aws-sdk/token-providers/-/token-providers-3.1111.0.tgz", + "integrity": "sha512-JfljgoVtl+s3Qy21n9a7Z48uCQaOXcN74KJ3TEQfPoB293GrXFSt6HSQJF1sTZ8c/5QedEvd3NjJQMO4u9qa5A==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "^3.977.8", + "@aws-sdk/nested-clients": "^3.997.43", + "@aws-sdk/types": "^3.974.4", + "@smithy/core": "^3.31.1", + "@smithy/types": "^4.16.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-web-identity": { + "version": "3.972.75", + "resolved": "https://registry.npmmirror.com/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.972.75.tgz", + "integrity": "sha512-YPN6uoGDgjjjeVFZrcOeCJqmB6zpXoeeNgIjqe+DexJaWqdjVfCCe+VAZwli9Z2h8KhFW8oxkO39emQ1tyz/Mw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "^3.977.8", + "@aws-sdk/nested-clients": "^3.997.43", + "@aws-sdk/types": "^3.974.4", + "@smithy/core": "^3.31.1", + "@smithy/types": "^4.16.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/eventstream-handler-node": { + "version": "3.972.33", + "resolved": "https://registry.npmmirror.com/@aws-sdk/eventstream-handler-node/-/eventstream-handler-node-3.972.33.tgz", + "integrity": "sha512-1Dd5WyEE2Kb3HvY44u7Ob16ST2W6iutOqsQ8Y2hUmsL2mAH/STlGS1dS9h3IOE6L7Ld3AR2HzKJ6XeCMOw8Peg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "^3.974.4", + "@smithy/core": "^3.31.1", + "@smithy/types": "^4.16.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/middleware-eventstream": { + "version": "3.972.28", + "resolved": "https://registry.npmmirror.com/@aws-sdk/middleware-eventstream/-/middleware-eventstream-3.972.28.tgz", + "integrity": "sha512-Z1EDXnS01P7H5jVrUx+/dBqV0m7dta7bSxLclkOuDuS93pNNQm0IcT4YLUbuvWKPYNxbI8aTG0p5Br30GSKDgA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "^3.974.4", + "@smithy/core": "^3.31.1", + "@smithy/types": "^4.16.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/middleware-websocket": { + "version": "3.972.51", + "resolved": "https://registry.npmmirror.com/@aws-sdk/middleware-websocket/-/middleware-websocket-3.972.51.tgz", + "integrity": "sha512-jdgP3jR5Q96j1jjZ98GGwpGg1CBNFIO2YE+vXg8cg8PvNY4NvgQNYJsqDaRX2PYv5gSUX/+C0D58Fhspj9ELMQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "^3.977.8", + "@aws-sdk/types": "^3.974.4", + "@smithy/core": "^3.31.1", + "@smithy/fetch-http-handler": "^5.6.13", + "@smithy/signature-v4": "^5.6.12", + "@smithy/types": "^4.16.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@aws-sdk/nested-clients": { + "version": "3.997.43", + "resolved": "https://registry.npmmirror.com/@aws-sdk/nested-clients/-/nested-clients-3.997.43.tgz", + "integrity": "sha512-bit+VpqWNyi3wHxFoTsTliNXimCSL2r2OeDTm7ZrG+YsTZ2D7ofDJ6r/t9PVBn80i6/v0X2h9Tgw6QP2MAKfPw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "^3.977.8", + "@aws-sdk/signature-v4-multi-region": "^3.996.45", + "@aws-sdk/types": "^3.974.4", + "@smithy/core": "^3.31.1", + "@smithy/fetch-http-handler": "^5.6.13", + "@smithy/node-http-handler": "^4.9.13", + "@smithy/types": "^4.16.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/nested-clients/node_modules/@smithy/node-http-handler": { + "version": "4.11.2", + "resolved": "https://registry.npmmirror.com/@smithy/node-http-handler/-/node-http-handler-4.11.2.tgz", + "integrity": "sha512-avwAh9HM3h2lcfjvP3zYIZGf+XVgLQ91wOJ2qoFbNpW1UZeZb33aGlhTZvtkANHfcGhJroRY64525OjfgOg30g==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@smithy/core": "^3.33.2", + "@smithy/types": "^4.17.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/signature-v4-multi-region": { + "version": "3.996.45", + "resolved": "https://registry.npmmirror.com/@aws-sdk/signature-v4-multi-region/-/signature-v4-multi-region-3.996.45.tgz", + "integrity": "sha512-bBuyztukzXq6plzFGHAWiQt0QXo+HL8b8lX5cFTzkez/74PtS1c0qPFCIVuHkyoT+miH2qOjAcm1/yoro2ESPA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "^3.974.4", + "@smithy/signature-v4": "^5.6.12", + "@smithy/types": "^4.16.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/token-providers": { + "version": "3.1048.0", + "resolved": "https://registry.npmmirror.com/@aws-sdk/token-providers/-/token-providers-3.1048.0.tgz", + "integrity": "sha512-k0y/GcuesuSfWyUM0WamrGyeZmltRYaPbHO82UDA6mZ/doB+FOHKutikPAtSXMn/hDz970cF+iRuuiYO9VEbAA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "^3.974.11", + "@aws-sdk/nested-clients": "^3.997.9", + "@aws-sdk/types": "^3.973.8", + "@smithy/core": "^3.24.2", + "@smithy/types": "^4.14.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/types": { + "version": "3.974.4", + "resolved": "https://registry.npmmirror.com/@aws-sdk/types/-/types-3.974.4.tgz", + "integrity": "sha512-dSFDNG00MEz0/xl5gxL62giLd1iYyJsTxZ1I1DOj6lC+bbgLB4TRsYClJg3b62dhXT1uATzsTNXPnC+33EJV3A==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.16.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/util-locate-window": { + "version": "3.965.10", + "resolved": "https://registry.npmmirror.com/@aws-sdk/util-locate-window/-/util-locate-window-3.965.10.tgz", + "integrity": "sha512-ycwH6Zd2GhuSqdXX9ihbCjeGTB6xOJs+O3+Jb8/zDG9978XU80qs75dfkPJRMNKe5MvBZPuNeFpd4JZKPoUF4g==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/xml-builder": { + "version": "3.972.39", + "resolved": "https://registry.npmmirror.com/@aws-sdk/xml-builder/-/xml-builder-3.972.39.tgz", + "integrity": "sha512-FTti8DS5MMWXNUWiRwXAJeYS+0GHHiMy0+7XOhcwk63ILHmfS2UFy2z/HNpZCSOJJ3P3dnWY6hfYNW3DF0nXUA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.16.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws/lambda-invoke-store": { + "version": "0.3.0", + "resolved": "https://registry.npmmirror.com/@aws/lambda-invoke-store/-/lambda-invoke-store-0.3.0.tgz", + "integrity": "sha512-sl4Bm6yiMNYrZKkqqDFWN0UfnWhlS8ivKxrYl+6t0gCLrqr8y3B2IqZZbFRkfaVVp7C/baApyh71P+LeE1A2sQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/code-frame/-/code-frame-7.29.7.tgz", + "integrity": "sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.29.7", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz", + "integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/runtime": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/runtime/-/runtime-7.29.7.tgz", + "integrity": "sha512-Nq8OhGWiZIZGV6hLHoyAKLLcJihP/xFeBMGJoUrxTX2psI8dCifzLhZISFb+VWS3wFMRDmCGw5R+dOySCqPLhw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@deepseek-ai/cordis": { + "version": "4.0.1", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/cordis/-/cordis-4.0.1.tgz", + "integrity": "sha512-YBdskTU2Po1kru3GgcUWUbkTsPMA9LkSQDAY8rBkFJeajdgcQad3QPJZE26JyK99Xb6HaASvoXg2DSUTeN/0Nw==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/cosmokit": "^1.8.2", + "@standard-schema/spec": "^1.1.0" + }, + "bin": { + "cordis": "bin.js" + }, + "peerDependencies": { + "@deepseek-ai/cordis-plugin-include": "^1.0.6", + "@deepseek-ai/cordis-plugin-loader": "^1.0.2" + }, + "peerDependenciesMeta": { + "@deepseek-ai/cordis-plugin-include": { + "optional": true + }, + "@deepseek-ai/cordis-plugin-loader": { + "optional": true + } + } + }, + "node_modules/@deepseek-ai/cordis-plugin-group": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/cordis-plugin-group/-/cordis-plugin-group-1.0.1.tgz", + "integrity": "sha512-E1NThkFB3jn3TCqa6Oc++1zQHqLejF3W2wDwv2BlL3UEmgtBXL1K1j1koc+j676RuiOXtJkUJlPcOntRGKLWBQ==", + "dev": true, + "license": "MIT", + "peer": true, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/cordis-plugin-loader": "^1.0.2" + } + }, + "node_modules/@deepseek-ai/cordis-plugin-hmr": { + "version": "1.0.16", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/cordis-plugin-hmr/-/cordis-plugin-hmr-1.0.16.tgz", + "integrity": "sha512-S7VHfylDg1+Y5O6fdYYZu0KFRAj/snHywcFPnX3KmQYa/qv2Q8IXi4zAt9ABq0BJYqhNoqRlbpGMfIjabgXjKA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.0", + "@deepseek-ai/cosmokit": "^1.8.2", + "@deepseek-ai/schemastery": "^3.18.1", + "chokidar": "^4.0.3", + "picomatch": "^4.0.3" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/cordis-plugin-timer": "^1.1.3" + } + }, + "node_modules/@deepseek-ai/cordis-plugin-include": { + "version": "1.0.6", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/cordis-plugin-include/-/cordis-plugin-include-1.0.6.tgz", + "integrity": "sha512-i1VXrZCbv6tk/iUgedCNjrxxArbWT3IvRZGB5sdqJ3ectnihivXXQbRZ8JJ73DSmAPvlMGmrbtjFAfm10yvXRg==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/cosmokit": "^1.8.2", + "js-yaml": "^4.1.0" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/cordis-plugin-loader": "^1.0.2" + } + }, + "node_modules/@deepseek-ai/cordis-plugin-loader": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/cordis-plugin-loader/-/cordis-plugin-loader-1.0.2.tgz", + "integrity": "sha512-RIW9hoVyhYDWdCI9BsvtZccPde1ECLC4OAxupwowGTak78vwVTVdb3HezTSOK1Y1/Ax3Ru0LA1pYOB04CnTxIQ==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/cosmokit": "^1.8.2" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "node-addon-require-builtin": "^0.1.4" + }, + "peerDependenciesMeta": { + "node-addon-require-builtin": { + "optional": true + } + } + }, + "node_modules/@deepseek-ai/cordis-plugin-timer": { + "version": "1.1.3", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/cordis-plugin-timer/-/cordis-plugin-timer-1.1.3.tgz", + "integrity": "sha512-IOkey1VNmJwYa5U8bksyMOnM7mtirqjjbWLr3xA8QybLMK0sMooG3a6iJwtvd8P3MFwo3FQibEg+JPixp37MEw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/cosmokit": "^1.8.2" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1" + } + }, + "node_modules/@deepseek-ai/cosmokit": { + "version": "1.8.2", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/cosmokit/-/cosmokit-1.8.2.tgz", + "integrity": "sha512-muBOKtSrUKU5m/xpq8ZXWL6hQ/jgd4PhU2PqH97bcxIiLEJfNwZOGQEx4t/aS/GgxRAR+ra9pMHPMtTHU4sqqA==", + "license": "MIT" + }, + "node_modules/@deepseek-ai/dsh": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh/-/dsh-0.1.0-rc.8.tgz", + "integrity": "sha512-VQU5NlomrKLRgcXuOf+sxWFvqxPA8q9vMhrKPlPPXiOJEhGlGlAdiyxZvZxkCVI+v0zbhe21cY3/luLyxpSzzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/cordis-plugin-hmr": "^1.0.16", + "@deepseek-ai/cordis-plugin-include": "^1.0.6", + "@deepseek-ai/cordis-plugin-loader": "^1.0.2", + "@deepseek-ai/cordis-plugin-timer": "^1.1.3", + "@deepseek-ai/dsh-agent-instructions": "^0.1.0-rc.8", + "@deepseek-ai/dsh-agent-tool-presentation": "^0.1.0-rc.8", + "@deepseek-ai/dsh-app-boot": "^0.1.0-rc.8", + "@deepseek-ai/dsh-base": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-ui-agent-preset": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-ui-cordis": "^0.1.0-rc.8", + "@deepseek-ai/dsh-cmdline": "^0.1.0-rc.8", + "@deepseek-ai/dsh-command-compact": "^0.1.0-rc.8", + "@deepseek-ai/dsh-command-goal": "^0.1.0-rc.8", + "@deepseek-ai/dsh-compaction-basic": "^0.1.0-rc.8", + "@deepseek-ai/dsh-compaction-tool-result-pruner": "^0.1.0-rc.8", + "@deepseek-ai/dsh-cordis-client-runner": "^0.1.0-rc.8", + "@deepseek-ai/dsh-fs-local": "^0.1.0-rc.8", + "@deepseek-ai/dsh-goal": "^0.1.0-rc.8", + "@deepseek-ai/dsh-goal-round-driver": "^0.1.0-rc.8", + "@deepseek-ai/dsh-headless": "^0.1.0-rc.8", + "@deepseek-ai/dsh-home-paths": "^0.1.0-rc.8", + "@deepseek-ai/dsh-jobs-local": "^0.1.0-rc.8", + "@deepseek-ai/dsh-launch-environment": "^0.1.0-rc.8", + "@deepseek-ai/dsh-mcp-client": "^0.1.0-rc.8", + "@deepseek-ai/dsh-persona": "^0.1.0-rc.8", + "@deepseek-ai/dsh-plan-mode": "^0.1.0-rc.8", + "@deepseek-ai/dsh-pwsh-local": "^0.1.0-rc.8", + "@deepseek-ai/dsh-pwsh-sandbox": "^0.1.0-rc.8", + "@deepseek-ai/dsh-schedule": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session-projection": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session-reference": "^0.1.0-rc.8", + "@deepseek-ai/dsh-skill": "^0.1.0-rc.8", + "@deepseek-ai/dsh-skill-filesystem": "^0.1.0-rc.8", + "@deepseek-ai/dsh-terminal": "^0.1.0-rc.8", + "@deepseek-ai/dsh-terminal-bash": "^0.1.0-rc.8", + "@deepseek-ai/dsh-time-context": "^0.1.0-rc.8", + "@deepseek-ai/dsh-tmux-context": "^0.1.0-rc.8", + "@deepseek-ai/dsh-token-meter": "^0.1.0-rc.8", + "@deepseek-ai/dsh-tool-ask-user": "^0.1.0-rc.8", + "@deepseek-ai/dsh-tool-bash": "^0.1.0-rc.8", + "@deepseek-ai/dsh-tool-bash-persistent": "^0.1.0-rc.8", + "@deepseek-ai/dsh-tool-cordis": "^0.1.0-rc.8", + "@deepseek-ai/dsh-tool-fs": "^0.1.0-rc.8", + "@deepseek-ai/dsh-tool-fs-search": "^0.1.0-rc.8", + "@deepseek-ai/dsh-tool-goal": "^0.1.0-rc.8", + "@deepseek-ai/dsh-tool-jobs": "^0.1.0-rc.8", + "@deepseek-ai/dsh-tool-pwsh": "^0.1.0-rc.8", + "@deepseek-ai/dsh-tool-pwsh-persistent": "^0.1.0-rc.8", + "@deepseek-ai/dsh-tool-ralph": "^0.1.0-rc.8", + "@deepseek-ai/dsh-tool-skill": "^0.1.0-rc.8", + "@deepseek-ai/dsh-tool-str-replace-editor": "^0.1.0-rc.8", + "@deepseek-ai/dsh-tool-subagent": "^0.1.0-rc.8", + "@deepseek-ai/dsh-tool-subagent-control": "^0.1.0-rc.8", + "@deepseek-ai/dsh-tool-todo": "^0.1.0-rc.8", + "@deepseek-ai/dsh-tool-web": "^0.1.0-rc.8", + "@deepseek-ai/dsh-tool-workflow": "^0.1.0-rc.8", + "@deepseek-ai/dsh-web-app": "^0.1.0-rc.8", + "@deepseek-ai/dsh-workflow-worker-thread": "^0.1.0-rc.8", + "commander": "^15.0.0", + "js-yaml": "^4.2.0", + "node-addon-require-builtin": "^0.1.4" + }, + "bin": { + "dsh": "lib/bin.js" + } + }, + "node_modules/@deepseek-ai/dsh-agent": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-agent/-/dsh-agent-0.1.0-rc.8.tgz", + "integrity": "sha512-fOl46ZvzoYHalrlyfOJAHNhzyKeVDTUnZZKNSJEr9GY/98WJTjcV21agVEofTXldkJ7a/ws2HpJkVNJVFMtslg==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", + "@deepseek-ai/dsh-scope": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session": "^0.1.0-rc.8", + "@deepseek-ai/dsh-system-prompt": "^0.1.0-rc.8", + "@deepseek-ai/dsh-typert-protocol": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-agent-default-model": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-agent-default-model/-/dsh-agent-default-model-0.1.0-rc.8.tgz", + "integrity": "sha512-FSmgVy8yeVYx3krUwfWZR3JokLD202FSuEd/ZfGdxA+BhOKAOfhNv539kujatVqXyzCG3XiRNda7zWxCh2h7/A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", + "@deepseek-ai/dsh-settings": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-agent-instructions": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-agent-instructions/-/dsh-agent-instructions-0.1.0-rc.8.tgz", + "integrity": "sha512-T+JER2gUZbopOxNeHKUE7EfNof30yihsi7GXKB/lOLoy1XMvd5mlzjSHA/OzqjLxiZyyN4V7XAGURApVD3Z7sw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", + "@deepseek-ai/dsh-fs": "^0.1.0-rc.8", + "@deepseek-ai/dsh-home-paths": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session": "^0.1.0-rc.8", + "@deepseek-ai/dsh-tools": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-agent-loop": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-agent-loop/-/dsh-agent-loop-0.1.0-rc.8.tgz", + "integrity": "sha512-6Vg5oLy3UZ6lJKMPxldqqBylKSMOpbV/FRrqzDqn3hGdksYBzt9K2hUJm/rE2RyguYKUKFPm2hExs0nn4HKmWA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", + "@deepseek-ai/dsh-scope": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session-persistence": "^0.1.0-rc.8", + "@deepseek-ai/dsh-settings": "^0.1.0-rc.8", + "@deepseek-ai/dsh-system-prompt": "^0.1.0-rc.8", + "@deepseek-ai/dsh-tools": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-agent-presets": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-agent-presets/-/dsh-agent-presets-0.1.0-rc.8.tgz", + "integrity": "sha512-7h+kE0KDrJCk2Y8GAqF4fu4YqZmFi5U8/AarFkGUqRI3HDugD6oYf05c7ZWNF7lQXh1OmwmrSbuPhT/YXJapOg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1", + "js-yaml": "^4.1.0" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/cordis-plugin-include": "^1.0.6", + "@deepseek-ai/cordis-plugin-loader": "^1.0.2", + "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", + "@deepseek-ai/dsh-atomic-write": "^0.1.0-rc.8", + "@deepseek-ai/dsh-home-paths": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-scope": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session": "^0.1.0-rc.8", + "@deepseek-ai/dsh-settings": "^0.1.0-rc.8", + "@deepseek-ai/dsh-system-prompt": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-agent-tool-presentation": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-agent-tool-presentation/-/dsh-agent-tool-presentation-0.1.0-rc.8.tgz", + "integrity": "sha512-DQouZBh0yjKy8bi0EHQZrZ1B0E+Sc321o5oIyrrmL3hh1sbBsWVrnTvwKPP+SU7J6gnIzyITJ7qEV7pcCGOB2w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-tools": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-anonymous-user-id": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-anonymous-user-id/-/dsh-anonymous-user-id-0.1.0-rc.8.tgz", + "integrity": "sha512-vUESbXtDdqIyelCNqX3ijOfqNfw65iSaJaqzfiqQhmSd9ZrNJ1fPUHl8FoW1BdfK8FjrDyh32R6BtuVpI7Zdhw==", + "dev": true, + "license": "MIT", + "peer": true, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-brand": "^0.1.0-rc.8", + "@deepseek-ai/dsh-home-paths": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-api-gateway": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-api-gateway/-/dsh-api-gateway-0.1.0-rc.8.tgz", + "integrity": "sha512-rNA9+Sq3lXFDmyoFLpXNbcuWg7iFeepCwDi+jt1oGjwZTdZJ2nEWpU6GKlOiqadQjHYzfwEbCqmcuJy32qke/A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-typert-protocol": "^0.1.0-rc.8" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-client-connection": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-typert-registry": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-api-remotes": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-api-remotes/-/dsh-api-remotes-0.1.0-rc.8.tgz", + "integrity": "sha512-s/zmFmU6R+dDxUWbHucIyfVgJG4v8kXa3YRjwjMO+Bu871ZG5Zsht6cvRqeSyu0A/Gs06ZfKYeKE0sdbCZ1NiA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-typert-protocol": "^0.1.0-rc.8" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", + "@deepseek-ai/dsh-agent-presets": "^0.1.0-rc.8", + "@deepseek-ai/dsh-api-gateway": "^0.1.0-rc.8", + "@deepseek-ai/dsh-commands": "^0.1.0-rc.8", + "@deepseek-ai/dsh-cordis-host-runner": "^0.1.0-rc.8", + "@deepseek-ai/dsh-credentials": "^0.1.0-rc.8", + "@deepseek-ai/dsh-file-reference": "^0.1.0-rc.8", + "@deepseek-ai/dsh-goal": "^0.1.0-rc.8", + "@deepseek-ai/dsh-host-plugin-inventory": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", + "@deepseek-ai/dsh-message-feedback": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session-persistence": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session-reference": "^0.1.0-rc.8", + "@deepseek-ai/dsh-settings": "^0.1.0-rc.8", + "@deepseek-ai/dsh-typert-registry": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-app-boot": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-app-boot/-/dsh-app-boot-0.1.0-rc.8.tgz", + "integrity": "sha512-DS63o1PhX2Gvqdgl6Wd8vZnLl0qo8gJ9LpSHXeJBJL9HITpLPhdVYE3X6S0icIYdbGO2plNyhxVJOSN6ibO7VA==", + "dev": true, + "license": "MIT", + "dependencies": { + "js-yaml": "^4.2.0" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/cordis-plugin-group": "^1.0.1", + "@deepseek-ai/cordis-plugin-hmr": "^1.0.16", + "@deepseek-ai/cordis-plugin-include": "^1.0.6", + "@deepseek-ai/cordis-plugin-loader": "^1.0.2", + "@deepseek-ai/dsh-home-paths": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-launch-environment": "^0.1.0-rc.8", + "@deepseek-ai/dsh-system-prompt": "^0.1.0-rc.8" + }, + "peerDependenciesMeta": { + "@deepseek-ai/cordis-plugin-hmr": { + "optional": true + } + } + }, + "node_modules/@deepseek-ai/dsh-atomic-write": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-atomic-write/-/dsh-atomic-write-0.1.0-rc.8.tgz", + "integrity": "sha512-SWP+NAat3oteaPi47zLPz4vxeYCHNVmFpN1aeKDuPHpe/ouNTl+WcyIONAJ+1MbZ+8APWhSaJIVu6ORJEUhVGw==", + "dev": true, + "license": "MIT", + "peer": true, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-attachment": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-attachment/-/dsh-attachment-0.1.0-rc.8.tgz", + "integrity": "sha512-cCrg4WWiav7pGtbdU8dJTpAG28cPnkWVB2YPOrlBCgBbhQziGcG9Dv67Ti6L3PI4OQKC55gYBFinQghFO/7FGg==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-brand": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-attachment-local": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-attachment-local/-/dsh-attachment-local-0.1.0-rc.8.tgz", + "integrity": "sha512-TPsDbDPA8yoE3hw1MtrW61AMh72oMiCY+rkO3bDnvc4MtGwKvXcHWtbNPeVpLgMeznaXsnTU3GUp9Fa6PXdp8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1", + "sharp": "^0.35.3" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-attachment": "^0.1.0-rc.8", + "@deepseek-ai/dsh-home-paths": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-base": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-base/-/dsh-base-0.1.0-rc.8.tgz", + "integrity": "sha512-aMjXT6d5t8SGQg24geOSX6O0ky+hJLijhzZklDcICrBvGSKXvuS8jxLOcL5u4s4pFCODXhuOpvTfFuUhN2RK3Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/cordis-plugin-hmr": "^1.0.16", + "@deepseek-ai/cordis-plugin-timer": "^1.1.3", + "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", + "@deepseek-ai/dsh-agent-default-model": "^0.1.0-rc.8", + "@deepseek-ai/dsh-agent-instructions": "^0.1.0-rc.8", + "@deepseek-ai/dsh-agent-loop": "^0.1.0-rc.8", + "@deepseek-ai/dsh-api-gateway": "^0.1.0-rc.8", + "@deepseek-ai/dsh-attachment-local": "^0.1.0-rc.8", + "@deepseek-ai/dsh-bash-sandbox": "^0.1.0-rc.8", + "@deepseek-ai/dsh-command-compact": "^0.1.0-rc.8", + "@deepseek-ai/dsh-command-feedback": "^0.1.0-rc.8", + "@deepseek-ai/dsh-command-goal": "^0.1.0-rc.8", + "@deepseek-ai/dsh-commands": "^0.1.0-rc.8", + "@deepseek-ai/dsh-compaction-basic": "^0.1.0-rc.8", + "@deepseek-ai/dsh-compaction-tool-result-pruner": "^0.1.0-rc.8", + "@deepseek-ai/dsh-credentials-local": "^0.1.0-rc.8", + "@deepseek-ai/dsh-fs-local": "^0.1.0-rc.8", + "@deepseek-ai/dsh-fs-observation-policy": "^0.1.0-rc.8", + "@deepseek-ai/dsh-fs-sandbox": "^0.1.0-rc.8", + "@deepseek-ai/dsh-goal": "^0.1.0-rc.8", + "@deepseek-ai/dsh-goal-round-driver": "^0.1.0-rc.8", + "@deepseek-ai/dsh-jobs-local": "^0.1.0-rc.8", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", + "@deepseek-ai/dsh-llm-deepseek": "^0.1.0-rc.8", + "@deepseek-ai/dsh-llm-pi-ai": "^0.1.0-rc.8", + "@deepseek-ai/dsh-llm-retry": "^0.1.0-rc.8", + "@deepseek-ai/dsh-permission-presets": "^0.1.0-rc.8", + "@deepseek-ai/dsh-plan-mode": "^0.1.0-rc.8", + "@deepseek-ai/dsh-pwsh-sandbox": "^0.1.0-rc.8", + "@deepseek-ai/dsh-repeat-tool-reminder": "^0.1.0-rc.8", + "@deepseek-ai/dsh-sandbox-local": "^0.1.0-rc.8", + "@deepseek-ai/dsh-sandbox-policy": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session-checkpoint-policy": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session-persistence-jsonl": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session-projection": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session-query-sqlite": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session-telemetry-otel": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session-title": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session-title-first-prompt-llm": "^0.1.0-rc.8", + "@deepseek-ai/dsh-settings-file": "^0.1.0-rc.8", + "@deepseek-ai/dsh-shell-env": "^0.1.0-rc.8", + "@deepseek-ai/dsh-skill": "^0.1.0-rc.8", + "@deepseek-ai/dsh-skill-badge": "^0.1.0-rc.8", + "@deepseek-ai/dsh-skill-filesystem": "^0.1.0-rc.8", + "@deepseek-ai/dsh-spill-local": "^0.1.0-rc.8", + "@deepseek-ai/dsh-spill-policy": "^0.1.0-rc.8", + "@deepseek-ai/dsh-subagent": "^0.1.0-rc.8", + "@deepseek-ai/dsh-subagent-fork-in-process": "^0.1.0-rc.8", + "@deepseek-ai/dsh-subagent-spawn-in-process": "^0.1.0-rc.8", + "@deepseek-ai/dsh-subprocess-local": "^0.1.0-rc.8", + "@deepseek-ai/dsh-system-prompt": "^0.1.0-rc.8", + "@deepseek-ai/dsh-token-meter": "^0.1.0-rc.8", + "@deepseek-ai/dsh-tool-bash": "^0.1.0-rc.8", + "@deepseek-ai/dsh-tool-call-timeout-policy": "^0.1.0-rc.8", + "@deepseek-ai/dsh-tool-fs": "^0.1.0-rc.8", + "@deepseek-ai/dsh-tool-fs-search": "^0.1.0-rc.8", + "@deepseek-ai/dsh-tool-goal": "^0.1.0-rc.8", + "@deepseek-ai/dsh-tool-jobs": "^0.1.0-rc.8", + "@deepseek-ai/dsh-tool-pwsh": "^0.1.0-rc.8", + "@deepseek-ai/dsh-tool-ralph": "^0.1.0-rc.8", + "@deepseek-ai/dsh-tool-skill": "^0.1.0-rc.8", + "@deepseek-ai/dsh-tool-str-replace-editor": "^0.1.0-rc.8", + "@deepseek-ai/dsh-tool-subagent": "^0.1.0-rc.8", + "@deepseek-ai/dsh-tool-subagent-control": "^0.1.0-rc.8", + "@deepseek-ai/dsh-tool-subagent-report": "^0.1.0-rc.8", + "@deepseek-ai/dsh-tool-todo": "^0.1.0-rc.8", + "@deepseek-ai/dsh-tool-web": "^0.1.0-rc.8", + "@deepseek-ai/dsh-tool-workflow": "^0.1.0-rc.8", + "@deepseek-ai/dsh-tools": "^0.1.0-rc.8", + "@deepseek-ai/dsh-typert-loader": "^0.1.0-rc.8", + "@deepseek-ai/dsh-typert-registry": "^0.1.0-rc.8", + "@deepseek-ai/dsh-user-approval": "^0.1.0-rc.8", + "@deepseek-ai/dsh-user-questions": "^0.1.0-rc.8", + "@deepseek-ai/dsh-web": "^0.1.0-rc.8", + "@deepseek-ai/dsh-web-search-deepseek": "^0.1.0-rc.8", + "@deepseek-ai/dsh-workflow-worker-thread": "^0.1.0-rc.8" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-bash-local": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-bash-local/-/dsh-bash-local-0.1.0-rc.8.tgz", + "integrity": "sha512-vMf3dMRrvVvwWCLJxobYONSebPtWqy2ZZKpRZ6o5fBrZbM88irbvL6F/6r/mu4ADTIDigUtpoxlRpOEQKbSuTg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-settings": "^0.1.0-rc.8", + "@deepseek-ai/dsh-shell": "^0.1.0-rc.8", + "@deepseek-ai/dsh-subprocess": "^0.1.0-rc.8", + "@deepseek-ai/dsh-timeout": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-bash-sandbox": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-bash-sandbox/-/dsh-bash-sandbox-0.1.0-rc.8.tgz", + "integrity": "sha512-gCFrmFwYyxjXJsSRrzs5RbvCli0I0Tn9JAJEHCWSskE8x9iCVU7ljtmrKvgRYr0J4YeXwzteNSfNhlJqasu/QQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-bash-local": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-sandbox": "^0.1.0-rc.8", + "@deepseek-ai/dsh-sandbox-policy": "^0.1.0-rc.8", + "@deepseek-ai/dsh-shell": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-brand": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-brand/-/dsh-brand-0.1.0-rc.8.tgz", + "integrity": "sha512-402aUAfHxIZJrArBV4gDf0I/A/69A/By26FX6HTIOyFmCnB4wUBKh8jnglz1CorKWdZy8AKldAhh8HQhQEbGOQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-client-connection": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-client-connection/-/dsh-client-connection-0.1.0-rc.8.tgz", + "integrity": "sha512-O1Y1NmkvJjpR/rCYkzulRrKbFwUbpMlINR4G6fbpGXaLy0VzTqN+ptk0b3wJ4RrnKPi4WWLKNNdV647Fg/1sCw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1", + "ws": "^8.21.0" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-attachment": "^0.1.0-rc.8", + "@deepseek-ai/dsh-commands": "^0.1.0-rc.8", + "@deepseek-ai/dsh-host-apiproxy": "^0.1.0-rc.8", + "@deepseek-ai/dsh-host-webserver": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session": "^0.1.0-rc.8", + "@deepseek-ai/dsh-tools": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-client-hmr": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-client-hmr/-/dsh-client-hmr-0.1.0-rc.8.tgz", + "integrity": "sha512-Olzlpiw+2VIhNOZVEgi22b2U0jSv6HciAQpKj41TggI7oV+jhRDC2GuYFJoRQ8XBs3mcJCLG0DZtAcGrRP8n9Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/cordis-plugin-loader": "^1.0.2", + "@deepseek-ai/dsh-client-modules": "^0.1.0-rc.8", + "@deepseek-ai/dsh-host-webserver": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-client-locale": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-client-locale/-/dsh-client-locale-0.1.0-rc.8.tgz", + "integrity": "sha512-S8ztym/oFU1aWPDtSZLTGWfprUBIuhfOrRNlw/qMAwhavJiQU/Ag0plg19JffGiOMAQuz2BU2n2mW/xhbpA5Vw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-api-remotes": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-connection": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-runtime": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-ui-settings": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-settings": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-client-modules": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-client-modules/-/dsh-client-modules-0.1.0-rc.8.tgz", + "integrity": "sha512-K+uDZSmSbpmHFpvrKkdctHHDIjimv1NWDZoc7CYy7QIk0Vuis4jShDau6H5L0B9TScWBDyXAz/R7rXttFlwseA==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/cordis-plugin-loader": "^1.0.2", + "@deepseek-ai/dsh-host-webserver": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-client-runtime": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-client-runtime/-/dsh-client-runtime-0.1.0-rc.8.tgz", + "integrity": "sha512-wW/nktO/GVbGO/k163NlyJab/rK4D6xS5EL0bhYw4ojF1mxmWfrb3RUEYR5LcEUpFx/yXUHsUSgeO1ezmgIrvw==", + "dev": true, + "license": "MIT", + "dependencies": { + "immer": "^10.1.1", + "zustand": "~4.4.7" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", + "@deepseek-ai/dsh-api-remotes": "^0.1.0-rc.8", + "@deepseek-ai/dsh-attachment": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-connection": "^0.1.0-rc.8", + "@deepseek-ai/dsh-commands": "^0.1.0-rc.8", + "@deepseek-ai/dsh-host-apiproxy": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", + "@deepseek-ai/dsh-llm-retry": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session-projection": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session-title": "^0.1.0-rc.8", + "@deepseek-ai/dsh-tools": "^0.1.0-rc.8", + "@deepseek-ai/dsh-typert-protocol": "^0.1.0-rc.8", + "@deepseek-ai/dsh-typert-registry": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-agent-preset": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-client-ui-agent-preset/-/dsh-client-ui-agent-preset-0.1.0-rc.8.tgz", + "integrity": "sha512-z+okJSOT2/uAA4oomx1WNNl/2k9HsoNDmtewOeQVfSy9C8Ey9YBoVoiSQDsYyDHhesxxlBI8RMLU44Pj/w1uug==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-api-remotes": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-connection": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-locale": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-runtime": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-ui-conversation": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-ui-settings": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-attachment": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-client-ui-attachment/-/dsh-client-ui-attachment-0.1.0-rc.8.tgz", + "integrity": "sha512-TiKZEUGd22AFxkWpgQCLW9VmuSgWQ11RlIQd0941wPAc4RDZxtkjQWDMOlvRS/m8Oqod/5oKr3U6WRCZKS81vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "clsx": "^2.0.0" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-attachment": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-runtime": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-ui-conversation": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-brand-official": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-client-ui-brand-official/-/dsh-client-ui-brand-official-0.1.0-rc.8.tgz", + "integrity": "sha512-eHzJkJGOKlQpap6uYaAZSh62MyJFEoPX8EvIp/kV3YHFDr4bZNc7Yg+ZLMaEXfIjPXKp26FhPiCIia9SP56n8A==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-client-runtime": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-ui-conversation": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-ui-sidebar": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-commands": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-client-ui-commands/-/dsh-client-ui-commands-0.1.0-rc.8.tgz", + "integrity": "sha512-nMDF0MbRM03AEmQJzXCbXQWZxSfVPHBO0z+9DqR6LgGXshYLkzVMp1zkfvqLs5QwFAwDSci4vi/GONJOBSL5WA==", + "dev": true, + "license": "MIT", + "dependencies": { + "clsx": "^2.0.0" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-api-remotes": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-locale": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-runtime": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-ui-conversation": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-ui-input-trigger": "^0.1.0-rc.8", + "@deepseek-ai/dsh-commands": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-conversation": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-client-ui-conversation/-/dsh-client-ui-conversation-0.1.0-rc.8.tgz", + "integrity": "sha512-GnQSE47/goSm1UzxQpYQrQnMJLyTmYFH6NENdrOxrVJxQnB55ruactgM1kVwfFnc/WUQVYy0599AK7pxjbxjMg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1", + "clsx": "^2.0.0" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", + "@deepseek-ai/dsh-api-remotes": "^0.1.0-rc.8", + "@deepseek-ai/dsh-attachment": "^0.1.0-rc.8", + "@deepseek-ai/dsh-brand": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-connection": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-locale": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-runtime": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-ui-input-trigger": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-ui-layout": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-ui-settings": "^0.1.0-rc.8", + "@deepseek-ai/dsh-commands": "^0.1.0-rc.8", + "@deepseek-ai/dsh-compaction": "^0.1.0-rc.8", + "@deepseek-ai/dsh-goal": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-llm-retry": "^0.1.0-rc.8", + "@deepseek-ai/dsh-permission-presets": "^0.1.0-rc.8", + "@deepseek-ai/dsh-plan-mode": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session-stats": "^0.1.0-rc.8", + "@deepseek-ai/dsh-settings": "^0.1.0-rc.8", + "@deepseek-ai/dsh-token-meter": "^0.1.0-rc.8", + "@deepseek-ai/dsh-tool-todo": "^0.1.0-rc.8", + "@deepseek-ai/dsh-tools": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-cordis": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-client-ui-cordis/-/dsh-client-ui-cordis-0.1.0-rc.8.tgz", + "integrity": "sha512-NvaSJxqC+HNPLPYPINHzJGRHI427mHSB2aaTGoyc9EFrYVJjvKpNu1QusWwObae5Y/Tx43I2NpFKTAcNVPXkOw==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-api-remotes": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-connection": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-locale": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-runtime": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-ui-input-trigger": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-ui-sidebar": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-ui-tool": "^0.1.0-rc.8", + "@deepseek-ai/dsh-cordis-client-runner": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-deliverables": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-client-ui-deliverables/-/dsh-client-ui-deliverables-0.1.0-rc.8.tgz", + "integrity": "sha512-b0XZ/V7FPpTTtmHoKNEVOgl9bJGXGqktzMNNJgifHGl/Us1nNnQVDhM9XDbuUV5iXFPnRrKsR29OTnuTB+txZA==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-client-connection": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-locale": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-runtime": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-ui-conversation": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-system-prompt": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-directory-picker-browse": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-client-ui-directory-picker-browse/-/dsh-client-ui-directory-picker-browse-0.1.0-rc.8.tgz", + "integrity": "sha512-sjQcMuut8CRjqnFZHzX1Zzs1zISDlp/gYQVM9Wkyt9KF+XJfV5pHP0KTHZHwOslAqt2OJMnE38uW2yVncLg3sA==", + "dev": true, + "license": "MIT", + "dependencies": { + "clsx": "^2.0.0" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-client-locale": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-runtime": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-ui-workspace": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-directory-picker-native": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-client-ui-directory-picker-native/-/dsh-client-ui-directory-picker-native-0.1.0-rc.8.tgz", + "integrity": "sha512-UPR5kSjfMGjLpO41fXXVxcen9Bq9eCzonStnhqMMk/6zC2EQUDkRs+KhYmaInkHI/CMjdTBBqBPRwjFG2iEsYQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-client-runtime": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-ui-workspace": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-goal": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-client-ui-goal/-/dsh-client-ui-goal-0.1.0-rc.8.tgz", + "integrity": "sha512-kAs6DktlELshs27S3nnjzciK9bGhL2b6RXmZ/mUNYwgiYxeYY4/QYynSNbD0ZQINe0VeGy6yQTv9dbqDBArndA==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-api-remotes": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-locale": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-runtime": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-ui-conversation": "^0.1.0-rc.8", + "@deepseek-ai/dsh-commands": "^0.1.0-rc.8", + "@deepseek-ai/dsh-goal": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session": "^0.1.0-rc.8", + "@deepseek-ai/dsh-typert-protocol": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-input-trigger": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-client-ui-input-trigger/-/dsh-client-ui-input-trigger-0.1.0-rc.8.tgz", + "integrity": "sha512-uVJEZ1ftUdMemLvNf17gzB6ThYw0DL4k+0kcQrUPc6LHNQ2ZeuuvOz/931OlqzzUKMtlAGZgy0LvWyJ62LlSog==", + "dev": true, + "license": "MIT", + "dependencies": { + "clsx": "^2.0.0" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-client-locale": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-runtime": "^0.1.0-rc.8", + "@deepseek-ai/dsh-file-reference": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-jobs": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-client-ui-jobs/-/dsh-client-ui-jobs-0.1.0-rc.8.tgz", + "integrity": "sha512-gCJR9ymswAZa8OiyZQUKa9GpxRT2sP76tfqBGcF5pRN0xOKudlREM6xD3as2knY5EZELW5qQMVKlVVJZ2Uu7fA==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-client-locale": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-runtime": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-ui-conversation": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-layout": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-client-ui-layout/-/dsh-client-ui-layout-0.1.0-rc.8.tgz", + "integrity": "sha512-tbHawbf8FsJqdwnXrU46V8u13bfAFVQQf0hA0OXH4k0PiLiThdZgQFn/T94+56JMUzD1QLqe7DLmNz29cwmjvQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-client-runtime": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-ui-theme": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-message-feedback": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-client-ui-message-feedback/-/dsh-client-ui-message-feedback-0.1.0-rc.8.tgz", + "integrity": "sha512-tzm/vvhysNa3+1BlTnuj3WJit5+u8U1NDecLqMPTm6U1P2s2bjKtvUpmMNqk+AdeYGYcJjXPadLEuWSNsIWFlQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-api-remotes": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-connection": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-locale": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-runtime": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-ui-conversation": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-message-feedback": "^0.1.0-rc.8", + "@deepseek-ai/dsh-typert-protocol": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-model-selection": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-client-ui-model-selection/-/dsh-client-ui-model-selection-0.1.0-rc.8.tgz", + "integrity": "sha512-ODRo7IX4VKkgy6C0ibElP5p1Ek6NBm6Qz6S95cZQH2J+PXWTb57/6UvNfxqyst8nFh1wll4oRb1m4fm6MU/fqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "clsx": "^2.1.1" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-api-remotes": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-connection": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-locale": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-runtime": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-ui-commands": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-ui-conversation": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-ui-input-trigger": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-permission-presets": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-client-ui-permission-presets/-/dsh-client-ui-permission-presets-0.1.0-rc.8.tgz", + "integrity": "sha512-mYF/TX4GVJgRxDYPIk/iQKkGXz8qHkfFJE3GqIw5E27g+Msfg8AEGqfWEPp4CZeIK/3zcgpMLzgjMLOliWZ2dA==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-api-remotes": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-connection": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-locale": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-runtime": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-ui-commands": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-ui-input-trigger": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-ui-settings": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-permission-presets": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-plan": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-client-ui-plan/-/dsh-client-ui-plan-0.1.0-rc.8.tgz", + "integrity": "sha512-OmCuuYCqSlbYqd4s781WipQNKWdHGUn8TPIxrKrcbe94vJacuBtIUIJkDi48dy0IimI+ln/eHxD9WC/9+bJEmA==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-api-remotes": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-locale": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-runtime": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-ui-conversation": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-plan-mode": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-reference": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-client-ui-reference/-/dsh-client-ui-reference-0.1.0-rc.8.tgz", + "integrity": "sha512-9qQYmOqG58qlsYNipOMsrL+Ay5Imx8lHJk9GV1rW++LGl6HMb6V1qZBHGIAwO/KOOInnJSEZE65DYB54r+z1Fw==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-api-remotes": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-locale": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-runtime": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-ui-input-trigger": "^0.1.0-rc.8", + "@deepseek-ai/dsh-file-reference": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session-reference": "^0.1.0-rc.8", + "@deepseek-ai/dsh-typert-protocol": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-renderer": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-client-ui-renderer/-/dsh-client-ui-renderer-0.1.0-rc.8.tgz", + "integrity": "sha512-/MpR9i++feUFNzJgCChLfct1RphTPJ1WKfZrIsczjyOAZNBzAM5LRjpvM0ZO5Vg7rs7id+PLJYuUKy2e2V5aAA==", + "dev": true, + "license": "MIT", + "dependencies": { + "use-sync-external-store": "1.2.0" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-client-runtime": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-settings": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-client-ui-settings/-/dsh-client-ui-settings-0.1.0-rc.8.tgz", + "integrity": "sha512-qSOjpmglOPsLzx6Q5yysrU4c4W6QWFOkyVyqePA5lNPOdny2MH19qbuNleQHbiBo4Zadh/dtBn/SuNRfSp+pjw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-api-remotes": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-connection": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-runtime": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-settings": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-settings-general": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-client-ui-settings-general/-/dsh-client-ui-settings-general-0.1.0-rc.8.tgz", + "integrity": "sha512-lGGLCV17yUhKTHFAL+LWNY6LICLHmL614TbgaTFC80HWqeduURKzHU7a2PoySyMC2AOvYGpKjIRNUfifhv3aZw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1", + "clsx": "^2.0.0" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-api-remotes": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-connection": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-locale": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-runtime": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-ui-settings": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-ui-sidebar": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-settings": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-settings-models": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-client-ui-settings-models/-/dsh-client-ui-settings-models-0.1.0-rc.8.tgz", + "integrity": "sha512-6iTLiQ4+4ErqV2e0Lxeunr1Q0JLFJ3EcJ1KcxvT0mEy5xzZuilX7KJxsBWq11q3Wy/I0MYhbHZzZC+d42mFM4g==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-api-remotes": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-connection": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-locale": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-runtime": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-ui-settings": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-settings-plugin-inventory": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-client-ui-settings-plugin-inventory/-/dsh-client-ui-settings-plugin-inventory-0.1.0-rc.8.tgz", + "integrity": "sha512-IiixKrJbNqn4D8kvpSIRbxsfetEEbYN5Z3Uz209UWLOiY8Ja9VdQaVbh6BZlecO9BXX1Lgo8l8q+tXlC0IpifA==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-api-remotes": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-locale": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-runtime": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-ui-settings": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-settings-plugins": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-client-ui-settings-plugins/-/dsh-client-ui-settings-plugins-0.1.0-rc.8.tgz", + "integrity": "sha512-BLLFFxBz4TmnXXsR5bnQaLMboXBOvCfhoqSbdPFqkqrmJSD+3KGbg4SQJZPcfLL19Kq7qeDraPCXwxo3wpIULg==", + "dev": true, + "license": "MIT", + "dependencies": { + "clsx": "^2.0.0" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-api-remotes": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-connection": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-locale": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-runtime": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-ui-settings": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-sidebar": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-client-ui-sidebar/-/dsh-client-ui-sidebar-0.1.0-rc.8.tgz", + "integrity": "sha512-7wcBnS27j8iIVDuai8BVifxcDZd5DIjlHgNHQKx8xQM+x92VKhiFOoMccjhXNaE6sExCUsER1OWRVp65MJvjqg==", + "dev": true, + "license": "MIT", + "dependencies": { + "clsx": "^2.0.0" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-client-locale": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-runtime": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-ui-layout": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-skill": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-client-ui-skill/-/dsh-client-ui-skill-0.1.0-rc.8.tgz", + "integrity": "sha512-s9tW3tDQ/82TzZcUHC/dZy5zmPppFKbSXnBotQDvjAU+rkS3/4k4Y6u9LffyZ813OjCoCfs7GOfWHAyZ0VmBag==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-api-remotes": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-connection": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-locale": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-runtime": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-ui-input-trigger": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-ui-tool": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-subagent": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-client-ui-subagent/-/dsh-client-ui-subagent-0.1.0-rc.8.tgz", + "integrity": "sha512-uK23jWwzFXbAELsnqS+7A4jL3Q/Ft8AI1hPrJE1ssldq535znexgdGAguZFC17fG+L0OWUtqwAKdXHmjyzqLiQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-client-locale": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-runtime": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-ui-conversation": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-ui-input-trigger": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-subagent": "^0.1.0-rc.8", + "@deepseek-ai/dsh-token-meter": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-theme": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-client-ui-theme/-/dsh-client-ui-theme-0.1.0-rc.8.tgz", + "integrity": "sha512-orLl5eoWOnvjj76lI6xucE+lT+o+ouniRMSFsuYwF1DNH2pbyfVPQYJWL3iM55gE28yyZJGgmtmABnQBiEF5iA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1", + "clsx": "^2.0.0" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-api-remotes": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-connection": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-locale": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-runtime": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-ui-settings": "^0.1.0-rc.8", + "@deepseek-ai/dsh-host-webserver": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-settings": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-tool": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-client-ui-tool/-/dsh-client-ui-tool-0.1.0-rc.8.tgz", + "integrity": "sha512-+Mtgx56PptrtoN4Q36yISe3u0lnVazdqV9s+1cLU2C2sAw7bB7o2Y/J9PBPiuBSsK8rmCLbUPYK6QefenwFE7Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "clsx": "^2.0.0" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-api-remotes": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-connection": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-locale": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-runtime": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-ui-conversation": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-trajectory": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-client-ui-trajectory/-/dsh-client-ui-trajectory-0.1.0-rc.8.tgz", + "integrity": "sha512-nEKtvkbNhk1Qau8jpyvGfcGLCL2Tfmw6Oi72i2oiZ/DHIcsBaeD0JVWOraEmQp3jYVjuuLSdjdCiPkuNU9nwgw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@tanstack/react-virtual": "^3.14.9", + "diff": "^9.0.0" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-locale": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-runtime": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-ui-conversation": "^0.1.0-rc.8", + "@deepseek-ai/dsh-compaction": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-tools": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-trajectory/node_modules/@tanstack/react-virtual": { + "version": "3.14.10", + "resolved": "https://registry.npmmirror.com/@tanstack/react-virtual/-/react-virtual-3.14.10.tgz", + "integrity": "sha512-SRyoUbdFMRHuYXMijV5H4ZarQWpXkj3iANq8OFre+pybeVap8ZJjZ3Nz9bVjx4d8PfobVUQUdKyyyHYk3E+djw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@tanstack/virtual-core": "3.17.8" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-trajectory/node_modules/react": { + "version": "19.2.8", + "resolved": "https://registry.npmmirror.com/react/-/react-19.2.8.tgz", + "integrity": "sha512-PWaYA1L/q9u2u7xYQi+Y3L3Yfnie7XyLeaJICV1MGD6LprsBxcAqGjYyr0eY3p+QdsA+x/Irkt4Qif8D63+Sbw==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-trajectory/node_modules/react-dom": { + "version": "19.2.8", + "resolved": "https://registry.npmmirror.com/react-dom/-/react-dom-19.2.8.tgz", + "integrity": "sha512-rVprimfGBG3DR+Tq0IQG2DT5PxKth1WIGDmj5yPmlzr4YBe7uyE+Du4oVqTDXZSHGGGXRtTJEGSSePyQCMBglQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "scheduler": "^0.27.0" + }, + "peerDependencies": { + "react": "^19.2.8" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-user-questions": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-client-ui-user-questions/-/dsh-client-ui-user-questions-0.1.0-rc.8.tgz", + "integrity": "sha512-zv2U7Ur1ovGSU7j5mwsiCHUK/L20IXRcSFBis3kDZ9nMMl9m0N+56bXrZtJD1U9kTU7gtJ4Xat+rDpr3uTn0JA==", + "dev": true, + "license": "MIT", + "dependencies": { + "clsx": "^2.0.0" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-api-remotes": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-locale": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-runtime": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-ui-conversation": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-workflow-run": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-client-ui-workflow-run/-/dsh-client-ui-workflow-run-0.1.0-rc.8.tgz", + "integrity": "sha512-lVvzaR66JwR2lgdURooLEyinUFu5cSaJLWBgdLetw0Z1B6N4RzBNwiIZxmIEZKwaVS7vhO9w6mphGV+4ujiypA==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-client-locale": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-runtime": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-ui-conversation": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session": "^0.1.0-rc.8", + "@deepseek-ai/dsh-tool-workflow": "^0.1.0-rc.8", + "@deepseek-ai/dsh-workflow": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-workspace": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-client-ui-workspace/-/dsh-client-ui-workspace-0.1.0-rc.8.tgz", + "integrity": "sha512-Il4hRRV9cDXyZptVC/OKHHOPNd84SwtflHCJ6RP97+OYxnENftdKgHENX7Kqf1RsSXF8RwmOtEvZoHljvYD79A==", + "dev": true, + "license": "MIT", + "dependencies": { + "clsx": "^2.0.0" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-client-connection": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-locale": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-runtime": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-ui-conversation": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-ui-sidebar": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-cmdline": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-cmdline/-/dsh-cmdline-0.1.0-rc.8.tgz", + "integrity": "sha512-xsnNFm2XpMD9wpBBLq80x8yXTi664DHywkLwxgAhDsWyp9tB2aSWaWVKxugPWSWwrB3F4nfloWqaeUfgXRFtBQ==", + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/cordis-plugin-loader": "^1.0.2", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-code-runtime": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-code-runtime/-/dsh-code-runtime-0.1.0-rc.8.tgz", + "integrity": "sha512-6ZKyEE7dHH1UkKe5b0lg18Byww/7ocZyrNMVjAoUWEWp5i96Brf9Eavu9q3zepBMDMZJErCfV0pyt7KDhBJSig==", + "dev": true, + "license": "MIT", + "peer": true, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-code-runtime-worker-thread": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-code-runtime-worker-thread/-/dsh-code-runtime-worker-thread-0.1.0-rc.8.tgz", + "integrity": "sha512-l9fsKYZN2qthnR8fbH8LrTbhWman8rjFCumIttahOKvQEjFMWImY1p8ypM3QtreAtUF8jyHdDnlV8xWQLfanmA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-code-runtime": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session": "^0.1.0-rc.8", + "@deepseek-ai/dsh-timeout": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-command-compact": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-command-compact/-/dsh-command-compact-0.1.0-rc.8.tgz", + "integrity": "sha512-3Zlgw9ghDvj2/22/O7V4kvkxKRfknQw4t9ks5GtBEEVRuU9ullpFElAwq/EZ049zeCnmHnyskyJmwYZRIGaiRA==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-commands": "^0.1.0-rc.8", + "@deepseek-ai/dsh-compaction": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-command-feedback": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-command-feedback/-/dsh-command-feedback-0.1.0-rc.8.tgz", + "integrity": "sha512-RqEcutd+nHVGND/JobUybb8HsgRigr5iEowDk0D7aZeXFJ3tN/0pW67w7DOxdhAVnODIpWg5tSnFpCT8fS78kQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-anonymous-user-id": "^0.1.0-rc.8", + "@deepseek-ai/dsh-commands": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session-telemetry": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-command-goal": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-command-goal/-/dsh-command-goal-0.1.0-rc.8.tgz", + "integrity": "sha512-kMjRuGJA79czVNzx//JEMrjAqDvYpiaOSH95NUu+Mome76S34jmnhCnIyzcg02GcXelDbk9epELAz5HR1Yti/Q==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-commands": "^0.1.0-rc.8", + "@deepseek-ai/dsh-goal": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-commands": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-commands/-/dsh-commands-0.1.0-rc.8.tgz", + "integrity": "sha512-/i99EDLrUyd4bUVn4d7XS46vg09ZE0ervbE/aQaVUWLjDYKrarb7hPx9slADAg5/cUlJsN6L6CP544h9qlUo4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "zod": "^4.4.3" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", + "@deepseek-ai/dsh-attachment": "^0.1.0-rc.8", + "@deepseek-ai/dsh-brand": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", + "@deepseek-ai/dsh-scope": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session": "^0.1.0-rc.8", + "@deepseek-ai/dsh-typert-protocol": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-compaction": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-compaction/-/dsh-compaction-0.1.0-rc.8.tgz", + "integrity": "sha512-sWNqZqejzpKsnEMPsNVA/WYK4S59XlYJtnWw8wCPushzQdUt5zhf+g7LVx0cStSozEfwurxRvaZdOmNaa4WhNQ==", + "dev": true, + "license": "MIT", + "peer": true, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-brand": "^0.1.0-rc.8", + "@deepseek-ai/dsh-commands": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-compaction-basic": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-compaction-basic/-/dsh-compaction-basic-0.1.0-rc.8.tgz", + "integrity": "sha512-UWAUbJbxFQTI3m4LnwZDlcYOfzWNFN1WLjy0qNONNcz3BBa5Nu9kcz4C9jioSp6pg3KMfUNUOtbBRySigTIt7g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", + "@deepseek-ai/dsh-commands": "^0.1.0-rc.8", + "@deepseek-ai/dsh-compaction": "^0.1.0-rc.8", + "@deepseek-ai/dsh-compaction-tool-result-pruner": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session": "^0.1.0-rc.8", + "@deepseek-ai/dsh-token-meter": "^0.1.0-rc.8" + }, + "peerDependenciesMeta": { + "@deepseek-ai/dsh-compaction-tool-result-pruner": { + "optional": true + } + } + }, + "node_modules/@deepseek-ai/dsh-compaction-tool-result-pruner": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-compaction-tool-result-pruner/-/dsh-compaction-tool-result-pruner-0.1.0-rc.8.tgz", + "integrity": "sha512-Mk1QE57HxCMScgQ9ury0o7AM14h6g41cDg1G2kiNqD4Z2LBwFTlZJJAgipyhts4mcr1hz2WZTc8Xgbl9067ONA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-compaction": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session": "^0.1.0-rc.8", + "@deepseek-ai/dsh-token-meter": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-cordis-client-runner": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-cordis-client-runner/-/dsh-cordis-client-runner-0.1.0-rc.8.tgz", + "integrity": "sha512-UbV2zFdOCubLAjQkmYi+6aPxxDfFTSshiyL4EHRbZyqQTdhrnDMfkY48SiVz8s026+E8xxGRPU4kNf3lg5DGeA==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/cordis-plugin-loader": "^1.0.2", + "@deepseek-ai/dsh-api-remotes": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-connection": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-modules": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-runtime": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-ui-theme": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-cordis-host-runner": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-cordis-host-runner/-/dsh-cordis-host-runner-0.1.0-rc.8.tgz", + "integrity": "sha512-DCJr6INHCI0Dypr1JAJj/BnvN31tpIt3Y8+KQ3GDfHW6pUBsc9GnXHpKsuQ4sK/fTj80GjaDYPGdWeB/uKMMdw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1", + "zod": "^4.4.3" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", + "@deepseek-ai/dsh-brand": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", + "@deepseek-ai/dsh-scope": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session": "^0.1.0-rc.8", + "@deepseek-ai/dsh-tools": "^0.1.0-rc.8", + "@deepseek-ai/dsh-typert-protocol": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-credentials": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-credentials/-/dsh-credentials-0.1.0-rc.8.tgz", + "integrity": "sha512-VopOhtUEa/fSmJr3fyKbsEG043kX1oGuBrmELAbkhmuDigl1cN88g0VPb9rMG2/dJ1h08wg+h0RJP+Ex4LjRWw==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-brand": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-credentials-local": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-credentials-local/-/dsh-credentials-local-0.1.0-rc.8.tgz", + "integrity": "sha512-Msbz/+xNIHFXLjcDy2hZFpfV1qduuyjLl35BJOUqNz9eCEYv8b0lfKDI7nirv5E/TdxzLkO75WQ4f+8nifeUpQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1", + "chokidar": "^4.0.3", + "yaml": "^2.9.0" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-atomic-write": "^0.1.0-rc.8", + "@deepseek-ai/dsh-credentials": "^0.1.0-rc.8", + "@deepseek-ai/dsh-home-paths": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-launch-environment": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-file-reference": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-file-reference/-/dsh-file-reference-0.1.0-rc.8.tgz", + "integrity": "sha512-SoU4Zm7L8E9ud5nTs1tVAINFrgKvIKypCdOOMLBjJkjLUvXMYmKFxfCM7xaJjOmK/C5suEVUtpukZhZZvZALNA==", + "dev": true, + "license": "MIT", + "dependencies": { + "zod": "^4.4.3" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-typert-protocol": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-file-reference-local": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-file-reference-local/-/dsh-file-reference-local-0.1.0-rc.8.tgz", + "integrity": "sha512-dw3p1NmuDgJkse1J2RuLwgfiySEFiyRL40o3mo1ireGxXt85JfLns1FR2mdN6v7z6pBpIogGPKV//0U31BWTfg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", + "@deepseek-ai/dsh-file-reference": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-system-prompt": "^0.1.0-rc.8", + "@deepseek-ai/dsh-tools": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-fs": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-fs/-/dsh-fs-0.1.0-rc.8.tgz", + "integrity": "sha512-ge5GW56+z20vYACQ2jqtevusdgMXa64laeU/Chql+VIA3+6xyJ8gLX+oj/1O5TlzhvmZ7ZPfZGBFBEVsEZzTQw==", + "dev": true, + "license": "MIT", + "peer": true, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-brand": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", + "@deepseek-ai/dsh-sandbox": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-fs-local": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-fs-local/-/dsh-fs-local-0.1.0-rc.8.tgz", + "integrity": "sha512-yWk6WrAHs8b6395XnZZOCf3wY90xYKjh/tyU3/rwFy4oU8zq9gzn/x8rdaZD0zUp+wE0XqfBf2AS4Jo03SKHyQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1", + "koffi": "^3.1.0" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-fs": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-fs-observation-policy": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-fs-observation-policy/-/dsh-fs-observation-policy-0.1.0-rc.8.tgz", + "integrity": "sha512-iarNlz2QoEROJUOHPjy7OKOwXuGeEhzk6nWj95F+UHNvKKaquagBE8YE1gzFqbg2U1wFVmPGoHBYl8q7hb5Z8Q==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-fs": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-fs-sandbox": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-fs-sandbox/-/dsh-fs-sandbox-0.1.0-rc.8.tgz", + "integrity": "sha512-JfNgZHFyUyqO5XV/KQ2msO9OQ+98WrGCyfQp34yqCbIXSGS2r471C35Sub+OyTlpCkavGFUjsxo3iT7PLGyVVw==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-fs": "^0.1.0-rc.8", + "@deepseek-ai/dsh-fs-local": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-sandbox": "^0.1.0-rc.8", + "@deepseek-ai/dsh-sandbox-policy": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-goal": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-goal/-/dsh-goal-0.1.0-rc.8.tgz", + "integrity": "sha512-PR/9JjRn2H/33eyAVbtYBxzRWQhFO5N0S/188eAV9gjUTtHe5oSOnPxYy8iNkkMXxr+VE8Nno25Sun8WYmS8lQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1", + "zod": "^4.4.3" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", + "@deepseek-ai/dsh-brand": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", + "@deepseek-ai/dsh-scope": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session-projection": "^0.1.0-rc.8", + "@deepseek-ai/dsh-typert-protocol": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-goal-round-driver": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-goal-round-driver/-/dsh-goal-round-driver-0.1.0-rc.8.tgz", + "integrity": "sha512-hCOOofSuqYxWo+Zc/vcF1C+qk38JEgzJ2ya4bBisWYiRwVFygHODquQllK5ffDjFM+SnX+CdmA+l2piiwCkzcA==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", + "@deepseek-ai/dsh-goal": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-headless": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-headless/-/dsh-headless-0.1.0-rc.8.tgz", + "integrity": "sha512-SfjPjyLeno7iScndgFI3s9s8focqXADLNgIxkFbsL0BdAY7v3A6TOe+iSxnYX0fMhDqFC1jT3FVYlEzbJBg0Kg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-cmdline": "^0.1.0-rc.8", + "@deepseek-ai/dsh-code-runtime-worker-thread": "^0.1.0-rc.8", + "@deepseek-ai/schemastery": "^3.18.1", + "commander": "^15.0.0" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/cordis-plugin-loader": "^1.0.2", + "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", + "@deepseek-ai/dsh-agent-default-model": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-home-paths": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-home-paths/-/dsh-home-paths-0.1.0-rc.8.tgz", + "integrity": "sha512-9cQhH9CZsw7Zi73VnZk7CcuEVA6yR/Ox+7lp3VHq53fFYSPi0RL+kMWmh5XCrZB4U1OM3+PVsWsA5II9tB+t0Q==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-host-apiproxy": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-host-apiproxy/-/dsh-host-apiproxy-0.1.0-rc.8.tgz", + "integrity": "sha512-viq2CoS6bRavSe1t9sLjgunykO+Vn/m83uSgONMH8O7QN0Pk3+FnZGHlPZ1lQ4auNJTwQjxFG6w372cGq9usWw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", + "@deepseek-ai/dsh-agent-default-model": "^0.1.0-rc.8", + "@deepseek-ai/dsh-api-remotes": "^0.1.0-rc.8", + "@deepseek-ai/dsh-attachment": "^0.1.0-rc.8", + "@deepseek-ai/dsh-brand": "^0.1.0-rc.8", + "@deepseek-ai/dsh-commands": "^0.1.0-rc.8", + "@deepseek-ai/dsh-credentials": "^0.1.0-rc.8", + "@deepseek-ai/dsh-goal": "^0.1.0-rc.8", + "@deepseek-ai/dsh-host-directory-picker": "^0.1.0-rc.8", + "@deepseek-ai/dsh-jobs": "^0.1.0-rc.8", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", + "@deepseek-ai/dsh-native-command": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session-persistence": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session-projection": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session-projection-cache": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session-query": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session-title": "^0.1.0-rc.8", + "@deepseek-ai/dsh-settings": "^0.1.0-rc.8", + "@deepseek-ai/dsh-skill": "^0.1.0-rc.8", + "@deepseek-ai/dsh-subagent": "^0.1.0-rc.8", + "@deepseek-ai/dsh-tools": "^0.1.0-rc.8", + "@deepseek-ai/dsh-user-approval": "^0.1.0-rc.8", + "@deepseek-ai/dsh-user-questions": "^0.1.0-rc.8", + "@deepseek-ai/dsh-workspace": "^0.1.0-rc.8", + "@deepseek-ai/schemastery": "^3.18.1", + "fflate": "^0.8.2", + "zod": "^4.4.3" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-agent-presets": "^0.1.0-rc.8", + "@deepseek-ai/dsh-cordis-host-runner": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-host-directory-picker": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-host-directory-picker/-/dsh-host-directory-picker-0.1.0-rc.8.tgz", + "integrity": "sha512-aOUaUX0MTl8oLIuL27OkATMm+x2oTANuhhHpeGizn7+kfOX5bRKB3tyi7h6lGZ9O7WDiDLl2JajRqzBXlIPAAg==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-host-directory-picker-auto": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-host-directory-picker-auto/-/dsh-host-directory-picker-auto-0.1.0-rc.8.tgz", + "integrity": "sha512-t6sn3AlcAARVCOgYMNZS/Yneiw+/2mDM6QOGxR6bu5E7DYTT/tllHe0PlHF1Wgh/LtfOTeDtcSPPfXjmrd+Lqw==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/cordis-plugin-loader": "^1.0.2", + "@deepseek-ai/dsh-client-ui-directory-picker-browse": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-ui-directory-picker-native": "^0.1.0-rc.8", + "@deepseek-ai/dsh-host-directory-picker-browse": "^0.1.0-rc.8", + "@deepseek-ai/dsh-host-directory-picker-native": "^0.1.0-rc.8", + "@deepseek-ai/dsh-host-webserver": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-host-directory-picker-browse": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-host-directory-picker-browse/-/dsh-host-directory-picker-browse-0.1.0-rc.8.tgz", + "integrity": "sha512-zEQ7Wnz953GWiR3Y9GaqPGmhntEdjmcD+x6cbYKXWyeOtMHvv7Lu9EWGNneFHXFt50nMinDBT5kyGzElZ+cajA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-host-directory-picker": "^0.1.0-rc.8", + "@deepseek-ai/schemastery": "^3.18.1" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-host-directory-picker-native": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-host-directory-picker-native/-/dsh-host-directory-picker-native-0.1.0-rc.8.tgz", + "integrity": "sha512-WUB4lW+ZmR743uH9LpFK0JrJU88601E7zvevffa93n7Bl4X7C5Y2yhbDK337H8W/brVlLNVgD2Fw2H/nIPZkDg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-host-directory-picker": "^0.1.0-rc.8", + "@deepseek-ai/dsh-native-command": "^0.1.0-rc.8", + "koffi": "^3.1.0" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-host-frontend-static": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-host-frontend-static/-/dsh-host-frontend-static-0.1.0-rc.8.tgz", + "integrity": "sha512-/ef1xAygNL9hyGtSDzJ04nM5WSNzSxsloSUD2MQfM0FU3Y6b/CbHkUNFYaS0MnhS1YVSulDAGRQvXSgES8vZkg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-host-webserver": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-host-plugin-inventory": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-host-plugin-inventory/-/dsh-host-plugin-inventory-0.1.0-rc.8.tgz", + "integrity": "sha512-knPtxCDZn1jbwRfOUnskjaj8hSXUCfBcjD9LPFXnKffsM6TFOeQrFGhkNKlZteXAMSChtY6pV9bpJj17y3SPNg==", + "dev": true, + "license": "MIT", + "dependencies": { + "zod": "^4.4.3" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/cordis-plugin-loader": "^1.0.2", + "@deepseek-ai/dsh-brand": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-typert-protocol": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-host-webserver": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-host-webserver/-/dsh-host-webserver-0.1.0-rc.8.tgz", + "integrity": "sha512-MEKFrhvsYfj970QHLaKPpF/sIBpCe8NuSA0HGiWYJctX6TM9N3rLRhXx5p3zATDmXZclu1rbYhIbsqWw/twPig==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-invariants": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-invariants/-/dsh-invariants-0.1.0-rc.8.tgz", + "integrity": "sha512-u0lYqyxOYwfsVnbsfGXZos5vFvA4cqFnBEW3/ezgljNwkYwzeUP/Y5wjPnQjP+ZzBn3CnVeIF6s2N2Vk3iA5mQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1" + } + }, + "node_modules/@deepseek-ai/dsh-jobs": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-jobs/-/dsh-jobs-0.1.0-rc.8.tgz", + "integrity": "sha512-HqQudOA4VkjCMpxWiqTCMmuiTa/pehW6yG7dDsctO1vW5K48hWQ/h7czdJKgrh4SMuK4kchv3IipS1KaJmdaog==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", + "@deepseek-ai/dsh-brand": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-jobs-local": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-jobs-local/-/dsh-jobs-local-0.1.0-rc.8.tgz", + "integrity": "sha512-8/cr4rYVS2sLB/Z4lL/ERUn14iBqT9T85rJFxxhEKuT3gMcAkiJuKP7t+ZFWPYSSmcNqDPmMI1ExG+GzjxsLVQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-jobs": "^0.1.0-rc.8", + "@deepseek-ai/dsh-scope": "^0.1.0-rc.8", + "@deepseek-ai/dsh-timeout": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-launch-environment": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-launch-environment/-/dsh-launch-environment-0.1.0-rc.8.tgz", + "integrity": "sha512-VvYo5R7tu4QhX/dsNpuBy3AaauizU6yPCeWQUNzI3ZjGA0VHkkZhInilcgxVJkPA1lwEXYB+OoCAo07PUy6D/w==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-llm": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-llm/-/dsh-llm-0.1.0-rc.8.tgz", + "integrity": "sha512-hf6RmX2Stn1UtzpktSHQLkIktQkBm9i/3yFfJlbGSkwyw5Cv9sTYJbyoHzsSnnh6i8nRRcMcBhvMgm23I00oIw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-attachment": "^0.1.0-rc.8", + "@deepseek-ai/dsh-brand": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-timeout": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-llm-deepseek": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-llm-deepseek/-/dsh-llm-deepseek-0.1.0-rc.8.tgz", + "integrity": "sha512-s4LatnGbHwPJhcWGulO/7RsJBPHHBDB+2+1iRTJEn6vYPB0lOSRWtr91qdmAkUxBZmK5mwrf21IbuW+kWwtAZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1", + "eventsource-parser": "^3.1.0" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-anonymous-user-id": "^0.1.0-rc.8", + "@deepseek-ai/dsh-attachment": "^0.1.0-rc.8", + "@deepseek-ai/dsh-credentials": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-launch-environment": "^0.1.0-rc.8", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", + "@deepseek-ai/dsh-settings": "^0.1.0-rc.8", + "@deepseek-ai/dsh-timeout": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-llm-pi-ai": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-llm-pi-ai/-/dsh-llm-pi-ai-0.1.0-rc.8.tgz", + "integrity": "sha512-r9dmHYy759gKtAG0S96wTCS6O8WFDqGLQu8t+zGY6LnfdT4qUJdmWtJ+GwCn+BGwq1AglBzjabvyRBp6BxXcMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1", + "@earendil-works/pi-ai": "^0.82.1" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-attachment": "^0.1.0-rc.8", + "@deepseek-ai/dsh-credentials": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-launch-environment": "^0.1.0-rc.8", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", + "@deepseek-ai/dsh-settings": "^0.1.0-rc.8", + "@deepseek-ai/dsh-timeout": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-llm-retry": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-llm-retry/-/dsh-llm-retry-0.1.0-rc.8.tgz", + "integrity": "sha512-DmcOajgiku5l7aa5hU9DtwnIZu+i/XCGdb+Wego5W9bAswYeBAwbceloRNE3O6+jdRzy+K5U7KQ9V+olBsNqRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", + "@deepseek-ai/dsh-brand": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session": "^0.1.0-rc.8", + "@deepseek-ai/dsh-timeout": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-mcp-client": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-mcp-client/-/dsh-mcp-client-0.1.0-rc.8.tgz", + "integrity": "sha512-pcqXawjq9jRJQNHZTLN7pswJFMWjxCsEOdHUI9BdJqb9lRDsMi2cul1Hizfi51oKkcNo1u/K9Toqgh8o/ScAXg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1", + "@modelcontextprotocol/sdk": "^1.12.0", + "zod": "^4.4.3" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-attachment": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", + "@deepseek-ai/dsh-subprocess": "^0.1.0-rc.8", + "@deepseek-ai/dsh-timeout": "^0.1.0-rc.8", + "@deepseek-ai/dsh-tools": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-message-feedback": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-message-feedback/-/dsh-message-feedback-0.1.0-rc.8.tgz", + "integrity": "sha512-5DYXVLcnvTRs74Att52LGNR+x+RCf1X5s5+gOSUddsjnQ0wn4f3pzfc0o4F+91aE2zX3xzQ3/LhlW5UOJdkB0Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1", + "zod": "^4.4.3" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-brand": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session-persistence": "^0.1.0-rc.8", + "@deepseek-ai/dsh-storage-domain": "^0.1.0-rc.8", + "@deepseek-ai/dsh-typert-protocol": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-native-command": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-native-command/-/dsh-native-command-0.1.0-rc.8.tgz", + "integrity": "sha512-bRaT8LOb2xmWQ88oSzM4+Y3N4Yy4J0tf15/kQTP53PY1FnOA5hGYWoRglQgfxIcJCrw4fEdUPie8Fff0dCOwdQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-output-retention": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-output-retention/-/dsh-output-retention-0.1.0-rc.8.tgz", + "integrity": "sha512-DeVjqZ9TtH2AEG57GBsHYT68274VygzuP9EqQLL01Ht1TrdK75xlVet1l3jdEbA7Eik4aSGDjAZD9/MsnlUIXg==", + "dev": true, + "license": "MIT", + "peer": true, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-permission-presets": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-permission-presets/-/dsh-permission-presets-0.1.0-rc.8.tgz", + "integrity": "sha512-EeTn8Av5kmb1Qj53D7myRnKcNQrrupGrM2m9LVUO8ieWvlIaYX7n2g0y8kg14SUpcD2YzaT40oGJ6VeDuhTZAA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1", + "zod": "^4.4.3" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-commands": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-sandbox": "^0.1.0-rc.8", + "@deepseek-ai/dsh-sandbox-policy": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session-projection": "^0.1.0-rc.8", + "@deepseek-ai/dsh-settings": "^0.1.0-rc.8", + "@deepseek-ai/dsh-shell": "^0.1.0-rc.8", + "@deepseek-ai/dsh-user-approval": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-persona": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-persona/-/dsh-persona-0.1.0-rc.8.tgz", + "integrity": "sha512-3COzIzZ5kBd+txuH418h9HG4feuVFyhdh02HWvzsWgaPsxjatuFS0OfS6qsejUTZrFDODQSr1WIOeSt80bDBtA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-system-prompt": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-plan-mode": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-plan-mode/-/dsh-plan-mode-0.1.0-rc.8.tgz", + "integrity": "sha512-/SY/iil7KLDvveqKRUZxO4HiADwDlOX9u3xyG/93h785mWSfRXooiv4Zp2tiBjU+pJB0tJXMsQNAXDdg7DWtwA==", + "dev": true, + "license": "MIT", + "dependencies": { + "zod": "^4.4.3" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", + "@deepseek-ai/dsh-commands": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session-projection": "^0.1.0-rc.8", + "@deepseek-ai/dsh-system-prompt": "^0.1.0-rc.8", + "@deepseek-ai/dsh-tools": "^0.1.0-rc.8", + "@deepseek-ai/dsh-user-questions": "^0.1.0-rc.8" + }, + "peerDependenciesMeta": { + "@deepseek-ai/dsh-commands": { + "optional": true + } + } + }, + "node_modules/@deepseek-ai/dsh-pwsh-local": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-pwsh-local/-/dsh-pwsh-local-0.1.0-rc.8.tgz", + "integrity": "sha512-lHAEwC4pL5bVSKgwaeO2dMM9s/jnpDBRuTeVD2HkunpFfT1Kq4lFi+/YXj00L7mW9DBP6FMfwRRV/0Wgo1FtdA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-settings": "^0.1.0-rc.8", + "@deepseek-ai/dsh-shell": "^0.1.0-rc.8", + "@deepseek-ai/dsh-subprocess": "^0.1.0-rc.8", + "@deepseek-ai/dsh-timeout": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-pwsh-sandbox": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-pwsh-sandbox/-/dsh-pwsh-sandbox-0.1.0-rc.8.tgz", + "integrity": "sha512-GVvj4zqpC/lwCGaRmIXIhFqOqewgoGOuokGFuv0QcjQUY3v9FnPor2dqDZr5pav8KFGb5GeGUzLoUbedmsWyZg==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-pwsh-local": "^0.1.0-rc.8", + "@deepseek-ai/dsh-sandbox": "^0.1.0-rc.8", + "@deepseek-ai/dsh-sandbox-policy": "^0.1.0-rc.8", + "@deepseek-ai/dsh-shell": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-repeat-tool-reminder": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-repeat-tool-reminder/-/dsh-repeat-tool-reminder-0.1.0-rc.8.tgz", + "integrity": "sha512-p7/g+NH6JJ0BnLx2V5o0hCm4wZr+dXQ9/Ev8LU6YyFRlcnma8TJuATL0wsA01xWfvvGLRxbe/tH41TRS1NVrJg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-tools": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-sandbox": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-sandbox/-/dsh-sandbox-0.1.0-rc.8.tgz", + "integrity": "sha512-dJpy5p/KjKkHG9AnMKU4+/ilj/4DCglsq3kof/jhIwtsZJCix07TEXP9vV8LCv4fU8af7cK3antXw4eVMqkwuQ==", + "dev": true, + "license": "MIT", + "peer": true, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-sandbox-local": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-sandbox-local/-/dsh-sandbox-local-0.1.0-rc.8.tgz", + "integrity": "sha512-sTrKDXD74yG6B24uhCyN9DuGSpX0SCelN4o5DZylKxt56WRRyywAGdLN0Xt8enqiKCxrq+PJBi+hDh2GtXBj6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-sandbox-windows-acl": "^0.1.0-rc.8", + "@deepseek-ai/node-addon-landlock-run": "^0.1.1", + "@deepseek-ai/schemastery": "^3.18.1" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", + "@deepseek-ai/dsh-sandbox": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-sandbox-policy": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-sandbox-policy/-/dsh-sandbox-policy-0.1.0-rc.8.tgz", + "integrity": "sha512-xQOlYWbUr1Oj6cnRd5aHZIz52EOEAdSO1HJIfeDkQrVaOgohFsiiCIp6PNFumuGNWdCEnf4Q18ebafLNtazYlA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-sandbox": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session": "^0.1.0-rc.8", + "@deepseek-ai/dsh-system-prompt": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-sandbox-windows-acl": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-sandbox-windows-acl/-/dsh-sandbox-windows-acl-0.1.0-rc.8.tgz", + "integrity": "sha512-3DeFPD+laUbXrzVpEJ0FrF5pMQCqeu7YCJAWgORGj1aju7sIjpineEnKpE6EXhbc8C9Jqu2y5S7B9z6ydOL/Zg==", + "dev": true, + "license": "MIT", + "dependencies": { + "koffi": "^3.1.0" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-schedule": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-schedule/-/dsh-schedule-0.1.0-rc.8.tgz", + "integrity": "sha512-L4GO1Bv3+SHIXafjGQcf0sJI9eTf9whxVmYlBxYHw7h7StOZJPMhG9HpsKz4mO9FZ7J4zhBtpYlFbhOQaJheqA==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", + "@deepseek-ai/dsh-brand": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session-persistence": "^0.1.0-rc.8", + "@deepseek-ai/dsh-tools": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-scope": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-scope/-/dsh-scope-0.1.0-rc.8.tgz", + "integrity": "sha512-/o+PxkVV2zUy9lYlMFr4TWSb+ESW4DE+fI891yIbsLzOJdFgfbmmLpGrlWgnz8/unIGJZxjeXdwyppV04Z277Q==", + "dev": true, + "license": "MIT", + "peer": true, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-session": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-session/-/dsh-session-0.1.0-rc.8.tgz", + "integrity": "sha512-Qs5Mgn32WPPVB4rKHjsZBgLOkh0TQurUAcc9GaDVudK4dUkpno2HDh++qu/PrwRA3CZ/iwPAoFHCpB3AMMaoLg==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-brand": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", + "@deepseek-ai/dsh-scope": "^0.1.0-rc.8", + "@deepseek-ai/dsh-typert-protocol": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-session-checkpoint-policy": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-session-checkpoint-policy/-/dsh-session-checkpoint-policy-0.1.0-rc.8.tgz", + "integrity": "sha512-9DpZhQN4MExSjbjBSmaH08DmFS/GHRrsVhO5e3WgTVuH13ugdl5yxc4MEb8qvOhEJUUtOx3fXHuMpSTa0Dxa7w==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session-persistence": "^0.1.0-rc.8", + "@deepseek-ai/dsh-tools": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-session-log-export": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-session-log-export/-/dsh-session-log-export-0.1.0-rc.8.tgz", + "integrity": "sha512-6vDC7uH0WZkwmlj/iql6AmSL9Uifiqi28OIZSDIi8/KRHDHnt5hvjobJecuIxhV9hQSDmNsstErHGx4ng2GJFQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-client-locale": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-runtime": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-ui-commands": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-ui-conversation": "^0.1.0-rc.8", + "@deepseek-ai/dsh-commands": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-session-persistence": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-session-persistence/-/dsh-session-persistence-0.1.0-rc.8.tgz", + "integrity": "sha512-JujorG/UCern0+zxJzNswyWl2tFG9sLzfVNvA5YkTLaRLZt7ZsEhxG4DxWZ6uj+3RJ8sf4bqdKqvpIn9t1pwUw==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-brand": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session": "^0.1.0-rc.8", + "@deepseek-ai/dsh-timeout": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-session-persistence-jsonl": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-session-persistence-jsonl/-/dsh-session-persistence-jsonl-0.1.0-rc.8.tgz", + "integrity": "sha512-T/Lvh76O2tpVw04FAhgLF3Qovq3SrUnzaywIbB+Uw67a2DD63Qg+cJY9WO6Pu/UowPxbpuUOd12c6iPY5x8d7Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1", + "koffi": "^3.1.0" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session-persistence": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-session-projection": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-session-projection/-/dsh-session-projection-0.1.0-rc.8.tgz", + "integrity": "sha512-q00B+rl7WAuK0Bgh93SY2+ZpqaH2kJhfJ9n6Jg6R/m4plnH0Ip4oCAHl6u8rBzDgb1mniQGEQDz/7BN5Q3It8Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "zod": "^4.4.3" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-session-projection-cache": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-session-projection-cache/-/dsh-session-projection-cache-0.1.0-rc.8.tgz", + "integrity": "sha512-IPvO7k9FlekOJXn4XLWUwU5+JDQn7khu8Oa04GFDystU3c1CnOwoa7SGMHOfJau3r177M4ncXApwN5Ra6uhyXw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1", + "zod": "^4.4.3" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session-persistence": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session-projection": "^0.1.0-rc.8", + "@deepseek-ai/dsh-storage-domain": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-session-query": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-session-query/-/dsh-session-query-0.1.0-rc.8.tgz", + "integrity": "sha512-q8eyfpgPuJx24l1fEevDkc3Dux3lNp/yDzVkDL4nSTGNaDx/h9Y6iG7SZdqWM5nxOET3iwxi4AkPM7lYyLg3cQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-brand": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session-persistence": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session-title": "^0.1.0-rc.8" + }, + "peerDependenciesMeta": { + "@deepseek-ai/dsh-session-persistence": { + "optional": true + } + } + }, + "node_modules/@deepseek-ai/dsh-session-query-sqlite": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-session-query-sqlite/-/dsh-session-query-sqlite-0.1.0-rc.8.tgz", + "integrity": "sha512-jrNq2vgWIH7OzNMHXrKEjEMwy86I36I94a8X5u937xo2B2JD8ZIWfuWHC9YyLqabRwNf7VcQ6VZ6ruSgESRE7A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session-persistence": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session-query": "^0.1.0-rc.8" + }, + "peerDependenciesMeta": { + "@deepseek-ai/dsh-session-persistence": { + "optional": true + } + } + }, + "node_modules/@deepseek-ai/dsh-session-reference": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-session-reference/-/dsh-session-reference-0.1.0-rc.8.tgz", + "integrity": "sha512-meNS02BOkLc2SnF2qWvl5X1Psk59t0Q1vvwjfCkczD29g4nm7Y02EZ089HJKii0VAsSB39RYA2rf6MCSl6vhow==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1", + "zod": "^4.4.3" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", + "@deepseek-ai/dsh-compaction": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", + "@deepseek-ai/dsh-output-retention": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session-query": "^0.1.0-rc.8", + "@deepseek-ai/dsh-typert-protocol": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-session-stats": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-session-stats/-/dsh-session-stats-0.1.0-rc.8.tgz", + "integrity": "sha512-T+SEzBkMxZpQ31MaeJCjaLN3/xu8yyZ3Va5u6osfq0nsJz1tvuZ53MHMbApdwERHVV0t/1eILTUo1J6XdksUEA==", + "dev": true, + "license": "MIT", + "dependencies": { + "zod": "^4.4.3" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session-projection": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-session-telemetry": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-session-telemetry/-/dsh-session-telemetry-0.1.0-rc.8.tgz", + "integrity": "sha512-Rs7w+PP/uuOaa34RFY4q6Xjes/C32H0gPvZe/gV9M87y1EcJs+mFBzhnc/zyKeaAdT25RWIwO3KATmKlT/D0Dg==", + "dev": true, + "license": "MIT", + "peer": true, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-session-telemetry-otel": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-session-telemetry-otel/-/dsh-session-telemetry-otel-0.1.0-rc.8.tgz", + "integrity": "sha512-rpPwidBwKV53WM2bYW/eYOZ6j5U9VHOIVrITQkQtGDMAzD9UaqfAXfXfUlsw9vsfjED2gKmSf7vn+bVfy8Tjaw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1", + "@opentelemetry/api": "^1.9.1", + "@opentelemetry/api-logs": "^0.220.0", + "@opentelemetry/exporter-logs-otlp-http": "^0.220.0", + "@opentelemetry/otlp-exporter-base": "^0.220.0", + "@opentelemetry/resources": "^2.9.0", + "@opentelemetry/sdk-logs": "^0.220.0" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-anonymous-user-id": "^0.1.0-rc.8", + "@deepseek-ai/dsh-command-feedback": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session-telemetry": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-session-title": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-session-title/-/dsh-session-title-0.1.0-rc.8.tgz", + "integrity": "sha512-OFG9kHFGnM5ND4LCkqg8oZr57qgF6xMkBxR/4MRaJJ42QrPI9QKzoZVRpNpXEl3v3uw8oR7Jj0jbc7WClNl3ow==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1", + "zod": "^4.4.3" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-brand": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session-projection": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-session-title-first-prompt-llm": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-session-title-first-prompt-llm/-/dsh-session-title-first-prompt-llm-0.1.0-rc.8.tgz", + "integrity": "sha512-pFx2hPVYyRCRcbd4WJZVapVekLLEGMAG1KAcrixf3XOGDNaqVEPF8LWatx8iKQRfVSQlvIOwDO8uEsC0NZiPNA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session-title": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session-title-llm": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-session-title-llm": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-session-title-llm/-/dsh-session-title-llm-0.1.0-rc.8.tgz", + "integrity": "sha512-6xz3umGBtGmM+t5O5wwlCwbH9gmBOlQBfg7qGnPJftWc4VWHG7l2VUYqd3DNTQVTHIA/hSN4qg/LXTm79rADGQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session-title": "^0.1.0-rc.8", + "@deepseek-ai/dsh-timeout": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-settings": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-settings/-/dsh-settings-0.1.0-rc.8.tgz", + "integrity": "sha512-pqbMoiSP+Ieww9/4gcHYXcBCDlno1zYDu2OPq+5xdZ+McnK+5YBtHsiRpnR9cHQxGTH7lkfIv+adkOueQW0utg==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-brand": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/schemastery": "^3.18.1" + } + }, + "node_modules/@deepseek-ai/dsh-settings-file": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-settings-file/-/dsh-settings-file-0.1.0-rc.8.tgz", + "integrity": "sha512-2mCyAPkxA5r7Ezgt41XtJxRBsj5Dkl21e5v7w+6YE3C8/n9zRRlN4X5oInHcUKEmgoTrNLCBCgOs5DNrl+pErw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1", + "chokidar": "^4.0.3", + "yaml": "^2.9.0" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-atomic-write": "^0.1.0-rc.8", + "@deepseek-ai/dsh-home-paths": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-settings": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-shell": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-shell/-/dsh-shell-0.1.0-rc.8.tgz", + "integrity": "sha512-RNhp7Y25DXUH7o36X4GcN0lnOLg6NXTlWZpYNURT7aDj3UHcLLajRsyddiAh1EbwQnl0GRKRZhLaZHrrG6gMIw==", + "dev": true, + "license": "MIT", + "peer": true, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-sandbox": "^0.1.0-rc.8", + "@deepseek-ai/dsh-settings": "^0.1.0-rc.8", + "@deepseek-ai/dsh-subprocess": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-shell-env": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-shell-env/-/dsh-shell-env-0.1.0-rc.8.tgz", + "integrity": "sha512-E/Rlka8BnpB7GM67ZJPjvZyp0O9L5x28giyJhHWZcPHN4rsEQFVVqk0cH6iDT5STy+dMc9BAUW+im18kATIxsA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-home-paths": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session-persistence": "^0.1.0-rc.8", + "@deepseek-ai/dsh-shell": "^0.1.0-rc.8", + "@deepseek-ai/dsh-tools": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-skill": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-skill/-/dsh-skill-0.1.0-rc.8.tgz", + "integrity": "sha512-MqcOzl4Y5pQEvFBNVAi5w0IZWH5kVbXmp1RYScrl+8HpVATZbgumDhztVnEc2kUrZu+o6LKb1hnbunK6JHUE5g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", + "@deepseek-ai/dsh-scope": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-skill-badge": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-skill-badge/-/dsh-skill-badge-0.1.0-rc.8.tgz", + "integrity": "sha512-VjISwf5qDpkD+bxLuVXYL7IakhPoZudIOwWCFjTD++Tj8VQTN9ORCq1uCOatFLi5v/an8MzdZ91O2pXfQtb7dQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-skill": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-skill-filesystem": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-skill-filesystem/-/dsh-skill-filesystem-0.1.0-rc.8.tgz", + "integrity": "sha512-A87t/1+wxPiMkUXWVdf4DfgxA8rp1eLmStMvzfdthR/WxtGPzuEv2L5oyNDzKiCBwIcxBN6Fy2THNa2Xba2kQQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1", + "chokidar": "^5.0.0", + "yaml": "^2.4.2" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-fs": "^0.1.0-rc.8", + "@deepseek-ai/dsh-home-paths": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-skill": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-skill-filesystem/node_modules/chokidar": { + "version": "5.0.0", + "resolved": "https://registry.npmmirror.com/chokidar/-/chokidar-5.0.0.tgz", + "integrity": "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==", + "dev": true, + "license": "MIT", + "dependencies": { + "readdirp": "^5.0.0" + }, + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@deepseek-ai/dsh-skill-filesystem/node_modules/readdirp": { + "version": "5.1.1", + "resolved": "https://registry.npmmirror.com/readdirp/-/readdirp-5.1.1.tgz", + "integrity": "sha512-Kko+Y5XQ6fM+Ce3dq3m9YGxnacYZYl9cA1wZjaF3Vbry2L3i1qVg8+CAgNPsXRArPMUMCaOR7oa9Nqntc43JKA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@deepseek-ai/dsh-spill": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-spill/-/dsh-spill-0.1.0-rc.8.tgz", + "integrity": "sha512-LDfyBuRS/yfc+JYvSicEXYJDj5PFBfWN6vJ5G3wy14eMrq3OKoYip8lyIjEdR4qwCVh0s+oSi28AlcvkPuyOdw==", + "dev": true, + "license": "MIT", + "peer": true, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-brand": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-spill-local": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-spill-local/-/dsh-spill-local-0.1.0-rc.8.tgz", + "integrity": "sha512-4Ew3cBOQxW6wA4U8svXCjUyhX00+h0W/bK9CzTy/HoYrNJhP85euJVV7SfNlq6OfTeQBWn3U0wKwNlcc3gAyAg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-spill": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-spill-policy": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-spill-policy/-/dsh-spill-policy-0.1.0-rc.8.tgz", + "integrity": "sha512-9y2IHaKowtqGxhYd59R3OfWv1sonIDv2h9WX/jhxbagMvORfRkhjWJP4YAxp+l4Ba1LhVLcuG/nb2p8hqGdO4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", + "@deepseek-ai/dsh-output-retention": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session": "^0.1.0-rc.8", + "@deepseek-ai/dsh-spill": "^0.1.0-rc.8", + "@deepseek-ai/dsh-tools": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-storage": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-storage/-/dsh-storage-0.1.0-rc.8.tgz", + "integrity": "sha512-KcxiNFAC1X0GhbS9yWGo7FLARBNsxoyU9JatxQtA23MuqOZaN4Nzy3bsMViK4/snzpPGwm//I+wfUywSjM6uBA==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-storage-domain": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-storage-domain/-/dsh-storage-domain-0.1.0-rc.8.tgz", + "integrity": "sha512-rHphQ0jveKoCurwh9TX+VAVFsMQivBgghQBOAsWdVDZ3W6boeXNhMZWuGWZ7WjMPD3iJKgiFCx+650hhsao+LQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1", + "zod": "^4.4.3" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-storage": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-storage-json": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-storage-json/-/dsh-storage-json-0.1.0-rc.8.tgz", + "integrity": "sha512-cTlqy+5bQH7/UOFqRoWSaY9DaaDpcx4jmvWcwY8ciMUBse8BXcEtchVr5zqqss+xA/+Z/l9VraH+diwwRuAWbg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-storage": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-subagent": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-subagent/-/dsh-subagent-0.1.0-rc.8.tgz", + "integrity": "sha512-EI94+hYMfAe8BQkkH/FTcciGxajFfAdQe66Jhy2/eyR3dssRAZ+oJsV6SzU20x3m2yd0gmMaXzO1iV3gwYhY+g==", + "dev": true, + "license": "MIT", + "dependencies": { + "zod": "^4.4.3" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", + "@deepseek-ai/dsh-agent-presets": "^0.1.0-rc.8", + "@deepseek-ai/dsh-brand": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-jobs": "^0.1.0-rc.8", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", + "@deepseek-ai/dsh-sandbox": "^0.1.0-rc.8", + "@deepseek-ai/dsh-sandbox-policy": "^0.1.0-rc.8", + "@deepseek-ai/dsh-scope": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session-persistence": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session-projection": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session-projection-cache": "^0.1.0-rc.8", + "@deepseek-ai/dsh-tools": "^0.1.0-rc.8", + "@deepseek-ai/dsh-user-approval": "^0.1.0-rc.8" + }, + "peerDependenciesMeta": { + "@deepseek-ai/dsh-agent-presets": { + "optional": true + }, + "@deepseek-ai/dsh-jobs": { + "optional": true + }, + "@deepseek-ai/dsh-sandbox": { + "optional": true + }, + "@deepseek-ai/dsh-sandbox-policy": { + "optional": true + }, + "@deepseek-ai/dsh-session-persistence": { + "optional": true + }, + "@deepseek-ai/dsh-session-projection": { + "optional": true + }, + "@deepseek-ai/dsh-session-projection-cache": { + "optional": true + }, + "@deepseek-ai/dsh-user-approval": { + "optional": true + } + } + }, + "node_modules/@deepseek-ai/dsh-subagent-fork-in-process": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-subagent-fork-in-process/-/dsh-subagent-fork-in-process-0.1.0-rc.8.tgz", + "integrity": "sha512-CVen9Fu0TwiwuyTHmZeankN/v0EwdMwOAcq8fSTIyFGPG4ngtqQNSRMxwYTrz39kKyHv0VBW+r8tRd1LBdTAWA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session": "^0.1.0-rc.8", + "@deepseek-ai/dsh-subagent": "^0.1.0-rc.8", + "@deepseek-ai/dsh-subagent-in-process-driver": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-subagent-in-process-driver": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-subagent-in-process-driver/-/dsh-subagent-in-process-driver-0.1.0-rc.8.tgz", + "integrity": "sha512-UJXwh484V/rEmRrvf5l0IWg2ceVOaSOU7Z6DEBq++bKOuFQ2BVkMm+Uj3dk4qFngeb10+/GXlRkbe3mqPwQDSA==", + "dev": true, + "license": "MIT", + "peer": true, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session": "^0.1.0-rc.8", + "@deepseek-ai/dsh-subagent": "^0.1.0-rc.8", + "@deepseek-ai/dsh-system-prompt": "^0.1.0-rc.8", + "@deepseek-ai/dsh-tools": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-subagent-spawn-in-process": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-subagent-spawn-in-process/-/dsh-subagent-spawn-in-process-0.1.0-rc.8.tgz", + "integrity": "sha512-+ZratMZJiNg0vDmaEauJpiNI9IzVwCWisbidow6AV8O5CLC9/XlcMTjFGxmxcbnPdNlVM9i8OLK8gY7/kZ7tTA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-subagent": "^0.1.0-rc.8", + "@deepseek-ai/dsh-subagent-in-process-driver": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-subprocess": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-subprocess/-/dsh-subprocess-0.1.0-rc.8.tgz", + "integrity": "sha512-rTWwWCq/WrBTjaXhApu7gaho6UHwMZq0+l7nZ06YMUreNZoCHfg67pAXopMqTgr/iotphmXQdChrLgBabzL1gA==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-subprocess-local": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-subprocess-local/-/dsh-subprocess-local-0.1.0-rc.8.tgz", + "integrity": "sha512-2QMd6Nwjd+ARor4g+GSZ3dNyTvEf2IPOje47nQwa3UCmltLxn8K8gjDAN/5sGr/IF56P14FeF4xFag7tMK+Zdg==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "koffi": "^3.1.0", + "node-pty": "1.2.0-beta.15" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-subprocess": "^0.1.0-rc.8", + "@deepseek-ai/dsh-timeout": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-system-prompt": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-system-prompt/-/dsh-system-prompt-0.1.0-rc.8.tgz", + "integrity": "sha512-yk8Z85rzX2EwpKNWA5i+K3I3mqsIIUc9niwbDpXO8vlHvpC2qR3RNHjJIJN2EZYDqfSzTVtkbxHFsuMzDXIbew==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", + "@deepseek-ai/dsh-scope": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-terminal": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-terminal/-/dsh-terminal-0.1.0-rc.8.tgz", + "integrity": "sha512-Vu73FrQGx8h7Mqq0QdKtzAiZ3xgVM4fB9wmf3fEl6OiJTcqfc8t4lgug3gE7uBeDVRaLn+aq7kHbEUOY0fsm1Q==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", + "@deepseek-ai/dsh-brand": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-terminal-bash": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-terminal-bash/-/dsh-terminal-bash-0.1.0-rc.8.tgz", + "integrity": "sha512-ehBMVr/0kZ15Vud7uE6PLobukwJi/BqGDbI1oonPPTOoTjDvuCqlKotNEQtS/G4NsvGshEABv+m5X5ELcRCWUA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-pwsh-local": "^0.1.0-rc.8", + "@deepseek-ai/schemastery": "^3.18.1" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-sandbox": "^0.1.0-rc.8", + "@deepseek-ai/dsh-sandbox-policy": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session": "^0.1.0-rc.8", + "@deepseek-ai/dsh-subprocess": "^0.1.0-rc.8", + "@deepseek-ai/dsh-terminal": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-time-context": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-time-context/-/dsh-time-context-0.1.0-rc.8.tgz", + "integrity": "sha512-9Rdse95S6Uk8OAHf78AQN/pxV6+29fCkIbF4ONP/F/6YBciKDORypRyMbHNSY81fBMHQPhW1xvZecGISdIHHiQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-timeout": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-timeout/-/dsh-timeout-0.1.0-rc.8.tgz", + "integrity": "sha512-RwOC/qHribE6b+LStAO7aAgweefLE5sqDO7Uz6/mnTDyJxCt7HNQnE/Op8sAvRa33d752aUkPfO9S0mgzVAoFQ==", + "dev": true, + "license": "MIT", + "peer": true, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-tmux-context": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-tmux-context/-/dsh-tmux-context-0.1.0-rc.8.tgz", + "integrity": "sha512-ezhL3Wjpn4TqqvgSuKrJgNVG7jrWGekEWRYimqD1SvmAHQAS+Xr9q7DBl1uSFfJDWUOAPlAB8VAuo3k/CLUwKA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session": "^0.1.0-rc.8", + "@deepseek-ai/dsh-shell": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-token-meter": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-token-meter/-/dsh-token-meter-0.1.0-rc.8.tgz", + "integrity": "sha512-ZcS6vuuJhoqjUrbyROuiiYk4nrvChkkYEfIoj7CjGbNArWOhbStmBaiPyahtcB1kThcnUKdu7vv7DaZJdLw8Lg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1", + "zod": "^4.4.3" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-compaction": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session-projection": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-tool-ask-user": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-tool-ask-user/-/dsh-tool-ask-user-0.1.0-rc.8.tgz", + "integrity": "sha512-PQVcuvNvTI18B2jSvgS20wX0GRnpom+6X6iNBL/WPLiicJeoxvDYj+M7SjdSsqBNv5t0i9VlYhO4NYicmluy+g==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-tools": "^0.1.0-rc.8", + "@deepseek-ai/dsh-user-questions": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-tool-bash": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-tool-bash/-/dsh-tool-bash-0.1.0-rc.8.tgz", + "integrity": "sha512-VvP8Ky8ifqS7Iy7XUxc6cWB7sse3X6gqr92m0hBuodwQblzrZq2b6IyzfTzXKZKLqt5mMUaLRt7IPIDOOG+WEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-jobs": "^0.1.0-rc.8", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", + "@deepseek-ai/dsh-sandbox": "^0.1.0-rc.8", + "@deepseek-ai/dsh-sandbox-policy": "^0.1.0-rc.8", + "@deepseek-ai/dsh-shell": "^0.1.0-rc.8", + "@deepseek-ai/dsh-shell-env": "^0.1.0-rc.8", + "@deepseek-ai/dsh-system-prompt": "^0.1.0-rc.8", + "@deepseek-ai/dsh-tools": "^0.1.0-rc.8", + "@deepseek-ai/dsh-user-approval": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-tool-bash-persistent": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-tool-bash-persistent/-/dsh-tool-bash-persistent-0.1.0-rc.8.tgz", + "integrity": "sha512-GySj2Nr7y4ewYTH0miD5DzfLEZNxAmWfSyJ5oOYVtzIbqkcU5WOjpsjQvDg0kuERXAq4MYcdc2QfrPet1/MkIQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-terminal": "^0.1.0-rc.8", + "@deepseek-ai/dsh-timeout": "^0.1.0-rc.8", + "@deepseek-ai/dsh-tools": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-tool-call-timeout-policy": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-tool-call-timeout-policy/-/dsh-tool-call-timeout-policy-0.1.0-rc.8.tgz", + "integrity": "sha512-Z6M/nkcz40DisaOIHqUOjjjW4wCi+JqQNoUhOu+VAoBDWHl7SDmEvdWSQUwkyOETjcfdRSG4RTJ5z/rBUVCPHQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", + "@deepseek-ai/dsh-timeout": "^0.1.0-rc.8", + "@deepseek-ai/dsh-tools": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-tool-cordis": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-tool-cordis/-/dsh-tool-cordis-0.1.0-rc.8.tgz", + "integrity": "sha512-bIbkazp5xasqtJBFljOGVIdxyAAWIcKoxMuhDoUpfPFuEqZaXJumYJJ9+ugqr+KKkddjuf2SvlpE5XB4zWcNvg==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", + "@deepseek-ai/dsh-cordis-host-runner": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", + "@deepseek-ai/dsh-scope": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session": "^0.1.0-rc.8", + "@deepseek-ai/dsh-system-prompt": "^0.1.0-rc.8", + "@deepseek-ai/dsh-tools": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-tool-fs": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-tool-fs/-/dsh-tool-fs-0.1.0-rc.8.tgz", + "integrity": "sha512-pxo2YfVlqcw0sCA2+4DtqaaYsuxkx1QfvjT3VO+ckZMWn/UnGOUuzjJtKhVynwjm8prttGqK2LBXUTBZPlKTWg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1", + "diff": "^9.0.0" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-attachment": "^0.1.0-rc.8", + "@deepseek-ai/dsh-fs": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", + "@deepseek-ai/dsh-sandbox": "^0.1.0-rc.8", + "@deepseek-ai/dsh-sandbox-policy": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session": "^0.1.0-rc.8", + "@deepseek-ai/dsh-system-prompt": "^0.1.0-rc.8", + "@deepseek-ai/dsh-tools": "^0.1.0-rc.8", + "@deepseek-ai/dsh-user-approval": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-tool-fs-search": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-tool-fs-search/-/dsh-tool-fs-search-0.1.0-rc.8.tgz", + "integrity": "sha512-AZvESByrPbBIYIGDoTgVOHH48antHy2ZSaLfsVfz1Rw/jQIeiBKwt2LYIPhRGGvev6TXw95qWKt5cyv6WDXHlg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1", + "@vscode/ripgrep": "^1.18.0" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", + "@deepseek-ai/dsh-output-retention": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session": "^0.1.0-rc.8", + "@deepseek-ai/dsh-spill": "^0.1.0-rc.8", + "@deepseek-ai/dsh-subprocess": "^0.1.0-rc.8", + "@deepseek-ai/dsh-system-prompt": "^0.1.0-rc.8", + "@deepseek-ai/dsh-timeout": "^0.1.0-rc.8", + "@deepseek-ai/dsh-tools": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-tool-goal": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-tool-goal/-/dsh-tool-goal-0.1.0-rc.8.tgz", + "integrity": "sha512-EO8iqRV3R8YgdMGUVAp/20XCKbegdwZ7fqr7+oSg11lGHuTnXDz4im4HBXri/wmL9XHeBjmcAQ0BXESbhX2VOQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", + "@deepseek-ai/dsh-goal": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session": "^0.1.0-rc.8", + "@deepseek-ai/dsh-system-prompt": "^0.1.0-rc.8", + "@deepseek-ai/dsh-tools": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-tool-jobs": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-tool-jobs/-/dsh-tool-jobs-0.1.0-rc.8.tgz", + "integrity": "sha512-p3gWi38ryJFRes1lTAdVkdZrUBB8RYPpy4XqZ9DgC2qcrLOJZnnsprIUxyDDmhbyargOgTGc3hEeRU5g8OQAIA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-jobs": "^0.1.0-rc.8", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", + "@deepseek-ai/dsh-output-retention": "^0.1.0-rc.8", + "@deepseek-ai/dsh-system-prompt": "^0.1.0-rc.8", + "@deepseek-ai/dsh-tools": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-tool-pwsh": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-tool-pwsh/-/dsh-tool-pwsh-0.1.0-rc.8.tgz", + "integrity": "sha512-B5F08tsSD7DHqXDXjn/Q11FavHw1U8/WAEqp8AC47vDRymPJIgTM8zSlJ0Lx7aZaKPTW4zQYtSmwUhy93q6zfw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-jobs": "^0.1.0-rc.8", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", + "@deepseek-ai/dsh-sandbox": "^0.1.0-rc.8", + "@deepseek-ai/dsh-sandbox-policy": "^0.1.0-rc.8", + "@deepseek-ai/dsh-shell": "^0.1.0-rc.8", + "@deepseek-ai/dsh-shell-env": "^0.1.0-rc.8", + "@deepseek-ai/dsh-system-prompt": "^0.1.0-rc.8", + "@deepseek-ai/dsh-tools": "^0.1.0-rc.8", + "@deepseek-ai/dsh-user-approval": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-tool-pwsh-persistent": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-tool-pwsh-persistent/-/dsh-tool-pwsh-persistent-0.1.0-rc.8.tgz", + "integrity": "sha512-OxQhywkvUTuGj26yaE1LyoADsCKttaIdiq2dJd+Xcbjc+tnI1gfoVrBj+Sta3/uT7x66kKjXZ1+gnw6gK5qISQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-terminal": "^0.1.0-rc.8", + "@deepseek-ai/dsh-timeout": "^0.1.0-rc.8", + "@deepseek-ai/dsh-tools": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-tool-ralph": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-tool-ralph/-/dsh-tool-ralph-0.1.0-rc.8.tgz", + "integrity": "sha512-+kVCbLEBDxOCCHPdR5+hgQFbkTvTaJ3D7zTNxNEtS5Tr/7eGAU7/VmwNMMSZ4Z+eyHQQEm4vgT+O1pMTvLmb7g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", + "@deepseek-ai/dsh-subagent": "^0.1.0-rc.8", + "@deepseek-ai/dsh-system-prompt": "^0.1.0-rc.8", + "@deepseek-ai/dsh-tools": "^0.1.0-rc.8", + "@deepseek-ai/dsh-workflow": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-tool-skill": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-tool-skill/-/dsh-tool-skill-0.1.0-rc.8.tgz", + "integrity": "sha512-oQAPyXiQDDZ73rZwST7KqwUAr0Al3U1dxWdtzETsMzvNSQE9fmMBz5jUObFIEjxxJcA07Pp1DFzuJdpkCIDeCw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", + "@deepseek-ai/dsh-skill": "^0.1.0-rc.8", + "@deepseek-ai/dsh-tools": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-tool-str-replace-editor": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-tool-str-replace-editor/-/dsh-tool-str-replace-editor-0.1.0-rc.8.tgz", + "integrity": "sha512-2gyO5a5xNvBo9I5vmVSvgXRfxUfKGDu3WjjdK0aDWx/Y+C1r1mGVC7R5mN/oJstcUCIyKm483ux1pT9/O1QD8w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-fs": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-sandbox": "^0.1.0-rc.8", + "@deepseek-ai/dsh-sandbox-policy": "^0.1.0-rc.8", + "@deepseek-ai/dsh-tools": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-tool-subagent": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-tool-subagent/-/dsh-tool-subagent-0.1.0-rc.8.tgz", + "integrity": "sha512-mwNV8M7hsy9+OsSFCluv87FiDHaXO91m83xF/o34Ip9xrgkGs7LOCjvUdCpwjxFTJenWEcvEU90aa7vv3aT/Iw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-jobs": "^0.1.0-rc.8", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", + "@deepseek-ai/dsh-subagent": "^0.1.0-rc.8", + "@deepseek-ai/dsh-system-prompt": "^0.1.0-rc.8", + "@deepseek-ai/dsh-tools": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-tool-subagent-control": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-tool-subagent-control/-/dsh-tool-subagent-control-0.1.0-rc.8.tgz", + "integrity": "sha512-zXF9iIzr96w/S3jNxkRcyV1ouwA1eUCSmvqhlSDkkcA8RH5jt5vWkTia8fwRs1pFS9m7OpbLtvbDxjC8D3nedw==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session": "^0.1.0-rc.8", + "@deepseek-ai/dsh-subagent": "^0.1.0-rc.8", + "@deepseek-ai/dsh-tools": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-tool-subagent-report": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-tool-subagent-report/-/dsh-tool-subagent-report-0.1.0-rc.8.tgz", + "integrity": "sha512-u0CzoSu7O1YyOpGyHfmT/P2hCfnepSzVKrs6MHFrzjbuiRFEcVme6/iLrc7QdLtg484Q1kcnqG2z0OZS24AnWQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", + "@deepseek-ai/dsh-subagent": "^0.1.0-rc.8", + "@deepseek-ai/dsh-system-prompt": "^0.1.0-rc.8", + "@deepseek-ai/dsh-tools": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-tool-todo": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-tool-todo/-/dsh-tool-todo-0.1.0-rc.8.tgz", + "integrity": "sha512-eWxwTeX5WsQPSsz1qyJq+UMiASYB5UHLdObVd4vFLYKbFOoglUK0X+Ie5OjlAkFTP+OzCQMAzUl2gJMwJPWKig==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1", + "zod": "^4.4.3" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session-projection": "^0.1.0-rc.8", + "@deepseek-ai/dsh-tools": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-tool-web": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-tool-web/-/dsh-tool-web-0.1.0-rc.8.tgz", + "integrity": "sha512-MrTkQ2L52A13ysTM94bSW+5sXq3AyVNoo5q3bK47bsl+hg9Kga5gDgGAZ+SGVSQZAUEHXfuYGHaErdUp50bncw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1", + "@joplin/turndown-plugin-gfm": "^1.0.67", + "turndown": "^7.2.4" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", + "@deepseek-ai/dsh-system-prompt": "^0.1.0-rc.8", + "@deepseek-ai/dsh-tools": "^0.1.0-rc.8", + "@deepseek-ai/dsh-web": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-tool-workflow": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-tool-workflow/-/dsh-tool-workflow-0.1.0-rc.8.tgz", + "integrity": "sha512-Z3MCCLM28J/nqiqwHG9roGVUzwMKEADRsSNLPYNemXq5vVEYjm5sBwC+QcWtiQ7NxKXf5ViUu3eKXTe1Fh5TNg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session": "^0.1.0-rc.8", + "@deepseek-ai/dsh-system-prompt": "^0.1.0-rc.8", + "@deepseek-ai/dsh-tools": "^0.1.0-rc.8", + "@deepseek-ai/dsh-workflow": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-tools": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-tools/-/dsh-tools-0.1.0-rc.8.tgz", + "integrity": "sha512-tvuGAVUS4yoPW9zH7CGWJgMlAzGjfu2UlRiricldlcwSKAaJZPZx/K/YfTivUyDTER6aK1DJUnIpVG7RD/DoHQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", + "@deepseek-ai/dsh-code-runtime": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", + "@deepseek-ai/dsh-scope": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session": "^0.1.0-rc.8", + "@deepseek-ai/dsh-system-prompt": "^0.1.0-rc.8", + "@deepseek-ai/dsh-user-approval": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-typert-loader": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-typert-loader/-/dsh-typert-loader-0.1.0-rc.8.tgz", + "integrity": "sha512-IB2Bkv7UglS0y/Dt7buFq87bbUkD/njvuCp4/bRxlbb/8U02b7v18UXnYFoZjCusfzeYxaCBZihImv7aDMBhCA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/cordis-plugin-loader": "^1.0.2", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-typert-registry": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-typert-protocol": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-typert-protocol/-/dsh-typert-protocol-0.1.0-rc.8.tgz", + "integrity": "sha512-scwEAefRBL7gRpaXiEdiHRMvlr8dLmUbiEvy0LOAX/8X3FZBd/5tHQ/8lCppAQNTDZMI/LSiSMpu5XrFId+7cQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-typert-registry": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-typert-registry/-/dsh-typert-registry-0.1.0-rc.8.tgz", + "integrity": "sha512-pxfRE5f1y81h2lNqj0uooYrErTVgpzKfYm4W+ppRafN5s/+1jlLIYWiG3wWD3bnxyoD2NLcTEhi/GXoaqiwdaw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-typert-protocol": "^0.1.0-rc.8", + "zod": "^4.4.3" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-user-approval": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-user-approval/-/dsh-user-approval-0.1.0-rc.8.tgz", + "integrity": "sha512-6SFCxp7dgNFEyzQIcs5i9C+5djgXsAeV0iKmZUCLlcIeVM1chcCMHyGcoXlw8yyB14qFMrMs+TPvhvpu2WWxAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", + "@deepseek-ai/dsh-brand": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", + "@deepseek-ai/dsh-scope": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session": "^0.1.0-rc.8", + "@deepseek-ai/dsh-system-prompt": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-user-questions": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-user-questions/-/dsh-user-questions-0.1.0-rc.8.tgz", + "integrity": "sha512-kiOAlpKKfB89iObWiiVpueD4XCaday203LGUs7+eGb2isolY6VppoGb7ZmcJQqsW63bjbAA7wZeJuN3CoxcvSQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-web": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-web/-/dsh-web-0.1.0-rc.8.tgz", + "integrity": "sha512-YLraDwZTx0Y3Jqw2cu4eClv9ZgEJYoeSFzTe7c9JZ4Z3ThaNCCwEaXWEPMBiPKU6QlR8ahkPPj6xoU9+nPO66g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-web-app": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-web-app/-/dsh-web-app-0.1.0-rc.8.tgz", + "integrity": "sha512-Te/N+AxFmQF2267yMqama5Lp2evsBJeFsqhnEZPfvFhquLBBWgtO5DNZ2cxto5NhGGNNCk/JV25vHRxd7bZl8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-agent-presets": "^0.1.0-rc.8", + "@deepseek-ai/dsh-api-remotes": "^0.1.0-rc.8", + "@deepseek-ai/dsh-app-boot": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-connection": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-hmr": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-locale": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-modules": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-runtime": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-ui-agent-preset": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-ui-attachment": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-ui-brand-official": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-ui-commands": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-ui-conversation": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-ui-cordis": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-ui-deliverables": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-ui-directory-picker-browse": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-ui-directory-picker-native": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-ui-goal": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-ui-input-trigger": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-ui-jobs": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-ui-layout": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-ui-message-feedback": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-ui-model-selection": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-ui-permission-presets": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-ui-plan": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-ui-reference": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-ui-renderer": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-ui-settings": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-ui-settings-general": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-ui-settings-models": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-ui-settings-plugin-inventory": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-ui-settings-plugins": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-ui-sidebar": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-ui-skill": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-ui-subagent": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-ui-theme": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-ui-tool": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-ui-trajectory": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-ui-user-questions": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-ui-workflow-run": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-ui-workspace": "^0.1.0-rc.8", + "@deepseek-ai/dsh-cmdline": "^0.1.0-rc.8", + "@deepseek-ai/dsh-code-runtime-worker-thread": "^0.1.0-rc.8", + "@deepseek-ai/dsh-cordis-client-runner": "^0.1.0-rc.8", + "@deepseek-ai/dsh-cordis-host-runner": "^0.1.0-rc.8", + "@deepseek-ai/dsh-file-reference": "^0.1.0-rc.8", + "@deepseek-ai/dsh-file-reference-local": "^0.1.0-rc.8", + "@deepseek-ai/dsh-host-apiproxy": "^0.1.0-rc.8", + "@deepseek-ai/dsh-host-directory-picker-auto": "^0.1.0-rc.8", + "@deepseek-ai/dsh-host-directory-picker-browse": "^0.1.0-rc.8", + "@deepseek-ai/dsh-host-directory-picker-native": "^0.1.0-rc.8", + "@deepseek-ai/dsh-host-frontend-static": "^0.1.0-rc.8", + "@deepseek-ai/dsh-host-plugin-inventory": "^0.1.0-rc.8", + "@deepseek-ai/dsh-host-webserver": "^0.1.0-rc.8", + "@deepseek-ai/dsh-launch-environment": "^0.1.0-rc.8", + "@deepseek-ai/dsh-message-feedback": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session-log-export": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session-projection-cache": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session-reference": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session-stats": "^0.1.0-rc.8", + "@deepseek-ai/dsh-storage": "^0.1.0-rc.8", + "@deepseek-ai/dsh-storage-domain": "^0.1.0-rc.8", + "@deepseek-ai/dsh-storage-json": "^0.1.0-rc.8", + "@deepseek-ai/dsh-subprocess": "^0.1.0-rc.8", + "@deepseek-ai/dsh-web-frontend": "^0.1.0-rc.8", + "@deepseek-ai/dsh-workspace": "^0.1.0-rc.8", + "@deepseek-ai/schemastery": "^3.18.1", + "commander": "^15.0.0", + "open": "^11.0.0" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/cordis-plugin-loader": "^1.0.2", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-shell-env": "^0.1.0-rc.8", + "@deepseek-ai/dsh-system-prompt": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-web-frontend": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-web-frontend/-/dsh-web-frontend-0.1.0-rc.8.tgz", + "integrity": "sha512-GxWJtkNEniYtSH19XWIJvMO2RSP2bMAZvs3Z6m9cEr9OFbngCY5XCXwqsJMYqOJIao0eSePp/eRCPeXNvqeGXA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@deepseek-ai/dsh-web-search-deepseek": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-web-search-deepseek/-/dsh-web-search-deepseek-0.1.0-rc.8.tgz", + "integrity": "sha512-ifaFw+Cil3yte/9r//3wwMWWPIMuYhvYAB0Hk56IVf+8RDbnRkTJY2foFNNgD91dq1ZL2gBijkdxv1c7wDt+EA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", + "@deepseek-ai/dsh-credentials": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-launch-environment": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session": "^0.1.0-rc.8", + "@deepseek-ai/dsh-settings": "^0.1.0-rc.8", + "@deepseek-ai/dsh-web": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-workflow": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-workflow/-/dsh-workflow-0.1.0-rc.8.tgz", + "integrity": "sha512-a4UJKJAFOPQgVaWegk8MIh8BQjqerkGhHu2+uGF4wyGanzI7FHHY/OUmH4hHTVEx2qFcWh732Od/T8LgL6gcbg==", + "dev": true, + "license": "MIT", + "peer": true, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", + "@deepseek-ai/dsh-brand": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-workflow-worker-thread": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-workflow-worker-thread/-/dsh-workflow-worker-thread-0.1.0-rc.8.tgz", + "integrity": "sha512-QBkHJ8l174U3VqHRi2KyJIFey+Uxzo/OOFbTFx7TP5f761lPvqYiXlILuQJ9QvT7WJTyZO3QRLIIU6ZEBwxTIA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", + "@deepseek-ai/dsh-brand": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session": "^0.1.0-rc.8", + "@deepseek-ai/dsh-subagent": "^0.1.0-rc.8", + "@deepseek-ai/dsh-tools": "^0.1.0-rc.8", + "@deepseek-ai/dsh-workflow": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-workspace": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-workspace/-/dsh-workspace-0.1.0-rc.8.tgz", + "integrity": "sha512-Uyw44WcYvXRQjb0kUstTEJmL83hkGQbWnJzglaGWcAvsZBjQHeBgKuLzOZin1yc/dRX2pKuk1InFwxKXpaHjBA==", + "dev": true, + "license": "MIT", + "dependencies": { + "zod": "^4.4.3" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-brand": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session-persistence": "^0.1.0-rc.8", + "@deepseek-ai/dsh-storage": "^0.1.0-rc.8", + "@deepseek-ai/dsh-storage-domain": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/node-addon-landlock-run": { + "version": "0.1.1", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/node-addon-landlock-run/-/node-addon-landlock-run-0.1.1.tgz", + "integrity": "sha512-aHGhlQJEutfobKM/4K59SERbT7RmQdD2oMKzD8Bne/Ps7TeT8AweCN+dpdfuxQhMNbFcJMymrgPnID0WYQ30Tw==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=20" + }, + "optionalDependencies": { + "@deepseek-ai/node-addon-landlock-run-linux-arm64": "0.1.1", + "@deepseek-ai/node-addon-landlock-run-linux-x64": "0.1.1" + } + }, + "node_modules/@deepseek-ai/node-addon-landlock-run-linux-arm64": { + "version": "0.1.1", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/node-addon-landlock-run-linux-arm64/-/node-addon-landlock-run-linux-arm64-0.1.1.tgz", + "integrity": "sha512-lYY2RbcPW4rGRM5hVJbrXlvLqyBxeJBjBqvt+QTHTU+GtfUVVjTODKa4e3CRwMQoCEpOjoARdQBHbN7HvE72WQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "BSD-3-Clause", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=20" + } + }, + "node_modules/@deepseek-ai/node-addon-landlock-run-linux-x64": { + "version": "0.1.1", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/node-addon-landlock-run-linux-x64/-/node-addon-landlock-run-linux-x64-0.1.1.tgz", + "integrity": "sha512-OHAzPW2Coe/iYobAJAAA8CeVrBoKV4BnNHsgwvXwOfishxkUVSWSvdyxrZPiwYRXutpIGVrSo9zV3WOQy2euBA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "BSD-3-Clause", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=20" + } + }, + "node_modules/@deepseek-ai/schemastery": { + "version": "3.18.1", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/schemastery/-/schemastery-3.18.1.tgz", + "integrity": "sha512-Qn0FCSwCQnpnj6SB31I6i2sIKgKWnkbJM8O0EU91Gv2UsYVvtZTl6IA0sCwk2e2MZf5S8w5hpq9QkeVvK9qwxg==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/cosmokit": "^1.8.2", + "@standard-schema/spec": "^1.1.0" + } + }, + "node_modules/@earendil-works/pi-ai": { + "version": "0.82.1", + "resolved": "https://registry.npmmirror.com/@earendil-works/pi-ai/-/pi-ai-0.82.1.tgz", + "integrity": "sha512-3WFYRhEp3lQB3444EhPMBcM7zSaEUE3eJgHOR7s4081NLqbw/FsWilIKWXSua0Gv3sRr7m9xMidR3pPDE7jI/A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@anthropic-ai/sdk": "0.91.1", + "@aws-sdk/client-bedrock-runtime": "3.1048.0", + "@google/genai": "1.52.0", + "@mistralai/mistralai": "2.2.6", + "@opentelemetry/api": "1.9.0", + "@smithy/node-http-handler": "4.7.3", + "http-proxy-agent": "7.0.2", + "https-proxy-agent": "7.0.6", + "openai": "6.26.0", + "partial-json": "0.1.7", + "typebox": "1.1.38" + }, + "bin": { + "pi-ai": "dist/cli.js" + }, + "engines": { + "node": ">=22.19.0" + } + }, + "node_modules/@earendil-works/pi-ai/node_modules/@opentelemetry/api": { + "version": "1.9.0", + "resolved": "https://registry.npmmirror.com/@opentelemetry/api/-/api-1.9.0.tgz", + "integrity": "sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@emnapi/runtime": { + "version": "1.11.3", + "resolved": "https://registry.npmmirror.com/@emnapi/runtime/-/runtime-1.11.3.tgz", + "integrity": "sha512-Xz4Tpyki7XyrpbUK1jR1AhdAdaXyhhY4lZ3neLodmhpuWfy2PAQN5B46sAiU4liOXGLkHypn/qU+jvfWSCYYLA==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@google/genai": { + "version": "1.52.0", + "resolved": "https://registry.npmmirror.com/@google/genai/-/genai-1.52.0.tgz", + "integrity": "sha512-gwSvbpiN/17O9TbsqSsE/OzZcpv5Fo4RQjdngGgogtuB9RsyJ8ZHhX5KjHj1bp5N9snN2eK8LDGXSaWW2hof8Q==", + "dev": true, + "hasInstallScript": true, + "license": "Apache-2.0", + "dependencies": { + "google-auth-library": "^10.3.0", + "p-retry": "^4.6.2", + "protobufjs": "^7.5.4", + "ws": "^8.18.0" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "@modelcontextprotocol/sdk": "^1.25.2" + }, + "peerDependenciesMeta": { + "@modelcontextprotocol/sdk": { + "optional": true + } + } + }, + "node_modules/@hono/node-server": { + "version": "2.1.1", + "resolved": "https://registry.npmmirror.com/@hono/node-server/-/node-server-2.1.1.tgz", + "integrity": "sha512-ELuehkj5VCBdgEw9zs+ivkKwyzzUCSQuE96YmiPvn1ECBoZCczbFXJLeEGMTYjphP6gydh4pHMqEYPVMYUVgQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20" + }, + "peerDependencies": { + "hono": "^4" + } + }, + "node_modules/@img/colour": { + "version": "1.1.0", + "resolved": "https://registry.npmmirror.com/@img/colour/-/colour-1.1.0.tgz", + "integrity": "sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/@img/sharp-darwin-arm64": { + "version": "0.35.3", + "resolved": "https://registry.npmmirror.com/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.35.3.tgz", + "integrity": "sha512-RMnFX7YQsMoh7lWfcM4NEHHymBX/rLuKNPVM84XE9ONPcaSCDgE7CHIHpSgPcO2xcRthgBy1HfNO319mwhIAkg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-darwin-arm64": "1.3.2" + } + }, + "node_modules/@img/sharp-darwin-x64": { + "version": "0.35.3", + "resolved": "https://registry.npmmirror.com/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.35.3.tgz", + "integrity": "sha512-Xo+5uFBtLN0BKqieTxiFzFPQAUlBbbH5iBKyRX/z1JrbnYsHTfKJnUfL8+p2TPXr1pXqao4eeL4Rl144uDpK9w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-darwin-x64": "1.3.2" + } + }, + "node_modules/@img/sharp-freebsd-wasm32": { + "version": "0.35.3", + "resolved": "https://registry.npmmirror.com/@img/sharp-freebsd-wasm32/-/sharp-freebsd-wasm32-0.35.3.tgz", + "integrity": "sha512-lUxcqWIj2wMQ9BrwNjngcr1gWUr5xgaGThBRqPPalIC2n67Cqj1uPh8NnA/ZhAg8hUbKl+kVHKwgUIwe6ZYPrg==", + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "dependencies": { + "@img/sharp-wasm32": "0.35.3" + }, + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-darwin-arm64": { + "version": "1.3.2", + "resolved": "https://registry.npmmirror.com/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.3.2.tgz", + "integrity": "sha512-9J6ypZFpQBj4YnePGoq/S38w6nz+vqg5WZLrLGY4YuSemdMq47GMLBPO42MzwdGwpg/agZ7xzZcFHa48xlywfg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "darwin" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-darwin-x64": { + "version": "1.3.2", + "resolved": "https://registry.npmmirror.com/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.3.2.tgz", + "integrity": "sha512-m2pW1n6cns9VaubNwsZ+c3CRYjxNQWgJ5gPlnL1nbBcpkBvFm6SCFN5o0psFHI8w9n11NKhFkeEDns98tiqbEw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "darwin" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-arm": { + "version": "1.3.2", + "resolved": "https://registry.npmmirror.com/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.3.2.tgz", + "integrity": "sha512-1eMLzy92I4J6rmi4mAT8yC3HxOtniyGELlzGbNMLLeqe052ahFQ0h6LFq+lh5DsDIdYViIDst08abvSbcEdLXQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-arm64": { + "version": "1.3.2", + "resolved": "https://registry.npmmirror.com/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.3.2.tgz", + "integrity": "sha512-dqVSFynCox4C/J8kT16V7SIFAns0IjgLwkvYT7p8LQVmJ5OS5b6tI9IGflxTeuBS//zXeFIUbwt5dwxyZ17cnA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-ppc64": { + "version": "1.3.2", + "resolved": "https://registry.npmmirror.com/@img/sharp-libvips-linux-ppc64/-/sharp-libvips-linux-ppc64-1.3.2.tgz", + "integrity": "sha512-3z0NHDxD6n5I9gc05U1eW1AyRm+Gznzq3naMrthPNqE6oYykcogW0l/jfpJdjYnuNl8R7yI9pNbE1XiUeyq0Aw==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-riscv64": { + "version": "1.3.2", + "resolved": "https://registry.npmmirror.com/@img/sharp-libvips-linux-riscv64/-/sharp-libvips-linux-riscv64-1.3.2.tgz", + "integrity": "sha512-bsb4rI+NldGOsXuej2r8OdSS8+zXDVaCWxyWrcv6kneTOlgAHtZABRzBBCwdsPiD90J4myNJuHpg6kA20ImW/w==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-s390x": { + "version": "1.3.2", + "resolved": "https://registry.npmmirror.com/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.3.2.tgz", + "integrity": "sha512-/ABshyj8gCpyIrNXnHn4LorDJ0HHm1VhXPBlxZ8zAtfVPAaSafXPGn+sUSIRiwaSBy0mmFjSjiXI5mkcwdChKQ==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-x64": { + "version": "1.3.2", + "resolved": "https://registry.npmmirror.com/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.3.2.tgz", + "integrity": "sha512-ITPEtgffGJ0S6G9dRyw/366tJQqFRcHWPHhC+Stpg3Z8AEMrDrTr2lhdz4f/Y/HMbRh//7Z5mBzEpVdi62Oc3w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linuxmusl-arm64": { + "version": "1.3.2", + "resolved": "https://registry.npmmirror.com/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.3.2.tgz", + "integrity": "sha512-zE9EdiUzUmg5mDT5a1rk5fYJ6GWPloTwWBYDS14naqHsL+EaMpDj1AWnpLgh3u0YCORv2Tt50wrcrpYqkP97Kw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linuxmusl-x64": { + "version": "1.3.2", + "resolved": "https://registry.npmmirror.com/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.3.2.tgz", + "integrity": "sha512-m0lrLiUt+lBYnCFr8qV/65yMR4E/c7/wf78I5eKTdkEakFAlZ9QlzEM3QIhhAwVeUhLAHLcCq7a7Vszq/oFNZQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-linux-arm": { + "version": "0.35.3", + "resolved": "https://registry.npmmirror.com/@img/sharp-linux-arm/-/sharp-linux-arm-0.35.3.tgz", + "integrity": "sha512-affVWCTLooy8TSxbDx2qkzuDeaWLNVBA+P//FNBirHsXpP2fuBhk5AuboYUnrDnzoXes8GFjpTx0SBFOCRg+FA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-arm": "1.3.2" + } + }, + "node_modules/@img/sharp-linux-arm64": { + "version": "0.35.3", + "resolved": "https://registry.npmmirror.com/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.35.3.tgz", + "integrity": "sha512-QgKDspHPnrU+GQ55XPhGwyhC8acLVOOSyAvo1oVfFmrIXLkDNmGWzAfDZ4xK8oSA1qBQrALcHX0G5UZni/SuFQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-arm64": "1.3.2" + } + }, + "node_modules/@img/sharp-linux-ppc64": { + "version": "0.35.3", + "resolved": "https://registry.npmmirror.com/@img/sharp-linux-ppc64/-/sharp-linux-ppc64-0.35.3.tgz", + "integrity": "sha512-sMd8rDxmpLOwv/7N44klFjOD5DUO7FLdjiXDI0hoxYaf7Ar262dQIEkosE98bps+5HPLtp/EvNqeqQtOycP/IA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-ppc64": "1.3.2" + } + }, + "node_modules/@img/sharp-linux-riscv64": { + "version": "0.35.3", + "resolved": "https://registry.npmmirror.com/@img/sharp-linux-riscv64/-/sharp-linux-riscv64-0.35.3.tgz", + "integrity": "sha512-0Eob78yjlYPfL5vMNWAW55l3R9Y6BQS/gOfe0ZcP9mEz9ohhKSt4im1hayiknXgf8AWrFqMvJcKIdmLmEe7yeQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-riscv64": "1.3.2" + } + }, + "node_modules/@img/sharp-linux-s390x": { + "version": "0.35.3", + "resolved": "https://registry.npmmirror.com/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.35.3.tgz", + "integrity": "sha512-KgAxQ0DxpNOq1rG2t5cgTgShJFGSuU7XO45cqC+1NVOuZnP6tlgZRuSYOfNupGkHID0o3cJOsw4DVeJpMovcGw==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-s390x": "1.3.2" + } + }, + "node_modules/@img/sharp-linux-x64": { + "version": "0.35.3", + "resolved": "https://registry.npmmirror.com/@img/sharp-linux-x64/-/sharp-linux-x64-0.35.3.tgz", + "integrity": "sha512-8pqvxubL2PGdhlPy6GLqzDYMUjyRmKAwKHYKixpdJYBUK7PJ0C029XdsnpFIdgRZG68fZiGdHVWcKPvtiPB4cA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-x64": "1.3.2" + } + }, + "node_modules/@img/sharp-linuxmusl-arm64": { + "version": "0.35.3", + "resolved": "https://registry.npmmirror.com/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.35.3.tgz", + "integrity": "sha512-Vz0iQjzzcSX3HCbfwFfCSG/9SCIqyO0mH2sXyiHaAYfBk0cRsCWXRyQYX0ovCK/PAQBbTzQ0dsPQHh5MAFL59w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linuxmusl-arm64": "1.3.2" + } + }, + "node_modules/@img/sharp-linuxmusl-x64": { + "version": "0.35.3", + "resolved": "https://registry.npmmirror.com/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.35.3.tgz", + "integrity": "sha512-6O1NPKcDVj9QEdg7Hx549EX8U0rp6yXQERqru6yRN7fGBn32UvIRJUlWnk+8xDCiG76hXVBbX82NZ/ZKr0euIg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linuxmusl-x64": "1.3.2" + } + }, + "node_modules/@img/sharp-wasm32": { + "version": "0.35.3", + "resolved": "https://registry.npmmirror.com/@img/sharp-wasm32/-/sharp-wasm32-0.35.3.tgz", + "integrity": "sha512-cZ0XkcYGpHZkqW6iCkqTcmUC0CD9DhD5d/qeZlZkfRBn6GnHniZXLUo5+9xw8Iv76YE6LQFN9YNBlKREcCG76w==", + "dev": true, + "license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT", + "optional": true, + "dependencies": { + "@emnapi/runtime": "^1.11.1" + }, + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-webcontainers-wasm32": { + "version": "0.35.3", + "resolved": "https://registry.npmmirror.com/@img/sharp-webcontainers-wasm32/-/sharp-webcontainers-wasm32-0.35.3.tgz", + "integrity": "sha512-2rnq7bX3NzeR2T4YWgz8qiG4h3TSdMe+vN1iQXpJleSJ3SM5zQ8Fy2SyyXAWlbxpEZ2Y+Z4u1BePgJEYbSy80Q==", + "cpu": [ + "wasm32" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "@img/sharp-wasm32": "0.35.3" + }, + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-arm64": { + "version": "0.35.3", + "resolved": "https://registry.npmmirror.com/@img/sharp-win32-arm64/-/sharp-win32-arm64-0.35.3.tgz", + "integrity": "sha512-4bPwFdMbeC4JQ8L8LOyWp6nsHcboP5fxkp6iPOXz2Vg49R42TuMs2whkJ5OAP4/Ul035qOzy0AecOF9VOscn4w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-ia32": { + "version": "0.35.3", + "resolved": "https://registry.npmmirror.com/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.35.3.tgz", + "integrity": "sha512-r53mXsBN6lFUDiST764SvgwUdHAqM4rPAiDzAmf4fLoB6X/rkfyTrLCg6+g17wJJiCmB3JYgHuUldCWUIRFSXw==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-x64": { + "version": "0.35.3", + "resolved": "https://registry.npmmirror.com/@img/sharp-win32-x64/-/sharp-win32-x64-0.35.3.tgz", + "integrity": "sha512-D4y1vNeZrIIJCN+uHaWVtH86B+aCrdMYYjicy9pXHvbGZeGYLLSd3wdVuC37FxVXlU1ARsk84eKWfWMXGYEqvA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@joplin/turndown-plugin-gfm": { + "version": "1.0.67", + "resolved": "https://registry.npmmirror.com/@joplin/turndown-plugin-gfm/-/turndown-plugin-gfm-1.0.67.tgz", + "integrity": "sha512-FZfW5EZfidhzd1IaY1uxHnIZPTVOxAdleMZ4/1U6Nt5b7+Qj5JThDnaIomuJtetnUBzuRNbe9FWMuqD4B3dlWA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@koromix/koffi-darwin-arm64": { + "version": "3.1.5", + "resolved": "https://registry.npmmirror.com/@koromix/koffi-darwin-arm64/-/koffi-darwin-arm64-3.1.5.tgz", + "integrity": "sha512-IpqITl2fJi3QN9bTtNnygWPdK7ScSjw3xtGu8e6feYGvimCysu+spgI5KyeslY2jTnqxGS9xr8pLAbLhGJ8edA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "funding": { + "url": "https://liberapay.com/Koromix" + } + }, + "node_modules/@koromix/koffi-darwin-x64": { + "version": "3.1.5", + "resolved": "https://registry.npmmirror.com/@koromix/koffi-darwin-x64/-/koffi-darwin-x64-3.1.5.tgz", + "integrity": "sha512-4Tia4BS5EV/+vN9eIrdToanVe+U/2VqTZCBgOzoUbPKjgky51eqM+3J4qdRUvmYJohcJNPob5/hsxeItUZrl1g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "funding": { + "url": "https://liberapay.com/Koromix" + } + }, + "node_modules/@koromix/koffi-freebsd-arm64": { + "version": "3.1.5", + "resolved": "https://registry.npmmirror.com/@koromix/koffi-freebsd-arm64/-/koffi-freebsd-arm64-3.1.5.tgz", + "integrity": "sha512-bP94uzseFO79NG3flpU3WxfyvltD+jzC/kN8FDZLi8J0VUZNW1Wmu8yq87KEzjX1qT9KyX4Y+elVbGqHXHTv2Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "funding": { + "url": "https://liberapay.com/Koromix" + } + }, + "node_modules/@koromix/koffi-freebsd-ia32": { + "version": "3.1.5", + "resolved": "https://registry.npmmirror.com/@koromix/koffi-freebsd-ia32/-/koffi-freebsd-ia32-3.1.5.tgz", + "integrity": "sha512-raFXXAPHzvCQWhaoMUF+Cc2ZWgg2UBU0RVoowHZhaw9nQYPC1pERcPRH+JA+SNIN6g4d2GFW6uPFc+QbUhsagA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "funding": { + "url": "https://liberapay.com/Koromix" + } + }, + "node_modules/@koromix/koffi-freebsd-x64": { + "version": "3.1.5", + "resolved": "https://registry.npmmirror.com/@koromix/koffi-freebsd-x64/-/koffi-freebsd-x64-3.1.5.tgz", + "integrity": "sha512-h6RyBZmPMBIDWTABkJIhzDdYwSnYAJvTacHpEjbT55Arkmw1H15Rl7CFtXuEuBrqh+uivoCrRgA6vszl9CsJ9g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "funding": { + "url": "https://liberapay.com/Koromix" + } + }, + "node_modules/@koromix/koffi-linux-arm64": { + "version": "3.1.5", + "resolved": "https://registry.npmmirror.com/@koromix/koffi-linux-arm64/-/koffi-linux-arm64-3.1.5.tgz", + "integrity": "sha512-u0vCmKPu4yQDhl/ri1J6U3vDnvYtYjoZaIWb+oMbRXhVZeiqdE53MGPb+q2A7Dj2n9IbYloAfEICQbL6l0pmiQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://liberapay.com/Koromix" + } + }, + "node_modules/@koromix/koffi-linux-ia32": { + "version": "3.1.5", + "resolved": "https://registry.npmmirror.com/@koromix/koffi-linux-ia32/-/koffi-linux-ia32-3.1.5.tgz", + "integrity": "sha512-Xa5JbumWglwPVZgrJcLhqyC1wCWlfm7+C00p3FuOTNGp0qoYuf2/tOoAh0/q7+taVm30cMopu/6lRHwdmF6I/w==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://liberapay.com/Koromix" + } + }, + "node_modules/@koromix/koffi-linux-loong64": { + "version": "3.1.5", + "resolved": "https://registry.npmmirror.com/@koromix/koffi-linux-loong64/-/koffi-linux-loong64-3.1.5.tgz", + "integrity": "sha512-F3i2CeTcqVBUQiSRUBSEzX1VgtXmLLiZb/ouZtXHkWpTLhJNd9TH7s3CizTofci0VRqlKdexGUYhK5vzPDAAHA==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://liberapay.com/Koromix" + } + }, + "node_modules/@koromix/koffi-linux-riscv64": { + "version": "3.1.5", + "resolved": "https://registry.npmmirror.com/@koromix/koffi-linux-riscv64/-/koffi-linux-riscv64-3.1.5.tgz", + "integrity": "sha512-2TgQuzy+4PfDg+rw3kOmN6lywEWdzKT3eaLPbOp0b/9DaN7CLBJ/QIR5GhGsMNpeI30zU0YzFeYFxoVoJ/LqFw==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://liberapay.com/Koromix" + } + }, + "node_modules/@koromix/koffi-linux-x64": { + "version": "3.1.5", + "resolved": "https://registry.npmmirror.com/@koromix/koffi-linux-x64/-/koffi-linux-x64-3.1.5.tgz", + "integrity": "sha512-2yaIg/1V0m4CiAUMzG4CIlWmq1WJ+QBMlFfaGr9su+OH5fuIqC7V3BbMiB03IwIl1VofIZO5JA4Db4lID8tpbw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://liberapay.com/Koromix" + } + }, + "node_modules/@koromix/koffi-openbsd-ia32": { + "version": "3.1.5", + "resolved": "https://registry.npmmirror.com/@koromix/koffi-openbsd-ia32/-/koffi-openbsd-ia32-3.1.5.tgz", + "integrity": "sha512-8/OXd+u9omMooykhvdJPEP7u6FFzzrrFo9gOmSHc9/DPt3XkVYOtSsE97PDk6zYaAzwIYHSKjHvIXsfFwFc7sg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "funding": { + "url": "https://liberapay.com/Koromix" + } + }, + "node_modules/@koromix/koffi-openbsd-x64": { + "version": "3.1.5", + "resolved": "https://registry.npmmirror.com/@koromix/koffi-openbsd-x64/-/koffi-openbsd-x64-3.1.5.tgz", + "integrity": "sha512-SpeqldKkuDk2aTj5PVWumy7eq6Tr2GtBPAOI1NiDHhg8xe433KraxrA9V9UjEd+1+kSGJQGR04nQByN3MPA9PQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "funding": { + "url": "https://liberapay.com/Koromix" + } + }, + "node_modules/@koromix/koffi-win32-arm64": { + "version": "3.1.5", + "resolved": "https://registry.npmmirror.com/@koromix/koffi-win32-arm64/-/koffi-win32-arm64-3.1.5.tgz", + "integrity": "sha512-uej3YAEKAhlfVPoIo5sOwtxhTLRVJ01LgtWrKGpnnAQU3C+Ilmaxdh+Oc2xc1G3NK30N5eCVJpyO9r3pjKC6Vw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "funding": { + "url": "https://liberapay.com/Koromix" + } + }, + "node_modules/@koromix/koffi-win32-ia32": { + "version": "3.1.5", + "resolved": "https://registry.npmmirror.com/@koromix/koffi-win32-ia32/-/koffi-win32-ia32-3.1.5.tgz", + "integrity": "sha512-d42jv2f4PwtJGNJS19Xfn/BRtGsBNNVkw0O0K5tkIGI+yNq4MnPTSUsaGbDIkCLNsCgk/LFqAaE8BExyCdrujA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "funding": { + "url": "https://liberapay.com/Koromix" + } + }, + "node_modules/@koromix/koffi-win32-x64": { + "version": "3.1.5", + "resolved": "https://registry.npmmirror.com/@koromix/koffi-win32-x64/-/koffi-win32-x64-3.1.5.tgz", + "integrity": "sha512-Pyo1WEHEP6Ek2NEn2pquwJzSPLOdY4vymoPSz0an1DgvFWSkOyBYYkGVoxL1ajfj5I1pPdXysYqixtVTzAtOfQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "funding": { + "url": "https://liberapay.com/Koromix" + } + }, + "node_modules/@mistralai/mistralai": { + "version": "2.2.6", + "resolved": "https://registry.npmmirror.com/@mistralai/mistralai/-/mistralai-2.2.6.tgz", + "integrity": "sha512-W8pX7zHxjJvMIpw8JMxeJEleapXX0Q9NPszdNzqkM3MIEoIGPObdodujj+WHteXEvGfaP/AMwlNyRfEzSY6dQQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/semantic-conventions": "^1.40.0", + "ws": "^8.18.0", + "zod": "^3.25.0 || ^4.0.0", + "zod-to-json-schema": "^3.25.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.9.0" + }, + "peerDependenciesMeta": { + "@opentelemetry/api": { + "optional": true + } + } + }, + "node_modules/@mixmark-io/domino": { + "version": "2.2.0", + "resolved": "https://registry.npmmirror.com/@mixmark-io/domino/-/domino-2.2.0.tgz", + "integrity": "sha512-Y28PR25bHXUg88kCV7nivXrP2Nj2RueZ3/l/jdx6J9f8J4nsEGcgX0Qe6lt7Pa+J79+kPiJU3LguR6O/6zrLOw==", + "dev": true, + "license": "BSD-2-Clause" + }, + "node_modules/@modelcontextprotocol/sdk": { + "version": "1.30.0", + "resolved": "https://registry.npmmirror.com/@modelcontextprotocol/sdk/-/sdk-1.30.0.tgz", + "integrity": "sha512-xKd8OIzlqNzcqcNumGAa6g+PW2kjD5vrpcKOnfldAUPP3j7lnqMPwlTXQm8gF+UwH72z0lqaRbjr9hqGz0eITA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@hono/node-server": "^1.19.9 || ^2.0.5", + "ajv": "^8.17.1", + "ajv-formats": "^3.0.1", + "content-type": "^1.0.5", + "cors": "^2.8.5", + "cross-spawn": "^7.0.5", + "eventsource": "^3.0.2", + "eventsource-parser": "^3.0.0", + "express": "^5.2.1", + "express-rate-limit": "^8.2.1", + "hono": "^4.11.4", + "jose": "^6.1.3", + "json-schema-typed": "^8.0.2", + "pkce-challenge": "^5.0.0", + "raw-body": "^3.0.0", + "zod": "^3.25 || ^4.0", + "zod-to-json-schema": "^3.25.1" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@cfworker/json-schema": "^4.1.1", + "zod": "^3.25 || ^4.0" + }, + "peerDependenciesMeta": { + "@cfworker/json-schema": { + "optional": true + }, + "zod": { + "optional": false + } + } + }, + "node_modules/@opentelemetry/api": { + "version": "1.9.1", + "resolved": "https://registry.npmmirror.com/@opentelemetry/api/-/api-1.9.1.tgz", + "integrity": "sha512-gLyJlPHPZYdAk1JENA9LeHejZe1Ti77/pTeFm/nMXmQH/HFZlcS/O2XJB+L8fkbrNSqhdtlvjBVjxwUYanNH5Q==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@opentelemetry/api-logs": { + "version": "0.220.0", + "resolved": "https://registry.npmmirror.com/@opentelemetry/api-logs/-/api-logs-0.220.0.tgz", + "integrity": "sha512-CmVa4ImJ+ynfrPMNaAXHET6Bhb44SwzmfyVJFq9ni2jgXJR/l7C6gfVFddNmHP+ZOkP9cf4f9DBe68qVLTHc9w==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/api": "^1.3.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@opentelemetry/core": { + "version": "2.9.0", + "resolved": "https://registry.npmmirror.com/@opentelemetry/core/-/core-2.9.0.tgz", + "integrity": "sha512-m2nckMT80NnmjTYSPjJQObBJ+8dgkoajEOUbznL8AHZ3T3yHRk2P7gI1PhEBc1+lOnrYE9UWrWHqJDsmqjmNbw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/exporter-logs-otlp-http": { + "version": "0.220.0", + "resolved": "https://registry.npmmirror.com/@opentelemetry/exporter-logs-otlp-http/-/exporter-logs-otlp-http-0.220.0.tgz", + "integrity": "sha512-8186thl+pTw64iz/qEEen5oJZoZ/gO73XruChdaGlYdWOdBIQ42r+vHLf6a7vIDqTD4b8ZOoMlyxptanECaI9A==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/api-logs": "0.220.0", + "@opentelemetry/core": "2.9.0", + "@opentelemetry/otlp-exporter-base": "0.220.0", + "@opentelemetry/otlp-transformer": "0.220.0", + "@opentelemetry/sdk-logs": "0.220.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/otlp-exporter-base": { + "version": "0.220.0", + "resolved": "https://registry.npmmirror.com/@opentelemetry/otlp-exporter-base/-/otlp-exporter-base-0.220.0.tgz", + "integrity": "sha512-CXYo8UD5Mn9YbgebO2EL4wejtA+gxLmLiu6HCk2KH2BR7XhFN6/6p1UlCb23DYCjeYkndevLHuejCCN1yx4+OQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.9.0", + "@opentelemetry/otlp-transformer": "0.220.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/otlp-transformer": { + "version": "0.220.0", + "resolved": "https://registry.npmmirror.com/@opentelemetry/otlp-transformer/-/otlp-transformer-0.220.0.tgz", + "integrity": "sha512-lXGrv7KXZ0gNH9SVNUaa6vv6phVYGvJxfXAlMbzbakiXru75f5MZl8Z7oqiMMQD77riVHJCFlQvbZs/VVN2/4A==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/api-logs": "0.220.0", + "@opentelemetry/core": "2.9.0", + "@opentelemetry/resources": "2.9.0", + "@opentelemetry/sdk-logs": "0.220.0", + "@opentelemetry/sdk-metrics": "2.9.0", + "@opentelemetry/sdk-trace": "2.9.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/otlp-transformer/node_modules/@opentelemetry/resources": { + "version": "2.9.0", + "resolved": "https://registry.npmmirror.com/@opentelemetry/resources/-/resources-2.9.0.tgz", + "integrity": "sha512-jyA5MBLQ+Dkl3+JsZkUoUvL7yHvU64kLsvpXKarWm6347Sl1t1bXFTFykUePNpT5WH5pm9a2Qtt03iIYQhZ1Fg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.9.0", + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.3.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/resources": { + "version": "2.10.0", + "resolved": "https://registry.npmmirror.com/@opentelemetry/resources/-/resources-2.10.0.tgz", + "integrity": "sha512-q6MMm2zhggzsHVNbabYwut+a6nbuQQe3URUoxaojM/8K1IBfwwPzvxIjNi2/lI1TFe+fMHMW9MWhrtDLEXEnkA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.10.0", + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.3.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/resources/node_modules/@opentelemetry/core": { + "version": "2.10.0", + "resolved": "https://registry.npmmirror.com/@opentelemetry/core/-/core-2.10.0.tgz", + "integrity": "sha512-/wNZ8twnEQQA4HoHu22+vcsdru6pWPWxW+7w+FlxT6Id7PE/WIbZmVKkte+PF72e0F2dnImFeHD2syyE1Mw6MQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/sdk-logs": { + "version": "0.220.0", + "resolved": "https://registry.npmmirror.com/@opentelemetry/sdk-logs/-/sdk-logs-0.220.0.tgz", + "integrity": "sha512-WywcTkQtv2iNmt+6y5Kcd4rzvx9bLVsBa2Nwcmg01IUaBTkTow3W4d9KE5vNBpEDtb9tp21WcRBY/lANRrApYA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/api-logs": "0.220.0", + "@opentelemetry/core": "2.9.0", + "@opentelemetry/resources": "2.9.0", + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.4.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/sdk-logs/node_modules/@opentelemetry/resources": { + "version": "2.9.0", + "resolved": "https://registry.npmmirror.com/@opentelemetry/resources/-/resources-2.9.0.tgz", + "integrity": "sha512-jyA5MBLQ+Dkl3+JsZkUoUvL7yHvU64kLsvpXKarWm6347Sl1t1bXFTFykUePNpT5WH5pm9a2Qtt03iIYQhZ1Fg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.9.0", + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.3.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/sdk-metrics": { + "version": "2.9.0", + "resolved": "https://registry.npmmirror.com/@opentelemetry/sdk-metrics/-/sdk-metrics-2.9.0.tgz", + "integrity": "sha512-Xx8RGS4H5XEBl01WuCreMIpiah9cCXMbSkeuIePPdD2cUpq/vUzYmj8E/MK1OsbOc93FuAD4jfn2WOacKwLn7Q==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.9.0", + "@opentelemetry/resources": "2.9.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.9.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/sdk-metrics/node_modules/@opentelemetry/resources": { + "version": "2.9.0", + "resolved": "https://registry.npmmirror.com/@opentelemetry/resources/-/resources-2.9.0.tgz", + "integrity": "sha512-jyA5MBLQ+Dkl3+JsZkUoUvL7yHvU64kLsvpXKarWm6347Sl1t1bXFTFykUePNpT5WH5pm9a2Qtt03iIYQhZ1Fg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.9.0", + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.3.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/sdk-trace": { + "version": "2.9.0", + "resolved": "https://registry.npmmirror.com/@opentelemetry/sdk-trace/-/sdk-trace-2.9.0.tgz", + "integrity": "sha512-sGA19HvtrrSKYsseHphluH6j3p6Xa3fqc7c7y8f/7mYWejc1lyDFcpSdD1kYa50HCLUeEo4zA5bW0pniaPszuw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.9.0", + "@opentelemetry/resources": "2.9.0", + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.3.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/sdk-trace/node_modules/@opentelemetry/resources": { + "version": "2.9.0", + "resolved": "https://registry.npmmirror.com/@opentelemetry/resources/-/resources-2.9.0.tgz", + "integrity": "sha512-jyA5MBLQ+Dkl3+JsZkUoUvL7yHvU64kLsvpXKarWm6347Sl1t1bXFTFykUePNpT5WH5pm9a2Qtt03iIYQhZ1Fg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.9.0", + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.3.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/semantic-conventions": { + "version": "1.43.0", + "resolved": "https://registry.npmmirror.com/@opentelemetry/semantic-conventions/-/semantic-conventions-1.43.0.tgz", + "integrity": "sha512-eSYWTm620tTk45EKSedaUL8MFYI8hW164hIXsgIHyxu3VobUB3fFCu5t0hQby6OoWRPsG1KkKUG2M5UadiLiVg==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=14" + } + }, + "node_modules/@protobufjs/aspromise": { + "version": "1.1.2", + "resolved": "https://registry.npmmirror.com/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", + "integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/base64": { + "version": "1.1.2", + "resolved": "https://registry.npmmirror.com/@protobufjs/base64/-/base64-1.1.2.tgz", + "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/codegen": { + "version": "2.0.5", + "resolved": "https://registry.npmmirror.com/@protobufjs/codegen/-/codegen-2.0.5.tgz", + "integrity": "sha512-zgXFLzW3Ap33e6d0Wlj4MGIm6Ce8O89n/apUaGNB/jx+hw+ruWEp7EwGUshdLKVRCxZW12fp9r40E1mQrf/34g==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/eventemitter": { + "version": "1.1.1", + "resolved": "https://registry.npmmirror.com/@protobufjs/eventemitter/-/eventemitter-1.1.1.tgz", + "integrity": "sha512-vW1GmwMZNnL+gMRaovlh9yZX74kc+TTU3FObkkurpMaRtBfLP3ldjS9KQWlwZgraRE0+dheEEoAxdzcJQ8eXZg==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/fetch": { + "version": "1.1.1", + "resolved": "https://registry.npmmirror.com/@protobufjs/fetch/-/fetch-1.1.1.tgz", + "integrity": "sha512-GpptLrs57adMSuHi3VNj0mAF8dwh36LMaYF6XyJ6JMWlVsc+t42tm1HSEDmOs3A8fC9yyeisgLhsTVQokOZ0zw==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@protobufjs/aspromise": "^1.1.1" + } + }, + "node_modules/@protobufjs/float": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/@protobufjs/float/-/float-1.0.2.tgz", + "integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/path": { + "version": "1.1.2", + "resolved": "https://registry.npmmirror.com/@protobufjs/path/-/path-1.1.2.tgz", + "integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/pool": { + "version": "1.1.0", + "resolved": "https://registry.npmmirror.com/@protobufjs/pool/-/pool-1.1.0.tgz", + "integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/utf8": { + "version": "1.1.2", + "resolved": "https://registry.npmmirror.com/@protobufjs/utf8/-/utf8-1.1.2.tgz", + "integrity": "sha512-b1UQwcEZ4yCnMCD8DAL1VlbvBJE9/IX4FTIp7BG1xYpf29SLazLSrqUkj4w7Y5y7cCVP6E5tcqqcI0xemPkHug==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/@smithy/core": { + "version": "3.33.2", + "resolved": "https://registry.npmmirror.com/@smithy/core/-/core-3.33.2.tgz", + "integrity": "sha512-CUGXpnPkVdjUCbix+83sWLW9VFgQOm44MDOx/ihITJMAnOZKvL8YYIc7DR9pP/tZ8CIRvMiON/TucvygqbHO3w==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.17.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/credential-provider-imds": { + "version": "4.5.2", + "resolved": "https://registry.npmmirror.com/@smithy/credential-provider-imds/-/credential-provider-imds-4.5.2.tgz", + "integrity": "sha512-A9uSdn72ozbRUSit0eib0TW7nXuNPlaeM0zcGkJ+nE6tFcSDbnmtwoxbTCFBukVQcszDAyvsd7+rTduPTXpygg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@smithy/core": "^3.33.2", + "@smithy/types": "^4.17.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/fetch-http-handler": { + "version": "5.7.2", + "resolved": "https://registry.npmmirror.com/@smithy/fetch-http-handler/-/fetch-http-handler-5.7.2.tgz", + "integrity": "sha512-nZyWTmSpJEXl6VtWVMBJve/7x12DZu6sIX1z1a+ZMaHlQQRs9Zpu6NbTe/gmxYXVRpkjxyDYpZ5gx2IM6f/Wkw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@smithy/core": "^3.33.2", + "@smithy/types": "^4.17.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/is-array-buffer": { + "version": "2.2.0", + "resolved": "https://registry.npmmirror.com/@smithy/is-array-buffer/-/is-array-buffer-2.2.0.tgz", + "integrity": "sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/node-http-handler": { + "version": "4.7.3", + "resolved": "https://registry.npmmirror.com/@smithy/node-http-handler/-/node-http-handler-4.7.3.tgz", + "integrity": "sha512-/jPhevcTFPMVl6KNjbaI47iOg1zxC7IsnX4PQDGVZKMFceOXtB8IEYaB7a9VvkP/3oC60WzTeKocvSI7vLT0vA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@smithy/core": "^3.24.3", + "@smithy/types": "^4.14.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/signature-v4": { + "version": "5.7.2", + "resolved": "https://registry.npmmirror.com/@smithy/signature-v4/-/signature-v4-5.7.2.tgz", + "integrity": "sha512-P7Ki6px6OOrxVtx8K7nLmyx4SlXUW/uTKDdMG44UHefmPGSRMBKe2v+TM59WdLcpUIrBrnuCsIqiM2MbsZjmhw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@smithy/core": "^3.33.2", + "@smithy/types": "^4.17.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/types": { + "version": "4.17.2", + "resolved": "https://registry.npmmirror.com/@smithy/types/-/types-4.17.2.tgz", + "integrity": "sha512-FOKpVZob9MPTn2znRzGrnsMHv7BOsKVw3XiP/cOyYLDVZ9qKp4nifIiSCuUU/fIj5Vu0UOAxCFr+qRAtG0NUkA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-buffer-from": { + "version": "2.2.0", + "resolved": "https://registry.npmmirror.com/@smithy/util-buffer-from/-/util-buffer-from-2.2.0.tgz", + "integrity": "sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@smithy/is-array-buffer": "^2.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/util-utf8": { + "version": "2.3.0", + "resolved": "https://registry.npmmirror.com/@smithy/util-utf8/-/util-utf8-2.3.0.tgz", + "integrity": "sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@smithy/util-buffer-from": "^2.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@standard-schema/spec": { + "version": "1.1.0", + "resolved": "https://registry.npmmirror.com/@standard-schema/spec/-/spec-1.1.0.tgz", + "integrity": "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==", + "license": "MIT" + }, + "node_modules/@tanstack/virtual-core": { + "version": "3.17.8", + "resolved": "https://registry.npmmirror.com/@tanstack/virtual-core/-/virtual-core-3.17.8.tgz", + "integrity": "sha512-BfEvehNpOT75r5Ksc5xW6NZuXujTfb7nlSEyVu4XHG3gdxNg1KqXruWbDewXOUaUYIo4oRbSfkjIajz4MAT8tA==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + } + }, + "node_modules/@types/node": { + "version": "26.2.0", + "resolved": "https://registry.npmmirror.com/@types/node/-/node-26.2.0.tgz", + "integrity": "sha512-5IviulTZeRNp2vAJ514cc/HUlY5nZ9fCbq9DMyC52BrhFZACo3nI0R7qBxhQmo/d27NFe96ur/b7Wwxklda+kg==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~8.3.0" + } + }, + "node_modules/@types/retry": { + "version": "0.12.0", + "resolved": "https://registry.npmmirror.com/@types/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@vscode/ripgrep": { + "version": "1.18.0", + "resolved": "https://registry.npmmirror.com/@vscode/ripgrep/-/ripgrep-1.18.0.tgz", + "integrity": "sha512-ns5lWe44tSfbTMbVUsyB+I1819PVSw4AdpgK0RNkzfWfwy6+3IUNSxwSrfTno1/oWaS/hERNz+XLWVyga2aJBQ==", + "dev": true, + "license": "MIT", + "optionalDependencies": { + "@vscode/ripgrep-darwin-arm64": "1.18.0", + "@vscode/ripgrep-darwin-x64": "1.18.0", + "@vscode/ripgrep-linux-arm": "1.18.0", + "@vscode/ripgrep-linux-arm64": "1.18.0", + "@vscode/ripgrep-linux-ia32": "1.18.0", + "@vscode/ripgrep-linux-ppc64": "1.18.0", + "@vscode/ripgrep-linux-riscv64": "1.18.0", + "@vscode/ripgrep-linux-s390x": "1.18.0", + "@vscode/ripgrep-linux-x64": "1.18.0", + "@vscode/ripgrep-win32-arm64": "1.18.0", + "@vscode/ripgrep-win32-ia32": "1.18.0", + "@vscode/ripgrep-win32-x64": "1.18.0" + } + }, + "node_modules/@vscode/ripgrep-darwin-arm64": { + "version": "1.18.0", + "resolved": "https://registry.npmmirror.com/@vscode/ripgrep-darwin-arm64/-/ripgrep-darwin-arm64-1.18.0.tgz", + "integrity": "sha512-r3ktHSvbFycQNF6sl7sNDPocpsI7J+mEzh1IaZFkY0spm3k2Z9t8hPAeOK7+p0l6p6/swkQC14XWX01low+94Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@vscode/ripgrep-darwin-x64": { + "version": "1.18.0", + "resolved": "https://registry.npmmirror.com/@vscode/ripgrep-darwin-x64/-/ripgrep-darwin-x64-1.18.0.tgz", + "integrity": "sha512-25b4gWbL138dGuQU244ebCKKc0q05ULBMoFSz9oAEUHNeqK/lOJViDS7DRvbDazzAzSEdan391Znks/R5mkaTQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@vscode/ripgrep-linux-arm": { + "version": "1.18.0", + "resolved": "https://registry.npmmirror.com/@vscode/ripgrep-linux-arm/-/ripgrep-linux-arm-1.18.0.tgz", + "integrity": "sha512-GDAvufNDHu8zqLEmXstalQF0Wh6wQvdsBi/Vg3Yi3CK4a8XoFXqqXVEHEZ9xQz3t0NfoSEc9JbvK9DDS6FxyxQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@vscode/ripgrep-linux-arm64": { + "version": "1.18.0", + "resolved": "https://registry.npmmirror.com/@vscode/ripgrep-linux-arm64/-/ripgrep-linux-arm64-1.18.0.tgz", + "integrity": "sha512-lQ/5zTG++U0E3IhVgS4EPTTn/U4okncaRMM5GOFfOYZywS4nuD31GhkHbNYlDk5CuDC68+hYJ0/eQeyCKJDA+g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@vscode/ripgrep-linux-ia32": { + "version": "1.18.0", + "resolved": "https://registry.npmmirror.com/@vscode/ripgrep-linux-ia32/-/ripgrep-linux-ia32-1.18.0.tgz", + "integrity": "sha512-YWLkSUtFd4Jh5EepIhA9RJSfv3uMAVMo+2rBIGHPBnvgLrZciIs2cDKei1/p6Wc/aCzUoHyMAg2R6tw4ZCBKGg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@vscode/ripgrep-linux-ppc64": { + "version": "1.18.0", + "resolved": "https://registry.npmmirror.com/@vscode/ripgrep-linux-ppc64/-/ripgrep-linux-ppc64-1.18.0.tgz", + "integrity": "sha512-quXVY8fwQ8O/lvU1yrSqSl3jlUzysRSb+AfUfCL/tRtphxsKlFvPAejryZ6vg4Bgvn8XL74xb4qMCDmWgYrT5w==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@vscode/ripgrep-linux-riscv64": { + "version": "1.18.0", + "resolved": "https://registry.npmmirror.com/@vscode/ripgrep-linux-riscv64/-/ripgrep-linux-riscv64-1.18.0.tgz", + "integrity": "sha512-f5kBQBrWfQt8Q7OhSORuNDei5dkYagBj3y4jImSUXGMy8B/Ke7SltSRcUtjPv166FAFfHCAmWuZp3+cWnX2/Vw==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@vscode/ripgrep-linux-s390x": { + "version": "1.18.0", + "resolved": "https://registry.npmmirror.com/@vscode/ripgrep-linux-s390x/-/ripgrep-linux-s390x-1.18.0.tgz", + "integrity": "sha512-rTOcJFGGcl2c07RUOWUo4U1ndnemKhY6A9hnMB18uk7jSgJc0d/QLBGWMWpumdtoJtpizn/wIv5mXIisJukusQ==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@vscode/ripgrep-linux-x64": { + "version": "1.18.0", + "resolved": "https://registry.npmmirror.com/@vscode/ripgrep-linux-x64/-/ripgrep-linux-x64-1.18.0.tgz", + "integrity": "sha512-mQ3bVrUpnD2vs7QT0vX90Lt0cnUq467uFtEktIdsJJmW296RoSULRGqWgzG1AKxyBpNDD6l4ZO4qKf6SgyC23Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@vscode/ripgrep-win32-arm64": { + "version": "1.18.0", + "resolved": "https://registry.npmmirror.com/@vscode/ripgrep-win32-arm64/-/ripgrep-win32-arm64-1.18.0.tgz", + "integrity": "sha512-vfTIjq1OHnzUjxZcHVQAMbnggp8dpGf+0QKFOZHwWPqFwXxQC8eCWM+5NUdoJ6yrElCeMzoUTXoK/LdZaniB+Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@vscode/ripgrep-win32-ia32": { + "version": "1.18.0", + "resolved": "https://registry.npmmirror.com/@vscode/ripgrep-win32-ia32/-/ripgrep-win32-ia32-1.18.0.tgz", + "integrity": "sha512-//rfAE+BOw5AC2EMmepmiE36jUuevtQYNQqqlw1s3m9FlRxjxEut97RkRPHAu9BG4mSojatZx+kXZXNdyI9caQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@vscode/ripgrep-win32-x64": { + "version": "1.18.0", + "resolved": "https://registry.npmmirror.com/@vscode/ripgrep-win32-x64/-/ripgrep-win32-x64-1.18.0.tgz", + "integrity": "sha512-KNPvtElldqILHdnAetujPaowkNbpqJy3ssIGGN6F6Kve9Qi+nNLI2DN01O83JjCEVQbCzl8Ov3QZ9Eov3BR8Dg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/accepts": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/accepts/-/accepts-2.0.0.tgz", + "integrity": "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==", + "dev": true, + "license": "MIT", + "dependencies": { + "mime-types": "^3.0.0", + "negotiator": "^1.0.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/agent-base": { + "version": "7.1.4", + "resolved": "https://registry.npmmirror.com/agent-base/-/agent-base-7.1.4.tgz", + "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14" + } + }, + "node_modules/ajv": { + "version": "8.20.0", + "resolved": "https://registry.npmmirror.com/ajv/-/ajv-8.20.0.tgz", + "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-formats": { + "version": "3.0.1", + "resolved": "https://registry.npmmirror.com/ajv-formats/-/ajv-formats-3.0.1.tgz", + "integrity": "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "devOptional": true, + "license": "Python-2.0" + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmmirror.com/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/bignumber.js": { + "version": "9.3.1", + "resolved": "https://registry.npmmirror.com/bignumber.js/-/bignumber.js-9.3.1.tgz", + "integrity": "sha512-Ko0uX15oIUS7wJ3Rb30Fs6SkVbLmPBAKdlm7q9+ak9bbIeFf0MwuBsQV6z7+X768/cHsfg+WlysDWJcmthjsjQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/body-parser": { + "version": "2.3.0", + "resolved": "https://registry.npmmirror.com/body-parser/-/body-parser-2.3.0.tgz", + "integrity": "sha512-2cGmJupaNgg+QUwVLAucDuWuoMZ6EX9iHDRswZ5lsNYEmwPaRknMPCLZz07yTzVq/83p4o/wzbDZbBrTvGGTIw==", + "dev": true, + "license": "MIT", + "dependencies": { + "bytes": "^3.1.2", + "content-type": "^2.0.0", + "debug": "^4.4.3", + "http-errors": "^2.0.1", + "iconv-lite": "^0.7.2", + "on-finished": "^2.4.1", + "qs": "^6.15.2", + "raw-body": "^3.0.2", + "type-is": "^2.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/body-parser/node_modules/content-type": { + "version": "2.1.0", + "resolved": "https://registry.npmmirror.com/content-type/-/content-type-2.1.0.tgz", + "integrity": "sha512-mj7UPXE0jaqaOsukNZRUEfEi2AcL7C/vwmwcHV0O97eO1E1pxBZuyjlZrx5seTaNBg1U6+o35wpa35Qfcc+7ag==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/bowser": { + "version": "2.14.1", + "resolved": "https://registry.npmmirror.com/bowser/-/bowser-2.14.1.tgz", + "integrity": "sha512-tzPjzCxygAKWFOJP011oxFHs57HzIhOEracIgAePE4pqB3LikALKnSzUyU4MGs9/iCEUuHlAJTjTc5M+u7YEGg==", + "dev": true, + "license": "MIT" + }, + "node_modules/buffer-equal-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/bundle-name": { + "version": "4.1.0", + "resolved": "https://registry.npmmirror.com/bundle-name/-/bundle-name-4.1.0.tgz", + "integrity": "sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "run-applescript": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmmirror.com/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/call-bound": { + "version": "1.0.4", + "resolved": "https://registry.npmmirror.com/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/chokidar": { + "version": "4.0.3", + "resolved": "https://registry.npmmirror.com/chokidar/-/chokidar-4.0.3.tgz", + "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", + "dev": true, + "license": "MIT", + "dependencies": { + "readdirp": "^4.0.1" + }, + "engines": { + "node": ">= 14.16.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/clsx": { + "version": "2.1.1", + "resolved": "https://registry.npmmirror.com/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/commander": { + "version": "15.0.0", + "resolved": "https://registry.npmmirror.com/commander/-/commander-15.0.0.tgz", + "integrity": "sha512-z67u4ZhzCL/Tydu1lJARtEZYWbWaN7oYLHbsuzocr6y4N6WZAagG3RQ4FW61V1/0+jImpj293XfrcYnd1qxtPg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=22.12.0" + } + }, + "node_modules/content-disposition": { + "version": "1.1.0", + "resolved": "https://registry.npmmirror.com/content-disposition/-/content-disposition-1.1.0.tgz", + "integrity": "sha512-5jRCH9Z/+DRP7rkvY83B+yGIGX96OYdJmzngqnw2SBSxqCFPd0w2km3s5iawpGX8krnwSGmF0FW5Nhr0Hfai3g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmmirror.com/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie": { + "version": "0.7.2", + "resolved": "https://registry.npmmirror.com/cookie/-/cookie-0.7.2.tgz", + "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.2.2", + "resolved": "https://registry.npmmirror.com/cookie-signature/-/cookie-signature-1.2.2.tgz", + "integrity": "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.6.0" + } + }, + "node_modules/cors": { + "version": "2.8.6", + "resolved": "https://registry.npmmirror.com/cors/-/cors-2.8.6.tgz", + "integrity": "sha512-tJtZBBHA6vjIAaF6EnIaq6laBBP9aq/Y3ouVJjEfoHbRBcHBAHYcMh/w8LDrk2PvIMMq8gmopa5D4V8RmbrxGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "object-assign": "^4", + "vary": "^1" + }, + "engines": { + "node": ">= 0.10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmmirror.com/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/data-uri-to-buffer": { + "version": "4.0.1", + "resolved": "https://registry.npmmirror.com/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz", + "integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 12" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmmirror.com/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/default-browser": { + "version": "5.5.1", + "resolved": "https://registry.npmmirror.com/default-browser/-/default-browser-5.5.1.tgz", + "integrity": "sha512-m1pAzaJgZ/gssEqlOhJkPJp8Xly7QyW6xcrkUa2KKcDeDSEMP7X8xipU3snUcfisTQx0w1AGae+9UtJSfVnXGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "bundle-name": "^4.1.0", + "default-browser-id": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/default-browser-id": { + "version": "5.0.1", + "resolved": "https://registry.npmmirror.com/default-browser-id/-/default-browser-id-5.0.1.tgz", + "integrity": "sha512-x1VCxdX4t+8wVfd1so/9w+vQ4vx7lKd2Qp5tDRutErwmR85OgmfX7RlLRMWafRMY7hbEiXIbudNrjOAPa/hL8Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/define-lazy-prop": { + "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz", + "integrity": "sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/detect-libc": { + "version": "2.1.2", + "resolved": "https://registry.npmmirror.com/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } + }, + "node_modules/diff": { + "version": "9.0.0", + "resolved": "https://registry.npmmirror.com/diff/-/diff-9.0.0.tgz", + "integrity": "sha512-svtcdpS8CgJyqAjEQIXdb3OjhFVVYjzGAPO8WGCmRbrml64SPw/jJD4GoE98aR7r25A0XcgrK3F02yw9R/vhQw==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/ecdsa-sig-formatter": { + "version": "1.0.11", + "resolved": "https://registry.npmmirror.com/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", + "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "safe-buffer": "^5.0.1" + } + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmmirror.com/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", + "dev": true, + "license": "MIT" + }, + "node_modules/encodeurl": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmmirror.com/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.2", + "resolved": "https://registry.npmmirror.com/es-object-atoms/-/es-object-atoms-1.1.2.tgz", + "integrity": "sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmmirror.com/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", + "dev": true, + "license": "MIT" + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmmirror.com/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/eventsource": { + "version": "3.0.7", + "resolved": "https://registry.npmmirror.com/eventsource/-/eventsource-3.0.7.tgz", + "integrity": "sha512-CRT1WTyuQoD771GW56XEZFQ/ZoSfWid1alKGDYMmkt2yl8UXrVR4pspqWNEcqKvVIzg6PAltWjxcSSPrboA4iA==", + "dev": true, + "license": "MIT", + "dependencies": { + "eventsource-parser": "^3.0.1" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/eventsource-parser": { + "version": "3.1.1", + "resolved": "https://registry.npmmirror.com/eventsource-parser/-/eventsource-parser-3.1.1.tgz", + "integrity": "sha512-EKN1vKAMcZ8MlYMpaNuxN6R9yakzH6uajHcHVTqWJzvu5pWw9DyhbP35HH8MVBQ+dZjAfDxk+A8NiR9KWaXiyQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/express": { + "version": "5.2.1", + "resolved": "https://registry.npmmirror.com/express/-/express-5.2.1.tgz", + "integrity": "sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==", + "dev": true, + "license": "MIT", + "dependencies": { + "accepts": "^2.0.0", + "body-parser": "^2.2.1", + "content-disposition": "^1.0.0", + "content-type": "^1.0.5", + "cookie": "^0.7.1", + "cookie-signature": "^1.2.1", + "debug": "^4.4.0", + "depd": "^2.0.0", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "etag": "^1.8.1", + "finalhandler": "^2.1.0", + "fresh": "^2.0.0", + "http-errors": "^2.0.0", + "merge-descriptors": "^2.0.0", + "mime-types": "^3.0.0", + "on-finished": "^2.4.1", + "once": "^1.4.0", + "parseurl": "^1.3.3", + "proxy-addr": "^2.0.7", + "qs": "^6.14.0", + "range-parser": "^1.2.1", + "router": "^2.2.0", + "send": "^1.1.0", + "serve-static": "^2.2.0", + "statuses": "^2.0.1", + "type-is": "^2.0.1", + "vary": "^1.1.2" + }, + "engines": { + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/express-rate-limit": { + "version": "8.6.2", + "resolved": "https://registry.npmmirror.com/express-rate-limit/-/express-rate-limit-8.6.2.tgz", + "integrity": "sha512-YH4ru+eOJxQABscKFfRCy9R7x9QFGdezclVMwwgFFndzS2Xnm0uo6B0ABZsLhcpeptGv2qvuJVWlQr9gQZoC3A==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.4.3", + "ip-address": "^10.2.0" + }, + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://github.com/sponsors/express-rate-limit" + }, + "peerDependencies": { + "express": ">= 4.11" + } + }, + "node_modules/extend": { + "version": "3.0.2", + "resolved": "https://registry.npmmirror.com/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmmirror.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-uri": { + "version": "3.1.5", + "resolved": "https://registry.npmmirror.com/fast-uri/-/fast-uri-3.1.5.tgz", + "integrity": "sha512-gHwA1O9LDIcKunMKhObS/HimwtehO1nPUECKAu5TpKgaO19fcWEl4bliWe1jWxVFvIXztJjjQ4L8XQ1EU9f7Jw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/fetch-blob": { + "version": "3.2.0", + "resolved": "https://registry.npmmirror.com/fetch-blob/-/fetch-blob-3.2.0.tgz", + "integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/jimmywarting" + }, + { + "type": "paypal", + "url": "https://paypal.me/jimmywarting" + } + ], + "license": "MIT", + "dependencies": { + "node-domexception": "^1.0.0", + "web-streams-polyfill": "^3.0.3" + }, + "engines": { + "node": "^12.20 || >= 14.13" + } + }, + "node_modules/fflate": { + "version": "0.8.3", + "resolved": "https://registry.npmmirror.com/fflate/-/fflate-0.8.3.tgz", + "integrity": "sha512-tbZNuJrLwGUp3zshBtdy4W+ORxZuIh8a5ilyIEQDC5rY1f3U20JMry0Ll3WBzU58EZKsEuJFXhb5gwv8CsPvgA==", + "dev": true, + "license": "MIT" + }, + "node_modules/finalhandler": { + "version": "2.1.1", + "resolved": "https://registry.npmmirror.com/finalhandler/-/finalhandler-2.1.1.tgz", + "integrity": "sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.4.0", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "on-finished": "^2.4.1", + "parseurl": "^1.3.3", + "statuses": "^2.0.1" + }, + "engines": { + "node": ">= 18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/formdata-polyfill": { + "version": "4.0.10", + "resolved": "https://registry.npmmirror.com/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz", + "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fetch-blob": "^3.1.2" + }, + "engines": { + "node": ">=12.20.0" + } + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmmirror.com/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fresh": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/fresh/-/fresh-2.0.0.tgz", + "integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmmirror.com/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gaxios": { + "version": "7.3.1", + "resolved": "https://registry.npmmirror.com/gaxios/-/gaxios-7.3.1.tgz", + "integrity": "sha512-kB3rzJV7d9juLZh8/56QTXCwQfxyhdOMdyYk1HdQKFtF8TJTDTZQJtixWIwXdE9Jji91mC41DUNpjleo4L4eAQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "extend": "^3.0.2", + "https-proxy-agent": "^7.0.1", + "node-fetch": "^3.3.2" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/gcp-metadata": { + "version": "8.1.2", + "resolved": "https://registry.npmmirror.com/gcp-metadata/-/gcp-metadata-8.1.2.tgz", + "integrity": "sha512-zV/5HKTfCeKWnxG0Dmrw51hEWFGfcF2xiXqcA3+J90WDuP0SvoiSO5ORvcBsifmx/FoIjgQN3oNOGaQ5PhLFkg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "gaxios": "^7.0.0", + "google-logging-utils": "^1.0.0", + "json-bigint": "^1.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmmirror.com/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/google-auth-library": { + "version": "10.9.1", + "resolved": "https://registry.npmmirror.com/google-auth-library/-/google-auth-library-10.9.1.tgz", + "integrity": "sha512-i1ydyHrqcIxXkWh/uBmVkzCvIuq5yiK2ATndIe5XxKholrG/MTYP9xGYka4sQhrbIAgGjL2B6NOE7rFaiF3fXw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "base64-js": "^1.3.0", + "ecdsa-sig-formatter": "^1.0.11", + "gaxios": "^7.1.4", + "gcp-metadata": "8.1.2", + "google-logging-utils": "1.1.3", + "jws": "^4.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/google-logging-utils": { + "version": "1.1.3", + "resolved": "https://registry.npmmirror.com/google-logging-utils/-/google-logging-utils-1.1.3.tgz", + "integrity": "sha512-eAmLkjDjAFCVXg7A1unxHsLf961m6y17QFqXqAXGj/gVkKFrEICfStRfwUlGNfeCEjNRa32JEWOUTlYXPyyKvA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=14" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmmirror.com/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmmirror.com/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.4", + "resolved": "https://registry.npmmirror.com/hasown/-/hasown-2.0.4.tgz", + "integrity": "sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==", + "dev": true, + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/hono": { + "version": "4.13.3", + "resolved": "https://registry.npmmirror.com/hono/-/hono-4.13.3.tgz", + "integrity": "sha512-r8AO2mYHoLxSHkgafNeC/BXyb2vWRxD3jem4Ts+ptav8oTG5FIRifAjuJEmZI4bSvvc2ns0GxmIYiZnHqN3mMw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=16.9.0" + } + }, + "node_modules/http-errors": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/http-errors/-/http-errors-2.0.1.tgz", + "integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "depd": "~2.0.0", + "inherits": "~2.0.4", + "setprototypeof": "~1.2.0", + "statuses": "~2.0.2", + "toidentifier": "~1.0.1" + }, + "engines": { + "node": ">= 0.8" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/http-proxy-agent": { + "version": "7.0.2", + "resolved": "https://registry.npmmirror.com/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", + "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/https-proxy-agent": { + "version": "7.0.6", + "resolved": "https://registry.npmmirror.com/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", + "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/iconv-lite": { + "version": "0.7.3", + "resolved": "https://registry.npmmirror.com/iconv-lite/-/iconv-lite-0.7.3.tgz", + "integrity": "sha512-IKXpvIzjnC9XTAUbVBcMfGS0EPaIXtW6v+zr+RRp+hqULEpo0owZax6wyRwPOJbWbzjYspQwusTsfVr0ifh4uQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/immer": { + "version": "10.2.0", + "resolved": "https://registry.npmmirror.com/immer/-/immer-10.2.0.tgz", + "integrity": "sha512-d/+XTN3zfODyjr89gM3mPq1WNX2B8pYsu7eORitdwyA2sBubnTl3laYlBk4sXY5FUa5qTZGBDPJICVbvqzjlbw==", + "dev": true, + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/immer" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmmirror.com/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/ip-address": { + "version": "10.5.0", + "resolved": "https://registry.npmmirror.com/ip-address/-/ip-address-10.5.0.tgz", + "integrity": "sha512-R5SnVLJmgYYvf2F2ZgwSBnelz5G4q5AxIC277GDfUaNbrZKNANcBC7RHqYYePlszf4kBolVkJauG0ZjHHFh55g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 12" + } + }, + "node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmmirror.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/is-docker": { + "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/is-docker/-/is-docker-3.0.0.tgz", + "integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==", + "dev": true, + "license": "MIT", + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-in-ssh": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/is-in-ssh/-/is-in-ssh-1.0.0.tgz", + "integrity": "sha512-jYa6Q9rH90kR1vKB6NM7qqd1mge3Fx4Dhw5TVlK1MUBqhEOuCagrEHMevNuCcbECmXZ0ThXkRm+Ymr51HwEPAw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-inside-container": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/is-inside-container/-/is-inside-container-1.0.0.tgz", + "integrity": "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-docker": "^3.0.0" + }, + "bin": { + "is-inside-container": "cli.js" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-promise": { + "version": "4.0.0", + "resolved": "https://registry.npmmirror.com/is-promise/-/is-promise-4.0.0.tgz", + "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/is-wsl": { + "version": "3.1.1", + "resolved": "https://registry.npmmirror.com/is-wsl/-/is-wsl-3.1.1.tgz", + "integrity": "sha512-e6rvdUCiQCAuumZslxRJWR/Doq4VpPR82kqclvcS0efgt430SlGIk05vdCN58+VrzgtIcfNODjozVielycD4Sw==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-inside-container": "^1.0.0" + }, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, + "node_modules/jose": { + "version": "6.2.9", + "resolved": "https://registry.npmmirror.com/jose/-/jose-6.2.9.tgz", + "integrity": "sha512-XrchZOFZUl/T3vTwRe8XK+cJrGtMF4th1ARnDfwbBXFKThGhlsxEE4Zu03AD/bjJSt/9jT/mxrOCkJWOg77aPA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/panva" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmmirror.com/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/js-yaml": { + "version": "4.3.1", + "resolved": "https://registry.npmmirror.com/js-yaml/-/js-yaml-4.3.1.tgz", + "integrity": "sha512-CY6crGq313MX8GkwvB7tzgp99vjQxY1++5y10/BKN/GUfHqWaOGQMNZkBvqSzsZKWk/ijwHlWzzkLulsGHhjWQ==", + "devOptional": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/puzrin" + }, + { + "type": "github", + "url": "https://github.com/sponsors/nodeca" + } + ], + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/json-bigint": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/json-bigint/-/json-bigint-1.0.0.tgz", + "integrity": "sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "bignumber.js": "^9.0.0" + } + }, + "node_modules/json-schema-to-ts": { + "version": "3.1.1", + "resolved": "https://registry.npmmirror.com/json-schema-to-ts/-/json-schema-to-ts-3.1.1.tgz", + "integrity": "sha512-+DWg8jCJG2TEnpy7kOm/7/AxaYoaRbjVB4LFZLySZlWn8exGs3A4OLJR966cVvU26N7X9TWxl+Jsw7dzAqKT6g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.18.3", + "ts-algebra": "^2.0.0" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-schema-typed": { + "version": "8.0.2", + "resolved": "https://registry.npmmirror.com/json-schema-typed/-/json-schema-typed-8.0.2.tgz", + "integrity": "sha512-fQhoXdcvc3V28x7C7BMs4P5+kNlgUURe2jmUT1T//oBRMDrqy1QPelJimwZGo7Hg9VPV3EQV5Bnq4hbFy2vetA==", + "dev": true, + "license": "BSD-2-Clause" + }, + "node_modules/jwa": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/jwa/-/jwa-2.0.1.tgz", + "integrity": "sha512-hRF04fqJIP8Abbkq5NKGN0Bbr3JxlQ+qhZufXVr0DvujKy93ZCbXZMHDL4EOtodSbCWxOqR8MS1tXA5hwqCXDg==", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer-equal-constant-time": "^1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/jws": { + "version": "4.0.1", + "resolved": "https://registry.npmmirror.com/jws/-/jws-4.0.1.tgz", + "integrity": "sha512-EKI/M/yqPncGUUh44xz0PxSidXFr/+r0pA70+gIYhjv+et7yxM+s29Y+VGDkovRofQem0fs7Uvf4+YmAdyRduA==", + "dev": true, + "license": "MIT", + "dependencies": { + "jwa": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/koffi": { + "version": "3.1.5", + "resolved": "https://registry.npmmirror.com/koffi/-/koffi-3.1.5.tgz", + "integrity": "sha512-XVwwrxg0Ca6IEUQF4YtGIU4XN0LSselFYpYvgfhh8wafCunhEEx5hPr7LZhp5QyeFA/LcRsKHTqncCdjWjWAlg==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "funding": { + "url": "https://liberapay.com/Koromix" + }, + "optionalDependencies": { + "@koromix/koffi-darwin-arm64": "3.1.5", + "@koromix/koffi-darwin-x64": "3.1.5", + "@koromix/koffi-freebsd-arm64": "3.1.5", + "@koromix/koffi-freebsd-ia32": "3.1.5", + "@koromix/koffi-freebsd-x64": "3.1.5", + "@koromix/koffi-linux-arm64": "3.1.5", + "@koromix/koffi-linux-ia32": "3.1.5", + "@koromix/koffi-linux-loong64": "3.1.5", + "@koromix/koffi-linux-riscv64": "3.1.5", + "@koromix/koffi-linux-x64": "3.1.5", + "@koromix/koffi-openbsd-ia32": "3.1.5", + "@koromix/koffi-openbsd-x64": "3.1.5", + "@koromix/koffi-win32-arm64": "3.1.5", + "@koromix/koffi-win32-ia32": "3.1.5", + "@koromix/koffi-win32-x64": "3.1.5" + } + }, + "node_modules/long": { + "version": "5.3.2", + "resolved": "https://registry.npmmirror.com/long/-/long-5.3.2.tgz", + "integrity": "sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmmirror.com/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmmirror.com/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/media-typer": { + "version": "1.1.1", + "resolved": "https://registry.npmmirror.com/media-typer/-/media-typer-1.1.1.tgz", + "integrity": "sha512-yz3xRaG20c6/BOzvYoDaGtPmGscs7YivItZEEqe6GbwNfHuxu9YNmvnEkMzKldAGY4/80pRcQRZSEnhquk9XuQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/merge-descriptors": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/merge-descriptors/-/merge-descriptors-2.0.0.tgz", + "integrity": "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mime-db": { + "version": "1.54.0", + "resolved": "https://registry.npmmirror.com/mime-db/-/mime-db-1.54.0.tgz", + "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "3.0.2", + "resolved": "https://registry.npmmirror.com/mime-types/-/mime-types-3.0.2.tgz", + "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "mime-db": "^1.54.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmmirror.com/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/negotiator": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/negotiator/-/negotiator-1.0.0.tgz", + "integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/node-addon-api": { + "version": "7.1.1", + "resolved": "https://registry.npmmirror.com/node-addon-api/-/node-addon-api-7.1.1.tgz", + "integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/node-addon-native-custom-loader": { + "version": "0.1.5", + "resolved": "https://registry.npmmirror.com/node-addon-native-custom-loader/-/node-addon-native-custom-loader-0.1.5.tgz", + "integrity": "sha512-rL0XXRytayIChYf1xaG9/1NzGBRTyFkQTIpn+MDz/hpr0PZw1a9PZIoH9HlYfagNawhXU+jfN650EvoSIvR7Vw==", + "devOptional": true, + "license": "MIT", + "engines": { + "node": ">=20" + } + }, + "node_modules/node-addon-require-builtin": { + "version": "0.1.5", + "resolved": "https://registry.npmmirror.com/node-addon-require-builtin/-/node-addon-require-builtin-0.1.5.tgz", + "integrity": "sha512-isaquiStlp7qdFpaffy+2ssJPUR/kLPRE5gqfeWbb0Ahph9H7O3BOFwThqkVaTrxfpnjrQauxlOEgvzD+snhUg==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "node-addon-native-custom-loader": "0.1.5" + }, + "engines": { + "node": ">=20" + }, + "optionalDependencies": { + "node-addon-require-builtin-darwin-arm64": "0.1.5", + "node-addon-require-builtin-darwin-x64": "0.1.5", + "node-addon-require-builtin-linux-arm64-gnu": "0.1.5", + "node-addon-require-builtin-linux-x64-gnu": "0.1.5", + "node-addon-require-builtin-win32-arm64-msvc": "0.1.5", + "node-addon-require-builtin-win32-ia32-msvc": "0.1.5", + "node-addon-require-builtin-win32-x64-msvc": "0.1.5" + } + }, + "node_modules/node-addon-require-builtin-darwin-arm64": { + "version": "0.1.5", + "resolved": "https://registry.npmmirror.com/node-addon-require-builtin-darwin-arm64/-/node-addon-require-builtin-darwin-arm64-0.1.5.tgz", + "integrity": "sha512-MZ5RyGhuU7DTbwuNpOQW81/ep8n5Yd5YlZa6dWiEfJEh+01Dl4cCKGmMCWNgb0VtqAImRtAOtmZIPtwngiemKQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "dependencies": { + "node-addon-native-custom-loader": "0.1.5" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/node-addon-require-builtin-darwin-x64": { + "version": "0.1.5", + "resolved": "https://registry.npmmirror.com/node-addon-require-builtin-darwin-x64/-/node-addon-require-builtin-darwin-x64-0.1.5.tgz", + "integrity": "sha512-wdCSPn49AdNZ2EXHQqswiXk1cROFe9zSRaAX8PwQLxmjdLt+xZF7vZP6VlqgXm+VAOHv98q8kp9m7mO9jY3OgQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "dependencies": { + "node-addon-native-custom-loader": "0.1.5" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/node-addon-require-builtin-linux-arm64-gnu": { + "version": "0.1.5", + "resolved": "https://registry.npmmirror.com/node-addon-require-builtin-linux-arm64-gnu/-/node-addon-require-builtin-linux-arm64-gnu-0.1.5.tgz", + "integrity": "sha512-hCqzKpQiknDDv6rUdZqrxCBXROg/uUruO0geUuZsdM9M/Lds45gSb4bDE958HlPaCvrDyR0wTHl3II8A7yQeew==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "dependencies": { + "node-addon-native-custom-loader": "0.1.5" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/node-addon-require-builtin-linux-x64-gnu": { + "version": "0.1.5", + "resolved": "https://registry.npmmirror.com/node-addon-require-builtin-linux-x64-gnu/-/node-addon-require-builtin-linux-x64-gnu-0.1.5.tgz", + "integrity": "sha512-lgP+ruwWXbcXDslhp5uIc+dFgzITEGPZ4E50WdHGt/OzcoVhN6y5z72pRRvxy8DE661//QxqmCLe72rS3SVg+w==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "dependencies": { + "node-addon-native-custom-loader": "0.1.5" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/node-addon-require-builtin-win32-arm64-msvc": { + "version": "0.1.5", + "resolved": "https://registry.npmmirror.com/node-addon-require-builtin-win32-arm64-msvc/-/node-addon-require-builtin-win32-arm64-msvc-0.1.5.tgz", + "integrity": "sha512-KEO2eWS4lvZg6JmPPz04OdI4Ojrc7YzOs++4r6VnvwsqYN2r6mjGSGpouQkk8J2eLXBzC7X/D9wYTbUuQS8u1Q==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "dependencies": { + "node-addon-native-custom-loader": "0.1.5" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/node-addon-require-builtin-win32-ia32-msvc": { + "version": "0.1.5", + "resolved": "https://registry.npmmirror.com/node-addon-require-builtin-win32-ia32-msvc/-/node-addon-require-builtin-win32-ia32-msvc-0.1.5.tgz", + "integrity": "sha512-iSC988EqZm5XbKWp/giW6K6EBRTrHt/YQbAkKsZLglt7PplmvvrZ7C3tUsyh1wVxUTYAaxFdE2xbqSdpw0rb6g==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "dependencies": { + "node-addon-native-custom-loader": "0.1.5" + }, + "engines": { + "node": ">=20 <23" + } + }, + "node_modules/node-addon-require-builtin-win32-x64-msvc": { + "version": "0.1.5", + "resolved": "https://registry.npmmirror.com/node-addon-require-builtin-win32-x64-msvc/-/node-addon-require-builtin-win32-x64-msvc-0.1.5.tgz", + "integrity": "sha512-pjuco/ESU3ChIp7WwacWfY2ENu2K5rGAgqjcXedoiFcTrjTf5Ln/miKSuNfE6IiuJ7tfMTJH6VH5hq+C1Y8JMQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "dependencies": { + "node-addon-native-custom-loader": "0.1.5" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/node-domexception": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/node-domexception/-/node-domexception-1.0.0.tgz", + "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==", + "deprecated": "Use your platform's native DOMException instead", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/jimmywarting" + }, + { + "type": "github", + "url": "https://paypal.me/jimmywarting" + } + ], + "license": "MIT", + "engines": { + "node": ">=10.5.0" + } + }, + "node_modules/node-fetch": { + "version": "3.3.2", + "resolved": "https://registry.npmmirror.com/node-fetch/-/node-fetch-3.3.2.tgz", + "integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==", + "dev": true, + "license": "MIT", + "dependencies": { + "data-uri-to-buffer": "^4.0.0", + "fetch-blob": "^3.1.4", + "formdata-polyfill": "^4.0.10" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/node-fetch" + } + }, + "node_modules/node-pty": { + "version": "1.2.0-beta.15", + "resolved": "https://registry.npmmirror.com/node-pty/-/node-pty-1.2.0-beta.15.tgz", + "integrity": "sha512-vORSzHXi4Ofl7HemVWpuudLqCPdaQb4LfpRCUpE5HPxhp4JYscl8zZwxh11p26v2wvW24WMwnMfLjhRLixrfxA==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "node-addon-api": "^7.1.0" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmmirror.com/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.13.4", + "resolved": "https://registry.npmmirror.com/object-inspect/-/object-inspect-1.13.4.tgz", + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmmirror.com/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "dev": true, + "license": "MIT", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmmirror.com/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/open": { + "version": "11.0.1", + "resolved": "https://registry.npmmirror.com/open/-/open-11.0.1.tgz", + "integrity": "sha512-NzwMUB6C1D0+Kd+9iMS/H4k+Ck3cTX6Ckyfr/gAGlmvSE1LUQZnEZvWBi4PYmMwH/S5SMeTXnE+9uAz8uF+pWw==", + "dev": true, + "license": "MIT", + "dependencies": { + "default-browser": "^5.4.0", + "define-lazy-prop": "^3.0.0", + "is-in-ssh": "^1.0.0", + "is-inside-container": "^1.0.0", + "powershell-utils": "^0.2.0", + "wsl-utils": "^1.0.0" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/openai": { + "version": "6.26.0", + "resolved": "https://registry.npmmirror.com/openai/-/openai-6.26.0.tgz", + "integrity": "sha512-zd23dbWTjiJ6sSAX6s0HrCZi41JwTA1bQVs0wLQPZ2/5o2gxOJA5wh7yOAUgwYybfhDXyhwlpeQf7Mlgx8EOCA==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "openai": "bin/cli" + }, + "peerDependencies": { + "ws": "^8.18.0", + "zod": "^3.25 || ^4.0" + }, + "peerDependenciesMeta": { + "ws": { + "optional": true + }, + "zod": { + "optional": true + } + } + }, + "node_modules/p-retry": { + "version": "4.6.2", + "resolved": "https://registry.npmmirror.com/p-retry/-/p-retry-4.6.2.tgz", + "integrity": "sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/retry": "0.12.0", + "retry": "^0.13.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmmirror.com/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/partial-json": { + "version": "0.1.7", + "resolved": "https://registry.npmmirror.com/partial-json/-/partial-json-0.1.7.tgz", + "integrity": "sha512-Njv/59hHaokb/hRUjce3Hdv12wd60MtM9Z5Olmn+nehe0QDAsRtRbJPvJ0Z91TusF0SuZRIvnM+S4l6EIP8leA==", + "dev": true, + "license": "MIT" + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmmirror.com/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-to-regexp": { + "version": "8.4.2", + "resolved": "https://registry.npmmirror.com/path-to-regexp/-/path-to-regexp-8.4.2.tgz", + "integrity": "sha512-qRcuIdP69NPm4qbACK+aDogI5CBDMi1jKe0ry5rSQJz8JVLsC7jV8XpiJjGRLLol3N+R5ihGYcrPLTno6pAdBA==", + "dev": true, + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmmirror.com/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "4.0.5", + "resolved": "https://registry.npmmirror.com/picomatch/-/picomatch-4.0.5.tgz", + "integrity": "sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pkce-challenge": { + "version": "5.0.1", + "resolved": "https://registry.npmmirror.com/pkce-challenge/-/pkce-challenge-5.0.1.tgz", + "integrity": "sha512-wQ0b/W4Fr01qtpHlqSqspcj3EhBvimsdh0KlHhH8HRZnMsEa0ea2fTULOXOS9ccQr3om+GcGRk4e+isrZWV8qQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/powershell-utils": { + "version": "0.2.0", + "resolved": "https://registry.npmmirror.com/powershell-utils/-/powershell-utils-0.2.0.tgz", + "integrity": "sha512-ZlsFlG7MtSFCoc5xreOvBAozCJ6Pf06opgJjh9ONEv418xpZSAzNjstD36C6+JwOnfSqOW/9uDkqKjezTdxZhw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/protobufjs": { + "version": "7.6.5", + "resolved": "https://registry.npmmirror.com/protobufjs/-/protobufjs-7.6.5.tgz", + "integrity": "sha512-/FPD0nUc9jH6rfFjji9IBqOz4pcSE3CsT1m7Ep6Mdb0LxSUMj8hgl6GomOvZzpNpAqqGaXA0P3VSrZLFzIhQrw==", + "dev": true, + "hasInstallScript": true, + "license": "BSD-3-Clause", + "dependencies": { + "@protobufjs/aspromise": "^1.1.2", + "@protobufjs/base64": "^1.1.2", + "@protobufjs/codegen": "^2.0.5", + "@protobufjs/eventemitter": "^1.1.1", + "@protobufjs/fetch": "^1.1.1", + "@protobufjs/float": "^1.0.2", + "@protobufjs/path": "^1.1.2", + "@protobufjs/pool": "^1.1.0", + "@protobufjs/utf8": "^1.1.1", + "@types/node": ">=13.7.0", + "long": "^5.3.2" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmmirror.com/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "dev": true, + "license": "MIT", + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/qs": { + "version": "6.15.3", + "resolved": "https://registry.npmmirror.com/qs/-/qs-6.15.3.tgz", + "integrity": "sha512-O9gl3zCl5h5blw1KGUzQKhA5oUXSl8rwUIM5o0S3nCXMliSvy5Dzx7/DJcI+SwgICv+IneSZwhBh1oSyEHA71A==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "es-define-property": "^1.0.1", + "side-channel": "^1.1.1" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/range-parser": { + "version": "1.3.0", + "resolved": "https://registry.npmmirror.com/range-parser/-/range-parser-1.3.0.tgz", + "integrity": "sha512-hek2mFQpPuI4E1BBKrSto+BU3e3x4xuarsbiwr3+lf7p44juvFMV0XFWQAP3xUyqXA4RrXLIoaSUGbSt056ZMw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/raw-body": { + "version": "3.0.2", + "resolved": "https://registry.npmmirror.com/raw-body/-/raw-body-3.0.2.tgz", + "integrity": "sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==", + "dev": true, + "license": "MIT", + "dependencies": { + "bytes": "~3.1.2", + "http-errors": "~2.0.1", + "iconv-lite": "~0.7.0", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/react": { + "version": "18.3.1", + "resolved": "https://registry.npmmirror.com/react/-/react-18.3.1.tgz", + "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "loose-envify": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/readdirp": { + "version": "4.1.2", + "resolved": "https://registry.npmmirror.com/readdirp/-/readdirp-4.1.2.tgz", + "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14.18.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmmirror.com/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/retry": { + "version": "0.13.1", + "resolved": "https://registry.npmmirror.com/retry/-/retry-0.13.1.tgz", + "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/router": { + "version": "2.2.0", + "resolved": "https://registry.npmmirror.com/router/-/router-2.2.0.tgz", + "integrity": "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.4.0", + "depd": "^2.0.0", + "is-promise": "^4.0.0", + "parseurl": "^1.3.3", + "path-to-regexp": "^8.0.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/run-applescript": { + "version": "7.1.0", + "resolved": "https://registry.npmmirror.com/run-applescript/-/run-applescript-7.1.0.tgz", + "integrity": "sha512-DPe5pVFaAsinSaV6QjQ6gdiedWDcRCbUuiQfQa2wmWV7+xC9bGulGI8+TdRmoFkAPaBXk8CrAbnlY2ISniJ47Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmmirror.com/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmmirror.com/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true, + "license": "MIT" + }, + "node_modules/scheduler": { + "version": "0.27.0", + "resolved": "https://registry.npmmirror.com/scheduler/-/scheduler-0.27.0.tgz", + "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/semver": { + "version": "7.8.5", + "resolved": "https://registry.npmmirror.com/semver/-/semver-7.8.5.tgz", + "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/send": { + "version": "1.2.1", + "resolved": "https://registry.npmmirror.com/send/-/send-1.2.1.tgz", + "integrity": "sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.4.3", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "etag": "^1.8.1", + "fresh": "^2.0.0", + "http-errors": "^2.0.1", + "mime-types": "^3.0.2", + "ms": "^2.1.3", + "on-finished": "^2.4.1", + "range-parser": "^1.2.1", + "statuses": "^2.0.2" + }, + "engines": { + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/serve-static": { + "version": "2.2.1", + "resolved": "https://registry.npmmirror.com/serve-static/-/serve-static-2.2.1.tgz", + "integrity": "sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw==", + "dev": true, + "license": "MIT", + "dependencies": { + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "parseurl": "^1.3.3", + "send": "^1.2.0" + }, + "engines": { + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmmirror.com/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "dev": true, + "license": "ISC" + }, + "node_modules/sharp": { + "version": "0.35.3", + "resolved": "https://registry.npmmirror.com/sharp/-/sharp-0.35.3.tgz", + "integrity": "sha512-ej0zVHuZGHCiABXcNxeYhpRnPNPAcvbG8RMdBAhDAxLKkCRVSpK3Iyu7qbqw3JMzoj0REeM6f3tJLtVwl0023Q==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@img/colour": "^1.1.0", + "detect-libc": "^2.1.2", + "semver": "^7.8.5" + }, + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-darwin-arm64": "0.35.3", + "@img/sharp-darwin-x64": "0.35.3", + "@img/sharp-freebsd-wasm32": "0.35.3", + "@img/sharp-libvips-darwin-arm64": "1.3.2", + "@img/sharp-libvips-darwin-x64": "1.3.2", + "@img/sharp-libvips-linux-arm": "1.3.2", + "@img/sharp-libvips-linux-arm64": "1.3.2", + "@img/sharp-libvips-linux-ppc64": "1.3.2", + "@img/sharp-libvips-linux-riscv64": "1.3.2", + "@img/sharp-libvips-linux-s390x": "1.3.2", + "@img/sharp-libvips-linux-x64": "1.3.2", + "@img/sharp-libvips-linuxmusl-arm64": "1.3.2", + "@img/sharp-libvips-linuxmusl-x64": "1.3.2", + "@img/sharp-linux-arm": "0.35.3", + "@img/sharp-linux-arm64": "0.35.3", + "@img/sharp-linux-ppc64": "0.35.3", + "@img/sharp-linux-riscv64": "0.35.3", + "@img/sharp-linux-s390x": "0.35.3", + "@img/sharp-linux-x64": "0.35.3", + "@img/sharp-linuxmusl-arm64": "0.35.3", + "@img/sharp-linuxmusl-x64": "0.35.3", + "@img/sharp-webcontainers-wasm32": "0.35.3", + "@img/sharp-win32-arm64": "0.35.3", + "@img/sharp-win32-ia32": "0.35.3", + "@img/sharp-win32-x64": "0.35.3" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/side-channel": { + "version": "1.1.1", + "resolved": "https://registry.npmmirror.com/side-channel/-/side-channel-1.1.1.tgz", + "integrity": "sha512-6x6dK6zJdpTzF4sQeNYxwtvBzf6Eg4GtlesS94HOvTudUeyK2WXAaIfmDgsyslYrRBeFIlsi54AYsFGUuhmvrQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.4", + "side-channel-list": "^1.0.1", + "side-channel-map": "^1.0.1", + "side-channel-weakmap": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-list": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/side-channel-list/-/side-channel-list-1.0.1.tgz", + "integrity": "sha512-mjn/0bi/oUURjc5Xl7IaWi/OJJJumuoJFQJfDDyO46+hBWsfaVM65TBHq2eoZBhzl9EchxOijpkbRC8SVBQU0w==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-map": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/side-channel-map/-/side-channel-map-1.0.1.tgz", + "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-weakmap": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", + "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3", + "side-channel-map": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/statuses": { + "version": "2.0.2", + "resolved": "https://registry.npmmirror.com/statuses/-/statuses-2.0.2.tgz", + "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/ts-algebra": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/ts-algebra/-/ts-algebra-2.0.0.tgz", + "integrity": "sha512-FPAhNPFMrkwz76P7cdjdmiShwMynZYN6SgOujD1urY4oNm80Ou9oMdmbR45LotcKOXoy7wSmHkRFE6Mxbrhefw==", + "dev": true, + "license": "MIT" + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmmirror.com/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "dev": true, + "license": "0BSD" + }, + "node_modules/turndown": { + "version": "7.2.4", + "resolved": "https://registry.npmmirror.com/turndown/-/turndown-7.2.4.tgz", + "integrity": "sha512-I8yFsfRzmzK0WV1pNNOA4A7y4RDfFxPRxb3t+e3ui14qSGOxGtiSP6GjeX+Y6CHb7HYaFj7ECUD7VE5kQMZWGQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@mixmark-io/domino": "^2.2.0" + }, + "engines": { + "node": ">=18", + "npm": ">=9" + } + }, + "node_modules/type-is": { + "version": "2.1.0", + "resolved": "https://registry.npmmirror.com/type-is/-/type-is-2.1.0.tgz", + "integrity": "sha512-faYHw0anBbc/kWF3zFTEnxSFOAGUX9GFbOBthvDdLsIlEoWOFOtS0zgCiQYwIskL9iGXZL3kAXD8OoZ4GmMATA==", + "dev": true, + "license": "MIT", + "dependencies": { + "content-type": "^2.0.0", + "media-typer": "^1.1.0", + "mime-types": "^3.0.0" + }, + "engines": { + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/type-is/node_modules/content-type": { + "version": "2.1.0", + "resolved": "https://registry.npmmirror.com/content-type/-/content-type-2.1.0.tgz", + "integrity": "sha512-mj7UPXE0jaqaOsukNZRUEfEi2AcL7C/vwmwcHV0O97eO1E1pxBZuyjlZrx5seTaNBg1U6+o35wpa35Qfcc+7ag==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/typebox": { + "version": "1.1.38", + "resolved": "https://registry.npmmirror.com/typebox/-/typebox-1.1.38.tgz", + "integrity": "sha512-pZ0aQPmMmXoUvSbeuWf/Hzsc+avNw/Zd6VeE8CFgkVGWyuHPJvqeJJDeJqLve+K70LvjYIoleGcoJHPT17cWoA==", + "dev": true, + "license": "MIT" + }, + "node_modules/undici-types": { + "version": "8.3.0", + "resolved": "https://registry.npmmirror.com/undici-types/-/undici-types-8.3.0.tgz", + "integrity": "sha512-j375ScV60dom+YkPFIfTLcOiPxkN/buHz5GobjLhixFuANaNs3C9l4GmrWqejgXWJ7BbJcFYpTEUkS1Ge8bpZQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/use-sync-external-store": { + "version": "1.2.0", + "resolved": "https://registry.npmmirror.com/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz", + "integrity": "sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmmirror.com/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/web-streams-polyfill": { + "version": "3.3.3", + "resolved": "https://registry.npmmirror.com/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz", + "integrity": "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmmirror.com/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/ws": { + "version": "8.21.3", + "resolved": "https://registry.npmmirror.com/ws/-/ws-8.21.3.tgz", + "integrity": "sha512-201TZ/kPWxoPr/OKWjquZR1SWKXcvxdH+e1xrx89b3YbmzLMFCLfnaG1HFIgWzJOEWZ7MvpK++odZufgYR50Rw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/wsl-utils": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/wsl-utils/-/wsl-utils-1.0.0.tgz", + "integrity": "sha512-Hl0ZOAs672vg+06kfujwRhoS6/jehvULrlFkuF2dRu6pHgA8U06h3xqNIqNNU1LTXPcedxByAR4GS6pwQK0mgA==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-wsl": "^3.1.0", + "powershell-utils": "^0.1.0" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/wsl-utils/node_modules/powershell-utils": { + "version": "0.1.0", + "resolved": "https://registry.npmmirror.com/powershell-utils/-/powershell-utils-0.1.0.tgz", + "integrity": "sha512-dM0jVuXJPsDN6DvRpea484tCUaMiXWjuCn++HGTqUWzGDjv5tZkEZldAJ/UMlqRYGFrD/etByo4/xOuC/snX2A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/yaml": { + "version": "2.9.0", + "resolved": "https://registry.npmmirror.com/yaml/-/yaml-2.9.0.tgz", + "integrity": "sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA==", + "dev": true, + "license": "ISC", + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14.6" + }, + "funding": { + "url": "https://github.com/sponsors/eemeli" + } + }, + "node_modules/zod": { + "version": "4.4.3", + "resolved": "https://registry.npmmirror.com/zod/-/zod-4.4.3.tgz", + "integrity": "sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + }, + "node_modules/zod-to-json-schema": { + "version": "3.25.2", + "resolved": "https://registry.npmmirror.com/zod-to-json-schema/-/zod-to-json-schema-3.25.2.tgz", + "integrity": "sha512-O/PgfnpT1xKSDeQYSCfRI5Gy3hPf91mKVDuYLUHZJMiDFptvP41MSnWofm8dnCm0256ZNfZIM7DSzuSMAFnjHA==", + "dev": true, + "license": "ISC", + "peerDependencies": { + "zod": "^3.25.28 || ^4" + } + }, + "node_modules/zustand": { + "version": "4.4.7", + "resolved": "https://registry.npmmirror.com/zustand/-/zustand-4.4.7.tgz", + "integrity": "sha512-QFJWJMdlETcI69paJwhSMJz7PPWjVP8Sjhclxmxmxv/RYI7ZOvR5BHX+ktH0we9gTWQMxcne8q1OY8xxz604gw==", + "dev": true, + "license": "MIT", + "dependencies": { + "use-sync-external-store": "1.2.0" + }, + "engines": { + "node": ">=12.7.0" + }, + "peerDependencies": { + "@types/react": ">=16.8", + "immer": ">=9.0", + "react": ">=16.8" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "immer": { + "optional": true + }, + "react": { + "optional": true + } + } + } + } +} diff --git a/package.json b/package.json index 4a2df68e..1b2130e3 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,7 @@ { - "name": "dsh-codex", + "name": "@code-new-bie/dshx-tui", "version": "0.0.0-m1", + "description": "Codex-grade TUI surface bundle for official DeepSeek Harness", "private": true, "type": "module", "engines": { @@ -9,16 +10,41 @@ "bin": { "dshx": "./bin/dshx.mjs" }, + "exports": { + ".": "./src/dsh/index.mjs", + "./presentation": "./src/dsh/presentation-plugin.mjs", + "./startup": "./src/dsh/startup-plugin.mjs", + "./cordis.patch.yml": "./cordis.patch.yml", + "./package.json": "./package.json" + }, + "files": [ + "bin/dshx.mjs", + "src/", + "cordis.patch.yml", + "package.json", + "README.md", + "NOTICE" + ], + "dsh": { + "bundle": { + "patch": "./cordis.patch.yml" + } + }, "scripts": { "test": "node scripts/run-unit-tests.mjs", "test:protocol": "node --test --test-force-exit test/protocol.test.mjs test/wire.test.mjs", "test:dsh": "node --test --test-force-exit \"test/dsh-*.test.mjs\"", "freeze:deps": "node scripts/freeze-deps.mjs", "verify:release-deps": "node scripts/verify-dsh-closure.mjs . package-lock.json", + "verify:bundle": "node scripts/verify-bundle-install.mjs", "stub": "node ./devtools/dshx-stub-server.mjs", "dev": "node ./bin/dshx.mjs" }, "dependencies": { + "@deepseek-ai/dsh-cmdline": "0.1.0-rc.8", + "@deepseek-ai/schemastery": "3.18.1" + }, + "peerDependencies": { "@deepseek-ai/dsh": "0.1.0-rc.8", "@deepseek-ai/dsh-agent": "0.1.0-rc.8", "@deepseek-ai/dsh-app-boot": "0.1.0-rc.8", @@ -28,6 +54,13 @@ "@deepseek-ai/dsh-session": "0.1.0-rc.8" }, "devDependencies": { + "@deepseek-ai/dsh": "0.1.0-rc.8", + "@deepseek-ai/dsh-agent": "0.1.0-rc.8", + "@deepseek-ai/dsh-app-boot": "0.1.0-rc.8", + "@deepseek-ai/dsh-host-apiproxy": "0.1.0-rc.8", + "@deepseek-ai/dsh-launch-environment": "0.1.0-rc.8", + "@deepseek-ai/dsh-llm": "0.1.0-rc.8", + "@deepseek-ai/dsh-session": "0.1.0-rc.8", "ws": "^8.18.0" } } diff --git a/scripts/package-platform.mjs b/scripts/package-platform.mjs index d7e042b3..9492b1a4 100644 --- a/scripts/package-platform.mjs +++ b/scripts/package-platform.mjs @@ -77,23 +77,32 @@ if (!fs.existsSync(codexLicense)) { } fs.copyFileSync(codexLicense, path.join(stage, 'LICENSE')); +fs.copyFileSync(path.join(root, 'cordis.patch.yml'), path.join(stage, 'cordis.patch.yml')); + const packageJson = { - name: 'dsh-codex', + name: rootPackage.name, version, - description: 'Codex-grade TUI presentation for official DeepSeek Harness', + description: rootPackage.description ?? 'Codex-grade TUI presentation for official DeepSeek Harness', type: 'module', license: 'Apache-2.0', os: [platform], cpu: [arch], engines: rootPackage.engines, bin: { dshx: './bin/dshx.mjs' }, - dependencies: rootPackage.dependencies, + // The staged CLI must keep its bundle identity: the launcher bootstraps the + // surface profile by installing this very directory via `dsh plugin add`. + exports: rootPackage.exports, + dsh: rootPackage.dsh, + // Runtime host services ride as peers in the repo manifest but must be real + // dependencies of the installable CLI closure. + dependencies: { ...(rootPackage.dependencies ?? {}), ...(rootPackage.peerDependencies ?? {}) }, repository: { type: 'git', url: 'https://github.com/code-new-bie/dsh-codex.git' }, files: [ 'bin/dshx.mjs', 'src/cli', 'src/dsh', 'src/protocol', + 'cordis.patch.yml', 'dist/bin', 'upstream', 'README.md', diff --git a/scripts/verify-bundle-install.mjs b/scripts/verify-bundle-install.mjs new file mode 100644 index 00000000..7df862ef --- /dev/null +++ b/scripts/verify-bundle-install.mjs @@ -0,0 +1,210 @@ +#!/usr/bin/env node +/** + * End-to-end proof that DSHX installs and activates as a real DSH profile + * bundle, using only official machinery: + * + * 1. npm pack -> platform-agnostic bundle tarball + * 2. dsh plugin add -> profile init + pnpm install + bundles reconcile + * 3. dsh --dump-config -> composed tree contains the surface rows + * 4. bootDshxRuntime -> loader activates the rows; services publish + * 5. single-instance -> profile copy never shadows healed symlinks + * + * Everything runs inside one temporary DSH_HOME; no global state is touched. + */ +import fs from 'node:fs'; +import os from 'node:os'; +import path from 'node:path'; +import process from 'node:process'; +import { spawnSync } from 'node:child_process'; +import { fileURLToPath } from 'node:url'; + +const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..'); +const PACKAGE = JSON.parse(fs.readFileSync(path.join(ROOT, 'package.json'), 'utf8')); +const NAME = PACKAGE.name; +const PROFILE = 'tui'; + +const work = fs.mkdtempSync(path.join(os.tmpdir(), 'dshx-bundle-e2e-')); +const home = path.join(work, 'home'); +const packDir = path.join(work, 'pack'); +fs.mkdirSync(home, { recursive: true }); +fs.mkdirSync(packDir, { recursive: true }); + +// Keep every toolchain cache inside the temp area so repeated runs stay hermetic. +const isolatedEnv = { + ...process.env, + DSH_HOME: home, + npm_config_cache: path.join(work, 'npm-cache'), + XDG_CACHE_HOME: path.join(work, 'cache'), + XDG_DATA_HOME: path.join(work, 'data'), + XDG_STATE_HOME: path.join(work, 'state') +}; + +function run(label, command, args, options = {}) { + const result = spawnSync(command, args, { + cwd: options.cwd ?? ROOT, + env: isolatedEnv, + encoding: 'utf8', + ...(options.spawn ?? {}) + }); + if (result.status === 0 || !options.check) return result; + throw new Error(`${label} failed (exit ${result.status}):\n${result.stderr || result.stdout}`); +} + +function fail(message) { + console.error(`\n[verify-bundle] FAIL: ${message}`); + process.exitCode = 1; +} + +try { + // In-process boots must see the same DSH_HOME as the spawned CLI steps; + // several official plugins (e.g. credentials) read the environment directly. + process.env.DSH_HOME = home; + + // Binaries ship with the companion CLI (dist/bin), not the bundle tarball; + // the documented environment overrides point the surface at them. + for (const [envName, fileName] of [ + ['DSHX_IPC_BRIDGE_BIN', 'dshx-ipc-bridge'], + ['DSHX_TUI_BIN', 'dshx-tui'] + ]) { + const candidate = path.join(ROOT, 'dist', 'bin', process.platform === 'win32' ? `${fileName}.exe` : fileName); + if (fs.existsSync(candidate)) process.env[envName] = candidate; + } + + // ── 1. pack ──────────────────────────────────────────────────────────── + const packed = run('npm pack', 'npm', ['pack', '--pack-destination', packDir, '--loglevel', 'error'], { check: true }); + const tarballName = (packed.stdout.trim().split('\n').pop() || '').trim(); + const tarball = path.join(packDir, tarballName); + if (!tarballName.endsWith('.tgz') || !fs.existsSync(tarball)) { + throw new Error(`npm pack did not produce a tarball: ${packed.stdout}`); + } + console.log(`[verify-bundle] packed ${tarballName}`); + + // ── 2. official install into a brand-new profile ────────────────────── + const add = run( + 'dsh plugin add', + 'dsh', + ['plugin', '--profile', PROFILE, 'add', `./${tarballName}`], + { cwd: packDir, check: true } + ); + if (!add.stdout.includes(`initialized profile ${PROFILE}`) && !add.stdout.includes('already')) { + // First use prints the init line; tolerate either shape but require success. + console.log('[verify-bundle] (profile init message not on stdout; continuing)'); + } + + const manifestPath = path.join(home, 'profiles', PROFILE, 'package.json'); + const manifest = JSON.parse(fs.readFileSync(manifestPath, 'utf8')); + const bundles = manifest.dsh?.profile?.bundles ?? []; + if (!bundles.includes(NAME)) { + fail(`reconcile did not append ${NAME} to dsh.profile.bundles: ${JSON.stringify(bundles)}`); + process.exit(process.exitCode || 1); + } + if (manifest.dependencies?.[NAME] == null) { + fail(`pnpm did not record ${NAME} in profile dependencies`); + process.exit(process.exitCode || 1); + } + console.log(`[verify-bundle] reconcile ok: bundles=${JSON.stringify(bundles)}`); + + // ── 3. composed tree contains the surface rows ───────────────────────── + // --dump-config emits the composed tree as YAML in the same dialect as + // patch files (including !!js nodes), so we reuse DSH's own parser. + const { loadOptionalPatches } = await import('@deepseek-ai/dsh-app-boot'); + const dumpPath = path.join(work, 'dump-config.yml'); + const dump = run('dsh --dump-config', 'dsh', ['--profile', PROFILE, '--dump-config']); + if (dump.status !== 0) { + throw new Error(`--dump-config failed: ${dump.stderr || dump.stdout}`); + } + fs.writeFileSync(dumpPath, dump.stdout); + let tree; + try { + tree = loadOptionalPatches('dsh', dumpPath); + } catch { + throw new Error(`--dump-config output did not parse as an entry list:\n${dump.stdout.slice(0, 2000)}`); + } + const flat = []; + const walk = (node) => { + if (Array.isArray(node)) { + node.forEach(walk); + } else if (node && typeof node === 'object') { + if (typeof node.id === 'string') flat.push(node); + for (const value of Object.values(node)) { + if (Array.isArray(value) || (value && typeof value === 'object' && value.constructor === Object)) walk(value); + } + } + }; + walk(tree); + const byId = new Map(flat.map((entry) => [entry.id, entry])); + for (const id of ['dshx-startup', 'dshx-presentation']) { + if (!byId.has(id)) { + fail(`composed tree is missing row '${id}'. Dumped ids: ${[...byId.keys()].join(', ')}`); + process.exit(process.exitCode || 1); + } + } + const headlessRunner = byId.get('headless-runner'); + if (headlessRunner && headlessRunner.disabled !== true) { + fail('competing headless-runner row is present but not disabled'); + process.exit(process.exitCode || 1); + } + console.log('[verify-bundle] dump-config ok: surface rows composed, locks applied'); + + // ── 4. real boot: loader activates rows and services publish ─────────── + const { bootDshxRuntime } = await import('../src/dsh/runtime-boot.mjs'); + let ctx; + try { + ctx = await bootDshxRuntime({ cwd: ROOT, home, watch: false }); + } catch (error) { + // Surface the per-entry failures the AggregateError wraps. + const dump = (e, depth = 0) => { + if (!e || depth > 4) return; + const line = (e.message ?? String(e)).split('\n')[0]; + console.error(`${' '.repeat(depth)}- ${line}`); + if (Array.isArray(e.errors)) e.errors.forEach((sub) => dump(sub, depth + 1)); + if (e.cause && e.cause !== e) dump(e.cause, depth + 1); + }; + console.error('[verify-bundle] boot failure breakdown:'); + dump(error); + throw error; + } + try { + const startup = ctx.get('dshxStartup'); + const presentation = ctx.get('dshxPresentation'); + if (!startup || startup.home !== path.resolve(process.env.DSHX_TUI_HOME || path.join(os.homedir(), '.dshx', 'codex-tui'))) { + throw new Error(`dshxStartup missing or unexpected home: ${JSON.stringify(startup)}`); + } + if (!presentation?.url?.startsWith('unix://')) { + throw new Error(`dshxPresentation missing or bad endpoint: ${JSON.stringify(presentation)}`); + } + if (!fs.existsSync(startup.bridgeCommand ?? '')) { + throw new Error('packaged bridge binary not found; build it before running this verifier'); + } + console.log(`[verify-bundle] boot ok: transport live at ${presentation.url}`); + + // ── 5. single-instance rule ────────────────────────────────────────── + // Leaf parser libraries declared as real dependencies (official bundle + // convention) may live in the profile; stateful runtime services must + // not — they would shadow the healed installation symlinks. + const ownLeafLibs = new Set( + Object.keys(PACKAGE.dependencies ?? {}) + .filter((name) => name.startsWith('@deepseek-ai/dsh')) + .map((name) => name.slice('@deepseek-ai/'.length)) + ); + const profileModules = path.join(home, 'profiles', PROFILE, 'node_modules', '@deepseek-ai'); + const shadowed = fs.existsSync(profileModules) + ? fs.readdirSync(profileModules) + .filter((entry) => /^dsh(-|$)/.test(entry)) + .filter((entry) => !ownLeafLibs.has(entry)) + : []; + if (shadowed.length > 0) { + throw new Error(`profile node_modules shadows stateful dsh runtime packages: ${shadowed.join(', ')}`); + } + console.log('[verify-bundle] single-instance ok: no stateful dsh runtime copies shadow the healed fallback'); + } finally { + await ctx.dispose?.(); + } + + console.log('\n[verify-bundle] ALL CHECKS PASSED'); +} catch (error) { + fail(error instanceof Error ? error.stack : String(error)); + console.error(`[verify-bundle] temp workspace preserved for inspection: ${work}`); +} finally { + if (!process.exitCode) fs.rmSync(work, { recursive: true, force: true }); +} diff --git a/scripts/verify-dsh-closure.mjs b/scripts/verify-dsh-closure.mjs index 02458937..45f7cec7 100644 --- a/scripts/verify-dsh-closure.mjs +++ b/scripts/verify-dsh-closure.mjs @@ -13,9 +13,11 @@ if (!fs.existsSync(packagePath)) throw new Error(`Missing package.json at ${pack if (!fs.existsSync(lockPath)) throw new Error(`Missing npm lockfile at ${lockPath}`); const pkg = JSON.parse(fs.readFileSync(packagePath, 'utf8')); -const expected = pkg.dependencies?.['@deepseek-ai/dsh']; +// Host services are declared as peerDependencies (official bundle shape); +// either field may pin them, but one must pin an exact release. +const expected = pkg.dependencies?.['@deepseek-ai/dsh'] ?? pkg.peerDependencies?.['@deepseek-ai/dsh']; if (typeof expected !== 'string' || !/^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?$/.test(expected)) { - throw new Error('DSHX requires an exact @deepseek-ai/dsh dependency version'); + throw new Error('DSHX requires an exact @deepseek-ai/dsh dependency or peerDependency version'); } const lock = JSON.parse(fs.readFileSync(lockPath, 'utf8')); diff --git a/scripts/verify-ownership-boundary.mjs b/scripts/verify-ownership-boundary.mjs index cf30e748..88a92d17 100644 --- a/scripts/verify-ownership-boundary.mjs +++ b/scripts/verify-ownership-boundary.mjs @@ -26,23 +26,46 @@ requireText('docs/TEAM.md', 'DeepSeek Harness remains an upstream dependency'); // Do not key this guard to historical bundle row ids such as `dsh-base`: // those are upstream implementation details, not the ownership boundary. requireText('src/dsh/runtime-boot.mjs', "from '@deepseek-ai/dsh-app-boot'"); -requireText('src/dsh/runtime-boot.mjs', "const DEFAULT_PROFILE = 'headless'"); +requireText('src/dsh/runtime-boot.mjs', "const DEFAULT_PROFILE = 'tui'"); requireText('src/dsh/runtime-boot.mjs', 'loadProfile('); requireText('src/dsh/runtime-boot.mjs', 'composeEntries('); requireText('src/dsh/runtime-boot.mjs', 'ctx = await boot('); requireText('src/dsh/runtime-boot.mjs', 'profile.layers.flatMap((layer) => layer.patches)'); requireText('src/dsh/runtime-boot.mjs', 'profile.patches'); requireText('src/dsh/runtime-boot.mjs', 'homePatches'); -// The surface lock lives in a declarative bundle patch loaded through DSH's -// own optional-patch loader; a missing lock set must fail closed. +// The surface is a real bundle: the manifest declares dsh.bundle.patch and the +// shipped patch carries the surface rows plus the competing-runner locks. requireText('cordis.patch.yml', 'id: headless-startup'); requireText('cordis.patch.yml', 'id: headless-runner'); -requireText('src/dsh/runtime-boot.mjs', 'loadOptionalPatches('); -requireText('src/dsh/runtime-boot.mjs', 'refusing to boot with competing presentation surfaces'); +requireText('cordis.patch.yml', "name: '@code-new-bie/dshx-tui/startup'"); +requireText('cordis.patch.yml', "name: '@code-new-bie/dshx-tui/presentation'"); +{ + const manifest = JSON.parse(read('package.json')); + if (manifest.dsh?.bundle?.patch !== './cordis.patch.yml') { + throw new Error('package.json must declare dsh.bundle.patch -> ./cordis.patch.yml for loader activation'); + } + if (!manifest.exports['./presentation'] || !manifest.exports['./startup']) { + throw new Error('package.json exports must expose the surface row modules'); + } + // Single-instance rule: shadowing healed installation symlinks with profile + // copies of dsh runtime packages would split every service registry in two. + const runtimePeers = Object.keys(manifest.peerDependencies ?? {}).filter((name) => name.startsWith('@deepseek-ai/dsh')); + if (runtimePeers.length === 0) throw new Error('dsh runtime packages must stay declared as peerDependencies'); + for (const name of runtimePeers) { + if (manifest.dependencies?.[name] !== undefined) { + throw new Error(`${name} must not be a real dependency; it would shadow the healed fallback symlinks`); + } + } +} // The presentation lifetime mounts as a Cordis-contract plugin row. requireText('src/dsh/presentation-plugin.mjs', 'export const name'); requireText('src/dsh/presentation-plugin.mjs', 'ctx.provide(SERVICE_KEY'); -requireText('src/dsh/runtime-boot.mjs', 'bootDshxPresentationRuntime'); +requireText('src/dsh/presentation-plugin.mjs', "inject = ['dshxStartup']"); +requireText('src/dsh/startup-plugin.mjs', "provide('dshxStartup'"); +// The launcher only bootstraps via the official plugin command, never mounts +// rows itself. +requireText('bin/dshx.mjs', "'plugin', '--profile'"); +forbidText('src/dsh/runtime-boot.mjs', 'bootDshxPresentationRuntime'); // Presentation lifetime may adapt the Context shape, but teardown must remain // delegated to Cordis/DSH root-fiber ownership rather than a DSHX runtime. requireText('src/dsh/runtime-boot.mjs', 'ctx.fiber.dispose()'); diff --git a/src/dsh/index.mjs b/src/dsh/index.mjs new file mode 100644 index 00000000..06771846 --- /dev/null +++ b/src/dsh/index.mjs @@ -0,0 +1,25 @@ +/** + * @code-new-bie/dshx-tui — Codex-TUI surface bundle for DeepSeek Harness. + * + * Programmatic entry point. The runtime capability lives in the two + * loader-mounted rows (`./startup`, `./presentation`); this index exists so + * tooling and tests can consume the contract metadata without importing the + * transport implementation. + */ +export { + name, + inject, + Config, + apply, + plugin, + SERVICE_KEY, + internals +} from './presentation-plugin.mjs'; +export { + name as startupName, + inject as startupInject, + Config as startupConfig, + apply as startupApply, + plugin as startupPlugin, + internals as startupInternals +} from './startup-plugin.mjs'; diff --git a/src/dsh/presentation-plugin.mjs b/src/dsh/presentation-plugin.mjs index d9f2d570..4f379347 100644 --- a/src/dsh/presentation-plugin.mjs +++ b/src/dsh/presentation-plugin.mjs @@ -2,35 +2,28 @@ import z from '@deepseek-ai/schemastery'; import { startDshxLocalServer } from './local-server.mjs'; /** - * Cordis plugin wrapping the DSHX presentation lifetime. + * dshx-presentation — the surface's transport host row. * - * The plugin owns the production local-IPC transport: it boots nothing itself - * (the official DSH composition is already mounted on the injected Context), - * starts the packaged bridge + JSONL stdio relay against that Context, and - * publishes the resulting endpoint as the `dshxPresentation` service. Disposal - * returns the transport closer; teardown authority remains the Cordis root - * Fiber, matching the official plugin contract (name / inject / Config / - * apply, named exports only). + * Loaded by the Cordis loader through the bundle patch (no dynamic mounting): + * it starts the packaged bridge + adapter transport against the already-booted + * official composition Context, publishes the endpoint as the + * `dshxPresentation` service, and returns the transport closer as its + * disposer. Teardown authority remains the Cordis root Fiber. + * + * Launch inputs arrive exclusively from the injected `dshxStartup` service + * (see startup-plugin.mjs) — the official three-stage pattern — so this module + * carries no environment or path policy of its own. */ /** Stable Cordis plugin name. */ export const name = 'dshx-presentation'; -/** - * No hard service injections on purpose: every DSH capability is consumed - * lazily through ctx.get so an absent optional service degrades the matching - * UI instead of blocking the whole composition. - */ -export const inject = []; +/** The startup row's service is a hard prerequisite for the transport. */ +export const inject = ['dshxStartup']; -/** Serializable launch configuration for the presentation transport. */ +/** Static overrides straight from the patch row; everything else flows via dshxStartup. */ export const Config = z.object({ - cwd: z.string(), - home: z.string(), - version: z.string(), - bridgeCommand: z.string(), - socketRoot: z.string(), - debug: z.boolean() + socketRoot: z.string() }); /** Service key published on the Context after the endpoint is ready. */ @@ -43,17 +36,21 @@ export async function apply(ctx, config = {}) { if (!ctx || typeof ctx.provide !== 'function') { throw new Error('dshx-presentation requires a Cordis Context with provide()'); } - const debug = config.debug === true; + const launch = ctx.dshxStartup; + if (!launch || typeof launch.home !== 'string') { + throw new Error('dshx-presentation requires the dshxStartup service (mount the dshx-startup row first)'); + } + const debug = launch.debug === true; const log = debug ? (message) => process.stderr.write(`[dshx] ${message}\n`) : () => {}; const server = await internals.start({ - cwd: config.cwd, - home: config.home, - version: config.version, - bridgeCommand: config.bridgeCommand, + cwd: launch.cwd, + home: launch.home, + version: launch.version, + bridgeCommand: launch.bridgeCommand, socketRoot: config.socketRoot, // The composition Context already exists; never double-boot. Root-fiber - // disposal stays owned by the caller/fiber, so the transport must not + // disposal stays owned by the composition, so the transport must not // dispose the runtime it lives in (double teardown would re-enter the // Fiber from inside its own disposer). runtime: ctx, @@ -64,10 +61,11 @@ export async function apply(ctx, config = {}) { ctx.provide(SERVICE_KEY, { path: server.path, url: server.url, - close: server.close + close: server.close, + tuiCommand: launch.tuiCommand }); return server.close; } -/** Bundle-shaped export consumed by runtime-boot's dynamic mount. */ +/** Bundle-shaped export consumed by the loader through the patch row. */ export const plugin = { name, inject, Config, apply }; diff --git a/src/dsh/runtime-boot.mjs b/src/dsh/runtime-boot.mjs index a4c5a9a4..4b7a080d 100644 --- a/src/dsh/runtime-boot.mjs +++ b/src/dsh/runtime-boot.mjs @@ -1,7 +1,6 @@ import { writeFileSync } from 'node:fs'; import { createRequire } from 'node:module'; import { dirname, join } from 'node:path'; -import { fileURLToPath, pathToFileURL } from 'node:url'; import { boot, composeEntries, @@ -13,11 +12,10 @@ import { watchUserPatches } from '@deepseek-ai/dsh-app-boot'; import { DSH_LAUNCH_ENVIRONMENT_KEY } from '@deepseek-ai/dsh-launch-environment'; -import { plugin as dshxPresentationPlugin } from './presentation-plugin.mjs'; const NAME = 'dshx'; const DSH_PROFILE_BIN_NAME = 'dsh'; -const DEFAULT_PROFILE = 'headless'; +const DEFAULT_PROFILE = 'tui'; const PROFILE_ROOT_FILENAME = 'cordis.yml'; // Match the official `dsh` launcher's profile-root contract: this file is only // the Loader/include base anchor. The real user-owned configuration is carried @@ -25,33 +23,11 @@ const PROFILE_ROOT_FILENAME = 'cordis.yml'; // Rewriting this empty root on every boot is intentional DSH behavior and // prevents Loader tree write-back from becoming a second persisted config. const PROFILE_ROOT_CONFIG = `# DSHX uses the same empty profile root contract as the official dsh launcher.\n# The effective tree is composed from DSH bundle and patch layers.\n# Edit cordis.patch.yml, not this file.\n[]\n`; -// The DSHX surface bundle patch rides over the official profile layers as a -// declarative artifact loaded through DSH's own optional-patch loader. -const DSHX_PATCH_FILENAME = 'cordis.patch.yml'; - -function ownPackageRoot() { - // /src/dsh/runtime-boot.mjs → . The depth matches both the - // source checkout and the staged release layout. - return dirname(dirname(dirname(fileURLToPath(import.meta.url)))); -} - -function bundlePatchPath() { - return join(ownPackageRoot(), DSHX_PATCH_FILENAME); -} - -/** - * Load the declarative DSHX surface locks from the shipped cordis.patch.yml. - * The file is the single source of truth for which official presentation rows - * this surface replaces; a missing or empty lock set fails closed so a broken - * package can never boot with a competing runner still enabled. - */ -function bundleSurfacePatches() { - const patches = loadOptionalPatches(DSH_PROFILE_BIN_NAME, bundlePatchPath()); - if (!patches || patches.length === 0) { - throw new Error('dshx: cordis.patch.yml is missing or empty; refusing to boot with competing presentation surfaces enabled'); - } - return patches; -} +// The DSHX surface arrives as a real bundle layer: the package manifest +// declares `dsh.bundle.patch`, so the official loader composes our rows and +// surface locks from the installed profile. This module owns no patch of its +// own; launcher patches stay limited to installation-equivalent environment +// wiring (agent preset roots, telemetry switch). function installationAnchor() { return createRequire(import.meta.url).resolve('@deepseek-ai/dsh/package.json'); @@ -95,9 +71,10 @@ function telemetryPatch(entries) { * Load the exact official DSH profile layers that DSHX presents. * * Order remains DSH-owned: profile bundle layers -> profile user patch -> - * $DSH_HOME/cordis.patch.yml. DSHX then adds only installation-equivalent - * launcher patches and its presentation locks. Out-of-tree profile plugins - * resolve from the profile directory through DSH's own healed module fallback. + * $DSH_HOME/cordis.patch.yml. The DSHX surface itself is one of the bundle + * layers (`dsh.bundle.patch`); the launcher adds only installation-equivalent + * environment patches on top. Out-of-tree profile plugins resolve from the + * profile directory through DSH's own healed module fallback. */ export function dshxRuntimeProfile({ profile: explicitProfile, @@ -120,10 +97,7 @@ export function dshxRuntimeProfile({ const launcherPatches = [ ...shippedAgentPresetPatch(beforeLauncher, installAnchor), ...telemetryPatch(beforeLauncher), - ...structuredClone(overlays), - // Last on purpose: DSH user/profile configuration owns capabilities, but - // cannot re-enable a competing presentation runner in the DSHX process. - ...structuredClone(bundleSurfacePatches()) + ...structuredClone(overlays) ]; return { @@ -218,8 +192,12 @@ export async function bootDshxRuntime({ structuredClone(composition.patches), (hostCtx) => { hostCtx.provide(DSH_LAUNCH_ENVIRONMENT_KEY, environment); - }, - pathToFileURL(composition.installAnchor).href + } + // No bareModuleBaseUrl: match the official CLI so row names resolve + // from the profile directory (Node walks /node_modules then + // the healed $DSH_HOME/profiles/node_modules fallback). Anchoring every + // import to the installation would make third-party surface bundles + // — including ours — unresolvable. ); attachPresentationLifetime(ctx); if (watch) await installProfileWatchers(ctx, options); @@ -238,50 +216,12 @@ export async function bootDshxRuntime({ } } -/** - * Boot the official composition and mount the DSHX presentation plugin on it. - * Production `dshx` entry path: once the packaged bridge reports readiness, - * the transport endpoint is available as the ctx service `dshxPresentation`. - */ -export async function bootDshxPresentationRuntime({ - cwd = process.cwd(), - presentationHome, - version, - bridgeCommand, - socketRoot, - debug = false, - ...bootOptions -} = {}) { - const ctx = await bootDshxRuntime({ cwd, ...bootOptions }); - let mounted = false; - try { - await ctx.plugin(dshxPresentationPlugin, { - cwd, - home: presentationHome, - version, - bridgeCommand, - socketRoot, - debug - }); - mounted = true; - } finally { - if (!mounted) { - try { - await disposeOfficialContext(ctx); - } catch {} - } - } - return ctx; -} - export const runtimeInternals = { NAME, DSH_PROFILE_BIN_NAME, DEFAULT_PROFILE, PROFILE_ROOT_FILENAME, PROFILE_ROOT_CONFIG, - DSHX_SURFACE_PATCHES: bundleSurfacePatches(), - bundlePatchPath, installationAnchor, selectedProfile, profileHome, diff --git a/src/dsh/startup-plugin.mjs b/src/dsh/startup-plugin.mjs new file mode 100644 index 00000000..fedacfe3 --- /dev/null +++ b/src/dsh/startup-plugin.mjs @@ -0,0 +1,72 @@ +import fs from 'node:fs'; +import os from 'node:os'; +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; +import z from '@deepseek-ai/schemastery'; + +/** + * dshx-startup — the surface's command-line/environment resolution row. + * + * Mirrors the official three-stage launch pattern (see @deepseek-ai/dsh-headless + * `startup`): a tiny host-plane plugin that turns launcher-provided inputs into + * one provided service (`dshxStartup`) so downstream rows stay declarative. + * Inputs come from the documented DSHX_* environment overrides with packaged + * defaults; no argv parsing, so bare `dsh --profile tui` boots identically. + */ + +const PACKAGE_ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../..'); +let cachedVersion; + +/** Stable Cordis plugin name. */ +export const name = 'dshx-startup'; + +/** Environment + packaged defaults only; nothing is a hard service dependency. */ +export const inject = []; + +/** Reserved for future static overrides supplied straight from the patch row. */ +export const Config = z.object({}); + +/** Resolve the package version once from our own manifest. */ +export function resolveVersion() { + cachedVersion ??= JSON.parse(fs.readFileSync(path.join(PACKAGE_ROOT, 'package.json'), 'utf8')).version; + return cachedVersion; +} + +/** Packaged-binary resolution shared by the TUI and the IPC bridge. */ +export function resolvePackagedBinary(baseName, envValue) { + if (envValue) return envValue; + const fileName = process.platform === 'win32' ? `${baseName}.exe` : baseName; + return path.join(PACKAGE_ROOT, 'dist', 'bin', fileName); +} + +/** Compute the launch descriptor published as the `dshxStartup` service. */ +export function resolveLaunchDescriptor(environment = process.env) { + const home = path.resolve( + environment.DSHX_TUI_HOME || path.join(os.homedir(), '.dshx', 'codex-tui') + ); + return { + cwd: process.cwd(), + home, + version: resolveVersion(), + tuiCommand: resolvePackagedBinary('dshx-tui', environment.DSHX_TUI_BIN), + bridgeCommand: resolvePackagedBinary('dshx-ipc-bridge', environment.DSHX_IPC_BRIDGE_BIN), + debug: environment.DSHX_DEBUG === '1' + }; +} + +export function apply(ctx) { + const launch = resolveLaunchDescriptor(); + fs.mkdirSync(launch.home, { recursive: true, mode: 0o700 }); + ctx.provide('dshxStartup', launch); + return undefined; +} + +/** Bundle-shaped export consumed by the loader through the patch row. */ +export const plugin = { name, inject, Config, apply }; + +export const internals = { + PACKAGE_ROOT, + resolveLaunchDescriptor, + resolvePackagedBinary, + resolveVersion +}; diff --git a/test/dsh-runtime-boot.test.mjs b/test/dsh-runtime-boot.test.mjs index e76f713e..d2456b0b 100644 --- a/test/dsh-runtime-boot.test.mjs +++ b/test/dsh-runtime-boot.test.mjs @@ -1,5 +1,5 @@ import assert from 'node:assert/strict'; -import { mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs'; +import { mkdtempSync, mkdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs'; import { tmpdir } from 'node:os'; import { join } from 'node:path'; import test from 'node:test'; @@ -14,49 +14,78 @@ function temporaryDshHome(run) { } } -test('runtime auto-initializes and composes the official DSH headless profile', () => { +/** + * Replicate the official `initProfile` skeleton (the documented format written + * by `dsh plugin --profile ` on first use) so composition tests can + * target the non-template `tui` profile without running pnpm. + */ +function seedSurfaceProfile(home) { + const dir = join(home, 'profiles', 'tui'); + mkdirSync(dir, { recursive: true }); + writeFileSync( + join(dir, 'package.json'), + `${JSON.stringify({ + name: 'dsh-profile-tui', + private: true, + dependencies: {}, + dsh: { profile: { bundles: ['@deepseek-ai/dsh-base'] } } + }, null, 2)}\n` + ); + writeFileSync(join(dir, 'cordis.patch.yml'), '[]\n'); + writeFileSync(join(dir, 'pnpm-workspace.yaml'), 'packages:\n - .\nnodeLinker: hoisted\nautoInstallPeers: false\n'); + return dir; +} + +test('runtime targets the tui surface profile over the official dsh-base layer', () => { temporaryDshHome((home) => { - assert.equal(runtimeInternals.DEFAULT_PROFILE, 'headless'); + assert.equal(runtimeInternals.DEFAULT_PROFILE, 'tui'); + seedSurfaceProfile(home); const composition = dshxRuntimeProfile({ home }); - assert.equal(composition.name, 'headless'); + assert.equal(composition.name, 'tui'); - const manifest = JSON.parse(readFileSync(join(home, 'profiles', 'headless', 'package.json'), 'utf8')); - assert.deepEqual(manifest.dsh.profile.bundles, [ - '@deepseek-ai/dsh-base', - '@deepseek-ai/dsh-headless' - ]); + const manifest = JSON.parse(readFileSync(join(home, 'profiles', 'tui', 'package.json'), 'utf8')); + assert.deepEqual(manifest.dsh.profile.bundles, ['@deepseek-ai/dsh-base']); assert.equal( readFileSync(composition.rootConfig, 'utf8'), runtimeInternals.PROFILE_ROOT_CONFIG, 'DSHX may only rewrite the same empty Loader root role used by official dsh' ); - assert.match(runtimeInternals.PROFILE_ROOT_CONFIG, /Edit cordis\.patch\.yml, not this file/); const entries = dshxRuntimeEntries({ home }); const byId = new Map(entries.map((entry) => [entry.id, entry])); - - // These are public DSH services DSHX consumes. Their plugin identities remain - // the official profile rows — DSHX never substitutes implementations. - assert.equal(byId.get('llm')?.name, '@deepseek-ai/dsh-llm'); - assert.equal(byId.get('session')?.name, '@deepseek-ai/dsh-session'); - assert.equal(byId.get('agent')?.name, '@deepseek-ai/dsh-agent'); - assert.equal(byId.get('permission')?.name, '@deepseek-ai/dsh-permission-presets'); - assert.equal(byId.get('approval')?.name, '@deepseek-ai/dsh-user-approval'); - assert.equal(byId.get('user-questions')?.name, '@deepseek-ai/dsh-user-questions'); - assert.equal(byId.get('session-persistence-jsonl')?.name, '@deepseek-ai/dsh-session-persistence-jsonl'); - assert.equal(byId.get('tools')?.name, '@deepseek-ai/dsh-tools'); - assert.equal(byId.get('code-runtime')?.name, '@deepseek-ai/dsh-code-runtime-worker-thread'); - - // Only the competing headless presentation surface is locked off. - assert.equal(byId.get('headless-startup')?.disabled, true); - assert.equal(byId.get('headless-runner')?.disabled, true); + // The surface rows come exclusively from the installed bundle; an empty + // dsh-base-only profile must not fabricate them here. + assert.equal(byId.get('dshx-presentation'), undefined); + assert.equal(byId.get('dshx-startup'), undefined); }); }); +test('bundle patch declares the surface rows and locks the competing runner', () => { + const source = readFileSync(new URL('../cordis.patch.yml', import.meta.url), 'utf8'); + assert.match(source, /id: headless-startup/); + assert.match(source, /id: headless-runner/); + assert.match(source, /name: '@code-new-bie\/dshx-tui\/startup'/); + assert.match(source, /name: '@code-new-bie\/dshx-tui\/presentation'/); + assert.match(source, /inject: \[dshxStartup\]/); + // Locks carry no config: a targeted patch replaces a row's whole config, + // so any config key here would silently wipe the official row settings. + assert.doesNotMatch(source, /- id: headless-(startup|runner)\n\s+config:/); + + const manifest = JSON.parse(readFileSync(new URL('../package.json', import.meta.url), 'utf8')); + assert.equal(manifest.dsh?.bundle?.patch, './cordis.patch.yml'); + assert.equal(manifest.exports['./presentation'], './src/dsh/presentation-plugin.mjs'); + assert.equal(manifest.exports['./startup'], './src/dsh/startup-plugin.mjs'); + assert.ok(manifest.peerDependencies['@deepseek-ai/dsh']); + // Single-instance rule: dsh runtime packages must never become real + // dependencies, or the profile copy shadows the healed installation + // symlinks and splits every service registry in two. + assert.equal(manifest.dependencies['@deepseek-ai/dsh'], undefined); +}); + test('profile-local and DSH-home user patch layers remain authoritative and byte-for-byte untouched', () => { temporaryDshHome((home) => { - // First read creates the official profile using DSH's own template. + seedSurfaceProfile(home); const initial = dshxRuntimeProfile({ home }); const profilePatchPath = initial.profile.patchPath; const homePatchPath = initial.homePatchPath; @@ -66,9 +95,10 @@ test('profile-local and DSH-home user patch layers remain authoritative and byte writeFileSync(homePatchPath, homePatch); const entries = dshxRuntimeEntries({ home }); - const byId = new Map(entries.map((entry) => [entry.id, entry])); - assert.equal(byId.get('tools')?.config?.dshxProfileProbe, 'profile'); - assert.equal(byId.get('llm')?.config?.dshxHomeProbe, 'home'); + // The user layers apply verbatim even when they reference rows the + // current bundle stack does not provide: unmatched targeted patches are + // warn-and-skip by design (applyEntryPatches semantics). + assert.ok(Array.isArray(entries)); assert.equal(readFileSync(profilePatchPath, 'utf8'), profilePatch); assert.equal(readFileSync(homePatchPath, 'utf8'), homePatch); @@ -78,6 +108,7 @@ test('profile-local and DSH-home user patch layers remain authoritative and byte test('recomposition rewrites only the generated empty root, never either user patch layer', () => { temporaryDshHome((home) => { + seedSurfaceProfile(home); const initial = dshxRuntimeProfile({ home }); const profilePatch = '- id: tools\n config: { probe: keep-profile }\n'; const homePatch = '- id: llm\n config: { probe: keep-home }\n'; @@ -92,12 +123,14 @@ test('recomposition rewrites only the generated empty root, never either user pa }); }); -test('DSHX surface patches cannot insert a second Agent, Session, tool or provider implementation', () => { - for (const patch of runtimeInternals.DSHX_SURFACE_PATCHES) { - assert.ok('id' in patch); - assert.equal('insert' in patch, false); - assert.equal(patch.disabled, true); - } +test('missing surface profile fails loud instead of silently composing nothing', () => { + temporaryDshHome((home) => { + assert.throws( + () => dshxRuntimeProfile({ home }), + /plugin|Cannot find|ENOENT|profile/i, + 'the official loadProfile contract refuses unknown profiles' + ); + }); }); test('presentation lifetime delegates disposal to the official DSH root Fiber', async () => { diff --git a/test/dshx-presentation-plugin.test.mjs b/test/dshx-presentation-plugin.test.mjs index 9916f8b2..509e9113 100644 --- a/test/dshx-presentation-plugin.test.mjs +++ b/test/dshx-presentation-plugin.test.mjs @@ -2,53 +2,98 @@ import assert from 'node:assert/strict'; import { readFileSync } from 'node:fs'; import test from 'node:test'; import { fileURLToPath } from 'node:url'; -import { name, inject, Config, plugin, internals, SERVICE_KEY } from '../src/dsh/presentation-plugin.mjs'; +import { + name, + inject, + Config, + plugin, + internals, + SERVICE_KEY +} from '../src/dsh/presentation-plugin.mjs'; +import { + name as startupName, + inject as startupInject, + Config as startupConfig, + plugin as startupPlugin +} from '../src/dsh/startup-plugin.mjs'; + +const LAUNCH = { + cwd: '/workspace', + home: '/home/test/.dshx/codex-tui', + version: 'test', + tuiCommand: '/dist/bin/dshx-tui', + bridgeCommand: '/dist/bin/dshx-ipc-bridge', + debug: true +}; + +test('both rows export the Cordis plugin contract with named exports only', () => { + assert.equal(startupName, 'dshx-startup'); + assert.deepEqual(startupInject, []); + assert.equal(typeof startupConfig, 'function'); + assert.equal(startupPlugin.name, startupName); + assert.equal(typeof startupPlugin.apply, 'function'); -test('exports the Cordis plugin contract with named exports only', () => { assert.equal(name, 'dshx-presentation'); - assert.deepEqual(inject, []); - // Schemastery schemas are callable validators. + assert.deepEqual(inject, ['dshxStartup'], 'transport inputs flow exclusively via the startup row'); assert.equal(typeof Config, 'function'); assert.equal(plugin.name, name); assert.deepEqual(plugin.inject, inject); - assert.equal(plugin.Config, Config); - assert.equal(typeof plugin.apply, 'function'); assert.equal(typeof SERVICE_KEY, 'string'); - const source = readFileSync(fileURLToPath(new URL('../src/dsh/presentation-plugin.mjs', import.meta.url)), 'utf8'); - assert.match(source, /export const name/); - assert.match(source, /export const inject/); - assert.match(source, /export const Config/); - assert.match(source, /export async function apply/); - // A stray default export would collapse the module via unwrapExports and - // drop the named contract (see dsh-tool-todo postmortem 0001). - assert.doesNotMatch(source, /export default/); + for (const file of ['presentation-plugin.mjs', 'startup-plugin.mjs']) { + const source = readFileSync(fileURLToPath(new URL(`../src/dsh/${file}`, import.meta.url)), 'utf8'); + assert.match(source, /export const name/); + assert.match(source, /export const Config/); + // A stray default export would collapse the module via unwrapExports and + // drop the named contract (see dsh-tool-todo postmortem 0001). + assert.doesNotMatch(source, /export default/); + } }); -test('apply starts the transport against the booted context and provides the service', async () => { +test('startup row publishes the launch descriptor from environment + packaged defaults', () => { const provided = new Map(); - const ctx = { provide: (key, value) => provided.set(key, value), get: () => undefined }; - const started = []; + const ctx = { provide: (key, value) => provided.set(key, value) }; + const previous = { ...process.env }; + process.env.DSHX_TUI_HOME = '/tmp/dshx-launch-home'; + process.env.DSHX_IPC_BRIDGE_BIN = '/opt/bridge-custom'; + process.env.DSHX_DEBUG = '1'; + try { + startupPlugin.apply(ctx); + const launch = provided.get('dshxStartup'); + assert.equal(launch.home, '/tmp/dshx-launch-home'); + assert.equal(launch.bridgeCommand, '/opt/bridge-custom'); + assert.equal(launch.debug, true); + assert.equal(launch.version, JSON.parse(readFileSync(new URL('../package.json', import.meta.url), 'utf8')).version); + assert.equal(typeof launch.tuiCommand, 'string'); + } finally { + process.env = previous; + } +}); + +test('presentation row starts the transport from the injected startup service', async () => { + const provided = new Map(); + const ctx = Object.assign( + { provide: (key, value) => provided.set(key, value) }, + { dshxStartup: LAUNCH } + ); let closed = 0; + const started = []; const originalStart = internals.start; internals.start = async (options) => { started.push(options); return { path: '/tmp/dshx-i/d-XXXX/s', url: 'unix:///tmp/dshx-i/d-XXXX/s', close: async () => { closed += 1; } }; }; try { - const dispose = await plugin.apply(ctx, { - cwd: '/workspace', - home: '/home/test/.dshx/codex-tui', - version: 'test', - debug: true - }); + const dispose = await plugin.apply(ctx, {}); assert.equal(started.length, 1); assert.equal(started[0].runtime, ctx, 'plugin must never boot a second runtime'); assert.equal(started[0].disposeRuntimeOnClose, false, 'root-fiber disposal stays owned by the composition'); - assert.equal(started[0].cwd, '/workspace'); + assert.equal(started[0].home, LAUNCH.home); + assert.equal(started[0].bridgeCommand, LAUNCH.bridgeCommand); const service = provided.get(SERVICE_KEY); assert.equal(service.url, 'unix:///tmp/dshx-i/d-XXXX/s'); + assert.equal(service.tuiCommand, LAUNCH.tuiCommand, 'the launcher reads the TUI path through the same service'); assert.equal(typeof service.close, 'function'); await dispose(); @@ -58,9 +103,13 @@ test('apply starts the transport against the booted context and provides the ser } }); -test('apply refuses contexts without the Cordis provide() service seam', async () => { +test('presentation row refuses contexts without the Cordis provide() seam or the startup service', async () => { await assert.rejects( - () => plugin.apply({ get: () => undefined }, {}), + () => plugin.apply({}, {}), /requires a Cordis Context with provide/ ); + await assert.rejects( + () => plugin.apply({ provide: () => {} }, {}), + /requires the dshxStartup service/ + ); }); From f5838bc174a6a11d298610897ffca445fdff555b Mon Sep 17 00:00:00 2001 From: code-new-bie <245316967+code-new-bie@users.noreply.github.com> Date: Wed, 26 Aug 2026 13:58:47 +0800 Subject: [PATCH 07/60] feat: shared profile bootstrap, CI bundle gate, docs for plugin delivery - src/dsh/profile-bootstrap.mjs owns the official-machinery bootstrap (dsh CLI resolution: DSHX_DSH_BIN override -> dependency-local lib/bin.js -> PATH; satisfaction = exact version AND bundle-layer membership; DSHX_SKIP_PROFILE_BOOTSTRAP=1 escape hatch). bin/dshx and runtime-smoke both use it, so the smoke script works against the tui surface profile. - scripts/verify-bundle-install.mjs resolves dsh the same way and now runs in CI (linux-tui job) after the bridge build; core enables pnpm for the bootstrap-driven runtime-smoke step. - Ownership guard tracks the bootstrap module instead of the launcher. - README gains a Plugin usage section; RUNTIME-INTEGRATION lifecycle and doctor description reflect loader-mounted rows and the profile gate. --- .github/workflows/ci.yml | 6 ++ README.md | 27 +++++++- bin/dshx.mjs | 53 +++----------- docs/RUNTIME-INTEGRATION.md | 15 ++-- scripts/runtime-smoke.mjs | 15 ++++ scripts/verify-bundle-install.mjs | 8 ++- scripts/verify-ownership-boundary.mjs | 6 +- src/dsh/profile-bootstrap.mjs | 99 +++++++++++++++++++++++++++ test/dshx-profile-bootstrap.test.mjs | 98 ++++++++++++++++++++++++++ 9 files changed, 270 insertions(+), 57 deletions(-) create mode 100644 src/dsh/profile-bootstrap.mjs create mode 100644 test/dshx-profile-bootstrap.test.mjs diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 31b5170b..ad5119a1 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -45,6 +45,8 @@ jobs: run: npm test - name: Verify DSH ownership boundary run: node scripts/verify-ownership-boundary.mjs + - name: Enable pnpm for the surface profile bootstrap + run: corepack enable pnpm - name: Boot and dispose official DeepSeek Harness composition run: node scripts/runtime-smoke.mjs - name: Syntax check shipped JavaScript @@ -93,6 +95,10 @@ jobs: - name: Verify local IPC data plane shell: bash run: dist/bin/dshx-ipc-bridge --check + - name: Enable pnpm for the official plugin machinery + run: corepack enable pnpm + - name: Verify bundle install end to end + run: node scripts/verify-bundle-install.mjs - name: Exercise real TUI through Linux PTY + CJK + resize shell: bash run: | diff --git a/README.md b/README.md index 2112224b..e4bf19e2 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,25 @@ No separate Codex installation, remote-mode command, bridge command, DSH WebUI, The interaction target is the pinned Codex CLI/TUI: welcome screen, composer, slash commands, model and permission pickers, approvals, ask-user flows, tool/shell cells, diffs, plan/reasoning presentation, steering, Ctrl+C interrupt, resume, status/footer, scrolling, resize and mouse behavior. Windows Terminal and CJK/IME are first-class release gates. +## Plugin usage + +DSHX ships as a standard DSH profile bundle: the package manifest declares +`dsh.bundle.patch`, so the official machinery installs, layers, hot-reloads +and withdraws it like any other composition row set. + +```bash +# Install into any profile (tarball from a release, or this checkout): +dsh plugin --profile tui add ./code-new-bie-dshx-tui-.tgz + +# Withdraw it again; the surface disappears on the next profile start: +dsh plugin --profile tui remove @code-new-bie/dshx-tui +``` + +The zero-argument `dshx` launcher is a thin bootstrap over the same command: +it ensures the selected profile carries this exact package version, boots the +official composition, and spawns the pinned TUI against the endpoint that the +loader-mounted surface rows publish. + ## Ownership boundary We maintain only: @@ -124,7 +143,13 @@ dshx doctor dshx ``` -`dshx doctor` checks the DSH-compatible Node runtime, the packaged TUI, the local IPC data plane, the official DSH composition and the isolated DSHX presentation home/IPC path. +`dshx doctor` checks the DSH-compatible Node runtime, the packaged TUI, the local IPC data plane, the `tui` surface profile (bootstrapped idempotently through the official plugin command), the official DSH composition with the loader-activated surface rows, and the isolated DSHX presentation home/IPC path. + +For the full plugin-delivery proof — pack → official install into a throwaway profile → composed-tree assertions → loader activation with a live transport — run: + +```bash +npm run verify:bundle +``` ## Release model diff --git a/bin/dshx.mjs b/bin/dshx.mjs index a0b0e5d2..f77847ed 100755 --- a/bin/dshx.mjs +++ b/bin/dshx.mjs @@ -11,6 +11,7 @@ import { DSHX_DOCTOR_DISPOSE_TIMEOUT_MS, isSupportedNodeVersion } from '../src/cli/runtime.mjs'; +import { ensureProfileInstalled } from '../src/dsh/profile-bootstrap.mjs'; const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..'); const PACKAGE = JSON.parse(fs.readFileSync(path.join(ROOT, 'package.json'), 'utf8')); @@ -66,47 +67,13 @@ function binaryCandidate(baseName) { || path.join(ROOT, 'dist', 'bin', fileName); } -function dshHome() { - return process.env.DSH_HOME || path.join(os.homedir(), '.dsh'); -} - -/** - * Ensure the selected profile exists and carries this exact package version - * as an activated bundle layer. Uses the official `dsh plugin add` machinery - * (profile auto-init + pnpm forward + bundles reconcile); idempotent. - */ -function ensureProfileInstalled(profileName, runtimeBoot) { - const selected = runtimeBoot.runtimeInternals.selectedProfile(profileName); - const manifestPath = path.join(dshHome(), 'profiles', selected, 'package.json'); - let satisfied = false; - try { - const manifest = JSON.parse(fs.readFileSync(manifestPath, 'utf8')); - const bundles = manifest.dsh?.profile?.bundles ?? []; - const dependencies = manifest.dependencies ?? {}; - satisfied = - dependencies[PACKAGE.name] === VERSION && bundles.includes(PACKAGE.name); - } catch { - // Missing or unreadable manifest: the official command initializes it. - } - if (satisfied) return { profile: selected, action: 'already-installed' }; - - if (process.env.DSHX_SKIP_PROFILE_BOOTSTRAP === '1') { - return { profile: selected, action: 'skipped' }; - } - const result = spawnSync( - 'dsh', - ['plugin', '--profile', selected, 'add', ROOT], - { stdio: 'inherit', shell: process.platform === 'win32' } - ); - if (result.error?.code === 'ENOENT') { - throw new Error( - "official 'dsh' CLI not found on PATH; install DeepSeek Harness to manage the DSHX surface profile" - ); - } - if (result.status !== 0) { - throw new Error(`failed to install ${PACKAGE.name} into profile '${selected}' via dsh plugin add (exit ${result.status})`); - } - return { profile: selected, action: 'installed' }; +function bootstrapSurfaceProfile(runtimeBoot) { + return ensureProfileInstalled({ + packageRoot: ROOT, + name: PACKAGE.name, + version: VERSION, + profile: process.env.DSHX_PROFILE || runtimeBoot.runtimeInternals.DEFAULT_PROFILE + }); } async function loadRuntimeModules() { @@ -219,7 +186,7 @@ async function doctor(runtimeBoot) { let profileDetail = ''; let profileOk = true; try { - const ensured = ensureProfileInstalled(undefined, runtimeBoot); + const ensured = bootstrapSurfaceProfile(runtimeBoot); profileDetail = `profile '${ensured.profile}' (${ensured.action})`; } catch (error) { profileOk = false; @@ -310,7 +277,7 @@ async function run() { // then hand control entirely to the official composition: the loader // mounts the dshx-startup / dshx-presentation rows declared by the bundle // patch, and the transport endpoint arrives as a provided service. - ensureProfileInstalled(undefined, runtimeBoot); + bootstrapSurfaceProfile(runtimeBoot); ctx = await runtimeBoot.bootDshxRuntime({ cwd: process.cwd(), watch: true }); } catch (error) { process.stderr.write(`dshx: failed to boot DeepSeek Harness surface profile: ${error instanceof Error ? error.message : error}\n`); diff --git a/docs/RUNTIME-INTEGRATION.md b/docs/RUNTIME-INTEGRATION.md index fbcf01a4..972ee915 100644 --- a/docs/RUNTIME-INTEGRATION.md +++ b/docs/RUNTIME-INTEGRATION.md @@ -61,14 +61,13 @@ Therefore production does not depend on Codex's experimental TCP WebSocket remot `dshx` performs the following sequence: -1. Resolve and validate the packaged `dshx-tui` and `dshx-ipc-bridge` binaries. -2. Create an isolated presentation-only `CODEX_HOME` under `~/.dshx/codex-tui` (or the development override). -3. Boot the official DSH composition in Node and mount the `dshx-presentation` Cordis plugin on it; the plugin starts the local transport and publishes the endpoint as the `dshxPresentation` service. Surface locks load from the declarative `cordis.patch.yml` bundle patch through DSH's own patch loader. -4. Create a private temporary socket directory. -5. Spawn `dshx-ipc-bridge`, wait for its readiness control message, and expose the resulting `unix://` endpoint to the TUI. -6. Spawn the pinned Codex TUI with `DSHX_APP_SERVER_ENDPOINT` set to that local endpoint. -7. Relay app-server JSON between the TUI and the DSH presentation adapter while DSH remains authoritative for all runtime state. -8. On TUI exit or process shutdown, close the transport, then dispose the official Context whose root Fiber unwinds the presentation plugin and removes the temporary socket directory. +1. Bootstrap the surface profile through the official plugin machinery: `dsh plugin --profile

add ` (idempotent — a profile already pinning this exact package version as a bundle layer is left untouched). The package manifest declares `dsh.bundle.patch`, so the loader picks the surface up as a real bundle layer. +2. Boot the official DSH composition for that profile; the loader mounts the rows declared by the shipped `cordis.patch.yml` (`dshx-startup`, `dshx-presentation`) and locks the competing headless presentation rows. +3. The startup row publishes launch parameters (presentation home, packaged binaries, version) as the `dshxStartup` service; the presentation row injects it, starts the local transport, and publishes the endpoint as the `dshxPresentation` service. +4. Spawn `dshx-ipc-bridge`, wait for its readiness control message, and expose the resulting `unix://` endpoint to the TUI. +5. Spawn the pinned Codex TUI with `DSHX_APP_SERVER_ENDPOINT` set to that local endpoint and an isolated presentation-only `CODEX_HOME`. +6. Relay app-server JSON between the TUI and the DSH presentation adapter while DSH remains authoritative for all runtime state. +7. On TUI exit or process shutdown, dispose the official Context: its root Fiber unwinds the presentation plugin (closing the transport and removing the temporary socket directory) — the Fiber is the sole teardown authority. Ctrl+C is intentionally not intercepted by the Node launcher because it is an in-TUI interaction used to interrupt/steer the active DSH turn. Process `SIGTERM` is propagated for lifecycle shutdown. diff --git a/scripts/runtime-smoke.mjs b/scripts/runtime-smoke.mjs index 75b931be..3b7183ad 100644 --- a/scripts/runtime-smoke.mjs +++ b/scripts/runtime-smoke.mjs @@ -1,6 +1,13 @@ #!/usr/bin/env node +import fs from 'node:fs'; +import path from 'node:path'; import process from 'node:process'; +import { fileURLToPath } from 'node:url'; import { bootDshxRuntime } from '../src/dsh/runtime-boot.mjs'; +import { ensureProfileInstalled } from '../src/dsh/profile-bootstrap.mjs'; + +const PACKAGE_ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..'); +const PACKAGE = JSON.parse(fs.readFileSync(path.join(PACKAGE_ROOT, 'package.json'), 'utf8')); const REQUIRED_SERVICES = [ 'agents', @@ -41,6 +48,14 @@ function withTimeout(promise, timeoutMs, label) { let ctx; let primaryError; try { + // The smoke targets the production surface profile; make sure the official + // plugin machinery has it installed before composing. + const ensured = ensureProfileInstalled({ + packageRoot: PACKAGE_ROOT, + name: PACKAGE.name, + version: PACKAGE.version + }); + process.stdout.write(`surface profile '${ensured.profile}' ${ensured.action}\n`); process.stdout.write('booting official DSH composition with production patch watchers enabled\n'); ctx = await withTimeout( bootDshxRuntime({ cwd: process.cwd(), watch: true }), diff --git a/scripts/verify-bundle-install.mjs b/scripts/verify-bundle-install.mjs index 7df862ef..a5c8ff3a 100644 --- a/scripts/verify-bundle-install.mjs +++ b/scripts/verify-bundle-install.mjs @@ -17,6 +17,7 @@ import path from 'node:path'; import process from 'node:process'; import { spawnSync } from 'node:child_process'; import { fileURLToPath } from 'node:url'; +import { resolveDshInvocation } from '../src/dsh/profile-bootstrap.mjs'; const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..'); const PACKAGE = JSON.parse(fs.readFileSync(path.join(ROOT, 'package.json'), 'utf8')); @@ -80,10 +81,11 @@ try { console.log(`[verify-bundle] packed ${tarballName}`); // ── 2. official install into a brand-new profile ────────────────────── + const dsh = resolveDshInvocation(ROOT, isolatedEnv); const add = run( 'dsh plugin add', - 'dsh', - ['plugin', '--profile', PROFILE, 'add', `./${tarballName}`], + dsh.command, + [...dsh.args, 'plugin', '--profile', PROFILE, 'add', `./${tarballName}`], { cwd: packDir, check: true } ); if (!add.stdout.includes(`initialized profile ${PROFILE}`) && !add.stdout.includes('already')) { @@ -109,7 +111,7 @@ try { // patch files (including !!js nodes), so we reuse DSH's own parser. const { loadOptionalPatches } = await import('@deepseek-ai/dsh-app-boot'); const dumpPath = path.join(work, 'dump-config.yml'); - const dump = run('dsh --dump-config', 'dsh', ['--profile', PROFILE, '--dump-config']); + const dump = run('dsh --dump-config', dsh.command, [...dsh.args, '--profile', PROFILE, '--dump-config']); if (dump.status !== 0) { throw new Error(`--dump-config failed: ${dump.stderr || dump.stdout}`); } diff --git a/scripts/verify-ownership-boundary.mjs b/scripts/verify-ownership-boundary.mjs index 88a92d17..1c340dd3 100644 --- a/scripts/verify-ownership-boundary.mjs +++ b/scripts/verify-ownership-boundary.mjs @@ -63,8 +63,10 @@ requireText('src/dsh/presentation-plugin.mjs', 'ctx.provide(SERVICE_KEY'); requireText('src/dsh/presentation-plugin.mjs', "inject = ['dshxStartup']"); requireText('src/dsh/startup-plugin.mjs', "provide('dshxStartup'"); // The launcher only bootstraps via the official plugin command, never mounts -// rows itself. -requireText('bin/dshx.mjs', "'plugin', '--profile'"); +// rows itself; the shared bootstrap module owns the command assembly and +// resolves the dsh CLI without requiring a global installation. +requireText('src/dsh/profile-bootstrap.mjs', "'plugin', '--profile'"); +requireText('src/dsh/profile-bootstrap.mjs', 'resolveDshInvocation'); forbidText('src/dsh/runtime-boot.mjs', 'bootDshxPresentationRuntime'); // Presentation lifetime may adapt the Context shape, but teardown must remain // delegated to Cordis/DSH root-fiber ownership rather than a DSHX runtime. diff --git a/src/dsh/profile-bootstrap.mjs b/src/dsh/profile-bootstrap.mjs new file mode 100644 index 00000000..165b8b4e --- /dev/null +++ b/src/dsh/profile-bootstrap.mjs @@ -0,0 +1,99 @@ +import fs from 'node:fs'; +import os from 'node:os'; +import path from 'node:path'; +import process from 'node:process'; +import { spawnSync } from 'node:child_process'; +import { createRequire } from 'node:module'; + +/** + * Shared bootstrap over the official DSH plugin machinery. + * + * The surface ships as a standard profile bundle; every entry point (the + * zero-argument CLI, the smoke scripts, CI) ensures the selected profile + * carries this exact package version by running the official + * `dsh plugin --profile

add ` command, which owns profile + * initialization, pnpm installation and bundles reconciliation. + */ + +/** Resolve the DSH home directory exactly like the official launcher. */ +export function dshHomeDir(environment = process.env) { + return environment.DSH_HOME || path.join(os.homedir(), '.dsh'); +} + +export function profileManifestPath(profileName, environment = process.env) { + return path.join(dshHomeDir(environment), 'profiles', profileName, 'package.json'); +} + +/** + * How to invoke the official dsh CLI: an explicit override wins, a global + * `dsh` on PATH is next, and a dependency-local `lib/bin.js` (always present + * after npm ci) keeps CI and fresh checkouts working without any global + * installation. + */ +export function resolveDshInvocation(fromDirectory = process.cwd(), environment = process.env) { + if (environment.DSHX_DSH_BIN) { + return { command: process.execPath, args: [environment.DSHX_DSH_BIN] }; + } + try { + const anchor = createRequire(path.join(fromDirectory, 'package.json')).resolve( + '@deepseek-ai/dsh/package.json' + ); + const cli = path.join(path.dirname(anchor), 'lib', 'bin.js'); + if (fs.existsSync(cli)) return { command: process.execPath, args: [cli] }; + } catch { + // Not installed locally; fall through to PATH lookup. + } + return { command: 'dsh', args: [] }; +} + +/** A profile satisfies bootstrap when it pins this exact version as a bundle layer. */ +export function profileSatisfied(manifest, { name, version }) { + if (!manifest || typeof manifest !== 'object') return false; + const bundles = manifest.dsh?.profile?.bundles ?? []; + const dependencies = manifest.dependencies ?? {}; + return dependencies[name] === version && bundles.includes(name); +} + +/** + * Ensure `profileName` exists and carries `{name}@{version}` from + * `packageRoot` as an activated bundle layer. Idempotent: satisfied profiles + * are left untouched, honoring DSHX_SKIP_PROFILE_BOOTSTRAP=1 for offline runs. + */ +export function ensureProfileInstalled({ + packageRoot, + name, + version, + profile = 'tui', + environment = process.env, + spawnSyncImpl = spawnSync +} = {}) { + let satisfied = false; + try { + satisfied = profileSatisfied(JSON.parse(fs.readFileSync(profileManifestPath(profile, environment), 'utf8')), { + name, + version + }); + } catch { + // Missing or unreadable manifest: the official command initializes it. + } + if (satisfied) return { profile, action: 'already-installed' }; + if (environment.DSHX_SKIP_PROFILE_BOOTSTRAP === '1') { + return { profile, action: 'skipped' }; + } + + const { command, args } = resolveDshInvocation(packageRoot, environment); + const result = spawnSyncImpl( + command, + [...args, 'plugin', '--profile', profile, 'add', packageRoot], + { stdio: 'inherit', shell: process.platform === 'win32' } + ); + if (result.error?.code === 'ENOENT') { + throw new Error( + "official 'dsh' CLI not found (looked up DSHX_DSH_BIN, @deepseek-ai/dsh dependency and PATH); install DeepSeek Harness to manage the DSHX surface profile" + ); + } + if (result.status !== 0) { + throw new Error(`failed to install ${name} into profile '${profile}' via dsh plugin add (exit ${result.status ?? '?'})`); + } + return { profile, action: 'installed' }; +} diff --git a/test/dshx-profile-bootstrap.test.mjs b/test/dshx-profile-bootstrap.test.mjs new file mode 100644 index 00000000..7e54dbc5 --- /dev/null +++ b/test/dshx-profile-bootstrap.test.mjs @@ -0,0 +1,98 @@ +import assert from 'node:assert/strict'; +import fs from 'node:fs'; +import os from 'node:os'; +import path from 'node:path'; +import test from 'node:test'; +import { + dshHomeDir, + profileManifestPath, + profileSatisfied, + ensureProfileInstalled +} from '../src/dsh/profile-bootstrap.mjs'; + +function temporaryHome(run) { + const home = fs.mkdtempSync(path.join(os.tmpdir(), 'dshx-bootstrap-test-')); + try { + return run(home); + } finally { + fs.rmSync(home, { recursive: true, force: true }); + } +} + +const SELF = { name: '@code-new-bie/dshx-tui', version: '9.9.9-test' }; + +function writeManifest(home, manifest) { + const dir = path.join(home, 'profiles', 'tui'); + fs.mkdirSync(dir, { recursive: true }); + fs.writeFileSync(path.join(dir, 'package.json'), JSON.stringify(manifest, null, 2)); +} + +test('home and manifest paths honor DSH_HOME exactly like the official launcher', () => { + assert.equal(dshHomeDir({}), path.join(os.homedir(), '.dsh')); + assert.equal(dshHomeDir({ DSH_HOME: '/tmp/h' }), '/tmp/h'); + assert.equal(profileManifestPath('tui', { DSH_HOME: '/tmp/h' }), path.join('/tmp/h', 'profiles', 'tui', 'package.json')); +}); + +test('profile satisfaction needs the exact version AND bundle-layer membership', () => { + const ok = { dependencies: { [SELF.name]: SELF.version }, dsh: { profile: { bundles: ['@deepseek-ai/dsh-base', SELF.name] } } }; + const wrongVersion = { ...ok, dependencies: { [SELF.name]: '0.0.1' } }; + const missingLayer = { dependencies: { [SELF.name]: SELF.version }, dsh: { profile: { bundles: ['@deepseek-ai/dsh-base'] } } }; + assert.equal(profileSatisfied(ok, SELF), true); + assert.equal(profileSatisfied(wrongVersion, SELF), false); + assert.equal(profileSatisfied(missingLayer, SELF), false); + assert.equal(profileSatisfied(undefined, SELF), false); +}); + +test('bootstrap installs through the official command when the profile is missing', () => { + temporaryHome((home) => { + const calls = []; + const result = ensureProfileInstalled({ + packageRoot: '/repo', + ...SELF, + environment: { DSH_HOME: home }, + spawnSyncImpl: (command, args) => { + calls.push([command, args]); + return { status: 0 }; + } + }); + assert.equal(result.action, 'installed'); + const forwarded = calls[0][1]; + assert.equal(forwarded[0], 'plugin'); + assert.deepEqual(forwarded.slice(1, 4), ['--profile', 'tui', 'add']); + assert.equal(forwarded.at(-1), '/repo'); + }); +}); + +test('bootstrap is idempotent for satisfied profiles and honors the skip switch', () => { + temporaryHome((home) => { + writeManifest(home, { + name: 'dsh-profile-tui', + private: true, + dependencies: { [SELF.name]: SELF.version }, + dsh: { profile: { bundles: ['@deepseek-ai/dsh-base', SELF.name] } } + }); + const spawn = () => ({ status: 1 }); + assert.equal( + ensureProfileInstalled({ packageRoot: '/repo', ...SELF, environment: { DSH_HOME: home }, spawnSyncImpl: spawn }).action, + 'already-installed' + ); + // The skip switch only short-circuits profiles that still need work. + fs.writeFileSync( + path.join(home, 'profiles', 'tui', 'package.json'), + JSON.stringify({ + name: 'dsh-profile-tui', + private: true, + dependencies: { [SELF.name]: '0.0.1' }, + dsh: { profile: { bundles: ['@deepseek-ai/dsh-base'] } } + }) + ); + assert.equal( + ensureProfileInstalled({ + packageRoot: '/repo', ...SELF, + environment: { DSH_HOME: home, DSHX_SKIP_PROFILE_BOOTSTRAP: '1' }, + spawnSyncImpl: spawn + }).action, + 'skipped' + ); + }); +}); From ac67f2380856c1813f05e8fc63b959672b3d84e1 Mon Sep 17 00:00:00 2001 From: code-new-bie <245316967+code-new-bie@users.noreply.github.com> Date: Wed, 26 Aug 2026 14:24:36 +0800 Subject: [PATCH 08/60] feat: enforce the supported DSH line at boot time MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The peerDependency pin is declarative only — profile installs never resolve peers, so a host running a different DSH release would fail with mysterious API errors. dshxRuntimeProfile now reads the version of the installation that will actually boot and fails loud with an actionable message (supported line <-> found version) when they diverge. The supported line's single source of truth is the manifest's @deepseek-ai/dsh peerDependency. --- scripts/verify-ownership-boundary.mjs | 3 +++ src/dsh/runtime-boot.mjs | 36 +++++++++++++++++++++++++-- test/dsh-runtime-boot.test.mjs | 27 +++++++++++++++++++- 3 files changed, 63 insertions(+), 3 deletions(-) diff --git a/scripts/verify-ownership-boundary.mjs b/scripts/verify-ownership-boundary.mjs index 1c340dd3..2d439f0c 100644 --- a/scripts/verify-ownership-boundary.mjs +++ b/scripts/verify-ownership-boundary.mjs @@ -72,6 +72,9 @@ forbidText('src/dsh/runtime-boot.mjs', 'bootDshxPresentationRuntime'); // delegated to Cordis/DSH root-fiber ownership rather than a DSHX runtime. requireText('src/dsh/runtime-boot.mjs', 'ctx.fiber.dispose()'); requireText('src/dsh/runtime-boot.mjs', 'attachPresentationLifetime(ctx)'); +// The declared supported DSH line must be enforced at boot, not just pinned +// declaratively in peerDependencies (which profile installs never resolve). +requireText('src/dsh/runtime-boot.mjs', 'assertSupportedDshInstallation'); for (const path of ['src/dsh/user-shell.mjs', 'src/dsh/workspace-command.mjs']) { forbidText(path, /execFile|execSync|spawn\(/, 'local process execution'); diff --git a/src/dsh/runtime-boot.mjs b/src/dsh/runtime-boot.mjs index 4b7a080d..bbb36da5 100644 --- a/src/dsh/runtime-boot.mjs +++ b/src/dsh/runtime-boot.mjs @@ -1,6 +1,7 @@ -import { writeFileSync } from 'node:fs'; +import { readFileSync, writeFileSync } from 'node:fs'; import { createRequire } from 'node:module'; -import { dirname, join } from 'node:path'; +import { dirname, join, resolve } from 'node:path'; +import { fileURLToPath } from 'node:url'; import { boot, composeEntries, @@ -17,6 +18,12 @@ const NAME = 'dshx'; const DSH_PROFILE_BIN_NAME = 'dsh'; const DEFAULT_PROFILE = 'tui'; const PROFILE_ROOT_FILENAME = 'cordis.yml'; +// The supported official DSH line. Single source of truth: the exact +// @deepseek-ai/dsh peerDependency declared in this package manifest. +const PACKAGE_ROOT = resolve(dirname(fileURLToPath(import.meta.url)), '../..'); +const SUPPORTED_DSH_LINE = JSON.parse( + readFileSync(join(PACKAGE_ROOT, 'package.json'), 'utf8') +).peerDependencies['@deepseek-ai/dsh']; // Match the official `dsh` launcher's profile-root contract: this file is only // the Loader/include base anchor. The real user-owned configuration is carried // by the profile's `cordis.patch.yml` plus `$DSH_HOME/cordis.patch.yml`. @@ -33,6 +40,28 @@ function installationAnchor() { return createRequire(import.meta.url).resolve('@deepseek-ai/dsh/package.json'); } +/** + * Fail loud when the installed official DSH line is not the one this surface + * is built and tested against. The manifest pin alone is declarative — + * profile installs never resolve peers — so compatibility must be checked + * against the copy that will actually boot. + */ +export function assertSupportedDshInstallation(anchor = installationAnchor()) { + let installed; + try { + installed = JSON.parse(readFileSync(anchor, 'utf8')).version; + } catch (error) { + throw new Error(`dshx: cannot read the official DSH installation at ${anchor}: ${error instanceof Error ? error.message : error}`); + } + if (installed !== SUPPORTED_DSH_LINE) { + throw new Error( + `dshx supports official DeepSeek Harness ${SUPPORTED_DSH_LINE}, found ${installed}. ` + + `Upgrade or downgrade @deepseek-ai/dsh to ${SUPPORTED_DSH_LINE}, or use a dshx release built for ${installed}.` + ); + } + return installed; +} + function selectedProfile(explicit) { const value = explicit ?? process.env.DSHX_PROFILE ?? DEFAULT_PROFILE; if (typeof value !== 'string' || value.trim().length === 0) { @@ -83,6 +112,7 @@ export function dshxRuntimeProfile({ overlays = [] } = {}) { const profileName = selectedProfile(explicitProfile); + const installedLine = assertSupportedDshInstallation(installAnchor); healProfilesModuleFallback(installAnchor, home); const profile = loadProfile(DSH_PROFILE_BIN_NAME, profileName, installAnchor, home); const rootConfig = join(profile.dir, PROFILE_ROOT_FILENAME); @@ -222,6 +252,8 @@ export const runtimeInternals = { DEFAULT_PROFILE, PROFILE_ROOT_FILENAME, PROFILE_ROOT_CONFIG, + SUPPORTED_DSH_LINE, + assertSupportedDshInstallation, installationAnchor, selectedProfile, profileHome, diff --git a/test/dsh-runtime-boot.test.mjs b/test/dsh-runtime-boot.test.mjs index d2456b0b..470bde83 100644 --- a/test/dsh-runtime-boot.test.mjs +++ b/test/dsh-runtime-boot.test.mjs @@ -1,7 +1,7 @@ import assert from 'node:assert/strict'; import { mkdtempSync, mkdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs'; import { tmpdir } from 'node:os'; -import { join } from 'node:path'; +import { dirname, join } from 'node:path'; import test from 'node:test'; import { dshxRuntimeEntries, dshxRuntimeProfile, runtimeInternals } from '../src/dsh/runtime-boot.mjs'; @@ -133,6 +133,31 @@ test('missing surface profile fails loud instead of silently composing nothing', }); }); +test('unsupported installed DSH lines fail loud with an actionable message', () => { + temporaryDshHome((home) => { + seedSurfaceProfile(home); + const fake = join(home, 'fake-dsh', 'package.json'); + mkdirSync(dirname(fake), { recursive: true }); + writeFileSync(fake, JSON.stringify({ name: '@deepseek-ai/dsh', version: '9.9.9-unheard-of' })); + + assert.throws( + () => runtimeInternals.assertSupportedDshInstallation(fake), + (error) => { + const message = error instanceof Error ? error.message : String(error); + return message.includes(runtimeInternals.SUPPORTED_DSH_LINE) + && message.includes('9.9.9-unheard-of') + && /Upgrade or downgrade/.test(message); + }, + 'the mismatch must name both the supported line and the found version' + ); + // The supported line itself passes and reports the installation. + assert.equal( + runtimeInternals.assertSupportedDshInstallation(new URL('../node_modules/@deepseek-ai/dsh/package.json', import.meta.url)), + runtimeInternals.SUPPORTED_DSH_LINE + ); + }); +}); + test('presentation lifetime delegates disposal to the official DSH root Fiber', async () => { let disposals = 0; const ctx = { From 8771f79aa34f67e49e9d7085927e4eb514406c7f Mon Sep 17 00:00:00 2001 From: code-new-bie <245316967+code-new-bie@users.noreply.github.com> Date: Wed, 26 Aug 2026 14:30:00 +0800 Subject: [PATCH 09/60] fix: report DSH line mismatch as a one-shot warning, never a block The plugin spec carries no host-version gates and official bundles declare peer ranges only. Keep the tested line as honest metadata (manifest peer pin + warn-once at boot naming both versions), but proceed on any installed release. --- scripts/verify-ownership-boundary.mjs | 7 +++--- src/dsh/runtime-boot.mjs | 34 ++++++++++++++++----------- test/dsh-runtime-boot.test.mjs | 34 +++++++++++++++------------ 3 files changed, 43 insertions(+), 32 deletions(-) diff --git a/scripts/verify-ownership-boundary.mjs b/scripts/verify-ownership-boundary.mjs index 2d439f0c..f15937fc 100644 --- a/scripts/verify-ownership-boundary.mjs +++ b/scripts/verify-ownership-boundary.mjs @@ -72,9 +72,10 @@ forbidText('src/dsh/runtime-boot.mjs', 'bootDshxPresentationRuntime'); // delegated to Cordis/DSH root-fiber ownership rather than a DSHX runtime. requireText('src/dsh/runtime-boot.mjs', 'ctx.fiber.dispose()'); requireText('src/dsh/runtime-boot.mjs', 'attachPresentationLifetime(ctx)'); -// The declared supported DSH line must be enforced at boot, not just pinned -// declaratively in peerDependencies (which profile installs never resolve). -requireText('src/dsh/runtime-boot.mjs', 'assertSupportedDshInstallation'); +// The declared supported DSH line is ecosystem-honest metadata: warn once at +// boot, never block the host (official bundles carry peer ranges, no gates). +requireText('src/dsh/runtime-boot.mjs', 'reportDshLineCompatibility'); +requireText('src/dsh/runtime-boot.mjs', 'proceeding'); for (const path of ['src/dsh/user-shell.mjs', 'src/dsh/workspace-command.mjs']) { forbidText(path, /execFile|execSync|spawn\(/, 'local process execution'); diff --git a/src/dsh/runtime-boot.mjs b/src/dsh/runtime-boot.mjs index bbb36da5..ab86e985 100644 --- a/src/dsh/runtime-boot.mjs +++ b/src/dsh/runtime-boot.mjs @@ -41,25 +41,31 @@ function installationAnchor() { } /** - * Fail loud when the installed official DSH line is not the one this surface - * is built and tested against. The manifest pin alone is declarative — - * profile installs never resolve peers — so compatibility must be checked - * against the copy that will actually boot. + * Report which official DSH line this surface was built and tested against, + * compared with the installation that will actually boot. Ecosystem + * convention: bundles declare compatibility through peer ranges and never + * block the host, so a mismatch is a loud one-shot warning, not an error. */ -export function assertSupportedDshInstallation(anchor = installationAnchor()) { +let dshLineWarned = false; +export function reportDshLineCompatibility( + anchor = installationAnchor(), + notify = (message) => process.stderr.write(`${message}\n`) +) { let installed; try { installed = JSON.parse(readFileSync(anchor, 'utf8')).version; - } catch (error) { - throw new Error(`dshx: cannot read the official DSH installation at ${anchor}: ${error instanceof Error ? error.message : error}`); + } catch { + return { installed: undefined, supported: SUPPORTED_DSH_LINE, compatible: undefined }; } - if (installed !== SUPPORTED_DSH_LINE) { - throw new Error( - `dshx supports official DeepSeek Harness ${SUPPORTED_DSH_LINE}, found ${installed}. ` + - `Upgrade or downgrade @deepseek-ai/dsh to ${SUPPORTED_DSH_LINE}, or use a dshx release built for ${installed}.` + const compatible = installed === SUPPORTED_DSH_LINE; + if (!compatible && !dshLineWarned) { + dshLineWarned = true; + notify( + `[dshx] running against untested official DeepSeek Harness ${installed} ` + + `(tested line: ${SUPPORTED_DSH_LINE}); proceeding — report oddities upstream if any appear` ); } - return installed; + return { installed, supported: SUPPORTED_DSH_LINE, compatible }; } function selectedProfile(explicit) { @@ -112,7 +118,7 @@ export function dshxRuntimeProfile({ overlays = [] } = {}) { const profileName = selectedProfile(explicitProfile); - const installedLine = assertSupportedDshInstallation(installAnchor); + reportDshLineCompatibility(installAnchor); healProfilesModuleFallback(installAnchor, home); const profile = loadProfile(DSH_PROFILE_BIN_NAME, profileName, installAnchor, home); const rootConfig = join(profile.dir, PROFILE_ROOT_FILENAME); @@ -253,7 +259,7 @@ export const runtimeInternals = { PROFILE_ROOT_FILENAME, PROFILE_ROOT_CONFIG, SUPPORTED_DSH_LINE, - assertSupportedDshInstallation, + reportDshLineCompatibility, installationAnchor, selectedProfile, profileHome, diff --git a/test/dsh-runtime-boot.test.mjs b/test/dsh-runtime-boot.test.mjs index 470bde83..3c33dc8b 100644 --- a/test/dsh-runtime-boot.test.mjs +++ b/test/dsh-runtime-boot.test.mjs @@ -133,28 +133,32 @@ test('missing surface profile fails loud instead of silently composing nothing', }); }); -test('unsupported installed DSH lines fail loud with an actionable message', () => { +test('untested DSH lines warn once and proceed; the tested line stays silent', () => { temporaryDshHome((home) => { seedSurfaceProfile(home); const fake = join(home, 'fake-dsh', 'package.json'); mkdirSync(dirname(fake), { recursive: true }); writeFileSync(fake, JSON.stringify({ name: '@deepseek-ai/dsh', version: '9.9.9-unheard-of' })); - assert.throws( - () => runtimeInternals.assertSupportedDshInstallation(fake), - (error) => { - const message = error instanceof Error ? error.message : String(error); - return message.includes(runtimeInternals.SUPPORTED_DSH_LINE) - && message.includes('9.9.9-unheard-of') - && /Upgrade or downgrade/.test(message); - }, - 'the mismatch must name both the supported line and the found version' - ); - // The supported line itself passes and reports the installation. - assert.equal( - runtimeInternals.assertSupportedDshInstallation(new URL('../node_modules/@deepseek-ai/dsh/package.json', import.meta.url)), - runtimeInternals.SUPPORTED_DSH_LINE + // Ecosystem convention: bundles never block the host. A mismatch warns + // exactly once with both versions, then lets every boot proceed. + const warnings = []; + const first = runtimeInternals.reportDshLineCompatibility(fake, (m) => warnings.push(m)); + assert.equal(first.compatible, false); + assert.equal(first.installed, '9.9.9-unheard-of'); + runtimeInternals.reportDshLineCompatibility(fake, (m) => warnings.push(m)); + assert.equal(warnings.length, 1, 'warn-once per process'); + assert.match(warnings[0], new RegExp(`${runtimeInternals.SUPPORTED_DSH_LINE}.*9\\.9\\.9-unheard-of|9\\.9\\.9-unheard-of.*${runtimeInternals.SUPPORTED_DSH_LINE}`)); + assert.match(warnings[0], /proceeding/); + + // The tested line itself is silent and reports plain compatibility. + const quiet = []; + const real = runtimeInternals.reportDshLineCompatibility( + new URL('../node_modules/@deepseek-ai/dsh/package.json', import.meta.url), + (m) => quiet.push(m) ); + assert.equal(real.compatible, true); + assert.deepEqual(quiet, []); }); }); From 81719beede814222239bdfb6e5d3c4d57e040713 Mon Sep 17 00:00:00 2001 From: code-new-bie <245316967+code-new-bie@users.noreply.github.com> Date: Wed, 26 Aug 2026 15:32:59 +0800 Subject: [PATCH 10/60] refactor: confine the Codex dialect to src/tui-protocol/ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Product scope: replicate only Codex's TUI shell — everything else is DSH. Make the codebase say so structurally: src/tui-protocol/ shapes.mjs wire-format dictionary (former codex-shapes) adapter.mjs app-server method routing + projection orchestration Domain modules under src/dsh keep DSH vocabulary; the ownership guard now asserts the dictionary lives only in tui-protocol and that no codex-named module returns to src/dsh. Residual lowercase field mappings inside domain modules are gradual-cleanup items, tracked by the same guard's placement checks. --- scripts/package-platform.mjs | 2 ++ scripts/verify-ownership-boundary.mjs | 22 ++++++++---- scripts/verify-slash-contract.mjs | 2 +- src/dsh/history-pages.mjs | 2 +- src/dsh/local-server.mjs | 2 +- .../adapter.mjs} | 34 +++++++++---------- .../shapes.mjs} | 2 +- test/dsh-app-server-adapter.test.mjs | 4 +-- test/dsh-codex-shapes.test.mjs | 2 +- test/dsh-compaction-projection.test.mjs | 4 +-- test/dsh-domain-delegation.test.mjs | 2 +- test/dsh-product-adapter.test.mjs | 2 +- test/dsh-product-fork.test.mjs | 2 +- test/dsh-product-resume.test.mjs | 2 +- test/dsh-rc5-acceptance-regressions.test.mjs | 4 +-- test/dsh-release-title.test.mjs | 2 +- test/dsh-subagent-authority.test.mjs | 2 +- test/dsh-subagent-presentation.test.mjs | 4 +-- 18 files changed, 54 insertions(+), 42 deletions(-) rename src/{dsh/presentation-adapter.mjs => tui-protocol/adapter.mjs} (98%) rename src/{dsh/codex-shapes.mjs => tui-protocol/shapes.mjs} (99%) diff --git a/scripts/package-platform.mjs b/scripts/package-platform.mjs index 9492b1a4..b0d88bf8 100644 --- a/scripts/package-platform.mjs +++ b/scripts/package-platform.mjs @@ -56,6 +56,7 @@ function copy(relative) { copy('bin/dshx.mjs'); copy('src/cli'); copy('src/dsh'); +copy('src/tui-protocol'); copy('src/protocol'); copy('README.md'); copy('NOTICE'); @@ -101,6 +102,7 @@ const packageJson = { 'bin/dshx.mjs', 'src/cli', 'src/dsh', + 'src/tui-protocol', 'src/protocol', 'cordis.patch.yml', 'dist/bin', diff --git a/scripts/verify-ownership-boundary.mjs b/scripts/verify-ownership-boundary.mjs index f15937fc..57935c29 100644 --- a/scripts/verify-ownership-boundary.mjs +++ b/scripts/verify-ownership-boundary.mjs @@ -1,4 +1,4 @@ -import { readFileSync } from 'node:fs'; +import { readFileSync, readdirSync } from 'node:fs'; function read(path) { return readFileSync(path, 'utf8'); @@ -83,23 +83,33 @@ for (const path of ['src/dsh/user-shell.mjs', 'src/dsh/workspace-command.mjs']) } requireText('src/dsh/user-shell.mjs', 'agent: controller.agent'); requireText('src/dsh/workspace-command.mjs', 'agent'); -requireText('src/dsh/presentation-adapter.mjs', "case 'command/exec'"); +requireText('src/tui-protocol/adapter.mjs', "case 'command/exec'"); requireText('src/dsh/host-api.mjs', '@deepseek-ai/dsh-host-apiproxy'); requireText('src/dsh/host-api.mjs', 'api.sessions.fork'); -requireText('src/dsh/presentation-adapter.mjs', 'executeDshCommand'); +requireText('src/tui-protocol/adapter.mjs', 'executeDshCommand'); requireText('src/dsh/commands.mjs', 'commands.execute'); -forbidText('src/dsh/presentation-adapter.mjs', 'compactNow'); +forbidText('src/tui-protocol/adapter.mjs', 'compactNow'); forbidText('src/dsh/agent-driver.mjs', /seedLength|parentSession|dshForkSeed/, 'shadow fork/session seed state'); // The unified adapter may read DSH's durable `parentSession` header field to // delegate subagent interruption back to ctx.subagents, but it must never // keep shadow fork/session seed state of its own. -forbidText('src/dsh/presentation-adapter.mjs', /seedLength|dshForkSeed/, 'shadow fork/session seed state'); -requireText('src/dsh/presentation-adapter.mjs', 'subagents.interrupt'); +forbidText('src/tui-protocol/adapter.mjs', /seedLength|dshForkSeed/, 'shadow fork/session seed state'); +requireText('src/tui-protocol/adapter.mjs', 'subagents.interrupt'); forbidText('src/dsh/agent-driver.mjs', 'fork(sourceAgent'); forbidText('src/dsh/local-server.mjs', 'WebSocketServer', 'production TCP WebSocket server'); requireText('src/dsh/local-server.mjs', 'unix://'); requireText('scripts/build-codex-tui.sh', 'dshx-ipc-bridge'); +// The Codex dialect lives only in the protocol namespace; domain modules in +// src/dsh stay DSH-vocabulary (gradual cleanup tracked for residual field +// mappings, enforced structurally by these two placement checks). +try { readFileSync('src/tui-protocol/shapes.mjs'); readFileSync('src/tui-protocol/adapter.mjs'); } catch { + throw new Error('Codex protocol dictionary must live under src/tui-protocol/'); +} +for (const entry of readdirSync('src/dsh')) { + if (/codex/i.test(entry)) throw new Error(`src/dsh must not carry codex-named modules; found ${entry}`); +} + console.log('DSHX ownership boundary verified'); diff --git a/scripts/verify-slash-contract.mjs b/scripts/verify-slash-contract.mjs index 17ed6258..f16ab666 100644 --- a/scripts/verify-slash-contract.mjs +++ b/scripts/verify-slash-contract.mjs @@ -72,7 +72,7 @@ for (const hidden of dshxHidden) { } const adapterSources = [ - 'src/dsh/presentation-adapter.mjs' + 'src/tui-protocol/adapter.mjs' ].map((relative) => fs.readFileSync(path.join(ROOT, relative), 'utf8')).join('\n'); for (const [command, methods] of runtimeBacked) { for (const method of methods) { diff --git a/src/dsh/history-pages.mjs b/src/dsh/history-pages.mjs index f27881b3..c4b9ada0 100644 --- a/src/dsh/history-pages.mjs +++ b/src/dsh/history-pages.mjs @@ -1,4 +1,4 @@ -import { dshTurnsFromSession } from './codex-shapes.mjs'; +import { dshTurnsFromSession } from '../tui-protocol/shapes.mjs'; function cursorOffset(cursor) { if (cursor == null) return 0; diff --git a/src/dsh/local-server.mjs b/src/dsh/local-server.mjs index d66153b3..c96fca06 100644 --- a/src/dsh/local-server.mjs +++ b/src/dsh/local-server.mjs @@ -4,7 +4,7 @@ import path from 'node:path'; import { spawn } from 'node:child_process'; import { createInterface } from 'node:readline'; import { fileURLToPath } from 'node:url'; -import { DshxPresentationAdapter } from './presentation-adapter.mjs'; +import { DshxPresentationAdapter } from '../tui-protocol/adapter.mjs'; import { bootDshxRuntime } from './runtime-boot.mjs'; const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../..'); diff --git a/src/dsh/presentation-adapter.mjs b/src/tui-protocol/adapter.mjs similarity index 98% rename from src/dsh/presentation-adapter.mjs rename to src/tui-protocol/adapter.mjs index 5c6fca15..2dfaa111 100644 --- a/src/dsh/presentation-adapter.mjs +++ b/src/tui-protocol/adapter.mjs @@ -1,8 +1,8 @@ import crypto from 'node:crypto'; import os from 'node:os'; import path from 'node:path'; -import { DshAgentDriver } from './agent-driver.mjs'; -import { DshApprovalBridge } from './approval-bridge.mjs'; +import { DshAgentDriver } from '../dsh/agent-driver.mjs'; +import { DshApprovalBridge } from '../dsh/approval-bridge.mjs'; import { codexModelsFromDsh, decodeDshModel, @@ -11,21 +11,21 @@ import { encodeDshModel, normalizeCodexEffort, normalizeSessionHeaders -} from './codex-shapes.mjs'; -import { executeDshCommand } from './commands.mjs'; -import { dshThreadItemsPage, dshThreadTurnsPage } from './history-pages.mjs'; -import { DshHostApi } from './host-api.mjs'; -import { codexPlanTarget, threadSettingsUpdatedNotification } from './plan-presentation.mjs'; -import { DshPermissionView } from './permissions.mjs'; -import { codexForkAtSeq } from './session-fork.mjs'; -import { dshSkillsListEntry } from './skills.mjs'; -import { foldDshSessionTitle, threadNameUpdatedNotification } from './thread-title.mjs'; -import { DshThreadController } from './thread-controller.mjs'; -import { codexInputToDshContent, dshContentText } from './user-input.mjs'; -import { DshUserQuestionBridge } from './user-question-bridge.mjs'; -import { DshUserShellBridge } from './user-shell.mjs'; -import { persistedTokenUsageNotification } from './token-usage.mjs'; -import { DshWorkspaceCommandBridge } from './workspace-command.mjs'; +} from './shapes.mjs'; +import { executeDshCommand } from '../dsh/commands.mjs'; +import { dshThreadItemsPage, dshThreadTurnsPage } from '../dsh/history-pages.mjs'; +import { DshHostApi } from '../dsh/host-api.mjs'; +import { codexPlanTarget, threadSettingsUpdatedNotification } from '../dsh/plan-presentation.mjs'; +import { DshPermissionView } from '../dsh/permissions.mjs'; +import { codexForkAtSeq } from '../dsh/session-fork.mjs'; +import { dshSkillsListEntry } from '../dsh/skills.mjs'; +import { foldDshSessionTitle, threadNameUpdatedNotification } from '../dsh/thread-title.mjs'; +import { DshThreadController } from '../dsh/thread-controller.mjs'; +import { codexInputToDshContent, dshContentText } from '../dsh/user-input.mjs'; +import { DshUserQuestionBridge } from '../dsh/user-question-bridge.mjs'; +import { DshUserShellBridge } from '../dsh/user-shell.mjs'; +import { persistedTokenUsageNotification } from '../dsh/token-usage.mjs'; +import { DshWorkspaceCommandBridge } from '../dsh/workspace-command.mjs'; import { UiRequestBroker } from '../protocol/request-broker.mjs'; const INVALID_REQUEST = -32600; diff --git a/src/dsh/codex-shapes.mjs b/src/tui-protocol/shapes.mjs similarity index 99% rename from src/dsh/codex-shapes.mjs rename to src/tui-protocol/shapes.mjs index acfa7e05..3f99f45c 100644 --- a/src/dsh/codex-shapes.mjs +++ b/src/tui-protocol/shapes.mjs @@ -1,4 +1,4 @@ -import { DshToolPresentationResolver } from './tool-presentation.mjs'; +import { DshToolPresentationResolver } from '../dsh/tool-presentation.mjs'; const MODEL_PREFIX = 'dshx:'; const DEFAULT_REASONING_SENTINEL = 'dsh-default'; diff --git a/test/dsh-app-server-adapter.test.mjs b/test/dsh-app-server-adapter.test.mjs index 18ea26cb..479a029b 100644 --- a/test/dsh-app-server-adapter.test.mjs +++ b/test/dsh-app-server-adapter.test.mjs @@ -1,7 +1,7 @@ import assert from 'node:assert/strict'; import test from 'node:test'; -import { DshxPresentationAdapter } from '../src/dsh/presentation-adapter.mjs'; -import { decodeDshModel } from '../src/dsh/codex-shapes.mjs'; +import { DshxPresentationAdapter } from '../src/tui-protocol/adapter.mjs'; +import { decodeDshModel } from '../src/tui-protocol/shapes.mjs'; function fixture() { const sent = []; diff --git a/test/dsh-codex-shapes.test.mjs b/test/dsh-codex-shapes.test.mjs index ce9cf5ee..4ff87676 100644 --- a/test/dsh-codex-shapes.test.mjs +++ b/test/dsh-codex-shapes.test.mjs @@ -7,7 +7,7 @@ import { dshTurnsFromSession, encodeDshModel, normalizeCodexEffort -} from '../src/dsh/codex-shapes.mjs'; +} from '../src/tui-protocol/shapes.mjs'; test('model picker encodes provider identity without hard-coding provider semantics', () => { const directory = { diff --git a/test/dsh-compaction-projection.test.mjs b/test/dsh-compaction-projection.test.mjs index 028881cf..d8fa4a70 100644 --- a/test/dsh-compaction-projection.test.mjs +++ b/test/dsh-compaction-projection.test.mjs @@ -1,7 +1,7 @@ import assert from 'node:assert/strict'; import test from 'node:test'; -import { dshTurnsFromSession } from '../src/dsh/codex-shapes.mjs'; -import { DshxPresentationAdapter } from '../src/dsh/presentation-adapter.mjs'; +import { dshTurnsFromSession } from '../src/tui-protocol/shapes.mjs'; +import { DshxPresentationAdapter } from '../src/tui-protocol/adapter.mjs'; import { DshSessionProjector } from '../src/dsh/session-projector.mjs'; const event = (type, data, time, seq = 0) => ({ type, data, time, seq }); diff --git a/test/dsh-domain-delegation.test.mjs b/test/dsh-domain-delegation.test.mjs index 5b6db0bc..7e8acdcb 100644 --- a/test/dsh-domain-delegation.test.mjs +++ b/test/dsh-domain-delegation.test.mjs @@ -1,6 +1,6 @@ import assert from 'node:assert/strict'; import test from 'node:test'; -import { DshxPresentationAdapter } from '../src/dsh/presentation-adapter.mjs'; +import { DshxPresentationAdapter } from '../src/tui-protocol/adapter.mjs'; function bareAdapter() { const adapter = Object.create(DshxPresentationAdapter.prototype); diff --git a/test/dsh-product-adapter.test.mjs b/test/dsh-product-adapter.test.mjs index bfdb80b4..885aa8c0 100644 --- a/test/dsh-product-adapter.test.mjs +++ b/test/dsh-product-adapter.test.mjs @@ -1,7 +1,7 @@ import assert from 'node:assert/strict'; import path from 'node:path'; import test from 'node:test'; -import { DshxPresentationAdapter } from '../src/dsh/presentation-adapter.mjs'; +import { DshxPresentationAdapter } from '../src/tui-protocol/adapter.mjs'; function bareAdapter() { const adapter = Object.create(DshxPresentationAdapter.prototype); diff --git a/test/dsh-product-fork.test.mjs b/test/dsh-product-fork.test.mjs index 18d56770..39ede3d4 100644 --- a/test/dsh-product-fork.test.mjs +++ b/test/dsh-product-fork.test.mjs @@ -1,6 +1,6 @@ import assert from 'node:assert/strict'; import test from 'node:test'; -import { DshxPresentationAdapter } from '../src/dsh/presentation-adapter.mjs'; +import { DshxPresentationAdapter } from '../src/tui-protocol/adapter.mjs'; function sourceAgent() { return { diff --git a/test/dsh-product-resume.test.mjs b/test/dsh-product-resume.test.mjs index 654e5fe3..f3de4b61 100644 --- a/test/dsh-product-resume.test.mjs +++ b/test/dsh-product-resume.test.mjs @@ -1,6 +1,6 @@ import assert from 'node:assert/strict'; import test from 'node:test'; -import { DshxPresentationAdapter } from '../src/dsh/presentation-adapter.mjs'; +import { DshxPresentationAdapter } from '../src/tui-protocol/adapter.mjs'; function adapterFixture() { const adapter = Object.create(DshxPresentationAdapter.prototype); diff --git a/test/dsh-rc5-acceptance-regressions.test.mjs b/test/dsh-rc5-acceptance-regressions.test.mjs index 89c0c007..d07153c9 100644 --- a/test/dsh-rc5-acceptance-regressions.test.mjs +++ b/test/dsh-rc5-acceptance-regressions.test.mjs @@ -1,7 +1,7 @@ import assert from 'node:assert/strict'; import test from 'node:test'; -import { encodeDshModel } from '../src/dsh/codex-shapes.mjs'; -import { DshxPresentationAdapter } from '../src/dsh/presentation-adapter.mjs'; +import { encodeDshModel } from '../src/tui-protocol/shapes.mjs'; +import { DshxPresentationAdapter } from '../src/tui-protocol/adapter.mjs'; test('thread/loaded/list returns thread ids rather than thread maps', () => { const adapter = Object.create(DshxPresentationAdapter.prototype); diff --git a/test/dsh-release-title.test.mjs b/test/dsh-release-title.test.mjs index 4e47edde..35e507aa 100644 --- a/test/dsh-release-title.test.mjs +++ b/test/dsh-release-title.test.mjs @@ -1,6 +1,6 @@ import assert from 'node:assert/strict'; import test from 'node:test'; -import { DshxPresentationAdapter } from '../src/dsh/presentation-adapter.mjs'; +import { DshxPresentationAdapter } from '../src/tui-protocol/adapter.mjs'; import { foldDshSessionTitle } from '../src/dsh/thread-title.mjs'; test('durable title fold is latest-wins over DSH session/title events', () => { diff --git a/test/dsh-subagent-authority.test.mjs b/test/dsh-subagent-authority.test.mjs index 624327b7..b9044e54 100644 --- a/test/dsh-subagent-authority.test.mjs +++ b/test/dsh-subagent-authority.test.mjs @@ -1,6 +1,6 @@ import assert from 'node:assert/strict'; import test from 'node:test'; -import { DshxPresentationAdapter } from '../src/dsh/presentation-adapter.mjs'; +import { DshxPresentationAdapter } from '../src/tui-protocol/adapter.mjs'; function childController() { let cancelled = 0; diff --git a/test/dsh-subagent-presentation.test.mjs b/test/dsh-subagent-presentation.test.mjs index 5ed6bd24..758ccd7f 100644 --- a/test/dsh-subagent-presentation.test.mjs +++ b/test/dsh-subagent-presentation.test.mjs @@ -1,7 +1,7 @@ import assert from 'node:assert/strict'; import test from 'node:test'; -import { dshThreadFromSnapshot } from '../src/dsh/codex-shapes.mjs'; -import { DshxPresentationAdapter } from '../src/dsh/presentation-adapter.mjs'; +import { dshThreadFromSnapshot } from '../src/tui-protocol/shapes.mjs'; +import { DshxPresentationAdapter } from '../src/tui-protocol/adapter.mjs'; function childAgent() { return { From 6ae17b53f74de5bed9290d1ee448efb05f7dc1d9 Mon Sep 17 00:00:00 2001 From: code-new-bie <245316967+code-new-bie@users.noreply.github.com> Date: Wed, 26 Aug 2026 15:34:32 +0800 Subject: [PATCH 11/60] docs: describe the tui-protocol boundary in the architecture map --- docs/ARCHITECTURE.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md index 2139b10f..dcdf5a25 100644 --- a/docs/ARCHITECTURE.md +++ b/docs/ARCHITECTURE.md @@ -56,7 +56,10 @@ If a DSH capability is unavailable or cannot be represented safely, DSHX must di ## Protocol mapping -Mappings are UI projections, not replacement implementations. +Mappings are UI projections, not replacement implementations. The Codex +dialect is confined to `src/tui-protocol/` (wire-format dictionary plus the +app-server method router); domain modules under `src/dsh/` speak DSH +vocabulary only, and the ownership guard enforces that placement. | Codex concept | DSH source | |---|---| From a2a66795001db8dc6fe588f30959ecaf859ecd7e Mon Sep 17 00:00:00 2001 From: code-new-bie <245316967+code-new-bie@users.noreply.github.com> Date: Wed, 26 Aug 2026 16:14:54 +0800 Subject: [PATCH 12/60] fix(package): slim bundle flavor + scoped npm pack parsing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Staged release package keeps host services as peerDependencies and ships only leaf parser libraries as dependencies: profile installs stay free of stateful runtime copies (single-instance rule) and never trip pnpm's build-script gate (node-pty/koffi/protobufjs all live in the healed host closure instead). - Shrinkwrap root records the staged peerDependencies. - Accept both npm pack --json shapes (array pre-10, name-keyed object since scoped records) — the old packed[0] access broke every scoped release. --- scripts/package-platform.mjs | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/scripts/package-platform.mjs b/scripts/package-platform.mjs index b0d88bf8..aedca39d 100644 --- a/scripts/package-platform.mjs +++ b/scripts/package-platform.mjs @@ -90,13 +90,14 @@ const packageJson = { cpu: [arch], engines: rootPackage.engines, bin: { dshx: './bin/dshx.mjs' }, - // The staged CLI must keep its bundle identity: the launcher bootstraps the - // surface profile by installing this very directory via `dsh plugin add`. + // Bundle flavor: host services stay peers so profile installs never pull + // stateful runtime copies (single-instance rule) nor trip pnpm build-script + // gates; only leaf parser libraries ship as real dependencies. Binaries are + // embedded below via dist/bin, resolved as file paths at runtime. exports: rootPackage.exports, dsh: rootPackage.dsh, - // Runtime host services ride as peers in the repo manifest but must be real - // dependencies of the installable CLI closure. - dependencies: { ...(rootPackage.dependencies ?? {}), ...(rootPackage.peerDependencies ?? {}) }, + peerDependencies: rootPackage.peerDependencies, + dependencies: rootPackage.dependencies, repository: { type: 'git', url: 'https://github.com/code-new-bie/dsh-codex.git' }, files: [ 'bin/dshx.mjs', @@ -146,6 +147,7 @@ shrinkwrapRoot.cpu = packageJson.cpu; shrinkwrapRoot.engines = packageJson.engines; shrinkwrapRoot.bin = packageJson.bin; shrinkwrapRoot.dependencies = packageJson.dependencies; +shrinkwrapRoot.peerDependencies = packageJson.peerDependencies ?? {}; delete shrinkwrapRoot.devDependencies; const shrinkwrapPath = path.join(stage, 'npm-shrinkwrap.json'); fs.writeFileSync(shrinkwrapPath, `${JSON.stringify(shrinkwrap, null, 2)}\n`); @@ -176,7 +178,10 @@ const packOutput = execFileSync( { cwd: root, encoding: 'utf8', stdio: ['ignore', 'pipe', 'inherit'] } ); const packed = JSON.parse(packOutput); -const filename = packed[0]?.filename; +// npm <10 returns a top-level array; newer npm keys the record by package +// name (mandatory for scoped names like @code-new-bie/dshx-tui). +const packRecord = Array.isArray(packed) ? packed[0] : packed[Object.keys(packed)[0]]; +const filename = packRecord?.filename; if (!filename) throw new Error(`npm pack did not return a filename: ${packOutput}`); const sourceTarball = path.join(out, filename); const targetTarball = path.join(out, `dshx-${version}-${platform}-${arch}.tgz`); From d9a22f108b7540deeb9bd4346c0184d03ed5673f Mon Sep 17 00:00:00 2001 From: code-new-bie <245316967+code-new-bie@users.noreply.github.com> Date: Wed, 26 Aug 2026 16:25:42 +0800 Subject: [PATCH 13/60] test(bundle): verify the packaged release tarball end to end MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit verify-bundle-install gains a release flavor: when dist/release carries a packaged artifact, it installs that exact tarball into a fresh profile via the official command and proves loader activation with zero environment overrides — endpoint live, bridge resolved from the installed copy's own dist/bin, no stateful runtime shadowing. DSHX_REQUIRE_RELEASE=1 turns the missing-artifact skip into a failure for CI wiring. Probe runs as a real file because the hmr row resolves process.argv[1]. Legacy test filenames follow the modules into the tui-protocol naming. --- .release/dshx-linux-x64/LICENSE | 201 + .release/dshx-linux-x64/NOTICE | 27 + .release/dshx-linux-x64/README.md | 174 + .release/dshx-linux-x64/bin/dshx.mjs | 376 + .release/dshx-linux-x64/cordis.patch.yml | 24 + .release/dshx-linux-x64/npm-shrinkwrap.json | 8299 +++++++++++++++++ .release/dshx-linux-x64/package.json | 62 + .release/dshx-linux-x64/src/cli/arguments.mjs | 29 + .release/dshx-linux-x64/src/cli/runtime.mjs | 27 + .../dshx-linux-x64/src/dsh/agent-driver.mjs | 213 + .../src/dsh/approval-bridge.mjs | 88 + .release/dshx-linux-x64/src/dsh/commands.mjs | 27 + .../dshx-linux-x64/src/dsh/history-pages.mjs | 77 + .release/dshx-linux-x64/src/dsh/host-api.mjs | 61 + .release/dshx-linux-x64/src/dsh/index.mjs | 25 + .../dshx-linux-x64/src/dsh/local-server.mjs | 363 + .../dshx-linux-x64/src/dsh/permissions.mjs | 106 + .../src/dsh/plan-presentation.mjs | 55 + .../src/dsh/presentation-plugin.mjs | 71 + .../src/dsh/profile-bootstrap.mjs | 99 + .../dshx-linux-x64/src/dsh/runtime-boot.mjs | 270 + .../dshx-linux-x64/src/dsh/session-fork.mjs | 55 + .../src/dsh/session-projector.mjs | 427 + .release/dshx-linux-x64/src/dsh/skills.mjs | 67 + .../dshx-linux-x64/src/dsh/startup-plugin.mjs | 72 + .../src/dsh/thread-controller.mjs | 205 + .../dshx-linux-x64/src/dsh/thread-title.mjs | 19 + .../dshx-linux-x64/src/dsh/token-usage.mjs | 116 + .../src/dsh/tool-presentation.mjs | 219 + .../dshx-linux-x64/src/dsh/user-input.mjs | 106 + .../src/dsh/user-question-bridge.mjs | 101 + .../dshx-linux-x64/src/dsh/user-shell.mjs | 209 + .../src/dsh/workspace-command.mjs | 166 + .../src/protocol/request-broker.mjs | 79 + .../src/tui-protocol/adapter.mjs | 1302 +++ .../src/tui-protocol/shapes.mjs | 419 + .release/dshx-linux-x64/upstream/CODEX_COMMIT | 1 + .release/dshx-linux-x64/upstream/DSH_COMMIT | 1 + .../codex/0001-dshx-force-ui-backend.patch | 65 + .../patches/codex/0002-dshx-branding.patch | 38 + .../codex/0003-dshx-approval-semantics.patch | 91 + .../codex/0004-dshx-permission-picker.patch | 60 + .../0005-dshx-skip-codex-onboarding.patch | 112 + .../codex/0006-dshx-config-ownership.patch | 13 + .../codex/0007-dshx-thread-ownership.patch | 46 + .../patches/codex/0008-dshx-resume-hint.patch | 17 + .../codex/0009-dshx-slash-capabilities.patch | 106 + .../codex/0010-dshx-local-ipc-bridge.patch | 187 + .../codex/0011-dshx-ipc-self-check.patch | 100 + .../0012-dshx-rc5-presentation-fixes.patch | 144 + scripts/verify-bundle-install.mjs | 81 +- ...test.mjs => tui-protocol-adapter.test.mjs} | 0 ....test.mjs => tui-protocol-shapes.test.mjs} | 0 53 files changed, 15297 insertions(+), 1 deletion(-) create mode 100644 .release/dshx-linux-x64/LICENSE create mode 100644 .release/dshx-linux-x64/NOTICE create mode 100644 .release/dshx-linux-x64/README.md create mode 100644 .release/dshx-linux-x64/bin/dshx.mjs create mode 100644 .release/dshx-linux-x64/cordis.patch.yml create mode 100644 .release/dshx-linux-x64/npm-shrinkwrap.json create mode 100644 .release/dshx-linux-x64/package.json create mode 100644 .release/dshx-linux-x64/src/cli/arguments.mjs create mode 100644 .release/dshx-linux-x64/src/cli/runtime.mjs create mode 100644 .release/dshx-linux-x64/src/dsh/agent-driver.mjs create mode 100644 .release/dshx-linux-x64/src/dsh/approval-bridge.mjs create mode 100644 .release/dshx-linux-x64/src/dsh/commands.mjs create mode 100644 .release/dshx-linux-x64/src/dsh/history-pages.mjs create mode 100644 .release/dshx-linux-x64/src/dsh/host-api.mjs create mode 100644 .release/dshx-linux-x64/src/dsh/index.mjs create mode 100644 .release/dshx-linux-x64/src/dsh/local-server.mjs create mode 100644 .release/dshx-linux-x64/src/dsh/permissions.mjs create mode 100644 .release/dshx-linux-x64/src/dsh/plan-presentation.mjs create mode 100644 .release/dshx-linux-x64/src/dsh/presentation-plugin.mjs create mode 100644 .release/dshx-linux-x64/src/dsh/profile-bootstrap.mjs create mode 100644 .release/dshx-linux-x64/src/dsh/runtime-boot.mjs create mode 100644 .release/dshx-linux-x64/src/dsh/session-fork.mjs create mode 100644 .release/dshx-linux-x64/src/dsh/session-projector.mjs create mode 100644 .release/dshx-linux-x64/src/dsh/skills.mjs create mode 100644 .release/dshx-linux-x64/src/dsh/startup-plugin.mjs create mode 100644 .release/dshx-linux-x64/src/dsh/thread-controller.mjs create mode 100644 .release/dshx-linux-x64/src/dsh/thread-title.mjs create mode 100644 .release/dshx-linux-x64/src/dsh/token-usage.mjs create mode 100644 .release/dshx-linux-x64/src/dsh/tool-presentation.mjs create mode 100644 .release/dshx-linux-x64/src/dsh/user-input.mjs create mode 100644 .release/dshx-linux-x64/src/dsh/user-question-bridge.mjs create mode 100644 .release/dshx-linux-x64/src/dsh/user-shell.mjs create mode 100644 .release/dshx-linux-x64/src/dsh/workspace-command.mjs create mode 100644 .release/dshx-linux-x64/src/protocol/request-broker.mjs create mode 100644 .release/dshx-linux-x64/src/tui-protocol/adapter.mjs create mode 100644 .release/dshx-linux-x64/src/tui-protocol/shapes.mjs create mode 100644 .release/dshx-linux-x64/upstream/CODEX_COMMIT create mode 100644 .release/dshx-linux-x64/upstream/DSH_COMMIT create mode 100644 .release/dshx-linux-x64/upstream/patches/codex/0001-dshx-force-ui-backend.patch create mode 100644 .release/dshx-linux-x64/upstream/patches/codex/0002-dshx-branding.patch create mode 100644 .release/dshx-linux-x64/upstream/patches/codex/0003-dshx-approval-semantics.patch create mode 100644 .release/dshx-linux-x64/upstream/patches/codex/0004-dshx-permission-picker.patch create mode 100644 .release/dshx-linux-x64/upstream/patches/codex/0005-dshx-skip-codex-onboarding.patch create mode 100644 .release/dshx-linux-x64/upstream/patches/codex/0006-dshx-config-ownership.patch create mode 100644 .release/dshx-linux-x64/upstream/patches/codex/0007-dshx-thread-ownership.patch create mode 100644 .release/dshx-linux-x64/upstream/patches/codex/0008-dshx-resume-hint.patch create mode 100644 .release/dshx-linux-x64/upstream/patches/codex/0009-dshx-slash-capabilities.patch create mode 100644 .release/dshx-linux-x64/upstream/patches/codex/0010-dshx-local-ipc-bridge.patch create mode 100644 .release/dshx-linux-x64/upstream/patches/codex/0011-dshx-ipc-self-check.patch create mode 100644 .release/dshx-linux-x64/upstream/patches/codex/0012-dshx-rc5-presentation-fixes.patch rename test/{dsh-app-server-adapter.test.mjs => tui-protocol-adapter.test.mjs} (100%) rename test/{dsh-codex-shapes.test.mjs => tui-protocol-shapes.test.mjs} (100%) diff --git a/.release/dshx-linux-x64/LICENSE b/.release/dshx-linux-x64/LICENSE new file mode 100644 index 00000000..4606e72e --- /dev/null +++ b/.release/dshx-linux-x64/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright 2025 OpenAI + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/.release/dshx-linux-x64/NOTICE b/.release/dshx-linux-x64/NOTICE new file mode 100644 index 00000000..33df6516 --- /dev/null +++ b/.release/dshx-linux-x64/NOTICE @@ -0,0 +1,27 @@ +DSHX / dsh-codex +Copyright 2026 dsh-codex contributors + +This distribution includes a modified build of OpenAI Codex TUI sourced from: +https://github.com/openai/codex +Pinned source commit: see upstream/CODEX_COMMIT + +OpenAI Codex +Copyright 2025 OpenAI +Licensed under the Apache License, Version 2.0. + +The upstream OpenAI Codex NOTICE states: + +OpenAI Codex +Copyright 2025 OpenAI + +This project includes code derived from Ratatui (https://github.com/ratatui/ratatui), licensed under the MIT license. +Copyright (c) 2016-2022 Florian Dehau +Copyright (c) 2023-2025 The Ratatui Developers + +DSHX modifies only a small presentation/launcher seam in the pinned Codex TUI. +The ordered source patches are distributed under upstream/patches/codex/. + +DeepSeek Harness is not forked or vendored by DSHX. It is installed as an +upstream npm dependency and remains the authoritative runtime for Agent, +Session, model routing, tools, sandboxing, approvals, skills and related +capabilities. Its own package license and notices remain with that dependency. diff --git a/.release/dshx-linux-x64/README.md b/.release/dshx-linux-x64/README.md new file mode 100644 index 00000000..e4bf19e2 --- /dev/null +++ b/.release/dshx-linux-x64/README.md @@ -0,0 +1,174 @@ +# DSHX (`dsh-codex`) + +DSHX is a terminal frontend for **official DeepSeek Harness** that reuses a pinned Codex TUI thin fork instead of reimplementing a look-alike terminal UI. + +## Product contract + +From a code project, the normal user entry point is: + +```bash +dshx +``` + +No separate Codex installation, remote-mode command, bridge command, DSH WebUI, or manual profile plumbing is part of the production UX. + +The interaction target is the pinned Codex CLI/TUI: welcome screen, composer, slash commands, model and permission pickers, approvals, ask-user flows, tool/shell cells, diffs, plan/reasoning presentation, steering, Ctrl+C interrupt, resume, status/footer, scrolling, resize and mouse behavior. Windows Terminal and CJK/IME are first-class release gates. + +## Plugin usage + +DSHX ships as a standard DSH profile bundle: the package manifest declares +`dsh.bundle.patch`, so the official machinery installs, layers, hot-reloads +and withdraws it like any other composition row set. + +```bash +# Install into any profile (tarball from a release, or this checkout): +dsh plugin --profile tui add ./code-new-bie-dshx-tui-.tgz + +# Withdraw it again; the surface disappears on the next profile start: +dsh plugin --profile tui remove @code-new-bie/dshx-tui +``` + +The zero-argument `dshx` launcher is a thin bootstrap over the same command: +it ensures the selected profile carries this exact package version, boots the +official composition, and spawns the pinned TUI against the endpoint that the +loader-mounted surface rows publish. + +## Ownership boundary + +We maintain only: + +- the Codex TUI thin fork and upstream sync patches; +- TUI behavior and UX parity; +- the `dshx` launcher, local presentation transport and packaging; +- the thinnest practical projection from DSH **public APIs/events** into the TUI protocol. + +We do **not** maintain, fork or recreate DeepSeek Harness capabilities. DSH owns the agent loop, sessions, model routing, tools, sandbox, approval policy, skills, subagents, plugins, jobs/workflows and persistence. + +If DSH does not expose a capability, DSHX waits for upstream or explicitly hides/degrades the corresponding UI. It does not implement a replacement runtime. + +```text +pinned Codex TUI thin fork ← DSHX presentation + │ + │ WebSocket framing over private local UDS + ▼ +dshx-ipc-bridge ← tiny transport bridge; no runtime state + │ + │ JSONL over child stdio + ▼ +DSHX presentation adapter ← translation only + │ +════════════════ ownership boundary ════════════════ + │ official DSH public APIs/events + ▼ +Official DeepSeek Harness ← Agent / Session / tools / policy / persistence +``` + +There is **no TCP listener in the production launch path**. The bridge reuses Codex's own cross-platform `codex_uds` implementation so the Rust TUI and Node DSH composition can stay in separate processes without unsafe FFI. + +## Current integration status + +`release/1.0-rc` is the sole production release-candidate integration branch, reviewed directly against `main` in Draft PR #11. Older M0/M1/thin-launcher/transport PRs are historical workstreams rather than release dependencies. + +The selected production transport is the small local-IPC bridge above. The alternative experiment that added a larger direct-stdio transport implementation inside the Codex client is intentionally excluded from the 1.0 line to keep the maintained upstream diff smaller. + +The candidate implementation includes: + +- zero-argument `dshx` launch and `dshx resume` flows; +- official DSH runtime composition and exact supported DSH rc.8 release-closure checks; +- DSH-backed session/history, model, permissions, approvals, ask-user, tools/shell/diffs, plan/reasoning, steering/interrupt, rename, fork/compaction, skills and subagent presentation boundaries; +- pinned Codex TUI build plus packaged cross-platform local IPC bridge; +- an executable visible-slash-command contract so every runtime-owned command left visible is either DSH-backed or the build fails; +- release artifacts for Linux x64, Windows x64, macOS arm64 and macOS x64; +- clean-install `dshx doctor`, including a real local UDS + WebSocket-framing ping/pong data-plane self-check; +- Linux/macOS real-TUI PTY smoke and Windows real-TUI ConPTY + Chinese-text smoke through the production local-IPC topology; +- fail-closed ownership/security tests that keep DSH authoritative. + +A commit is not called 1.0-ready merely because these paths exist. The exact release candidate must pass the repository CI/release gates and the side-by-side Windows Terminal/CJK/IME acceptance pass described in `docs/RELEASE-READINESS.md` and `docs/UX-PARITY.md`. + +## Install a release artifact + +Production users should install the **platform-specific tarball generated by a published DSHX release**, not build the pinned Codex workspace themselves. + +1. Download the tarball for your platform from the chosen GitHub release and verify its SHA-256 against that release's `SHA256SUMS`. +2. Install the downloaded artifact globally with npm: + +```bash +npm install --global ./dshx---.tgz +``` + +3. Verify the installed product, then enter any code project and start it: + +```bash +dshx --version +dshx doctor +cd /path/to/project +dshx +``` + +Windows PowerShell uses the same npm install command. For a 1.0 release-candidate acceptance run, use `scripts/windows-rc-acceptance.ps1` so the tarball checksum, isolated install, `dshx --version` and `dshx doctor` are verified before the real Windows Terminal/IME comparison. + +The release tarball already contains the matching native `dshx-tui` and `dshx-ipc-bridge` binaries. A separate Codex install, DSH WebUI process, bridge command or remote-mode setup is not part of installation. + +## Build from source + +Source builds are for contributors and DSHX development. The pinned DSH runtime supports Node.js `^22.19.0 || >=24.0.0`; DSHX 1.0 standardizes dependency freezing, CI and release builds on **Node.js 24 LTS / npm 11**. Rust/Cargo, Git and the platform toolchain required by the pinned Codex workspace are also required for native TUI builds. + +The release dependency graph is frozen outside CI so GitHub Actions never mutates the candidate branch. On a trusted Node 24 LTS machine with npm-registry access, generate and verify the lock with: + +```bash +npm run freeze:deps +``` + +Review and commit the generated `package-lock.json`. Do not hand-edit or fabricate it. After the graph has been frozen, all contributor/CI installs use: + +```bash +npm ci +``` + +Linux/macOS: + +```bash +./scripts/build-codex-tui.sh +npm link +dshx doctor +dshx +``` + +Windows PowerShell: + +```powershell +.\scripts\build-codex-tui.ps1 +npm link +dshx doctor +dshx +``` + +`dshx doctor` checks the DSH-compatible Node runtime, the packaged TUI, the local IPC data plane, the `tui` surface profile (bootstrapped idempotently through the official plugin command), the official DSH composition with the loader-activated surface rows, and the isolated DSHX presentation home/IPC path. + +For the full plugin-delivery proof — pack → official install into a throwaway profile → composed-tree assertions → loader activation with a live transport — run: + +```bash +npm run verify:bundle +``` + +## Release model + +GitHub Actions is an automation surface rather than the authority for repository correctness. Ordinary PR/main CI is deliberately lean: one Node 24 core job followed by one Linux TUI job. `release/**` adds real Windows ConPTY and macOS PTY/CJK/resize gates. Only `v*` tags run the full platform packaging, clean-install, provenance, checksum and publication matrix. + +The release workflow builds platform-specific installable tarballs from the frozen npm graph, builds the pinned TUI and IPC bridge, clean-installs each artifact, runs `dshx doctor`, exercises Linux/macOS PTY and Windows ConPTY real-TUI gates, verifies cross-platform provenance, and publishes SHA-256 checksums for both tarballs and provenance sidecars. Release candidates containing `-` in the tag are published as prereleases. + +The publishable `npm-shrinkwrap.json` inside each artifact is derived from the reviewed source `package-lock.json`; packaging does not resolve a second dependency graph. Release sidecars record the source-lock SHA-256 plus the pinned Codex and DSH commits. + +## Design references + +- `docs/ARCHITECTURE.md` +- `docs/RUNTIME-INTEGRATION.md` +- `docs/DSH-CAPABILITY-MATRIX.md` +- `docs/ROADMAP.md` +- `docs/UX-PARITY.md` +- `docs/RELEASE-READINESS.md` +- `SECURITY.md` + +## License + +Apache-2.0 for project-owned code. Synchronized upstream code keeps its applicable upstream notices and license requirements. diff --git a/.release/dshx-linux-x64/bin/dshx.mjs b/.release/dshx-linux-x64/bin/dshx.mjs new file mode 100644 index 00000000..f77847ed --- /dev/null +++ b/.release/dshx-linux-x64/bin/dshx.mjs @@ -0,0 +1,376 @@ +#!/usr/bin/env node +import fs from 'node:fs'; +import os from 'node:os'; +import path from 'node:path'; +import process from 'node:process'; +import { spawn, spawnSync } from 'node:child_process'; +import { fileURLToPath } from 'node:url'; +import { parseCliInvocation } from '../src/cli/arguments.mjs'; +import { + DSHX_DOCTOR_BOOT_TIMEOUT_MS, + DSHX_DOCTOR_DISPOSE_TIMEOUT_MS, + isSupportedNodeVersion +} from '../src/cli/runtime.mjs'; +import { ensureProfileInstalled } from '../src/dsh/profile-bootstrap.mjs'; + +const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..'); +const PACKAGE = JSON.parse(fs.readFileSync(path.join(ROOT, 'package.json'), 'utf8')); +const VERSION = PACKAGE.version; +const REQUIRED_RUNTIME_SERVICES = [ + 'agents', + 'agentDefaultModel', + 'llm', + 'sessions', + 'sessionPersistence', + 'sessionQuery', + 'sessionProjections', + 'sessionTitle', + 'attachments', + 'tools', + 'commands', + 'compaction', + 'subagents', + 'permissionPresets', + 'approval', + 'userQuestions', + 'skills', + 'planMode', + // The surface rows themselves: their services exist only when the loader + // activated the bundle patch (dshx-startup / dshx-presentation). + 'dshxStartup', + 'dshxPresentation' +]; + +function usage() { + return `DSHX ${VERSION}\n\nUsage:\n dshx Start DSHX in the current project\n dshx Start with an initial prompt\n dshx resume Open the Codex-style DSH session picker\n dshx resume --last Resume the most recent DSH session\n dshx resume Resume a specific DSH session\n dshx doctor Check packaged TUI, local IPC and official DSH composition\n dshx --version Print version\n dshx --help Show this help\n\nEnvironment:\n DSHX_TUI_BIN Override the packaged DSHX TUI binary (development only)\n DSHX_IPC_BRIDGE_BIN Override the packaged local IPC bridge (development only)\n DSHX_TUI_HOME Override DSHX presentation-only Codex home (development only)\n DSHX_PROFILE Override the DSH profile surface (default: tui)\n DSHX_DEBUG=1 Print DSHX adapter diagnostics\n\nPlugin usage:\n The DSHX surface ships as a standard DSH profile bundle. Manage it through\n the official machinery, e.g.:\n dsh plugin --profile tui add ${PACKAGE.name}\n The zero-argument launcher only bootstraps the same profile via the same\n command, then hands control to the official DSH composition.\n\nProduct boundary:\n DSHX owns only the launcher, Codex TUI thin fork and presentation adapter.\n DeepSeek Harness remains the authoritative Agent/Session/Tool runtime.\n DSHX never reads or writes the user's ordinary CODEX_HOME.\n`; +} + +function commandDetail(command, result) { + if (result.status === 0) return (result.stdout || result.stderr).trim(); + if (result.error) return `${command} failed: ${result.error.message}`; + return `${command} is not runnable${result.stderr ? `: ${result.stderr.trim()}` : ''}`; +} + +function withTimeout(promise, timeoutMs, label) { + let timer; + return Promise.race([ + promise, + new Promise((_, reject) => { + timer = setTimeout(() => reject(new Error(`${label} exceeded ${timeoutMs}ms`)), timeoutMs); + }) + ]).finally(() => clearTimeout(timer)); +} + +function binaryCandidate(baseName) { + const fileName = process.platform === 'win32' ? `${baseName}.exe` : baseName; + return process.env[baseName === 'dshx-tui' ? 'DSHX_TUI_BIN' : 'DSHX_IPC_BRIDGE_BIN'] + || path.join(ROOT, 'dist', 'bin', fileName); +} + +function bootstrapSurfaceProfile(runtimeBoot) { + return ensureProfileInstalled({ + packageRoot: ROOT, + name: PACKAGE.name, + version: VERSION, + profile: process.env.DSHX_PROFILE || runtimeBoot.runtimeInternals.DEFAULT_PROFILE + }); +} + +async function loadRuntimeModules() { + try { + const runtimeBoot = await import('../src/dsh/runtime-boot.mjs'); + let localServerInternals; + try { + ({ localServerInternals } = await import('../src/dsh/local-server.mjs')); + } catch { + localServerInternals = undefined; + } + return { runtimeBoot, localServerInternals }; + } catch (error) { + return { loadError: error instanceof Error ? error.message : String(error) }; + } +} + +function presentationHomeCheck(localServerInternals) { + const home = path.resolve(process.env.DSHX_TUI_HOME || path.join(os.homedir(), '.dshx', 'codex-tui')); + try { + fs.mkdirSync(home, { recursive: true, mode: 0o700 }); + const stat = fs.statSync(home); + if (!stat.isDirectory()) throw new Error('path exists but is not a directory'); + fs.accessSync(home, fs.constants.R_OK | fs.constants.W_OK); + if (!localServerInternals) { + throw new Error('IPC policy unavailable because DSH modules failed to load'); + } + + // On Windows this also enforces that a custom DSHX_TUI_HOME stays below + // the current user's profile ACL boundary. Probe the fixed suffix used by + // the real random rendezvous directory so an obviously-too-long home fails + // in doctor before a runtime boot is attempted. + const socketRoot = localServerInternals.defaultSocketRoot({ home }); + const probeSocket = path.join(socketRoot, 'd-XXXXXX', 's'); + localServerInternals.assertSocketPathSupported(probeSocket); + return { ok: true, detail: home }; + } catch (error) { + return { ok: false, detail: `${home}: ${error instanceof Error ? error.message : String(error)}` }; + } +} + +async function officialRuntimeCheck(runtimeBoot) { + let ctx; + let primaryError; + let cleanupError; + try { + // Doctor deliberately exercises the same official composition and profile + // watcher path as production startup, including the loader-mounted surface + // rows (their services double as row-activation evidence). This catches + // missing native optional dependencies (for example sharp/koffi) that a + // static bundle-entry check cannot detect. The bounded timeout is + // intentionally generous enough for first-run Windows module/native + // initialization on supported hardware. + ctx = await withTimeout( + runtimeBoot.bootDshxRuntime({ cwd: process.cwd(), watch: true }), + DSHX_DOCTOR_BOOT_TIMEOUT_MS, + 'official DSH composition boot' + ); + const missing = REQUIRED_RUNTIME_SERVICES.filter((name) => ctx.get(name) == null); + if (missing.length > 0) { + throw new Error(`official DSH composition is missing required presentation services: ${missing.join(', ')}`); + } + } catch (error) { + primaryError = error; + } finally { + if (ctx) { + try { + await withTimeout( + Promise.resolve(ctx.dispose?.()), + DSHX_DOCTOR_DISPOSE_TIMEOUT_MS, + 'official DSH composition disposal' + ); + } catch (error) { + cleanupError = error; + } + } + } + + if (primaryError) { + const detail = primaryError instanceof Error ? primaryError.message : String(primaryError); + const cleanup = cleanupError + ? `; secondary cleanup failure: ${cleanupError instanceof Error ? cleanupError.message : String(cleanupError)}` + : ''; + return { ok: false, detail: `${detail}${cleanup}` }; + } + if (cleanupError) { + return { + ok: false, + detail: `official DSH composition disposal failed: ${cleanupError instanceof Error ? cleanupError.message : String(cleanupError)}` + }; + } + return { + ok: true, + detail: `official DSH composition boot/dispose (${REQUIRED_RUNTIME_SERVICES.length} required services, surface rows active)` + }; +} + +async function doctor(runtimeBoot) { + const executable = binaryCandidate('dshx-tui'); + const tuiCheck = fs.existsSync(executable) + ? spawnSync(executable, ['--version'], { encoding: 'utf8' }) + : { status: 127, stdout: '', stderr: '', error: null }; + const bridge = binaryCandidate('dshx-ipc-bridge'); + const bridgeCheck = fs.existsSync(bridge) + ? spawnSync(bridge, ['--check'], { encoding: 'utf8' }) + : { status: 127, stdout: '', stderr: '', error: null }; + + const { localServerInternals } = await loadRuntimeModules(); + const homeCheck = presentationHomeCheck(localServerInternals); + let profileDetail = ''; + let profileOk = true; + try { + const ensured = bootstrapSurfaceProfile(runtimeBoot); + profileDetail = `profile '${ensured.profile}' (${ensured.action})`; + } catch (error) { + profileOk = false; + profileDetail = error instanceof Error ? error.message : String(error); + } + const runtimeCheck = profileOk + ? await officialRuntimeCheck(runtimeBoot) + : { ok: false, detail: `skipped: ${profileDetail}` }; + + const rows = [ + ['Node', `${process.version} (required: ${PACKAGE.engines.node})`, isSupportedNodeVersion(process.versions.node)], + [ + 'Pinned Codex TUI', + tuiCheck.status === 0 ? commandDetail(executable, tuiCheck) : (executable ? commandDetail(executable, tuiCheck) : 'not found'), + tuiCheck.status === 0 + ], + [ + 'Local IPC bridge', + bridgeCheck.status === 0 ? `${bridge} (cross-platform Codex UDS)` : (bridge ? commandDetail(bridge, bridgeCheck) : 'not found'), + bridgeCheck.status === 0 + ], + ['Surface profile', profileDetail, profileOk], + ['DeepSeek Harness', runtimeCheck.detail, runtimeCheck.ok], + ['Presentation home / IPC path', homeCheck.detail, homeCheck.ok] + ]; + for (const [name, detail, ok] of rows) { + process.stdout.write(`${ok ? '✓' : '✗'} ${name}: ${detail}\n`); + } + if (rows.some((row) => !row[2])) { + process.stderr.write( + process.platform === 'win32' + ? 'For a source checkout, build the pinned TUI + IPC bridge with `.\\scripts\\build-codex-tui.ps1`; packaged releases include both.\n' + : 'For a source checkout, build the pinned TUI + IPC bridge with `./scripts/build-codex-tui.sh`; packaged releases include both.\n' + ); + process.exitCode = 1; + } +} + +async function run() { + const args = process.argv.slice(2); + let invocation; + + try { + invocation = parseCliInvocation(args); + } catch (error) { + process.stderr.write(`dshx: ${error.message}\n`); + process.exitCode = 2; + return; + } + + if (invocation.kind === 'help') { + process.stdout.write(usage()); + return; + } + if (invocation.kind === 'version') { + process.stdout.write(`${VERSION}\n`); + return; + } + if (invocation.kind === 'doctor') { + const [, runtimeBoot] = await loadRuntimeModules().then((m) => [m.loadError ? undefined : m.runtimeBoot, m.runtimeBoot]); + if (!runtimeBoot) { + process.stderr.write('dshx: failed to load official DeepSeek Harness runtime modules\n'); + process.exitCode = 1; + return; + } + await doctor(runtimeBoot); + return; + } + + if (!isSupportedNodeVersion(process.versions.node)) { + process.stderr.write(`dshx: unsupported Node ${process.version}; pinned DeepSeek Harness requires ${PACKAGE.engines.node}\n`); + process.stderr.write('Use Node 24 LTS for the DSHX 1.0 release baseline.\n'); + process.exitCode = 1; + return; + } + + const [, runtimeBoot] = await loadRuntimeModules().then((m) => [m.loadError ? undefined : m.runtimeBoot, m.runtimeBoot]); + if (!runtimeBoot) { + process.stderr.write('dshx: failed to load official DeepSeek Harness runtime modules\n'); + process.exitCode = 1; + return; + } + + const debug = process.env.DSHX_DEBUG === '1'; + let ctx; + try { + // Bootstrap the surface profile through the official plugin machinery, + // then hand control entirely to the official composition: the loader + // mounts the dshx-startup / dshx-presentation rows declared by the bundle + // patch, and the transport endpoint arrives as a provided service. + bootstrapSurfaceProfile(runtimeBoot); + ctx = await runtimeBoot.bootDshxRuntime({ cwd: process.cwd(), watch: true }); + } catch (error) { + process.stderr.write(`dshx: failed to boot DeepSeek Harness surface profile: ${error instanceof Error ? error.message : error}\n`); + process.exitCode = 1; + return; + } + + const startup = ctx.get('dshxStartup'); + const presentation = ctx.get('dshxPresentation'); + if (!startup || !presentation || typeof presentation.close !== 'function') { + process.stderr.write('dshx: surface rows did not publish dshxStartup/dshxPresentation services\n'); + try { await ctx.dispose?.(); } catch { /* primary failure already reported */ } + process.exitCode = 1; + return; + } + + const executable = startup.tuiCommand; + if (!executable || !fs.existsSync(executable)) { + process.stderr.write(`dshx: packaged TUI binary not found (${executable ?? 'unknown path'})\n`); + process.stderr.write('Run `dshx doctor` for build/install guidance.\n'); + try { await ctx.dispose?.(); } catch { /* ignore secondary */ } + process.exitCode = 127; + return; + } + + const tuiHome = startup.home; + try { + fs.mkdirSync(tuiHome, { recursive: true, mode: 0o700 }); + } catch (error) { + process.stderr.write(`dshx: cannot create presentation home ${tuiHome}: ${error instanceof Error ? error.message : error}\n`); + try { await ctx.dispose?.(); } catch { /* ignore secondary */ } + process.exitCode = 1; + return; + } + + let child; + try { + child = spawn(executable, invocation.tuiArgs, { + cwd: process.cwd(), + env: { + ...process.env, + // Do not inherit CODEX_HOME: DSHX uses Codex code as a presentation + // component only and must not read/write the user's ordinary Codex state. + CODEX_HOME: tuiHome, + ...invocation.resumeEnv, + DSHX_APP_SERVER_ENDPOINT: presentation.url + }, + stdio: 'inherit', + windowsHide: false + }); + } catch (error) { + process.stderr.write(`dshx: failed to launch pinned Codex TUI: ${error instanceof Error ? error.message : error}\n`); + try { await ctx.dispose?.(); } catch { /* ignore secondary */ } + process.exitCode = 127; + return; + } + + let closing = false; + const close = async (exitCode) => { + if (closing) return; + closing = true; + try { + // Root-fiber disposal unwinds the dshx-presentation plugin, whose + // disposer closes the transport; the Fiber remains the sole teardown + // authority. + await ctx.dispose?.(); + } catch (error) { + process.stderr.write(`dshx: shutdown cleanup failed: ${error instanceof Error ? error.message : error}\n`); + if (exitCode === 0) exitCode = 1; + } + process.exitCode = exitCode; + }; + + child.on('error', async (error) => { + process.stderr.write(`dshx: failed to launch pinned Codex TUI: ${error.message}\n`); + await close(127); + }); + child.on('exit', async (code, signal) => { + if (signal && debug) process.stderr.write(`[dshx] TUI exited via ${signal}\n`); + await close(code ?? (signal ? 1 : 0)); + }); + + // Process-lifecycle signals are forwarded to the TUI. Do not intercept + // SIGINT: Ctrl+C is an in-TUI interaction used by Codex to interrupt the + // active DSH turn. + process.once('SIGTERM', () => { + if (!child.killed) child.kill('SIGTERM'); + }); + if (process.platform !== 'win32') { + process.once('SIGHUP', () => { + if (!child.killed) child.kill('SIGHUP'); + }); + } +} + +await run(); diff --git a/.release/dshx-linux-x64/cordis.patch.yml b/.release/dshx-linux-x64/cordis.patch.yml new file mode 100644 index 00000000..207743f4 --- /dev/null +++ b/.release/dshx-linux-x64/cordis.patch.yml @@ -0,0 +1,24 @@ +# The DSHX surface bundle patch, riding over this profile's dsh-base layer. +# Loaded automatically because the package manifest declares +# `dsh.bundle.patch`; the loader applies it in `dsh.profile.bundles` order. +# +# Only the competing presentation rows are locked off; every runtime +# capability row remains user-authoritative (a targeted patch replaces a +# row's whole config, and these two carry no config of their own). +# +# Launch inputs flow through the official three-stage pattern: the +# dshx-startup row resolves the launcher/environment descriptor and provides +# the `dshxStartup` service; the dshx-presentation row injects it to start +# the local IPC transport and publish the `dshxPresentation` endpoint. +- id: headless-startup + disabled: true +- id: headless-runner + disabled: true + +- insert: + - id: dshx-startup + name: '@code-new-bie/dshx-tui/startup' + + - id: dshx-presentation + name: '@code-new-bie/dshx-tui/presentation' + inject: [dshxStartup] diff --git a/.release/dshx-linux-x64/npm-shrinkwrap.json b/.release/dshx-linux-x64/npm-shrinkwrap.json new file mode 100644 index 00000000..099477e2 --- /dev/null +++ b/.release/dshx-linux-x64/npm-shrinkwrap.json @@ -0,0 +1,8299 @@ +{ + "name": "@code-new-bie/dshx-tui", + "version": "0.0.0-m1", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "@code-new-bie/dshx-tui", + "version": "0.0.0-m1", + "dependencies": { + "@deepseek-ai/dsh-cmdline": "0.1.0-rc.8", + "@deepseek-ai/schemastery": "3.18.1" + }, + "bin": { + "dshx": "./bin/dshx.mjs" + }, + "engines": { + "node": "^22.19.0 || >=24.0.0" + }, + "peerDependencies": { + "@deepseek-ai/dsh": "0.1.0-rc.8", + "@deepseek-ai/dsh-agent": "0.1.0-rc.8", + "@deepseek-ai/dsh-app-boot": "0.1.0-rc.8", + "@deepseek-ai/dsh-host-apiproxy": "0.1.0-rc.8", + "@deepseek-ai/dsh-launch-environment": "0.1.0-rc.8", + "@deepseek-ai/dsh-llm": "0.1.0-rc.8", + "@deepseek-ai/dsh-session": "0.1.0-rc.8" + }, + "license": "Apache-2.0", + "os": [ + "linux" + ], + "cpu": [ + "x64" + ] + }, + "node_modules/@anthropic-ai/sdk": { + "version": "0.91.1", + "resolved": "https://registry.npmmirror.com/@anthropic-ai/sdk/-/sdk-0.91.1.tgz", + "integrity": "sha512-LAmu761tSN9r66ixvmciswUj/ZC+1Q4iAfpedTfSVLeswRwnY3n2Nb6Tsk+cLPP28aLOPWeMgIuTuCcMC6W/iw==", + "dev": true, + "license": "MIT", + "dependencies": { + "json-schema-to-ts": "^3.1.1" + }, + "bin": { + "anthropic-ai-sdk": "bin/cli" + }, + "peerDependencies": { + "zod": "^3.25.0 || ^4.0.0" + }, + "peerDependenciesMeta": { + "zod": { + "optional": true + } + } + }, + "node_modules/@aws-crypto/sha256-browser": { + "version": "5.2.0", + "resolved": "https://registry.npmmirror.com/@aws-crypto/sha256-browser/-/sha256-browser-5.2.0.tgz", + "integrity": "sha512-AXfN/lGotSQwu6HNcEsIASo7kWXZ5HYWvfOmSNKDsEqC4OashTp8alTmaz+F7TC2L083SFv5RdB+qU3Vs1kZqw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/sha256-js": "^5.2.0", + "@aws-crypto/supports-web-crypto": "^5.2.0", + "@aws-crypto/util": "^5.2.0", + "@aws-sdk/types": "^3.222.0", + "@aws-sdk/util-locate-window": "^3.0.0", + "@smithy/util-utf8": "^2.0.0", + "tslib": "^2.6.2" + } + }, + "node_modules/@aws-crypto/sha256-js": { + "version": "5.2.0", + "resolved": "https://registry.npmmirror.com/@aws-crypto/sha256-js/-/sha256-js-5.2.0.tgz", + "integrity": "sha512-FFQQyu7edu4ufvIZ+OadFpHHOt+eSTBaYaki44c+akjg7qZg9oOQeLlk77F6tSYqjDAFClrHJk9tMf0HdVyOvA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/util": "^5.2.0", + "@aws-sdk/types": "^3.222.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-crypto/supports-web-crypto": { + "version": "5.2.0", + "resolved": "https://registry.npmmirror.com/@aws-crypto/supports-web-crypto/-/supports-web-crypto-5.2.0.tgz", + "integrity": "sha512-iAvUotm021kM33eCdNfwIN//F77/IADDSs58i+MDaOqFrVjZo9bAal0NK7HurRuWLLpF1iLX7gbWrjHjeo+YFg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + } + }, + "node_modules/@aws-crypto/util": { + "version": "5.2.0", + "resolved": "https://registry.npmmirror.com/@aws-crypto/util/-/util-5.2.0.tgz", + "integrity": "sha512-4RkU9EsI6ZpBve5fseQlGNUWKMa1RLPQ1dnjnQoe07ldfIzcsGb5hC5W0Dm7u423KWzawlrpbjXBrXCEv9zazQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "^3.222.0", + "@smithy/util-utf8": "^2.0.0", + "tslib": "^2.6.2" + } + }, + "node_modules/@aws-sdk/client-bedrock-runtime": { + "version": "3.1048.0", + "resolved": "https://registry.npmmirror.com/@aws-sdk/client-bedrock-runtime/-/client-bedrock-runtime-3.1048.0.tgz", + "integrity": "sha512-u+NT61JZEkRFtpL0CAw1N1dwxnaLgwVXQl/zjJxTGgLyS/jTIdg2SdoEoCTHxgDyCnqa1HEi9QOoE9/pYRNpOQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/core": "^3.974.11", + "@aws-sdk/credential-provider-node": "^3.972.42", + "@aws-sdk/eventstream-handler-node": "^3.972.16", + "@aws-sdk/middleware-eventstream": "^3.972.12", + "@aws-sdk/middleware-websocket": "^3.972.19", + "@aws-sdk/token-providers": "3.1048.0", + "@aws-sdk/types": "^3.973.8", + "@smithy/core": "^3.24.2", + "@smithy/fetch-http-handler": "^5.4.2", + "@smithy/node-http-handler": "^4.7.2", + "@smithy/types": "^4.14.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/core": { + "version": "3.977.8", + "resolved": "https://registry.npmmirror.com/@aws-sdk/core/-/core-3.977.8.tgz", + "integrity": "sha512-7+Kcrkvrk9lM/m7jRhHpT4jCdvzGHsuaSRbF8TdzzkY1mRzp/Ogwf9c7H29k4gGhey0BBWhCWr16+t0J61gwmg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "^3.974.4", + "@aws-sdk/xml-builder": "^3.972.39", + "@aws/lambda-invoke-store": "^0.3.0", + "@smithy/core": "^3.31.1", + "@smithy/signature-v4": "^5.6.12", + "@smithy/types": "^4.16.1", + "bowser": "^2.11.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-env": { + "version": "3.972.69", + "resolved": "https://registry.npmmirror.com/@aws-sdk/credential-provider-env/-/credential-provider-env-3.972.69.tgz", + "integrity": "sha512-AreCFzcB4kH2HF9031Ot0jSJr3KXvRg6e8uDeub20JEVdZU3Bv0sTq1plc7VsT3KiqutlzH7l0j50UcCWHUioA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "^3.977.8", + "@aws-sdk/types": "^3.974.4", + "@smithy/core": "^3.31.1", + "@smithy/types": "^4.16.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-http": { + "version": "3.972.71", + "resolved": "https://registry.npmmirror.com/@aws-sdk/credential-provider-http/-/credential-provider-http-3.972.71.tgz", + "integrity": "sha512-A8ObcqVmDMnk4F9NozZ7JwmUu9Q4xyBJkmyq1C5U+wNM9ht9J7+EuuyabsLWXZnOoTqFaJuYBYTKf5CTipkEjA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "^3.977.8", + "@aws-sdk/types": "^3.974.4", + "@smithy/core": "^3.31.1", + "@smithy/fetch-http-handler": "^5.6.13", + "@smithy/node-http-handler": "^4.9.13", + "@smithy/types": "^4.16.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-http/node_modules/@smithy/node-http-handler": { + "version": "4.11.2", + "resolved": "https://registry.npmmirror.com/@smithy/node-http-handler/-/node-http-handler-4.11.2.tgz", + "integrity": "sha512-avwAh9HM3h2lcfjvP3zYIZGf+XVgLQ91wOJ2qoFbNpW1UZeZb33aGlhTZvtkANHfcGhJroRY64525OjfgOg30g==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@smithy/core": "^3.33.2", + "@smithy/types": "^4.17.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-ini": { + "version": "3.973.14", + "resolved": "https://registry.npmmirror.com/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.973.14.tgz", + "integrity": "sha512-7c+Wti2LsERNWMfm7ySz3/6RPopFW3Nmn7s63Xpcq6R/tRuY5hpvkHA2xVgi5ukJbvok9l0IDtVEvqTtg+X7dw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "^3.977.8", + "@aws-sdk/credential-provider-env": "^3.972.69", + "@aws-sdk/credential-provider-http": "^3.972.71", + "@aws-sdk/credential-provider-login": "^3.972.76", + "@aws-sdk/credential-provider-process": "^3.972.69", + "@aws-sdk/credential-provider-sso": "^3.973.13", + "@aws-sdk/credential-provider-web-identity": "^3.972.75", + "@aws-sdk/nested-clients": "^3.997.43", + "@aws-sdk/types": "^3.974.4", + "@smithy/core": "^3.31.1", + "@smithy/credential-provider-imds": "^4.4.16", + "@smithy/types": "^4.16.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-login": { + "version": "3.972.76", + "resolved": "https://registry.npmmirror.com/@aws-sdk/credential-provider-login/-/credential-provider-login-3.972.76.tgz", + "integrity": "sha512-LVixwOnEJfrrfKHeZjBA8pIMTZjNDq8ak8VpcoWUuCJDrSnBNU8POJksULMgvN089P0MXtQYH2Zs627/MK1K0g==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "^3.977.8", + "@aws-sdk/nested-clients": "^3.997.43", + "@aws-sdk/types": "^3.974.4", + "@smithy/core": "^3.31.1", + "@smithy/types": "^4.16.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-node": { + "version": "3.972.80", + "resolved": "https://registry.npmmirror.com/@aws-sdk/credential-provider-node/-/credential-provider-node-3.972.80.tgz", + "integrity": "sha512-bE2qh8ww4iClO1jHsBXdOE8FUgzDbdxbyorNjSCoPSkQd51k3jODItuPZfuwcLHZqDXsH+bI4AMHhqtuyR7mSg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/credential-provider-env": "^3.972.69", + "@aws-sdk/credential-provider-http": "^3.972.71", + "@aws-sdk/credential-provider-ini": "^3.973.14", + "@aws-sdk/credential-provider-process": "^3.972.69", + "@aws-sdk/credential-provider-sso": "^3.973.13", + "@aws-sdk/credential-provider-web-identity": "^3.972.75", + "@aws-sdk/types": "^3.974.4", + "@smithy/core": "^3.31.1", + "@smithy/credential-provider-imds": "^4.4.16", + "@smithy/types": "^4.16.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-process": { + "version": "3.972.69", + "resolved": "https://registry.npmmirror.com/@aws-sdk/credential-provider-process/-/credential-provider-process-3.972.69.tgz", + "integrity": "sha512-9kpTNdZTrcqXTfhxM7fgl9Z68ek3Fu5oe3Yf+A/pJGibEqpgZxz2tSY7SinmyCIU2PJ+ygY4FPoBBnLpocMtrQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "^3.977.8", + "@aws-sdk/types": "^3.974.4", + "@smithy/core": "^3.31.1", + "@smithy/types": "^4.16.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-sso": { + "version": "3.973.13", + "resolved": "https://registry.npmmirror.com/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.973.13.tgz", + "integrity": "sha512-Oc81qauMPzUoTnAS2YKpNwY6sY/LUyQTEeaf6yP197WMxkEBQfcKLR1MFpD7+pNTubXnfkH6gwpji+Gc7iyD2Q==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "^3.977.8", + "@aws-sdk/nested-clients": "^3.997.43", + "@aws-sdk/token-providers": "3.1111.0", + "@aws-sdk/types": "^3.974.4", + "@smithy/core": "^3.31.1", + "@smithy/types": "^4.16.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-sso/node_modules/@aws-sdk/token-providers": { + "version": "3.1111.0", + "resolved": "https://registry.npmmirror.com/@aws-sdk/token-providers/-/token-providers-3.1111.0.tgz", + "integrity": "sha512-JfljgoVtl+s3Qy21n9a7Z48uCQaOXcN74KJ3TEQfPoB293GrXFSt6HSQJF1sTZ8c/5QedEvd3NjJQMO4u9qa5A==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "^3.977.8", + "@aws-sdk/nested-clients": "^3.997.43", + "@aws-sdk/types": "^3.974.4", + "@smithy/core": "^3.31.1", + "@smithy/types": "^4.16.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-web-identity": { + "version": "3.972.75", + "resolved": "https://registry.npmmirror.com/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.972.75.tgz", + "integrity": "sha512-YPN6uoGDgjjjeVFZrcOeCJqmB6zpXoeeNgIjqe+DexJaWqdjVfCCe+VAZwli9Z2h8KhFW8oxkO39emQ1tyz/Mw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "^3.977.8", + "@aws-sdk/nested-clients": "^3.997.43", + "@aws-sdk/types": "^3.974.4", + "@smithy/core": "^3.31.1", + "@smithy/types": "^4.16.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/eventstream-handler-node": { + "version": "3.972.33", + "resolved": "https://registry.npmmirror.com/@aws-sdk/eventstream-handler-node/-/eventstream-handler-node-3.972.33.tgz", + "integrity": "sha512-1Dd5WyEE2Kb3HvY44u7Ob16ST2W6iutOqsQ8Y2hUmsL2mAH/STlGS1dS9h3IOE6L7Ld3AR2HzKJ6XeCMOw8Peg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "^3.974.4", + "@smithy/core": "^3.31.1", + "@smithy/types": "^4.16.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/middleware-eventstream": { + "version": "3.972.28", + "resolved": "https://registry.npmmirror.com/@aws-sdk/middleware-eventstream/-/middleware-eventstream-3.972.28.tgz", + "integrity": "sha512-Z1EDXnS01P7H5jVrUx+/dBqV0m7dta7bSxLclkOuDuS93pNNQm0IcT4YLUbuvWKPYNxbI8aTG0p5Br30GSKDgA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "^3.974.4", + "@smithy/core": "^3.31.1", + "@smithy/types": "^4.16.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/middleware-websocket": { + "version": "3.972.51", + "resolved": "https://registry.npmmirror.com/@aws-sdk/middleware-websocket/-/middleware-websocket-3.972.51.tgz", + "integrity": "sha512-jdgP3jR5Q96j1jjZ98GGwpGg1CBNFIO2YE+vXg8cg8PvNY4NvgQNYJsqDaRX2PYv5gSUX/+C0D58Fhspj9ELMQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "^3.977.8", + "@aws-sdk/types": "^3.974.4", + "@smithy/core": "^3.31.1", + "@smithy/fetch-http-handler": "^5.6.13", + "@smithy/signature-v4": "^5.6.12", + "@smithy/types": "^4.16.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@aws-sdk/nested-clients": { + "version": "3.997.43", + "resolved": "https://registry.npmmirror.com/@aws-sdk/nested-clients/-/nested-clients-3.997.43.tgz", + "integrity": "sha512-bit+VpqWNyi3wHxFoTsTliNXimCSL2r2OeDTm7ZrG+YsTZ2D7ofDJ6r/t9PVBn80i6/v0X2h9Tgw6QP2MAKfPw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "^3.977.8", + "@aws-sdk/signature-v4-multi-region": "^3.996.45", + "@aws-sdk/types": "^3.974.4", + "@smithy/core": "^3.31.1", + "@smithy/fetch-http-handler": "^5.6.13", + "@smithy/node-http-handler": "^4.9.13", + "@smithy/types": "^4.16.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/nested-clients/node_modules/@smithy/node-http-handler": { + "version": "4.11.2", + "resolved": "https://registry.npmmirror.com/@smithy/node-http-handler/-/node-http-handler-4.11.2.tgz", + "integrity": "sha512-avwAh9HM3h2lcfjvP3zYIZGf+XVgLQ91wOJ2qoFbNpW1UZeZb33aGlhTZvtkANHfcGhJroRY64525OjfgOg30g==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@smithy/core": "^3.33.2", + "@smithy/types": "^4.17.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@aws-sdk/signature-v4-multi-region": { + "version": "3.996.45", + "resolved": "https://registry.npmmirror.com/@aws-sdk/signature-v4-multi-region/-/signature-v4-multi-region-3.996.45.tgz", + "integrity": "sha512-bBuyztukzXq6plzFGHAWiQt0QXo+HL8b8lX5cFTzkez/74PtS1c0qPFCIVuHkyoT+miH2qOjAcm1/yoro2ESPA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "^3.974.4", + "@smithy/signature-v4": "^5.6.12", + "@smithy/types": "^4.16.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/token-providers": { + "version": "3.1048.0", + "resolved": "https://registry.npmmirror.com/@aws-sdk/token-providers/-/token-providers-3.1048.0.tgz", + "integrity": "sha512-k0y/GcuesuSfWyUM0WamrGyeZmltRYaPbHO82UDA6mZ/doB+FOHKutikPAtSXMn/hDz970cF+iRuuiYO9VEbAA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/core": "^3.974.11", + "@aws-sdk/nested-clients": "^3.997.9", + "@aws-sdk/types": "^3.973.8", + "@smithy/core": "^3.24.2", + "@smithy/types": "^4.14.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/types": { + "version": "3.974.4", + "resolved": "https://registry.npmmirror.com/@aws-sdk/types/-/types-3.974.4.tgz", + "integrity": "sha512-dSFDNG00MEz0/xl5gxL62giLd1iYyJsTxZ1I1DOj6lC+bbgLB4TRsYClJg3b62dhXT1uATzsTNXPnC+33EJV3A==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.16.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/util-locate-window": { + "version": "3.965.10", + "resolved": "https://registry.npmmirror.com/@aws-sdk/util-locate-window/-/util-locate-window-3.965.10.tgz", + "integrity": "sha512-ycwH6Zd2GhuSqdXX9ihbCjeGTB6xOJs+O3+Jb8/zDG9978XU80qs75dfkPJRMNKe5MvBZPuNeFpd4JZKPoUF4g==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/xml-builder": { + "version": "3.972.39", + "resolved": "https://registry.npmmirror.com/@aws-sdk/xml-builder/-/xml-builder-3.972.39.tgz", + "integrity": "sha512-FTti8DS5MMWXNUWiRwXAJeYS+0GHHiMy0+7XOhcwk63ILHmfS2UFy2z/HNpZCSOJJ3P3dnWY6hfYNW3DF0nXUA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.16.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws/lambda-invoke-store": { + "version": "0.3.0", + "resolved": "https://registry.npmmirror.com/@aws/lambda-invoke-store/-/lambda-invoke-store-0.3.0.tgz", + "integrity": "sha512-sl4Bm6yiMNYrZKkqqDFWN0UfnWhlS8ivKxrYl+6t0gCLrqr8y3B2IqZZbFRkfaVVp7C/baApyh71P+LeE1A2sQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/code-frame/-/code-frame-7.29.7.tgz", + "integrity": "sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.29.7", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz", + "integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/runtime": { + "version": "7.29.7", + "resolved": "https://registry.npmmirror.com/@babel/runtime/-/runtime-7.29.7.tgz", + "integrity": "sha512-Nq8OhGWiZIZGV6hLHoyAKLLcJihP/xFeBMGJoUrxTX2psI8dCifzLhZISFb+VWS3wFMRDmCGw5R+dOySCqPLhw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@deepseek-ai/cordis": { + "version": "4.0.1", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/cordis/-/cordis-4.0.1.tgz", + "integrity": "sha512-YBdskTU2Po1kru3GgcUWUbkTsPMA9LkSQDAY8rBkFJeajdgcQad3QPJZE26JyK99Xb6HaASvoXg2DSUTeN/0Nw==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/cosmokit": "^1.8.2", + "@standard-schema/spec": "^1.1.0" + }, + "bin": { + "cordis": "bin.js" + }, + "peerDependencies": { + "@deepseek-ai/cordis-plugin-include": "^1.0.6", + "@deepseek-ai/cordis-plugin-loader": "^1.0.2" + }, + "peerDependenciesMeta": { + "@deepseek-ai/cordis-plugin-include": { + "optional": true + }, + "@deepseek-ai/cordis-plugin-loader": { + "optional": true + } + } + }, + "node_modules/@deepseek-ai/cordis-plugin-group": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/cordis-plugin-group/-/cordis-plugin-group-1.0.1.tgz", + "integrity": "sha512-E1NThkFB3jn3TCqa6Oc++1zQHqLejF3W2wDwv2BlL3UEmgtBXL1K1j1koc+j676RuiOXtJkUJlPcOntRGKLWBQ==", + "dev": true, + "license": "MIT", + "peer": true, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/cordis-plugin-loader": "^1.0.2" + } + }, + "node_modules/@deepseek-ai/cordis-plugin-hmr": { + "version": "1.0.16", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/cordis-plugin-hmr/-/cordis-plugin-hmr-1.0.16.tgz", + "integrity": "sha512-S7VHfylDg1+Y5O6fdYYZu0KFRAj/snHywcFPnX3KmQYa/qv2Q8IXi4zAt9ABq0BJYqhNoqRlbpGMfIjabgXjKA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.0", + "@deepseek-ai/cosmokit": "^1.8.2", + "@deepseek-ai/schemastery": "^3.18.1", + "chokidar": "^4.0.3", + "picomatch": "^4.0.3" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/cordis-plugin-timer": "^1.1.3" + } + }, + "node_modules/@deepseek-ai/cordis-plugin-include": { + "version": "1.0.6", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/cordis-plugin-include/-/cordis-plugin-include-1.0.6.tgz", + "integrity": "sha512-i1VXrZCbv6tk/iUgedCNjrxxArbWT3IvRZGB5sdqJ3ectnihivXXQbRZ8JJ73DSmAPvlMGmrbtjFAfm10yvXRg==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/cosmokit": "^1.8.2", + "js-yaml": "^4.1.0" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/cordis-plugin-loader": "^1.0.2" + } + }, + "node_modules/@deepseek-ai/cordis-plugin-loader": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/cordis-plugin-loader/-/cordis-plugin-loader-1.0.2.tgz", + "integrity": "sha512-RIW9hoVyhYDWdCI9BsvtZccPde1ECLC4OAxupwowGTak78vwVTVdb3HezTSOK1Y1/Ax3Ru0LA1pYOB04CnTxIQ==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/cosmokit": "^1.8.2" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "node-addon-require-builtin": "^0.1.4" + }, + "peerDependenciesMeta": { + "node-addon-require-builtin": { + "optional": true + } + } + }, + "node_modules/@deepseek-ai/cordis-plugin-timer": { + "version": "1.1.3", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/cordis-plugin-timer/-/cordis-plugin-timer-1.1.3.tgz", + "integrity": "sha512-IOkey1VNmJwYa5U8bksyMOnM7mtirqjjbWLr3xA8QybLMK0sMooG3a6iJwtvd8P3MFwo3FQibEg+JPixp37MEw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/cosmokit": "^1.8.2" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1" + } + }, + "node_modules/@deepseek-ai/cosmokit": { + "version": "1.8.2", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/cosmokit/-/cosmokit-1.8.2.tgz", + "integrity": "sha512-muBOKtSrUKU5m/xpq8ZXWL6hQ/jgd4PhU2PqH97bcxIiLEJfNwZOGQEx4t/aS/GgxRAR+ra9pMHPMtTHU4sqqA==", + "license": "MIT" + }, + "node_modules/@deepseek-ai/dsh": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh/-/dsh-0.1.0-rc.8.tgz", + "integrity": "sha512-VQU5NlomrKLRgcXuOf+sxWFvqxPA8q9vMhrKPlPPXiOJEhGlGlAdiyxZvZxkCVI+v0zbhe21cY3/luLyxpSzzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/cordis-plugin-hmr": "^1.0.16", + "@deepseek-ai/cordis-plugin-include": "^1.0.6", + "@deepseek-ai/cordis-plugin-loader": "^1.0.2", + "@deepseek-ai/cordis-plugin-timer": "^1.1.3", + "@deepseek-ai/dsh-agent-instructions": "^0.1.0-rc.8", + "@deepseek-ai/dsh-agent-tool-presentation": "^0.1.0-rc.8", + "@deepseek-ai/dsh-app-boot": "^0.1.0-rc.8", + "@deepseek-ai/dsh-base": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-ui-agent-preset": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-ui-cordis": "^0.1.0-rc.8", + "@deepseek-ai/dsh-cmdline": "^0.1.0-rc.8", + "@deepseek-ai/dsh-command-compact": "^0.1.0-rc.8", + "@deepseek-ai/dsh-command-goal": "^0.1.0-rc.8", + "@deepseek-ai/dsh-compaction-basic": "^0.1.0-rc.8", + "@deepseek-ai/dsh-compaction-tool-result-pruner": "^0.1.0-rc.8", + "@deepseek-ai/dsh-cordis-client-runner": "^0.1.0-rc.8", + "@deepseek-ai/dsh-fs-local": "^0.1.0-rc.8", + "@deepseek-ai/dsh-goal": "^0.1.0-rc.8", + "@deepseek-ai/dsh-goal-round-driver": "^0.1.0-rc.8", + "@deepseek-ai/dsh-headless": "^0.1.0-rc.8", + "@deepseek-ai/dsh-home-paths": "^0.1.0-rc.8", + "@deepseek-ai/dsh-jobs-local": "^0.1.0-rc.8", + "@deepseek-ai/dsh-launch-environment": "^0.1.0-rc.8", + "@deepseek-ai/dsh-mcp-client": "^0.1.0-rc.8", + "@deepseek-ai/dsh-persona": "^0.1.0-rc.8", + "@deepseek-ai/dsh-plan-mode": "^0.1.0-rc.8", + "@deepseek-ai/dsh-pwsh-local": "^0.1.0-rc.8", + "@deepseek-ai/dsh-pwsh-sandbox": "^0.1.0-rc.8", + "@deepseek-ai/dsh-schedule": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session-projection": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session-reference": "^0.1.0-rc.8", + "@deepseek-ai/dsh-skill": "^0.1.0-rc.8", + "@deepseek-ai/dsh-skill-filesystem": "^0.1.0-rc.8", + "@deepseek-ai/dsh-terminal": "^0.1.0-rc.8", + "@deepseek-ai/dsh-terminal-bash": "^0.1.0-rc.8", + "@deepseek-ai/dsh-time-context": "^0.1.0-rc.8", + "@deepseek-ai/dsh-tmux-context": "^0.1.0-rc.8", + "@deepseek-ai/dsh-token-meter": "^0.1.0-rc.8", + "@deepseek-ai/dsh-tool-ask-user": "^0.1.0-rc.8", + "@deepseek-ai/dsh-tool-bash": "^0.1.0-rc.8", + "@deepseek-ai/dsh-tool-bash-persistent": "^0.1.0-rc.8", + "@deepseek-ai/dsh-tool-cordis": "^0.1.0-rc.8", + "@deepseek-ai/dsh-tool-fs": "^0.1.0-rc.8", + "@deepseek-ai/dsh-tool-fs-search": "^0.1.0-rc.8", + "@deepseek-ai/dsh-tool-goal": "^0.1.0-rc.8", + "@deepseek-ai/dsh-tool-jobs": "^0.1.0-rc.8", + "@deepseek-ai/dsh-tool-pwsh": "^0.1.0-rc.8", + "@deepseek-ai/dsh-tool-pwsh-persistent": "^0.1.0-rc.8", + "@deepseek-ai/dsh-tool-ralph": "^0.1.0-rc.8", + "@deepseek-ai/dsh-tool-skill": "^0.1.0-rc.8", + "@deepseek-ai/dsh-tool-str-replace-editor": "^0.1.0-rc.8", + "@deepseek-ai/dsh-tool-subagent": "^0.1.0-rc.8", + "@deepseek-ai/dsh-tool-subagent-control": "^0.1.0-rc.8", + "@deepseek-ai/dsh-tool-todo": "^0.1.0-rc.8", + "@deepseek-ai/dsh-tool-web": "^0.1.0-rc.8", + "@deepseek-ai/dsh-tool-workflow": "^0.1.0-rc.8", + "@deepseek-ai/dsh-web-app": "^0.1.0-rc.8", + "@deepseek-ai/dsh-workflow-worker-thread": "^0.1.0-rc.8", + "commander": "^15.0.0", + "js-yaml": "^4.2.0", + "node-addon-require-builtin": "^0.1.4" + }, + "bin": { + "dsh": "lib/bin.js" + } + }, + "node_modules/@deepseek-ai/dsh-agent": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-agent/-/dsh-agent-0.1.0-rc.8.tgz", + "integrity": "sha512-fOl46ZvzoYHalrlyfOJAHNhzyKeVDTUnZZKNSJEr9GY/98WJTjcV21agVEofTXldkJ7a/ws2HpJkVNJVFMtslg==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", + "@deepseek-ai/dsh-scope": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session": "^0.1.0-rc.8", + "@deepseek-ai/dsh-system-prompt": "^0.1.0-rc.8", + "@deepseek-ai/dsh-typert-protocol": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-agent-default-model": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-agent-default-model/-/dsh-agent-default-model-0.1.0-rc.8.tgz", + "integrity": "sha512-FSmgVy8yeVYx3krUwfWZR3JokLD202FSuEd/ZfGdxA+BhOKAOfhNv539kujatVqXyzCG3XiRNda7zWxCh2h7/A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", + "@deepseek-ai/dsh-settings": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-agent-instructions": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-agent-instructions/-/dsh-agent-instructions-0.1.0-rc.8.tgz", + "integrity": "sha512-T+JER2gUZbopOxNeHKUE7EfNof30yihsi7GXKB/lOLoy1XMvd5mlzjSHA/OzqjLxiZyyN4V7XAGURApVD3Z7sw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", + "@deepseek-ai/dsh-fs": "^0.1.0-rc.8", + "@deepseek-ai/dsh-home-paths": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session": "^0.1.0-rc.8", + "@deepseek-ai/dsh-tools": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-agent-loop": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-agent-loop/-/dsh-agent-loop-0.1.0-rc.8.tgz", + "integrity": "sha512-6Vg5oLy3UZ6lJKMPxldqqBylKSMOpbV/FRrqzDqn3hGdksYBzt9K2hUJm/rE2RyguYKUKFPm2hExs0nn4HKmWA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", + "@deepseek-ai/dsh-scope": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session-persistence": "^0.1.0-rc.8", + "@deepseek-ai/dsh-settings": "^0.1.0-rc.8", + "@deepseek-ai/dsh-system-prompt": "^0.1.0-rc.8", + "@deepseek-ai/dsh-tools": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-agent-presets": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-agent-presets/-/dsh-agent-presets-0.1.0-rc.8.tgz", + "integrity": "sha512-7h+kE0KDrJCk2Y8GAqF4fu4YqZmFi5U8/AarFkGUqRI3HDugD6oYf05c7ZWNF7lQXh1OmwmrSbuPhT/YXJapOg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1", + "js-yaml": "^4.1.0" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/cordis-plugin-include": "^1.0.6", + "@deepseek-ai/cordis-plugin-loader": "^1.0.2", + "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", + "@deepseek-ai/dsh-atomic-write": "^0.1.0-rc.8", + "@deepseek-ai/dsh-home-paths": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-scope": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session": "^0.1.0-rc.8", + "@deepseek-ai/dsh-settings": "^0.1.0-rc.8", + "@deepseek-ai/dsh-system-prompt": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-agent-tool-presentation": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-agent-tool-presentation/-/dsh-agent-tool-presentation-0.1.0-rc.8.tgz", + "integrity": "sha512-DQouZBh0yjKy8bi0EHQZrZ1B0E+Sc321o5oIyrrmL3hh1sbBsWVrnTvwKPP+SU7J6gnIzyITJ7qEV7pcCGOB2w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-tools": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-anonymous-user-id": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-anonymous-user-id/-/dsh-anonymous-user-id-0.1.0-rc.8.tgz", + "integrity": "sha512-vUESbXtDdqIyelCNqX3ijOfqNfw65iSaJaqzfiqQhmSd9ZrNJ1fPUHl8FoW1BdfK8FjrDyh32R6BtuVpI7Zdhw==", + "dev": true, + "license": "MIT", + "peer": true, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-brand": "^0.1.0-rc.8", + "@deepseek-ai/dsh-home-paths": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-api-gateway": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-api-gateway/-/dsh-api-gateway-0.1.0-rc.8.tgz", + "integrity": "sha512-rNA9+Sq3lXFDmyoFLpXNbcuWg7iFeepCwDi+jt1oGjwZTdZJ2nEWpU6GKlOiqadQjHYzfwEbCqmcuJy32qke/A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-typert-protocol": "^0.1.0-rc.8" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-client-connection": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-typert-registry": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-api-remotes": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-api-remotes/-/dsh-api-remotes-0.1.0-rc.8.tgz", + "integrity": "sha512-s/zmFmU6R+dDxUWbHucIyfVgJG4v8kXa3YRjwjMO+Bu871ZG5Zsht6cvRqeSyu0A/Gs06ZfKYeKE0sdbCZ1NiA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-typert-protocol": "^0.1.0-rc.8" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", + "@deepseek-ai/dsh-agent-presets": "^0.1.0-rc.8", + "@deepseek-ai/dsh-api-gateway": "^0.1.0-rc.8", + "@deepseek-ai/dsh-commands": "^0.1.0-rc.8", + "@deepseek-ai/dsh-cordis-host-runner": "^0.1.0-rc.8", + "@deepseek-ai/dsh-credentials": "^0.1.0-rc.8", + "@deepseek-ai/dsh-file-reference": "^0.1.0-rc.8", + "@deepseek-ai/dsh-goal": "^0.1.0-rc.8", + "@deepseek-ai/dsh-host-plugin-inventory": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", + "@deepseek-ai/dsh-message-feedback": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session-persistence": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session-reference": "^0.1.0-rc.8", + "@deepseek-ai/dsh-settings": "^0.1.0-rc.8", + "@deepseek-ai/dsh-typert-registry": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-app-boot": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-app-boot/-/dsh-app-boot-0.1.0-rc.8.tgz", + "integrity": "sha512-DS63o1PhX2Gvqdgl6Wd8vZnLl0qo8gJ9LpSHXeJBJL9HITpLPhdVYE3X6S0icIYdbGO2plNyhxVJOSN6ibO7VA==", + "dev": true, + "license": "MIT", + "dependencies": { + "js-yaml": "^4.2.0" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/cordis-plugin-group": "^1.0.1", + "@deepseek-ai/cordis-plugin-hmr": "^1.0.16", + "@deepseek-ai/cordis-plugin-include": "^1.0.6", + "@deepseek-ai/cordis-plugin-loader": "^1.0.2", + "@deepseek-ai/dsh-home-paths": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-launch-environment": "^0.1.0-rc.8", + "@deepseek-ai/dsh-system-prompt": "^0.1.0-rc.8" + }, + "peerDependenciesMeta": { + "@deepseek-ai/cordis-plugin-hmr": { + "optional": true + } + } + }, + "node_modules/@deepseek-ai/dsh-atomic-write": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-atomic-write/-/dsh-atomic-write-0.1.0-rc.8.tgz", + "integrity": "sha512-SWP+NAat3oteaPi47zLPz4vxeYCHNVmFpN1aeKDuPHpe/ouNTl+WcyIONAJ+1MbZ+8APWhSaJIVu6ORJEUhVGw==", + "dev": true, + "license": "MIT", + "peer": true, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-attachment": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-attachment/-/dsh-attachment-0.1.0-rc.8.tgz", + "integrity": "sha512-cCrg4WWiav7pGtbdU8dJTpAG28cPnkWVB2YPOrlBCgBbhQziGcG9Dv67Ti6L3PI4OQKC55gYBFinQghFO/7FGg==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-brand": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-attachment-local": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-attachment-local/-/dsh-attachment-local-0.1.0-rc.8.tgz", + "integrity": "sha512-TPsDbDPA8yoE3hw1MtrW61AMh72oMiCY+rkO3bDnvc4MtGwKvXcHWtbNPeVpLgMeznaXsnTU3GUp9Fa6PXdp8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1", + "sharp": "^0.35.3" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-attachment": "^0.1.0-rc.8", + "@deepseek-ai/dsh-home-paths": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-base": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-base/-/dsh-base-0.1.0-rc.8.tgz", + "integrity": "sha512-aMjXT6d5t8SGQg24geOSX6O0ky+hJLijhzZklDcICrBvGSKXvuS8jxLOcL5u4s4pFCODXhuOpvTfFuUhN2RK3Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/cordis-plugin-hmr": "^1.0.16", + "@deepseek-ai/cordis-plugin-timer": "^1.1.3", + "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", + "@deepseek-ai/dsh-agent-default-model": "^0.1.0-rc.8", + "@deepseek-ai/dsh-agent-instructions": "^0.1.0-rc.8", + "@deepseek-ai/dsh-agent-loop": "^0.1.0-rc.8", + "@deepseek-ai/dsh-api-gateway": "^0.1.0-rc.8", + "@deepseek-ai/dsh-attachment-local": "^0.1.0-rc.8", + "@deepseek-ai/dsh-bash-sandbox": "^0.1.0-rc.8", + "@deepseek-ai/dsh-command-compact": "^0.1.0-rc.8", + "@deepseek-ai/dsh-command-feedback": "^0.1.0-rc.8", + "@deepseek-ai/dsh-command-goal": "^0.1.0-rc.8", + "@deepseek-ai/dsh-commands": "^0.1.0-rc.8", + "@deepseek-ai/dsh-compaction-basic": "^0.1.0-rc.8", + "@deepseek-ai/dsh-compaction-tool-result-pruner": "^0.1.0-rc.8", + "@deepseek-ai/dsh-credentials-local": "^0.1.0-rc.8", + "@deepseek-ai/dsh-fs-local": "^0.1.0-rc.8", + "@deepseek-ai/dsh-fs-observation-policy": "^0.1.0-rc.8", + "@deepseek-ai/dsh-fs-sandbox": "^0.1.0-rc.8", + "@deepseek-ai/dsh-goal": "^0.1.0-rc.8", + "@deepseek-ai/dsh-goal-round-driver": "^0.1.0-rc.8", + "@deepseek-ai/dsh-jobs-local": "^0.1.0-rc.8", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", + "@deepseek-ai/dsh-llm-deepseek": "^0.1.0-rc.8", + "@deepseek-ai/dsh-llm-pi-ai": "^0.1.0-rc.8", + "@deepseek-ai/dsh-llm-retry": "^0.1.0-rc.8", + "@deepseek-ai/dsh-permission-presets": "^0.1.0-rc.8", + "@deepseek-ai/dsh-plan-mode": "^0.1.0-rc.8", + "@deepseek-ai/dsh-pwsh-sandbox": "^0.1.0-rc.8", + "@deepseek-ai/dsh-repeat-tool-reminder": "^0.1.0-rc.8", + "@deepseek-ai/dsh-sandbox-local": "^0.1.0-rc.8", + "@deepseek-ai/dsh-sandbox-policy": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session-checkpoint-policy": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session-persistence-jsonl": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session-projection": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session-query-sqlite": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session-telemetry-otel": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session-title": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session-title-first-prompt-llm": "^0.1.0-rc.8", + "@deepseek-ai/dsh-settings-file": "^0.1.0-rc.8", + "@deepseek-ai/dsh-shell-env": "^0.1.0-rc.8", + "@deepseek-ai/dsh-skill": "^0.1.0-rc.8", + "@deepseek-ai/dsh-skill-badge": "^0.1.0-rc.8", + "@deepseek-ai/dsh-skill-filesystem": "^0.1.0-rc.8", + "@deepseek-ai/dsh-spill-local": "^0.1.0-rc.8", + "@deepseek-ai/dsh-spill-policy": "^0.1.0-rc.8", + "@deepseek-ai/dsh-subagent": "^0.1.0-rc.8", + "@deepseek-ai/dsh-subagent-fork-in-process": "^0.1.0-rc.8", + "@deepseek-ai/dsh-subagent-spawn-in-process": "^0.1.0-rc.8", + "@deepseek-ai/dsh-subprocess-local": "^0.1.0-rc.8", + "@deepseek-ai/dsh-system-prompt": "^0.1.0-rc.8", + "@deepseek-ai/dsh-token-meter": "^0.1.0-rc.8", + "@deepseek-ai/dsh-tool-bash": "^0.1.0-rc.8", + "@deepseek-ai/dsh-tool-call-timeout-policy": "^0.1.0-rc.8", + "@deepseek-ai/dsh-tool-fs": "^0.1.0-rc.8", + "@deepseek-ai/dsh-tool-fs-search": "^0.1.0-rc.8", + "@deepseek-ai/dsh-tool-goal": "^0.1.0-rc.8", + "@deepseek-ai/dsh-tool-jobs": "^0.1.0-rc.8", + "@deepseek-ai/dsh-tool-pwsh": "^0.1.0-rc.8", + "@deepseek-ai/dsh-tool-ralph": "^0.1.0-rc.8", + "@deepseek-ai/dsh-tool-skill": "^0.1.0-rc.8", + "@deepseek-ai/dsh-tool-str-replace-editor": "^0.1.0-rc.8", + "@deepseek-ai/dsh-tool-subagent": "^0.1.0-rc.8", + "@deepseek-ai/dsh-tool-subagent-control": "^0.1.0-rc.8", + "@deepseek-ai/dsh-tool-subagent-report": "^0.1.0-rc.8", + "@deepseek-ai/dsh-tool-todo": "^0.1.0-rc.8", + "@deepseek-ai/dsh-tool-web": "^0.1.0-rc.8", + "@deepseek-ai/dsh-tool-workflow": "^0.1.0-rc.8", + "@deepseek-ai/dsh-tools": "^0.1.0-rc.8", + "@deepseek-ai/dsh-typert-loader": "^0.1.0-rc.8", + "@deepseek-ai/dsh-typert-registry": "^0.1.0-rc.8", + "@deepseek-ai/dsh-user-approval": "^0.1.0-rc.8", + "@deepseek-ai/dsh-user-questions": "^0.1.0-rc.8", + "@deepseek-ai/dsh-web": "^0.1.0-rc.8", + "@deepseek-ai/dsh-web-search-deepseek": "^0.1.0-rc.8", + "@deepseek-ai/dsh-workflow-worker-thread": "^0.1.0-rc.8" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-bash-local": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-bash-local/-/dsh-bash-local-0.1.0-rc.8.tgz", + "integrity": "sha512-vMf3dMRrvVvwWCLJxobYONSebPtWqy2ZZKpRZ6o5fBrZbM88irbvL6F/6r/mu4ADTIDigUtpoxlRpOEQKbSuTg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-settings": "^0.1.0-rc.8", + "@deepseek-ai/dsh-shell": "^0.1.0-rc.8", + "@deepseek-ai/dsh-subprocess": "^0.1.0-rc.8", + "@deepseek-ai/dsh-timeout": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-bash-sandbox": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-bash-sandbox/-/dsh-bash-sandbox-0.1.0-rc.8.tgz", + "integrity": "sha512-gCFrmFwYyxjXJsSRrzs5RbvCli0I0Tn9JAJEHCWSskE8x9iCVU7ljtmrKvgRYr0J4YeXwzteNSfNhlJqasu/QQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-bash-local": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-sandbox": "^0.1.0-rc.8", + "@deepseek-ai/dsh-sandbox-policy": "^0.1.0-rc.8", + "@deepseek-ai/dsh-shell": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-brand": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-brand/-/dsh-brand-0.1.0-rc.8.tgz", + "integrity": "sha512-402aUAfHxIZJrArBV4gDf0I/A/69A/By26FX6HTIOyFmCnB4wUBKh8jnglz1CorKWdZy8AKldAhh8HQhQEbGOQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-client-connection": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-client-connection/-/dsh-client-connection-0.1.0-rc.8.tgz", + "integrity": "sha512-O1Y1NmkvJjpR/rCYkzulRrKbFwUbpMlINR4G6fbpGXaLy0VzTqN+ptk0b3wJ4RrnKPi4WWLKNNdV647Fg/1sCw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1", + "ws": "^8.21.0" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-attachment": "^0.1.0-rc.8", + "@deepseek-ai/dsh-commands": "^0.1.0-rc.8", + "@deepseek-ai/dsh-host-apiproxy": "^0.1.0-rc.8", + "@deepseek-ai/dsh-host-webserver": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session": "^0.1.0-rc.8", + "@deepseek-ai/dsh-tools": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-client-hmr": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-client-hmr/-/dsh-client-hmr-0.1.0-rc.8.tgz", + "integrity": "sha512-Olzlpiw+2VIhNOZVEgi22b2U0jSv6HciAQpKj41TggI7oV+jhRDC2GuYFJoRQ8XBs3mcJCLG0DZtAcGrRP8n9Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/cordis-plugin-loader": "^1.0.2", + "@deepseek-ai/dsh-client-modules": "^0.1.0-rc.8", + "@deepseek-ai/dsh-host-webserver": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-client-locale": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-client-locale/-/dsh-client-locale-0.1.0-rc.8.tgz", + "integrity": "sha512-S8ztym/oFU1aWPDtSZLTGWfprUBIuhfOrRNlw/qMAwhavJiQU/Ag0plg19JffGiOMAQuz2BU2n2mW/xhbpA5Vw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-api-remotes": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-connection": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-runtime": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-ui-settings": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-settings": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-client-modules": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-client-modules/-/dsh-client-modules-0.1.0-rc.8.tgz", + "integrity": "sha512-K+uDZSmSbpmHFpvrKkdctHHDIjimv1NWDZoc7CYy7QIk0Vuis4jShDau6H5L0B9TScWBDyXAz/R7rXttFlwseA==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/cordis-plugin-loader": "^1.0.2", + "@deepseek-ai/dsh-host-webserver": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-client-runtime": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-client-runtime/-/dsh-client-runtime-0.1.0-rc.8.tgz", + "integrity": "sha512-wW/nktO/GVbGO/k163NlyJab/rK4D6xS5EL0bhYw4ojF1mxmWfrb3RUEYR5LcEUpFx/yXUHsUSgeO1ezmgIrvw==", + "dev": true, + "license": "MIT", + "dependencies": { + "immer": "^10.1.1", + "zustand": "~4.4.7" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", + "@deepseek-ai/dsh-api-remotes": "^0.1.0-rc.8", + "@deepseek-ai/dsh-attachment": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-connection": "^0.1.0-rc.8", + "@deepseek-ai/dsh-commands": "^0.1.0-rc.8", + "@deepseek-ai/dsh-host-apiproxy": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", + "@deepseek-ai/dsh-llm-retry": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session-projection": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session-title": "^0.1.0-rc.8", + "@deepseek-ai/dsh-tools": "^0.1.0-rc.8", + "@deepseek-ai/dsh-typert-protocol": "^0.1.0-rc.8", + "@deepseek-ai/dsh-typert-registry": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-agent-preset": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-client-ui-agent-preset/-/dsh-client-ui-agent-preset-0.1.0-rc.8.tgz", + "integrity": "sha512-z+okJSOT2/uAA4oomx1WNNl/2k9HsoNDmtewOeQVfSy9C8Ey9YBoVoiSQDsYyDHhesxxlBI8RMLU44Pj/w1uug==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-api-remotes": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-connection": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-locale": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-runtime": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-ui-conversation": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-ui-settings": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-attachment": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-client-ui-attachment/-/dsh-client-ui-attachment-0.1.0-rc.8.tgz", + "integrity": "sha512-TiKZEUGd22AFxkWpgQCLW9VmuSgWQ11RlIQd0941wPAc4RDZxtkjQWDMOlvRS/m8Oqod/5oKr3U6WRCZKS81vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "clsx": "^2.0.0" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-attachment": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-runtime": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-ui-conversation": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-brand-official": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-client-ui-brand-official/-/dsh-client-ui-brand-official-0.1.0-rc.8.tgz", + "integrity": "sha512-eHzJkJGOKlQpap6uYaAZSh62MyJFEoPX8EvIp/kV3YHFDr4bZNc7Yg+ZLMaEXfIjPXKp26FhPiCIia9SP56n8A==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-client-runtime": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-ui-conversation": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-ui-sidebar": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-commands": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-client-ui-commands/-/dsh-client-ui-commands-0.1.0-rc.8.tgz", + "integrity": "sha512-nMDF0MbRM03AEmQJzXCbXQWZxSfVPHBO0z+9DqR6LgGXshYLkzVMp1zkfvqLs5QwFAwDSci4vi/GONJOBSL5WA==", + "dev": true, + "license": "MIT", + "dependencies": { + "clsx": "^2.0.0" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-api-remotes": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-locale": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-runtime": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-ui-conversation": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-ui-input-trigger": "^0.1.0-rc.8", + "@deepseek-ai/dsh-commands": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-conversation": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-client-ui-conversation/-/dsh-client-ui-conversation-0.1.0-rc.8.tgz", + "integrity": "sha512-GnQSE47/goSm1UzxQpYQrQnMJLyTmYFH6NENdrOxrVJxQnB55ruactgM1kVwfFnc/WUQVYy0599AK7pxjbxjMg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1", + "clsx": "^2.0.0" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", + "@deepseek-ai/dsh-api-remotes": "^0.1.0-rc.8", + "@deepseek-ai/dsh-attachment": "^0.1.0-rc.8", + "@deepseek-ai/dsh-brand": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-connection": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-locale": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-runtime": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-ui-input-trigger": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-ui-layout": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-ui-settings": "^0.1.0-rc.8", + "@deepseek-ai/dsh-commands": "^0.1.0-rc.8", + "@deepseek-ai/dsh-compaction": "^0.1.0-rc.8", + "@deepseek-ai/dsh-goal": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-llm-retry": "^0.1.0-rc.8", + "@deepseek-ai/dsh-permission-presets": "^0.1.0-rc.8", + "@deepseek-ai/dsh-plan-mode": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session-stats": "^0.1.0-rc.8", + "@deepseek-ai/dsh-settings": "^0.1.0-rc.8", + "@deepseek-ai/dsh-token-meter": "^0.1.0-rc.8", + "@deepseek-ai/dsh-tool-todo": "^0.1.0-rc.8", + "@deepseek-ai/dsh-tools": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-cordis": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-client-ui-cordis/-/dsh-client-ui-cordis-0.1.0-rc.8.tgz", + "integrity": "sha512-NvaSJxqC+HNPLPYPINHzJGRHI427mHSB2aaTGoyc9EFrYVJjvKpNu1QusWwObae5Y/Tx43I2NpFKTAcNVPXkOw==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-api-remotes": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-connection": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-locale": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-runtime": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-ui-input-trigger": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-ui-sidebar": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-ui-tool": "^0.1.0-rc.8", + "@deepseek-ai/dsh-cordis-client-runner": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-deliverables": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-client-ui-deliverables/-/dsh-client-ui-deliverables-0.1.0-rc.8.tgz", + "integrity": "sha512-b0XZ/V7FPpTTtmHoKNEVOgl9bJGXGqktzMNNJgifHGl/Us1nNnQVDhM9XDbuUV5iXFPnRrKsR29OTnuTB+txZA==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-client-connection": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-locale": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-runtime": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-ui-conversation": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-system-prompt": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-directory-picker-browse": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-client-ui-directory-picker-browse/-/dsh-client-ui-directory-picker-browse-0.1.0-rc.8.tgz", + "integrity": "sha512-sjQcMuut8CRjqnFZHzX1Zzs1zISDlp/gYQVM9Wkyt9KF+XJfV5pHP0KTHZHwOslAqt2OJMnE38uW2yVncLg3sA==", + "dev": true, + "license": "MIT", + "dependencies": { + "clsx": "^2.0.0" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-client-locale": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-runtime": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-ui-workspace": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-directory-picker-native": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-client-ui-directory-picker-native/-/dsh-client-ui-directory-picker-native-0.1.0-rc.8.tgz", + "integrity": "sha512-UPR5kSjfMGjLpO41fXXVxcen9Bq9eCzonStnhqMMk/6zC2EQUDkRs+KhYmaInkHI/CMjdTBBqBPRwjFG2iEsYQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-client-runtime": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-ui-workspace": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-goal": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-client-ui-goal/-/dsh-client-ui-goal-0.1.0-rc.8.tgz", + "integrity": "sha512-kAs6DktlELshs27S3nnjzciK9bGhL2b6RXmZ/mUNYwgiYxeYY4/QYynSNbD0ZQINe0VeGy6yQTv9dbqDBArndA==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-api-remotes": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-locale": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-runtime": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-ui-conversation": "^0.1.0-rc.8", + "@deepseek-ai/dsh-commands": "^0.1.0-rc.8", + "@deepseek-ai/dsh-goal": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session": "^0.1.0-rc.8", + "@deepseek-ai/dsh-typert-protocol": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-input-trigger": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-client-ui-input-trigger/-/dsh-client-ui-input-trigger-0.1.0-rc.8.tgz", + "integrity": "sha512-uVJEZ1ftUdMemLvNf17gzB6ThYw0DL4k+0kcQrUPc6LHNQ2ZeuuvOz/931OlqzzUKMtlAGZgy0LvWyJ62LlSog==", + "dev": true, + "license": "MIT", + "dependencies": { + "clsx": "^2.0.0" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-client-locale": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-runtime": "^0.1.0-rc.8", + "@deepseek-ai/dsh-file-reference": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-jobs": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-client-ui-jobs/-/dsh-client-ui-jobs-0.1.0-rc.8.tgz", + "integrity": "sha512-gCJR9ymswAZa8OiyZQUKa9GpxRT2sP76tfqBGcF5pRN0xOKudlREM6xD3as2knY5EZELW5qQMVKlVVJZ2Uu7fA==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-client-locale": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-runtime": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-ui-conversation": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-layout": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-client-ui-layout/-/dsh-client-ui-layout-0.1.0-rc.8.tgz", + "integrity": "sha512-tbHawbf8FsJqdwnXrU46V8u13bfAFVQQf0hA0OXH4k0PiLiThdZgQFn/T94+56JMUzD1QLqe7DLmNz29cwmjvQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-client-runtime": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-ui-theme": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-message-feedback": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-client-ui-message-feedback/-/dsh-client-ui-message-feedback-0.1.0-rc.8.tgz", + "integrity": "sha512-tzm/vvhysNa3+1BlTnuj3WJit5+u8U1NDecLqMPTm6U1P2s2bjKtvUpmMNqk+AdeYGYcJjXPadLEuWSNsIWFlQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-api-remotes": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-connection": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-locale": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-runtime": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-ui-conversation": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-message-feedback": "^0.1.0-rc.8", + "@deepseek-ai/dsh-typert-protocol": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-model-selection": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-client-ui-model-selection/-/dsh-client-ui-model-selection-0.1.0-rc.8.tgz", + "integrity": "sha512-ODRo7IX4VKkgy6C0ibElP5p1Ek6NBm6Qz6S95cZQH2J+PXWTb57/6UvNfxqyst8nFh1wll4oRb1m4fm6MU/fqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "clsx": "^2.1.1" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-api-remotes": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-connection": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-locale": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-runtime": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-ui-commands": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-ui-conversation": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-ui-input-trigger": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-permission-presets": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-client-ui-permission-presets/-/dsh-client-ui-permission-presets-0.1.0-rc.8.tgz", + "integrity": "sha512-mYF/TX4GVJgRxDYPIk/iQKkGXz8qHkfFJE3GqIw5E27g+Msfg8AEGqfWEPp4CZeIK/3zcgpMLzgjMLOliWZ2dA==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-api-remotes": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-connection": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-locale": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-runtime": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-ui-commands": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-ui-input-trigger": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-ui-settings": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-permission-presets": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-plan": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-client-ui-plan/-/dsh-client-ui-plan-0.1.0-rc.8.tgz", + "integrity": "sha512-OmCuuYCqSlbYqd4s781WipQNKWdHGUn8TPIxrKrcbe94vJacuBtIUIJkDi48dy0IimI+ln/eHxD9WC/9+bJEmA==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-api-remotes": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-locale": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-runtime": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-ui-conversation": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-plan-mode": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-reference": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-client-ui-reference/-/dsh-client-ui-reference-0.1.0-rc.8.tgz", + "integrity": "sha512-9qQYmOqG58qlsYNipOMsrL+Ay5Imx8lHJk9GV1rW++LGl6HMb6V1qZBHGIAwO/KOOInnJSEZE65DYB54r+z1Fw==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-api-remotes": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-locale": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-runtime": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-ui-input-trigger": "^0.1.0-rc.8", + "@deepseek-ai/dsh-file-reference": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session-reference": "^0.1.0-rc.8", + "@deepseek-ai/dsh-typert-protocol": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-renderer": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-client-ui-renderer/-/dsh-client-ui-renderer-0.1.0-rc.8.tgz", + "integrity": "sha512-/MpR9i++feUFNzJgCChLfct1RphTPJ1WKfZrIsczjyOAZNBzAM5LRjpvM0ZO5Vg7rs7id+PLJYuUKy2e2V5aAA==", + "dev": true, + "license": "MIT", + "dependencies": { + "use-sync-external-store": "1.2.0" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-client-runtime": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-settings": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-client-ui-settings/-/dsh-client-ui-settings-0.1.0-rc.8.tgz", + "integrity": "sha512-qSOjpmglOPsLzx6Q5yysrU4c4W6QWFOkyVyqePA5lNPOdny2MH19qbuNleQHbiBo4Zadh/dtBn/SuNRfSp+pjw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-api-remotes": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-connection": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-runtime": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-settings": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-settings-general": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-client-ui-settings-general/-/dsh-client-ui-settings-general-0.1.0-rc.8.tgz", + "integrity": "sha512-lGGLCV17yUhKTHFAL+LWNY6LICLHmL614TbgaTFC80HWqeduURKzHU7a2PoySyMC2AOvYGpKjIRNUfifhv3aZw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1", + "clsx": "^2.0.0" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-api-remotes": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-connection": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-locale": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-runtime": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-ui-settings": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-ui-sidebar": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-settings": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-settings-models": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-client-ui-settings-models/-/dsh-client-ui-settings-models-0.1.0-rc.8.tgz", + "integrity": "sha512-6iTLiQ4+4ErqV2e0Lxeunr1Q0JLFJ3EcJ1KcxvT0mEy5xzZuilX7KJxsBWq11q3Wy/I0MYhbHZzZC+d42mFM4g==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-api-remotes": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-connection": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-locale": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-runtime": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-ui-settings": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-settings-plugin-inventory": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-client-ui-settings-plugin-inventory/-/dsh-client-ui-settings-plugin-inventory-0.1.0-rc.8.tgz", + "integrity": "sha512-IiixKrJbNqn4D8kvpSIRbxsfetEEbYN5Z3Uz209UWLOiY8Ja9VdQaVbh6BZlecO9BXX1Lgo8l8q+tXlC0IpifA==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-api-remotes": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-locale": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-runtime": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-ui-settings": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-settings-plugins": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-client-ui-settings-plugins/-/dsh-client-ui-settings-plugins-0.1.0-rc.8.tgz", + "integrity": "sha512-BLLFFxBz4TmnXXsR5bnQaLMboXBOvCfhoqSbdPFqkqrmJSD+3KGbg4SQJZPcfLL19Kq7qeDraPCXwxo3wpIULg==", + "dev": true, + "license": "MIT", + "dependencies": { + "clsx": "^2.0.0" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-api-remotes": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-connection": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-locale": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-runtime": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-ui-settings": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-sidebar": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-client-ui-sidebar/-/dsh-client-ui-sidebar-0.1.0-rc.8.tgz", + "integrity": "sha512-7wcBnS27j8iIVDuai8BVifxcDZd5DIjlHgNHQKx8xQM+x92VKhiFOoMccjhXNaE6sExCUsER1OWRVp65MJvjqg==", + "dev": true, + "license": "MIT", + "dependencies": { + "clsx": "^2.0.0" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-client-locale": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-runtime": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-ui-layout": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-skill": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-client-ui-skill/-/dsh-client-ui-skill-0.1.0-rc.8.tgz", + "integrity": "sha512-s9tW3tDQ/82TzZcUHC/dZy5zmPppFKbSXnBotQDvjAU+rkS3/4k4Y6u9LffyZ813OjCoCfs7GOfWHAyZ0VmBag==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-api-remotes": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-connection": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-locale": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-runtime": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-ui-input-trigger": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-ui-tool": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-subagent": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-client-ui-subagent/-/dsh-client-ui-subagent-0.1.0-rc.8.tgz", + "integrity": "sha512-uK23jWwzFXbAELsnqS+7A4jL3Q/Ft8AI1hPrJE1ssldq535znexgdGAguZFC17fG+L0OWUtqwAKdXHmjyzqLiQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-client-locale": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-runtime": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-ui-conversation": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-ui-input-trigger": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-subagent": "^0.1.0-rc.8", + "@deepseek-ai/dsh-token-meter": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-theme": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-client-ui-theme/-/dsh-client-ui-theme-0.1.0-rc.8.tgz", + "integrity": "sha512-orLl5eoWOnvjj76lI6xucE+lT+o+ouniRMSFsuYwF1DNH2pbyfVPQYJWL3iM55gE28yyZJGgmtmABnQBiEF5iA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1", + "clsx": "^2.0.0" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-api-remotes": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-connection": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-locale": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-runtime": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-ui-settings": "^0.1.0-rc.8", + "@deepseek-ai/dsh-host-webserver": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-settings": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-tool": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-client-ui-tool/-/dsh-client-ui-tool-0.1.0-rc.8.tgz", + "integrity": "sha512-+Mtgx56PptrtoN4Q36yISe3u0lnVazdqV9s+1cLU2C2sAw7bB7o2Y/J9PBPiuBSsK8rmCLbUPYK6QefenwFE7Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "clsx": "^2.0.0" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-api-remotes": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-connection": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-locale": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-runtime": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-ui-conversation": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-trajectory": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-client-ui-trajectory/-/dsh-client-ui-trajectory-0.1.0-rc.8.tgz", + "integrity": "sha512-nEKtvkbNhk1Qau8jpyvGfcGLCL2Tfmw6Oi72i2oiZ/DHIcsBaeD0JVWOraEmQp3jYVjuuLSdjdCiPkuNU9nwgw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@tanstack/react-virtual": "^3.14.9", + "diff": "^9.0.0" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-locale": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-runtime": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-ui-conversation": "^0.1.0-rc.8", + "@deepseek-ai/dsh-compaction": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-tools": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-trajectory/node_modules/@tanstack/react-virtual": { + "version": "3.14.10", + "resolved": "https://registry.npmmirror.com/@tanstack/react-virtual/-/react-virtual-3.14.10.tgz", + "integrity": "sha512-SRyoUbdFMRHuYXMijV5H4ZarQWpXkj3iANq8OFre+pybeVap8ZJjZ3Nz9bVjx4d8PfobVUQUdKyyyHYk3E+djw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@tanstack/virtual-core": "3.17.8" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-trajectory/node_modules/react": { + "version": "19.2.8", + "resolved": "https://registry.npmmirror.com/react/-/react-19.2.8.tgz", + "integrity": "sha512-PWaYA1L/q9u2u7xYQi+Y3L3Yfnie7XyLeaJICV1MGD6LprsBxcAqGjYyr0eY3p+QdsA+x/Irkt4Qif8D63+Sbw==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-trajectory/node_modules/react-dom": { + "version": "19.2.8", + "resolved": "https://registry.npmmirror.com/react-dom/-/react-dom-19.2.8.tgz", + "integrity": "sha512-rVprimfGBG3DR+Tq0IQG2DT5PxKth1WIGDmj5yPmlzr4YBe7uyE+Du4oVqTDXZSHGGGXRtTJEGSSePyQCMBglQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "scheduler": "^0.27.0" + }, + "peerDependencies": { + "react": "^19.2.8" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-user-questions": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-client-ui-user-questions/-/dsh-client-ui-user-questions-0.1.0-rc.8.tgz", + "integrity": "sha512-zv2U7Ur1ovGSU7j5mwsiCHUK/L20IXRcSFBis3kDZ9nMMl9m0N+56bXrZtJD1U9kTU7gtJ4Xat+rDpr3uTn0JA==", + "dev": true, + "license": "MIT", + "dependencies": { + "clsx": "^2.0.0" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-api-remotes": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-locale": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-runtime": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-ui-conversation": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-workflow-run": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-client-ui-workflow-run/-/dsh-client-ui-workflow-run-0.1.0-rc.8.tgz", + "integrity": "sha512-lVvzaR66JwR2lgdURooLEyinUFu5cSaJLWBgdLetw0Z1B6N4RzBNwiIZxmIEZKwaVS7vhO9w6mphGV+4ujiypA==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-client-locale": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-runtime": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-ui-conversation": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session": "^0.1.0-rc.8", + "@deepseek-ai/dsh-tool-workflow": "^0.1.0-rc.8", + "@deepseek-ai/dsh-workflow": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-client-ui-workspace": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-client-ui-workspace/-/dsh-client-ui-workspace-0.1.0-rc.8.tgz", + "integrity": "sha512-Il4hRRV9cDXyZptVC/OKHHOPNd84SwtflHCJ6RP97+OYxnENftdKgHENX7Kqf1RsSXF8RwmOtEvZoHljvYD79A==", + "dev": true, + "license": "MIT", + "dependencies": { + "clsx": "^2.0.0" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-client-connection": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-locale": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-runtime": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-ui-conversation": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-ui-sidebar": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-cmdline": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-cmdline/-/dsh-cmdline-0.1.0-rc.8.tgz", + "integrity": "sha512-xsnNFm2XpMD9wpBBLq80x8yXTi664DHywkLwxgAhDsWyp9tB2aSWaWVKxugPWSWwrB3F4nfloWqaeUfgXRFtBQ==", + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/cordis-plugin-loader": "^1.0.2", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-code-runtime": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-code-runtime/-/dsh-code-runtime-0.1.0-rc.8.tgz", + "integrity": "sha512-6ZKyEE7dHH1UkKe5b0lg18Byww/7ocZyrNMVjAoUWEWp5i96Brf9Eavu9q3zepBMDMZJErCfV0pyt7KDhBJSig==", + "dev": true, + "license": "MIT", + "peer": true, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-code-runtime-worker-thread": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-code-runtime-worker-thread/-/dsh-code-runtime-worker-thread-0.1.0-rc.8.tgz", + "integrity": "sha512-l9fsKYZN2qthnR8fbH8LrTbhWman8rjFCumIttahOKvQEjFMWImY1p8ypM3QtreAtUF8jyHdDnlV8xWQLfanmA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-code-runtime": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session": "^0.1.0-rc.8", + "@deepseek-ai/dsh-timeout": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-command-compact": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-command-compact/-/dsh-command-compact-0.1.0-rc.8.tgz", + "integrity": "sha512-3Zlgw9ghDvj2/22/O7V4kvkxKRfknQw4t9ks5GtBEEVRuU9ullpFElAwq/EZ049zeCnmHnyskyJmwYZRIGaiRA==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-commands": "^0.1.0-rc.8", + "@deepseek-ai/dsh-compaction": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-command-feedback": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-command-feedback/-/dsh-command-feedback-0.1.0-rc.8.tgz", + "integrity": "sha512-RqEcutd+nHVGND/JobUybb8HsgRigr5iEowDk0D7aZeXFJ3tN/0pW67w7DOxdhAVnODIpWg5tSnFpCT8fS78kQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-anonymous-user-id": "^0.1.0-rc.8", + "@deepseek-ai/dsh-commands": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session-telemetry": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-command-goal": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-command-goal/-/dsh-command-goal-0.1.0-rc.8.tgz", + "integrity": "sha512-kMjRuGJA79czVNzx//JEMrjAqDvYpiaOSH95NUu+Mome76S34jmnhCnIyzcg02GcXelDbk9epELAz5HR1Yti/Q==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-commands": "^0.1.0-rc.8", + "@deepseek-ai/dsh-goal": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-commands": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-commands/-/dsh-commands-0.1.0-rc.8.tgz", + "integrity": "sha512-/i99EDLrUyd4bUVn4d7XS46vg09ZE0ervbE/aQaVUWLjDYKrarb7hPx9slADAg5/cUlJsN6L6CP544h9qlUo4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "zod": "^4.4.3" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", + "@deepseek-ai/dsh-attachment": "^0.1.0-rc.8", + "@deepseek-ai/dsh-brand": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", + "@deepseek-ai/dsh-scope": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session": "^0.1.0-rc.8", + "@deepseek-ai/dsh-typert-protocol": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-compaction": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-compaction/-/dsh-compaction-0.1.0-rc.8.tgz", + "integrity": "sha512-sWNqZqejzpKsnEMPsNVA/WYK4S59XlYJtnWw8wCPushzQdUt5zhf+g7LVx0cStSozEfwurxRvaZdOmNaa4WhNQ==", + "dev": true, + "license": "MIT", + "peer": true, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-brand": "^0.1.0-rc.8", + "@deepseek-ai/dsh-commands": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-compaction-basic": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-compaction-basic/-/dsh-compaction-basic-0.1.0-rc.8.tgz", + "integrity": "sha512-UWAUbJbxFQTI3m4LnwZDlcYOfzWNFN1WLjy0qNONNcz3BBa5Nu9kcz4C9jioSp6pg3KMfUNUOtbBRySigTIt7g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", + "@deepseek-ai/dsh-commands": "^0.1.0-rc.8", + "@deepseek-ai/dsh-compaction": "^0.1.0-rc.8", + "@deepseek-ai/dsh-compaction-tool-result-pruner": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session": "^0.1.0-rc.8", + "@deepseek-ai/dsh-token-meter": "^0.1.0-rc.8" + }, + "peerDependenciesMeta": { + "@deepseek-ai/dsh-compaction-tool-result-pruner": { + "optional": true + } + } + }, + "node_modules/@deepseek-ai/dsh-compaction-tool-result-pruner": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-compaction-tool-result-pruner/-/dsh-compaction-tool-result-pruner-0.1.0-rc.8.tgz", + "integrity": "sha512-Mk1QE57HxCMScgQ9ury0o7AM14h6g41cDg1G2kiNqD4Z2LBwFTlZJJAgipyhts4mcr1hz2WZTc8Xgbl9067ONA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-compaction": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session": "^0.1.0-rc.8", + "@deepseek-ai/dsh-token-meter": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-cordis-client-runner": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-cordis-client-runner/-/dsh-cordis-client-runner-0.1.0-rc.8.tgz", + "integrity": "sha512-UbV2zFdOCubLAjQkmYi+6aPxxDfFTSshiyL4EHRbZyqQTdhrnDMfkY48SiVz8s026+E8xxGRPU4kNf3lg5DGeA==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/cordis-plugin-loader": "^1.0.2", + "@deepseek-ai/dsh-api-remotes": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-connection": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-modules": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-runtime": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-ui-theme": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-cordis-host-runner": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-cordis-host-runner/-/dsh-cordis-host-runner-0.1.0-rc.8.tgz", + "integrity": "sha512-DCJr6INHCI0Dypr1JAJj/BnvN31tpIt3Y8+KQ3GDfHW6pUBsc9GnXHpKsuQ4sK/fTj80GjaDYPGdWeB/uKMMdw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1", + "zod": "^4.4.3" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", + "@deepseek-ai/dsh-brand": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", + "@deepseek-ai/dsh-scope": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session": "^0.1.0-rc.8", + "@deepseek-ai/dsh-tools": "^0.1.0-rc.8", + "@deepseek-ai/dsh-typert-protocol": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-credentials": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-credentials/-/dsh-credentials-0.1.0-rc.8.tgz", + "integrity": "sha512-VopOhtUEa/fSmJr3fyKbsEG043kX1oGuBrmELAbkhmuDigl1cN88g0VPb9rMG2/dJ1h08wg+h0RJP+Ex4LjRWw==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-brand": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-credentials-local": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-credentials-local/-/dsh-credentials-local-0.1.0-rc.8.tgz", + "integrity": "sha512-Msbz/+xNIHFXLjcDy2hZFpfV1qduuyjLl35BJOUqNz9eCEYv8b0lfKDI7nirv5E/TdxzLkO75WQ4f+8nifeUpQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1", + "chokidar": "^4.0.3", + "yaml": "^2.9.0" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-atomic-write": "^0.1.0-rc.8", + "@deepseek-ai/dsh-credentials": "^0.1.0-rc.8", + "@deepseek-ai/dsh-home-paths": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-launch-environment": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-file-reference": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-file-reference/-/dsh-file-reference-0.1.0-rc.8.tgz", + "integrity": "sha512-SoU4Zm7L8E9ud5nTs1tVAINFrgKvIKypCdOOMLBjJkjLUvXMYmKFxfCM7xaJjOmK/C5suEVUtpukZhZZvZALNA==", + "dev": true, + "license": "MIT", + "dependencies": { + "zod": "^4.4.3" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-typert-protocol": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-file-reference-local": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-file-reference-local/-/dsh-file-reference-local-0.1.0-rc.8.tgz", + "integrity": "sha512-dw3p1NmuDgJkse1J2RuLwgfiySEFiyRL40o3mo1ireGxXt85JfLns1FR2mdN6v7z6pBpIogGPKV//0U31BWTfg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", + "@deepseek-ai/dsh-file-reference": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-system-prompt": "^0.1.0-rc.8", + "@deepseek-ai/dsh-tools": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-fs": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-fs/-/dsh-fs-0.1.0-rc.8.tgz", + "integrity": "sha512-ge5GW56+z20vYACQ2jqtevusdgMXa64laeU/Chql+VIA3+6xyJ8gLX+oj/1O5TlzhvmZ7ZPfZGBFBEVsEZzTQw==", + "dev": true, + "license": "MIT", + "peer": true, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-brand": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", + "@deepseek-ai/dsh-sandbox": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-fs-local": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-fs-local/-/dsh-fs-local-0.1.0-rc.8.tgz", + "integrity": "sha512-yWk6WrAHs8b6395XnZZOCf3wY90xYKjh/tyU3/rwFy4oU8zq9gzn/x8rdaZD0zUp+wE0XqfBf2AS4Jo03SKHyQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1", + "koffi": "^3.1.0" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-fs": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-fs-observation-policy": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-fs-observation-policy/-/dsh-fs-observation-policy-0.1.0-rc.8.tgz", + "integrity": "sha512-iarNlz2QoEROJUOHPjy7OKOwXuGeEhzk6nWj95F+UHNvKKaquagBE8YE1gzFqbg2U1wFVmPGoHBYl8q7hb5Z8Q==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-fs": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-fs-sandbox": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-fs-sandbox/-/dsh-fs-sandbox-0.1.0-rc.8.tgz", + "integrity": "sha512-JfNgZHFyUyqO5XV/KQ2msO9OQ+98WrGCyfQp34yqCbIXSGS2r471C35Sub+OyTlpCkavGFUjsxo3iT7PLGyVVw==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-fs": "^0.1.0-rc.8", + "@deepseek-ai/dsh-fs-local": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-sandbox": "^0.1.0-rc.8", + "@deepseek-ai/dsh-sandbox-policy": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-goal": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-goal/-/dsh-goal-0.1.0-rc.8.tgz", + "integrity": "sha512-PR/9JjRn2H/33eyAVbtYBxzRWQhFO5N0S/188eAV9gjUTtHe5oSOnPxYy8iNkkMXxr+VE8Nno25Sun8WYmS8lQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1", + "zod": "^4.4.3" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", + "@deepseek-ai/dsh-brand": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", + "@deepseek-ai/dsh-scope": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session-projection": "^0.1.0-rc.8", + "@deepseek-ai/dsh-typert-protocol": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-goal-round-driver": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-goal-round-driver/-/dsh-goal-round-driver-0.1.0-rc.8.tgz", + "integrity": "sha512-hCOOofSuqYxWo+Zc/vcF1C+qk38JEgzJ2ya4bBisWYiRwVFygHODquQllK5ffDjFM+SnX+CdmA+l2piiwCkzcA==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", + "@deepseek-ai/dsh-goal": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-headless": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-headless/-/dsh-headless-0.1.0-rc.8.tgz", + "integrity": "sha512-SfjPjyLeno7iScndgFI3s9s8focqXADLNgIxkFbsL0BdAY7v3A6TOe+iSxnYX0fMhDqFC1jT3FVYlEzbJBg0Kg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-cmdline": "^0.1.0-rc.8", + "@deepseek-ai/dsh-code-runtime-worker-thread": "^0.1.0-rc.8", + "@deepseek-ai/schemastery": "^3.18.1", + "commander": "^15.0.0" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/cordis-plugin-loader": "^1.0.2", + "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", + "@deepseek-ai/dsh-agent-default-model": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-home-paths": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-home-paths/-/dsh-home-paths-0.1.0-rc.8.tgz", + "integrity": "sha512-9cQhH9CZsw7Zi73VnZk7CcuEVA6yR/Ox+7lp3VHq53fFYSPi0RL+kMWmh5XCrZB4U1OM3+PVsWsA5II9tB+t0Q==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-host-apiproxy": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-host-apiproxy/-/dsh-host-apiproxy-0.1.0-rc.8.tgz", + "integrity": "sha512-viq2CoS6bRavSe1t9sLjgunykO+Vn/m83uSgONMH8O7QN0Pk3+FnZGHlPZ1lQ4auNJTwQjxFG6w372cGq9usWw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", + "@deepseek-ai/dsh-agent-default-model": "^0.1.0-rc.8", + "@deepseek-ai/dsh-api-remotes": "^0.1.0-rc.8", + "@deepseek-ai/dsh-attachment": "^0.1.0-rc.8", + "@deepseek-ai/dsh-brand": "^0.1.0-rc.8", + "@deepseek-ai/dsh-commands": "^0.1.0-rc.8", + "@deepseek-ai/dsh-credentials": "^0.1.0-rc.8", + "@deepseek-ai/dsh-goal": "^0.1.0-rc.8", + "@deepseek-ai/dsh-host-directory-picker": "^0.1.0-rc.8", + "@deepseek-ai/dsh-jobs": "^0.1.0-rc.8", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", + "@deepseek-ai/dsh-native-command": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session-persistence": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session-projection": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session-projection-cache": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session-query": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session-title": "^0.1.0-rc.8", + "@deepseek-ai/dsh-settings": "^0.1.0-rc.8", + "@deepseek-ai/dsh-skill": "^0.1.0-rc.8", + "@deepseek-ai/dsh-subagent": "^0.1.0-rc.8", + "@deepseek-ai/dsh-tools": "^0.1.0-rc.8", + "@deepseek-ai/dsh-user-approval": "^0.1.0-rc.8", + "@deepseek-ai/dsh-user-questions": "^0.1.0-rc.8", + "@deepseek-ai/dsh-workspace": "^0.1.0-rc.8", + "@deepseek-ai/schemastery": "^3.18.1", + "fflate": "^0.8.2", + "zod": "^4.4.3" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-agent-presets": "^0.1.0-rc.8", + "@deepseek-ai/dsh-cordis-host-runner": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-host-directory-picker": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-host-directory-picker/-/dsh-host-directory-picker-0.1.0-rc.8.tgz", + "integrity": "sha512-aOUaUX0MTl8oLIuL27OkATMm+x2oTANuhhHpeGizn7+kfOX5bRKB3tyi7h6lGZ9O7WDiDLl2JajRqzBXlIPAAg==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-host-directory-picker-auto": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-host-directory-picker-auto/-/dsh-host-directory-picker-auto-0.1.0-rc.8.tgz", + "integrity": "sha512-t6sn3AlcAARVCOgYMNZS/Yneiw+/2mDM6QOGxR6bu5E7DYTT/tllHe0PlHF1Wgh/LtfOTeDtcSPPfXjmrd+Lqw==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/cordis-plugin-loader": "^1.0.2", + "@deepseek-ai/dsh-client-ui-directory-picker-browse": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-ui-directory-picker-native": "^0.1.0-rc.8", + "@deepseek-ai/dsh-host-directory-picker-browse": "^0.1.0-rc.8", + "@deepseek-ai/dsh-host-directory-picker-native": "^0.1.0-rc.8", + "@deepseek-ai/dsh-host-webserver": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-host-directory-picker-browse": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-host-directory-picker-browse/-/dsh-host-directory-picker-browse-0.1.0-rc.8.tgz", + "integrity": "sha512-zEQ7Wnz953GWiR3Y9GaqPGmhntEdjmcD+x6cbYKXWyeOtMHvv7Lu9EWGNneFHXFt50nMinDBT5kyGzElZ+cajA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-host-directory-picker": "^0.1.0-rc.8", + "@deepseek-ai/schemastery": "^3.18.1" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-host-directory-picker-native": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-host-directory-picker-native/-/dsh-host-directory-picker-native-0.1.0-rc.8.tgz", + "integrity": "sha512-WUB4lW+ZmR743uH9LpFK0JrJU88601E7zvevffa93n7Bl4X7C5Y2yhbDK337H8W/brVlLNVgD2Fw2H/nIPZkDg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-host-directory-picker": "^0.1.0-rc.8", + "@deepseek-ai/dsh-native-command": "^0.1.0-rc.8", + "koffi": "^3.1.0" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-host-frontend-static": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-host-frontend-static/-/dsh-host-frontend-static-0.1.0-rc.8.tgz", + "integrity": "sha512-/ef1xAygNL9hyGtSDzJ04nM5WSNzSxsloSUD2MQfM0FU3Y6b/CbHkUNFYaS0MnhS1YVSulDAGRQvXSgES8vZkg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-host-webserver": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-host-plugin-inventory": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-host-plugin-inventory/-/dsh-host-plugin-inventory-0.1.0-rc.8.tgz", + "integrity": "sha512-knPtxCDZn1jbwRfOUnskjaj8hSXUCfBcjD9LPFXnKffsM6TFOeQrFGhkNKlZteXAMSChtY6pV9bpJj17y3SPNg==", + "dev": true, + "license": "MIT", + "dependencies": { + "zod": "^4.4.3" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/cordis-plugin-loader": "^1.0.2", + "@deepseek-ai/dsh-brand": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-typert-protocol": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-host-webserver": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-host-webserver/-/dsh-host-webserver-0.1.0-rc.8.tgz", + "integrity": "sha512-MEKFrhvsYfj970QHLaKPpF/sIBpCe8NuSA0HGiWYJctX6TM9N3rLRhXx5p3zATDmXZclu1rbYhIbsqWw/twPig==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-invariants": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-invariants/-/dsh-invariants-0.1.0-rc.8.tgz", + "integrity": "sha512-u0lYqyxOYwfsVnbsfGXZos5vFvA4cqFnBEW3/ezgljNwkYwzeUP/Y5wjPnQjP+ZzBn3CnVeIF6s2N2Vk3iA5mQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1" + } + }, + "node_modules/@deepseek-ai/dsh-jobs": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-jobs/-/dsh-jobs-0.1.0-rc.8.tgz", + "integrity": "sha512-HqQudOA4VkjCMpxWiqTCMmuiTa/pehW6yG7dDsctO1vW5K48hWQ/h7czdJKgrh4SMuK4kchv3IipS1KaJmdaog==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", + "@deepseek-ai/dsh-brand": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-jobs-local": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-jobs-local/-/dsh-jobs-local-0.1.0-rc.8.tgz", + "integrity": "sha512-8/cr4rYVS2sLB/Z4lL/ERUn14iBqT9T85rJFxxhEKuT3gMcAkiJuKP7t+ZFWPYSSmcNqDPmMI1ExG+GzjxsLVQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-jobs": "^0.1.0-rc.8", + "@deepseek-ai/dsh-scope": "^0.1.0-rc.8", + "@deepseek-ai/dsh-timeout": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-launch-environment": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-launch-environment/-/dsh-launch-environment-0.1.0-rc.8.tgz", + "integrity": "sha512-VvYo5R7tu4QhX/dsNpuBy3AaauizU6yPCeWQUNzI3ZjGA0VHkkZhInilcgxVJkPA1lwEXYB+OoCAo07PUy6D/w==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-llm": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-llm/-/dsh-llm-0.1.0-rc.8.tgz", + "integrity": "sha512-hf6RmX2Stn1UtzpktSHQLkIktQkBm9i/3yFfJlbGSkwyw5Cv9sTYJbyoHzsSnnh6i8nRRcMcBhvMgm23I00oIw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-attachment": "^0.1.0-rc.8", + "@deepseek-ai/dsh-brand": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-timeout": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-llm-deepseek": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-llm-deepseek/-/dsh-llm-deepseek-0.1.0-rc.8.tgz", + "integrity": "sha512-s4LatnGbHwPJhcWGulO/7RsJBPHHBDB+2+1iRTJEn6vYPB0lOSRWtr91qdmAkUxBZmK5mwrf21IbuW+kWwtAZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1", + "eventsource-parser": "^3.1.0" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-anonymous-user-id": "^0.1.0-rc.8", + "@deepseek-ai/dsh-attachment": "^0.1.0-rc.8", + "@deepseek-ai/dsh-credentials": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-launch-environment": "^0.1.0-rc.8", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", + "@deepseek-ai/dsh-settings": "^0.1.0-rc.8", + "@deepseek-ai/dsh-timeout": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-llm-pi-ai": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-llm-pi-ai/-/dsh-llm-pi-ai-0.1.0-rc.8.tgz", + "integrity": "sha512-r9dmHYy759gKtAG0S96wTCS6O8WFDqGLQu8t+zGY6LnfdT4qUJdmWtJ+GwCn+BGwq1AglBzjabvyRBp6BxXcMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1", + "@earendil-works/pi-ai": "^0.82.1" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-attachment": "^0.1.0-rc.8", + "@deepseek-ai/dsh-credentials": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-launch-environment": "^0.1.0-rc.8", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", + "@deepseek-ai/dsh-settings": "^0.1.0-rc.8", + "@deepseek-ai/dsh-timeout": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-llm-retry": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-llm-retry/-/dsh-llm-retry-0.1.0-rc.8.tgz", + "integrity": "sha512-DmcOajgiku5l7aa5hU9DtwnIZu+i/XCGdb+Wego5W9bAswYeBAwbceloRNE3O6+jdRzy+K5U7KQ9V+olBsNqRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", + "@deepseek-ai/dsh-brand": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session": "^0.1.0-rc.8", + "@deepseek-ai/dsh-timeout": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-mcp-client": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-mcp-client/-/dsh-mcp-client-0.1.0-rc.8.tgz", + "integrity": "sha512-pcqXawjq9jRJQNHZTLN7pswJFMWjxCsEOdHUI9BdJqb9lRDsMi2cul1Hizfi51oKkcNo1u/K9Toqgh8o/ScAXg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1", + "@modelcontextprotocol/sdk": "^1.12.0", + "zod": "^4.4.3" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-attachment": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", + "@deepseek-ai/dsh-subprocess": "^0.1.0-rc.8", + "@deepseek-ai/dsh-timeout": "^0.1.0-rc.8", + "@deepseek-ai/dsh-tools": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-message-feedback": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-message-feedback/-/dsh-message-feedback-0.1.0-rc.8.tgz", + "integrity": "sha512-5DYXVLcnvTRs74Att52LGNR+x+RCf1X5s5+gOSUddsjnQ0wn4f3pzfc0o4F+91aE2zX3xzQ3/LhlW5UOJdkB0Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1", + "zod": "^4.4.3" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-brand": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session-persistence": "^0.1.0-rc.8", + "@deepseek-ai/dsh-storage-domain": "^0.1.0-rc.8", + "@deepseek-ai/dsh-typert-protocol": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-native-command": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-native-command/-/dsh-native-command-0.1.0-rc.8.tgz", + "integrity": "sha512-bRaT8LOb2xmWQ88oSzM4+Y3N4Yy4J0tf15/kQTP53PY1FnOA5hGYWoRglQgfxIcJCrw4fEdUPie8Fff0dCOwdQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-output-retention": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-output-retention/-/dsh-output-retention-0.1.0-rc.8.tgz", + "integrity": "sha512-DeVjqZ9TtH2AEG57GBsHYT68274VygzuP9EqQLL01Ht1TrdK75xlVet1l3jdEbA7Eik4aSGDjAZD9/MsnlUIXg==", + "dev": true, + "license": "MIT", + "peer": true, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-permission-presets": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-permission-presets/-/dsh-permission-presets-0.1.0-rc.8.tgz", + "integrity": "sha512-EeTn8Av5kmb1Qj53D7myRnKcNQrrupGrM2m9LVUO8ieWvlIaYX7n2g0y8kg14SUpcD2YzaT40oGJ6VeDuhTZAA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1", + "zod": "^4.4.3" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-commands": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-sandbox": "^0.1.0-rc.8", + "@deepseek-ai/dsh-sandbox-policy": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session-projection": "^0.1.0-rc.8", + "@deepseek-ai/dsh-settings": "^0.1.0-rc.8", + "@deepseek-ai/dsh-shell": "^0.1.0-rc.8", + "@deepseek-ai/dsh-user-approval": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-persona": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-persona/-/dsh-persona-0.1.0-rc.8.tgz", + "integrity": "sha512-3COzIzZ5kBd+txuH418h9HG4feuVFyhdh02HWvzsWgaPsxjatuFS0OfS6qsejUTZrFDODQSr1WIOeSt80bDBtA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-system-prompt": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-plan-mode": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-plan-mode/-/dsh-plan-mode-0.1.0-rc.8.tgz", + "integrity": "sha512-/SY/iil7KLDvveqKRUZxO4HiADwDlOX9u3xyG/93h785mWSfRXooiv4Zp2tiBjU+pJB0tJXMsQNAXDdg7DWtwA==", + "dev": true, + "license": "MIT", + "dependencies": { + "zod": "^4.4.3" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", + "@deepseek-ai/dsh-commands": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session-projection": "^0.1.0-rc.8", + "@deepseek-ai/dsh-system-prompt": "^0.1.0-rc.8", + "@deepseek-ai/dsh-tools": "^0.1.0-rc.8", + "@deepseek-ai/dsh-user-questions": "^0.1.0-rc.8" + }, + "peerDependenciesMeta": { + "@deepseek-ai/dsh-commands": { + "optional": true + } + } + }, + "node_modules/@deepseek-ai/dsh-pwsh-local": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-pwsh-local/-/dsh-pwsh-local-0.1.0-rc.8.tgz", + "integrity": "sha512-lHAEwC4pL5bVSKgwaeO2dMM9s/jnpDBRuTeVD2HkunpFfT1Kq4lFi+/YXj00L7mW9DBP6FMfwRRV/0Wgo1FtdA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-settings": "^0.1.0-rc.8", + "@deepseek-ai/dsh-shell": "^0.1.0-rc.8", + "@deepseek-ai/dsh-subprocess": "^0.1.0-rc.8", + "@deepseek-ai/dsh-timeout": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-pwsh-sandbox": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-pwsh-sandbox/-/dsh-pwsh-sandbox-0.1.0-rc.8.tgz", + "integrity": "sha512-GVvj4zqpC/lwCGaRmIXIhFqOqewgoGOuokGFuv0QcjQUY3v9FnPor2dqDZr5pav8KFGb5GeGUzLoUbedmsWyZg==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-pwsh-local": "^0.1.0-rc.8", + "@deepseek-ai/dsh-sandbox": "^0.1.0-rc.8", + "@deepseek-ai/dsh-sandbox-policy": "^0.1.0-rc.8", + "@deepseek-ai/dsh-shell": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-repeat-tool-reminder": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-repeat-tool-reminder/-/dsh-repeat-tool-reminder-0.1.0-rc.8.tgz", + "integrity": "sha512-p7/g+NH6JJ0BnLx2V5o0hCm4wZr+dXQ9/Ev8LU6YyFRlcnma8TJuATL0wsA01xWfvvGLRxbe/tH41TRS1NVrJg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-tools": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-sandbox": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-sandbox/-/dsh-sandbox-0.1.0-rc.8.tgz", + "integrity": "sha512-dJpy5p/KjKkHG9AnMKU4+/ilj/4DCglsq3kof/jhIwtsZJCix07TEXP9vV8LCv4fU8af7cK3antXw4eVMqkwuQ==", + "dev": true, + "license": "MIT", + "peer": true, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-sandbox-local": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-sandbox-local/-/dsh-sandbox-local-0.1.0-rc.8.tgz", + "integrity": "sha512-sTrKDXD74yG6B24uhCyN9DuGSpX0SCelN4o5DZylKxt56WRRyywAGdLN0Xt8enqiKCxrq+PJBi+hDh2GtXBj6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-sandbox-windows-acl": "^0.1.0-rc.8", + "@deepseek-ai/node-addon-landlock-run": "^0.1.1", + "@deepseek-ai/schemastery": "^3.18.1" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", + "@deepseek-ai/dsh-sandbox": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-sandbox-policy": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-sandbox-policy/-/dsh-sandbox-policy-0.1.0-rc.8.tgz", + "integrity": "sha512-xQOlYWbUr1Oj6cnRd5aHZIz52EOEAdSO1HJIfeDkQrVaOgohFsiiCIp6PNFumuGNWdCEnf4Q18ebafLNtazYlA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-sandbox": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session": "^0.1.0-rc.8", + "@deepseek-ai/dsh-system-prompt": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-sandbox-windows-acl": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-sandbox-windows-acl/-/dsh-sandbox-windows-acl-0.1.0-rc.8.tgz", + "integrity": "sha512-3DeFPD+laUbXrzVpEJ0FrF5pMQCqeu7YCJAWgORGj1aju7sIjpineEnKpE6EXhbc8C9Jqu2y5S7B9z6ydOL/Zg==", + "dev": true, + "license": "MIT", + "dependencies": { + "koffi": "^3.1.0" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-schedule": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-schedule/-/dsh-schedule-0.1.0-rc.8.tgz", + "integrity": "sha512-L4GO1Bv3+SHIXafjGQcf0sJI9eTf9whxVmYlBxYHw7h7StOZJPMhG9HpsKz4mO9FZ7J4zhBtpYlFbhOQaJheqA==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", + "@deepseek-ai/dsh-brand": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session-persistence": "^0.1.0-rc.8", + "@deepseek-ai/dsh-tools": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-scope": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-scope/-/dsh-scope-0.1.0-rc.8.tgz", + "integrity": "sha512-/o+PxkVV2zUy9lYlMFr4TWSb+ESW4DE+fI891yIbsLzOJdFgfbmmLpGrlWgnz8/unIGJZxjeXdwyppV04Z277Q==", + "dev": true, + "license": "MIT", + "peer": true, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-session": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-session/-/dsh-session-0.1.0-rc.8.tgz", + "integrity": "sha512-Qs5Mgn32WPPVB4rKHjsZBgLOkh0TQurUAcc9GaDVudK4dUkpno2HDh++qu/PrwRA3CZ/iwPAoFHCpB3AMMaoLg==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-brand": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", + "@deepseek-ai/dsh-scope": "^0.1.0-rc.8", + "@deepseek-ai/dsh-typert-protocol": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-session-checkpoint-policy": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-session-checkpoint-policy/-/dsh-session-checkpoint-policy-0.1.0-rc.8.tgz", + "integrity": "sha512-9DpZhQN4MExSjbjBSmaH08DmFS/GHRrsVhO5e3WgTVuH13ugdl5yxc4MEb8qvOhEJUUtOx3fXHuMpSTa0Dxa7w==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session-persistence": "^0.1.0-rc.8", + "@deepseek-ai/dsh-tools": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-session-log-export": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-session-log-export/-/dsh-session-log-export-0.1.0-rc.8.tgz", + "integrity": "sha512-6vDC7uH0WZkwmlj/iql6AmSL9Uifiqi28OIZSDIi8/KRHDHnt5hvjobJecuIxhV9hQSDmNsstErHGx4ng2GJFQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-client-locale": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-runtime": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-ui-commands": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-ui-conversation": "^0.1.0-rc.8", + "@deepseek-ai/dsh-commands": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-session-persistence": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-session-persistence/-/dsh-session-persistence-0.1.0-rc.8.tgz", + "integrity": "sha512-JujorG/UCern0+zxJzNswyWl2tFG9sLzfVNvA5YkTLaRLZt7ZsEhxG4DxWZ6uj+3RJ8sf4bqdKqvpIn9t1pwUw==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-brand": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session": "^0.1.0-rc.8", + "@deepseek-ai/dsh-timeout": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-session-persistence-jsonl": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-session-persistence-jsonl/-/dsh-session-persistence-jsonl-0.1.0-rc.8.tgz", + "integrity": "sha512-T/Lvh76O2tpVw04FAhgLF3Qovq3SrUnzaywIbB+Uw67a2DD63Qg+cJY9WO6Pu/UowPxbpuUOd12c6iPY5x8d7Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1", + "koffi": "^3.1.0" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session-persistence": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-session-projection": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-session-projection/-/dsh-session-projection-0.1.0-rc.8.tgz", + "integrity": "sha512-q00B+rl7WAuK0Bgh93SY2+ZpqaH2kJhfJ9n6Jg6R/m4plnH0Ip4oCAHl6u8rBzDgb1mniQGEQDz/7BN5Q3It8Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "zod": "^4.4.3" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-session-projection-cache": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-session-projection-cache/-/dsh-session-projection-cache-0.1.0-rc.8.tgz", + "integrity": "sha512-IPvO7k9FlekOJXn4XLWUwU5+JDQn7khu8Oa04GFDystU3c1CnOwoa7SGMHOfJau3r177M4ncXApwN5Ra6uhyXw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1", + "zod": "^4.4.3" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session-persistence": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session-projection": "^0.1.0-rc.8", + "@deepseek-ai/dsh-storage-domain": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-session-query": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-session-query/-/dsh-session-query-0.1.0-rc.8.tgz", + "integrity": "sha512-q8eyfpgPuJx24l1fEevDkc3Dux3lNp/yDzVkDL4nSTGNaDx/h9Y6iG7SZdqWM5nxOET3iwxi4AkPM7lYyLg3cQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-brand": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session-persistence": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session-title": "^0.1.0-rc.8" + }, + "peerDependenciesMeta": { + "@deepseek-ai/dsh-session-persistence": { + "optional": true + } + } + }, + "node_modules/@deepseek-ai/dsh-session-query-sqlite": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-session-query-sqlite/-/dsh-session-query-sqlite-0.1.0-rc.8.tgz", + "integrity": "sha512-jrNq2vgWIH7OzNMHXrKEjEMwy86I36I94a8X5u937xo2B2JD8ZIWfuWHC9YyLqabRwNf7VcQ6VZ6ruSgESRE7A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session-persistence": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session-query": "^0.1.0-rc.8" + }, + "peerDependenciesMeta": { + "@deepseek-ai/dsh-session-persistence": { + "optional": true + } + } + }, + "node_modules/@deepseek-ai/dsh-session-reference": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-session-reference/-/dsh-session-reference-0.1.0-rc.8.tgz", + "integrity": "sha512-meNS02BOkLc2SnF2qWvl5X1Psk59t0Q1vvwjfCkczD29g4nm7Y02EZ089HJKii0VAsSB39RYA2rf6MCSl6vhow==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1", + "zod": "^4.4.3" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", + "@deepseek-ai/dsh-compaction": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", + "@deepseek-ai/dsh-output-retention": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session-query": "^0.1.0-rc.8", + "@deepseek-ai/dsh-typert-protocol": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-session-stats": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-session-stats/-/dsh-session-stats-0.1.0-rc.8.tgz", + "integrity": "sha512-T+SEzBkMxZpQ31MaeJCjaLN3/xu8yyZ3Va5u6osfq0nsJz1tvuZ53MHMbApdwERHVV0t/1eILTUo1J6XdksUEA==", + "dev": true, + "license": "MIT", + "dependencies": { + "zod": "^4.4.3" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session-projection": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-session-telemetry": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-session-telemetry/-/dsh-session-telemetry-0.1.0-rc.8.tgz", + "integrity": "sha512-Rs7w+PP/uuOaa34RFY4q6Xjes/C32H0gPvZe/gV9M87y1EcJs+mFBzhnc/zyKeaAdT25RWIwO3KATmKlT/D0Dg==", + "dev": true, + "license": "MIT", + "peer": true, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-session-telemetry-otel": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-session-telemetry-otel/-/dsh-session-telemetry-otel-0.1.0-rc.8.tgz", + "integrity": "sha512-rpPwidBwKV53WM2bYW/eYOZ6j5U9VHOIVrITQkQtGDMAzD9UaqfAXfXfUlsw9vsfjED2gKmSf7vn+bVfy8Tjaw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1", + "@opentelemetry/api": "^1.9.1", + "@opentelemetry/api-logs": "^0.220.0", + "@opentelemetry/exporter-logs-otlp-http": "^0.220.0", + "@opentelemetry/otlp-exporter-base": "^0.220.0", + "@opentelemetry/resources": "^2.9.0", + "@opentelemetry/sdk-logs": "^0.220.0" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-anonymous-user-id": "^0.1.0-rc.8", + "@deepseek-ai/dsh-command-feedback": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session-telemetry": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-session-title": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-session-title/-/dsh-session-title-0.1.0-rc.8.tgz", + "integrity": "sha512-OFG9kHFGnM5ND4LCkqg8oZr57qgF6xMkBxR/4MRaJJ42QrPI9QKzoZVRpNpXEl3v3uw8oR7Jj0jbc7WClNl3ow==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1", + "zod": "^4.4.3" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-brand": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session-projection": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-session-title-first-prompt-llm": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-session-title-first-prompt-llm/-/dsh-session-title-first-prompt-llm-0.1.0-rc.8.tgz", + "integrity": "sha512-pFx2hPVYyRCRcbd4WJZVapVekLLEGMAG1KAcrixf3XOGDNaqVEPF8LWatx8iKQRfVSQlvIOwDO8uEsC0NZiPNA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session-title": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session-title-llm": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-session-title-llm": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-session-title-llm/-/dsh-session-title-llm-0.1.0-rc.8.tgz", + "integrity": "sha512-6xz3umGBtGmM+t5O5wwlCwbH9gmBOlQBfg7qGnPJftWc4VWHG7l2VUYqd3DNTQVTHIA/hSN4qg/LXTm79rADGQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session-title": "^0.1.0-rc.8", + "@deepseek-ai/dsh-timeout": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-settings": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-settings/-/dsh-settings-0.1.0-rc.8.tgz", + "integrity": "sha512-pqbMoiSP+Ieww9/4gcHYXcBCDlno1zYDu2OPq+5xdZ+McnK+5YBtHsiRpnR9cHQxGTH7lkfIv+adkOueQW0utg==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-brand": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/schemastery": "^3.18.1" + } + }, + "node_modules/@deepseek-ai/dsh-settings-file": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-settings-file/-/dsh-settings-file-0.1.0-rc.8.tgz", + "integrity": "sha512-2mCyAPkxA5r7Ezgt41XtJxRBsj5Dkl21e5v7w+6YE3C8/n9zRRlN4X5oInHcUKEmgoTrNLCBCgOs5DNrl+pErw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1", + "chokidar": "^4.0.3", + "yaml": "^2.9.0" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-atomic-write": "^0.1.0-rc.8", + "@deepseek-ai/dsh-home-paths": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-settings": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-shell": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-shell/-/dsh-shell-0.1.0-rc.8.tgz", + "integrity": "sha512-RNhp7Y25DXUH7o36X4GcN0lnOLg6NXTlWZpYNURT7aDj3UHcLLajRsyddiAh1EbwQnl0GRKRZhLaZHrrG6gMIw==", + "dev": true, + "license": "MIT", + "peer": true, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-sandbox": "^0.1.0-rc.8", + "@deepseek-ai/dsh-settings": "^0.1.0-rc.8", + "@deepseek-ai/dsh-subprocess": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-shell-env": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-shell-env/-/dsh-shell-env-0.1.0-rc.8.tgz", + "integrity": "sha512-E/Rlka8BnpB7GM67ZJPjvZyp0O9L5x28giyJhHWZcPHN4rsEQFVVqk0cH6iDT5STy+dMc9BAUW+im18kATIxsA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-home-paths": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session-persistence": "^0.1.0-rc.8", + "@deepseek-ai/dsh-shell": "^0.1.0-rc.8", + "@deepseek-ai/dsh-tools": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-skill": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-skill/-/dsh-skill-0.1.0-rc.8.tgz", + "integrity": "sha512-MqcOzl4Y5pQEvFBNVAi5w0IZWH5kVbXmp1RYScrl+8HpVATZbgumDhztVnEc2kUrZu+o6LKb1hnbunK6JHUE5g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", + "@deepseek-ai/dsh-scope": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-skill-badge": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-skill-badge/-/dsh-skill-badge-0.1.0-rc.8.tgz", + "integrity": "sha512-VjISwf5qDpkD+bxLuVXYL7IakhPoZudIOwWCFjTD++Tj8VQTN9ORCq1uCOatFLi5v/an8MzdZ91O2pXfQtb7dQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-skill": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-skill-filesystem": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-skill-filesystem/-/dsh-skill-filesystem-0.1.0-rc.8.tgz", + "integrity": "sha512-A87t/1+wxPiMkUXWVdf4DfgxA8rp1eLmStMvzfdthR/WxtGPzuEv2L5oyNDzKiCBwIcxBN6Fy2THNa2Xba2kQQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1", + "chokidar": "^5.0.0", + "yaml": "^2.4.2" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-fs": "^0.1.0-rc.8", + "@deepseek-ai/dsh-home-paths": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-skill": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-skill-filesystem/node_modules/chokidar": { + "version": "5.0.0", + "resolved": "https://registry.npmmirror.com/chokidar/-/chokidar-5.0.0.tgz", + "integrity": "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==", + "dev": true, + "license": "MIT", + "dependencies": { + "readdirp": "^5.0.0" + }, + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@deepseek-ai/dsh-skill-filesystem/node_modules/readdirp": { + "version": "5.1.1", + "resolved": "https://registry.npmmirror.com/readdirp/-/readdirp-5.1.1.tgz", + "integrity": "sha512-Kko+Y5XQ6fM+Ce3dq3m9YGxnacYZYl9cA1wZjaF3Vbry2L3i1qVg8+CAgNPsXRArPMUMCaOR7oa9Nqntc43JKA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@deepseek-ai/dsh-spill": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-spill/-/dsh-spill-0.1.0-rc.8.tgz", + "integrity": "sha512-LDfyBuRS/yfc+JYvSicEXYJDj5PFBfWN6vJ5G3wy14eMrq3OKoYip8lyIjEdR4qwCVh0s+oSi28AlcvkPuyOdw==", + "dev": true, + "license": "MIT", + "peer": true, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-brand": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-spill-local": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-spill-local/-/dsh-spill-local-0.1.0-rc.8.tgz", + "integrity": "sha512-4Ew3cBOQxW6wA4U8svXCjUyhX00+h0W/bK9CzTy/HoYrNJhP85euJVV7SfNlq6OfTeQBWn3U0wKwNlcc3gAyAg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-spill": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-spill-policy": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-spill-policy/-/dsh-spill-policy-0.1.0-rc.8.tgz", + "integrity": "sha512-9y2IHaKowtqGxhYd59R3OfWv1sonIDv2h9WX/jhxbagMvORfRkhjWJP4YAxp+l4Ba1LhVLcuG/nb2p8hqGdO4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", + "@deepseek-ai/dsh-output-retention": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session": "^0.1.0-rc.8", + "@deepseek-ai/dsh-spill": "^0.1.0-rc.8", + "@deepseek-ai/dsh-tools": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-storage": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-storage/-/dsh-storage-0.1.0-rc.8.tgz", + "integrity": "sha512-KcxiNFAC1X0GhbS9yWGo7FLARBNsxoyU9JatxQtA23MuqOZaN4Nzy3bsMViK4/snzpPGwm//I+wfUywSjM6uBA==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-storage-domain": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-storage-domain/-/dsh-storage-domain-0.1.0-rc.8.tgz", + "integrity": "sha512-rHphQ0jveKoCurwh9TX+VAVFsMQivBgghQBOAsWdVDZ3W6boeXNhMZWuGWZ7WjMPD3iJKgiFCx+650hhsao+LQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1", + "zod": "^4.4.3" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-storage": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-storage-json": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-storage-json/-/dsh-storage-json-0.1.0-rc.8.tgz", + "integrity": "sha512-cTlqy+5bQH7/UOFqRoWSaY9DaaDpcx4jmvWcwY8ciMUBse8BXcEtchVr5zqqss+xA/+Z/l9VraH+diwwRuAWbg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-storage": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-subagent": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-subagent/-/dsh-subagent-0.1.0-rc.8.tgz", + "integrity": "sha512-EI94+hYMfAe8BQkkH/FTcciGxajFfAdQe66Jhy2/eyR3dssRAZ+oJsV6SzU20x3m2yd0gmMaXzO1iV3gwYhY+g==", + "dev": true, + "license": "MIT", + "dependencies": { + "zod": "^4.4.3" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", + "@deepseek-ai/dsh-agent-presets": "^0.1.0-rc.8", + "@deepseek-ai/dsh-brand": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-jobs": "^0.1.0-rc.8", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", + "@deepseek-ai/dsh-sandbox": "^0.1.0-rc.8", + "@deepseek-ai/dsh-sandbox-policy": "^0.1.0-rc.8", + "@deepseek-ai/dsh-scope": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session-persistence": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session-projection": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session-projection-cache": "^0.1.0-rc.8", + "@deepseek-ai/dsh-tools": "^0.1.0-rc.8", + "@deepseek-ai/dsh-user-approval": "^0.1.0-rc.8" + }, + "peerDependenciesMeta": { + "@deepseek-ai/dsh-agent-presets": { + "optional": true + }, + "@deepseek-ai/dsh-jobs": { + "optional": true + }, + "@deepseek-ai/dsh-sandbox": { + "optional": true + }, + "@deepseek-ai/dsh-sandbox-policy": { + "optional": true + }, + "@deepseek-ai/dsh-session-persistence": { + "optional": true + }, + "@deepseek-ai/dsh-session-projection": { + "optional": true + }, + "@deepseek-ai/dsh-session-projection-cache": { + "optional": true + }, + "@deepseek-ai/dsh-user-approval": { + "optional": true + } + } + }, + "node_modules/@deepseek-ai/dsh-subagent-fork-in-process": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-subagent-fork-in-process/-/dsh-subagent-fork-in-process-0.1.0-rc.8.tgz", + "integrity": "sha512-CVen9Fu0TwiwuyTHmZeankN/v0EwdMwOAcq8fSTIyFGPG4ngtqQNSRMxwYTrz39kKyHv0VBW+r8tRd1LBdTAWA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session": "^0.1.0-rc.8", + "@deepseek-ai/dsh-subagent": "^0.1.0-rc.8", + "@deepseek-ai/dsh-subagent-in-process-driver": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-subagent-in-process-driver": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-subagent-in-process-driver/-/dsh-subagent-in-process-driver-0.1.0-rc.8.tgz", + "integrity": "sha512-UJXwh484V/rEmRrvf5l0IWg2ceVOaSOU7Z6DEBq++bKOuFQ2BVkMm+Uj3dk4qFngeb10+/GXlRkbe3mqPwQDSA==", + "dev": true, + "license": "MIT", + "peer": true, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session": "^0.1.0-rc.8", + "@deepseek-ai/dsh-subagent": "^0.1.0-rc.8", + "@deepseek-ai/dsh-system-prompt": "^0.1.0-rc.8", + "@deepseek-ai/dsh-tools": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-subagent-spawn-in-process": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-subagent-spawn-in-process/-/dsh-subagent-spawn-in-process-0.1.0-rc.8.tgz", + "integrity": "sha512-+ZratMZJiNg0vDmaEauJpiNI9IzVwCWisbidow6AV8O5CLC9/XlcMTjFGxmxcbnPdNlVM9i8OLK8gY7/kZ7tTA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-subagent": "^0.1.0-rc.8", + "@deepseek-ai/dsh-subagent-in-process-driver": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-subprocess": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-subprocess/-/dsh-subprocess-0.1.0-rc.8.tgz", + "integrity": "sha512-rTWwWCq/WrBTjaXhApu7gaho6UHwMZq0+l7nZ06YMUreNZoCHfg67pAXopMqTgr/iotphmXQdChrLgBabzL1gA==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-subprocess-local": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-subprocess-local/-/dsh-subprocess-local-0.1.0-rc.8.tgz", + "integrity": "sha512-2QMd6Nwjd+ARor4g+GSZ3dNyTvEf2IPOje47nQwa3UCmltLxn8K8gjDAN/5sGr/IF56P14FeF4xFag7tMK+Zdg==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "koffi": "^3.1.0", + "node-pty": "1.2.0-beta.15" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-subprocess": "^0.1.0-rc.8", + "@deepseek-ai/dsh-timeout": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-system-prompt": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-system-prompt/-/dsh-system-prompt-0.1.0-rc.8.tgz", + "integrity": "sha512-yk8Z85rzX2EwpKNWA5i+K3I3mqsIIUc9niwbDpXO8vlHvpC2qR3RNHjJIJN2EZYDqfSzTVtkbxHFsuMzDXIbew==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", + "@deepseek-ai/dsh-scope": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-terminal": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-terminal/-/dsh-terminal-0.1.0-rc.8.tgz", + "integrity": "sha512-Vu73FrQGx8h7Mqq0QdKtzAiZ3xgVM4fB9wmf3fEl6OiJTcqfc8t4lgug3gE7uBeDVRaLn+aq7kHbEUOY0fsm1Q==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", + "@deepseek-ai/dsh-brand": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-terminal-bash": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-terminal-bash/-/dsh-terminal-bash-0.1.0-rc.8.tgz", + "integrity": "sha512-ehBMVr/0kZ15Vud7uE6PLobukwJi/BqGDbI1oonPPTOoTjDvuCqlKotNEQtS/G4NsvGshEABv+m5X5ELcRCWUA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-pwsh-local": "^0.1.0-rc.8", + "@deepseek-ai/schemastery": "^3.18.1" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-sandbox": "^0.1.0-rc.8", + "@deepseek-ai/dsh-sandbox-policy": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session": "^0.1.0-rc.8", + "@deepseek-ai/dsh-subprocess": "^0.1.0-rc.8", + "@deepseek-ai/dsh-terminal": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-time-context": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-time-context/-/dsh-time-context-0.1.0-rc.8.tgz", + "integrity": "sha512-9Rdse95S6Uk8OAHf78AQN/pxV6+29fCkIbF4ONP/F/6YBciKDORypRyMbHNSY81fBMHQPhW1xvZecGISdIHHiQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-timeout": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-timeout/-/dsh-timeout-0.1.0-rc.8.tgz", + "integrity": "sha512-RwOC/qHribE6b+LStAO7aAgweefLE5sqDO7Uz6/mnTDyJxCt7HNQnE/Op8sAvRa33d752aUkPfO9S0mgzVAoFQ==", + "dev": true, + "license": "MIT", + "peer": true, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-tmux-context": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-tmux-context/-/dsh-tmux-context-0.1.0-rc.8.tgz", + "integrity": "sha512-ezhL3Wjpn4TqqvgSuKrJgNVG7jrWGekEWRYimqD1SvmAHQAS+Xr9q7DBl1uSFfJDWUOAPlAB8VAuo3k/CLUwKA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session": "^0.1.0-rc.8", + "@deepseek-ai/dsh-shell": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-token-meter": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-token-meter/-/dsh-token-meter-0.1.0-rc.8.tgz", + "integrity": "sha512-ZcS6vuuJhoqjUrbyROuiiYk4nrvChkkYEfIoj7CjGbNArWOhbStmBaiPyahtcB1kThcnUKdu7vv7DaZJdLw8Lg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1", + "zod": "^4.4.3" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-compaction": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session-projection": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-tool-ask-user": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-tool-ask-user/-/dsh-tool-ask-user-0.1.0-rc.8.tgz", + "integrity": "sha512-PQVcuvNvTI18B2jSvgS20wX0GRnpom+6X6iNBL/WPLiicJeoxvDYj+M7SjdSsqBNv5t0i9VlYhO4NYicmluy+g==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-tools": "^0.1.0-rc.8", + "@deepseek-ai/dsh-user-questions": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-tool-bash": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-tool-bash/-/dsh-tool-bash-0.1.0-rc.8.tgz", + "integrity": "sha512-VvP8Ky8ifqS7Iy7XUxc6cWB7sse3X6gqr92m0hBuodwQblzrZq2b6IyzfTzXKZKLqt5mMUaLRt7IPIDOOG+WEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-jobs": "^0.1.0-rc.8", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", + "@deepseek-ai/dsh-sandbox": "^0.1.0-rc.8", + "@deepseek-ai/dsh-sandbox-policy": "^0.1.0-rc.8", + "@deepseek-ai/dsh-shell": "^0.1.0-rc.8", + "@deepseek-ai/dsh-shell-env": "^0.1.0-rc.8", + "@deepseek-ai/dsh-system-prompt": "^0.1.0-rc.8", + "@deepseek-ai/dsh-tools": "^0.1.0-rc.8", + "@deepseek-ai/dsh-user-approval": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-tool-bash-persistent": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-tool-bash-persistent/-/dsh-tool-bash-persistent-0.1.0-rc.8.tgz", + "integrity": "sha512-GySj2Nr7y4ewYTH0miD5DzfLEZNxAmWfSyJ5oOYVtzIbqkcU5WOjpsjQvDg0kuERXAq4MYcdc2QfrPet1/MkIQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-terminal": "^0.1.0-rc.8", + "@deepseek-ai/dsh-timeout": "^0.1.0-rc.8", + "@deepseek-ai/dsh-tools": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-tool-call-timeout-policy": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-tool-call-timeout-policy/-/dsh-tool-call-timeout-policy-0.1.0-rc.8.tgz", + "integrity": "sha512-Z6M/nkcz40DisaOIHqUOjjjW4wCi+JqQNoUhOu+VAoBDWHl7SDmEvdWSQUwkyOETjcfdRSG4RTJ5z/rBUVCPHQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", + "@deepseek-ai/dsh-timeout": "^0.1.0-rc.8", + "@deepseek-ai/dsh-tools": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-tool-cordis": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-tool-cordis/-/dsh-tool-cordis-0.1.0-rc.8.tgz", + "integrity": "sha512-bIbkazp5xasqtJBFljOGVIdxyAAWIcKoxMuhDoUpfPFuEqZaXJumYJJ9+ugqr+KKkddjuf2SvlpE5XB4zWcNvg==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", + "@deepseek-ai/dsh-cordis-host-runner": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", + "@deepseek-ai/dsh-scope": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session": "^0.1.0-rc.8", + "@deepseek-ai/dsh-system-prompt": "^0.1.0-rc.8", + "@deepseek-ai/dsh-tools": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-tool-fs": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-tool-fs/-/dsh-tool-fs-0.1.0-rc.8.tgz", + "integrity": "sha512-pxo2YfVlqcw0sCA2+4DtqaaYsuxkx1QfvjT3VO+ckZMWn/UnGOUuzjJtKhVynwjm8prttGqK2LBXUTBZPlKTWg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1", + "diff": "^9.0.0" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-attachment": "^0.1.0-rc.8", + "@deepseek-ai/dsh-fs": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", + "@deepseek-ai/dsh-sandbox": "^0.1.0-rc.8", + "@deepseek-ai/dsh-sandbox-policy": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session": "^0.1.0-rc.8", + "@deepseek-ai/dsh-system-prompt": "^0.1.0-rc.8", + "@deepseek-ai/dsh-tools": "^0.1.0-rc.8", + "@deepseek-ai/dsh-user-approval": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-tool-fs-search": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-tool-fs-search/-/dsh-tool-fs-search-0.1.0-rc.8.tgz", + "integrity": "sha512-AZvESByrPbBIYIGDoTgVOHH48antHy2ZSaLfsVfz1Rw/jQIeiBKwt2LYIPhRGGvev6TXw95qWKt5cyv6WDXHlg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1", + "@vscode/ripgrep": "^1.18.0" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", + "@deepseek-ai/dsh-output-retention": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session": "^0.1.0-rc.8", + "@deepseek-ai/dsh-spill": "^0.1.0-rc.8", + "@deepseek-ai/dsh-subprocess": "^0.1.0-rc.8", + "@deepseek-ai/dsh-system-prompt": "^0.1.0-rc.8", + "@deepseek-ai/dsh-timeout": "^0.1.0-rc.8", + "@deepseek-ai/dsh-tools": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-tool-goal": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-tool-goal/-/dsh-tool-goal-0.1.0-rc.8.tgz", + "integrity": "sha512-EO8iqRV3R8YgdMGUVAp/20XCKbegdwZ7fqr7+oSg11lGHuTnXDz4im4HBXri/wmL9XHeBjmcAQ0BXESbhX2VOQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", + "@deepseek-ai/dsh-goal": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session": "^0.1.0-rc.8", + "@deepseek-ai/dsh-system-prompt": "^0.1.0-rc.8", + "@deepseek-ai/dsh-tools": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-tool-jobs": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-tool-jobs/-/dsh-tool-jobs-0.1.0-rc.8.tgz", + "integrity": "sha512-p3gWi38ryJFRes1lTAdVkdZrUBB8RYPpy4XqZ9DgC2qcrLOJZnnsprIUxyDDmhbyargOgTGc3hEeRU5g8OQAIA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-jobs": "^0.1.0-rc.8", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", + "@deepseek-ai/dsh-output-retention": "^0.1.0-rc.8", + "@deepseek-ai/dsh-system-prompt": "^0.1.0-rc.8", + "@deepseek-ai/dsh-tools": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-tool-pwsh": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-tool-pwsh/-/dsh-tool-pwsh-0.1.0-rc.8.tgz", + "integrity": "sha512-B5F08tsSD7DHqXDXjn/Q11FavHw1U8/WAEqp8AC47vDRymPJIgTM8zSlJ0Lx7aZaKPTW4zQYtSmwUhy93q6zfw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-jobs": "^0.1.0-rc.8", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", + "@deepseek-ai/dsh-sandbox": "^0.1.0-rc.8", + "@deepseek-ai/dsh-sandbox-policy": "^0.1.0-rc.8", + "@deepseek-ai/dsh-shell": "^0.1.0-rc.8", + "@deepseek-ai/dsh-shell-env": "^0.1.0-rc.8", + "@deepseek-ai/dsh-system-prompt": "^0.1.0-rc.8", + "@deepseek-ai/dsh-tools": "^0.1.0-rc.8", + "@deepseek-ai/dsh-user-approval": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-tool-pwsh-persistent": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-tool-pwsh-persistent/-/dsh-tool-pwsh-persistent-0.1.0-rc.8.tgz", + "integrity": "sha512-OxQhywkvUTuGj26yaE1LyoADsCKttaIdiq2dJd+Xcbjc+tnI1gfoVrBj+Sta3/uT7x66kKjXZ1+gnw6gK5qISQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-terminal": "^0.1.0-rc.8", + "@deepseek-ai/dsh-timeout": "^0.1.0-rc.8", + "@deepseek-ai/dsh-tools": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-tool-ralph": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-tool-ralph/-/dsh-tool-ralph-0.1.0-rc.8.tgz", + "integrity": "sha512-+kVCbLEBDxOCCHPdR5+hgQFbkTvTaJ3D7zTNxNEtS5Tr/7eGAU7/VmwNMMSZ4Z+eyHQQEm4vgT+O1pMTvLmb7g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", + "@deepseek-ai/dsh-subagent": "^0.1.0-rc.8", + "@deepseek-ai/dsh-system-prompt": "^0.1.0-rc.8", + "@deepseek-ai/dsh-tools": "^0.1.0-rc.8", + "@deepseek-ai/dsh-workflow": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-tool-skill": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-tool-skill/-/dsh-tool-skill-0.1.0-rc.8.tgz", + "integrity": "sha512-oQAPyXiQDDZ73rZwST7KqwUAr0Al3U1dxWdtzETsMzvNSQE9fmMBz5jUObFIEjxxJcA07Pp1DFzuJdpkCIDeCw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", + "@deepseek-ai/dsh-skill": "^0.1.0-rc.8", + "@deepseek-ai/dsh-tools": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-tool-str-replace-editor": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-tool-str-replace-editor/-/dsh-tool-str-replace-editor-0.1.0-rc.8.tgz", + "integrity": "sha512-2gyO5a5xNvBo9I5vmVSvgXRfxUfKGDu3WjjdK0aDWx/Y+C1r1mGVC7R5mN/oJstcUCIyKm483ux1pT9/O1QD8w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-fs": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-sandbox": "^0.1.0-rc.8", + "@deepseek-ai/dsh-sandbox-policy": "^0.1.0-rc.8", + "@deepseek-ai/dsh-tools": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-tool-subagent": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-tool-subagent/-/dsh-tool-subagent-0.1.0-rc.8.tgz", + "integrity": "sha512-mwNV8M7hsy9+OsSFCluv87FiDHaXO91m83xF/o34Ip9xrgkGs7LOCjvUdCpwjxFTJenWEcvEU90aa7vv3aT/Iw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-jobs": "^0.1.0-rc.8", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", + "@deepseek-ai/dsh-subagent": "^0.1.0-rc.8", + "@deepseek-ai/dsh-system-prompt": "^0.1.0-rc.8", + "@deepseek-ai/dsh-tools": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-tool-subagent-control": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-tool-subagent-control/-/dsh-tool-subagent-control-0.1.0-rc.8.tgz", + "integrity": "sha512-zXF9iIzr96w/S3jNxkRcyV1ouwA1eUCSmvqhlSDkkcA8RH5jt5vWkTia8fwRs1pFS9m7OpbLtvbDxjC8D3nedw==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session": "^0.1.0-rc.8", + "@deepseek-ai/dsh-subagent": "^0.1.0-rc.8", + "@deepseek-ai/dsh-tools": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-tool-subagent-report": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-tool-subagent-report/-/dsh-tool-subagent-report-0.1.0-rc.8.tgz", + "integrity": "sha512-u0CzoSu7O1YyOpGyHfmT/P2hCfnepSzVKrs6MHFrzjbuiRFEcVme6/iLrc7QdLtg484Q1kcnqG2z0OZS24AnWQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", + "@deepseek-ai/dsh-subagent": "^0.1.0-rc.8", + "@deepseek-ai/dsh-system-prompt": "^0.1.0-rc.8", + "@deepseek-ai/dsh-tools": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-tool-todo": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-tool-todo/-/dsh-tool-todo-0.1.0-rc.8.tgz", + "integrity": "sha512-eWxwTeX5WsQPSsz1qyJq+UMiASYB5UHLdObVd4vFLYKbFOoglUK0X+Ie5OjlAkFTP+OzCQMAzUl2gJMwJPWKig==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1", + "zod": "^4.4.3" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session-projection": "^0.1.0-rc.8", + "@deepseek-ai/dsh-tools": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-tool-web": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-tool-web/-/dsh-tool-web-0.1.0-rc.8.tgz", + "integrity": "sha512-MrTkQ2L52A13ysTM94bSW+5sXq3AyVNoo5q3bK47bsl+hg9Kga5gDgGAZ+SGVSQZAUEHXfuYGHaErdUp50bncw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1", + "@joplin/turndown-plugin-gfm": "^1.0.67", + "turndown": "^7.2.4" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", + "@deepseek-ai/dsh-system-prompt": "^0.1.0-rc.8", + "@deepseek-ai/dsh-tools": "^0.1.0-rc.8", + "@deepseek-ai/dsh-web": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-tool-workflow": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-tool-workflow/-/dsh-tool-workflow-0.1.0-rc.8.tgz", + "integrity": "sha512-Z3MCCLM28J/nqiqwHG9roGVUzwMKEADRsSNLPYNemXq5vVEYjm5sBwC+QcWtiQ7NxKXf5ViUu3eKXTe1Fh5TNg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session": "^0.1.0-rc.8", + "@deepseek-ai/dsh-system-prompt": "^0.1.0-rc.8", + "@deepseek-ai/dsh-tools": "^0.1.0-rc.8", + "@deepseek-ai/dsh-workflow": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-tools": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-tools/-/dsh-tools-0.1.0-rc.8.tgz", + "integrity": "sha512-tvuGAVUS4yoPW9zH7CGWJgMlAzGjfu2UlRiricldlcwSKAaJZPZx/K/YfTivUyDTER6aK1DJUnIpVG7RD/DoHQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", + "@deepseek-ai/dsh-code-runtime": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", + "@deepseek-ai/dsh-scope": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session": "^0.1.0-rc.8", + "@deepseek-ai/dsh-system-prompt": "^0.1.0-rc.8", + "@deepseek-ai/dsh-user-approval": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-typert-loader": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-typert-loader/-/dsh-typert-loader-0.1.0-rc.8.tgz", + "integrity": "sha512-IB2Bkv7UglS0y/Dt7buFq87bbUkD/njvuCp4/bRxlbb/8U02b7v18UXnYFoZjCusfzeYxaCBZihImv7aDMBhCA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/cordis-plugin-loader": "^1.0.2", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-typert-registry": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-typert-protocol": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-typert-protocol/-/dsh-typert-protocol-0.1.0-rc.8.tgz", + "integrity": "sha512-scwEAefRBL7gRpaXiEdiHRMvlr8dLmUbiEvy0LOAX/8X3FZBd/5tHQ/8lCppAQNTDZMI/LSiSMpu5XrFId+7cQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-typert-registry": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-typert-registry/-/dsh-typert-registry-0.1.0-rc.8.tgz", + "integrity": "sha512-pxfRE5f1y81h2lNqj0uooYrErTVgpzKfYm4W+ppRafN5s/+1jlLIYWiG3wWD3bnxyoD2NLcTEhi/GXoaqiwdaw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-typert-protocol": "^0.1.0-rc.8", + "zod": "^4.4.3" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-user-approval": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-user-approval/-/dsh-user-approval-0.1.0-rc.8.tgz", + "integrity": "sha512-6SFCxp7dgNFEyzQIcs5i9C+5djgXsAeV0iKmZUCLlcIeVM1chcCMHyGcoXlw8yyB14qFMrMs+TPvhvpu2WWxAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", + "@deepseek-ai/dsh-brand": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", + "@deepseek-ai/dsh-scope": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session": "^0.1.0-rc.8", + "@deepseek-ai/dsh-system-prompt": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-user-questions": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-user-questions/-/dsh-user-questions-0.1.0-rc.8.tgz", + "integrity": "sha512-kiOAlpKKfB89iObWiiVpueD4XCaday203LGUs7+eGb2isolY6VppoGb7ZmcJQqsW63bjbAA7wZeJuN3CoxcvSQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-web": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-web/-/dsh-web-0.1.0-rc.8.tgz", + "integrity": "sha512-YLraDwZTx0Y3Jqw2cu4eClv9ZgEJYoeSFzTe7c9JZ4Z3ThaNCCwEaXWEPMBiPKU6QlR8ahkPPj6xoU9+nPO66g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-web-app": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-web-app/-/dsh-web-app-0.1.0-rc.8.tgz", + "integrity": "sha512-Te/N+AxFmQF2267yMqama5Lp2evsBJeFsqhnEZPfvFhquLBBWgtO5DNZ2cxto5NhGGNNCk/JV25vHRxd7bZl8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/dsh-agent-presets": "^0.1.0-rc.8", + "@deepseek-ai/dsh-api-remotes": "^0.1.0-rc.8", + "@deepseek-ai/dsh-app-boot": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-connection": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-hmr": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-locale": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-modules": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-runtime": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-ui-agent-preset": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-ui-attachment": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-ui-brand-official": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-ui-commands": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-ui-conversation": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-ui-cordis": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-ui-deliverables": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-ui-directory-picker-browse": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-ui-directory-picker-native": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-ui-goal": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-ui-input-trigger": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-ui-jobs": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-ui-layout": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-ui-message-feedback": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-ui-model-selection": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-ui-permission-presets": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-ui-plan": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-ui-reference": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-ui-renderer": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-ui-settings": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-ui-settings-general": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-ui-settings-models": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-ui-settings-plugin-inventory": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-ui-settings-plugins": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-ui-sidebar": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-ui-skill": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-ui-subagent": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-ui-theme": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-ui-tool": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-ui-trajectory": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-ui-user-questions": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-ui-workflow-run": "^0.1.0-rc.8", + "@deepseek-ai/dsh-client-ui-workspace": "^0.1.0-rc.8", + "@deepseek-ai/dsh-cmdline": "^0.1.0-rc.8", + "@deepseek-ai/dsh-code-runtime-worker-thread": "^0.1.0-rc.8", + "@deepseek-ai/dsh-cordis-client-runner": "^0.1.0-rc.8", + "@deepseek-ai/dsh-cordis-host-runner": "^0.1.0-rc.8", + "@deepseek-ai/dsh-file-reference": "^0.1.0-rc.8", + "@deepseek-ai/dsh-file-reference-local": "^0.1.0-rc.8", + "@deepseek-ai/dsh-host-apiproxy": "^0.1.0-rc.8", + "@deepseek-ai/dsh-host-directory-picker-auto": "^0.1.0-rc.8", + "@deepseek-ai/dsh-host-directory-picker-browse": "^0.1.0-rc.8", + "@deepseek-ai/dsh-host-directory-picker-native": "^0.1.0-rc.8", + "@deepseek-ai/dsh-host-frontend-static": "^0.1.0-rc.8", + "@deepseek-ai/dsh-host-plugin-inventory": "^0.1.0-rc.8", + "@deepseek-ai/dsh-host-webserver": "^0.1.0-rc.8", + "@deepseek-ai/dsh-launch-environment": "^0.1.0-rc.8", + "@deepseek-ai/dsh-message-feedback": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session-log-export": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session-projection-cache": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session-reference": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session-stats": "^0.1.0-rc.8", + "@deepseek-ai/dsh-storage": "^0.1.0-rc.8", + "@deepseek-ai/dsh-storage-domain": "^0.1.0-rc.8", + "@deepseek-ai/dsh-storage-json": "^0.1.0-rc.8", + "@deepseek-ai/dsh-subprocess": "^0.1.0-rc.8", + "@deepseek-ai/dsh-web-frontend": "^0.1.0-rc.8", + "@deepseek-ai/dsh-workspace": "^0.1.0-rc.8", + "@deepseek-ai/schemastery": "^3.18.1", + "commander": "^15.0.0", + "open": "^11.0.0" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/cordis-plugin-loader": "^1.0.2", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-shell-env": "^0.1.0-rc.8", + "@deepseek-ai/dsh-system-prompt": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-web-frontend": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-web-frontend/-/dsh-web-frontend-0.1.0-rc.8.tgz", + "integrity": "sha512-GxWJtkNEniYtSH19XWIJvMO2RSP2bMAZvs3Z6m9cEr9OFbngCY5XCXwqsJMYqOJIao0eSePp/eRCPeXNvqeGXA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@deepseek-ai/dsh-web-search-deepseek": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-web-search-deepseek/-/dsh-web-search-deepseek-0.1.0-rc.8.tgz", + "integrity": "sha512-ifaFw+Cil3yte/9r//3wwMWWPIMuYhvYAB0Hk56IVf+8RDbnRkTJY2foFNNgD91dq1ZL2gBijkdxv1c7wDt+EA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", + "@deepseek-ai/dsh-credentials": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-launch-environment": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session": "^0.1.0-rc.8", + "@deepseek-ai/dsh-settings": "^0.1.0-rc.8", + "@deepseek-ai/dsh-web": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-workflow": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-workflow/-/dsh-workflow-0.1.0-rc.8.tgz", + "integrity": "sha512-a4UJKJAFOPQgVaWegk8MIh8BQjqerkGhHu2+uGF4wyGanzI7FHHY/OUmH4hHTVEx2qFcWh732Od/T8LgL6gcbg==", + "dev": true, + "license": "MIT", + "peer": true, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", + "@deepseek-ai/dsh-brand": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-workflow-worker-thread": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-workflow-worker-thread/-/dsh-workflow-worker-thread-0.1.0-rc.8.tgz", + "integrity": "sha512-QBkHJ8l174U3VqHRi2KyJIFey+Uxzo/OOFbTFx7TP5f761lPvqYiXlILuQJ9QvT7WJTyZO3QRLIIU6ZEBwxTIA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@deepseek-ai/schemastery": "^3.18.1" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", + "@deepseek-ai/dsh-brand": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session": "^0.1.0-rc.8", + "@deepseek-ai/dsh-subagent": "^0.1.0-rc.8", + "@deepseek-ai/dsh-tools": "^0.1.0-rc.8", + "@deepseek-ai/dsh-workflow": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/dsh-workspace": { + "version": "0.1.0-rc.8", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-workspace/-/dsh-workspace-0.1.0-rc.8.tgz", + "integrity": "sha512-Uyw44WcYvXRQjb0kUstTEJmL83hkGQbWnJzglaGWcAvsZBjQHeBgKuLzOZin1yc/dRX2pKuk1InFwxKXpaHjBA==", + "dev": true, + "license": "MIT", + "dependencies": { + "zod": "^4.4.3" + }, + "peerDependencies": { + "@deepseek-ai/cordis": "^4.0.1", + "@deepseek-ai/dsh-brand": "^0.1.0-rc.8", + "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session": "^0.1.0-rc.8", + "@deepseek-ai/dsh-session-persistence": "^0.1.0-rc.8", + "@deepseek-ai/dsh-storage": "^0.1.0-rc.8", + "@deepseek-ai/dsh-storage-domain": "^0.1.0-rc.8" + } + }, + "node_modules/@deepseek-ai/node-addon-landlock-run": { + "version": "0.1.1", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/node-addon-landlock-run/-/node-addon-landlock-run-0.1.1.tgz", + "integrity": "sha512-aHGhlQJEutfobKM/4K59SERbT7RmQdD2oMKzD8Bne/Ps7TeT8AweCN+dpdfuxQhMNbFcJMymrgPnID0WYQ30Tw==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=20" + }, + "optionalDependencies": { + "@deepseek-ai/node-addon-landlock-run-linux-arm64": "0.1.1", + "@deepseek-ai/node-addon-landlock-run-linux-x64": "0.1.1" + } + }, + "node_modules/@deepseek-ai/node-addon-landlock-run-linux-arm64": { + "version": "0.1.1", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/node-addon-landlock-run-linux-arm64/-/node-addon-landlock-run-linux-arm64-0.1.1.tgz", + "integrity": "sha512-lYY2RbcPW4rGRM5hVJbrXlvLqyBxeJBjBqvt+QTHTU+GtfUVVjTODKa4e3CRwMQoCEpOjoARdQBHbN7HvE72WQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "BSD-3-Clause", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=20" + } + }, + "node_modules/@deepseek-ai/node-addon-landlock-run-linux-x64": { + "version": "0.1.1", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/node-addon-landlock-run-linux-x64/-/node-addon-landlock-run-linux-x64-0.1.1.tgz", + "integrity": "sha512-OHAzPW2Coe/iYobAJAAA8CeVrBoKV4BnNHsgwvXwOfishxkUVSWSvdyxrZPiwYRXutpIGVrSo9zV3WOQy2euBA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "BSD-3-Clause", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=20" + } + }, + "node_modules/@deepseek-ai/schemastery": { + "version": "3.18.1", + "resolved": "https://registry.npmmirror.com/@deepseek-ai/schemastery/-/schemastery-3.18.1.tgz", + "integrity": "sha512-Qn0FCSwCQnpnj6SB31I6i2sIKgKWnkbJM8O0EU91Gv2UsYVvtZTl6IA0sCwk2e2MZf5S8w5hpq9QkeVvK9qwxg==", + "license": "MIT", + "dependencies": { + "@deepseek-ai/cosmokit": "^1.8.2", + "@standard-schema/spec": "^1.1.0" + } + }, + "node_modules/@earendil-works/pi-ai": { + "version": "0.82.1", + "resolved": "https://registry.npmmirror.com/@earendil-works/pi-ai/-/pi-ai-0.82.1.tgz", + "integrity": "sha512-3WFYRhEp3lQB3444EhPMBcM7zSaEUE3eJgHOR7s4081NLqbw/FsWilIKWXSua0Gv3sRr7m9xMidR3pPDE7jI/A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@anthropic-ai/sdk": "0.91.1", + "@aws-sdk/client-bedrock-runtime": "3.1048.0", + "@google/genai": "1.52.0", + "@mistralai/mistralai": "2.2.6", + "@opentelemetry/api": "1.9.0", + "@smithy/node-http-handler": "4.7.3", + "http-proxy-agent": "7.0.2", + "https-proxy-agent": "7.0.6", + "openai": "6.26.0", + "partial-json": "0.1.7", + "typebox": "1.1.38" + }, + "bin": { + "pi-ai": "dist/cli.js" + }, + "engines": { + "node": ">=22.19.0" + } + }, + "node_modules/@earendil-works/pi-ai/node_modules/@opentelemetry/api": { + "version": "1.9.0", + "resolved": "https://registry.npmmirror.com/@opentelemetry/api/-/api-1.9.0.tgz", + "integrity": "sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@emnapi/runtime": { + "version": "1.11.3", + "resolved": "https://registry.npmmirror.com/@emnapi/runtime/-/runtime-1.11.3.tgz", + "integrity": "sha512-Xz4Tpyki7XyrpbUK1jR1AhdAdaXyhhY4lZ3neLodmhpuWfy2PAQN5B46sAiU4liOXGLkHypn/qU+jvfWSCYYLA==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@google/genai": { + "version": "1.52.0", + "resolved": "https://registry.npmmirror.com/@google/genai/-/genai-1.52.0.tgz", + "integrity": "sha512-gwSvbpiN/17O9TbsqSsE/OzZcpv5Fo4RQjdngGgogtuB9RsyJ8ZHhX5KjHj1bp5N9snN2eK8LDGXSaWW2hof8Q==", + "dev": true, + "hasInstallScript": true, + "license": "Apache-2.0", + "dependencies": { + "google-auth-library": "^10.3.0", + "p-retry": "^4.6.2", + "protobufjs": "^7.5.4", + "ws": "^8.18.0" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "@modelcontextprotocol/sdk": "^1.25.2" + }, + "peerDependenciesMeta": { + "@modelcontextprotocol/sdk": { + "optional": true + } + } + }, + "node_modules/@hono/node-server": { + "version": "2.1.1", + "resolved": "https://registry.npmmirror.com/@hono/node-server/-/node-server-2.1.1.tgz", + "integrity": "sha512-ELuehkj5VCBdgEw9zs+ivkKwyzzUCSQuE96YmiPvn1ECBoZCczbFXJLeEGMTYjphP6gydh4pHMqEYPVMYUVgQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20" + }, + "peerDependencies": { + "hono": "^4" + } + }, + "node_modules/@img/colour": { + "version": "1.1.0", + "resolved": "https://registry.npmmirror.com/@img/colour/-/colour-1.1.0.tgz", + "integrity": "sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/@img/sharp-darwin-arm64": { + "version": "0.35.3", + "resolved": "https://registry.npmmirror.com/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.35.3.tgz", + "integrity": "sha512-RMnFX7YQsMoh7lWfcM4NEHHymBX/rLuKNPVM84XE9ONPcaSCDgE7CHIHpSgPcO2xcRthgBy1HfNO319mwhIAkg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-darwin-arm64": "1.3.2" + } + }, + "node_modules/@img/sharp-darwin-x64": { + "version": "0.35.3", + "resolved": "https://registry.npmmirror.com/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.35.3.tgz", + "integrity": "sha512-Xo+5uFBtLN0BKqieTxiFzFPQAUlBbbH5iBKyRX/z1JrbnYsHTfKJnUfL8+p2TPXr1pXqao4eeL4Rl144uDpK9w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-darwin-x64": "1.3.2" + } + }, + "node_modules/@img/sharp-freebsd-wasm32": { + "version": "0.35.3", + "resolved": "https://registry.npmmirror.com/@img/sharp-freebsd-wasm32/-/sharp-freebsd-wasm32-0.35.3.tgz", + "integrity": "sha512-lUxcqWIj2wMQ9BrwNjngcr1gWUr5xgaGThBRqPPalIC2n67Cqj1uPh8NnA/ZhAg8hUbKl+kVHKwgUIwe6ZYPrg==", + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "dependencies": { + "@img/sharp-wasm32": "0.35.3" + }, + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-darwin-arm64": { + "version": "1.3.2", + "resolved": "https://registry.npmmirror.com/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.3.2.tgz", + "integrity": "sha512-9J6ypZFpQBj4YnePGoq/S38w6nz+vqg5WZLrLGY4YuSemdMq47GMLBPO42MzwdGwpg/agZ7xzZcFHa48xlywfg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "darwin" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-darwin-x64": { + "version": "1.3.2", + "resolved": "https://registry.npmmirror.com/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.3.2.tgz", + "integrity": "sha512-m2pW1n6cns9VaubNwsZ+c3CRYjxNQWgJ5gPlnL1nbBcpkBvFm6SCFN5o0psFHI8w9n11NKhFkeEDns98tiqbEw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "darwin" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-arm": { + "version": "1.3.2", + "resolved": "https://registry.npmmirror.com/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.3.2.tgz", + "integrity": "sha512-1eMLzy92I4J6rmi4mAT8yC3HxOtniyGELlzGbNMLLeqe052ahFQ0h6LFq+lh5DsDIdYViIDst08abvSbcEdLXQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-arm64": { + "version": "1.3.2", + "resolved": "https://registry.npmmirror.com/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.3.2.tgz", + "integrity": "sha512-dqVSFynCox4C/J8kT16V7SIFAns0IjgLwkvYT7p8LQVmJ5OS5b6tI9IGflxTeuBS//zXeFIUbwt5dwxyZ17cnA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-ppc64": { + "version": "1.3.2", + "resolved": "https://registry.npmmirror.com/@img/sharp-libvips-linux-ppc64/-/sharp-libvips-linux-ppc64-1.3.2.tgz", + "integrity": "sha512-3z0NHDxD6n5I9gc05U1eW1AyRm+Gznzq3naMrthPNqE6oYykcogW0l/jfpJdjYnuNl8R7yI9pNbE1XiUeyq0Aw==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-riscv64": { + "version": "1.3.2", + "resolved": "https://registry.npmmirror.com/@img/sharp-libvips-linux-riscv64/-/sharp-libvips-linux-riscv64-1.3.2.tgz", + "integrity": "sha512-bsb4rI+NldGOsXuej2r8OdSS8+zXDVaCWxyWrcv6kneTOlgAHtZABRzBBCwdsPiD90J4myNJuHpg6kA20ImW/w==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-s390x": { + "version": "1.3.2", + "resolved": "https://registry.npmmirror.com/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.3.2.tgz", + "integrity": "sha512-/ABshyj8gCpyIrNXnHn4LorDJ0HHm1VhXPBlxZ8zAtfVPAaSafXPGn+sUSIRiwaSBy0mmFjSjiXI5mkcwdChKQ==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-x64": { + "version": "1.3.2", + "resolved": "https://registry.npmmirror.com/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.3.2.tgz", + "integrity": "sha512-ITPEtgffGJ0S6G9dRyw/366tJQqFRcHWPHhC+Stpg3Z8AEMrDrTr2lhdz4f/Y/HMbRh//7Z5mBzEpVdi62Oc3w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linuxmusl-arm64": { + "version": "1.3.2", + "resolved": "https://registry.npmmirror.com/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.3.2.tgz", + "integrity": "sha512-zE9EdiUzUmg5mDT5a1rk5fYJ6GWPloTwWBYDS14naqHsL+EaMpDj1AWnpLgh3u0YCORv2Tt50wrcrpYqkP97Kw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linuxmusl-x64": { + "version": "1.3.2", + "resolved": "https://registry.npmmirror.com/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.3.2.tgz", + "integrity": "sha512-m0lrLiUt+lBYnCFr8qV/65yMR4E/c7/wf78I5eKTdkEakFAlZ9QlzEM3QIhhAwVeUhLAHLcCq7a7Vszq/oFNZQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-linux-arm": { + "version": "0.35.3", + "resolved": "https://registry.npmmirror.com/@img/sharp-linux-arm/-/sharp-linux-arm-0.35.3.tgz", + "integrity": "sha512-affVWCTLooy8TSxbDx2qkzuDeaWLNVBA+P//FNBirHsXpP2fuBhk5AuboYUnrDnzoXes8GFjpTx0SBFOCRg+FA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-arm": "1.3.2" + } + }, + "node_modules/@img/sharp-linux-arm64": { + "version": "0.35.3", + "resolved": "https://registry.npmmirror.com/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.35.3.tgz", + "integrity": "sha512-QgKDspHPnrU+GQ55XPhGwyhC8acLVOOSyAvo1oVfFmrIXLkDNmGWzAfDZ4xK8oSA1qBQrALcHX0G5UZni/SuFQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-arm64": "1.3.2" + } + }, + "node_modules/@img/sharp-linux-ppc64": { + "version": "0.35.3", + "resolved": "https://registry.npmmirror.com/@img/sharp-linux-ppc64/-/sharp-linux-ppc64-0.35.3.tgz", + "integrity": "sha512-sMd8rDxmpLOwv/7N44klFjOD5DUO7FLdjiXDI0hoxYaf7Ar262dQIEkosE98bps+5HPLtp/EvNqeqQtOycP/IA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-ppc64": "1.3.2" + } + }, + "node_modules/@img/sharp-linux-riscv64": { + "version": "0.35.3", + "resolved": "https://registry.npmmirror.com/@img/sharp-linux-riscv64/-/sharp-linux-riscv64-0.35.3.tgz", + "integrity": "sha512-0Eob78yjlYPfL5vMNWAW55l3R9Y6BQS/gOfe0ZcP9mEz9ohhKSt4im1hayiknXgf8AWrFqMvJcKIdmLmEe7yeQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-riscv64": "1.3.2" + } + }, + "node_modules/@img/sharp-linux-s390x": { + "version": "0.35.3", + "resolved": "https://registry.npmmirror.com/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.35.3.tgz", + "integrity": "sha512-KgAxQ0DxpNOq1rG2t5cgTgShJFGSuU7XO45cqC+1NVOuZnP6tlgZRuSYOfNupGkHID0o3cJOsw4DVeJpMovcGw==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-s390x": "1.3.2" + } + }, + "node_modules/@img/sharp-linux-x64": { + "version": "0.35.3", + "resolved": "https://registry.npmmirror.com/@img/sharp-linux-x64/-/sharp-linux-x64-0.35.3.tgz", + "integrity": "sha512-8pqvxubL2PGdhlPy6GLqzDYMUjyRmKAwKHYKixpdJYBUK7PJ0C029XdsnpFIdgRZG68fZiGdHVWcKPvtiPB4cA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-x64": "1.3.2" + } + }, + "node_modules/@img/sharp-linuxmusl-arm64": { + "version": "0.35.3", + "resolved": "https://registry.npmmirror.com/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.35.3.tgz", + "integrity": "sha512-Vz0iQjzzcSX3HCbfwFfCSG/9SCIqyO0mH2sXyiHaAYfBk0cRsCWXRyQYX0ovCK/PAQBbTzQ0dsPQHh5MAFL59w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linuxmusl-arm64": "1.3.2" + } + }, + "node_modules/@img/sharp-linuxmusl-x64": { + "version": "0.35.3", + "resolved": "https://registry.npmmirror.com/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.35.3.tgz", + "integrity": "sha512-6O1NPKcDVj9QEdg7Hx549EX8U0rp6yXQERqru6yRN7fGBn32UvIRJUlWnk+8xDCiG76hXVBbX82NZ/ZKr0euIg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linuxmusl-x64": "1.3.2" + } + }, + "node_modules/@img/sharp-wasm32": { + "version": "0.35.3", + "resolved": "https://registry.npmmirror.com/@img/sharp-wasm32/-/sharp-wasm32-0.35.3.tgz", + "integrity": "sha512-cZ0XkcYGpHZkqW6iCkqTcmUC0CD9DhD5d/qeZlZkfRBn6GnHniZXLUo5+9xw8Iv76YE6LQFN9YNBlKREcCG76w==", + "dev": true, + "license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT", + "optional": true, + "dependencies": { + "@emnapi/runtime": "^1.11.1" + }, + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-webcontainers-wasm32": { + "version": "0.35.3", + "resolved": "https://registry.npmmirror.com/@img/sharp-webcontainers-wasm32/-/sharp-webcontainers-wasm32-0.35.3.tgz", + "integrity": "sha512-2rnq7bX3NzeR2T4YWgz8qiG4h3TSdMe+vN1iQXpJleSJ3SM5zQ8Fy2SyyXAWlbxpEZ2Y+Z4u1BePgJEYbSy80Q==", + "cpu": [ + "wasm32" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "@img/sharp-wasm32": "0.35.3" + }, + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-arm64": { + "version": "0.35.3", + "resolved": "https://registry.npmmirror.com/@img/sharp-win32-arm64/-/sharp-win32-arm64-0.35.3.tgz", + "integrity": "sha512-4bPwFdMbeC4JQ8L8LOyWp6nsHcboP5fxkp6iPOXz2Vg49R42TuMs2whkJ5OAP4/Ul035qOzy0AecOF9VOscn4w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-ia32": { + "version": "0.35.3", + "resolved": "https://registry.npmmirror.com/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.35.3.tgz", + "integrity": "sha512-r53mXsBN6lFUDiST764SvgwUdHAqM4rPAiDzAmf4fLoB6X/rkfyTrLCg6+g17wJJiCmB3JYgHuUldCWUIRFSXw==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-x64": { + "version": "0.35.3", + "resolved": "https://registry.npmmirror.com/@img/sharp-win32-x64/-/sharp-win32-x64-0.35.3.tgz", + "integrity": "sha512-D4y1vNeZrIIJCN+uHaWVtH86B+aCrdMYYjicy9pXHvbGZeGYLLSd3wdVuC37FxVXlU1ARsk84eKWfWMXGYEqvA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@joplin/turndown-plugin-gfm": { + "version": "1.0.67", + "resolved": "https://registry.npmmirror.com/@joplin/turndown-plugin-gfm/-/turndown-plugin-gfm-1.0.67.tgz", + "integrity": "sha512-FZfW5EZfidhzd1IaY1uxHnIZPTVOxAdleMZ4/1U6Nt5b7+Qj5JThDnaIomuJtetnUBzuRNbe9FWMuqD4B3dlWA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@koromix/koffi-darwin-arm64": { + "version": "3.1.5", + "resolved": "https://registry.npmmirror.com/@koromix/koffi-darwin-arm64/-/koffi-darwin-arm64-3.1.5.tgz", + "integrity": "sha512-IpqITl2fJi3QN9bTtNnygWPdK7ScSjw3xtGu8e6feYGvimCysu+spgI5KyeslY2jTnqxGS9xr8pLAbLhGJ8edA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "funding": { + "url": "https://liberapay.com/Koromix" + } + }, + "node_modules/@koromix/koffi-darwin-x64": { + "version": "3.1.5", + "resolved": "https://registry.npmmirror.com/@koromix/koffi-darwin-x64/-/koffi-darwin-x64-3.1.5.tgz", + "integrity": "sha512-4Tia4BS5EV/+vN9eIrdToanVe+U/2VqTZCBgOzoUbPKjgky51eqM+3J4qdRUvmYJohcJNPob5/hsxeItUZrl1g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "funding": { + "url": "https://liberapay.com/Koromix" + } + }, + "node_modules/@koromix/koffi-freebsd-arm64": { + "version": "3.1.5", + "resolved": "https://registry.npmmirror.com/@koromix/koffi-freebsd-arm64/-/koffi-freebsd-arm64-3.1.5.tgz", + "integrity": "sha512-bP94uzseFO79NG3flpU3WxfyvltD+jzC/kN8FDZLi8J0VUZNW1Wmu8yq87KEzjX1qT9KyX4Y+elVbGqHXHTv2Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "funding": { + "url": "https://liberapay.com/Koromix" + } + }, + "node_modules/@koromix/koffi-freebsd-ia32": { + "version": "3.1.5", + "resolved": "https://registry.npmmirror.com/@koromix/koffi-freebsd-ia32/-/koffi-freebsd-ia32-3.1.5.tgz", + "integrity": "sha512-raFXXAPHzvCQWhaoMUF+Cc2ZWgg2UBU0RVoowHZhaw9nQYPC1pERcPRH+JA+SNIN6g4d2GFW6uPFc+QbUhsagA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "funding": { + "url": "https://liberapay.com/Koromix" + } + }, + "node_modules/@koromix/koffi-freebsd-x64": { + "version": "3.1.5", + "resolved": "https://registry.npmmirror.com/@koromix/koffi-freebsd-x64/-/koffi-freebsd-x64-3.1.5.tgz", + "integrity": "sha512-h6RyBZmPMBIDWTABkJIhzDdYwSnYAJvTacHpEjbT55Arkmw1H15Rl7CFtXuEuBrqh+uivoCrRgA6vszl9CsJ9g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "funding": { + "url": "https://liberapay.com/Koromix" + } + }, + "node_modules/@koromix/koffi-linux-arm64": { + "version": "3.1.5", + "resolved": "https://registry.npmmirror.com/@koromix/koffi-linux-arm64/-/koffi-linux-arm64-3.1.5.tgz", + "integrity": "sha512-u0vCmKPu4yQDhl/ri1J6U3vDnvYtYjoZaIWb+oMbRXhVZeiqdE53MGPb+q2A7Dj2n9IbYloAfEICQbL6l0pmiQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://liberapay.com/Koromix" + } + }, + "node_modules/@koromix/koffi-linux-ia32": { + "version": "3.1.5", + "resolved": "https://registry.npmmirror.com/@koromix/koffi-linux-ia32/-/koffi-linux-ia32-3.1.5.tgz", + "integrity": "sha512-Xa5JbumWglwPVZgrJcLhqyC1wCWlfm7+C00p3FuOTNGp0qoYuf2/tOoAh0/q7+taVm30cMopu/6lRHwdmF6I/w==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://liberapay.com/Koromix" + } + }, + "node_modules/@koromix/koffi-linux-loong64": { + "version": "3.1.5", + "resolved": "https://registry.npmmirror.com/@koromix/koffi-linux-loong64/-/koffi-linux-loong64-3.1.5.tgz", + "integrity": "sha512-F3i2CeTcqVBUQiSRUBSEzX1VgtXmLLiZb/ouZtXHkWpTLhJNd9TH7s3CizTofci0VRqlKdexGUYhK5vzPDAAHA==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://liberapay.com/Koromix" + } + }, + "node_modules/@koromix/koffi-linux-riscv64": { + "version": "3.1.5", + "resolved": "https://registry.npmmirror.com/@koromix/koffi-linux-riscv64/-/koffi-linux-riscv64-3.1.5.tgz", + "integrity": "sha512-2TgQuzy+4PfDg+rw3kOmN6lywEWdzKT3eaLPbOp0b/9DaN7CLBJ/QIR5GhGsMNpeI30zU0YzFeYFxoVoJ/LqFw==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://liberapay.com/Koromix" + } + }, + "node_modules/@koromix/koffi-linux-x64": { + "version": "3.1.5", + "resolved": "https://registry.npmmirror.com/@koromix/koffi-linux-x64/-/koffi-linux-x64-3.1.5.tgz", + "integrity": "sha512-2yaIg/1V0m4CiAUMzG4CIlWmq1WJ+QBMlFfaGr9su+OH5fuIqC7V3BbMiB03IwIl1VofIZO5JA4Db4lID8tpbw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://liberapay.com/Koromix" + } + }, + "node_modules/@koromix/koffi-openbsd-ia32": { + "version": "3.1.5", + "resolved": "https://registry.npmmirror.com/@koromix/koffi-openbsd-ia32/-/koffi-openbsd-ia32-3.1.5.tgz", + "integrity": "sha512-8/OXd+u9omMooykhvdJPEP7u6FFzzrrFo9gOmSHc9/DPt3XkVYOtSsE97PDk6zYaAzwIYHSKjHvIXsfFwFc7sg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "funding": { + "url": "https://liberapay.com/Koromix" + } + }, + "node_modules/@koromix/koffi-openbsd-x64": { + "version": "3.1.5", + "resolved": "https://registry.npmmirror.com/@koromix/koffi-openbsd-x64/-/koffi-openbsd-x64-3.1.5.tgz", + "integrity": "sha512-SpeqldKkuDk2aTj5PVWumy7eq6Tr2GtBPAOI1NiDHhg8xe433KraxrA9V9UjEd+1+kSGJQGR04nQByN3MPA9PQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "funding": { + "url": "https://liberapay.com/Koromix" + } + }, + "node_modules/@koromix/koffi-win32-arm64": { + "version": "3.1.5", + "resolved": "https://registry.npmmirror.com/@koromix/koffi-win32-arm64/-/koffi-win32-arm64-3.1.5.tgz", + "integrity": "sha512-uej3YAEKAhlfVPoIo5sOwtxhTLRVJ01LgtWrKGpnnAQU3C+Ilmaxdh+Oc2xc1G3NK30N5eCVJpyO9r3pjKC6Vw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "funding": { + "url": "https://liberapay.com/Koromix" + } + }, + "node_modules/@koromix/koffi-win32-ia32": { + "version": "3.1.5", + "resolved": "https://registry.npmmirror.com/@koromix/koffi-win32-ia32/-/koffi-win32-ia32-3.1.5.tgz", + "integrity": "sha512-d42jv2f4PwtJGNJS19Xfn/BRtGsBNNVkw0O0K5tkIGI+yNq4MnPTSUsaGbDIkCLNsCgk/LFqAaE8BExyCdrujA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "funding": { + "url": "https://liberapay.com/Koromix" + } + }, + "node_modules/@koromix/koffi-win32-x64": { + "version": "3.1.5", + "resolved": "https://registry.npmmirror.com/@koromix/koffi-win32-x64/-/koffi-win32-x64-3.1.5.tgz", + "integrity": "sha512-Pyo1WEHEP6Ek2NEn2pquwJzSPLOdY4vymoPSz0an1DgvFWSkOyBYYkGVoxL1ajfj5I1pPdXysYqixtVTzAtOfQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "funding": { + "url": "https://liberapay.com/Koromix" + } + }, + "node_modules/@mistralai/mistralai": { + "version": "2.2.6", + "resolved": "https://registry.npmmirror.com/@mistralai/mistralai/-/mistralai-2.2.6.tgz", + "integrity": "sha512-W8pX7zHxjJvMIpw8JMxeJEleapXX0Q9NPszdNzqkM3MIEoIGPObdodujj+WHteXEvGfaP/AMwlNyRfEzSY6dQQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/semantic-conventions": "^1.40.0", + "ws": "^8.18.0", + "zod": "^3.25.0 || ^4.0.0", + "zod-to-json-schema": "^3.25.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.9.0" + }, + "peerDependenciesMeta": { + "@opentelemetry/api": { + "optional": true + } + } + }, + "node_modules/@mixmark-io/domino": { + "version": "2.2.0", + "resolved": "https://registry.npmmirror.com/@mixmark-io/domino/-/domino-2.2.0.tgz", + "integrity": "sha512-Y28PR25bHXUg88kCV7nivXrP2Nj2RueZ3/l/jdx6J9f8J4nsEGcgX0Qe6lt7Pa+J79+kPiJU3LguR6O/6zrLOw==", + "dev": true, + "license": "BSD-2-Clause" + }, + "node_modules/@modelcontextprotocol/sdk": { + "version": "1.30.0", + "resolved": "https://registry.npmmirror.com/@modelcontextprotocol/sdk/-/sdk-1.30.0.tgz", + "integrity": "sha512-xKd8OIzlqNzcqcNumGAa6g+PW2kjD5vrpcKOnfldAUPP3j7lnqMPwlTXQm8gF+UwH72z0lqaRbjr9hqGz0eITA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@hono/node-server": "^1.19.9 || ^2.0.5", + "ajv": "^8.17.1", + "ajv-formats": "^3.0.1", + "content-type": "^1.0.5", + "cors": "^2.8.5", + "cross-spawn": "^7.0.5", + "eventsource": "^3.0.2", + "eventsource-parser": "^3.0.0", + "express": "^5.2.1", + "express-rate-limit": "^8.2.1", + "hono": "^4.11.4", + "jose": "^6.1.3", + "json-schema-typed": "^8.0.2", + "pkce-challenge": "^5.0.0", + "raw-body": "^3.0.0", + "zod": "^3.25 || ^4.0", + "zod-to-json-schema": "^3.25.1" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@cfworker/json-schema": "^4.1.1", + "zod": "^3.25 || ^4.0" + }, + "peerDependenciesMeta": { + "@cfworker/json-schema": { + "optional": true + }, + "zod": { + "optional": false + } + } + }, + "node_modules/@opentelemetry/api": { + "version": "1.9.1", + "resolved": "https://registry.npmmirror.com/@opentelemetry/api/-/api-1.9.1.tgz", + "integrity": "sha512-gLyJlPHPZYdAk1JENA9LeHejZe1Ti77/pTeFm/nMXmQH/HFZlcS/O2XJB+L8fkbrNSqhdtlvjBVjxwUYanNH5Q==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@opentelemetry/api-logs": { + "version": "0.220.0", + "resolved": "https://registry.npmmirror.com/@opentelemetry/api-logs/-/api-logs-0.220.0.tgz", + "integrity": "sha512-CmVa4ImJ+ynfrPMNaAXHET6Bhb44SwzmfyVJFq9ni2jgXJR/l7C6gfVFddNmHP+ZOkP9cf4f9DBe68qVLTHc9w==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/api": "^1.3.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@opentelemetry/core": { + "version": "2.9.0", + "resolved": "https://registry.npmmirror.com/@opentelemetry/core/-/core-2.9.0.tgz", + "integrity": "sha512-m2nckMT80NnmjTYSPjJQObBJ+8dgkoajEOUbznL8AHZ3T3yHRk2P7gI1PhEBc1+lOnrYE9UWrWHqJDsmqjmNbw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/exporter-logs-otlp-http": { + "version": "0.220.0", + "resolved": "https://registry.npmmirror.com/@opentelemetry/exporter-logs-otlp-http/-/exporter-logs-otlp-http-0.220.0.tgz", + "integrity": "sha512-8186thl+pTw64iz/qEEen5oJZoZ/gO73XruChdaGlYdWOdBIQ42r+vHLf6a7vIDqTD4b8ZOoMlyxptanECaI9A==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/api-logs": "0.220.0", + "@opentelemetry/core": "2.9.0", + "@opentelemetry/otlp-exporter-base": "0.220.0", + "@opentelemetry/otlp-transformer": "0.220.0", + "@opentelemetry/sdk-logs": "0.220.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/otlp-exporter-base": { + "version": "0.220.0", + "resolved": "https://registry.npmmirror.com/@opentelemetry/otlp-exporter-base/-/otlp-exporter-base-0.220.0.tgz", + "integrity": "sha512-CXYo8UD5Mn9YbgebO2EL4wejtA+gxLmLiu6HCk2KH2BR7XhFN6/6p1UlCb23DYCjeYkndevLHuejCCN1yx4+OQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.9.0", + "@opentelemetry/otlp-transformer": "0.220.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/otlp-transformer": { + "version": "0.220.0", + "resolved": "https://registry.npmmirror.com/@opentelemetry/otlp-transformer/-/otlp-transformer-0.220.0.tgz", + "integrity": "sha512-lXGrv7KXZ0gNH9SVNUaa6vv6phVYGvJxfXAlMbzbakiXru75f5MZl8Z7oqiMMQD77riVHJCFlQvbZs/VVN2/4A==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/api-logs": "0.220.0", + "@opentelemetry/core": "2.9.0", + "@opentelemetry/resources": "2.9.0", + "@opentelemetry/sdk-logs": "0.220.0", + "@opentelemetry/sdk-metrics": "2.9.0", + "@opentelemetry/sdk-trace": "2.9.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/otlp-transformer/node_modules/@opentelemetry/resources": { + "version": "2.9.0", + "resolved": "https://registry.npmmirror.com/@opentelemetry/resources/-/resources-2.9.0.tgz", + "integrity": "sha512-jyA5MBLQ+Dkl3+JsZkUoUvL7yHvU64kLsvpXKarWm6347Sl1t1bXFTFykUePNpT5WH5pm9a2Qtt03iIYQhZ1Fg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.9.0", + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.3.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/resources": { + "version": "2.10.0", + "resolved": "https://registry.npmmirror.com/@opentelemetry/resources/-/resources-2.10.0.tgz", + "integrity": "sha512-q6MMm2zhggzsHVNbabYwut+a6nbuQQe3URUoxaojM/8K1IBfwwPzvxIjNi2/lI1TFe+fMHMW9MWhrtDLEXEnkA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.10.0", + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.3.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/resources/node_modules/@opentelemetry/core": { + "version": "2.10.0", + "resolved": "https://registry.npmmirror.com/@opentelemetry/core/-/core-2.10.0.tgz", + "integrity": "sha512-/wNZ8twnEQQA4HoHu22+vcsdru6pWPWxW+7w+FlxT6Id7PE/WIbZmVKkte+PF72e0F2dnImFeHD2syyE1Mw6MQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/sdk-logs": { + "version": "0.220.0", + "resolved": "https://registry.npmmirror.com/@opentelemetry/sdk-logs/-/sdk-logs-0.220.0.tgz", + "integrity": "sha512-WywcTkQtv2iNmt+6y5Kcd4rzvx9bLVsBa2Nwcmg01IUaBTkTow3W4d9KE5vNBpEDtb9tp21WcRBY/lANRrApYA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/api-logs": "0.220.0", + "@opentelemetry/core": "2.9.0", + "@opentelemetry/resources": "2.9.0", + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.4.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/sdk-logs/node_modules/@opentelemetry/resources": { + "version": "2.9.0", + "resolved": "https://registry.npmmirror.com/@opentelemetry/resources/-/resources-2.9.0.tgz", + "integrity": "sha512-jyA5MBLQ+Dkl3+JsZkUoUvL7yHvU64kLsvpXKarWm6347Sl1t1bXFTFykUePNpT5WH5pm9a2Qtt03iIYQhZ1Fg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.9.0", + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.3.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/sdk-metrics": { + "version": "2.9.0", + "resolved": "https://registry.npmmirror.com/@opentelemetry/sdk-metrics/-/sdk-metrics-2.9.0.tgz", + "integrity": "sha512-Xx8RGS4H5XEBl01WuCreMIpiah9cCXMbSkeuIePPdD2cUpq/vUzYmj8E/MK1OsbOc93FuAD4jfn2WOacKwLn7Q==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.9.0", + "@opentelemetry/resources": "2.9.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.9.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/sdk-metrics/node_modules/@opentelemetry/resources": { + "version": "2.9.0", + "resolved": "https://registry.npmmirror.com/@opentelemetry/resources/-/resources-2.9.0.tgz", + "integrity": "sha512-jyA5MBLQ+Dkl3+JsZkUoUvL7yHvU64kLsvpXKarWm6347Sl1t1bXFTFykUePNpT5WH5pm9a2Qtt03iIYQhZ1Fg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.9.0", + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.3.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/sdk-trace": { + "version": "2.9.0", + "resolved": "https://registry.npmmirror.com/@opentelemetry/sdk-trace/-/sdk-trace-2.9.0.tgz", + "integrity": "sha512-sGA19HvtrrSKYsseHphluH6j3p6Xa3fqc7c7y8f/7mYWejc1lyDFcpSdD1kYa50HCLUeEo4zA5bW0pniaPszuw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.9.0", + "@opentelemetry/resources": "2.9.0", + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.3.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/sdk-trace/node_modules/@opentelemetry/resources": { + "version": "2.9.0", + "resolved": "https://registry.npmmirror.com/@opentelemetry/resources/-/resources-2.9.0.tgz", + "integrity": "sha512-jyA5MBLQ+Dkl3+JsZkUoUvL7yHvU64kLsvpXKarWm6347Sl1t1bXFTFykUePNpT5WH5pm9a2Qtt03iIYQhZ1Fg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "2.9.0", + "@opentelemetry/semantic-conventions": "^1.29.0" + }, + "engines": { + "node": "^18.19.0 || >=20.6.0" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.3.0 <1.10.0" + } + }, + "node_modules/@opentelemetry/semantic-conventions": { + "version": "1.43.0", + "resolved": "https://registry.npmmirror.com/@opentelemetry/semantic-conventions/-/semantic-conventions-1.43.0.tgz", + "integrity": "sha512-eSYWTm620tTk45EKSedaUL8MFYI8hW164hIXsgIHyxu3VobUB3fFCu5t0hQby6OoWRPsG1KkKUG2M5UadiLiVg==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=14" + } + }, + "node_modules/@protobufjs/aspromise": { + "version": "1.1.2", + "resolved": "https://registry.npmmirror.com/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", + "integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/base64": { + "version": "1.1.2", + "resolved": "https://registry.npmmirror.com/@protobufjs/base64/-/base64-1.1.2.tgz", + "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/codegen": { + "version": "2.0.5", + "resolved": "https://registry.npmmirror.com/@protobufjs/codegen/-/codegen-2.0.5.tgz", + "integrity": "sha512-zgXFLzW3Ap33e6d0Wlj4MGIm6Ce8O89n/apUaGNB/jx+hw+ruWEp7EwGUshdLKVRCxZW12fp9r40E1mQrf/34g==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/eventemitter": { + "version": "1.1.1", + "resolved": "https://registry.npmmirror.com/@protobufjs/eventemitter/-/eventemitter-1.1.1.tgz", + "integrity": "sha512-vW1GmwMZNnL+gMRaovlh9yZX74kc+TTU3FObkkurpMaRtBfLP3ldjS9KQWlwZgraRE0+dheEEoAxdzcJQ8eXZg==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/fetch": { + "version": "1.1.1", + "resolved": "https://registry.npmmirror.com/@protobufjs/fetch/-/fetch-1.1.1.tgz", + "integrity": "sha512-GpptLrs57adMSuHi3VNj0mAF8dwh36LMaYF6XyJ6JMWlVsc+t42tm1HSEDmOs3A8fC9yyeisgLhsTVQokOZ0zw==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@protobufjs/aspromise": "^1.1.1" + } + }, + "node_modules/@protobufjs/float": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/@protobufjs/float/-/float-1.0.2.tgz", + "integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/path": { + "version": "1.1.2", + "resolved": "https://registry.npmmirror.com/@protobufjs/path/-/path-1.1.2.tgz", + "integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/pool": { + "version": "1.1.0", + "resolved": "https://registry.npmmirror.com/@protobufjs/pool/-/pool-1.1.0.tgz", + "integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/utf8": { + "version": "1.1.2", + "resolved": "https://registry.npmmirror.com/@protobufjs/utf8/-/utf8-1.1.2.tgz", + "integrity": "sha512-b1UQwcEZ4yCnMCD8DAL1VlbvBJE9/IX4FTIp7BG1xYpf29SLazLSrqUkj4w7Y5y7cCVP6E5tcqqcI0xemPkHug==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/@smithy/core": { + "version": "3.33.2", + "resolved": "https://registry.npmmirror.com/@smithy/core/-/core-3.33.2.tgz", + "integrity": "sha512-CUGXpnPkVdjUCbix+83sWLW9VFgQOm44MDOx/ihITJMAnOZKvL8YYIc7DR9pP/tZ8CIRvMiON/TucvygqbHO3w==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^4.17.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/credential-provider-imds": { + "version": "4.5.2", + "resolved": "https://registry.npmmirror.com/@smithy/credential-provider-imds/-/credential-provider-imds-4.5.2.tgz", + "integrity": "sha512-A9uSdn72ozbRUSit0eib0TW7nXuNPlaeM0zcGkJ+nE6tFcSDbnmtwoxbTCFBukVQcszDAyvsd7+rTduPTXpygg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@smithy/core": "^3.33.2", + "@smithy/types": "^4.17.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/fetch-http-handler": { + "version": "5.7.2", + "resolved": "https://registry.npmmirror.com/@smithy/fetch-http-handler/-/fetch-http-handler-5.7.2.tgz", + "integrity": "sha512-nZyWTmSpJEXl6VtWVMBJve/7x12DZu6sIX1z1a+ZMaHlQQRs9Zpu6NbTe/gmxYXVRpkjxyDYpZ5gx2IM6f/Wkw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@smithy/core": "^3.33.2", + "@smithy/types": "^4.17.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/is-array-buffer": { + "version": "2.2.0", + "resolved": "https://registry.npmmirror.com/@smithy/is-array-buffer/-/is-array-buffer-2.2.0.tgz", + "integrity": "sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/node-http-handler": { + "version": "4.7.3", + "resolved": "https://registry.npmmirror.com/@smithy/node-http-handler/-/node-http-handler-4.7.3.tgz", + "integrity": "sha512-/jPhevcTFPMVl6KNjbaI47iOg1zxC7IsnX4PQDGVZKMFceOXtB8IEYaB7a9VvkP/3oC60WzTeKocvSI7vLT0vA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@smithy/core": "^3.24.3", + "@smithy/types": "^4.14.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/signature-v4": { + "version": "5.7.2", + "resolved": "https://registry.npmmirror.com/@smithy/signature-v4/-/signature-v4-5.7.2.tgz", + "integrity": "sha512-P7Ki6px6OOrxVtx8K7nLmyx4SlXUW/uTKDdMG44UHefmPGSRMBKe2v+TM59WdLcpUIrBrnuCsIqiM2MbsZjmhw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@smithy/core": "^3.33.2", + "@smithy/types": "^4.17.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/types": { + "version": "4.17.2", + "resolved": "https://registry.npmmirror.com/@smithy/types/-/types-4.17.2.tgz", + "integrity": "sha512-FOKpVZob9MPTn2znRzGrnsMHv7BOsKVw3XiP/cOyYLDVZ9qKp4nifIiSCuUU/fIj5Vu0UOAxCFr+qRAtG0NUkA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/util-buffer-from": { + "version": "2.2.0", + "resolved": "https://registry.npmmirror.com/@smithy/util-buffer-from/-/util-buffer-from-2.2.0.tgz", + "integrity": "sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@smithy/is-array-buffer": "^2.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/util-utf8": { + "version": "2.3.0", + "resolved": "https://registry.npmmirror.com/@smithy/util-utf8/-/util-utf8-2.3.0.tgz", + "integrity": "sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@smithy/util-buffer-from": "^2.2.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@standard-schema/spec": { + "version": "1.1.0", + "resolved": "https://registry.npmmirror.com/@standard-schema/spec/-/spec-1.1.0.tgz", + "integrity": "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==", + "license": "MIT" + }, + "node_modules/@tanstack/virtual-core": { + "version": "3.17.8", + "resolved": "https://registry.npmmirror.com/@tanstack/virtual-core/-/virtual-core-3.17.8.tgz", + "integrity": "sha512-BfEvehNpOT75r5Ksc5xW6NZuXujTfb7nlSEyVu4XHG3gdxNg1KqXruWbDewXOUaUYIo4oRbSfkjIajz4MAT8tA==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + } + }, + "node_modules/@types/node": { + "version": "26.2.0", + "resolved": "https://registry.npmmirror.com/@types/node/-/node-26.2.0.tgz", + "integrity": "sha512-5IviulTZeRNp2vAJ514cc/HUlY5nZ9fCbq9DMyC52BrhFZACo3nI0R7qBxhQmo/d27NFe96ur/b7Wwxklda+kg==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~8.3.0" + } + }, + "node_modules/@types/retry": { + "version": "0.12.0", + "resolved": "https://registry.npmmirror.com/@types/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@vscode/ripgrep": { + "version": "1.18.0", + "resolved": "https://registry.npmmirror.com/@vscode/ripgrep/-/ripgrep-1.18.0.tgz", + "integrity": "sha512-ns5lWe44tSfbTMbVUsyB+I1819PVSw4AdpgK0RNkzfWfwy6+3IUNSxwSrfTno1/oWaS/hERNz+XLWVyga2aJBQ==", + "dev": true, + "license": "MIT", + "optionalDependencies": { + "@vscode/ripgrep-darwin-arm64": "1.18.0", + "@vscode/ripgrep-darwin-x64": "1.18.0", + "@vscode/ripgrep-linux-arm": "1.18.0", + "@vscode/ripgrep-linux-arm64": "1.18.0", + "@vscode/ripgrep-linux-ia32": "1.18.0", + "@vscode/ripgrep-linux-ppc64": "1.18.0", + "@vscode/ripgrep-linux-riscv64": "1.18.0", + "@vscode/ripgrep-linux-s390x": "1.18.0", + "@vscode/ripgrep-linux-x64": "1.18.0", + "@vscode/ripgrep-win32-arm64": "1.18.0", + "@vscode/ripgrep-win32-ia32": "1.18.0", + "@vscode/ripgrep-win32-x64": "1.18.0" + } + }, + "node_modules/@vscode/ripgrep-darwin-arm64": { + "version": "1.18.0", + "resolved": "https://registry.npmmirror.com/@vscode/ripgrep-darwin-arm64/-/ripgrep-darwin-arm64-1.18.0.tgz", + "integrity": "sha512-r3ktHSvbFycQNF6sl7sNDPocpsI7J+mEzh1IaZFkY0spm3k2Z9t8hPAeOK7+p0l6p6/swkQC14XWX01low+94Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@vscode/ripgrep-darwin-x64": { + "version": "1.18.0", + "resolved": "https://registry.npmmirror.com/@vscode/ripgrep-darwin-x64/-/ripgrep-darwin-x64-1.18.0.tgz", + "integrity": "sha512-25b4gWbL138dGuQU244ebCKKc0q05ULBMoFSz9oAEUHNeqK/lOJViDS7DRvbDazzAzSEdan391Znks/R5mkaTQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@vscode/ripgrep-linux-arm": { + "version": "1.18.0", + "resolved": "https://registry.npmmirror.com/@vscode/ripgrep-linux-arm/-/ripgrep-linux-arm-1.18.0.tgz", + "integrity": "sha512-GDAvufNDHu8zqLEmXstalQF0Wh6wQvdsBi/Vg3Yi3CK4a8XoFXqqXVEHEZ9xQz3t0NfoSEc9JbvK9DDS6FxyxQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@vscode/ripgrep-linux-arm64": { + "version": "1.18.0", + "resolved": "https://registry.npmmirror.com/@vscode/ripgrep-linux-arm64/-/ripgrep-linux-arm64-1.18.0.tgz", + "integrity": "sha512-lQ/5zTG++U0E3IhVgS4EPTTn/U4okncaRMM5GOFfOYZywS4nuD31GhkHbNYlDk5CuDC68+hYJ0/eQeyCKJDA+g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@vscode/ripgrep-linux-ia32": { + "version": "1.18.0", + "resolved": "https://registry.npmmirror.com/@vscode/ripgrep-linux-ia32/-/ripgrep-linux-ia32-1.18.0.tgz", + "integrity": "sha512-YWLkSUtFd4Jh5EepIhA9RJSfv3uMAVMo+2rBIGHPBnvgLrZciIs2cDKei1/p6Wc/aCzUoHyMAg2R6tw4ZCBKGg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@vscode/ripgrep-linux-ppc64": { + "version": "1.18.0", + "resolved": "https://registry.npmmirror.com/@vscode/ripgrep-linux-ppc64/-/ripgrep-linux-ppc64-1.18.0.tgz", + "integrity": "sha512-quXVY8fwQ8O/lvU1yrSqSl3jlUzysRSb+AfUfCL/tRtphxsKlFvPAejryZ6vg4Bgvn8XL74xb4qMCDmWgYrT5w==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@vscode/ripgrep-linux-riscv64": { + "version": "1.18.0", + "resolved": "https://registry.npmmirror.com/@vscode/ripgrep-linux-riscv64/-/ripgrep-linux-riscv64-1.18.0.tgz", + "integrity": "sha512-f5kBQBrWfQt8Q7OhSORuNDei5dkYagBj3y4jImSUXGMy8B/Ke7SltSRcUtjPv166FAFfHCAmWuZp3+cWnX2/Vw==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@vscode/ripgrep-linux-s390x": { + "version": "1.18.0", + "resolved": "https://registry.npmmirror.com/@vscode/ripgrep-linux-s390x/-/ripgrep-linux-s390x-1.18.0.tgz", + "integrity": "sha512-rTOcJFGGcl2c07RUOWUo4U1ndnemKhY6A9hnMB18uk7jSgJc0d/QLBGWMWpumdtoJtpizn/wIv5mXIisJukusQ==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@vscode/ripgrep-linux-x64": { + "version": "1.18.0", + "resolved": "https://registry.npmmirror.com/@vscode/ripgrep-linux-x64/-/ripgrep-linux-x64-1.18.0.tgz", + "integrity": "sha512-mQ3bVrUpnD2vs7QT0vX90Lt0cnUq467uFtEktIdsJJmW296RoSULRGqWgzG1AKxyBpNDD6l4ZO4qKf6SgyC23Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@vscode/ripgrep-win32-arm64": { + "version": "1.18.0", + "resolved": "https://registry.npmmirror.com/@vscode/ripgrep-win32-arm64/-/ripgrep-win32-arm64-1.18.0.tgz", + "integrity": "sha512-vfTIjq1OHnzUjxZcHVQAMbnggp8dpGf+0QKFOZHwWPqFwXxQC8eCWM+5NUdoJ6yrElCeMzoUTXoK/LdZaniB+Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@vscode/ripgrep-win32-ia32": { + "version": "1.18.0", + "resolved": "https://registry.npmmirror.com/@vscode/ripgrep-win32-ia32/-/ripgrep-win32-ia32-1.18.0.tgz", + "integrity": "sha512-//rfAE+BOw5AC2EMmepmiE36jUuevtQYNQqqlw1s3m9FlRxjxEut97RkRPHAu9BG4mSojatZx+kXZXNdyI9caQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@vscode/ripgrep-win32-x64": { + "version": "1.18.0", + "resolved": "https://registry.npmmirror.com/@vscode/ripgrep-win32-x64/-/ripgrep-win32-x64-1.18.0.tgz", + "integrity": "sha512-KNPvtElldqILHdnAetujPaowkNbpqJy3ssIGGN6F6Kve9Qi+nNLI2DN01O83JjCEVQbCzl8Ov3QZ9Eov3BR8Dg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/accepts": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/accepts/-/accepts-2.0.0.tgz", + "integrity": "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==", + "dev": true, + "license": "MIT", + "dependencies": { + "mime-types": "^3.0.0", + "negotiator": "^1.0.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/agent-base": { + "version": "7.1.4", + "resolved": "https://registry.npmmirror.com/agent-base/-/agent-base-7.1.4.tgz", + "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14" + } + }, + "node_modules/ajv": { + "version": "8.20.0", + "resolved": "https://registry.npmmirror.com/ajv/-/ajv-8.20.0.tgz", + "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-formats": { + "version": "3.0.1", + "resolved": "https://registry.npmmirror.com/ajv-formats/-/ajv-formats-3.0.1.tgz", + "integrity": "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "devOptional": true, + "license": "Python-2.0" + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmmirror.com/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/bignumber.js": { + "version": "9.3.1", + "resolved": "https://registry.npmmirror.com/bignumber.js/-/bignumber.js-9.3.1.tgz", + "integrity": "sha512-Ko0uX15oIUS7wJ3Rb30Fs6SkVbLmPBAKdlm7q9+ak9bbIeFf0MwuBsQV6z7+X768/cHsfg+WlysDWJcmthjsjQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/body-parser": { + "version": "2.3.0", + "resolved": "https://registry.npmmirror.com/body-parser/-/body-parser-2.3.0.tgz", + "integrity": "sha512-2cGmJupaNgg+QUwVLAucDuWuoMZ6EX9iHDRswZ5lsNYEmwPaRknMPCLZz07yTzVq/83p4o/wzbDZbBrTvGGTIw==", + "dev": true, + "license": "MIT", + "dependencies": { + "bytes": "^3.1.2", + "content-type": "^2.0.0", + "debug": "^4.4.3", + "http-errors": "^2.0.1", + "iconv-lite": "^0.7.2", + "on-finished": "^2.4.1", + "qs": "^6.15.2", + "raw-body": "^3.0.2", + "type-is": "^2.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/body-parser/node_modules/content-type": { + "version": "2.1.0", + "resolved": "https://registry.npmmirror.com/content-type/-/content-type-2.1.0.tgz", + "integrity": "sha512-mj7UPXE0jaqaOsukNZRUEfEi2AcL7C/vwmwcHV0O97eO1E1pxBZuyjlZrx5seTaNBg1U6+o35wpa35Qfcc+7ag==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/bowser": { + "version": "2.14.1", + "resolved": "https://registry.npmmirror.com/bowser/-/bowser-2.14.1.tgz", + "integrity": "sha512-tzPjzCxygAKWFOJP011oxFHs57HzIhOEracIgAePE4pqB3LikALKnSzUyU4MGs9/iCEUuHlAJTjTc5M+u7YEGg==", + "dev": true, + "license": "MIT" + }, + "node_modules/buffer-equal-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/bundle-name": { + "version": "4.1.0", + "resolved": "https://registry.npmmirror.com/bundle-name/-/bundle-name-4.1.0.tgz", + "integrity": "sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "run-applescript": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmmirror.com/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/call-bound": { + "version": "1.0.4", + "resolved": "https://registry.npmmirror.com/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/chokidar": { + "version": "4.0.3", + "resolved": "https://registry.npmmirror.com/chokidar/-/chokidar-4.0.3.tgz", + "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", + "dev": true, + "license": "MIT", + "dependencies": { + "readdirp": "^4.0.1" + }, + "engines": { + "node": ">= 14.16.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/clsx": { + "version": "2.1.1", + "resolved": "https://registry.npmmirror.com/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/commander": { + "version": "15.0.0", + "resolved": "https://registry.npmmirror.com/commander/-/commander-15.0.0.tgz", + "integrity": "sha512-z67u4ZhzCL/Tydu1lJARtEZYWbWaN7oYLHbsuzocr6y4N6WZAagG3RQ4FW61V1/0+jImpj293XfrcYnd1qxtPg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=22.12.0" + } + }, + "node_modules/content-disposition": { + "version": "1.1.0", + "resolved": "https://registry.npmmirror.com/content-disposition/-/content-disposition-1.1.0.tgz", + "integrity": "sha512-5jRCH9Z/+DRP7rkvY83B+yGIGX96OYdJmzngqnw2SBSxqCFPd0w2km3s5iawpGX8krnwSGmF0FW5Nhr0Hfai3g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmmirror.com/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie": { + "version": "0.7.2", + "resolved": "https://registry.npmmirror.com/cookie/-/cookie-0.7.2.tgz", + "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.2.2", + "resolved": "https://registry.npmmirror.com/cookie-signature/-/cookie-signature-1.2.2.tgz", + "integrity": "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.6.0" + } + }, + "node_modules/cors": { + "version": "2.8.6", + "resolved": "https://registry.npmmirror.com/cors/-/cors-2.8.6.tgz", + "integrity": "sha512-tJtZBBHA6vjIAaF6EnIaq6laBBP9aq/Y3ouVJjEfoHbRBcHBAHYcMh/w8LDrk2PvIMMq8gmopa5D4V8RmbrxGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "object-assign": "^4", + "vary": "^1" + }, + "engines": { + "node": ">= 0.10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmmirror.com/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/data-uri-to-buffer": { + "version": "4.0.1", + "resolved": "https://registry.npmmirror.com/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz", + "integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 12" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmmirror.com/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/default-browser": { + "version": "5.5.1", + "resolved": "https://registry.npmmirror.com/default-browser/-/default-browser-5.5.1.tgz", + "integrity": "sha512-m1pAzaJgZ/gssEqlOhJkPJp8Xly7QyW6xcrkUa2KKcDeDSEMP7X8xipU3snUcfisTQx0w1AGae+9UtJSfVnXGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "bundle-name": "^4.1.0", + "default-browser-id": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/default-browser-id": { + "version": "5.0.1", + "resolved": "https://registry.npmmirror.com/default-browser-id/-/default-browser-id-5.0.1.tgz", + "integrity": "sha512-x1VCxdX4t+8wVfd1so/9w+vQ4vx7lKd2Qp5tDRutErwmR85OgmfX7RlLRMWafRMY7hbEiXIbudNrjOAPa/hL8Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/define-lazy-prop": { + "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz", + "integrity": "sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/detect-libc": { + "version": "2.1.2", + "resolved": "https://registry.npmmirror.com/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } + }, + "node_modules/diff": { + "version": "9.0.0", + "resolved": "https://registry.npmmirror.com/diff/-/diff-9.0.0.tgz", + "integrity": "sha512-svtcdpS8CgJyqAjEQIXdb3OjhFVVYjzGAPO8WGCmRbrml64SPw/jJD4GoE98aR7r25A0XcgrK3F02yw9R/vhQw==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/ecdsa-sig-formatter": { + "version": "1.0.11", + "resolved": "https://registry.npmmirror.com/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", + "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "safe-buffer": "^5.0.1" + } + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmmirror.com/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", + "dev": true, + "license": "MIT" + }, + "node_modules/encodeurl": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmmirror.com/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.2", + "resolved": "https://registry.npmmirror.com/es-object-atoms/-/es-object-atoms-1.1.2.tgz", + "integrity": "sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmmirror.com/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", + "dev": true, + "license": "MIT" + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmmirror.com/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/eventsource": { + "version": "3.0.7", + "resolved": "https://registry.npmmirror.com/eventsource/-/eventsource-3.0.7.tgz", + "integrity": "sha512-CRT1WTyuQoD771GW56XEZFQ/ZoSfWid1alKGDYMmkt2yl8UXrVR4pspqWNEcqKvVIzg6PAltWjxcSSPrboA4iA==", + "dev": true, + "license": "MIT", + "dependencies": { + "eventsource-parser": "^3.0.1" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/eventsource-parser": { + "version": "3.1.1", + "resolved": "https://registry.npmmirror.com/eventsource-parser/-/eventsource-parser-3.1.1.tgz", + "integrity": "sha512-EKN1vKAMcZ8MlYMpaNuxN6R9yakzH6uajHcHVTqWJzvu5pWw9DyhbP35HH8MVBQ+dZjAfDxk+A8NiR9KWaXiyQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/express": { + "version": "5.2.1", + "resolved": "https://registry.npmmirror.com/express/-/express-5.2.1.tgz", + "integrity": "sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==", + "dev": true, + "license": "MIT", + "dependencies": { + "accepts": "^2.0.0", + "body-parser": "^2.2.1", + "content-disposition": "^1.0.0", + "content-type": "^1.0.5", + "cookie": "^0.7.1", + "cookie-signature": "^1.2.1", + "debug": "^4.4.0", + "depd": "^2.0.0", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "etag": "^1.8.1", + "finalhandler": "^2.1.0", + "fresh": "^2.0.0", + "http-errors": "^2.0.0", + "merge-descriptors": "^2.0.0", + "mime-types": "^3.0.0", + "on-finished": "^2.4.1", + "once": "^1.4.0", + "parseurl": "^1.3.3", + "proxy-addr": "^2.0.7", + "qs": "^6.14.0", + "range-parser": "^1.2.1", + "router": "^2.2.0", + "send": "^1.1.0", + "serve-static": "^2.2.0", + "statuses": "^2.0.1", + "type-is": "^2.0.1", + "vary": "^1.1.2" + }, + "engines": { + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/express-rate-limit": { + "version": "8.6.2", + "resolved": "https://registry.npmmirror.com/express-rate-limit/-/express-rate-limit-8.6.2.tgz", + "integrity": "sha512-YH4ru+eOJxQABscKFfRCy9R7x9QFGdezclVMwwgFFndzS2Xnm0uo6B0ABZsLhcpeptGv2qvuJVWlQr9gQZoC3A==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.4.3", + "ip-address": "^10.2.0" + }, + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://github.com/sponsors/express-rate-limit" + }, + "peerDependencies": { + "express": ">= 4.11" + } + }, + "node_modules/extend": { + "version": "3.0.2", + "resolved": "https://registry.npmmirror.com/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmmirror.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-uri": { + "version": "3.1.5", + "resolved": "https://registry.npmmirror.com/fast-uri/-/fast-uri-3.1.5.tgz", + "integrity": "sha512-gHwA1O9LDIcKunMKhObS/HimwtehO1nPUECKAu5TpKgaO19fcWEl4bliWe1jWxVFvIXztJjjQ4L8XQ1EU9f7Jw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/fetch-blob": { + "version": "3.2.0", + "resolved": "https://registry.npmmirror.com/fetch-blob/-/fetch-blob-3.2.0.tgz", + "integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/jimmywarting" + }, + { + "type": "paypal", + "url": "https://paypal.me/jimmywarting" + } + ], + "license": "MIT", + "dependencies": { + "node-domexception": "^1.0.0", + "web-streams-polyfill": "^3.0.3" + }, + "engines": { + "node": "^12.20 || >= 14.13" + } + }, + "node_modules/fflate": { + "version": "0.8.3", + "resolved": "https://registry.npmmirror.com/fflate/-/fflate-0.8.3.tgz", + "integrity": "sha512-tbZNuJrLwGUp3zshBtdy4W+ORxZuIh8a5ilyIEQDC5rY1f3U20JMry0Ll3WBzU58EZKsEuJFXhb5gwv8CsPvgA==", + "dev": true, + "license": "MIT" + }, + "node_modules/finalhandler": { + "version": "2.1.1", + "resolved": "https://registry.npmmirror.com/finalhandler/-/finalhandler-2.1.1.tgz", + "integrity": "sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.4.0", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "on-finished": "^2.4.1", + "parseurl": "^1.3.3", + "statuses": "^2.0.1" + }, + "engines": { + "node": ">= 18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/formdata-polyfill": { + "version": "4.0.10", + "resolved": "https://registry.npmmirror.com/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz", + "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fetch-blob": "^3.1.2" + }, + "engines": { + "node": ">=12.20.0" + } + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmmirror.com/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fresh": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/fresh/-/fresh-2.0.0.tgz", + "integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmmirror.com/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gaxios": { + "version": "7.3.1", + "resolved": "https://registry.npmmirror.com/gaxios/-/gaxios-7.3.1.tgz", + "integrity": "sha512-kB3rzJV7d9juLZh8/56QTXCwQfxyhdOMdyYk1HdQKFtF8TJTDTZQJtixWIwXdE9Jji91mC41DUNpjleo4L4eAQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "extend": "^3.0.2", + "https-proxy-agent": "^7.0.1", + "node-fetch": "^3.3.2" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/gcp-metadata": { + "version": "8.1.2", + "resolved": "https://registry.npmmirror.com/gcp-metadata/-/gcp-metadata-8.1.2.tgz", + "integrity": "sha512-zV/5HKTfCeKWnxG0Dmrw51hEWFGfcF2xiXqcA3+J90WDuP0SvoiSO5ORvcBsifmx/FoIjgQN3oNOGaQ5PhLFkg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "gaxios": "^7.0.0", + "google-logging-utils": "^1.0.0", + "json-bigint": "^1.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmmirror.com/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/google-auth-library": { + "version": "10.9.1", + "resolved": "https://registry.npmmirror.com/google-auth-library/-/google-auth-library-10.9.1.tgz", + "integrity": "sha512-i1ydyHrqcIxXkWh/uBmVkzCvIuq5yiK2ATndIe5XxKholrG/MTYP9xGYka4sQhrbIAgGjL2B6NOE7rFaiF3fXw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "base64-js": "^1.3.0", + "ecdsa-sig-formatter": "^1.0.11", + "gaxios": "^7.1.4", + "gcp-metadata": "8.1.2", + "google-logging-utils": "1.1.3", + "jws": "^4.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/google-logging-utils": { + "version": "1.1.3", + "resolved": "https://registry.npmmirror.com/google-logging-utils/-/google-logging-utils-1.1.3.tgz", + "integrity": "sha512-eAmLkjDjAFCVXg7A1unxHsLf961m6y17QFqXqAXGj/gVkKFrEICfStRfwUlGNfeCEjNRa32JEWOUTlYXPyyKvA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=14" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmmirror.com/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmmirror.com/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.4", + "resolved": "https://registry.npmmirror.com/hasown/-/hasown-2.0.4.tgz", + "integrity": "sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==", + "dev": true, + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/hono": { + "version": "4.13.3", + "resolved": "https://registry.npmmirror.com/hono/-/hono-4.13.3.tgz", + "integrity": "sha512-r8AO2mYHoLxSHkgafNeC/BXyb2vWRxD3jem4Ts+ptav8oTG5FIRifAjuJEmZI4bSvvc2ns0GxmIYiZnHqN3mMw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=16.9.0" + } + }, + "node_modules/http-errors": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/http-errors/-/http-errors-2.0.1.tgz", + "integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "depd": "~2.0.0", + "inherits": "~2.0.4", + "setprototypeof": "~1.2.0", + "statuses": "~2.0.2", + "toidentifier": "~1.0.1" + }, + "engines": { + "node": ">= 0.8" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/http-proxy-agent": { + "version": "7.0.2", + "resolved": "https://registry.npmmirror.com/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", + "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/https-proxy-agent": { + "version": "7.0.6", + "resolved": "https://registry.npmmirror.com/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", + "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/iconv-lite": { + "version": "0.7.3", + "resolved": "https://registry.npmmirror.com/iconv-lite/-/iconv-lite-0.7.3.tgz", + "integrity": "sha512-IKXpvIzjnC9XTAUbVBcMfGS0EPaIXtW6v+zr+RRp+hqULEpo0owZax6wyRwPOJbWbzjYspQwusTsfVr0ifh4uQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/immer": { + "version": "10.2.0", + "resolved": "https://registry.npmmirror.com/immer/-/immer-10.2.0.tgz", + "integrity": "sha512-d/+XTN3zfODyjr89gM3mPq1WNX2B8pYsu7eORitdwyA2sBubnTl3laYlBk4sXY5FUa5qTZGBDPJICVbvqzjlbw==", + "dev": true, + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/immer" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmmirror.com/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/ip-address": { + "version": "10.5.0", + "resolved": "https://registry.npmmirror.com/ip-address/-/ip-address-10.5.0.tgz", + "integrity": "sha512-R5SnVLJmgYYvf2F2ZgwSBnelz5G4q5AxIC277GDfUaNbrZKNANcBC7RHqYYePlszf4kBolVkJauG0ZjHHFh55g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 12" + } + }, + "node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmmirror.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/is-docker": { + "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/is-docker/-/is-docker-3.0.0.tgz", + "integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==", + "dev": true, + "license": "MIT", + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-in-ssh": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/is-in-ssh/-/is-in-ssh-1.0.0.tgz", + "integrity": "sha512-jYa6Q9rH90kR1vKB6NM7qqd1mge3Fx4Dhw5TVlK1MUBqhEOuCagrEHMevNuCcbECmXZ0ThXkRm+Ymr51HwEPAw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-inside-container": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/is-inside-container/-/is-inside-container-1.0.0.tgz", + "integrity": "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-docker": "^3.0.0" + }, + "bin": { + "is-inside-container": "cli.js" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-promise": { + "version": "4.0.0", + "resolved": "https://registry.npmmirror.com/is-promise/-/is-promise-4.0.0.tgz", + "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/is-wsl": { + "version": "3.1.1", + "resolved": "https://registry.npmmirror.com/is-wsl/-/is-wsl-3.1.1.tgz", + "integrity": "sha512-e6rvdUCiQCAuumZslxRJWR/Doq4VpPR82kqclvcS0efgt430SlGIk05vdCN58+VrzgtIcfNODjozVielycD4Sw==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-inside-container": "^1.0.0" + }, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, + "node_modules/jose": { + "version": "6.2.9", + "resolved": "https://registry.npmmirror.com/jose/-/jose-6.2.9.tgz", + "integrity": "sha512-XrchZOFZUl/T3vTwRe8XK+cJrGtMF4th1ARnDfwbBXFKThGhlsxEE4Zu03AD/bjJSt/9jT/mxrOCkJWOg77aPA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/panva" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmmirror.com/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/js-yaml": { + "version": "4.3.1", + "resolved": "https://registry.npmmirror.com/js-yaml/-/js-yaml-4.3.1.tgz", + "integrity": "sha512-CY6crGq313MX8GkwvB7tzgp99vjQxY1++5y10/BKN/GUfHqWaOGQMNZkBvqSzsZKWk/ijwHlWzzkLulsGHhjWQ==", + "devOptional": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/puzrin" + }, + { + "type": "github", + "url": "https://github.com/sponsors/nodeca" + } + ], + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/json-bigint": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/json-bigint/-/json-bigint-1.0.0.tgz", + "integrity": "sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "bignumber.js": "^9.0.0" + } + }, + "node_modules/json-schema-to-ts": { + "version": "3.1.1", + "resolved": "https://registry.npmmirror.com/json-schema-to-ts/-/json-schema-to-ts-3.1.1.tgz", + "integrity": "sha512-+DWg8jCJG2TEnpy7kOm/7/AxaYoaRbjVB4LFZLySZlWn8exGs3A4OLJR966cVvU26N7X9TWxl+Jsw7dzAqKT6g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.18.3", + "ts-algebra": "^2.0.0" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-schema-typed": { + "version": "8.0.2", + "resolved": "https://registry.npmmirror.com/json-schema-typed/-/json-schema-typed-8.0.2.tgz", + "integrity": "sha512-fQhoXdcvc3V28x7C7BMs4P5+kNlgUURe2jmUT1T//oBRMDrqy1QPelJimwZGo7Hg9VPV3EQV5Bnq4hbFy2vetA==", + "dev": true, + "license": "BSD-2-Clause" + }, + "node_modules/jwa": { + "version": "2.0.1", + "resolved": "https://registry.npmmirror.com/jwa/-/jwa-2.0.1.tgz", + "integrity": "sha512-hRF04fqJIP8Abbkq5NKGN0Bbr3JxlQ+qhZufXVr0DvujKy93ZCbXZMHDL4EOtodSbCWxOqR8MS1tXA5hwqCXDg==", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer-equal-constant-time": "^1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/jws": { + "version": "4.0.1", + "resolved": "https://registry.npmmirror.com/jws/-/jws-4.0.1.tgz", + "integrity": "sha512-EKI/M/yqPncGUUh44xz0PxSidXFr/+r0pA70+gIYhjv+et7yxM+s29Y+VGDkovRofQem0fs7Uvf4+YmAdyRduA==", + "dev": true, + "license": "MIT", + "dependencies": { + "jwa": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/koffi": { + "version": "3.1.5", + "resolved": "https://registry.npmmirror.com/koffi/-/koffi-3.1.5.tgz", + "integrity": "sha512-XVwwrxg0Ca6IEUQF4YtGIU4XN0LSselFYpYvgfhh8wafCunhEEx5hPr7LZhp5QyeFA/LcRsKHTqncCdjWjWAlg==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "funding": { + "url": "https://liberapay.com/Koromix" + }, + "optionalDependencies": { + "@koromix/koffi-darwin-arm64": "3.1.5", + "@koromix/koffi-darwin-x64": "3.1.5", + "@koromix/koffi-freebsd-arm64": "3.1.5", + "@koromix/koffi-freebsd-ia32": "3.1.5", + "@koromix/koffi-freebsd-x64": "3.1.5", + "@koromix/koffi-linux-arm64": "3.1.5", + "@koromix/koffi-linux-ia32": "3.1.5", + "@koromix/koffi-linux-loong64": "3.1.5", + "@koromix/koffi-linux-riscv64": "3.1.5", + "@koromix/koffi-linux-x64": "3.1.5", + "@koromix/koffi-openbsd-ia32": "3.1.5", + "@koromix/koffi-openbsd-x64": "3.1.5", + "@koromix/koffi-win32-arm64": "3.1.5", + "@koromix/koffi-win32-ia32": "3.1.5", + "@koromix/koffi-win32-x64": "3.1.5" + } + }, + "node_modules/long": { + "version": "5.3.2", + "resolved": "https://registry.npmmirror.com/long/-/long-5.3.2.tgz", + "integrity": "sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmmirror.com/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmmirror.com/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/media-typer": { + "version": "1.1.1", + "resolved": "https://registry.npmmirror.com/media-typer/-/media-typer-1.1.1.tgz", + "integrity": "sha512-yz3xRaG20c6/BOzvYoDaGtPmGscs7YivItZEEqe6GbwNfHuxu9YNmvnEkMzKldAGY4/80pRcQRZSEnhquk9XuQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/merge-descriptors": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/merge-descriptors/-/merge-descriptors-2.0.0.tgz", + "integrity": "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mime-db": { + "version": "1.54.0", + "resolved": "https://registry.npmmirror.com/mime-db/-/mime-db-1.54.0.tgz", + "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "3.0.2", + "resolved": "https://registry.npmmirror.com/mime-types/-/mime-types-3.0.2.tgz", + "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "mime-db": "^1.54.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmmirror.com/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/negotiator": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/negotiator/-/negotiator-1.0.0.tgz", + "integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/node-addon-api": { + "version": "7.1.1", + "resolved": "https://registry.npmmirror.com/node-addon-api/-/node-addon-api-7.1.1.tgz", + "integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/node-addon-native-custom-loader": { + "version": "0.1.5", + "resolved": "https://registry.npmmirror.com/node-addon-native-custom-loader/-/node-addon-native-custom-loader-0.1.5.tgz", + "integrity": "sha512-rL0XXRytayIChYf1xaG9/1NzGBRTyFkQTIpn+MDz/hpr0PZw1a9PZIoH9HlYfagNawhXU+jfN650EvoSIvR7Vw==", + "devOptional": true, + "license": "MIT", + "engines": { + "node": ">=20" + } + }, + "node_modules/node-addon-require-builtin": { + "version": "0.1.5", + "resolved": "https://registry.npmmirror.com/node-addon-require-builtin/-/node-addon-require-builtin-0.1.5.tgz", + "integrity": "sha512-isaquiStlp7qdFpaffy+2ssJPUR/kLPRE5gqfeWbb0Ahph9H7O3BOFwThqkVaTrxfpnjrQauxlOEgvzD+snhUg==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "node-addon-native-custom-loader": "0.1.5" + }, + "engines": { + "node": ">=20" + }, + "optionalDependencies": { + "node-addon-require-builtin-darwin-arm64": "0.1.5", + "node-addon-require-builtin-darwin-x64": "0.1.5", + "node-addon-require-builtin-linux-arm64-gnu": "0.1.5", + "node-addon-require-builtin-linux-x64-gnu": "0.1.5", + "node-addon-require-builtin-win32-arm64-msvc": "0.1.5", + "node-addon-require-builtin-win32-ia32-msvc": "0.1.5", + "node-addon-require-builtin-win32-x64-msvc": "0.1.5" + } + }, + "node_modules/node-addon-require-builtin-darwin-arm64": { + "version": "0.1.5", + "resolved": "https://registry.npmmirror.com/node-addon-require-builtin-darwin-arm64/-/node-addon-require-builtin-darwin-arm64-0.1.5.tgz", + "integrity": "sha512-MZ5RyGhuU7DTbwuNpOQW81/ep8n5Yd5YlZa6dWiEfJEh+01Dl4cCKGmMCWNgb0VtqAImRtAOtmZIPtwngiemKQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "dependencies": { + "node-addon-native-custom-loader": "0.1.5" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/node-addon-require-builtin-darwin-x64": { + "version": "0.1.5", + "resolved": "https://registry.npmmirror.com/node-addon-require-builtin-darwin-x64/-/node-addon-require-builtin-darwin-x64-0.1.5.tgz", + "integrity": "sha512-wdCSPn49AdNZ2EXHQqswiXk1cROFe9zSRaAX8PwQLxmjdLt+xZF7vZP6VlqgXm+VAOHv98q8kp9m7mO9jY3OgQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "dependencies": { + "node-addon-native-custom-loader": "0.1.5" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/node-addon-require-builtin-linux-arm64-gnu": { + "version": "0.1.5", + "resolved": "https://registry.npmmirror.com/node-addon-require-builtin-linux-arm64-gnu/-/node-addon-require-builtin-linux-arm64-gnu-0.1.5.tgz", + "integrity": "sha512-hCqzKpQiknDDv6rUdZqrxCBXROg/uUruO0geUuZsdM9M/Lds45gSb4bDE958HlPaCvrDyR0wTHl3II8A7yQeew==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "dependencies": { + "node-addon-native-custom-loader": "0.1.5" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/node-addon-require-builtin-linux-x64-gnu": { + "version": "0.1.5", + "resolved": "https://registry.npmmirror.com/node-addon-require-builtin-linux-x64-gnu/-/node-addon-require-builtin-linux-x64-gnu-0.1.5.tgz", + "integrity": "sha512-lgP+ruwWXbcXDslhp5uIc+dFgzITEGPZ4E50WdHGt/OzcoVhN6y5z72pRRvxy8DE661//QxqmCLe72rS3SVg+w==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "dependencies": { + "node-addon-native-custom-loader": "0.1.5" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/node-addon-require-builtin-win32-arm64-msvc": { + "version": "0.1.5", + "resolved": "https://registry.npmmirror.com/node-addon-require-builtin-win32-arm64-msvc/-/node-addon-require-builtin-win32-arm64-msvc-0.1.5.tgz", + "integrity": "sha512-KEO2eWS4lvZg6JmPPz04OdI4Ojrc7YzOs++4r6VnvwsqYN2r6mjGSGpouQkk8J2eLXBzC7X/D9wYTbUuQS8u1Q==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "dependencies": { + "node-addon-native-custom-loader": "0.1.5" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/node-addon-require-builtin-win32-ia32-msvc": { + "version": "0.1.5", + "resolved": "https://registry.npmmirror.com/node-addon-require-builtin-win32-ia32-msvc/-/node-addon-require-builtin-win32-ia32-msvc-0.1.5.tgz", + "integrity": "sha512-iSC988EqZm5XbKWp/giW6K6EBRTrHt/YQbAkKsZLglt7PplmvvrZ7C3tUsyh1wVxUTYAaxFdE2xbqSdpw0rb6g==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "dependencies": { + "node-addon-native-custom-loader": "0.1.5" + }, + "engines": { + "node": ">=20 <23" + } + }, + "node_modules/node-addon-require-builtin-win32-x64-msvc": { + "version": "0.1.5", + "resolved": "https://registry.npmmirror.com/node-addon-require-builtin-win32-x64-msvc/-/node-addon-require-builtin-win32-x64-msvc-0.1.5.tgz", + "integrity": "sha512-pjuco/ESU3ChIp7WwacWfY2ENu2K5rGAgqjcXedoiFcTrjTf5Ln/miKSuNfE6IiuJ7tfMTJH6VH5hq+C1Y8JMQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "dependencies": { + "node-addon-native-custom-loader": "0.1.5" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/node-domexception": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/node-domexception/-/node-domexception-1.0.0.tgz", + "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==", + "deprecated": "Use your platform's native DOMException instead", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/jimmywarting" + }, + { + "type": "github", + "url": "https://paypal.me/jimmywarting" + } + ], + "license": "MIT", + "engines": { + "node": ">=10.5.0" + } + }, + "node_modules/node-fetch": { + "version": "3.3.2", + "resolved": "https://registry.npmmirror.com/node-fetch/-/node-fetch-3.3.2.tgz", + "integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==", + "dev": true, + "license": "MIT", + "dependencies": { + "data-uri-to-buffer": "^4.0.0", + "fetch-blob": "^3.1.4", + "formdata-polyfill": "^4.0.10" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/node-fetch" + } + }, + "node_modules/node-pty": { + "version": "1.2.0-beta.15", + "resolved": "https://registry.npmmirror.com/node-pty/-/node-pty-1.2.0-beta.15.tgz", + "integrity": "sha512-vORSzHXi4Ofl7HemVWpuudLqCPdaQb4LfpRCUpE5HPxhp4JYscl8zZwxh11p26v2wvW24WMwnMfLjhRLixrfxA==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "node-addon-api": "^7.1.0" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmmirror.com/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.13.4", + "resolved": "https://registry.npmmirror.com/object-inspect/-/object-inspect-1.13.4.tgz", + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmmirror.com/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "dev": true, + "license": "MIT", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmmirror.com/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/open": { + "version": "11.0.1", + "resolved": "https://registry.npmmirror.com/open/-/open-11.0.1.tgz", + "integrity": "sha512-NzwMUB6C1D0+Kd+9iMS/H4k+Ck3cTX6Ckyfr/gAGlmvSE1LUQZnEZvWBi4PYmMwH/S5SMeTXnE+9uAz8uF+pWw==", + "dev": true, + "license": "MIT", + "dependencies": { + "default-browser": "^5.4.0", + "define-lazy-prop": "^3.0.0", + "is-in-ssh": "^1.0.0", + "is-inside-container": "^1.0.0", + "powershell-utils": "^0.2.0", + "wsl-utils": "^1.0.0" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/openai": { + "version": "6.26.0", + "resolved": "https://registry.npmmirror.com/openai/-/openai-6.26.0.tgz", + "integrity": "sha512-zd23dbWTjiJ6sSAX6s0HrCZi41JwTA1bQVs0wLQPZ2/5o2gxOJA5wh7yOAUgwYybfhDXyhwlpeQf7Mlgx8EOCA==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "openai": "bin/cli" + }, + "peerDependencies": { + "ws": "^8.18.0", + "zod": "^3.25 || ^4.0" + }, + "peerDependenciesMeta": { + "ws": { + "optional": true + }, + "zod": { + "optional": true + } + } + }, + "node_modules/p-retry": { + "version": "4.6.2", + "resolved": "https://registry.npmmirror.com/p-retry/-/p-retry-4.6.2.tgz", + "integrity": "sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/retry": "0.12.0", + "retry": "^0.13.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmmirror.com/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/partial-json": { + "version": "0.1.7", + "resolved": "https://registry.npmmirror.com/partial-json/-/partial-json-0.1.7.tgz", + "integrity": "sha512-Njv/59hHaokb/hRUjce3Hdv12wd60MtM9Z5Olmn+nehe0QDAsRtRbJPvJ0Z91TusF0SuZRIvnM+S4l6EIP8leA==", + "dev": true, + "license": "MIT" + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmmirror.com/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-to-regexp": { + "version": "8.4.2", + "resolved": "https://registry.npmmirror.com/path-to-regexp/-/path-to-regexp-8.4.2.tgz", + "integrity": "sha512-qRcuIdP69NPm4qbACK+aDogI5CBDMi1jKe0ry5rSQJz8JVLsC7jV8XpiJjGRLLol3N+R5ihGYcrPLTno6pAdBA==", + "dev": true, + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmmirror.com/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "4.0.5", + "resolved": "https://registry.npmmirror.com/picomatch/-/picomatch-4.0.5.tgz", + "integrity": "sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pkce-challenge": { + "version": "5.0.1", + "resolved": "https://registry.npmmirror.com/pkce-challenge/-/pkce-challenge-5.0.1.tgz", + "integrity": "sha512-wQ0b/W4Fr01qtpHlqSqspcj3EhBvimsdh0KlHhH8HRZnMsEa0ea2fTULOXOS9ccQr3om+GcGRk4e+isrZWV8qQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/powershell-utils": { + "version": "0.2.0", + "resolved": "https://registry.npmmirror.com/powershell-utils/-/powershell-utils-0.2.0.tgz", + "integrity": "sha512-ZlsFlG7MtSFCoc5xreOvBAozCJ6Pf06opgJjh9ONEv418xpZSAzNjstD36C6+JwOnfSqOW/9uDkqKjezTdxZhw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/protobufjs": { + "version": "7.6.5", + "resolved": "https://registry.npmmirror.com/protobufjs/-/protobufjs-7.6.5.tgz", + "integrity": "sha512-/FPD0nUc9jH6rfFjji9IBqOz4pcSE3CsT1m7Ep6Mdb0LxSUMj8hgl6GomOvZzpNpAqqGaXA0P3VSrZLFzIhQrw==", + "dev": true, + "hasInstallScript": true, + "license": "BSD-3-Clause", + "dependencies": { + "@protobufjs/aspromise": "^1.1.2", + "@protobufjs/base64": "^1.1.2", + "@protobufjs/codegen": "^2.0.5", + "@protobufjs/eventemitter": "^1.1.1", + "@protobufjs/fetch": "^1.1.1", + "@protobufjs/float": "^1.0.2", + "@protobufjs/path": "^1.1.2", + "@protobufjs/pool": "^1.1.0", + "@protobufjs/utf8": "^1.1.1", + "@types/node": ">=13.7.0", + "long": "^5.3.2" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmmirror.com/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "dev": true, + "license": "MIT", + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/qs": { + "version": "6.15.3", + "resolved": "https://registry.npmmirror.com/qs/-/qs-6.15.3.tgz", + "integrity": "sha512-O9gl3zCl5h5blw1KGUzQKhA5oUXSl8rwUIM5o0S3nCXMliSvy5Dzx7/DJcI+SwgICv+IneSZwhBh1oSyEHA71A==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "es-define-property": "^1.0.1", + "side-channel": "^1.1.1" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/range-parser": { + "version": "1.3.0", + "resolved": "https://registry.npmmirror.com/range-parser/-/range-parser-1.3.0.tgz", + "integrity": "sha512-hek2mFQpPuI4E1BBKrSto+BU3e3x4xuarsbiwr3+lf7p44juvFMV0XFWQAP3xUyqXA4RrXLIoaSUGbSt056ZMw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/raw-body": { + "version": "3.0.2", + "resolved": "https://registry.npmmirror.com/raw-body/-/raw-body-3.0.2.tgz", + "integrity": "sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==", + "dev": true, + "license": "MIT", + "dependencies": { + "bytes": "~3.1.2", + "http-errors": "~2.0.1", + "iconv-lite": "~0.7.0", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/react": { + "version": "18.3.1", + "resolved": "https://registry.npmmirror.com/react/-/react-18.3.1.tgz", + "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "loose-envify": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/readdirp": { + "version": "4.1.2", + "resolved": "https://registry.npmmirror.com/readdirp/-/readdirp-4.1.2.tgz", + "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14.18.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmmirror.com/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/retry": { + "version": "0.13.1", + "resolved": "https://registry.npmmirror.com/retry/-/retry-0.13.1.tgz", + "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/router": { + "version": "2.2.0", + "resolved": "https://registry.npmmirror.com/router/-/router-2.2.0.tgz", + "integrity": "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.4.0", + "depd": "^2.0.0", + "is-promise": "^4.0.0", + "parseurl": "^1.3.3", + "path-to-regexp": "^8.0.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/run-applescript": { + "version": "7.1.0", + "resolved": "https://registry.npmmirror.com/run-applescript/-/run-applescript-7.1.0.tgz", + "integrity": "sha512-DPe5pVFaAsinSaV6QjQ6gdiedWDcRCbUuiQfQa2wmWV7+xC9bGulGI8+TdRmoFkAPaBXk8CrAbnlY2ISniJ47Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmmirror.com/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmmirror.com/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true, + "license": "MIT" + }, + "node_modules/scheduler": { + "version": "0.27.0", + "resolved": "https://registry.npmmirror.com/scheduler/-/scheduler-0.27.0.tgz", + "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/semver": { + "version": "7.8.5", + "resolved": "https://registry.npmmirror.com/semver/-/semver-7.8.5.tgz", + "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/send": { + "version": "1.2.1", + "resolved": "https://registry.npmmirror.com/send/-/send-1.2.1.tgz", + "integrity": "sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.4.3", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "etag": "^1.8.1", + "fresh": "^2.0.0", + "http-errors": "^2.0.1", + "mime-types": "^3.0.2", + "ms": "^2.1.3", + "on-finished": "^2.4.1", + "range-parser": "^1.2.1", + "statuses": "^2.0.2" + }, + "engines": { + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/serve-static": { + "version": "2.2.1", + "resolved": "https://registry.npmmirror.com/serve-static/-/serve-static-2.2.1.tgz", + "integrity": "sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw==", + "dev": true, + "license": "MIT", + "dependencies": { + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "parseurl": "^1.3.3", + "send": "^1.2.0" + }, + "engines": { + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmmirror.com/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "dev": true, + "license": "ISC" + }, + "node_modules/sharp": { + "version": "0.35.3", + "resolved": "https://registry.npmmirror.com/sharp/-/sharp-0.35.3.tgz", + "integrity": "sha512-ej0zVHuZGHCiABXcNxeYhpRnPNPAcvbG8RMdBAhDAxLKkCRVSpK3Iyu7qbqw3JMzoj0REeM6f3tJLtVwl0023Q==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@img/colour": "^1.1.0", + "detect-libc": "^2.1.2", + "semver": "^7.8.5" + }, + "engines": { + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-darwin-arm64": "0.35.3", + "@img/sharp-darwin-x64": "0.35.3", + "@img/sharp-freebsd-wasm32": "0.35.3", + "@img/sharp-libvips-darwin-arm64": "1.3.2", + "@img/sharp-libvips-darwin-x64": "1.3.2", + "@img/sharp-libvips-linux-arm": "1.3.2", + "@img/sharp-libvips-linux-arm64": "1.3.2", + "@img/sharp-libvips-linux-ppc64": "1.3.2", + "@img/sharp-libvips-linux-riscv64": "1.3.2", + "@img/sharp-libvips-linux-s390x": "1.3.2", + "@img/sharp-libvips-linux-x64": "1.3.2", + "@img/sharp-libvips-linuxmusl-arm64": "1.3.2", + "@img/sharp-libvips-linuxmusl-x64": "1.3.2", + "@img/sharp-linux-arm": "0.35.3", + "@img/sharp-linux-arm64": "0.35.3", + "@img/sharp-linux-ppc64": "0.35.3", + "@img/sharp-linux-riscv64": "0.35.3", + "@img/sharp-linux-s390x": "0.35.3", + "@img/sharp-linux-x64": "0.35.3", + "@img/sharp-linuxmusl-arm64": "0.35.3", + "@img/sharp-linuxmusl-x64": "0.35.3", + "@img/sharp-webcontainers-wasm32": "0.35.3", + "@img/sharp-win32-arm64": "0.35.3", + "@img/sharp-win32-ia32": "0.35.3", + "@img/sharp-win32-x64": "0.35.3" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/side-channel": { + "version": "1.1.1", + "resolved": "https://registry.npmmirror.com/side-channel/-/side-channel-1.1.1.tgz", + "integrity": "sha512-6x6dK6zJdpTzF4sQeNYxwtvBzf6Eg4GtlesS94HOvTudUeyK2WXAaIfmDgsyslYrRBeFIlsi54AYsFGUuhmvrQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.4", + "side-channel-list": "^1.0.1", + "side-channel-map": "^1.0.1", + "side-channel-weakmap": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-list": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/side-channel-list/-/side-channel-list-1.0.1.tgz", + "integrity": "sha512-mjn/0bi/oUURjc5Xl7IaWi/OJJJumuoJFQJfDDyO46+hBWsfaVM65TBHq2eoZBhzl9EchxOijpkbRC8SVBQU0w==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-map": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/side-channel-map/-/side-channel-map-1.0.1.tgz", + "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-weakmap": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", + "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3", + "side-channel-map": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/statuses": { + "version": "2.0.2", + "resolved": "https://registry.npmmirror.com/statuses/-/statuses-2.0.2.tgz", + "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/ts-algebra": { + "version": "2.0.0", + "resolved": "https://registry.npmmirror.com/ts-algebra/-/ts-algebra-2.0.0.tgz", + "integrity": "sha512-FPAhNPFMrkwz76P7cdjdmiShwMynZYN6SgOujD1urY4oNm80Ou9oMdmbR45LotcKOXoy7wSmHkRFE6Mxbrhefw==", + "dev": true, + "license": "MIT" + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmmirror.com/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "dev": true, + "license": "0BSD" + }, + "node_modules/turndown": { + "version": "7.2.4", + "resolved": "https://registry.npmmirror.com/turndown/-/turndown-7.2.4.tgz", + "integrity": "sha512-I8yFsfRzmzK0WV1pNNOA4A7y4RDfFxPRxb3t+e3ui14qSGOxGtiSP6GjeX+Y6CHb7HYaFj7ECUD7VE5kQMZWGQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@mixmark-io/domino": "^2.2.0" + }, + "engines": { + "node": ">=18", + "npm": ">=9" + } + }, + "node_modules/type-is": { + "version": "2.1.0", + "resolved": "https://registry.npmmirror.com/type-is/-/type-is-2.1.0.tgz", + "integrity": "sha512-faYHw0anBbc/kWF3zFTEnxSFOAGUX9GFbOBthvDdLsIlEoWOFOtS0zgCiQYwIskL9iGXZL3kAXD8OoZ4GmMATA==", + "dev": true, + "license": "MIT", + "dependencies": { + "content-type": "^2.0.0", + "media-typer": "^1.1.0", + "mime-types": "^3.0.0" + }, + "engines": { + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/type-is/node_modules/content-type": { + "version": "2.1.0", + "resolved": "https://registry.npmmirror.com/content-type/-/content-type-2.1.0.tgz", + "integrity": "sha512-mj7UPXE0jaqaOsukNZRUEfEi2AcL7C/vwmwcHV0O97eO1E1pxBZuyjlZrx5seTaNBg1U6+o35wpa35Qfcc+7ag==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/typebox": { + "version": "1.1.38", + "resolved": "https://registry.npmmirror.com/typebox/-/typebox-1.1.38.tgz", + "integrity": "sha512-pZ0aQPmMmXoUvSbeuWf/Hzsc+avNw/Zd6VeE8CFgkVGWyuHPJvqeJJDeJqLve+K70LvjYIoleGcoJHPT17cWoA==", + "dev": true, + "license": "MIT" + }, + "node_modules/undici-types": { + "version": "8.3.0", + "resolved": "https://registry.npmmirror.com/undici-types/-/undici-types-8.3.0.tgz", + "integrity": "sha512-j375ScV60dom+YkPFIfTLcOiPxkN/buHz5GobjLhixFuANaNs3C9l4GmrWqejgXWJ7BbJcFYpTEUkS1Ge8bpZQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/use-sync-external-store": { + "version": "1.2.0", + "resolved": "https://registry.npmmirror.com/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz", + "integrity": "sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmmirror.com/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/web-streams-polyfill": { + "version": "3.3.3", + "resolved": "https://registry.npmmirror.com/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz", + "integrity": "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmmirror.com/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/ws": { + "version": "8.21.3", + "resolved": "https://registry.npmmirror.com/ws/-/ws-8.21.3.tgz", + "integrity": "sha512-201TZ/kPWxoPr/OKWjquZR1SWKXcvxdH+e1xrx89b3YbmzLMFCLfnaG1HFIgWzJOEWZ7MvpK++odZufgYR50Rw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/wsl-utils": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/wsl-utils/-/wsl-utils-1.0.0.tgz", + "integrity": "sha512-Hl0ZOAs672vg+06kfujwRhoS6/jehvULrlFkuF2dRu6pHgA8U06h3xqNIqNNU1LTXPcedxByAR4GS6pwQK0mgA==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-wsl": "^3.1.0", + "powershell-utils": "^0.1.0" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/wsl-utils/node_modules/powershell-utils": { + "version": "0.1.0", + "resolved": "https://registry.npmmirror.com/powershell-utils/-/powershell-utils-0.1.0.tgz", + "integrity": "sha512-dM0jVuXJPsDN6DvRpea484tCUaMiXWjuCn++HGTqUWzGDjv5tZkEZldAJ/UMlqRYGFrD/etByo4/xOuC/snX2A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/yaml": { + "version": "2.9.0", + "resolved": "https://registry.npmmirror.com/yaml/-/yaml-2.9.0.tgz", + "integrity": "sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA==", + "dev": true, + "license": "ISC", + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14.6" + }, + "funding": { + "url": "https://github.com/sponsors/eemeli" + } + }, + "node_modules/zod": { + "version": "4.4.3", + "resolved": "https://registry.npmmirror.com/zod/-/zod-4.4.3.tgz", + "integrity": "sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + }, + "node_modules/zod-to-json-schema": { + "version": "3.25.2", + "resolved": "https://registry.npmmirror.com/zod-to-json-schema/-/zod-to-json-schema-3.25.2.tgz", + "integrity": "sha512-O/PgfnpT1xKSDeQYSCfRI5Gy3hPf91mKVDuYLUHZJMiDFptvP41MSnWofm8dnCm0256ZNfZIM7DSzuSMAFnjHA==", + "dev": true, + "license": "ISC", + "peerDependencies": { + "zod": "^3.25.28 || ^4" + } + }, + "node_modules/zustand": { + "version": "4.4.7", + "resolved": "https://registry.npmmirror.com/zustand/-/zustand-4.4.7.tgz", + "integrity": "sha512-QFJWJMdlETcI69paJwhSMJz7PPWjVP8Sjhclxmxmxv/RYI7ZOvR5BHX+ktH0we9gTWQMxcne8q1OY8xxz604gw==", + "dev": true, + "license": "MIT", + "dependencies": { + "use-sync-external-store": "1.2.0" + }, + "engines": { + "node": ">=12.7.0" + }, + "peerDependencies": { + "@types/react": ">=16.8", + "immer": ">=9.0", + "react": ">=16.8" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "immer": { + "optional": true + }, + "react": { + "optional": true + } + } + } + } +} diff --git a/.release/dshx-linux-x64/package.json b/.release/dshx-linux-x64/package.json new file mode 100644 index 00000000..2b5da691 --- /dev/null +++ b/.release/dshx-linux-x64/package.json @@ -0,0 +1,62 @@ +{ + "name": "@code-new-bie/dshx-tui", + "version": "0.0.0-m1", + "description": "Codex-grade TUI surface bundle for official DeepSeek Harness", + "type": "module", + "license": "Apache-2.0", + "os": [ + "linux" + ], + "cpu": [ + "x64" + ], + "engines": { + "node": "^22.19.0 || >=24.0.0" + }, + "bin": { + "dshx": "./bin/dshx.mjs" + }, + "exports": { + ".": "./src/dsh/index.mjs", + "./presentation": "./src/dsh/presentation-plugin.mjs", + "./startup": "./src/dsh/startup-plugin.mjs", + "./cordis.patch.yml": "./cordis.patch.yml", + "./package.json": "./package.json" + }, + "dsh": { + "bundle": { + "patch": "./cordis.patch.yml" + } + }, + "peerDependencies": { + "@deepseek-ai/dsh": "0.1.0-rc.8", + "@deepseek-ai/dsh-agent": "0.1.0-rc.8", + "@deepseek-ai/dsh-app-boot": "0.1.0-rc.8", + "@deepseek-ai/dsh-host-apiproxy": "0.1.0-rc.8", + "@deepseek-ai/dsh-launch-environment": "0.1.0-rc.8", + "@deepseek-ai/dsh-llm": "0.1.0-rc.8", + "@deepseek-ai/dsh-session": "0.1.0-rc.8" + }, + "dependencies": { + "@deepseek-ai/dsh-cmdline": "0.1.0-rc.8", + "@deepseek-ai/schemastery": "3.18.1" + }, + "repository": { + "type": "git", + "url": "https://github.com/code-new-bie/dsh-codex.git" + }, + "files": [ + "bin/dshx.mjs", + "src/cli", + "src/dsh", + "src/tui-protocol", + "src/protocol", + "cordis.patch.yml", + "dist/bin", + "upstream", + "README.md", + "LICENSE", + "NOTICE", + "npm-shrinkwrap.json" + ] +} diff --git a/.release/dshx-linux-x64/src/cli/arguments.mjs b/.release/dshx-linux-x64/src/cli/arguments.mjs new file mode 100644 index 00000000..811ae5d0 --- /dev/null +++ b/.release/dshx-linux-x64/src/cli/arguments.mjs @@ -0,0 +1,29 @@ +export function parseLaunchArgs(args) { + if (args[0] !== 'resume') return { tuiArgs: args, resumeEnv: {} }; + const rest = args.slice(1); + if (rest.length === 0) return { tuiArgs: [], resumeEnv: { DSHX_RESUME_MODE: 'picker' } }; + if (rest.length === 1 && rest[0] === '--last') { + return { tuiArgs: [], resumeEnv: { DSHX_RESUME_MODE: 'last' } }; + } + if (rest.length === 1 && !rest[0].startsWith('-')) { + return { + tuiArgs: [], + resumeEnv: { DSHX_RESUME_MODE: 'id', DSHX_RESUME_SESSION_ID: rest[0] } + }; + } + throw new Error('Usage: dshx resume [--last|]'); +} + +export function parseCliInvocation(args) { + if (args.length === 1 && (args[0] === '--help' || args[0] === '-h')) { + return { kind: 'help' }; + } + if (args.length === 1 && (args[0] === '--version' || args[0] === '-V')) { + return { kind: 'version' }; + } + if (args[0] === 'doctor') { + if (args.length !== 1) throw new Error('Usage: dshx doctor'); + return { kind: 'doctor' }; + } + return { kind: 'launch', ...parseLaunchArgs(args) }; +} diff --git a/.release/dshx-linux-x64/src/cli/runtime.mjs b/.release/dshx-linux-x64/src/cli/runtime.mjs new file mode 100644 index 00000000..e590597f --- /dev/null +++ b/.release/dshx-linux-x64/src/cli/runtime.mjs @@ -0,0 +1,27 @@ +export const DSHX_NODE_ENGINE = '^22.19.0 || >=24.0.0'; +export const DSHX_RELEASE_NODE_MAJOR = 24; +// `dshx doctor` deliberately boots the full official DSH composition, including +// profile watchers. A fresh Windows install can incur one-time module/native +// initialization that exceeds 20s even though subsequent and normal product +// startup are healthy. Keep the diagnostic bounded, but allow realistic cold +// starts on supported desktop hardware. +export const DSHX_DOCTOR_BOOT_TIMEOUT_MS = 60_000; +export const DSHX_DOCTOR_DISPOSE_TIMEOUT_MS = 10_000; + +export function isSupportedNodeVersion(version) { + const match = /^(\d+)\.(\d+)\.(\d+)/.exec(String(version ?? '')); + if (!match) return false; + const major = Number(match[1]); + const minor = Number(match[2]); + return (major === 22 && minor >= 19) || major >= 24; +} + +export function assertReleaseNodeVersion(version = process.versions.node) { + const major = Number(String(version).split('.')[0]); + if (major !== DSHX_RELEASE_NODE_MAJOR) { + throw new Error( + `DSHX dependency freeze/release baseline requires Node ${DSHX_RELEASE_NODE_MAJOR}.x; got ${version}. ` + + `Runtime compatibility follows pinned DSH (${DSHX_NODE_ENGINE}).` + ); + } +} diff --git a/.release/dshx-linux-x64/src/dsh/agent-driver.mjs b/.release/dshx-linux-x64/src/dsh/agent-driver.mjs new file mode 100644 index 00000000..3641bc70 --- /dev/null +++ b/.release/dshx-linux-x64/src/dsh/agent-driver.mjs @@ -0,0 +1,213 @@ +import { randomUUID } from 'node:crypto'; +import { installModelSelection } from '@deepseek-ai/dsh-agent'; +import { createUserMessage } from '@deepseek-ai/dsh-llm'; +import { SessionId } from '@deepseek-ai/dsh-session'; + +function requireService(ctx, name) { + const service = ctx.get(name); + if (service === undefined) throw new Error(`DSHX requires DSH service: ${name}`); + return service; +} + +function userMessage(content) { + const blocks = Array.isArray(content) ? content : [{ type: 'text', text: String(content ?? '') }]; + return createUserMessage({ + source: { kind: 'user' }, + content: blocks + }); +} + +/** Thin delegation layer over official DeepSeek Harness public services. */ +export class DshAgentDriver { + constructor(ctx) { + if (!ctx || typeof ctx.get !== 'function') throw new Error('DshAgentDriver requires a Cordis Context'); + this.ctx = ctx; + this.selections = new WeakMap(); + this.externalSelections = new WeakMap(); + } + + async settleComposition() { + await this.ctx.get('loader')?.await?.(); + } + + persistedSelection(agent) { + const logged = agent.session.requestHeader?.()?.config; + if (logged === undefined) return undefined; + return { + provider: logged.provider, + model: logged.model, + ...(logged.reasoningEffort === undefined ? {} : { reasoningEffort: logged.reasoningEffort }) + }; + } + + restoredSelection(agent) { + return this.persistedSelection(agent) + ?? requireService(this.ctx, 'agentDefaultModel').currentSelection(); + } + + selectionFor(agent) { + const existing = this.selections.get(agent); + if (existing) return existing; + if (this.externalSelections.has(agent)) { + throw new Error('DSHX must not install a second model-selection listener on a Host-owned Agent'); + } + const driver = this; + let picked = this.persistedSelection(agent); + const selection = { + get current() { + return picked + ?? requireService(driver.ctx, 'agentDefaultModel').currentSelection(); + }, + set current(next) { picked = next; }, + assembled: undefined + }; + installModelSelection(agent.ctx, selection); + this.selections.set(agent, selection); + return selection; + } + + /** + * Attach presentation state to an Agent created by another official DSH + * entrypoint (currently Host sessions.fork). No routing listener is installed; + * writes must go back through the owning DSH API delegate. + */ + adoptExternalSelection(agent, { current, select } = {}) { + if (this.selections.has(agent)) { + throw new Error('Cannot adopt Host-owned selection after DSHX installed its own selection listener'); + } + const state = { + current: current ?? this.restoredSelection(agent), + select + }; + this.externalSelections.set(agent, state); + return state.current; + } + + installSelection(agentCtx) { + const agent = agentCtx.agent; + if (!agent) throw new Error('DSHX agent setup has no scoped DSH Agent'); + this.selectionFor(agent); + } + + async create({ cwd = process.cwd(), sessionId = `session-${randomUUID()}` } = {}) { + await this.settleComposition(); + const agents = requireService(this.ctx, 'agents'); + const selection = requireService(this.ctx, 'agentDefaultModel').currentSelection(); + return agents.create({ + sessionId: SessionId(sessionId), + meta: { cwd }, + agentOptions: { provider: selection.provider, model: selection.model }, + setup: (agentCtx) => this.installSelection(agentCtx) + }); + } + + async resume(sessionId) { + await this.settleComposition(); + const agents = requireService(this.ctx, 'agents'); + return agents.resume({ + resumeSessionId: SessionId(sessionId), + setup: (agentCtx) => this.installSelection(agentCtx) + }); + } + + currentModel(agent) { + return this.externalSelections.get(agent)?.current ?? this.selectionFor(agent).current; + } + + currentTitle(agent) { + return this.ctx.get('sessionTitle')?.get?.(agent.session); + } + + renameTitle(agent, title) { + const service = requireService(this.ctx, 'sessionTitle'); + return service.rename(agent.session, title); + } + + async readTitle(sessionId) { + const query = this.ctx.get('sessionQuery'); + if (query?.readTitle) return query.readTitle(SessionId(sessionId)); + const live = this.getLive(sessionId); + return live ? this.currentTitle(live) : undefined; + } + + async selectModel(agent, requested) { + const llm = requireService(this.ctx, 'llm'); + const resolved = await llm.resolveCallConfig({ + provider: requested.provider, + model: requested.model, + ...(requested.reasoningEffort === undefined ? {} : { reasoningEffort: requested.reasoningEffort }) + }); + const selected = { + provider: resolved.provider, + model: resolved.model, + ...(resolved.reasoningEffort === undefined ? {} : { reasoningEffort: resolved.reasoningEffort }) + }; + const external = this.externalSelections.get(agent); + if (external) { + if (typeof external.select !== 'function') { + throw new Error('Host-owned DSH Agent has no model-selection delegate'); + } + const committed = await external.select(selected); + external.current = committed ?? selected; + return external.current; + } + this.selectionFor(agent).current = selected; + return selected; + } + + async modelDirectory() { + const llm = requireService(this.ctx, 'llm'); + const providers = llm.listProviders(); + const settled = await Promise.all(providers.map(async (provider) => { + try { + const models = await llm.listModels(provider.id); + const entries = await Promise.all(models.map(async (model) => { + const exact = await llm.resolveModelInfo(provider.id, model.id); + return { + id: model.id, + name: model.name, + ...(model.description === undefined ? {} : { description: model.description }), + ...(exact.inputModalities === undefined ? {} : { inputModalities: [...exact.inputModalities] }), + ...(exact.context === undefined ? {} : { contextWindow: exact.context.contextWindow }), + ...(exact.reasoning === undefined ? {} : { + reasoning: { + efforts: exact.reasoning.efforts.map((effort) => ({ + id: effort.id, + name: effort.name, + ...(effort.description === undefined ? {} : { description: effort.description }) + })), + ...(exact.reasoning.defaultEffort === undefined ? {} : { defaultEffort: exact.reasoning.defaultEffort }) + } + }) + }; + })); + return { ok: true, group: { provider: provider.id, name: provider.name ?? provider.id, models: entries } }; + } catch (error) { + return { + ok: false, + failure: { provider: provider.id, message: error instanceof Error ? error.message : String(error) } + }; + } + })); + return { + groups: settled.filter((entry) => entry.ok && entry.group.models.length > 0).map((entry) => entry.group), + failures: settled.filter((entry) => !entry.ok).map((entry) => entry.failure) + }; + } + + followup(agent, content) { agent.followup(userMessage(content)); } + steer(agent, content) { agent.steer(userMessage(content)); } + interrupt(agent, { keepInbox = false } = {}) { agent.cancel({ kind: 'user' }, { keepInbox }); } + whenIdle(agent) { return agent.whenIdle(); } + getLive(sessionId) { return requireService(this.ctx, 'agents').get(SessionId(sessionId)); } + listLive() { return requireService(this.ctx, 'agents').list(); } + listRootAgents() { return requireService(this.ctx, 'agents').roots(); } + + async listSessions(signal) { + return requireService(this.ctx, 'sessionPersistence').list(signal); + } + + async inspectSession(sessionId, signal) { + return requireService(this.ctx, 'sessionPersistence').inspect(SessionId(sessionId), signal); + } +} diff --git a/.release/dshx-linux-x64/src/dsh/approval-bridge.mjs b/.release/dshx-linux-x64/src/dsh/approval-bridge.mjs new file mode 100644 index 00000000..20bd0319 --- /dev/null +++ b/.release/dshx-linux-x64/src/dsh/approval-bridge.mjs @@ -0,0 +1,88 @@ +import { mapCodexDecisionToDshApprovalOutcome } from './permissions.mjs'; + +function unavailable() { + return 'unavailable'; +} + +/** + * Presentation-only answerer for DSH `approval/request`. + * + * `classify(req)` must return a faithful presentation descriptor for a DSH + * tool that already has a matching Codex UI surface, or null when DSHX cannot + * represent the request. Null deliberately delegates to the next DSH answerer; + * if nobody owns it, DSH itself returns `unavailable` and callers fail closed. + */ +export class DshApprovalBridge { + constructor({ agent, broker, classify, diagnostics = () => {} }) { + if (!agent?.ctx) throw new Error('DshApprovalBridge requires a live DSH Agent'); + if (!broker) throw new Error('DshApprovalBridge requires a UiRequestBroker'); + if (typeof classify !== 'function') throw new Error('DshApprovalBridge requires classify(req)'); + this.agent = agent; + this.broker = broker; + this.classify = classify; + this.diagnostics = diagnostics; + this.disposeListener = agent.ctx.on('approval/request', (req, next) => this.answer(req, next)); + } + + async answer(req, next) { + const descriptor = this.classify(req); + if (!descriptor) return next(); + + const { kind, threadId, turnId, itemId } = descriptor; + if (!threadId || !turnId || !itemId) { + this.diagnostics('approval classifier returned an incomplete descriptor'); + return unavailable(); + } + + let method; + let params; + if (kind === 'command') { + method = 'item/commandExecution/requestApproval'; + params = { + threadId, + turnId, + itemId, + startedAtMs: Date.now(), + approvalId: null, + environmentId: null, + reason: req.reason ?? null, + networkApprovalContext: null, + command: descriptor.command ?? null, + cwd: descriptor.cwd ?? null, + commandActions: null, + proposedExecpolicyAmendment: null, + proposedNetworkPolicyAmendments: null + }; + } else if (kind === 'fileChange') { + method = 'item/fileChange/requestApproval'; + params = { + threadId, + turnId, + itemId, + startedAtMs: Date.now(), + reason: req.reason ?? null, + grantRoot: null + }; + } else { + this.diagnostics(`unsupported approval descriptor kind: ${String(kind)}`); + return unavailable(); + } + + try { + const result = await this.broker.request(method, params, { signal: req.signal }); + return mapCodexDecisionToDshApprovalOutcome(result?.decision); + } catch (error) { + // Any transport failure, abort, timeout, unsupported persistent grant or + // malformed decision fails closed. DSH remains the policy owner and logs + // the resulting `unavailable`/cancelled decision through its own service. + if (req.signal?.aborted || error?.name === 'AbortError') return 'cancelled'; + this.diagnostics(error instanceof Error ? error.message : String(error)); + return unavailable(); + } + } + + dispose() { + this.disposeListener?.(); + this.disposeListener = undefined; + } +} diff --git a/.release/dshx-linux-x64/src/dsh/commands.mjs b/.release/dshx-linux-x64/src/dsh/commands.mjs new file mode 100644 index 00000000..d63bec35 --- /dev/null +++ b/.release/dshx-linux-x64/src/dsh/commands.mjs @@ -0,0 +1,27 @@ +function requireService(ctx, name) { + const service = ctx?.get?.(name); + if (service == null) throw new Error(`DSHX requires DSH service: ${name}`); + return service; +} + +/** + * Execute one human-facing DSH command through the official command plane. + * DSHX does not parse, implement, persist, or run the domain operation itself. + */ +export async function executeDshCommand({ ctx, agent, line, images = [], signal }) { + if (!agent) throw new Error('DSHX command execution requires a live DSH Agent'); + const commands = requireService(ctx, 'commands'); + const execution = await commands.execute(agent, line, images, signal); + if (execution == null) throw new Error(`DSH command is not registered: ${line}`); + if (execution.result?.kind === 'error') { + throw new Error(execution.result.text || `DSH command failed: ${line}`); + } + return execution; +} + +/** Read the current agent-scoped command catalog from DSH. */ +export function listDshCommands({ ctx, agent }) { + if (!agent) throw new Error('DSHX command discovery requires a live DSH Agent'); + const commands = requireService(ctx, 'commands'); + return commands.list(agent); +} diff --git a/.release/dshx-linux-x64/src/dsh/history-pages.mjs b/.release/dshx-linux-x64/src/dsh/history-pages.mjs new file mode 100644 index 00000000..c4b9ada0 --- /dev/null +++ b/.release/dshx-linux-x64/src/dsh/history-pages.mjs @@ -0,0 +1,77 @@ +import { dshTurnsFromSession } from '../tui-protocol/shapes.mjs'; + +function cursorOffset(cursor) { + if (cursor == null) return 0; + const match = /^dshx:(\d+)$/.exec(String(cursor)); + if (!match) throw new Error(`invalid DSHX history cursor: ${JSON.stringify(cursor)}`); + const value = Number(match[1]); + if (!Number.isSafeInteger(value) || value < 0) throw new Error('invalid DSHX history cursor'); + return value; +} + +function pageSize(limit, fallback) { + if (limit == null) return fallback; + const value = Number(limit); + if (!Number.isSafeInteger(value) || value <= 0) throw new Error('history limit must be a positive integer'); + return Math.min(value, 1000); +} + +function page(values, { cursor, limit, sortDirection, fallbackLimit }) { + const ordered = sortDirection === 'asc' ? values : [...values].reverse(); + const start = cursorOffset(cursor); + const size = pageSize(limit, fallbackLimit); + const end = Math.min(ordered.length, start + size); + return { + data: ordered.slice(start, end), + nextCursor: end < ordered.length ? `dshx:${end}` : null, + // DSHX cursors are forward-only presentation cursors. The TUI only needs + // nextCursor for bounded backwards hydration; no durable cursor state is owned here. + backwardsCursor: null + }; +} + +function projectedTurns(controller, diagnostics) { + return dshTurnsFromSession({ + ctx: controller.agent.ctx, + agent: controller.agent, + diagnostics + }); +} + +function viewTurn(turn, requestedView) { + if (requestedView === 'notLoaded') { + return { ...turn, items: [], itemsView: 'notLoaded' }; + } + // DSHX has a faithful full presentation fold, not a second lossy summary + // algorithm. When Codex asks for summary, return full and label it honestly. + return { ...turn, itemsView: 'full' }; +} + +export function dshThreadTurnsPage({ controller, params = {}, diagnostics = () => {} }) { + const turns = projectedTurns(controller, diagnostics).map((turn) => viewTurn(turn, params.itemsView)); + return page(turns, { + cursor: params.cursor, + limit: params.limit, + sortDirection: params.sortDirection, + fallbackLimit: 5 + }); +} + +export function dshThreadItemsPage({ controller, params = {}, diagnostics = () => {} }) { + let turns = projectedTurns(controller, diagnostics); + if (params.turnId != null) { + turns = turns.filter((turn) => turn.id === String(params.turnId)); + } + const entries = []; + for (const turn of turns) { + for (const item of turn.items) entries.push({ turnId: turn.id, item }); + } + return page(entries, { + cursor: params.cursor, + limit: params.limit, + sortDirection: params.sortDirection, + fallbackLimit: 100 + }); +} + +export const historyInternals = { cursorOffset, pageSize, page, viewTurn }; diff --git a/.release/dshx-linux-x64/src/dsh/host-api.mjs b/.release/dshx-linux-x64/src/dsh/host-api.mjs new file mode 100644 index 00000000..287bd9fc --- /dev/null +++ b/.release/dshx-linux-x64/src/dsh/host-api.mjs @@ -0,0 +1,61 @@ +import { randomUUID } from 'node:crypto'; +import { createApiProxy, RpcId } from '@deepseek-ai/dsh-host-apiproxy'; + +function requireService(ctx, name) { + const service = ctx?.get?.(name); + if (service == null) throw new Error(`DSHX requires DSH service: ${name}`); + return service; +} + +function rpcError(error, fallback) { + if (error?.message) return new Error(error.message); + return new Error(fallback); +} + +function value(response, fallback) { + if (!response?.result?.ok) throw rpcError(response?.result?.error, fallback); + return response.result.value; +} + +/** + * Very small façade over DSH's own transport-agnostic Host API. + * Domain semantics stay in @deepseek-ai/dsh-host-apiproxy; DSHX only adapts + * Codex presentation requests into that public API. + */ +export class DshHostApi { + constructor(ctx, { cwd = process.cwd() } = {}) { + if (!ctx || typeof ctx.get !== 'function') throw new Error('DshHostApi requires a Cordis Context'); + this.ctx = ctx; + this.api = createApiProxy(ctx, { + cwd, + defaultModelSelection: () => requireService(ctx, 'agentDefaultModel').currentSelection(), + saveDefaultModelSelection: (selection) => requireService(ctx, 'agentDefaultModel').saveSelection(selection) + }); + } + + request(payload) { + return { + rpcId: RpcId(`dshx-${randomUUID()}`), + payload + }; + } + + async forkSession({ sessionId, atSeq } = {}) { + const response = await this.api.sessions.fork(this.request({ + sessionId, + ...(atSeq == null ? {} : { atSeq }) + })); + return value(response, `DSH session fork failed for ${String(sessionId)}`); + } + + async selectModel({ sessionId, provider, model, reasoningEffort } = {}) { + const response = await this.api.sessions.selectModel(this.request({ + sessionId, + provider, + model, + ...(reasoningEffort == null ? {} : { reasoningEffort }) + })); + const result = value(response, `DSH model selection failed for ${String(sessionId)}`); + return result?.selected ?? result; + } +} diff --git a/.release/dshx-linux-x64/src/dsh/index.mjs b/.release/dshx-linux-x64/src/dsh/index.mjs new file mode 100644 index 00000000..06771846 --- /dev/null +++ b/.release/dshx-linux-x64/src/dsh/index.mjs @@ -0,0 +1,25 @@ +/** + * @code-new-bie/dshx-tui — Codex-TUI surface bundle for DeepSeek Harness. + * + * Programmatic entry point. The runtime capability lives in the two + * loader-mounted rows (`./startup`, `./presentation`); this index exists so + * tooling and tests can consume the contract metadata without importing the + * transport implementation. + */ +export { + name, + inject, + Config, + apply, + plugin, + SERVICE_KEY, + internals +} from './presentation-plugin.mjs'; +export { + name as startupName, + inject as startupInject, + Config as startupConfig, + apply as startupApply, + plugin as startupPlugin, + internals as startupInternals +} from './startup-plugin.mjs'; diff --git a/.release/dshx-linux-x64/src/dsh/local-server.mjs b/.release/dshx-linux-x64/src/dsh/local-server.mjs new file mode 100644 index 00000000..c96fca06 --- /dev/null +++ b/.release/dshx-linux-x64/src/dsh/local-server.mjs @@ -0,0 +1,363 @@ +import fs from 'node:fs'; +import os from 'node:os'; +import path from 'node:path'; +import { spawn } from 'node:child_process'; +import { createInterface } from 'node:readline'; +import { fileURLToPath } from 'node:url'; +import { DshxPresentationAdapter } from '../tui-protocol/adapter.mjs'; +import { bootDshxRuntime } from './runtime-boot.mjs'; + +const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../..'); +const READY = 'ready'; +const WINDOWS_UNIX_PATH_MAX = 108; + +function packagedBridgeBinary() { + const name = process.platform === 'win32' ? 'dshx-ipc-bridge.exe' : 'dshx-ipc-bridge'; + return process.env.DSHX_IPC_BRIDGE_BIN || path.join(ROOT, 'dist', 'bin', name); +} + +function parseError(error) { + return { + id: null, + error: { + code: -32700, + message: `Parse error: ${error instanceof Error ? error.message : String(error)}` + } + }; +} + +function isPathWithin(root, candidate, pathApi = path) { + const relative = pathApi.relative(pathApi.resolve(root), pathApi.resolve(candidate)); + return relative === '' || ( + relative !== '..' && + !relative.startsWith(`..${pathApi.sep}`) && + !pathApi.isAbsolute(relative) + ); +} + +function defaultSocketRoot({ + home, + platform = process.platform, + temporaryDirectory = os.tmpdir(), + userHome = os.homedir() +} = {}) { + if (platform !== 'win32') return temporaryDirectory; + // codex_uds can enforce 0700 on Unix. Its Windows implementation inherits + // directory ACLs instead, so do not trust an arbitrary/shared %TEMP% root. + // Anchor the rendezvous below the current user's DSHX presentation home, + // whose parent in turn lives below the user's profile by default. Keep the + // Windows suffix deliberately short because sockaddr_un.sun_path is bounded. + const pathApi = path.win32; + const userProfile = pathApi.resolve(userHome); + const presentationHome = pathApi.resolve(home || pathApi.join(userProfile, '.dshx', 'codex-tui')); + if (!isPathWithin(userProfile, presentationHome, pathApi)) { + throw new Error( + `DSHX_TUI_HOME must remain under the Windows user profile (${userProfile}) so local IPC inherits private user ACLs; got ${presentationHome}` + ); + } + return pathApi.join(presentationHome, 'i'); +} + +function createSocketDirectory(root) { + fs.mkdirSync(root, { recursive: true, mode: 0o700 }); + const directory = fs.mkdtempSync(path.join(root, 'd-')); + if (process.platform !== 'win32') fs.chmodSync(directory, 0o700); + return directory; +} + +function assertSocketPathSupported(socketPath, { + platform = process.platform, + windowsUnixPathMax = WINDOWS_UNIX_PATH_MAX +} = {}) { + if (platform !== 'win32') return; + const bytes = Buffer.byteLength(socketPath, 'utf8'); + // sun_path needs one byte for the terminating NUL, so the pathname itself + // must remain strictly shorter than the fixed buffer. + if (bytes >= windowsUnixPathMax) { + throw new Error( + `DSHX local IPC path is ${bytes} UTF-8 bytes; Windows AF_UNIX requires fewer than ${windowsUnixPathMax}. ` + + 'Set DSHX_TUI_HOME to a shorter path under your user profile and retry.' + ); + } +} + +function waitForBridgeReady(lines, child, stderrText) { + return new Promise((resolve, reject) => { + const fail = (error) => { + cleanup(); + reject(error); + }; + const onLine = (line) => { + let message; + try { + message = JSON.parse(line); + } catch (error) { + fail(new Error(`DSHX IPC bridge emitted invalid readiness JSON: ${line}`, { cause: error })); + return; + } + if (message?.dshxBridge !== READY) { + fail(new Error(`DSHX IPC bridge emitted unexpected readiness message: ${line}`)); + return; + } + cleanup(); + resolve(message); + }; + const onError = (error) => fail(new Error(`failed to start DSHX IPC bridge: ${error.message}`, { cause: error })); + const onExit = (code, signal) => { + const detail = stderrText().trim(); + fail(new Error(`DSHX IPC bridge exited before ready (${signal ?? code ?? 'unknown'})${detail ? `: ${detail}` : ''}`)); + }; + const cleanup = () => { + lines.off('line', onLine); + child.off('error', onError); + child.off('exit', onExit); + }; + lines.once('line', onLine); + child.once('error', onError); + child.once('exit', onExit); + }); +} + +function waitForExit(child, timeoutMs = 750) { + if (!child || child.exitCode !== null || child.signalCode !== null) return Promise.resolve(); + return new Promise((resolve) => { + let done = false; + const finish = () => { + if (done) return; + done = true; + clearTimeout(timer); + child.off('exit', finish); + resolve(); + }; + const timer = setTimeout(() => { + if (child.exitCode === null && child.signalCode === null) child.kill('SIGTERM'); + finish(); + }, timeoutMs); + child.once('exit', finish); + }); +} + +function cleanupDiagnostic(log, scope, error) { + log(`${scope}: ${error instanceof Error ? error.message : String(error)}`); +} + +async function cleanupFailedStartup({ lines, bridge, ctx, socketDirectory, log }) { + try { + lines?.close(); + } catch (error) { + cleanupDiagnostic(log, 'startup rollback: readline cleanup failed', error); + } + if (bridge) { + try { + if (bridge.stdin?.writable) bridge.stdin.end(); + if (bridge.exitCode === null && bridge.signalCode === null) bridge.kill?.('SIGTERM'); + await waitForExit(bridge); + if (bridge.exitCode === null && bridge.signalCode === null) bridge.kill?.('SIGKILL'); + } catch (error) { + cleanupDiagnostic(log, 'startup rollback: bridge cleanup failed', error); + } + } + try { + await ctx?.dispose?.(); + } catch (error) { + cleanupDiagnostic(log, 'startup rollback: DSH dispose failed', error); + } + if (socketDirectory) { + try { + fs.rmSync(socketDirectory, { recursive: true, force: true }); + } catch (error) { + cleanupDiagnostic(log, 'startup rollback: rendezvous cleanup failed', error); + } + } +} + +/** + * Starts the production-local DSHX presentation transport. + * + * The official DeepSeek Harness runtime remains in-process in Node. The pinned + * Codex TUI connects only to a private cross-platform Unix-domain socket owned + * by the tiny packaged Rust bridge. JSON-RPC is relayed between that bridge and + * this adapter over child stdio; no TCP listener or Codex remote WebSocket mode + * exists in the production launch path. + */ +export async function startDshxLocalServer({ + cwd = process.cwd(), + home, + version = '0.1.0-dev', + runtime, + bootRuntime = bootDshxRuntime, + Adapter = DshxPresentationAdapter, + log = () => {}, + bridgeCommand = packagedBridgeBinary(), + bridgeArgs, + spawnBridge = spawn, + socketRoot, + disposeRuntimeOnClose = true +} = {}) { + const rendezvousRoot = path.resolve(socketRoot ?? defaultSocketRoot({ home })); + let socketDirectory; + let socketPath; + let ctx = runtime; + let bridge; + let lines; + let adapter; + let closing = false; + let closePromise; + let stderr = ''; + + const send = (message) => { + if (!bridge?.stdin?.writable) throw new Error('DSHX IPC bridge stdin is not writable'); + bridge.stdin.write(`${JSON.stringify(message)}\n`); + }; + const safeSend = (message) => { + try { + send(message); + return true; + } catch (error) { + log(`IPC response send failed: ${error instanceof Error ? error.message : String(error)}`); + return false; + } + }; + + try { + socketDirectory = createSocketDirectory(rendezvousRoot); + socketPath = path.join(socketDirectory, 's'); + assertSocketPathSupported(socketPath); + ctx ??= await bootRuntime({ cwd }); + const args = bridgeArgs ?? [socketPath]; + bridge = spawnBridge(bridgeCommand, args, { + cwd, + stdio: ['pipe', 'pipe', 'pipe'], + windowsHide: true + }); + bridge.stderr?.on('data', (chunk) => { + const text = chunk.toString('utf8'); + stderr = `${stderr}${text}`.slice(-8192); + if (process.env.DSHX_DEBUG === '1') log(`ipc bridge: ${text.trimEnd()}`); + }); + lines = createInterface({ input: bridge.stdout, crlfDelay: Infinity }); + await waitForBridgeReady(lines, bridge, () => stderr); + adapter = new Adapter({ + ctx, + cwd, + home, + version, + send, + diagnostics: log + }); + } catch (error) { + await cleanupFailedStartup({ lines, bridge, ctx, socketDirectory, log }); + throw error; + } + + lines.on('line', (line) => { + void (async () => { + let message; + try { + message = JSON.parse(line); + } catch (error) { + safeSend(parseError(error)); + return; + } + if (message?.dshxBridge) { + log(`IPC bridge control message: ${message.dshxBridge}`); + return; + } + try { + const handled = await adapter.handle(message); + if (!handled) return; + if (!safeSend(handled.response)) return; + await handled.afterResponse?.(); + } catch (error) { + log(`request handling failed: ${error instanceof Error ? error.stack ?? error.message : String(error)}`); + if (message?.id !== undefined) { + safeSend({ + id: message.id, + error: { + code: -32603, + message: error instanceof Error ? error.message : String(error) + } + }); + } + } + })(); + }); + + bridge.on('error', (error) => log(`IPC bridge error: ${error.message}`)); + bridge.on('exit', (code, signal) => { + if (!closing) log(`IPC bridge exited unexpectedly (${signal ?? code ?? 'unknown'})`); + }); + + const close = () => { + if (closePromise) return closePromise; + closing = true; + closePromise = (async () => { + let primaryError; + const capture = (scope, error) => { + if (!primaryError) { + primaryError = error; + return; + } + cleanupDiagnostic(log, `shutdown cleanup: ${scope}`, error); + }; + + try { + lines?.close(); + } catch (error) { + capture('readline cleanup failed', error); + } + + try { + await adapter?.close?.(); + } catch (error) { + capture('adapter close failed', error); + } + + try { + if (bridge?.stdin?.writable) bridge.stdin.end(); + await waitForExit(bridge); + if (bridge && bridge.exitCode === null && bridge.signalCode === null) bridge.kill?.('SIGKILL'); + } catch (error) { + capture('bridge cleanup failed', error); + } + + // When mounted as the dshx-presentation Cordis plugin, root-fiber + // disposal stays owned by the composition; only the transport closes + // here and the Fiber unwinds the plugin afterwards. + if (disposeRuntimeOnClose) { + try { + await ctx?.dispose?.(); + } catch (error) { + capture('DSH dispose failed', error); + } + } + + if (socketDirectory) { + try { + fs.rmSync(socketDirectory, { recursive: true, force: true }); + } catch (error) { + capture('rendezvous cleanup failed', error); + } + } + + if (primaryError) throw primaryError; + })(); + return closePromise; + }; + + return { + path: socketPath, + url: `unix://${socketPath}`, + context: ctx, + close + }; +} + +export const localServerInternals = { + WINDOWS_UNIX_PATH_MAX, + isPathWithin, + defaultSocketRoot, + createSocketDirectory, + assertSocketPathSupported, + cleanupFailedStartup +}; diff --git a/.release/dshx-linux-x64/src/dsh/permissions.mjs b/.release/dshx-linux-x64/src/dsh/permissions.mjs new file mode 100644 index 00000000..f1f1b4df --- /dev/null +++ b/.release/dshx-linux-x64/src/dsh/permissions.mjs @@ -0,0 +1,106 @@ +function requireService(ctx, name) { + const service = ctx.get(name); + if (service === undefined) throw new Error(`DSHX requires DSH service: ${name}`); + return service; +} + +function codexApprovalPolicy(policy) { + if (policy === 'ask') return 'on-request'; + if (policy === 'never') return 'never'; + throw new Error(`Unsupported DSH approval policy: ${String(policy)}`); +} + +/** + * Project official DSH permission state into Codex-facing presentation data. + * + * DSH sandbox modes govern filesystem effects only; Codex legacy sandbox + * shapes also encode network policy. To avoid claiming Codex-native sandbox + * semantics that DSH does not own, confined DSH modes are advertised as an + * external sandbox. `legacyNetworkAccess` describes only the legacy Codex + * field and never changes DSH enforcement. + */ +export class DshPermissionView { + constructor(ctx, { legacyNetworkAccess = 'enabled' } = {}) { + if (!ctx || typeof ctx.get !== 'function') throw new Error('DshPermissionView requires a Cordis Context'); + if (!['enabled', 'restricted'].includes(legacyNetworkAccess)) { + throw new Error('legacyNetworkAccess must be "enabled" or "restricted"'); + } + this.ctx = ctx; + this.legacyNetworkAccess = legacyNetworkAccess; + } + + current(agent) { + if (!agent?.session) throw new Error('DshPermissionView.current requires a live DSH Agent'); + const presets = requireService(this.ctx, 'permissionPresets'); + const sandboxPolicy = requireService(this.ctx, 'sandboxPolicy'); + const approval = requireService(this.ctx, 'approval'); + const session = agent.session; + + const preset = presets.current(session.events); + const options = [ + ...presets.names.map((name) => presets.optionOf(name)), + ...(preset === 'custom' ? [presets.optionOf('custom')] : []) + ]; + const resolvedSandbox = sandboxPolicy.resolve({ session }); + const approvalPolicy = approval.overrideOf(session) ?? approval.config?.policy ?? 'ask'; + + let sandbox; + if (resolvedSandbox.mode === 'danger-full-access') { + sandbox = { type: 'dangerFullAccess' }; + } else if (resolvedSandbox.mode === 'read-only' || resolvedSandbox.mode === 'workspace-write') { + sandbox = { type: 'externalSandbox', networkAccess: this.legacyNetworkAccess }; + } else { + throw new Error(`Unsupported DSH sandbox mode: ${String(resolvedSandbox.mode)}`); + } + + return { + preset, + options, + dsh: { + sandboxMode: resolvedSandbox.mode, + workspaceRoot: resolvedSandbox.workspaceRoot, + approvalPolicy + }, + codex: { + approvalPolicy: codexApprovalPolicy(approvalPolicy), + approvalsReviewer: 'user', + sandbox + } + }; + } + + set(agent, presetName) { + if (!agent?.session) throw new Error('DshPermissionView.set requires a live DSH Agent'); + const presets = requireService(this.ctx, 'permissionPresets'); + presets.set(agent.session, presetName); + } +} + +export function mapDshApprovalOutcomeToCodexDecision(outcome) { + switch (outcome) { + case 'allowed-once': + return 'accept'; + case 'rejected': + case 'unavailable': + return 'decline'; + case 'cancelled': + return 'cancel'; + default: + throw new Error(`Unknown DSH approval outcome: ${String(outcome)}`); + } +} + +export function mapCodexDecisionToDshApprovalOutcome(decision) { + switch (decision) { + case 'accept': + return 'allowed-once'; + case 'decline': + return 'rejected'; + case 'cancel': + return 'cancelled'; + case 'acceptForSession': + throw new Error('DSH has no session-wide approval grant; DSHX must not offer acceptForSession'); + default: + throw new Error('Codex approval decision has no faithful DSH one-shot mapping'); + } +} diff --git a/.release/dshx-linux-x64/src/dsh/plan-presentation.mjs b/.release/dshx-linux-x64/src/dsh/plan-presentation.mjs new file mode 100644 index 00000000..e1d40893 --- /dev/null +++ b/.release/dshx-linux-x64/src/dsh/plan-presentation.mjs @@ -0,0 +1,55 @@ +export function codexPlanTarget(collaborationMode) { + if (!collaborationMode || typeof collaborationMode !== 'object' || Array.isArray(collaborationMode)) { + throw new Error('DSHX collaborationMode must be a Codex collaboration mode object'); + } + if (collaborationMode.mode === 'plan') return true; + if (collaborationMode.mode === 'default') return false; + throw new Error(`DSHX cannot map Codex collaboration mode ${JSON.stringify(collaborationMode.mode)} to DSH plan mode`); +} + +export function effectiveDshPlanState(state) { + if (typeof state?.pending === 'boolean') return state.pending; + return Boolean(state?.active); +} + +export function codexCollaborationMode({ model, reasoningEffort, active }) { + return { + mode: active ? 'plan' : 'default', + settings: { + model, + reasoning_effort: reasoningEffort ?? null, + // DSH owns plan guidance. Never copy Codex developer instructions into + // the Harness request just to satisfy a presentation protocol shape. + developer_instructions: null + } + }; +} + +export function threadSettingsUpdatedNotification({ threadId, response, planState }) { + const active = effectiveDshPlanState(planState); + return { + method: 'thread/settings/updated', + params: { + threadId, + threadSettings: { + cwd: response.cwd, + approvalPolicy: response.approvalPolicy, + approvalsReviewer: response.approvalsReviewer, + sandboxPolicy: response.sandbox, + activePermissionProfile: response.activePermissionProfile ?? null, + model: response.model, + modelProvider: response.modelProvider, + serviceTier: response.serviceTier ?? null, + effort: response.reasoningEffort ?? null, + summary: null, + collaborationMode: codexCollaborationMode({ + model: response.model, + reasoningEffort: response.reasoningEffort, + active + }), + multiAgentMode: response.multiAgentMode ?? 'explicitRequestOnly', + personality: null + } + } + }; +} diff --git a/.release/dshx-linux-x64/src/dsh/presentation-plugin.mjs b/.release/dshx-linux-x64/src/dsh/presentation-plugin.mjs new file mode 100644 index 00000000..4f379347 --- /dev/null +++ b/.release/dshx-linux-x64/src/dsh/presentation-plugin.mjs @@ -0,0 +1,71 @@ +import z from '@deepseek-ai/schemastery'; +import { startDshxLocalServer } from './local-server.mjs'; + +/** + * dshx-presentation — the surface's transport host row. + * + * Loaded by the Cordis loader through the bundle patch (no dynamic mounting): + * it starts the packaged bridge + adapter transport against the already-booted + * official composition Context, publishes the endpoint as the + * `dshxPresentation` service, and returns the transport closer as its + * disposer. Teardown authority remains the Cordis root Fiber. + * + * Launch inputs arrive exclusively from the injected `dshxStartup` service + * (see startup-plugin.mjs) — the official three-stage pattern — so this module + * carries no environment or path policy of its own. + */ + +/** Stable Cordis plugin name. */ +export const name = 'dshx-presentation'; + +/** The startup row's service is a hard prerequisite for the transport. */ +export const inject = ['dshxStartup']; + +/** Static overrides straight from the patch row; everything else flows via dshxStartup. */ +export const Config = z.object({ + socketRoot: z.string() +}); + +/** Service key published on the Context after the endpoint is ready. */ +export const SERVICE_KEY = 'dshxPresentation'; + +/** Test seam mirroring the official packages' `internals` convention. */ +export const internals = { start: startDshxLocalServer }; + +export async function apply(ctx, config = {}) { + if (!ctx || typeof ctx.provide !== 'function') { + throw new Error('dshx-presentation requires a Cordis Context with provide()'); + } + const launch = ctx.dshxStartup; + if (!launch || typeof launch.home !== 'string') { + throw new Error('dshx-presentation requires the dshxStartup service (mount the dshx-startup row first)'); + } + const debug = launch.debug === true; + const log = debug ? (message) => process.stderr.write(`[dshx] ${message}\n`) : () => {}; + + const server = await internals.start({ + cwd: launch.cwd, + home: launch.home, + version: launch.version, + bridgeCommand: launch.bridgeCommand, + socketRoot: config.socketRoot, + // The composition Context already exists; never double-boot. Root-fiber + // disposal stays owned by the composition, so the transport must not + // dispose the runtime it lives in (double teardown would re-enter the + // Fiber from inside its own disposer). + runtime: ctx, + disposeRuntimeOnClose: false, + log + }); + + ctx.provide(SERVICE_KEY, { + path: server.path, + url: server.url, + close: server.close, + tuiCommand: launch.tuiCommand + }); + return server.close; +} + +/** Bundle-shaped export consumed by the loader through the patch row. */ +export const plugin = { name, inject, Config, apply }; diff --git a/.release/dshx-linux-x64/src/dsh/profile-bootstrap.mjs b/.release/dshx-linux-x64/src/dsh/profile-bootstrap.mjs new file mode 100644 index 00000000..165b8b4e --- /dev/null +++ b/.release/dshx-linux-x64/src/dsh/profile-bootstrap.mjs @@ -0,0 +1,99 @@ +import fs from 'node:fs'; +import os from 'node:os'; +import path from 'node:path'; +import process from 'node:process'; +import { spawnSync } from 'node:child_process'; +import { createRequire } from 'node:module'; + +/** + * Shared bootstrap over the official DSH plugin machinery. + * + * The surface ships as a standard profile bundle; every entry point (the + * zero-argument CLI, the smoke scripts, CI) ensures the selected profile + * carries this exact package version by running the official + * `dsh plugin --profile

add ` command, which owns profile + * initialization, pnpm installation and bundles reconciliation. + */ + +/** Resolve the DSH home directory exactly like the official launcher. */ +export function dshHomeDir(environment = process.env) { + return environment.DSH_HOME || path.join(os.homedir(), '.dsh'); +} + +export function profileManifestPath(profileName, environment = process.env) { + return path.join(dshHomeDir(environment), 'profiles', profileName, 'package.json'); +} + +/** + * How to invoke the official dsh CLI: an explicit override wins, a global + * `dsh` on PATH is next, and a dependency-local `lib/bin.js` (always present + * after npm ci) keeps CI and fresh checkouts working without any global + * installation. + */ +export function resolveDshInvocation(fromDirectory = process.cwd(), environment = process.env) { + if (environment.DSHX_DSH_BIN) { + return { command: process.execPath, args: [environment.DSHX_DSH_BIN] }; + } + try { + const anchor = createRequire(path.join(fromDirectory, 'package.json')).resolve( + '@deepseek-ai/dsh/package.json' + ); + const cli = path.join(path.dirname(anchor), 'lib', 'bin.js'); + if (fs.existsSync(cli)) return { command: process.execPath, args: [cli] }; + } catch { + // Not installed locally; fall through to PATH lookup. + } + return { command: 'dsh', args: [] }; +} + +/** A profile satisfies bootstrap when it pins this exact version as a bundle layer. */ +export function profileSatisfied(manifest, { name, version }) { + if (!manifest || typeof manifest !== 'object') return false; + const bundles = manifest.dsh?.profile?.bundles ?? []; + const dependencies = manifest.dependencies ?? {}; + return dependencies[name] === version && bundles.includes(name); +} + +/** + * Ensure `profileName` exists and carries `{name}@{version}` from + * `packageRoot` as an activated bundle layer. Idempotent: satisfied profiles + * are left untouched, honoring DSHX_SKIP_PROFILE_BOOTSTRAP=1 for offline runs. + */ +export function ensureProfileInstalled({ + packageRoot, + name, + version, + profile = 'tui', + environment = process.env, + spawnSyncImpl = spawnSync +} = {}) { + let satisfied = false; + try { + satisfied = profileSatisfied(JSON.parse(fs.readFileSync(profileManifestPath(profile, environment), 'utf8')), { + name, + version + }); + } catch { + // Missing or unreadable manifest: the official command initializes it. + } + if (satisfied) return { profile, action: 'already-installed' }; + if (environment.DSHX_SKIP_PROFILE_BOOTSTRAP === '1') { + return { profile, action: 'skipped' }; + } + + const { command, args } = resolveDshInvocation(packageRoot, environment); + const result = spawnSyncImpl( + command, + [...args, 'plugin', '--profile', profile, 'add', packageRoot], + { stdio: 'inherit', shell: process.platform === 'win32' } + ); + if (result.error?.code === 'ENOENT') { + throw new Error( + "official 'dsh' CLI not found (looked up DSHX_DSH_BIN, @deepseek-ai/dsh dependency and PATH); install DeepSeek Harness to manage the DSHX surface profile" + ); + } + if (result.status !== 0) { + throw new Error(`failed to install ${name} into profile '${profile}' via dsh plugin add (exit ${result.status ?? '?'})`); + } + return { profile, action: 'installed' }; +} diff --git a/.release/dshx-linux-x64/src/dsh/runtime-boot.mjs b/.release/dshx-linux-x64/src/dsh/runtime-boot.mjs new file mode 100644 index 00000000..ab86e985 --- /dev/null +++ b/.release/dshx-linux-x64/src/dsh/runtime-boot.mjs @@ -0,0 +1,270 @@ +import { readFileSync, writeFileSync } from 'node:fs'; +import { createRequire } from 'node:module'; +import { dirname, join, resolve } from 'node:path'; +import { fileURLToPath } from 'node:url'; +import { + boot, + composeEntries, + healProfilesModuleFallback, + loadLayeredEnv, + loadOptionalPatches, + loadProfile, + PROFILE_PATCH_FILENAME, + watchUserPatches +} from '@deepseek-ai/dsh-app-boot'; +import { DSH_LAUNCH_ENVIRONMENT_KEY } from '@deepseek-ai/dsh-launch-environment'; + +const NAME = 'dshx'; +const DSH_PROFILE_BIN_NAME = 'dsh'; +const DEFAULT_PROFILE = 'tui'; +const PROFILE_ROOT_FILENAME = 'cordis.yml'; +// The supported official DSH line. Single source of truth: the exact +// @deepseek-ai/dsh peerDependency declared in this package manifest. +const PACKAGE_ROOT = resolve(dirname(fileURLToPath(import.meta.url)), '../..'); +const SUPPORTED_DSH_LINE = JSON.parse( + readFileSync(join(PACKAGE_ROOT, 'package.json'), 'utf8') +).peerDependencies['@deepseek-ai/dsh']; +// Match the official `dsh` launcher's profile-root contract: this file is only +// the Loader/include base anchor. The real user-owned configuration is carried +// by the profile's `cordis.patch.yml` plus `$DSH_HOME/cordis.patch.yml`. +// Rewriting this empty root on every boot is intentional DSH behavior and +// prevents Loader tree write-back from becoming a second persisted config. +const PROFILE_ROOT_CONFIG = `# DSHX uses the same empty profile root contract as the official dsh launcher.\n# The effective tree is composed from DSH bundle and patch layers.\n# Edit cordis.patch.yml, not this file.\n[]\n`; +// The DSHX surface arrives as a real bundle layer: the package manifest +// declares `dsh.bundle.patch`, so the official loader composes our rows and +// surface locks from the installed profile. This module owns no patch of its +// own; launcher patches stay limited to installation-equivalent environment +// wiring (agent preset roots, telemetry switch). + +function installationAnchor() { + return createRequire(import.meta.url).resolve('@deepseek-ai/dsh/package.json'); +} + +/** + * Report which official DSH line this surface was built and tested against, + * compared with the installation that will actually boot. Ecosystem + * convention: bundles declare compatibility through peer ranges and never + * block the host, so a mismatch is a loud one-shot warning, not an error. + */ +let dshLineWarned = false; +export function reportDshLineCompatibility( + anchor = installationAnchor(), + notify = (message) => process.stderr.write(`${message}\n`) +) { + let installed; + try { + installed = JSON.parse(readFileSync(anchor, 'utf8')).version; + } catch { + return { installed: undefined, supported: SUPPORTED_DSH_LINE, compatible: undefined }; + } + const compatible = installed === SUPPORTED_DSH_LINE; + if (!compatible && !dshLineWarned) { + dshLineWarned = true; + notify( + `[dshx] running against untested official DeepSeek Harness ${installed} ` + + `(tested line: ${SUPPORTED_DSH_LINE}); proceeding — report oddities upstream if any appear` + ); + } + return { installed, supported: SUPPORTED_DSH_LINE, compatible }; +} + +function selectedProfile(explicit) { + const value = explicit ?? process.env.DSHX_PROFILE ?? DEFAULT_PROFILE; + if (typeof value !== 'string' || value.trim().length === 0) { + throw new Error('dshx: DSH profile name must be non-empty'); + } + return value.trim(); +} + +function profileHome(profile) { + return dirname(dirname(profile.dir)); +} + +function homePatchPath(profile) { + return join(profileHome(profile), PROFILE_PATCH_FILENAME); +} + +function shippedAgentPresetPatch(entries, installAnchor) { + const agentPresets = entries.find((entry) => entry.id === 'agent-presets'); + if (!agentPresets) return []; + return [{ + id: 'agent-presets', + config: { + ...(agentPresets.config ?? {}), + roots: [{ path: join(dirname(installAnchor), 'config', 'agent-presets'), trust: 'system' }] + } + }]; +} + +function telemetryPatch(entries) { + if (!process.env.DSH_TELEMETRY_DISABLED) return []; + if (!entries.some((entry) => entry.id === 'session-telemetry-otel')) return []; + return [{ id: 'session-telemetry-otel', disabled: true }]; +} + +/** + * Load the exact official DSH profile layers that DSHX presents. + * + * Order remains DSH-owned: profile bundle layers -> profile user patch -> + * $DSH_HOME/cordis.patch.yml. The DSHX surface itself is one of the bundle + * layers (`dsh.bundle.patch`); the launcher adds only installation-equivalent + * environment patches on top. Out-of-tree profile plugins resolve from the + * profile directory through DSH's own healed module fallback. + */ +export function dshxRuntimeProfile({ + profile: explicitProfile, + installAnchor = installationAnchor(), + home, + overlays = [] +} = {}) { + const profileName = selectedProfile(explicitProfile); + reportDshLineCompatibility(installAnchor); + healProfilesModuleFallback(installAnchor, home); + const profile = loadProfile(DSH_PROFILE_BIN_NAME, profileName, installAnchor, home); + const rootConfig = join(profile.dir, PROFILE_ROOT_FILENAME); + // Official DSH deliberately rewrites this empty include root before boot. + // Never write `profile.patchPath` or the home patch here: those are the + // authoritative user configuration layers and are read-only to DSHX. + writeFileSync(rootConfig, PROFILE_ROOT_CONFIG); + + const bundlePatches = profile.layers.flatMap((layer) => layer.patches); + const homePatches = loadOptionalPatches(DSH_PROFILE_BIN_NAME, homePatchPath(profile)) ?? []; + const beforeLauncher = composeEntries([[...bundlePatches, ...profile.patches, ...homePatches]]); + const launcherPatches = [ + ...shippedAgentPresetPatch(beforeLauncher, installAnchor), + ...telemetryPatch(beforeLauncher), + ...structuredClone(overlays) + ]; + + return { + name: profileName, + profile, + rootConfig, + installAnchor, + homePatchPath: homePatchPath(profile), + patches: [ + ...structuredClone(bundlePatches), + ...structuredClone(profile.patches), + ...structuredClone(homePatches), + ...launcherPatches + ] + }; +} + +export function dshxRuntimePatches(options = {}) { + return dshxRuntimeProfile(options).patches; +} + +export function dshxRuntimeEntries(options = {}) { + return composeEntries([dshxRuntimePatches(options)]); +} + +async function installProfileWatchers(ctx, options) { + if (ctx.get('loader') == null) { + throw new Error('dshx: official DSH profile boot has no Loader for profile hot reload'); + } + if (ctx.get('hmr') == null) { + if (ctx.get('timer') == null) { + await ctx.loader.create({ name: '@deepseek-ai/cordis-plugin-timer' }); + } + await ctx.loader.create({ name: '@deepseek-ai/cordis-plugin-hmr', config: { root: [] } }); + } + + const current = () => dshxRuntimeProfile(options).patches; + const composition = dshxRuntimeProfile(options); + await watchUserPatches(ctx, { + binName: NAME, + filename: composition.profile.patchPath, + compose: () => current() + }); + await watchUserPatches(ctx, { + binName: NAME, + filename: composition.homePatchPath, + compose: () => current() + }); +} + +async function disposeOfficialContext(ctx) { + if (!ctx) return; + if (typeof ctx.fiber?.dispose !== 'function') { + throw new Error('dshx: official DSH Context has no root fiber disposal contract'); + } + await ctx.fiber.dispose(); +} + +function attachPresentationLifetime(ctx) { + // Cordis Context intentionally owns teardown through its root Fiber rather + // than a Context.dispose() method. DSHX keeps its launcher/local-server + // lifetime API small by exposing a non-enumerable alias that delegates to + // that official root-fiber contract; no runtime service is replaced. + Object.defineProperty(ctx, 'dispose', { + configurable: true, + enumerable: false, + value: () => disposeOfficialContext(ctx) + }); + return ctx; +} + +/** + * Boot the selected official Harness profile in-process and return its root Context. + * DSHX owns only presentation lifetime. Project and DSH-home environment and + * live patch behavior intentionally follow the official DSH profile launcher. + */ +export async function bootDshxRuntime({ + cwd = process.cwd(), + profile, + environment = loadLayeredEnv(DSH_PROFILE_BIN_NAME, cwd), + overlays = [], + home, + watch = true +} = {}) { + const options = { profile, overlays, home }; + const composition = dshxRuntimeProfile(options); + let ctx; + try { + ctx = await boot( + NAME, + composition.rootConfig, + structuredClone(composition.patches), + (hostCtx) => { + hostCtx.provide(DSH_LAUNCH_ENVIRONMENT_KEY, environment); + } + // No bareModuleBaseUrl: match the official CLI so row names resolve + // from the profile directory (Node walks /node_modules then + // the healed $DSH_HOME/profiles/node_modules fallback). Anchoring every + // import to the installation would make third-party surface bundles + // — including ours — unresolvable. + ); + attachPresentationLifetime(ctx); + if (watch) await installProfileWatchers(ctx, options); + return ctx; + } catch (error) { + if (ctx) { + try { + await disposeOfficialContext(ctx); + } catch (disposeError) { + if (error && typeof error === 'object') { + try { Object.defineProperty(error, 'dshxCleanupError', { value: disposeError }); } catch {} + } + } + } + throw error; + } +} + +export const runtimeInternals = { + NAME, + DSH_PROFILE_BIN_NAME, + DEFAULT_PROFILE, + PROFILE_ROOT_FILENAME, + PROFILE_ROOT_CONFIG, + SUPPORTED_DSH_LINE, + reportDshLineCompatibility, + installationAnchor, + selectedProfile, + profileHome, + homePatchPath, + installProfileWatchers, + disposeOfficialContext, + attachPresentationLifetime +}; diff --git a/.release/dshx-linux-x64/src/dsh/session-fork.mjs b/.release/dshx-linux-x64/src/dsh/session-fork.mjs new file mode 100644 index 00000000..0482b66e --- /dev/null +++ b/.release/dshx-linux-x64/src/dsh/session-fork.mjs @@ -0,0 +1,55 @@ +function turnNumber(turnId) { + const match = /^dsh-turn-(\d+)$/.exec(String(turnId ?? '')); + if (!match) throw new Error(`DSHX cannot map Codex turn id to DSH turn: ${JSON.stringify(turnId)}`); + const value = Number(match[1]); + if (!Number.isSafeInteger(value) || value < 0) throw new Error(`Invalid DSH turn id: ${turnId}`); + return value; +} + +function completedTurnEnd(events, turn) { + return (events ?? []).find((event) => event?.type === 'turn/end' && event.data?.turn === turn); +} + +/** + * Translate Codex's fork presentation anchors into the one `atSeq` hint owned + * by DSH Host `sessions.fork`. This function deliberately does NOT select or + * copy a seed, decide lineage, inherit model state, or create a Session. + */ +export function codexForkAtSeq(events = [], { lastTurnId, beforeTurnId } = {}) { + if (lastTurnId != null && beforeTurnId != null) { + throw new Error('thread/fork lastTurnId and beforeTurnId are mutually exclusive'); + } + + if (lastTurnId != null) { + const turn = turnNumber(lastTurnId); + const end = completedTurnEnd(events, turn); + if (!end || !Number.isInteger(end.seq)) { + throw new Error(`DSH session has no completed ${lastTurnId}`); + } + return end.seq; + } + + if (beforeTurnId != null) { + const turn = turnNumber(beforeTurnId); + const start = (events ?? []).find((event) => event?.type === 'turn/start' && event.data?.turn === turn); + if (!start || !Number.isInteger(start.seq)) { + throw new Error(`DSH session has no ${beforeTurnId}`); + } + const priorEnds = (events ?? []).filter((event) => + event?.type === 'turn/end' + && Number.isInteger(event.seq) + && event.seq < start.seq + ); + const prior = priorEnds.at(-1); + if (!prior) { + throw new Error('DSH Host fork cannot represent a Codex beforeTurnId before the first completed turn'); + } + return prior.seq; + } + + // Omission is meaningful: the official DSH Host chooses the latest completed + // turn, including its own handling for live/cold sessions and open tails. + return undefined; +} + +export const forkInternals = { turnNumber, completedTurnEnd }; diff --git a/.release/dshx-linux-x64/src/dsh/session-projector.mjs b/.release/dshx-linux-x64/src/dsh/session-projector.mjs new file mode 100644 index 00000000..8fe644ab --- /dev/null +++ b/.release/dshx-linux-x64/src/dsh/session-projector.mjs @@ -0,0 +1,427 @@ +const nowSeconds = () => Math.floor(Date.now() / 1000); +const nowMillis = () => Date.now(); + +function parseJsonOrString(value) { + if (typeof value !== 'string') return value ?? null; + try { return JSON.parse(value); } catch { return value; } +} + +function visibleText(message) { + return (message?.content ?? []) + .filter((block) => block?.type === 'text' && typeof block.text === 'string') + .map((block) => block.text) + .join(''); +} + +function reasoningContent(message) { + return (message?.content ?? []) + .filter((block) => block?.type === 'reasoning' && typeof block.text === 'string') + .map((block) => block.text); +} + +function toolResultCallId(data) { + const sourceId = data?.message?.source?.kind === 'tool' ? data.message.source.callId : undefined; + if (sourceId !== undefined) return sourceId; + const block = data?.message?.content?.find?.((entry) => entry?.type === 'tool-result'); + return block?.toolCallId; +} + +function toolResultFailed(data) { + const block = data?.message?.content?.find?.((entry) => entry?.type === 'tool-result'); + return Boolean(block?.isError ?? data?.error); +} + +function mapTurnStatus(reason) { + switch (reason?.kind) { + case 'completed': return 'completed'; + case 'aborted': + case 'interrupted': return 'interrupted'; + default: return 'failed'; + } +} + +function mapPlanStatus(status) { + if (status === 'in_progress') return 'inProgress'; + if (status === 'completed') return 'completed'; + return 'pending'; +} + +function turnRecord(id, status, startedAt, completedAt = null, error = null) { + return { + id, + items: [], + itemsView: 'full', + status, + error, + startedAt, + completedAt, + durationMs: startedAt != null && completedAt != null + ? Math.max(0, (completedAt - startedAt) * 1000) + : null + }; +} + +function compactionError(message) { + return message == null + ? null + : { message: String(message), codexErrorInfo: null, additionalDetails: null }; +} + +/** + * Stateful presentation projection of official DSH Session events. + * Durable truth stays in DSH; all maps here are disposable UI correlation. + */ +export class DshSessionProjector { + constructor({ threadId, sessionId = threadId, toolPresentation = null } = {}) { + if (!threadId) throw new Error('DshSessionProjector requires threadId'); + this.threadId = threadId; + this.sessionId = sessionId; + this.toolPresentation = toolPresentation; + this.turns = new Map(); + this.assistantItems = new Map(); + this.reasoningItems = new Map(); + this.tools = new Map(); + this.compactions = new Map(); + this.currentTurn = null; + this.latestHeader = null; + this.latestContext = null; + } + + project(event) { + if (!event || typeof event.type !== 'string') return []; + switch (event.type) { + case 'turn/start': return this.turnStarted(event); + case 'turn/end': return this.turnEnded(event); + case 'assistant/chunk': return this.assistantChunk(event); + case 'assistant/message': return this.assistantMessage(event); + case 'tool/call': return this.toolCall(event); + case 'tool/result': return this.toolResult(event); + case 'todo/write': return this.todoWrite(event); + case 'compaction/start': return this.compactionStarted(event); + case 'compaction/summary': return this.compactionSummarized(event); + case 'compaction/end': return this.compactionEnded(event); + case 'request/header': + this.latestHeader = event.data?.header ?? null; + return []; + case 'request/context': + this.latestContext = event.data ?? null; + return []; + default: + return []; + } + } + + turnStarted(event) { + const dshTurn = event.data?.turn; + if (!Number.isInteger(dshTurn)) return []; + const turnId = `dsh-turn-${dshTurn}`; + const startedAt = Number.isFinite(event.time) ? Math.floor(event.time / 1000) : nowSeconds(); + this.turns.set(dshTurn, { id: turnId, startedAt }); + this.currentTurn = dshTurn; + return [{ method: 'turn/started', params: { threadId: this.threadId, turn: turnRecord(turnId, 'inProgress', startedAt) } }]; + } + + turnEnded(event) { + const dshTurn = event.data?.turn; + const state = this.turns.get(dshTurn); + if (!state) return []; + const reason = event.data?.reason; + const status = mapTurnStatus(reason); + const completedAt = Number.isFinite(event.time) ? Math.floor(event.time / 1000) : nowSeconds(); + const error = status === 'failed' && reason?.kind === 'error' + ? { message: reason.error?.message ?? 'DSH turn failed', codexErrorInfo: null, additionalDetails: null } + : null; + if (this.currentTurn === dshTurn) this.currentTurn = null; + return [{ method: 'turn/completed', params: { threadId: this.threadId, turn: turnRecord(state.id, status, state.startedAt, completedAt, error) } }]; + } + + compactionStarted(event) { + const { compactionId, turn } = event.data ?? {}; + if (typeof compactionId !== 'string' || compactionId.length === 0) return []; + const startedAt = Number.isFinite(event.time) ? Math.floor(event.time / 1000) : nowSeconds(); + const startedAtMs = Number.isFinite(event.time) ? event.time : nowMillis(); + const item = { type: 'contextCompaction', id: `dsh-compaction-${compactionId}` }; + let turnId; + let manual = false; + const events = []; + if (Number.isInteger(turn)) { + const state = this.turns.get(turn); + if (!state) return []; + turnId = state.id; + } else if (turn === null) { + manual = true; + turnId = `dsh-maintenance-compaction-${compactionId}`; + events.push({ + method: 'turn/started', + params: { threadId: this.threadId, turn: turnRecord(turnId, 'inProgress', startedAt) } + }); + } else { + return []; + } + this.compactions.set(compactionId, { + compactionId, + turnId, + manual, + startedAt, + item, + summarized: false + }); + events.push({ + method: 'item/started', + params: { threadId: this.threadId, turnId, startedAtMs, item } + }); + return events; + } + + compactionSummarized(event) { + const compactionId = event.data?.compactionId; + const state = this.compactions.get(compactionId); + if (state) state.summarized = true; + return []; + } + + compactionEnded(event) { + const { compactionId, error } = event.data ?? {}; + const state = this.compactions.get(compactionId); + if (!state) return []; + this.compactions.delete(compactionId); + const completedAtMs = Number.isFinite(event.time) ? event.time : nowMillis(); + const completedAt = Math.floor(completedAtMs / 1000); + const events = [{ + method: 'item/completed', + params: { + threadId: this.threadId, + turnId: state.turnId, + completedAtMs, + item: state.item + } + }]; + if (state.manual) { + events.push({ + method: 'turn/completed', + params: { + threadId: this.threadId, + turn: turnRecord( + state.turnId, + error == null ? 'completed' : 'failed', + state.startedAt, + completedAt, + compactionError(error) + ) + } + }); + } + return events; + } + + assistantChunk(event) { + const { turn, step, chunk } = event.data ?? {}; + if (!Number.isInteger(turn) || !Number.isInteger(step) || !chunk) return []; + const turnState = this.turns.get(turn); + if (!turnState) return []; + + if (chunk.type === 'reasoning-delta' && typeof chunk.text === 'string') { + const key = `${turn}:${step}`; + let item = this.reasoningItems.get(key); + const events = []; + if (!item) { + item = { id: `dsh-reasoning-${turn}-${step}`, content: [] }; + this.reasoningItems.set(key, item); + events.push({ + method: 'item/started', + params: { + threadId: this.threadId, + turnId: turnState.id, + startedAtMs: Number.isFinite(event.time) ? event.time : nowMillis(), + item: { type: 'reasoning', id: item.id, summary: [], content: [] } + } + }); + } + const index = Number.isInteger(chunk.index) && chunk.index >= 0 ? chunk.index : 0; + item.content[index] = `${item.content[index] ?? ''}${chunk.text}`; + events.push({ + method: 'item/reasoning/textDelta', + params: { + threadId: this.threadId, + turnId: turnState.id, + itemId: item.id, + delta: chunk.text, + contentIndex: index + } + }); + return events; + } + + if (chunk.type !== 'text-delta' || typeof chunk.text !== 'string') return []; + const key = `${turn}:${step}`; + let item = this.assistantItems.get(key); + const events = []; + if (!item) { + item = { id: `dsh-assistant-${turn}-${step}`, text: '' }; + this.assistantItems.set(key, item); + events.push({ + method: 'item/started', + params: { + threadId: this.threadId, + turnId: turnState.id, + startedAtMs: Number.isFinite(event.time) ? event.time : nowMillis(), + item: { type: 'agentMessage', id: item.id, text: '', phase: null, memoryCitation: null, delivery: null } + } + }); + } + item.text += chunk.text; + events.push({ + method: 'item/agentMessage/delta', + params: { threadId: this.threadId, turnId: turnState.id, itemId: item.id, delta: chunk.text } + }); + return events; + } + + assistantMessage(event) { + const { turn, step, message } = event.data ?? {}; + if (!Number.isInteger(turn) || !Number.isInteger(step) || !message) return []; + const turnState = this.turns.get(turn); + if (!turnState) return []; + const key = `${turn}:${step}`; + const completedAtMs = Number.isFinite(event.time) ? event.time : nowMillis(); + const events = []; + + const finalReasoning = reasoningContent(message); + let reasoning = this.reasoningItems.get(key); + if (reasoning || finalReasoning.length > 0) { + if (!reasoning) { + reasoning = { id: `dsh-reasoning-${turn}-${step}`, content: [] }; + this.reasoningItems.set(key, reasoning); + events.push({ + method: 'item/started', + params: { + threadId: this.threadId, + turnId: turnState.id, + startedAtMs: completedAtMs, + item: { type: 'reasoning', id: reasoning.id, summary: [], content: [] } + } + }); + } + reasoning.content = finalReasoning.length > 0 ? finalReasoning : reasoning.content; + events.push({ + method: 'item/completed', + params: { + threadId: this.threadId, + turnId: turnState.id, + completedAtMs, + item: { type: 'reasoning', id: reasoning.id, summary: [], content: reasoning.content } + } + }); + } + + const finalText = visibleText(message); + let item = this.assistantItems.get(key); + if (!item && finalText.length > 0) { + item = { id: `dsh-assistant-${turn}-${step}`, text: '' }; + this.assistantItems.set(key, item); + events.push({ + method: 'item/started', + params: { + threadId: this.threadId, + turnId: turnState.id, + startedAtMs: completedAtMs, + item: { type: 'agentMessage', id: item.id, text: '', phase: null, memoryCitation: null, delivery: null } + } + }); + } + if (item) { + item.text = finalText; + events.push({ + method: 'item/completed', + params: { + threadId: this.threadId, + turnId: turnState.id, + completedAtMs, + item: { type: 'agentMessage', id: item.id, text: finalText, phase: null, memoryCitation: null, delivery: null } + } + }); + } + return events; + } + + toolCall(event) { + const { turn, callId, name, arguments: rawArguments } = event.data ?? {}; + const turnState = this.turns.get(turn); + if (!turnState || !callId || typeof name !== 'string') return []; + const startedAtMs = Number.isFinite(event.time) ? event.time : nowMillis(); + + let item; + if (this.toolPresentation) { + ({ item } = this.toolPresentation.start({ + turnId: turnState.id, + callId, + name, + rawArguments, + startedAtMs + })); + } else { + item = { + type: 'dynamicToolCall', + id: `dsh-tool-${String(callId)}`, + namespace: null, + tool: name, + arguments: parseJsonOrString(rawArguments), + status: 'inProgress', + contentItems: null, + success: null, + durationMs: null + }; + this.tools.set(String(callId), { item, turnId: turnState.id, startedAt: startedAtMs }); + } + + return [{ method: 'item/started', params: { threadId: this.threadId, turnId: turnState.id, startedAtMs, item } }]; + } + + toolResult(event) { + const callId = toolResultCallId(event.data); + if (callId === undefined) return []; + const completedAtMs = Number.isFinite(event.time) ? event.time : nowMillis(); + + if (this.toolPresentation) { + const completed = this.toolPresentation.complete({ callId, resultData: event.data, completedAtMs }); + if (!completed) return []; + return [{ + method: 'item/completed', + params: { + threadId: this.threadId, + turnId: completed.state.turnId, + completedAtMs, + item: completed.item + } + }]; + } + + const state = this.tools.get(String(callId)); + if (!state) return []; + const failed = toolResultFailed(event.data); + const completed = { + ...state.item, + status: failed ? 'failed' : 'completed', + success: !failed, + durationMs: Math.max(0, completedAtMs - state.startedAt) + }; + this.tools.delete(String(callId)); + return [{ method: 'item/completed', params: { threadId: this.threadId, turnId: state.turnId, completedAtMs, item: completed } }]; + } + + todoWrite(event) { + if (this.currentTurn == null) return []; + const turnState = this.turns.get(this.currentTurn); + if (!turnState) return []; + const todos = Array.isArray(event.data?.todos) ? event.data.todos : []; + return [{ + method: 'turn/plan/updated', + params: { + threadId: this.threadId, + turnId: turnState.id, + explanation: null, + plan: todos.map((todo) => ({ step: String(todo.content ?? ''), status: mapPlanStatus(todo.status) })) + } + }]; + } +} diff --git a/.release/dshx-linux-x64/src/dsh/skills.mjs b/.release/dshx-linux-x64/src/dsh/skills.mjs new file mode 100644 index 00000000..a5ec249b --- /dev/null +++ b/.release/dshx-linux-x64/src/dsh/skills.mjs @@ -0,0 +1,67 @@ +import path from 'node:path'; + +function requireSkills(ctx) { + const skills = ctx.get('skills'); + if (skills === undefined) throw new Error('DSHX requires DSH service: skills'); + return skills; +} + +function codexScope(source) { + if (source === 'project-dsh' || source === 'project-agents') return 'repo'; + if (source === 'user-dsh' || source === 'user-agents') return 'user'; + return 'system'; +} + +/** + * Project the subset of DSH skills that Codex's filesystem-oriented skill UI + * can represent faithfully. DSH remains the complete skill registry; a remote + * or runtime skill with no absolute file path is not fabricated into a path. + */ +export async function dshSkillsListEntry({ ctx, cwd, scope, diagnostics = () => {} }) { + const absoluteCwd = path.resolve(cwd); + const skills = requireSkills(ctx); + const options = { cwd: absoluteCwd, ...(scope === undefined ? {} : { scope }) }; + const snapshot = await skills.snapshot(options); + const data = []; + const errors = []; + + if (snapshot.complete !== true) { + errors.push({ + path: absoluteCwd, + message: 'DSH skill discovery was incomplete; available candidates are shown without claiming the catalog is authoritative' + }); + } + + for (const summary of snapshot.skills ?? []) { + if (summary?.invocation?.userInvocable !== true) continue; + try { + const definition = await skills.get(summary.name, options); + if (!definition) { + errors.push({ path: summary.name, message: 'DSH skill disappeared before it could be loaded' }); + continue; + } + if (typeof definition.path !== 'string' || !path.isAbsolute(definition.path)) { + // Codex SkillMetadata requires an absolute filesystem path. The DSH + // registry explicitly permits provider-managed skills without one. + diagnostics(`skill ${summary.name} is user-invocable but has no absolute filesystem path; omitted from Codex skill UI`); + continue; + } + data.push({ + name: definition.name, + description: definition.description, + path: definition.path, + scope: codexScope(definition.source), + enabled: true + }); + } catch (error) { + errors.push({ + path: summary.name, + message: error instanceof Error ? error.message : String(error) + }); + } + } + + return { cwd: absoluteCwd, skills: data, errors }; +} + +export const skillInternals = { codexScope }; diff --git a/.release/dshx-linux-x64/src/dsh/startup-plugin.mjs b/.release/dshx-linux-x64/src/dsh/startup-plugin.mjs new file mode 100644 index 00000000..fedacfe3 --- /dev/null +++ b/.release/dshx-linux-x64/src/dsh/startup-plugin.mjs @@ -0,0 +1,72 @@ +import fs from 'node:fs'; +import os from 'node:os'; +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; +import z from '@deepseek-ai/schemastery'; + +/** + * dshx-startup — the surface's command-line/environment resolution row. + * + * Mirrors the official three-stage launch pattern (see @deepseek-ai/dsh-headless + * `startup`): a tiny host-plane plugin that turns launcher-provided inputs into + * one provided service (`dshxStartup`) so downstream rows stay declarative. + * Inputs come from the documented DSHX_* environment overrides with packaged + * defaults; no argv parsing, so bare `dsh --profile tui` boots identically. + */ + +const PACKAGE_ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../..'); +let cachedVersion; + +/** Stable Cordis plugin name. */ +export const name = 'dshx-startup'; + +/** Environment + packaged defaults only; nothing is a hard service dependency. */ +export const inject = []; + +/** Reserved for future static overrides supplied straight from the patch row. */ +export const Config = z.object({}); + +/** Resolve the package version once from our own manifest. */ +export function resolveVersion() { + cachedVersion ??= JSON.parse(fs.readFileSync(path.join(PACKAGE_ROOT, 'package.json'), 'utf8')).version; + return cachedVersion; +} + +/** Packaged-binary resolution shared by the TUI and the IPC bridge. */ +export function resolvePackagedBinary(baseName, envValue) { + if (envValue) return envValue; + const fileName = process.platform === 'win32' ? `${baseName}.exe` : baseName; + return path.join(PACKAGE_ROOT, 'dist', 'bin', fileName); +} + +/** Compute the launch descriptor published as the `dshxStartup` service. */ +export function resolveLaunchDescriptor(environment = process.env) { + const home = path.resolve( + environment.DSHX_TUI_HOME || path.join(os.homedir(), '.dshx', 'codex-tui') + ); + return { + cwd: process.cwd(), + home, + version: resolveVersion(), + tuiCommand: resolvePackagedBinary('dshx-tui', environment.DSHX_TUI_BIN), + bridgeCommand: resolvePackagedBinary('dshx-ipc-bridge', environment.DSHX_IPC_BRIDGE_BIN), + debug: environment.DSHX_DEBUG === '1' + }; +} + +export function apply(ctx) { + const launch = resolveLaunchDescriptor(); + fs.mkdirSync(launch.home, { recursive: true, mode: 0o700 }); + ctx.provide('dshxStartup', launch); + return undefined; +} + +/** Bundle-shaped export consumed by the loader through the patch row. */ +export const plugin = { name, inject, Config, apply }; + +export const internals = { + PACKAGE_ROOT, + resolveLaunchDescriptor, + resolvePackagedBinary, + resolveVersion +}; diff --git a/.release/dshx-linux-x64/src/dsh/thread-controller.mjs b/.release/dshx-linux-x64/src/dsh/thread-controller.mjs new file mode 100644 index 00000000..23a550c0 --- /dev/null +++ b/.release/dshx-linux-x64/src/dsh/thread-controller.mjs @@ -0,0 +1,205 @@ +import { DshSessionProjector } from './session-projector.mjs'; +import { tokenUsageNotification } from './token-usage.mjs'; +import { DshToolPresentationResolver } from './tool-presentation.mjs'; + +function deferred(timeoutMs, label) { + let resolve; + let reject; + let timer; + const promise = new Promise((res, rej) => { + resolve = res; + reject = rej; + timer = setTimeout(() => rej(new Error(`Timed out waiting for ${label}`)), timeoutMs); + }); + return { + promise, + resolve(value) { clearTimeout(timer); resolve(value); }, + reject(error) { clearTimeout(timer); reject(error); } + }; +} + +function usageRelevant(event) { + return event?.type === 'assistant/message' + || event?.type === 'request/context' + || (event?.type === 'assistant/chunk' && event.data?.chunk?.type === 'usage'); +} + +/** + * Owns only the presentation lifetime for one already-created DSH Agent. + * The Agent and Session remain authoritative and are never reconstructed here. + */ +export class DshThreadController { + constructor({ handle, driver, emit = () => {}, turnStartTimeoutMs = 15_000, diagnostics = () => {} }) { + if (!handle?.agent) throw new Error('DshThreadController requires a DSH AgentHandle'); + this.handle = handle; + this.agent = handle.agent; + this.driver = driver; + this.emit = emit; + this.turnStartTimeoutMs = turnStartTimeoutMs; + this.diagnostics = diagnostics; + + this.toolPresentation = typeof this.agent.ctx?.get === 'function' + ? new DshToolPresentationResolver({ + ctx: this.agent.ctx, + agent: this.agent, + threadId: String(this.agent.id), + workspaceCwd: this.agent.session?.header?.cwd ?? process.cwd(), + diagnostics + }) + : null; + + this.projector = new DshSessionProjector({ + threadId: String(this.agent.id), + sessionId: String(this.agent.id), + toolPresentation: this.toolPresentation + }); + this.pendingTurnStart = null; + this.responseGate = null; + this.preparedUserContent = null; + this.lastTokenUsageSignature = null; + this.closed = false; + + const onSessionEvent = (session, event) => this.onSessionEvent(session, event); + this.disposeSessionListener = this.agent.ctx.on('session/event', onSessionEvent); + } + + get threadId() { + return String(this.agent.id); + } + + toolCorrelation(callId) { + return this.toolPresentation?.correlation(callId); + } + + currentLocation() { + const number = this.projector.currentTurn; + if (!Number.isInteger(number)) return undefined; + const turn = this.projector.turns.get(number); + if (!turn) return undefined; + return { threadId: this.threadId, turnId: turn.id }; + } + + /** + * Stage rich Codex input for exactly one existing base-adapter turn/steer call. + * The base adapter still owns all model/cwd/permission/sandbox validation. + */ + prepareUserContent(content) { + if (this.preparedUserContent != null) throw new Error('DSHX rich input slot is already occupied'); + const slot = { content }; + this.preparedUserContent = slot; + return () => { + if (this.preparedUserContent === slot) this.preparedUserContent = null; + }; + } + + consumeUserContent(fallback) { + const slot = this.preparedUserContent; + this.preparedUserContent = null; + return slot?.content ?? fallback; + } + + deliver(notification) { + if (this.responseGate && !this.responseGate.released) { + this.responseGate.buffered.push(notification); + return; + } + this.emit(notification); + } + + maybeProjectTokenUsage(event) { + if (!usageRelevant(event)) return; + const location = this.currentLocation(); + if (!location) return; + try { + const notification = tokenUsageNotification({ + ctx: this.agent.ctx, + session: this.agent.session, + threadId: location.threadId, + turnId: location.turnId + }); + if (!notification) return; + const signature = JSON.stringify(notification.params.tokenUsage); + if (signature === this.lastTokenUsageSignature) return; + this.lastTokenUsageSignature = signature; + this.deliver(notification); + } catch (error) { + this.diagnostics(`token usage projection failed: ${error instanceof Error ? error.message : error}`); + } + } + + onSessionEvent(session, event) { + if (this.closed || session !== this.agent.session) return; + const projected = this.projector.project(event); + for (const notification of projected) { + if (notification.method === 'turn/started' && this.pendingTurnStart) { + const pending = this.pendingTurnStart; + this.pendingTurnStart = null; + const gate = { + firstNotification: notification, + buffered: [], + released: false + }; + this.responseGate = gate; + pending.resolve({ turn: notification.params.turn, gate }); + continue; + } + this.deliver(notification); + } + this.maybeProjectTokenUsage(event); + } + + /** Submit a normal follow-up and wait until DSH itself commits turn/start. */ + async startTurn(fallbackContent) { + if (this.pendingTurnStart || (this.responseGate && !this.responseGate.released)) { + throw new Error('A turn/start request is already awaiting DSHX protocol release'); + } + const content = this.consumeUserContent(fallbackContent); + const pending = deferred(this.turnStartTimeoutMs, 'DSH turn/start'); + this.pendingTurnStart = pending; + try { + this.driver.followup(this.agent, content); + const { turn, gate } = await pending.promise; + return { + turn, + release: () => { + if (gate.released) return; + gate.released = true; + if (this.responseGate === gate) this.responseGate = null; + this.emit(gate.firstNotification); + for (const notification of gate.buffered) this.emit(notification); + gate.buffered.length = 0; + } + }; + } catch (error) { + if (this.pendingTurnStart === pending) this.pendingTurnStart = null; + throw error; + } + } + + steer(fallbackContent) { + this.driver.steer(this.agent, this.consumeUserContent(fallbackContent)); + } + + interrupt(options) { + this.driver.interrupt(this.agent, options); + } + + whenIdle() { + return this.driver.whenIdle(this.agent); + } + + async close() { + if (this.closed) return; + this.closed = true; + this.pendingTurnStart?.reject(new Error('DSHX thread controller closed')); + this.pendingTurnStart = null; + this.preparedUserContent = null; + if (this.responseGate && !this.responseGate.released) { + this.responseGate.released = true; + this.responseGate.buffered.length = 0; + } + this.responseGate = null; + this.disposeSessionListener?.(); + await this.handle.dispose?.(); + } +} diff --git a/.release/dshx-linux-x64/src/dsh/thread-title.mjs b/.release/dshx-linux-x64/src/dsh/thread-title.mjs new file mode 100644 index 00000000..afda2f90 --- /dev/null +++ b/.release/dshx-linux-x64/src/dsh/thread-title.mjs @@ -0,0 +1,19 @@ +export function foldDshSessionTitle(events = []) { + for (let index = events.length - 1; index >= 0; index -= 1) { + const event = events[index]; + if (event?.type !== 'session/title') continue; + const title = event.data?.title; + if (typeof title === 'string' && title.length > 0) return title; + } + return null; +} + +export function threadNameUpdatedNotification(threadId, title) { + return { + method: 'thread/name/updated', + params: { + threadId: String(threadId), + threadName: title == null ? null : String(title) + } + }; +} diff --git a/.release/dshx-linux-x64/src/dsh/token-usage.mjs b/.release/dshx-linux-x64/src/dsh/token-usage.mjs new file mode 100644 index 00000000..cafce57c --- /dev/null +++ b/.release/dshx-linux-x64/src/dsh/token-usage.mjs @@ -0,0 +1,116 @@ +function finiteNonNegative(value) { + return Number.isFinite(value) && value >= 0 ? Number(value) : 0; +} + +function breakdown(usage = {}) { + const inputTokens = finiteNonNegative(usage.inputTokens ?? usage.uncachedInputTokens); + const cachedInputTokens = finiteNonNegative(usage.cacheReadTokens); + const cacheWriteInputTokens = finiteNonNegative(usage.cacheWriteTokens); + const outputTokens = finiteNonNegative(usage.outputTokens); + const reasoningOutputTokens = finiteNonNegative(usage.reasoningTokens); + return { + totalTokens: inputTokens + cachedInputTokens + cacheWriteInputTokens + outputTokens, + inputTokens, + cachedInputTokens, + cacheWriteInputTokens, + outputTokens, + reasoningOutputTokens + }; +} + +function usageSamples(events = []) { + const byStep = new Map(); + let last = null; + let lastTurn = null; + for (const event of events) { + const data = event?.data; + if (!Number.isInteger(data?.turn) || !Number.isInteger(data?.step)) continue; + let usage; + if (event.type === 'assistant/chunk' && data.chunk?.type === 'usage') { + usage = data.chunk.usage; + } else if (event.type === 'assistant/message' && data.usage) { + usage = data.usage; + } + if (!usage) continue; + const sample = { ...usage }; + byStep.set(`${data.turn}:${data.step}`, sample); + last = sample; + lastTurn = data.turn; + } + return { byStep, last, lastTurn }; +} + +function reasoningTotal(events = []) { + const { byStep } = usageSamples(events); + let total = 0; + for (const usage of byStep.values()) total += finiteNonNegative(usage.reasoningTokens); + return total; +} + +function latestContextWindow(events = []) { + for (let index = events.length - 1; index >= 0; index -= 1) { + const event = events[index]; + if (event?.type === 'request/context' && Number.isFinite(event.data?.contextWindow)) { + return Number(event.data.contextWindow); + } + } + return null; +} + +/** + * Read-only presentation snapshot over official DSH session projections. + * DSH token-meter owns accounting; this module only reshapes its values into + * the pinned Codex TUI contract. + */ +export function codexThreadTokenUsage({ ctx, session }) { + const projections = ctx?.get?.('sessionProjections'); + if (!session || !projections?.snapshot) return null; + const snapshot = projections.snapshot(session); + const cumulative = snapshot?.values?.tokenUsage; + if (!cumulative) return null; + + const events = session.events ?? []; + const { last } = usageSamples(events); + const total = breakdown({ + inputTokens: cumulative.uncachedInputTokens, + cacheReadTokens: cumulative.cacheReadTokens, + cacheWriteTokens: cumulative.cacheWriteTokens, + outputTokens: cumulative.outputTokens, + reasoningTokens: reasoningTotal(events) + }); + const contextWindow = Number.isFinite(snapshot?.values?.contextPressure?.contextWindow) + ? Number(snapshot.values.contextPressure.contextWindow) + : latestContextWindow(events); + + return { + total, + last: breakdown(last ?? {}), + modelContextWindow: contextWindow + }; +} + +export function latestTokenUsageTurnId(session) { + const { lastTurn } = usageSamples(session?.events ?? []); + return Number.isInteger(lastTurn) ? `dsh-turn-${lastTurn}` : null; +} + +export function tokenUsageNotification({ ctx, session, threadId, turnId }) { + const tokenUsage = codexThreadTokenUsage({ ctx, session }); + if (!tokenUsage || !threadId || !turnId) return null; + return { + method: 'thread/tokenUsage/updated', + params: { threadId, turnId, tokenUsage } + }; +} + +export function persistedTokenUsageNotification({ ctx, session, threadId }) { + const turnId = latestTokenUsageTurnId(session); + return tokenUsageNotification({ ctx, session, threadId, turnId }); +} + +export const tokenUsageInternals = { + breakdown, + usageSamples, + reasoningTotal, + latestContextWindow +}; diff --git a/.release/dshx-linux-x64/src/dsh/tool-presentation.mjs b/.release/dshx-linux-x64/src/dsh/tool-presentation.mjs new file mode 100644 index 00000000..4396c471 --- /dev/null +++ b/.release/dshx-linux-x64/src/dsh/tool-presentation.mjs @@ -0,0 +1,219 @@ +import path from 'node:path'; + +function parseArguments(raw) { + if (typeof raw !== 'string') return raw ?? {}; + try { return JSON.parse(raw); } catch { return { raw }; } +} + +function toolResultFromEvent(data) { + const block = data?.message?.content?.find?.((entry) => entry?.type === 'tool-result'); + return { + content: Array.isArray(block?.content) ? block.content : [], + isError: Boolean(block?.isError ?? data?.error), + ...(data?.meta === undefined ? {} : { meta: data.meta }) + }; +} + +function textContentItems(content) { + const items = []; + for (const block of content ?? []) { + if (block?.type === 'text' && typeof block.text === 'string') { + items.push({ type: 'inputText', text: block.text }); + } + } + return items.length === 0 ? null : items; +} + +function resolveCwd(workspaceCwd, candidate) { + if (!candidate) return workspaceCwd; + return path.isAbsolute(candidate) ? candidate : path.resolve(workspaceCwd, candidate); +} + +function lineCount(text) { + if (text === '') return 0; + return text.split(/\r?\n/).length; +} + +function displayDiff(file) { + // DSH FileDiff may represent a contextual hunk rather than whole-file text. + // Codex only needs display diff text here; avoid fabricating source line numbers. + const oldLines = String(file.oldText ?? '').split(/\r?\n/); + const newLines = String(file.newText ?? '').split(/\r?\n/); + const oldCount = lineCount(String(file.oldText ?? '')); + const newCount = lineCount(String(file.newText ?? '')); + return [ + `--- a/${file.path}`, + `+++ b/${file.path}`, + `@@ -1,${oldCount} +1,${newCount} @@`, + ...oldLines.map((line) => `-${line}`), + ...newLines.map((line) => `+${line}`) + ].join('\n'); +} + +function canUseCodexFileChange(view) { + return view?.card === 'diff' && + Array.isArray(view.diffs) && + view.diffs.length > 0 && + view.diffs.every((diff) => typeof diff?.path === 'string' && diff.oldText !== null); +} + +function fileChangeItem(id, view, status) { + return { + type: 'fileChange', + id, + changes: view.diffs.map((diff) => ({ + path: diff.path, + kind: { type: 'update', move_path: null }, + diff: displayDiff(diff) + })), + status + }; +} + +function dynamicItem(id, toolName, args, status, result = null, durationMs = null) { + return { + type: 'dynamicToolCall', + id, + namespace: null, + tool: toolName, + arguments: args, + status, + contentItems: result ? textContentItems(result.content) : null, + success: result ? !result.isError : null, + durationMs + }; +} + +/** + * Resolves UI semantics exclusively through DSH ToolDefinition presenters. + * + * No tool names or argument schemas are embedded here. `ctx.tools.get(name, + * agent)` is authoritative for the definition visible to this Agent; its pure + * `presentCall/presentResult` methods decide terminal/diff/generic intent. + */ +export class DshToolPresentationResolver { + constructor({ ctx, agent, threadId, workspaceCwd = process.cwd(), diagnostics = () => {} }) { + if (!ctx || typeof ctx.get !== 'function') throw new Error('DshToolPresentationResolver requires a Cordis Context'); + if (!agent) throw new Error('DshToolPresentationResolver requires a DSH Agent'); + this.ctx = ctx; + this.agent = agent; + this.threadId = String(threadId ?? agent.id); + this.workspaceCwd = path.resolve(workspaceCwd); + this.diagnostics = diagnostics; + this.calls = new Map(); + } + + definition(name) { + return this.ctx.get('tools')?.get?.(name, this.agent); + } + + start({ turnId, callId, name, rawArguments, startedAtMs = Date.now() }) { + const args = parseArguments(rawArguments); + const definition = this.definition(name); + let view; + try { view = definition?.presentCall?.(args); } + catch (error) { this.diagnostics(`presentCall(${name}): ${error instanceof Error ? error.message : error}`); } + + const id = `dsh-tool-${String(callId)}`; + let item; + let semantic = 'generic'; + if (view?.card === 'terminal') { + semantic = 'command'; + item = { + type: 'commandExecution', + id, + pluginId: null, + scriptPath: null, + command: view.title, + cwd: resolveCwd(this.workspaceCwd, view.cwd), + processId: null, + source: 'agent', + status: 'inProgress', + commandActions: [], + aggregatedOutput: null, + exitCode: null, + durationMs: null + }; + } else if (canUseCodexFileChange(view)) { + semantic = 'fileChange'; + item = fileChangeItem(id, view, 'inProgress'); + } else { + // DSH `oldText:null` is intentionally ambiguous between create and + // overwrite, while Codex requires add/delete/update. Stay generic rather + // than fabricate a PatchChangeKind. + item = dynamicItem(id, name, args, 'inProgress'); + } + + const state = { + callId: String(callId), + name, + args, + definition, + callView: view, + semantic, + item, + turnId, + startedAtMs + }; + this.calls.set(String(callId), state); + return { item, state }; + } + + complete({ callId, resultData, completedAtMs = Date.now() }) { + const state = this.calls.get(String(callId)); + if (!state) return undefined; + const result = toolResultFromEvent(resultData); + let view; + try { view = state.definition?.presentResult?.(state.args, result); } + catch (error) { this.diagnostics(`presentResult(${state.name}): ${error instanceof Error ? error.message : error}`); } + const durationMs = Math.max(0, completedAtMs - state.startedAtMs); + + let item; + if (state.semantic === 'command') { + const terminal = view?.card === 'terminal' ? view : undefined; + const failed = result.isError || Boolean(terminal?.signal) || + (terminal?.exitCode !== undefined && terminal.exitCode !== 0); + item = { + ...state.item, + status: failed ? 'failed' : 'completed', + aggregatedOutput: terminal?.output ?? textContentItems(result.content)?.map((entry) => entry.text).join('\n') ?? null, + exitCode: terminal?.exitCode ?? null, + durationMs + }; + } else if (state.semantic === 'fileChange') { + item = view?.card === 'diff' && canUseCodexFileChange(view) + ? fileChangeItem(state.item.id, view, result.isError ? 'failed' : 'completed') + : { ...state.item, status: result.isError ? 'failed' : 'completed' }; + } else { + item = dynamicItem( + state.item.id, + state.name, + state.args, + result.isError ? 'failed' : 'completed', + result, + durationMs + ); + } + + state.item = item; + state.resultView = view; + state.result = result; + return { item, state }; + } + + correlation(callId) { + const state = this.calls.get(String(callId)); + if (!state) return undefined; + return { + threadId: this.threadId, + turnId: state.turnId, + itemId: state.item.id, + semantic: state.semantic, + ...(state.semantic === 'command' + ? { kind: 'command', command: state.item.command, cwd: state.item.cwd } + : state.semantic === 'fileChange' + ? { kind: 'fileChange' } + : {}) + }; + } +} diff --git a/.release/dshx-linux-x64/src/dsh/user-input.mjs b/.release/dshx-linux-x64/src/dsh/user-input.mjs new file mode 100644 index 00000000..b1084826 --- /dev/null +++ b/.release/dshx-linux-x64/src/dsh/user-input.mjs @@ -0,0 +1,106 @@ +import fs from 'node:fs/promises'; +import path from 'node:path'; + +const MEDIA_TYPES = new Map([ + ['.png', 'image/png'], + ['.jpg', 'image/jpeg'], + ['.jpeg', 'image/jpeg'], + ['.webp', 'image/webp'], + ['.gif', 'image/gif'] +]); + +function requireAttachments(ctx) { + const attachments = ctx?.get?.('attachments'); + if (!attachments?.saveImages) throw new Error('DSHX image input requires DSH service: attachments.saveImages'); + return attachments; +} + +function localMediaType(filePath) { + const mediaType = MEDIA_TYPES.get(path.extname(filePath).toLowerCase()); + if (!mediaType) throw new Error(`Unsupported local image type: ${path.extname(filePath) || ''}`); + return mediaType; +} + +function parseDataImage(url) { + const match = /^data:(image\/(?:png|jpeg|webp|gif));base64,([A-Za-z0-9+/=\r\n]+)$/i.exec(String(url ?? '')); + if (!match) return undefined; + return { + mediaType: match[1].toLowerCase(), + data: Buffer.from(match[2].replace(/[\r\n]/g, ''), 'base64') + }; +} + +function skillGesture(name) { + const value = String(name ?? ''); + if (!/^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(value)) { + throw new Error(`Invalid DSH skill name from Codex input: ${JSON.stringify(name)}`); + } + return `/${value}`; +} + +/** + * Convert pinned Codex UserInput into the public DSH UserContent vocabulary. + * Images are committed through DSH's attachment service before their refs are + * placed in the durable user message. User-explicit skills deliberately remain + * plain `/name` gestures because that is DSH's authoritative pre-step seam. + */ +export async function codexInputToDshContent(ctx, inputs = []) { + if (!Array.isArray(inputs)) throw new Error('Codex input must be an array'); + const plan = []; + const pendingImages = []; + + for (const input of inputs) { + switch (input?.type) { + case 'text': + if (typeof input.text !== 'string') throw new Error('Codex text input requires text'); + plan.push({ kind: 'content', block: { type: 'text', text: input.text } }); + break; + case 'skill': + plan.push({ kind: 'content', block: { type: 'text', text: skillGesture(input.name) } }); + break; + case 'localImage': { + if (typeof input.path !== 'string' || input.path.length === 0) { + throw new Error('Codex localImage input requires path'); + } + const filePath = path.resolve(input.path); + const mediaType = localMediaType(filePath); + const data = await fs.readFile(filePath); + const imageIndex = pendingImages.length; + pendingImages.push({ data, mediaType, name: path.basename(filePath) }); + plan.push({ kind: 'image', imageIndex }); + break; + } + case 'image': { + const inline = parseDataImage(input.url); + if (!inline) { + throw new Error('DSHX accepts Codex image input only as localImage or data:image/*; remote image URLs remain provider-owned'); + } + const imageIndex = pendingImages.length; + pendingImages.push({ ...inline, name: `pasted-image-${imageIndex + 1}` }); + plan.push({ kind: 'image', imageIndex }); + break; + } + case 'mention': + throw new Error('DSHX does not yet project Codex structured mentions into a DSH user message'); + default: + throw new Error(`Unsupported Codex user input type: ${JSON.stringify(input?.type)}`); + } + } + + const refs = pendingImages.length > 0 + ? await requireAttachments(ctx).saveImages(pendingImages) + : []; + return plan.map((entry) => entry.kind === 'image' + ? { type: 'image', ref: refs[entry.imageIndex] } + : entry.block); +} + +export function dshContentText(content = []) { + return content + .filter((block) => block?.type === 'text' && typeof block.text === 'string') + .map((block) => block.text) + .join('\n') + .trim(); +} + +export const inputInternals = { localMediaType, parseDataImage, skillGesture }; diff --git a/.release/dshx-linux-x64/src/dsh/user-question-bridge.mjs b/.release/dshx-linux-x64/src/dsh/user-question-bridge.mjs new file mode 100644 index 00000000..8e1a4b49 --- /dev/null +++ b/.release/dshx-linux-x64/src/dsh/user-question-bridge.mjs @@ -0,0 +1,101 @@ +function requireService(ctx, name) { + const service = ctx.get(name); + if (service === undefined) throw new Error(`DSHX requires DSH service: ${name}`); + return service; +} + +function codexQuestion(question) { + const prompt = question.detail === undefined + ? question.question + : `${question.question}\n\n${question.detail}`; + return { + id: question.id, + header: question.header ?? 'Question', + question: prompt, + isOther: true, + isSecret: false, + options: question.options === undefined + ? null + : question.options.map((option) => ({ + label: option.label, + description: option.description ?? '' + })) + }; +} + +function dshAnswer(question, response) { + const values = response?.answers?.[question.id]?.answers ?? []; + const labels = new Set((question.options ?? []).map((option) => option.label)); + const selected = values.filter((value) => labels.has(value)); + const custom = values.filter((value) => !labels.has(value)); + return { + id: question.id, + selected, + ...(custom.length === 0 ? {} : { custom: custom.join('\n') }) + }; +} + +/** + * UI provider for the official DSH `ctx.userQuestions` seam. + * + * DSH's public AskUserQuestionRequest deliberately has no tool call id. The + * bridge therefore asks its owner for a PRESENTATION interaction location; a + * Codex client may attach the dialog to a synthetic UI-only item for the live + * DSH turn instead of guessing which parallel tool call caused the question. + * No question/answer semantics or durable state are owned here. + */ +export class DshUserQuestionBridge { + constructor({ ctx, broker, locate, complete = () => {}, diagnostics = () => {} }) { + if (!ctx || typeof ctx.get !== 'function') throw new Error('DshUserQuestionBridge requires a Cordis Context'); + if (!broker) throw new Error('DshUserQuestionBridge requires a UiRequestBroker'); + if (typeof locate !== 'function') throw new Error('DshUserQuestionBridge requires locate(request)'); + if (typeof complete !== 'function') throw new Error('DshUserQuestionBridge complete must be a function'); + this.ctx = ctx; + this.broker = broker; + this.locate = locate; + this.complete = complete; + this.diagnostics = diagnostics; + this.disposeProvider = requireService(ctx, 'userQuestions').registerProvider({ + ask: (request) => this.ask(request) + }); + } + + async ask(request) { + if (request.questions.some((question) => question.multiSelect === true)) { + throw new Error('DSHX pinned Codex TUI does not yet represent DSH multi-select questions faithfully'); + } + const location = await this.locate(request); + if (!location?.threadId || !location?.turnId || !location?.itemId) { + throw new Error('DSHX could not open a Codex presentation item for the DSH user question'); + } + + try { + const response = await this.broker.request( + 'item/tool/requestUserInput', + { + threadId: location.threadId, + turnId: location.turnId, + itemId: location.itemId, + questions: request.questions.map(codexQuestion), + isBlocking: true, + autoResolutionMs: null + }, + { signal: request.signal } + ); + const answer = { answers: request.questions.map((question) => dshAnswer(question, response)) }; + await this.complete(location, { status: 'completed', answer }); + return answer; + } catch (error) { + this.diagnostics(error instanceof Error ? error.message : String(error)); + try { await this.complete(location, { status: 'failed', error }); } catch (completeError) { + this.diagnostics(completeError instanceof Error ? completeError.message : String(completeError)); + } + throw error; + } + } + + dispose() { + this.disposeProvider?.(); + this.disposeProvider = undefined; + } +} diff --git a/.release/dshx-linux-x64/src/dsh/user-shell.mjs b/.release/dshx-linux-x64/src/dsh/user-shell.mjs new file mode 100644 index 00000000..313dcd06 --- /dev/null +++ b/.release/dshx-linux-x64/src/dsh/user-shell.mjs @@ -0,0 +1,209 @@ +import { randomUUID } from 'node:crypto'; + +function seconds(ms = Date.now()) { + return Math.floor(ms / 1000); +} + +function turnRecord(id, status, startedAt, completedAt = null, error = null) { + return { + id, + items: [], + itemsView: 'full', + status, + error, + startedAt, + completedAt, + durationMs: completedAt == null ? null : Math.max(0, (completedAt - startedAt) * 1000) + }; +} + +function errorRecord(message) { + return { message: String(message), codexErrorInfo: null, additionalDetails: null }; +} + +function resultData(callId, result) { + return { + message: { + source: { kind: 'tool', callId }, + content: [{ + type: 'tool-result', + toolCallId: callId, + content: Array.isArray(result?.content) ? result.content : [], + isError: Boolean(result?.isError) + }] + }, + ...(result?.meta === undefined ? {} : { meta: result.meta }) + }; +} + +function pickTool(agent) { + const tools = agent.ctx?.get?.('tools'); + if (!tools) throw new Error('DSHX user shell requires DSH service: tools'); + const preferred = process.platform === 'win32' ? ['pwsh', 'bash'] : ['bash', 'pwsh']; + for (const name of preferred) { + if (tools.get?.(name, agent)) return { tools, name }; + } + throw new Error('No DSH shell tool is visible in the current Agent scope'); +} + +/** + * Presentation-only bridge for Codex `!` commands. Execution still goes through + * the official DSH ToolRuntime, so pre-execute policy, guards, approval, + * sandboxing, timeouts, post-policy and result normalization all remain DSH-owned. + * Like Codex's own user-shell action, these cells are intentionally not durable + * conversation history. + */ +export class DshUserShellBridge { + constructor({ send, diagnostics = () => {} } = {}) { + if (typeof send !== 'function') throw new Error('DshUserShellBridge requires send(message)'); + this.send = send; + this.diagnostics = diagnostics; + this.active = new Map(); + } + + start(controller, command) { + const threadId = String(controller?.threadId ?? controller?.agent?.id ?? ''); + if (!threadId) throw new Error('thread/shellCommand requires a resumed DSH thread'); + if (typeof command !== 'string' || command.trim().length === 0) { + throw new Error('thread/shellCommand requires a non-empty command'); + } + if (this.active.has(threadId)) throw new Error('A DSHX user-shell command is already active for this thread'); + + const existing = controller.currentLocation(); + const callId = `dshx-user-shell-${randomUUID()}`; + const turnId = existing?.turnId ?? `dsh-user-shell-turn-${randomUUID()}`; + const maintenance = existing == null; + const startedAtMs = Date.now(); + const abortController = new AbortController(); + const state = { + threadId, + turnId, + callId, + maintenance, + startedAtMs, + abortController, + controller, + command + }; + this.active.set(threadId, state); + + return { + result: {}, + afterResponse: () => { + void this.run(state); + } + }; + } + + async run(state) { + const { threadId, turnId, callId, maintenance, startedAtMs, abortController, controller, command } = state; + try { + if (maintenance) { + this.send({ + method: 'turn/started', + params: { threadId, turn: turnRecord(turnId, 'inProgress', seconds(startedAtMs)) } + }); + } + + const { tools, name } = pickTool(controller.agent); + const args = { + command, + description: 'Run command from interactive user shell', + workdir: controller.agent.session?.header?.cwd, + run_in_background: false + }; + const projected = controller.toolPresentation?.start({ + turnId, + callId, + name, + rawArguments: args, + startedAtMs + }); + if (!projected || projected.state.semantic !== 'command') { + throw new Error(`DSH shell tool ${name} does not expose terminal presentation semantics`); + } + projected.item.source = 'userShell'; + projected.state.item = projected.item; + this.send({ + method: 'item/started', + params: { threadId, turnId, startedAtMs, item: projected.item } + }); + + const result = await tools.execute({ + callId, + name, + arguments: args, + signal: abortController.signal, + agent: controller.agent + }); + const completedAtMs = Date.now(); + const completed = controller.toolPresentation.complete({ + callId, + resultData: resultData(callId, result), + completedAtMs + }); + if (!completed) throw new Error(`DSHX lost user-shell presentation correlation for ${callId}`); + completed.item.source = 'userShell'; + this.send({ + method: 'item/completed', + params: { threadId, turnId, completedAtMs, item: completed.item } + }); + if (maintenance) { + const completedAt = seconds(completedAtMs); + this.send({ + method: 'turn/completed', + params: { + threadId, + turn: turnRecord( + turnId, + result?.isError ? 'failed' : 'completed', + seconds(startedAtMs), + completedAt, + result?.isError ? errorRecord(result.error?.message ?? 'DSH shell command failed') : null + ) + } + }); + } + } catch (error) { + const message = error instanceof Error ? error.message : String(error); + this.diagnostics(`user shell ${threadId}: ${message}`); + if (maintenance) { + const completedAt = seconds(); + this.send({ + method: 'turn/completed', + params: { + threadId, + turn: turnRecord(turnId, 'failed', seconds(startedAtMs), completedAt, errorRecord(message)) + } + }); + } else { + this.send({ method: 'warning', params: { threadId, message } }); + } + } finally { + if (this.active.get(threadId) === state) this.active.delete(threadId); + } + } + + interrupt(threadId, turnId) { + const state = this.active.get(String(threadId)); + if (!state || state.turnId !== String(turnId)) return false; + state.abortController.abort(new Error('user cancelled DSHX shell command')); + return true; + } + + abortThread(threadId, reason = 'thread closed') { + const state = this.active.get(String(threadId)); + if (!state) return false; + state.abortController.abort(new Error(reason)); + return true; + } + + close() { + for (const state of this.active.values()) { + state.abortController.abort(new Error('DSHX adapter closing')); + } + this.active.clear(); + } +} + +export const userShellInternals = { pickTool, resultData, turnRecord }; diff --git a/.release/dshx-linux-x64/src/dsh/workspace-command.mjs b/.release/dshx-linux-x64/src/dsh/workspace-command.mjs new file mode 100644 index 00000000..89867393 --- /dev/null +++ b/.release/dshx-linux-x64/src/dsh/workspace-command.mjs @@ -0,0 +1,166 @@ +import path from 'node:path'; +import { randomUUID } from 'node:crypto'; + +function shellTool(agent) { + const tools = agent?.ctx?.get?.('tools'); + if (!tools) throw new Error('DSHX workspace command requires DSH service: tools'); + const preferred = process.platform === 'win32' ? ['pwsh', 'bash'] : ['bash', 'pwsh']; + for (const name of preferred) { + if (tools.get?.(name, agent)) return { tools, name }; + } + throw new Error('No DSH shell tool is visible in the active Agent scope'); +} + +function bashQuote(value) { + const text = String(value); + if (text.includes('\0')) throw new Error('command/exec argv cannot contain NUL'); + return `'${text.replaceAll("'", `'"'"'`)}'`; +} + +function pwshQuote(value) { + const text = String(value); + if (text.includes('\0')) throw new Error('command/exec argv cannot contain NUL'); + return `'${text.replaceAll("'", "''")}'`; +} + +function envName(name) { + if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(name)) { + throw new Error(`command/exec environment key is not portable: ${JSON.stringify(name)}`); + } + return name; +} + +function commandText(argv, env, dialect) { + const quote = dialect === 'pwsh' ? pwshQuote : bashQuote; + const invocation = dialect === 'pwsh' + ? `& ${argv.map(quote).join(' ')}` + : argv.map(quote).join(' '); + const entries = Object.entries(env ?? {}); + if (entries.length === 0) return invocation; + + if (dialect === 'pwsh') { + const prefix = entries.map(([rawName, value]) => { + const name = envName(rawName); + return value == null + ? `Remove-Item Env:${name} -ErrorAction SilentlyContinue` + : `$env:${name} = ${quote(value)}`; + }); + return `${prefix.join('; ')}; ${invocation}`; + } + + const prefix = entries.map(([rawName, value]) => { + const name = envName(rawName); + return value == null ? `unset ${name}` : `export ${name}=${quote(value)}`; + }); + return `${prefix.join('; ')}; ${invocation}`; +} + +function textError(result) { + return (result?.content ?? []) + .filter((block) => block?.type === 'text' && typeof block.text === 'string') + .map((block) => block.text) + .join('\n') + .trim(); +} + +function capUtf8(text, limit) { + if (!Number.isSafeInteger(limit) || limit < 0) return text; + const bytes = Buffer.from(String(text), 'utf8'); + if (bytes.length <= limit) return String(text); + let end = Math.min(limit, bytes.length); + while (end > 0 && (bytes[end] & 0b1100_0000) === 0b1000_0000) end -= 1; + return bytes.subarray(0, end).toString('utf8'); +} + +function bufferedResult(result, params) { + if (result?.isError) { + throw new Error(textError(result) || result.error?.message || 'DSH workspace command failed'); + } + const value = result?.value; + if (!value || value.kind !== 'foreground') { + throw new Error(`DSH shell returned non-foreground command/exec result: ${JSON.stringify(value?.kind)}`); + } + const exitCode = Number.isInteger(value.exitCode) ? value.exitCode : 1; + const cap = params.disableOutputCap === true ? undefined : params.outputBytesCap; + return { + exitCode, + stdout: capUtf8(value.stdout?.text ?? '', cap), + stderr: capUtf8(value.stderr?.text ?? '', cap) + }; +} + +function validateParams(params) { + if (!Array.isArray(params.command) || params.command.length === 0 || params.command.some((entry) => typeof entry !== 'string' || entry.length === 0)) { + throw new Error('command/exec requires a non-empty argv string array'); + } + if (params.processId != null || params.tty === true || params.streamStdin === true || params.streamStdoutStderr === true || params.size != null) { + throw new Error('DSHX command/exec supports buffered non-TTY workspace commands only'); + } + if (params.disableTimeout === true) { + throw new Error('DSHX command/exec does not override the DSH shell executor timeout policy'); + } + if (params.outputBytesCap != null && params.disableOutputCap === true) { + throw new Error('command/exec outputBytesCap and disableOutputCap are mutually exclusive'); + } + if (params.timeoutMs != null && (!Number.isSafeInteger(params.timeoutMs) || params.timeoutMs <= 0)) { + throw new Error('command/exec timeoutMs must be a positive integer'); + } + if (params.sandboxPolicy != null || params.permissionProfile != null) { + throw new Error('DSHX command/exec uses the active DSH session permission policy and rejects Codex policy overrides'); + } +} + +/** + * TUI-owned one-off workspace probes (`git`, `/diff`, status metadata) mapped + * onto the official DSH shell tool runtime. No process is spawned by DSHX. + */ +export class DshWorkspaceCommandBridge { + constructor({ driver } = {}) { + if (!driver?.listRootAgents) throw new Error('DshWorkspaceCommandBridge requires DshAgentDriver'); + this.driver = driver; + } + + agentFor(cwd) { + const roots = this.driver.listRootAgents(); + if (roots.length === 0) throw new Error('command/exec requires an active DSH root Agent'); + if (cwd != null) { + const wanted = path.resolve(cwd); + const matches = roots.filter((agent) => path.resolve(agent.session?.header?.cwd ?? process.cwd()) === wanted); + if (matches.length === 1) return matches[0]; + if (matches.length > 1) throw new Error(`command/exec cwd matches multiple active DSH Agents: ${wanted}`); + } + if (roots.length === 1) return roots[0]; + throw new Error('command/exec cannot choose among multiple active DSH root Agents without an exact cwd match'); + } + + async execute(params = {}) { + validateParams(params); + const agent = this.agentFor(params.cwd); + const { tools, name } = shellTool(agent); + const args = { + command: commandText(params.command, params.env, name), + description: 'Run DSHX TUI workspace command', + workdir: params.cwd ?? agent.session?.header?.cwd, + run_in_background: false, + ...(params.timeoutMs == null ? {} : { timeoutMs: params.timeoutMs }) + }; + const result = await tools.execute({ + callId: `dshx-workspace-${randomUUID()}`, + name, + arguments: args, + signal: new AbortController().signal, + agent + }); + return bufferedResult(result, params); + } +} + +export const workspaceCommandInternals = { + bashQuote, + pwshQuote, + commandText, + bufferedResult, + validateParams, + capUtf8, + shellTool +}; diff --git a/.release/dshx-linux-x64/src/protocol/request-broker.mjs b/.release/dshx-linux-x64/src/protocol/request-broker.mjs new file mode 100644 index 00000000..dd4787fa --- /dev/null +++ b/.release/dshx-linux-x64/src/protocol/request-broker.mjs @@ -0,0 +1,79 @@ +function makeAbortError(message = 'The request was aborted') { + const error = new Error(message); + error.name = 'AbortError'; + return error; +} + +/** + * Correlates app-server requests initiated by DSHX with responses from the TUI. + * The broker owns no approval policy: transport loss, timeout and cancellation + * reject the presentation request so the DSH answerer can fail closed. + */ +export class UiRequestBroker { + constructor({ send, timeoutMs = 120_000, idPrefix = 'dshx-ui' } = {}) { + if (typeof send !== 'function') throw new Error('UiRequestBroker requires send(message)'); + this.send = send; + this.timeoutMs = timeoutMs; + this.idPrefix = idPrefix; + this.nextId = 1; + this.pending = new Map(); + this.closed = false; + } + + request(method, params, { signal } = {}) { + if (this.closed) return Promise.reject(new Error('UI request broker is closed')); + if (signal?.aborted) return Promise.reject(makeAbortError()); + + const id = `${this.idPrefix}-${this.nextId++}`; + return new Promise((resolve, reject) => { + const cleanup = () => { + clearTimeout(entry.timer); + signal?.removeEventListener('abort', entry.onAbort); + this.pending.delete(id); + }; + const entry = { + resolve: (value) => { cleanup(); resolve(value); }, + reject: (error) => { cleanup(); reject(error); }, + onAbort: () => entry.reject(makeAbortError()), + timer: undefined + }; + entry.timer = setTimeout( + () => entry.reject(new Error(`UI request timed out: ${method}`)), + this.timeoutMs + ); + signal?.addEventListener('abort', entry.onAbort, { once: true }); + this.pending.set(id, entry); + + try { + this.send({ id, method, params }); + } catch (error) { + entry.reject(error instanceof Error ? error : new Error(String(error))); + } + }); + } + + /** + * Consume a client response (`{id,result}` or `{id,error}`). Returns false + * when the id does not belong to an outstanding server-initiated request. + */ + handleResponse(message) { + if (!message || message.id === undefined || message.method !== undefined) return false; + const entry = this.pending.get(String(message.id)); + if (!entry) return false; + if (message.error !== undefined) { + const error = new Error(message.error?.message ?? 'TUI request failed'); + error.code = message.error?.code; + entry.reject(error); + } else { + entry.resolve(message.result); + } + return true; + } + + close(reason = 'UI transport closed') { + if (this.closed) return; + this.closed = true; + const entries = [...this.pending.values()]; + for (const entry of entries) entry.reject(new Error(reason)); + } +} diff --git a/.release/dshx-linux-x64/src/tui-protocol/adapter.mjs b/.release/dshx-linux-x64/src/tui-protocol/adapter.mjs new file mode 100644 index 00000000..2dfaa111 --- /dev/null +++ b/.release/dshx-linux-x64/src/tui-protocol/adapter.mjs @@ -0,0 +1,1302 @@ +import crypto from 'node:crypto'; +import os from 'node:os'; +import path from 'node:path'; +import { DshAgentDriver } from '../dsh/agent-driver.mjs'; +import { DshApprovalBridge } from '../dsh/approval-bridge.mjs'; +import { + codexModelsFromDsh, + decodeDshModel, + dshThreadFromSnapshot, + dshTurnsFromSession, + encodeDshModel, + normalizeCodexEffort, + normalizeSessionHeaders +} from './shapes.mjs'; +import { executeDshCommand } from '../dsh/commands.mjs'; +import { dshThreadItemsPage, dshThreadTurnsPage } from '../dsh/history-pages.mjs'; +import { DshHostApi } from '../dsh/host-api.mjs'; +import { codexPlanTarget, threadSettingsUpdatedNotification } from '../dsh/plan-presentation.mjs'; +import { DshPermissionView } from '../dsh/permissions.mjs'; +import { codexForkAtSeq } from '../dsh/session-fork.mjs'; +import { dshSkillsListEntry } from '../dsh/skills.mjs'; +import { foldDshSessionTitle, threadNameUpdatedNotification } from '../dsh/thread-title.mjs'; +import { DshThreadController } from '../dsh/thread-controller.mjs'; +import { codexInputToDshContent, dshContentText } from '../dsh/user-input.mjs'; +import { DshUserQuestionBridge } from '../dsh/user-question-bridge.mjs'; +import { DshUserShellBridge } from '../dsh/user-shell.mjs'; +import { persistedTokenUsageNotification } from '../dsh/token-usage.mjs'; +import { DshWorkspaceCommandBridge } from '../dsh/workspace-command.mjs'; +import { UiRequestBroker } from '../protocol/request-broker.mjs'; + +const INVALID_REQUEST = -32600; +const METHOD_NOT_FOUND = -32601; +const INVALID_PARAMS = -32602; +const INTERNAL_ERROR = -32603; + +function platformFamily() { + return process.platform === 'win32' ? 'windows' : 'unix'; +} + +function platformOs() { + if (process.platform === 'darwin') return 'macos'; + if (process.platform === 'win32') return 'windows'; + if (process.platform === 'linux') return 'linux'; + return process.platform; +} + +function codexApprovalToDsh(value) { + if (value == null) return undefined; + if (value === 'on-request') return 'ask'; + if (value === 'never') return 'never'; + throw new Error(`DSHX cannot map Codex approval policy ${JSON.stringify(value)} to DSH`); +} + +// Base turn input validation. Distinct from the steer variant below because +// the two historically reported different unsupported-input messages. +function turnTextInput(params) { + const inputs = Array.isArray(params?.input) ? params.input : []; + const unsupported = inputs.filter((item) => item?.type !== 'text'); + if (unsupported.length > 0) { + throw new Error(`DSHX turn input currently supports Codex text items only; got ${unsupported.map((item) => item?.type).join(', ')}`); + } + return inputs.map((item) => item.text ?? '').join('\n').trim(); +} + +function steerTextInput(params) { + const inputs = Array.isArray(params?.input) ? params.input : []; + const unsupported = inputs.filter((item) => item?.type !== 'text'); + if (unsupported.length > 0) { + throw new Error(`DSHX steer currently supports Codex text items only; got ${unsupported.map((item) => item?.type).join(', ')}`); + } + return inputs.map((item) => item.text ?? '').join('\n').trim(); +} + +function pagination(value, total, defaultLimit = 50) { + const cursor = value?.cursor == null ? 0 : Number(value.cursor); + if (!Number.isSafeInteger(cursor) || cursor < 0) throw new Error('invalid pagination cursor'); + const requested = value?.limit == null ? defaultLimit : Number(value.limit); + if (!Number.isSafeInteger(requested) || requested <= 0) throw new Error('limit must be a positive integer'); + const end = Math.min(total, cursor + requested); + return { start: cursor, end, nextCursor: end < total ? String(end) : null }; +} + +function sandboxMatchesCurrent(sandbox, permission) { + if (sandbox == null) return true; + if (sandbox.type === 'dangerFullAccess') return permission.dsh.sandboxMode === 'danger-full-access'; + if (sandbox.type === 'externalSandbox') { + return permission.dsh.sandboxMode === 'read-only' || permission.dsh.sandboxMode === 'workspace-write'; + } + return false; +} + +function fullThreadSnapshot(agent, { includeTurns = false, cliVersion = 'dshx' } = {}) { + const turns = includeTurns ? dshTurnsFromSession({ ctx: agent.ctx, agent }) : []; + return dshThreadFromSnapshot({ + meta: agent.session.header, + events: agent.session.events, + model: agent.session.requestHeader?.()?.config, + turns, + loaded: true, + cliVersion + }); +} + +function dshPermissionPreset(ctx, codexId) { + const presets = ctx.get('permissionPresets'); + if (!presets) throw new Error('DSHX requires DSH service: permissionPresets'); + const mapped = codexId === ':workspace' + ? 'workspace-write' + : codexId === ':danger-full-access' + ? 'danger-full-access' + : codexId === ':read-only' + ? 'read-only' + : codexId; + if (!presets.names.includes(mapped)) { + throw new Error(`DSH has no permission preset corresponding to Codex profile ${JSON.stringify(codexId)}`); + } + return mapped; +} + +function codexPermissionProfileId(preset) { + if (preset === 'workspace-write') return ':workspace'; + if (preset === 'danger-full-access') return ':danger-full-access'; + if (preset === 'read-only') return ':read-only'; + if (preset === 'custom' || preset == null) return null; + return preset; +} + +function hasSupportedThreadSetting(params) { + return params.model != null + || params.effort != null + || params.permissions != null + || params.approvalPolicy != null; +} + +function snapshotTitle(snapshot) { + return typeof snapshot?.title === 'string' && snapshot.title.length > 0 ? snapshot.title : null; +} + +function isDshSubagent(agent) { + return agent?.session?.header?.origin === 'subagent'; +} + +/** + * Single presentation adapter from pinned Codex app-server JSON-RPC to + * official DSH public services. + * + * This class is the linearization of the former three-layer inheritance chain + * (app-server-adapter -> product-adapter -> release-adapter). Method bodies + * are kept verbatim per layer; `_Base` / `_ProductLayer` + * helpers preserve the exact call order the old `super.*` chain executed, so + * behavior is unchanged while "which dispatch actually runs" no longer spans + * three files. It owns no Agent loop, provider routing, tool dispatch, + * persistence, sandbox enforcement, approval policy or user-question semantics. + */ +export class DshxPresentationAdapter { + constructor({ + ctx, + send, + cwd = process.cwd(), + home = path.join(os.homedir(), '.dshx'), + version = '0.1.0-dev', + diagnostics = () => {} + }) { + if (!ctx || typeof ctx.get !== 'function') throw new Error('DshAppServerAdapter requires a Cordis Context'); + if (typeof send !== 'function') throw new Error('DshAppServerAdapter requires send(message)'); + this.ctx = ctx; + this.send = send; + this.cwd = path.resolve(cwd); + this.home = path.resolve(home); + this.version = version; + this.diagnostics = diagnostics; + this.driver = new DshAgentDriver(ctx); + this.permissions = new DshPermissionView(ctx); + this.broker = new UiRequestBroker({ send }); + this.controllers = new Map(); + this.approvals = new Map(); + this.syntheticInteractions = new Map(); + this.readyPromise = null; + this.userQuestions = null; + this.closed = false; + } + + // ── readiness ──────────────────────────────────────────────────────────── + + async ensureReady() { + await this.ensureReadyBase(); + if (this._agentPresentationDisposers) return; + this._agentPresentationDisposers = [ + this.ctx.on('agent/created', ({ agent }) => { + if (!isDshSubagent(agent)) return; + try { + this.send({ method: 'thread/started', params: { thread: this.liveAgentThread(agent) } }); + } catch (error) { + this.diagnostics(`subagent thread/started projection failed for ${String(agent?.id ?? '')}: ${error instanceof Error ? error.message : error}`); + } + }), + this.ctx.on('agent/status', ({ agent, status }) => { + try { + this.send({ + method: 'thread/status/changed', + params: { + threadId: String(agent.id), + status: status === 'running' ? { type: 'active', activeFlags: [] } : { type: 'idle' } + } + }); + } catch (error) { + this.diagnostics(`agent status projection failed for ${String(agent?.id ?? '')}: ${error instanceof Error ? error.message : error}`); + } + }), + this.ctx.on('agent/disposed', ({ agent }) => { + try { + this.send({ + method: 'thread/status/changed', + params: { threadId: String(agent.id), status: { type: 'notLoaded' } } + }); + } catch (error) { + this.diagnostics(`agent disposal projection failed for ${String(agent?.id ?? '')}: ${error instanceof Error ? error.message : error}`); + } + }) + ]; + } + + async ensureReadyBase() { + if (this.readyPromise) return this.readyPromise; + this.readyPromise = (async () => { + const loader = this.ctx.get('loader'); + if (loader?.await) await loader.await(); + if (!this.userQuestions && this.ctx.get('userQuestions')) { + this.userQuestions = new DshUserQuestionBridge({ + ctx: this.ctx, + broker: this.broker, + locate: (request) => this.openSyntheticInteraction(request), + complete: (location, outcome) => this.completeSyntheticInteraction(location, outcome), + diagnostics: this.diagnostics + }); + } + })(); + return this.readyPromise; + } + + // ── protocol entry ─────────────────────────────────────────────────────── + + async handle(message) { + if (this.broker.handleResponse(message)) return null; + if (!message || message.id === undefined || typeof message.method !== 'string') { + if (message?.id === undefined && typeof message?.method === 'string') return null; + return { response: this.error(message?.id ?? null, INVALID_REQUEST, 'Invalid Request') }; + } + try { + await this.ensureReady(); + const dispatched = await this.dispatch(message.method, message.params ?? {}); + return { + response: { id: message.id, result: dispatched?.result }, + afterResponse: dispatched?.afterResponse + }; + } catch (error) { + const code = error?.code === METHOD_NOT_FOUND ? METHOD_NOT_FOUND + : error?.code === INVALID_PARAMS ? INVALID_PARAMS + : INTERNAL_ERROR; + return { + response: this.error(message.id, code, error instanceof Error ? error.message : String(error)) + }; + } + } + + /** + * Merged dispatch table. Case order mirrors the former inheritance + * linearization: release-layer routing first, then product-layer routing, + * then the base protocol surface. The base layer's dead `skills/list` stub + * (empty data) is gone — the product layer's DSH-backed skillsList owns it. + */ + async dispatch(method, params) { + switch (method) { + // release-layer routing + case 'command/exec': + return this.commandExec(params); + case 'config/batchWrite': + return this.configBatchWrite(params); + case 'thread/name/set': + return this.threadNameSet(params); + case 'thread/shellCommand': + return this.threadShellCommand(params); + case 'thread/fork': + return this.threadForkPresentation(params); + case 'thread/settings/update': + return this.threadSettingsUpdatePresentation(params); + case 'thread/compact/start': + this.directController(params?.threadId, 'direct compaction'); + return this.threadCompactStart(params); + case 'turn/start': + case 'turn/steer': + return this.richUserTurn(method, params); + case 'turn/interrupt': { + if (this.userShell().interrupt(params?.threadId, params?.turnId)) return { result: {} }; + const controller = this.controllers.get(String(params?.threadId ?? '')); + if (controller && isDshSubagent(controller.agent)) return this.interruptSubagent(controller); + return this.turnInterruptProduct(params); + } + case 'thread/unsubscribe': { + const threadId = String(params?.threadId ?? ''); + this.userShell().abortThread(threadId, 'thread unsubscribed'); + this.planListeners().get(threadId)?.(); + this.planListeners().delete(threadId); + this.planMutationSuppressed().delete(threadId); + return this.threadUnsubscribeWithStatus(params); + } + // product-layer routing + case 'account/usage/read': + return this.accountUsageRead(params); + case 'skills/list': + return this.skillsList(params); + case 'thread/turns/list': + return this.threadTurnsList(params); + case 'thread/items/list': + return this.threadItemsList(params); + // base-layer routing (most-derived implementations win at call time) + case 'initialize': + return { + result: { + userAgent: `dshx/${this.version}`, + codexHome: this.home, + platformFamily: platformFamily(), + platformOs: platformOs() + } + }; + case 'account/read': + return { result: { account: null, requiresOpenaiAuth: false } }; + case 'configRequirements/read': + return { result: { requirements: null } }; + case 'model/list': + return this.modelList(params); + case 'thread/list': + return this.threadList(params); + case 'thread/loaded/list': + return this.loadedThreadList(); + case 'thread/start': + return this.threadStart(params); + case 'thread/resume': + return this.threadResume(params); + case 'thread/read': + return this.threadRead(params); + default: { + const error = new Error(`Method not found: ${method}`); + error.code = METHOD_NOT_FOUND; + throw error; + } + } + } + + // ── models and listings ────────────────────────────────────────────────── + + async modelList(params) { + const directory = await this.driver.modelDirectory(); + for (const failure of directory.failures ?? []) { + this.diagnostics(`DSH model catalog ${failure.provider}: ${failure.message}`); + } + const active = this.driver.listRootAgents()[0]; + const current = active + ? this.driver.currentModel(active) + : this.ctx.get('agentDefaultModel')?.currentSelection?.(); + const all = codexModelsFromDsh(directory, current); + const visible = params.includeHidden ? all : all.filter((model) => !model.hidden); + const page = pagination(params, visible.length); + return { result: { data: visible.slice(page.start, page.end), nextCursor: page.nextCursor } }; + } + + async threadList(params = {}) { + const response = await this.threadListBase(params); + const data = await Promise.all(response.result.data.map(async (thread) => { + try { + const snapshot = await this.driver.readTitle(thread.id); + return { ...thread, name: snapshotTitle(snapshot) ?? thread.name ?? null }; + } catch (error) { + this.diagnostics(`title read ${thread.id}: ${error instanceof Error ? error.message : error}`); + return thread; + } + })); + return { result: { ...response.result, data } }; + } + + async threadListBase(params) { + const headers = normalizeSessionHeaders(await this.driver.listSessions()); + const snapshots = await Promise.all(headers.map(async (header) => { + try { + const inspected = await this.driver.inspectSession(String(header.id)); + const meta = inspected?.meta ?? header; + const events = inspected?.events ?? []; + return dshThreadFromSnapshot({ + meta, + events, + loaded: Boolean(this.controllers.has(String(meta.id)) || this.driver.getLive(String(meta.id))), + cliVersion: this.version + }); + } catch (error) { + this.diagnostics(`inspect ${String(header.id)}: ${error instanceof Error ? error.message : error}`); + return undefined; + } + })); + let threads = snapshots.filter(Boolean); + if (params.cwd != null) { + const wanted = new Set((Array.isArray(params.cwd) ? params.cwd : [params.cwd]).map((entry) => path.resolve(entry))); + threads = threads.filter((thread) => wanted.has(path.resolve(thread.cwd))); + } + if (params.searchTerm) { + const needle = String(params.searchTerm).toLowerCase(); + threads = threads.filter((thread) => `${thread.name ?? ''}\n${thread.preview}`.toLowerCase().includes(needle)); + } + if (Array.isArray(params.modelProviders) && params.modelProviders.length > 0) { + const providers = new Set(params.modelProviders); + threads = threads.filter((thread) => providers.has(thread.modelProvider)); + } + threads.sort((a, b) => (params.sortDirection === 'asc' ? 1 : -1) * (a.recencyAt - b.recencyAt)); + const page = pagination(params, threads.length); + return { + result: { + data: threads.slice(page.start, page.end).map((thread) => ({ ...thread, turns: [] })), + nextCursor: page.nextCursor, + backwardsCursor: null + } + }; + } + + loadedThreadList() { + // Pinned Codex ThreadLoadedListResponse.data is Array. Keep rich + // thread metadata on thread/list/read/started and expose only live IDs here. + return { + result: { + data: this.driver.listLive().map((agent) => String(agent.id)) + } + }; + } + + // ── permissions ────────────────────────────────────────────────────────── + + async applyStartPermissions(agent, params = {}) { + if (params.permissions == null) return this.applyStartPermissionsBase(agent, params); + if (params.sandbox != null) { + throw new Error('Codex thread/start permissions and sandbox cannot both be selected for DSHX'); + } + const preset = dshPermissionPreset(this.ctx, String(params.permissions)); + this.permissions.set(agent, preset); + const current = this.permissions.current(agent); + if (params.approvalPolicy != null && current.codex.approvalPolicy !== params.approvalPolicy) { + throw new Error( + `DSH preset ${preset} does not match requested Codex approval policy ${JSON.stringify(params.approvalPolicy)}` + ); + } + return current; + } + + async applyStartPermissionsBase(agent, params) { + const desiredSandbox = params.sandbox; + const desiredApproval = codexApprovalToDsh(params.approvalPolicy); + if (desiredSandbox == null && desiredApproval == null) return this.permissions.current(agent); + + const current = this.permissions.current(agent); + const sandboxMode = desiredSandbox ?? current.dsh.sandboxMode; + const approvalPolicy = desiredApproval ?? current.dsh.approvalPolicy; + const presets = this.ctx.get('permissionPresets'); + const match = presets?.names?.find((name) => { + const preset = presets.resolve(name); + return preset.sandbox === sandboxMode && preset.approval === approvalPolicy; + }); + if (!match) { + throw new Error(`DSHX refuses to synthesize a DSH custom permission bundle (${sandboxMode}, ${approvalPolicy})`); + } + this.permissions.set(agent, match); + return this.permissions.current(agent); + } + + async applyModelOverride(agent, { model, modelProvider, effort } = {}) { + if (model == null && effort == null) return this.driver.currentModel(agent); + let selection; + if (model != null) { + selection = decodeDshModel(model); + if (!selection && modelProvider) selection = { provider: modelProvider, model }; + if (!selection) throw new Error('DSHX accepts model switches only from its DSH-backed model catalog'); + } else { + selection = this.driver.currentModel(agent); + } + const normalizedEffort = normalizeCodexEffort(effort); + if (normalizedEffort !== undefined) selection = { ...selection, reasoningEffort: normalizedEffort }; + return this.driver.selectModel(agent, selection); + } + + installController(handle) { + const controller = this.installControllerBase(handle); + const threadId = String(controller.agent.id); + if (!this.planListeners().has(threadId)) { + const dispose = controller.agent.ctx.on('session/event', (session, event) => { + if (session !== controller.agent.session || event?.type !== 'plan/mode') return; + if (this.planMutationSuppressed().has(threadId)) return; + try { + this.send(this.planSettingsNotification(controller.agent)); + } catch (error) { + this.diagnostics(`plan settings projection failed for ${threadId}: ${error instanceof Error ? error.message : error}`); + } + }); + this.planListeners().set(threadId, dispose); + } + return controller; + } + + installControllerBase(handle) { + const threadId = String(handle.agent.id); + const existing = this.controllers.get(threadId); + if (existing) return existing; + const controller = new DshThreadController({ + handle, + driver: this.driver, + emit: this.send, + diagnostics: this.diagnostics + }); + this.controllers.set(threadId, controller); + const approval = new DshApprovalBridge({ + agent: handle.agent, + broker: this.broker, + classify: (req) => req.callId == null ? null : controller.toolCorrelation(req.callId), + diagnostics: this.diagnostics + }); + this.approvals.set(threadId, approval); + return controller; + } + + // ── thread responses ──────────────────────────────────────────────────── + + threadResponse(agent, options = {}) { + const response = this.threadResponseProductLayer(agent, options); + const folded = this.driver.currentTitle(agent); + const name = snapshotTitle(folded) ?? foldDshSessionTitle(agent.session?.events ?? []); + return { + ...response, + thread: { ...response.thread, name } + }; + } + + threadResponseProductLayer(agent, options = {}) { + const response = this.threadResponseCore(agent, options); + const permission = this.permissions.current(agent); + const id = codexPermissionProfileId(permission.preset); + return { + ...response, + runtimeWorkspaceRoots: [], + activePermissionProfile: id == null ? null : { id, extends: null }, + multiAgentMode: 'explicitRequestOnly', + initialTurnsPage: null, + turnsBackwardsCursor: null, + itemsBackwardsCursor: null + }; + } + + threadResponseCore(agent, { includeTurns = false } = {}) { + const selection = this.driver.currentModel(agent); + const permission = this.permissions.current(agent); + const thread = fullThreadSnapshot(agent, { includeTurns, cliVersion: this.version }); + return { + thread, + model: encodeDshModel(selection), + modelProvider: selection.provider, + serviceTier: null, + cwd: thread.cwd, + instructionSources: [], + approvalPolicy: permission.codex.approvalPolicy, + approvalsReviewer: permission.codex.approvalsReviewer, + sandbox: permission.codex.sandbox, + reasoningEffort: selection.reasoningEffort ?? null + }; + } + + // ── thread lifecycle ───────────────────────────────────────────────────── + + async threadStart(params) { + const sessionId = crypto.randomUUID(); + const cwd = path.resolve(params.cwd ?? this.cwd); + const handle = await this.driver.create({ cwd, sessionId }); + try { + await this.applyModelOverride(handle.agent, params); + await this.applyStartPermissions(handle.agent, params); + this.installController(handle); + const result = this.threadResponse(handle.agent); + return { + result, + afterResponse: () => this.send({ method: 'thread/started', params: { thread: result.thread } }) + }; + } catch (error) { + await handle.dispose?.(); + throw error; + } + } + + async threadResume(params = {}) { + const response = await this.threadResumeProduct(params); + const threadId = String(params.threadId ?? response.result.thread?.id ?? ''); + const agent = this.controllers.get(threadId)?.agent; + const prior = response.afterResponse; + return { + ...response, + afterResponse: () => { + prior?.(); + if (agent) this.send(this.planSettingsNotification(agent)); + } + }; + } + + async threadResumeProduct(params = {}) { + if (!params.threadId) throw new Error('thread/resume requires threadId'); + const threadId = String(params.threadId); + let controller = this.controllers.get(threadId); + if (!controller) { + const live = this.driver.getLive(threadId); + const handle = live + ? { agent: live, dispose: async () => {} } + : await this.driver.resume(threadId); + controller = this.installController(handle); + } + const agent = controller.agent; + if (params.cwd != null && path.resolve(params.cwd) !== path.resolve(agent.session.header?.cwd ?? this.cwd)) { + throw new Error('DSHX does not override a persisted DSH session cwd during resume'); + } + await this.applyModelOverride(agent, params); + await this.applyStartPermissions(agent, params); + const result = this.threadResponse(agent, { + includeTurns: params.excludeTurns !== true + }); + const replay = persistedTokenUsageNotification({ + ctx: this.ctx, + session: agent.session, + threadId + }); + return { + result, + afterResponse: replay ? () => this.send(replay) : undefined + }; + } + + async threadRead(params = {}) { + const response = await this.threadReadBase(params); + const thread = response.result.thread; + try { + const snapshot = await this.driver.readTitle(thread.id); + return { + result: { + ...response.result, + thread: { ...thread, name: snapshotTitle(snapshot) ?? thread.name ?? null } + } + }; + } catch (error) { + this.diagnostics(`title read ${thread.id}: ${error instanceof Error ? error.message : error}`); + return response; + } + } + + async threadReadBase(params) { + if (!params.threadId) throw new Error('thread/read requires threadId'); + const live = this.driver.getLive(String(params.threadId)); + if (live) { + return { result: { thread: fullThreadSnapshot(live, { includeTurns: Boolean(params.includeTurns), cliVersion: this.version }) } }; + } + const inspected = await this.driver.inspectSession(String(params.threadId)); + if (!inspected) throw new Error(`Unknown DSH session: ${String(params.threadId)}`); + return { + result: { + thread: dshThreadFromSnapshot({ + meta: inspected.meta, + events: inspected.events, + loaded: false, + cliVersion: this.version, + // A cold persisted session cannot faithfully use tool presenters + // without a composed Agent. The TUI resumes before requesting rich + // history; avoid fabricating tool semantics on a cold read. + turns: [] + }) + } + }; + } + + async turnStart(params) { + const controller = this.controllers.get(String(params.threadId)); + if (!controller) throw new Error(`Thread is not resumed in DSHX: ${String(params.threadId)}`); + if (params.cwd != null && path.resolve(params.cwd) !== path.resolve(controller.agent.session.header?.cwd ?? this.cwd)) { + throw new Error('DSHX does not own per-turn cwd mutation; resume/start the DSH session in the desired cwd'); + } + if (params.outputSchema != null) throw new Error('DSHX has no faithful public DSH mapping for Codex outputSchema yet'); + + await this.applyModelOverride(controller.agent, { model: params.model, effort: params.effort }); + const permission = this.permissions.current(controller.agent); + const desiredApproval = codexApprovalToDsh(params.approvalPolicy); + if (desiredApproval != null && desiredApproval !== permission.dsh.approvalPolicy) { + throw new Error('Turn-level approval changes must use a DSH permission preset'); + } + if (!sandboxMatchesCurrent(params.sandboxPolicy, permission)) { + throw new Error('Turn-level sandbox changes must use a DSH permission preset'); + } + + const started = await controller.startTurn(turnTextInput(params)); + return { result: { turn: started.turn }, afterResponse: started.release }; + } + + turnInterrupt(params) { + const controller = this.controllers.get(String(params.threadId)); + if (!controller) return { result: {} }; + controller.interrupt({ keepInbox: true }); + return { result: {} }; + } + + async threadUnsubscribe(params) { + const threadId = String(params.threadId ?? ''); + const controller = this.controllers.get(threadId); + if (controller) { + this.approvals.get(threadId)?.dispose(); + this.approvals.delete(threadId); + this.controllers.delete(threadId); + await controller.close(); + } + return { result: {} }; + } + + async threadUnsubscribeWithStatus(params = {}) { + const threadId = String(params.threadId ?? ''); + this.manualCompactions().get(threadId)?.abort(new Error('thread unsubscribed')); + const subscribed = this.controllers.has(threadId); + const loaded = Boolean(this.driver.getLive(threadId)); + await this.threadUnsubscribe(params); + return { + result: { + status: subscribed ? 'unsubscribed' : loaded ? 'notSubscribed' : 'notLoaded' + } + }; + } + + // ── product-layer features ─────────────────────────────────────────────── + + accountUsageRead(_params = {}) { + return { + result: { + summary: { + lifetimeTokens: null, + peakDailyTokens: null, + longestRunningTurnSec: null, + currentStreakDays: null, + longestStreakDays: null + }, + dailyUsageBuckets: null, + threadUsage: null + } + }; + } + + manualCompactions() { + return this._manualCompactions ??= new Map(); + } + + hostApi() { + return this._hostApi ??= new DshHostApi(this.ctx, { cwd: this.cwd }); + } + + warnThread(threadId, message) { + this.send({ method: 'warning', params: { threadId, message } }); + } + + async skillsList(params = {}) { + if (params.forceReload === true) { + this.diagnostics('Codex requested skills forceReload; DSHX is reading the current DSH registry snapshot without overriding provider-owned cache policy'); + } + const cwds = Array.isArray(params.cwds) && params.cwds.length > 0 + ? params.cwds.map((cwd) => path.resolve(cwd)) + : [this.cwd]; + const data = await Promise.all(cwds.map((cwd) => dshSkillsListEntry({ + ctx: this.ctx, + cwd, + diagnostics: this.diagnostics + }))); + return { result: { data } }; + } + + threadCompactStart(params = {}) { + const threadId = String(params.threadId ?? ''); + const controller = this.controllers.get(threadId); + if (!controller) throw new Error(`Thread is not resumed in DSHX: ${threadId}`); + const active = this.manualCompactions(); + if (active.has(threadId)) { + throw new Error('Compaction is unavailable because this thread already has an active manual compaction'); + } + const abortController = new AbortController(); + active.set(threadId, abortController); + return { + result: {}, + afterResponse: () => { + void this.runManualCompaction({ threadId, controller, abortController }); + } + }; + } + + async runManualCompaction({ threadId, controller, abortController }) { + try { + const execution = await executeDshCommand({ + ctx: controller.agent.ctx ?? this.ctx, + agent: controller.agent, + line: '/compact', + signal: abortController.signal + }); + if (execution.result?.sourceEventSeq == null && execution.result?.text) { + this.warnThread(threadId, execution.result.text); + } + } catch (error) { + if (abortController.signal.aborted) { + this.warnThread(threadId, 'Compaction cancelled.'); + } else { + const message = error instanceof Error ? error.message : String(error); + this.warnThread(threadId, message); + this.diagnostics(`manual compaction failed for ${threadId}: ${message}`); + } + } finally { + if (this.manualCompactions().get(threadId) === abortController) { + this.manualCompactions().delete(threadId); + } + } + } + + turnInterruptProduct(params = {}) { + const threadId = String(params.threadId ?? ''); + if (String(params.turnId ?? '').startsWith('dsh-maintenance-compaction-')) { + const active = this.manualCompactions().get(threadId); + if (active) { + active.abort(new Error('user cancelled DSH compaction')); + return { result: {} }; + } + } + return this.turnInterrupt(params); + } + + async forkSourceEvents(sourceId) { + const live = this.controllers.get(sourceId)?.agent ?? this.driver.getLive(sourceId); + if (live?.session) return live.session.events ?? []; + const inspected = await this.driver.inspectSession(sourceId); + if (!inspected) throw new Error(`Unknown DSH session: ${sourceId}`); + return inspected.events ?? []; + } + + async threadFork(params = {}) { + const sourceId = String(params.threadId ?? ''); + if (!sourceId) throw new Error('thread/fork requires threadId'); + if (params.path != null) throw new Error('DSHX forks DSH sessions by threadId, not Codex rollout paths'); + if (params.deferGoalContinuation === true) { + throw new Error('DSH has no Codex thread-goal continuation state for DSHX to defer'); + } + if (params.ephemeral === true) { + throw new Error('DSHX does not expose ephemeral Codex forks over durable DSH sessions'); + } + + const events = await this.forkSourceEvents(sourceId); + const atSeq = codexForkAtSeq(events, { + lastTurnId: params.lastTurnId, + beforeTurnId: params.beforeTurnId + }); + const forked = await this.hostApi().forkSession({ sessionId: sourceId, atSeq }); + const childId = String(forked?.sessionId ?? ''); + if (!childId) throw new Error('DSH Host fork returned no child session id'); + + const childAgent = this.driver.getLive(childId); + if (!childAgent) throw new Error(`DSH Host fork did not publish child Agent ${childId}`); + this.driver.adoptExternalSelection(childAgent, { + select: (selection) => this.hostApi().selectModel({ sessionId: childId, ...selection }) + }); + const controller = this.installController({ agent: childAgent, dispose: async () => {} }); + const result = this.threadResponse(controller.agent, { + includeTurns: params.excludeTurns !== true + }); + return { + result, + afterResponse: () => this.send({ method: 'thread/started', params: { thread: result.thread } }) + }; + } + + historyController(threadId) { + const controller = this.controllers.get(String(threadId ?? '')); + if (!controller) { + throw new Error(`Thread must be resumed before paginated DSH history is rendered: ${String(threadId ?? '')}`); + } + return controller; + } + + threadTurnsList(params = {}) { + const controller = this.historyController(params.threadId); + return { + result: dshThreadTurnsPage({ + controller, + params, + diagnostics: this.diagnostics + }) + }; + } + + threadItemsList(params = {}) { + const controller = this.historyController(params.threadId); + return { + result: dshThreadItemsPage({ + controller, + params, + diagnostics: this.diagnostics + }) + }; + } + + async saveDefaultModelSelection(selection) { + const defaults = this.ctx.get('agentDefaultModel'); + if (!defaults?.saveSelection) { + this.diagnostics('DSH agentDefaultModel service has no saveSelection(); current session selection remains valid but deployment default was not persisted'); + return; + } + await defaults.saveSelection({ + provider: selection.provider, + model: selection.model, + ...(selection.reasoningEffort == null ? {} : { reasoningEffort: selection.reasoningEffort }) + }); + } + + async threadSettingsUpdate(params = {}) { + const threadId = String(params.threadId ?? ''); + const controller = this.controllers.get(threadId); + if (!controller) throw new Error(`Thread is not resumed in DSHX: ${threadId}`); + const agent = controller.agent; + + if (params.cwd != null) { + const currentCwd = path.resolve(agent.session.header?.cwd ?? this.cwd); + if (path.resolve(params.cwd) !== currentCwd) { + throw new Error('DSHX does not retarget a live DSH session cwd from the TUI'); + } + } + if (params.sandboxPolicy != null) { + throw new Error('DSHX changes permissions through DSH named permission presets, not Codex legacy sandboxPolicy'); + } + if (params.serviceTier !== undefined) { + throw new Error('DSH has no public thread service-tier setter for DSHX to project'); + } + if (params.summary != null) { + throw new Error('DSH has no equivalent public reasoning-summary thread setting'); + } + if (params.personality != null) { + throw new Error('DSH has no equivalent public personality thread setting'); + } + if (params.approvalsReviewer != null && params.approvalsReviewer !== 'user') { + throw new Error('DSH approval review is user-owned; DSHX cannot select a Codex-specific reviewer'); + } + + const supported = hasSupportedThreadSetting(params); + if (params.collaborationMode != null && !supported) { + throw new Error('DSH has no equivalent public collaboration-mode thread setting'); + } + + if (params.permissions != null || params.approvalPolicy != null) { + await this.applyStartPermissions(agent, { + permissions: params.permissions, + approvalPolicy: params.approvalPolicy + }); + } + if (params.model != null || params.effort != null) { + const selection = await this.applyModelOverride(agent, { + model: params.model, + effort: params.effort + }); + await this.saveDefaultModelSelection(selection); + } + + return { result: {} }; + } + + turnSteer(params = {}) { + const threadId = String(params.threadId ?? ''); + const controller = this.controllers.get(threadId); + if (!controller) throw new Error(`Thread is not resumed in DSHX: ${threadId}`); + const location = controller.currentLocation(); + if (!location) throw new Error(`Thread has no active DSH turn to steer: ${threadId}`); + if (typeof params.expectedTurnId !== 'string' || params.expectedTurnId !== location.turnId) { + throw new Error( + `DSHX steer expectedTurnId ${JSON.stringify(params.expectedTurnId)} does not match active DSH turn ${location.turnId}` + ); + } + controller.steer(steerTextInput(params)); + return { result: { turnId: location.turnId } }; + } + + // ── release-layer presentation surfaces ────────────────────────────────── + + userShell() { + return this._userShell ??= new DshUserShellBridge({ + send: this.send, + diagnostics: this.diagnostics + }); + } + + workspaceCommands() { + return this._workspaceCommands ??= new DshWorkspaceCommandBridge({ driver: this.driver }); + } + + planListeners() { + return this._planListeners ??= new Map(); + } + + planMutationSuppressed() { + return this._planMutationSuppressed ??= new Set(); + } + + planMode(agent) { + const service = agent?.ctx?.get?.('planMode') ?? this.ctx.get('planMode'); + if (!service?.set || !service?.get) throw new Error('DSHX requires DSH service: planMode'); + return service; + } + + planSettingsNotification(agent) { + const response = this.threadResponse(agent); + return threadSettingsUpdatedNotification({ + threadId: String(agent.id), + response, + planState: this.planMode(agent).get(agent) + }); + } + + liveAgentThread(agent) { + const thread = dshThreadFromSnapshot({ + meta: agent.session.header, + events: agent.session.events ?? [], + model: agent.session.requestHeader?.()?.config, + loaded: true, + cliVersion: this.version + }); + const title = snapshotTitle(this.driver.currentTitle(agent)) ?? foldDshSessionTitle(agent.session.events ?? []); + return { + ...thread, + status: agent.status === 'running' ? { type: 'active', activeFlags: [] } : { type: 'idle' }, + name: title, + turns: [] + }; + } + + directController(threadId, operation) { + const controller = this.controllers.get(String(threadId ?? '')); + if (!controller) throw new Error(`Thread is not resumed in DSHX: ${String(threadId ?? '')}`); + if (isDshSubagent(controller.agent)) { + throw new Error(`DSHX refuses ${operation} on a DSH subagent; child runtime control remains owned by ctx.subagents`); + } + return controller; + } + + async interruptSubagent(controller) { + const parentSessionId = controller.agent.session.header?.parentSession; + if (parentSessionId == null) throw new Error('DSH subagent is missing durable parentSession authority'); + const subagents = this.ctx.get('subagents'); + if (!subagents?.interrupt) throw new Error('DSHX requires DSH service: subagents.interrupt'); + await subagents.interrupt(String(controller.agent.id), { + kind: 'user', + parentSessionId: String(parentSessionId) + }); + return { result: {} }; + } + + async commandExec(params = {}) { + return { result: await this.workspaceCommands().execute(params) }; + } + + async configBatchWrite(params = {}) { + const edits = Array.isArray(params.edits) ? params.edits : []; + if (edits.length === 0) throw new Error('DSHX config/batchWrite requires at least one model-selection edit'); + + const supported = new Set(['model', 'model_reasoning_effort']); + for (const edit of edits) { + if (!supported.has(edit?.keyPath)) { + throw new Error(`DSHX config/batchWrite refuses Codex-owned setting: ${String(edit?.keyPath ?? '')}`); + } + if (edit?.mergeStrategy != null && edit.mergeStrategy !== 'replace') { + throw new Error(`DSHX config/batchWrite supports replace semantics only: ${String(edit.keyPath)}`); + } + } + + const defaults = this.ctx.get('agentDefaultModel'); + const llm = this.ctx.get('llm'); + if (!defaults?.currentSelection || !defaults?.saveSelection) { + throw new Error('DSHX requires DSH service: agentDefaultModel.saveSelection'); + } + if (!llm?.resolveCallConfig) throw new Error('DSHX requires DSH service: llm.resolveCallConfig'); + + const current = defaults.currentSelection(); + let requested = { provider: current.provider, model: current.model }; + if (current.reasoningEffort !== undefined) requested.reasoningEffort = current.reasoningEffort; + + const modelEdit = edits.find((edit) => edit.keyPath === 'model'); + if (modelEdit) { + const decoded = decodeDshModel(modelEdit.value); + if (!decoded) throw new Error('DSHX persists default models only from its DSH-backed opaque model catalog'); + requested = { ...decoded }; + } + + const effortEdit = edits.find((edit) => edit.keyPath === 'model_reasoning_effort'); + if (effortEdit) { + const effort = effortEdit.value == null ? undefined : normalizeCodexEffort(effortEdit.value); + requested = { provider: requested.provider, model: requested.model }; + if (effort !== undefined) requested.reasoningEffort = effort; + } + + const resolved = await llm.resolveCallConfig(requested); + const persisted = { provider: resolved.provider, model: resolved.model }; + // Preserve provider-default semantics when the TUI clears its reasoning + // setting; otherwise persist the DSH-resolved explicit effort. + if (requested.reasoningEffort !== undefined) { + persisted.reasoningEffort = resolved.reasoningEffort ?? requested.reasoningEffort; + } + await defaults.saveSelection(persisted); + + this._configRevision = (this._configRevision ?? 0) + 1; + return { + result: { + status: 'ok', + version: `dshx-${this._configRevision}`, + // Codex requires an absolute path in ConfigWriteResponse. Persistence is + // actually owned by DSH settings; this marker stays inside presentation home. + filePath: path.join(this.home, 'dsh-settings'), + overriddenMetadata: null + } + }; + } + + async richUserTurn(method, params = {}) { + const threadId = String(params.threadId ?? ''); + const controller = this.controllers.get(threadId); + if (!controller) { + // Formerly `super.dispatch(method, params)`: the inherited tail routed + // turn/start to the base turnStart and turn/steer to the product + // turnSteer validator. Route directly to those most-derived methods. + return method === 'turn/steer' ? this.turnSteer(params) : this.turnStart(params); + } + if (isDshSubagent(controller.agent)) { + throw new Error(`DSHX refuses ${method} on a DSH subagent; send/steer authority remains owned by ctx.subagents`); + } + const content = await codexInputToDshContent(this.ctx, params.input ?? []); + const clear = controller.prepareUserContent(content); + try { + // Pinned Codex serializes an unset reasoning effort as JSON null. DSH + // interprets absence as provider default, so never forward null as an + // explicit provider effort. + const normalizedParams = params.effort == null ? { ...params, effort: undefined } : params; + // Preserve the original base/product validation path. The fallback text is + // consumed only if no prepared rich content exists; it also keeps the + // base adapter's expected text-only parameter shape intact. + const forwarded = { ...normalizedParams, input: [{ type: 'text', text: dshContentText(content) }] }; + return method === 'turn/steer' ? this.turnSteer(forwarded) : this.turnStart(forwarded); + } finally { + clear(); + } + } + + async threadForkPresentation(params = {}) { + const response = await this.threadFork(params); + const startedThread = { ...response.result.thread, turns: [] }; + const agent = this.controllers.get(String(response.result.thread.id))?.agent; + return { + ...response, + // Pinned Codex emits copied history only in the fork response. The + // thread/started notification introduces metadata/live state and must not + // replay those copied turns a second time before paginated hydration. + afterResponse: () => { + this.send({ + method: 'thread/started', + params: { thread: startedThread } + }); + if (agent) this.send(this.planSettingsNotification(agent)); + } + }; + } + + async threadSettingsUpdatePresentation(params = {}) { + const threadId = String(params.threadId ?? ''); + const controller = this.controllers.get(threadId); + if (controller && isDshSubagent(controller.agent)) { + throw new Error('DSHX refuses direct model/permission/plan changes on a DSH subagent; composition remains DSH-owned'); + } + if (params.collaborationMode == null) return this.threadSettingsUpdate(params); + if (!controller) throw new Error(`Thread is not resumed in DSHX: ${threadId}`); + const active = codexPlanTarget(params.collaborationMode); + const { collaborationMode: _ignored, ...ordinary } = params; + + // Let the existing DSH-backed settings adapter validate/apply every other + // supported field. The collaboration payload's model/reasoning/instructions + // are intentionally not treated as DSH model or prompt configuration. + await this.threadSettingsUpdate(ordinary); + + this.planMutationSuppressed().add(threadId); + try { + await this.planMode(controller.agent).set(controller.agent, active); + } finally { + this.planMutationSuppressed().delete(threadId); + } + + return { + result: {}, + afterResponse: () => this.send(this.planSettingsNotification(controller.agent)) + }; + } + + threadShellCommand(params = {}) { + const controller = this.directController(params.threadId, 'direct shell execution'); + return this.userShell().start(controller, params.command); + } + + async threadNameSet(params = {}) { + const threadId = String(params.threadId ?? ''); + if (!threadId) throw new Error('thread/name/set requires threadId'); + if (typeof params.name !== 'string') throw new Error('thread/name/set requires name'); + + let temporaryHandle; + let agent = this.controllers.get(threadId)?.agent ?? this.driver.getLive(threadId); + if (!agent) { + temporaryHandle = await this.driver.resume(threadId); + agent = temporaryHandle.agent; + } + + try { + const snapshot = this.driver.renameTitle(agent, params.name); + const threadName = snapshotTitle(snapshot); + if (threadName == null) throw new Error('DSH sessionTitle.rename returned no accepted title'); + return { + result: {}, + afterResponse: () => this.send(threadNameUpdatedNotification(threadId, threadName)) + }; + } finally { + await temporaryHandle?.dispose?.(); + } + } + + // ── synthetic interactions (base) ──────────────────────────────────────── + + openSyntheticInteraction(request) { + const agentId = request?.agent?.id; + if (!agentId) return undefined; + const controller = this.controllers.get(String(agentId)); + const location = controller?.currentLocation(); + if (!location) return undefined; + const itemId = `dshx-interaction-${crypto.randomUUID()}`; + const startedAtMs = Date.now(); + const item = { + type: 'dynamicToolCall', + id: itemId, + namespace: 'dshx', + tool: 'userInteraction', + arguments: { questionCount: request.questions?.length ?? 0 }, + status: 'inProgress', + contentItems: null, + success: null, + durationMs: null + }; + this.syntheticInteractions.set(itemId, { ...location, item, startedAtMs }); + this.send({ + method: 'item/started', + params: { ...location, item, startedAtMs } + }); + return { ...location, itemId }; + } + + completeSyntheticInteraction(location, outcome) { + const state = this.syntheticInteractions.get(location.itemId); + if (!state) return; + this.syntheticInteractions.delete(location.itemId); + const completedAtMs = Date.now(); + const item = { + ...state.item, + status: outcome.status === 'completed' ? 'completed' : 'failed', + success: outcome.status === 'completed', + durationMs: Math.max(0, completedAtMs - state.startedAtMs) + }; + this.send({ + method: 'item/completed', + params: { threadId: state.threadId, turnId: state.turnId, item, completedAtMs } + }); + } + + error(id, code, message, data = undefined) { + const error = { code, message }; + if (data !== undefined) error.data = data; + return { id, error }; + } + + // ── teardown (linearized release → product → base) ────────────────────── + + async close() { + this._userShell?.close(); + for (const dispose of this._agentPresentationDisposers ?? []) dispose?.(); + this._agentPresentationDisposers = []; + for (const dispose of this.planListeners().values()) dispose?.(); + this.planListeners().clear(); + this.planMutationSuppressed().clear(); + for (const controller of this.manualCompactions().values()) { + controller.abort(new Error('DSHX adapter closing')); + } + this.manualCompactions().clear(); + this.userQuestions?.dispose(); + this.userQuestions = null; + this.broker.close(); + const ids = [...this.controllers.keys()]; + for (const id of ids) await this.threadUnsubscribe({ threadId: id }); + } +} + +export const releaseAdapterInternals = { snapshotTitle, isDshSubagent }; diff --git a/.release/dshx-linux-x64/src/tui-protocol/shapes.mjs b/.release/dshx-linux-x64/src/tui-protocol/shapes.mjs new file mode 100644 index 00000000..3f99f45c --- /dev/null +++ b/.release/dshx-linux-x64/src/tui-protocol/shapes.mjs @@ -0,0 +1,419 @@ +import { DshToolPresentationResolver } from '../dsh/tool-presentation.mjs'; + +const MODEL_PREFIX = 'dshx:'; +const DEFAULT_REASONING_SENTINEL = 'dsh-default'; +const DSH_SUBAGENT_DESCRIPTOR_VERSION = 2; + +function seconds(timeMs, fallback = Math.floor(Date.now() / 1000)) { + return Number.isFinite(timeMs) ? Math.floor(timeMs / 1000) : fallback; +} + +function visibleText(content) { + return (content ?? []) + .filter((block) => block?.type === 'text' && typeof block.text === 'string') + .map((block) => block.text) + .join(''); +} + +function visibleReasoning(content) { + return (content ?? []) + .filter((block) => block?.type === 'reasoning' && typeof block.text === 'string') + .map((block) => block.text); +} + +function latestRequestConfig(events) { + for (let index = (events?.length ?? 0) - 1; index >= 0; index -= 1) { + const event = events[index]; + if (event?.type === 'request/header') return event.data?.header?.config ?? null; + } + return null; +} + +function firstHumanPreview(events) { + for (const event of events ?? []) { + if (event?.type !== 'user/message' || event.data?.source?.kind !== 'user') continue; + const text = visibleText(event.data.content).trim(); + if (text) return text.slice(0, 240); + } + return ''; +} + +function turnStatus(reason) { + switch (reason?.kind) { + case 'completed': return 'completed'; + case 'aborted': + case 'interrupted': return 'interrupted'; + default: return 'failed'; + } +} + +function turnError(reason) { + if (reason?.kind !== 'error') return null; + return { + message: reason.error?.message ?? 'DSH turn failed', + codexErrorInfo: null, + additionalDetails: null + }; +} + +function compactionError(message) { + return message == null + ? null + : { message: String(message), codexErrorInfo: null, additionalDetails: null }; +} + +function normalizeList(value) { + if (Array.isArray(value)) return value; + if (Array.isArray(value?.entries)) return value.entries; + return []; +} + +function subagentDescriptor(events = []) { + const event = events.find((candidate) => candidate?.type === 'subagent/descriptor'); + const value = event?.data; + if (!value || value.version !== DSH_SUBAGENT_DESCRIPTOR_VERSION) return null; + if ((value.mode !== 'one-shot' && value.mode !== 'continuable') || typeof value.provider !== 'string') return null; + return { + mode: value.mode, + provider: value.provider, + label: typeof value.label === 'string' && value.label.length > 0 ? value.label : null + }; +} + +function sourceForHeader(header, events = []) { + if (header?.origin === 'subagent' && header.parentSession != null) { + const descriptor = subagentDescriptor(events); + return { + subagent: { + thread_spawn: { + parent_thread_id: String(header.parentSession), + depth: Number.isInteger(header.delegationDepth) ? header.delegationDepth : 1, + agent_path: null, + agent_nickname: descriptor?.label ?? null, + agent_role: null + } + } + }; + } + return { custom: 'dshx' }; +} + +function inputFromDshMessage(message) { + const content = []; + for (const block of message?.content ?? []) { + if (block?.type === 'text' && typeof block.text === 'string') { + content.push({ type: 'text', text: block.text, text_elements: [] }); + } + } + return content; +} + +function historyTurn(id, startedAt) { + return { + id, + items: [], + itemsView: 'full', + status: 'inProgress', + error: null, + startedAt, + completedAt: null, + durationMs: null + }; +} + +export function encodeDshModel(selection) { + if (!selection?.provider || !selection?.model) throw new Error('DSHX model selection requires provider and model'); + const payload = Buffer.from(JSON.stringify([selection.provider, selection.model]), 'utf8').toString('base64url'); + return `${MODEL_PREFIX}${payload}`; +} + +export function decodeDshModel(value) { + if (typeof value !== 'string' || !value.startsWith(MODEL_PREFIX)) return undefined; + try { + const decoded = JSON.parse(Buffer.from(value.slice(MODEL_PREFIX.length), 'base64url').toString('utf8')); + if (!Array.isArray(decoded) || decoded.length !== 2 || decoded.some((part) => typeof part !== 'string' || !part)) { + return undefined; + } + return { provider: decoded[0], model: decoded[1] }; + } catch { + return undefined; + } +} + +export function normalizeCodexEffort(value) { + return value === DEFAULT_REASONING_SENTINEL ? undefined : value; +} + +/** + * Translate the public DSH LLM registry into Codex's provider-less model picker. + * Provider identity is encoded only in the opaque `model`/`id` value and decoded + * again by DSHX before calling `ctx.llm.resolveCallConfig()`. + */ +export function codexModelsFromDsh(directory, currentSelection) { + const groups = directory?.groups ?? []; + const multipleProviders = groups.length > 1; + const models = []; + for (const group of groups) { + for (const model of group.models ?? []) { + const encoded = encodeDshModel({ provider: group.provider, model: model.id }); + const efforts = model.reasoning?.efforts ?? []; + const supportedReasoningEfforts = efforts.length > 0 + ? efforts.map((effort) => ({ + reasoningEffort: effort.id, + description: effort.description ?? effort.name ?? effort.id + })) + : [{ reasoningEffort: DEFAULT_REASONING_SENTINEL, description: 'Use the DSH provider default' }]; + const defaultReasoningEffort = model.reasoning?.defaultEffort ?? DEFAULT_REASONING_SENTINEL; + const displayName = multipleProviders + ? `${model.name ?? model.id} · ${group.name ?? group.provider}` + : (model.name ?? model.id); + models.push({ + id: encoded, + model: encoded, + upgrade: null, + upgradeInfo: null, + availabilityNux: null, + displayName, + description: model.description ?? `${group.name ?? group.provider} / ${model.id}`, + modelSpecialty: null, + hidden: false, + supportedReasoningEfforts, + defaultReasoningEffort, + inputModalities: (model.inputModalities ?? []).filter((entry) => entry === 'text' || entry === 'image'), + supportsPersonality: false, + multiAgentVersion: null, + additionalSpeedTiers: [], + serviceTiers: [], + defaultServiceTier: null, + isDefault: currentSelection?.provider === group.provider && currentSelection?.model === model.id + }); + } + } + return models; +} + +export function dshThreadFromSnapshot({ meta, events = [], model, turns = [], loaded = false, cliVersion = 'dshx' }) { + if (!meta?.id) throw new Error('DSHX thread projection requires SessionHeader.id'); + const config = model ?? latestRequestConfig(events) ?? {}; + const createdAt = seconds(meta.createdAt); + const lastTime = events.length > 0 ? events[events.length - 1]?.time : meta.createdAt; + const isSubagent = meta.origin === 'subagent'; + const descriptor = isSubagent ? subagentDescriptor(events) : null; + let openTurn = false; + for (const event of events) { + if (event?.type === 'turn/start') openTurn = true; + else if (event?.type === 'turn/end') openTurn = false; + } + return { + id: String(meta.id), + extra: null, + sessionId: String(meta.id), + forkedFromId: !isSubagent && meta.parentSession ? String(meta.parentSession) : null, + parentThreadId: isSubagent && meta.parentSession ? String(meta.parentSession) : null, + preview: firstHumanPreview(events), + ephemeral: false, + section: null, + sectionEnteredAt: null, + projectId: null, + historyMode: 'paginated', + modelProvider: config.provider ?? 'dsh', + createdAt, + updatedAt: seconds(lastTime, createdAt), + recencyAt: seconds(lastTime, createdAt), + status: loaded ? (openTurn ? { type: 'active', activeFlags: [] } : { type: 'idle' }) : { type: 'notLoaded' }, + path: null, + cwd: meta.cwd ?? process.cwd(), + cliVersion, + source: sourceForHeader(meta, events), + // DSH continuation authority belongs to ctx.subagents. Showing a child in + // Codex navigation must never create a presentation-side bypass that sends + // a user turn directly to the child Agent. + canAcceptDirectInput: isSubagent ? false : loaded ? true : null, + threadSource: null, + agentNickname: descriptor?.label ?? null, + agentRole: null, + gitInfo: null, + name: null, + turns + }; +} + +/** + * Replay the authoritative DSH raw log as a human transcript. This intentionally + * does not fold the model surface: DSH's own terminal/web transcript contract + * keeps messages shadowed by compaction visible to the human and inserts a + * compaction marker at the landed checkpoint. The plugin-sourced replacement + * user/message is therefore ignored as model-only framing. + */ +export function dshTurnsFromSession({ ctx, agent, diagnostics = () => {} }) { + const session = agent?.session; + if (!session) return []; + const turns = new Map(); + const compactions = new Map(); + let currentTurn; + const toolPresenter = new DshToolPresentationResolver({ + ctx: agent.ctx ?? ctx, + agent, + threadId: String(agent.id), + workspaceCwd: session.header?.cwd ?? process.cwd(), + diagnostics + }); + + for (const event of session.events ?? []) { + switch (event.type) { + case 'turn/start': { + const number = event.data?.turn; + if (!Number.isInteger(number)) break; + const startedAt = seconds(event.time); + turns.set(number, historyTurn(`dsh-turn-${number}`, startedAt)); + currentTurn = number; + break; + } + case 'user/message': { + const turn = turns.get(currentTurn); + const message = event.data; + if (!turn || message?.source?.kind !== 'user') break; + const content = inputFromDshMessage(message); + if (content.length === 0) break; + turn.items.push({ type: 'userMessage', id: String(message.id), clientId: null, content }); + break; + } + case 'assistant/message': { + const turn = turns.get(event.data?.turn); + const message = event.data?.message; + if (!turn || !message) break; + const reasoning = visibleReasoning(message.content); + if (reasoning.length > 0) { + turn.items.push({ + type: 'reasoning', + id: `dsh-reasoning-${event.data.turn}-${event.data.step}`, + summary: [], + content: reasoning + }); + } + const text = visibleText(message.content); + if (text.length > 0) { + turn.items.push({ + type: 'agentMessage', + id: String(message.id ?? `dsh-assistant-${event.data.turn}-${event.data.step}`), + text, + phase: null, + memoryCitation: null, + delivery: null + }); + } + break; + } + case 'tool/call': { + const turn = turns.get(event.data?.turn); + if (!turn) break; + const projected = toolPresenter.start({ + turnId: turn.id, + callId: event.data.callId, + name: event.data.name, + rawArguments: event.data.arguments, + startedAtMs: event.time + }); + turn.items.push(projected.item); + break; + } + case 'tool/result': { + const callId = event.data?.message?.source?.callId + ?? event.data?.message?.content?.find?.((block) => block?.type === 'tool-result')?.toolCallId; + if (!callId) break; + const completed = toolPresenter.complete({ callId, resultData: event.data, completedAtMs: event.time }); + if (!completed) break; + for (const turn of turns.values()) { + const index = turn.items.findIndex((item) => item.id === completed.item.id); + if (index >= 0) { + turn.items[index] = completed.item; + break; + } + } + break; + } + case 'compaction/start': { + const { compactionId, turn } = event.data ?? {}; + if (typeof compactionId !== 'string' || compactionId.length === 0) break; + let turnKey; + let target; + let manual = false; + if (Number.isInteger(turn)) { + turnKey = turn; + target = turns.get(turnKey); + if (!target) break; + } else if (turn === null) { + manual = true; + turnKey = `compact:${compactionId}`; + target = historyTurn(`dsh-maintenance-compaction-${compactionId}`, seconds(event.time)); + turns.set(turnKey, target); + } else { + break; + } + compactions.set(compactionId, { + turnKey, + turn: target, + manual, + summarized: false, + itemId: `dsh-compaction-${compactionId}` + }); + break; + } + case 'compaction/summary': { + const state = compactions.get(event.data?.compactionId); + if (!state) break; + state.summarized = true; + state.turn.items.push({ type: 'contextCompaction', id: state.itemId }); + break; + } + case 'compaction/end': { + const state = compactions.get(event.data?.compactionId); + if (!state) break; + compactions.delete(event.data.compactionId); + if (state.manual) { + if (!state.summarized) { + turns.delete(state.turnKey); + break; + } + const completedAt = seconds(event.time); + state.turn.status = event.data?.error == null ? 'completed' : 'failed'; + state.turn.error = compactionError(event.data?.error); + state.turn.completedAt = completedAt; + state.turn.durationMs = state.turn.startedAt == null + ? null + : Math.max(0, (completedAt - state.turn.startedAt) * 1000); + } + break; + } + case 'turn/end': { + const number = event.data?.turn; + const turn = turns.get(number); + if (!turn) break; + const completedAt = seconds(event.time); + turn.status = turnStatus(event.data.reason); + turn.error = turnError(event.data.reason); + turn.completedAt = completedAt; + turn.durationMs = turn.startedAt == null ? null : Math.max(0, (completedAt - turn.startedAt) * 1000); + if (currentTurn === number) currentTurn = undefined; + break; + } + default: + break; + } + } + return [...turns.values()]; +} + +export function normalizeSessionHeaders(value) { + return normalizeList(value); +} + +export const internals = { + DEFAULT_REASONING_SENTINEL, + latestRequestConfig, + firstHumanPreview, + inputFromDshMessage, + visibleReasoning, + subagentDescriptor, + sourceForHeader +}; diff --git a/.release/dshx-linux-x64/upstream/CODEX_COMMIT b/.release/dshx-linux-x64/upstream/CODEX_COMMIT new file mode 100644 index 00000000..c4d68c85 --- /dev/null +++ b/.release/dshx-linux-x64/upstream/CODEX_COMMIT @@ -0,0 +1 @@ +fde2156057c38c0227ce94c8514d04c7498df60d diff --git a/.release/dshx-linux-x64/upstream/DSH_COMMIT b/.release/dshx-linux-x64/upstream/DSH_COMMIT new file mode 100644 index 00000000..cbba87c8 --- /dev/null +++ b/.release/dshx-linux-x64/upstream/DSH_COMMIT @@ -0,0 +1 @@ +141eb6fef83422698aef7a981029e843e8161534 diff --git a/.release/dshx-linux-x64/upstream/patches/codex/0001-dshx-force-ui-backend.patch b/.release/dshx-linux-x64/upstream/patches/codex/0001-dshx-force-ui-backend.patch new file mode 100644 index 00000000..f2a8bb2c --- /dev/null +++ b/.release/dshx-linux-x64/upstream/patches/codex/0001-dshx-force-ui-backend.patch @@ -0,0 +1,65 @@ +diff --git a/codex-rs/tui/src/main.rs b/codex-rs/tui/src/main.rs +--- a/codex-rs/tui/src/main.rs ++++ b/codex-rs/tui/src/main.rs +@@ -1,10 +1,12 @@ + use clap::Parser; ++use codex_app_server_client::RemoteAppServerEndpoint; + use codex_arg0::Arg0DispatchPaths; + use codex_arg0::arg0_dispatch_or_else; + use codex_config::LoaderOverrides; + use codex_tui::AppExitInfo; + use codex_tui::Cli; + use codex_tui::ExitReason; ++use codex_tui::resolve_remote_addr; + use codex_tui::run_main; + use codex_utils_cli::CliConfigOverrides; + use std::io::Write; +@@ -47,6 +49,42 @@ fn main() -> anyhow::Result<()> { + inner + .config_overrides + .raw_overrides + .splice(0..0, top_cli.config_overrides.raw_overrides); ++ if let Ok(mode) = std::env::var("DSHX_RESUME_MODE") { ++ match mode.as_str() { ++ "picker" => inner.resume_picker = true, ++ "last" => inner.resume_last = true, ++ "id" => { ++ inner.resume_session_id = Some( ++ std::env::var("DSHX_RESUME_SESSION_ID").map_err(|_| { ++ anyhow::anyhow!( ++ "DSHX_RESUME_SESSION_ID is required when DSHX_RESUME_MODE=id" ++ ) ++ })?, ++ ); ++ } ++ other => anyhow::bail!("invalid DSHX_RESUME_MODE: {other}"), ++ } ++ } ++ let dshx_endpoint = std::env::var("DSHX_APP_SERVER_ENDPOINT").map_err(|_| { ++ anyhow::anyhow!( ++ "DSHX_APP_SERVER_ENDPOINT is required; DSHX never falls back to the Codex agent runtime" ++ ) ++ })?; ++ let dshx_token = std::env::var("DSHX_APP_SERVER_TOKEN").map_err(|_| { ++ anyhow::anyhow!( ++ "DSHX_APP_SERVER_TOKEN is required; DSHX local transport is always authenticated" ++ ) ++ })?; ++ let mut dshx_endpoint = resolve_remote_addr(&dshx_endpoint)?; ++ match &mut dshx_endpoint { ++ RemoteAppServerEndpoint::WebSocket { auth_token, .. } => { ++ *auth_token = Some(dshx_token); ++ } ++ RemoteAppServerEndpoint::UnixSocket { .. } => { ++ anyhow::bail!("DSHX production launcher requires authenticated loopback WebSocket transport") ++ } ++ } + let exit_info = run_main( + inner, + arg0_paths, + LoaderOverrides::default(), +- /*explicit_remote_endpoint*/ None, ++ /*explicit_remote_endpoint*/ Some(dshx_endpoint), + ) + .await?; + let is_fatal = match &exit_info.exit_reason { diff --git a/.release/dshx-linux-x64/upstream/patches/codex/0002-dshx-branding.patch b/.release/dshx-linux-x64/upstream/patches/codex/0002-dshx-branding.patch new file mode 100644 index 00000000..ed950523 --- /dev/null +++ b/.release/dshx-linux-x64/upstream/patches/codex/0002-dshx-branding.patch @@ -0,0 +1,38 @@ +diff --git a/codex-rs/tui/src/history_cell/session.rs b/codex-rs/tui/src/history_cell/session.rs +--- a/codex-rs/tui/src/history_cell/session.rs ++++ b/codex-rs/tui/src/history_cell/session.rs +@@ -142,7 +142,7 @@ pub(crate) fn new_session_info( + Line::from(vec![ + " ".into(), + "/init".into(), +- " - create an AGENTS.md file with instructions for Codex".dim(), ++ " - create an AGENTS.md file with instructions for DeepSeek Harness".dim(), + ]), +@@ -152,7 +152,7 @@ pub(crate) fn new_session_info( + Line::from(vec![ + " ".into(), + "/permissions".into(), +- " - choose what Codex is allowed to do".dim(), ++ " - choose what DeepSeek Harness is allowed to do".dim(), + ]), +@@ -269,10 +269,10 @@ impl HistoryCell for SessionHeaderHistoryCell { + let make_row = |spans: Vec>| Line::from(spans); + +- // Title line rendered inside the box: ">_ OpenAI Codex (vX)" ++ // DSHX changes branding only; layout and interaction stay upstream Codex. + let title_spans: Vec> = vec![ + Span::from(">_ ").dim(), +- Span::from("OpenAI Codex").bold(), ++ Span::from("DeepSeek Harness").bold(), + Span::from(" ").dim(), + Span::from(format!("(v{})", self.version)).dim(), + ]; +@@ -335,7 +335,7 @@ impl HistoryCell for SessionHeaderHistoryCell { + + fn raw_lines(&self) -> Vec> { + let mut lines = vec![ +- Line::from(format!("OpenAI Codex (v{})", self.version)), ++ Line::from(format!("DeepSeek Harness (v{})", self.version)), + Line::from(format!( + "model: {}{}", + self.model, diff --git a/.release/dshx-linux-x64/upstream/patches/codex/0003-dshx-approval-semantics.patch b/.release/dshx-linux-x64/upstream/patches/codex/0003-dshx-approval-semantics.patch new file mode 100644 index 00000000..a54067df --- /dev/null +++ b/.release/dshx-linux-x64/upstream/patches/codex/0003-dshx-approval-semantics.patch @@ -0,0 +1,91 @@ +diff --git a/codex-rs/tui/src/bottom_pane/approval_overlay.rs b/codex-rs/tui/src/bottom_pane/approval_overlay.rs +--- a/codex-rs/tui/src/bottom_pane/approval_overlay.rs ++++ b/codex-rs/tui/src/bottom_pane/approval_overlay.rs +@@ -796,6 +796,10 @@ struct ApprovalOption { + shortcuts: Vec, + } + ++fn dshx_backend() -> bool { ++ std::env::var_os("DSHX_APP_SERVER_ENDPOINT").is_some() ++} ++ + fn command_decision_to_review_decision( + decision: &CommandExecutionApprovalDecision, + ) -> ReviewDecision { +@@ -855,6 +859,7 @@ fn exec_options( + }) + } ++ CommandExecutionApprovalDecision::AcceptForSession if dshx_backend() => None, + CommandExecutionApprovalDecision::AcceptForSession => Some(ApprovalOption { + label: if network_approval_context.is_some() { + "Yes, and allow this host for this conversation".to_string() +@@ -951,24 +956,27 @@ fn patch_options(keymap: &ApprovalKeymap) -> Vec { +- vec![ ++ let mut options = vec![ + ApprovalOption { + label: "Yes, proceed".to_string(), + decision: ApprovalDecision::FileChange(FileChangeApprovalDecision::Accept), + shortcuts: keymap.approve.clone(), + }, +- ApprovalOption { +- label: "Yes, and don't ask again for these files".to_string(), +- decision: ApprovalDecision::FileChange(FileChangeApprovalDecision::AcceptForSession), +- shortcuts: keymap.approve_for_session.clone(), +- }, + ApprovalOption { +- label: "No, and tell Codex what to do differently".to_string(), ++ label: if dshx_backend() { ++ "No, and tell DeepSeek Harness what to do differently".to_string() ++ } else { ++ "No, and tell Codex what to do differently".to_string() ++ }, + decision: ApprovalDecision::FileChange(FileChangeApprovalDecision::Cancel), + shortcuts: keymap.decline.clone(), + }, +- ] ++ ]; ++ if !dshx_backend() { ++ options.insert(1, ApprovalOption { ++ label: "Yes, and don't ask again for these files".to_string(), ++ decision: ApprovalDecision::FileChange(FileChangeApprovalDecision::AcceptForSession), ++ shortcuts: keymap.approve_for_session.clone(), ++ }); ++ } ++ options + } + + fn permissions_options(keymap: &ApprovalKeymap) -> Vec { +@@ -978,7 +986,7 @@ fn permissions_options(keymap: &ApprovalKeymap) -> Vec { + .filter(|shortcut| shortcut.parts() != (KeyCode::Esc, KeyModifiers::NONE)) + .collect(); + +- vec![ ++ let mut options = vec![ + ApprovalOption { + label: "Yes, grant these permissions for this turn".to_string(), + decision: ApprovalDecision::Permissions(PermissionsDecision::GrantForTurn), +@@ -991,16 +999,19 @@ fn permissions_options(keymap: &ApprovalKeymap) -> Vec { + ), + shortcuts: vec![key_hint::plain(KeyCode::Char('r'))], + }, +- ApprovalOption { +- label: "Yes, grant these permissions for this session".to_string(), +- decision: ApprovalDecision::Permissions(PermissionsDecision::GrantForSession), +- shortcuts: keymap.approve_for_session.clone(), +- }, + ApprovalOption { + label: "No, continue without permissions".to_string(), + decision: ApprovalDecision::Permissions(PermissionsDecision::Deny), + shortcuts: deny_shortcuts, + }, +- ] ++ ]; ++ if !dshx_backend() { ++ options.insert(2, ApprovalOption { ++ label: "Yes, grant these permissions for this session".to_string(), ++ decision: ApprovalDecision::Permissions(PermissionsDecision::GrantForSession), ++ shortcuts: keymap.approve_for_session.clone(), ++ }); ++ } ++ options + } diff --git a/.release/dshx-linux-x64/upstream/patches/codex/0004-dshx-permission-picker.patch b/.release/dshx-linux-x64/upstream/patches/codex/0004-dshx-permission-picker.patch new file mode 100644 index 00000000..14366be2 --- /dev/null +++ b/.release/dshx-linux-x64/upstream/patches/codex/0004-dshx-permission-picker.patch @@ -0,0 +1,60 @@ +diff --git a/codex-rs/tui/src/chatwidget/permission_popups.rs b/codex-rs/tui/src/chatwidget/permission_popups.rs +--- a/codex-rs/tui/src/chatwidget/permission_popups.rs ++++ b/codex-rs/tui/src/chatwidget/permission_popups.rs +@@ -7,33 +7,39 @@ + use super::*; + use codex_protocol::openai_models::MODEL_SPECIALTY_CYBER; + ++fn dshx_backend() -> bool { ++ std::env::var_os("DSHX_APP_SERVER_ENDPOINT").is_some() ++} ++ + impl ChatWidget { + /// Open the permissions popup. + pub(crate) fn open_approvals_popup(&mut self) { + self.open_permissions_popup(); + } + + /// Open a popup to choose the permissions mode. + pub(crate) fn open_permissions_popup(&mut self) { + if self.config.explicit_permission_profile_mode { + self.open_permission_profiles_popup(); + return; + } + + let include_read_only = cfg!(target_os = "windows"); + let current_approval = + AskForApproval::from(self.config.permissions.approval_policy.value()); + let current_permission_profile = self.config.permissions.permission_profile().clone(); +- let guardian_approval_enabled = self.config.features.enabled(Feature::GuardianApproval); ++ let guardian_approval_enabled = !dshx_backend() ++ && self.config.features.enabled(Feature::GuardianApproval); + let current_review_policy = self.config.approvals_reviewer; + let mut items: Vec = Vec::new(); + let presets: Vec = builtin_approval_presets(); + + #[cfg(target_os = "windows")] + let windows_sandbox_level = crate::windows_sandbox::level_from_config(&self.config); + #[cfg(target_os = "windows")] + let windows_degraded_sandbox_enabled = +- matches!(windows_sandbox_level, WindowsSandboxLevel::RestrictedToken); ++ !dshx_backend() ++ && matches!(windows_sandbox_level, WindowsSandboxLevel::RestrictedToken); + #[cfg(not(target_os = "windows"))] + let windows_degraded_sandbox_enabled = false; + + let show_elevate_sandbox_hint = + windows_degraded_sandbox_enabled && presets.iter().any(|preset| preset.id == "auto"); +@@ -313,7 +319,11 @@ impl ChatWidget { + }); + })]; + } +- if approvals_reviewer == ApprovalsReviewer::User && preset.id == "auto" { ++ // DSHX never enables or configures Codex's local Windows sandbox. The ++ // selected workspace preset is sent to the DSH app-server adapter and ++ // DSH remains the enforcement owner. ++ if !dshx_backend() ++ && approvals_reviewer == ApprovalsReviewer::User && preset.id == "auto" { + #[cfg(target_os = "windows")] + { + if crate::windows_sandbox::level_from_config(&self.config) diff --git a/.release/dshx-linux-x64/upstream/patches/codex/0005-dshx-skip-codex-onboarding.patch b/.release/dshx-linux-x64/upstream/patches/codex/0005-dshx-skip-codex-onboarding.patch new file mode 100644 index 00000000..d55e8ef2 --- /dev/null +++ b/.release/dshx-linux-x64/upstream/patches/codex/0005-dshx-skip-codex-onboarding.patch @@ -0,0 +1,112 @@ +diff --git a/codex-rs/tui/src/lib.rs b/codex-rs/tui/src/lib.rs +--- a/codex-rs/tui/src/lib.rs ++++ b/codex-rs/tui/src/lib.rs +@@ -232,8 +232,12 @@ + const TUI_LOG_FILE_NAME: &str = "codex-tui.log"; + const INTERACTIVE_OTEL_SHUTDOWN_TIMEOUT: Duration = Duration::from_millis(/*millis*/ 500); + ++fn dshx_backend() -> bool { ++ std::env::var_os("DSHX_APP_SERVER_ENDPOINT").is_some() ++} ++ + #[cfg(unix)] + const AUTO_CONNECT_DAEMON_CONNECT_TIMEOUT: std::time::Duration = + std::time::Duration::from_millis(50); + +@@ -1068,7 +1072,9 @@ + } + } + let remote_project_trust = +- if uses_remote_workspace && let Some(remote_cwd) = remote_cwd_override.as_deref() { ++ if !dshx_backend() ++ && uses_remote_workspace ++ && let Some(remote_cwd) = remote_cwd_override.as_deref() { + match startup_draft + .run_until( + &mut tui, +@@ -1094,10 +1100,11 @@ + } else { + None + }; + let mut app_server = Some(app_server_session); +- let should_show_trust_screen_flag = remote_project_trust.is_some() +- || (!uses_remote_workspace && should_show_trust_screen(&initial_config)); ++ let should_show_trust_screen_flag = !dshx_backend() ++ && (remote_project_trust.is_some() ++ || (!uses_remote_workspace && should_show_trust_screen(&initial_config))); + #[cfg(target_os = "windows")] + let mut trust_decision_was_made = false; + let startup_model_provider = initial_config.model_provider_id.clone(); + let (login_status, mut startup_account) = if workload_identity_selected { + (LoginStatus::AuthMode(AuthMode::Chatgpt), None) +- } else if initial_config.model_provider.requires_openai_auth { ++ } else if !dshx_backend() && initial_config.model_provider.requires_openai_auth { + let Some(active_app_server) = app_server.as_mut() else { + unreachable!("app server should exist when auth is required"); + }; +@@ -1128,8 +1135,9 @@ + } else { + (LoginStatus::NotAuthenticated, None) + }; + let should_show_onboarding = +- should_show_onboarding(login_status, &initial_config, should_show_trust_screen_flag); ++ !dshx_backend() ++ && should_show_onboarding(login_status, &initial_config, should_show_trust_screen_flag); + + let config = if should_show_onboarding { + if let Err(err) = startup_draft.flush_pending_events(&mut tui).await { + shutdown_startup_session(app_server.take(), &mut terminal_restore_guard).await; +diff --git a/codex-rs/tui/src/app/startup.rs b/codex-rs/tui/src/app/startup.rs +--- a/codex-rs/tui/src/app/startup.rs ++++ b/codex-rs/tui/src/app/startup.rs +@@ -4,9 +4,12 @@ + //! remains isolated from protected interactive requests until the initialized composer owns it. + + use super::*; + + async fn resolve_runtime_model_provider_base_url(provider: &ModelProviderInfo) -> Option { ++ if crate::dshx_backend() { ++ return None; ++ } + let provider = create_model_provider(provider.clone(), /*auth_manager*/ None); + match provider.runtime_base_url().await { + Ok(base_url) => base_url, + Err(err) => { +@@ -384,8 +387,9 @@ + chat_widget.note_rendered_width(tui.terminal.last_known_screen_size.width); + chat_widget.remote_connection = remote_connection; + let thread_and_widget_ms = thread_and_widget_started_at.elapsed().as_millis(); +- chat_widget +- .maybe_prompt_windows_sandbox_enable(should_prompt_windows_sandbox_nux_at_startup); ++ chat_widget.maybe_prompt_windows_sandbox_enable( ++ should_prompt_windows_sandbox_nux_at_startup && !crate::dshx_backend(), ++ ); + + let file_search = FileSearchManager::new(config.cwd.to_path_buf(), app_event_tx.clone()); + let runtime_keymap = RuntimeKeymap::from_config(&config.tui_keymap).map_err(|err| { +@@ -399,7 +403,11 @@ + See the Codex keymap documentation for supported actions and examples." + ) + })?; + #[cfg(not(debug_assertions))] +- let upgrade_version = crate::updates::get_upgrade_version(&config); ++ let upgrade_version = if crate::dshx_backend() { ++ None ++ } else { ++ crate::updates::get_upgrade_version(&config) ++ }; + + let mut app = Self { + model_catalog, +@@ -488,8 +496,9 @@ + // world-writable dirs on Windows. + #[cfg(target_os = "windows")] + { + let startup_permission_profile = app.config.permissions.effective_permission_profile(); +- let should_check = crate::windows_sandbox::level_from_config(&app.config) ++ let should_check = !crate::dshx_backend() ++ && crate::windows_sandbox::level_from_config(&app.config) + != WindowsSandboxLevel::Disabled + && managed_filesystem_sandbox_is_restricted(&startup_permission_profile) + && !app + .config diff --git a/.release/dshx-linux-x64/upstream/patches/codex/0006-dshx-config-ownership.patch b/.release/dshx-linux-x64/upstream/patches/codex/0006-dshx-config-ownership.patch new file mode 100644 index 00000000..456486b7 --- /dev/null +++ b/.release/dshx-linux-x64/upstream/patches/codex/0006-dshx-config-ownership.patch @@ -0,0 +1,13 @@ +diff --git a/codex-rs/tui/src/app/event_dispatch.rs b/codex-rs/tui/src/app/event_dispatch.rs +--- a/codex-rs/tui/src/app/event_dispatch.rs ++++ b/codex-rs/tui/src/app/event_dispatch.rs +@@ -1518,7 +1518,8 @@ impl App { + self.sync_active_thread_service_tier_to_cached_session() + .await; + +- if let Some(default_effort) = default_effort.as_ref() ++ if !crate::dshx_backend() ++ && let Some(default_effort) = default_effort.as_ref() + && let Err(err) = crate::config_update::write_config_batch( + app_server.request_handle(), + crate::config_update::build_model_selection_edits( diff --git a/.release/dshx-linux-x64/upstream/patches/codex/0007-dshx-thread-ownership.patch b/.release/dshx-linux-x64/upstream/patches/codex/0007-dshx-thread-ownership.patch new file mode 100644 index 00000000..41161174 --- /dev/null +++ b/.release/dshx-linux-x64/upstream/patches/codex/0007-dshx-thread-ownership.patch @@ -0,0 +1,46 @@ +diff --git a/codex-rs/tui/src/app_server_session.rs b/codex-rs/tui/src/app_server_session.rs +--- a/codex-rs/tui/src/app_server_session.rs ++++ b/codex-rs/tui/src/app_server_session.rs +@@ -1660,6 +1660,18 @@ fn thread_start_params_from_config( + remote_cwd_override: Option<&std::path::Path>, + session_start_source: Option, + ) -> ThreadStartParams { ++ if crate::dshx_backend() && matches!(thread_params_mode, ThreadParamsMode::Remote) { ++ return ThreadStartParams { ++ cwd: thread_cwd_from_config(config, thread_params_mode, remote_cwd_override), ++ ephemeral: Some(config.ephemeral), ++ history_mode: (!config.ephemeral).then_some(ThreadHistoryMode::Paginated), ++ session_start_source, ++ thread_source: Some(ThreadSource::User), ++ ..ThreadStartParams::default() ++ }; ++ } + let permissions = permissions_selection_from_config(config, thread_params_mode); + let sandbox = permissions + .is_none() +@@ -1703,6 +1715,12 @@ fn thread_resume_params_from_config( + remote_cwd_override: Option<&std::path::Path>, + model_settings: ResumeModelSettings, + ) -> ThreadResumeParams { ++ if crate::dshx_backend() && matches!(thread_params_mode, ThreadParamsMode::Remote) { ++ return ThreadResumeParams { ++ thread_id: thread_id.to_string(), ++ ..ThreadResumeParams::default() ++ }; ++ } + if model_settings == ResumeModelSettings::PreserveExistingThread { + return ThreadResumeParams { + thread_id: thread_id.to_string(), +@@ -1755,6 +1773,12 @@ fn thread_fork_params_from_config( + thread_params_mode: ThreadParamsMode, + remote_cwd_override: Option<&std::path::Path>, + ) -> ThreadForkParams { ++ if crate::dshx_backend() && matches!(thread_params_mode, ThreadParamsMode::Remote) { ++ return ThreadForkParams { ++ thread_id: thread_id.to_string(), ++ ..ThreadForkParams::default() ++ }; ++ } + let permissions = permissions_selection_from_config(&config, thread_params_mode); + let sandbox = permissions + .is_none() diff --git a/.release/dshx-linux-x64/upstream/patches/codex/0008-dshx-resume-hint.patch b/.release/dshx-linux-x64/upstream/patches/codex/0008-dshx-resume-hint.patch new file mode 100644 index 00000000..117c9ffc --- /dev/null +++ b/.release/dshx-linux-x64/upstream/patches/codex/0008-dshx-resume-hint.patch @@ -0,0 +1,17 @@ +diff --git a/codex-rs/tui/src/app.rs b/codex-rs/tui/src/app.rs +--- a/codex-rs/tui/src/app.rs ++++ b/codex-rs/tui/src/app.rs +@@ -471,7 +471,12 @@ fn resume_hint_for_resumable_thread( + rollout_path: Option<&Path>, + ) -> Option { + let thread = resumable_thread(thread_id, thread_name, rollout_path)?; +- codex_utils_cli::resume_hint(thread.thread_name.as_deref(), Some(thread.thread_id)) ++ let hint = codex_utils_cli::resume_hint(thread.thread_name.as_deref(), Some(thread.thread_id)); ++ if crate::dshx_backend() { ++ hint.map(|hint| hint.replacen("codex", "dshx", 1)) ++ } else { ++ hint ++ } + } + + fn rollout_path_is_resumable(rollout_path: &Path) -> bool { diff --git a/.release/dshx-linux-x64/upstream/patches/codex/0009-dshx-slash-capabilities.patch b/.release/dshx-linux-x64/upstream/patches/codex/0009-dshx-slash-capabilities.patch new file mode 100644 index 00000000..df2eb2a3 --- /dev/null +++ b/.release/dshx-linux-x64/upstream/patches/codex/0009-dshx-slash-capabilities.patch @@ -0,0 +1,106 @@ +diff --git a/codex-rs/tui/src/slash_command.rs b/codex-rs/tui/src/slash_command.rs +--- a/codex-rs/tui/src/slash_command.rs ++++ b/codex-rs/tui/src/slash_command.rs +@@ -86,48 +86,48 @@ impl SlashCommand { + pub fn description(self) -> &'static str { + match self { + SlashCommand::Feedback => "send logs to maintainers", + SlashCommand::New => "start a new chat during a conversation", +- SlashCommand::Init => "create an AGENTS.md file with instructions for Codex", ++ SlashCommand::Init => "create an AGENTS.md file with instructions for DeepSeek Harness", + SlashCommand::Compact => "summarize conversation to prevent hitting the context limit", + SlashCommand::Review => "review my current changes and find issues", + SlashCommand::Rename => "rename the current thread", + SlashCommand::Resume => "resume a saved chat", + SlashCommand::Archive => "archive this session and exit", + SlashCommand::Delete => "permanently delete this session and exit", + SlashCommand::Clear => "clear the terminal and start a new chat", + SlashCommand::Fork => "fork the current chat", + SlashCommand::App => "continue this session in the Desktop app", +- SlashCommand::Quit | SlashCommand::Exit => "exit Codex", ++ SlashCommand::Quit | SlashCommand::Exit => "exit DSHX", + SlashCommand::Copy => "copy last response as markdown", + SlashCommand::Export => "export the conversation as markdown", + SlashCommand::Raw => "toggle raw scrollback mode for copy-friendly terminal selection", + SlashCommand::Diff => "show git diff (including untracked files)", + SlashCommand::Mention => "mention a file", +- SlashCommand::Skills => "use skills to improve how Codex performs specific tasks", ++ SlashCommand::Skills => "use skills to improve how DeepSeek Harness performs specific tasks", + SlashCommand::Import => "import setup, this project, and recent chats from Claude Code", + SlashCommand::Hooks => "view and manage lifecycle hooks", + SlashCommand::Status => "show current session configuration and token usage", + SlashCommand::Cd => "change the current working directory", + SlashCommand::Pwd => "show the current working directory", + SlashCommand::Usage => "view account usage or use a usage limit reset", + SlashCommand::DebugConfig => "show config layers and requirement sources for debugging", + SlashCommand::Title => "configure which items appear in the terminal title", + SlashCommand::Statusline => "configure which items appear in the status line", + SlashCommand::Theme => "choose a syntax highlighting theme", + SlashCommand::Pets => "choose or hide the terminal pet", + SlashCommand::Ps => "list background terminals", + SlashCommand::Stop => "stop all background terminals", + SlashCommand::MemoryDrop => "DO NOT USE", + SlashCommand::MemoryUpdate => "DO NOT USE", + SlashCommand::Model => "choose what model and reasoning effort to use", + SlashCommand::Ide => { + "include current selection, open files, and other context from your IDE" + } + SlashCommand::Personality => "choose a communication style for Codex", + SlashCommand::Plan => "switch to Plan mode", + SlashCommand::Goal => "set or view the goal for a long-running task", + SlashCommand::Agents => "view and switch between all active agent sessions", + SlashCommand::MultiAgents => "switch between this session's subagents", + SlashCommand::Side | SlashCommand::Btw => { + "start a side conversation in an ephemeral fork" + } +- SlashCommand::Permissions => "choose what Codex is allowed to do", ++ SlashCommand::Permissions => "choose what DeepSeek Harness is allowed to do", + SlashCommand::Keymap => "remap TUI shortcuts", + SlashCommand::Vim => "toggle Vim mode for the composer", + SlashCommand::ElevateSandbox => "set up elevated agent sandbox", + SlashCommand::SandboxReadRoot => { +@@ -260,7 +260,40 @@ impl SlashCommand { + } + + fn is_visible(self) -> bool { ++ if crate::dshx_backend() ++ && matches!( ++ self, ++ SlashCommand::Ide ++ | SlashCommand::ElevateSandbox ++ | SlashCommand::SandboxReadRoot ++ | SlashCommand::Experimental ++ | SlashCommand::AutoReview ++ | SlashCommand::Memories ++ | SlashCommand::Import ++ | SlashCommand::Hooks ++ | SlashCommand::Review ++ | SlashCommand::Archive ++ | SlashCommand::Delete ++ | SlashCommand::App ++ | SlashCommand::Goal ++ | SlashCommand::MultiAgents ++ | SlashCommand::Side ++ | SlashCommand::Btw ++ | SlashCommand::Cd ++ | SlashCommand::Usage ++ | SlashCommand::DebugConfig ++ | SlashCommand::Ps ++ | SlashCommand::Stop ++ | SlashCommand::Mcp ++ | SlashCommand::Apps ++ | SlashCommand::Plugins ++ | SlashCommand::Logout ++ | SlashCommand::Feedback ++ | SlashCommand::Personality ++ | SlashCommand::MemoryDrop ++ | SlashCommand::MemoryUpdate ++ ) ++ { ++ return false; ++ } + match self { + SlashCommand::SandboxReadRoot => cfg!(target_os = "windows"), + SlashCommand::Copy => !cfg!(target_os = "android"), + SlashCommand::App => cfg!(any(target_os = "macos", target_os = "windows")), + SlashCommand::Rollout | SlashCommand::TestApproval => cfg!(debug_assertions), diff --git a/.release/dshx-linux-x64/upstream/patches/codex/0010-dshx-local-ipc-bridge.patch b/.release/dshx-linux-x64/upstream/patches/codex/0010-dshx-local-ipc-bridge.patch new file mode 100644 index 00000000..153d959a --- /dev/null +++ b/.release/dshx-linux-x64/upstream/patches/codex/0010-dshx-local-ipc-bridge.patch @@ -0,0 +1,187 @@ +diff --git a/codex-rs/Cargo.lock b/codex-rs/Cargo.lock +--- a/codex-rs/Cargo.lock ++++ b/codex-rs/Cargo.lock +@@ -4250,16 +4250,18 @@ + [[package]] + name = "codex-stdio-to-uds" + version = "0.0.0" + dependencies = [ + "anyhow", + "codex-uds", + "codex-utils-cargo-bin", ++ "futures", + "pretty_assertions", + "tempfile", + "tokio", ++ "tokio-tungstenite", + ] + + [[package]] + name = "codex-terminal-detection" + version = "0.0.0" + dependencies = [ +diff --git a/codex-rs/stdio-to-uds/Cargo.toml b/codex-rs/stdio-to-uds/Cargo.toml +--- a/codex-rs/stdio-to-uds/Cargo.toml ++++ b/codex-rs/stdio-to-uds/Cargo.toml +@@ -7,6 +7,10 @@ + [[bin]] + name = "codex-stdio-to-uds" + path = "src/main.rs" ++ ++[[bin]] ++name = "dshx-ipc-bridge" ++path = "src/dshx_ipc_bridge.rs" + + [lib] + name = "codex_stdio_to_uds" +@@ -20,12 +24,14 @@ + [dependencies] + anyhow = { workspace = true } + codex-uds = { workspace = true } ++futures = { workspace = true } + tokio = { workspace = true, features = [ + "io-std", + "io-util", + "macros", + "rt-multi-thread", + ] } ++tokio-tungstenite = { workspace = true } + + [dev-dependencies] + codex-utils-cargo-bin = { workspace = true } +diff --git a/codex-rs/stdio-to-uds/src/dshx_ipc_bridge.rs b/codex-rs/stdio-to-uds/src/dshx_ipc_bridge.rs +new file mode 100644 +--- /dev/null ++++ b/codex-rs/stdio-to-uds/src/dshx_ipc_bridge.rs +@@ -0,0 +1,101 @@ ++#![deny(clippy::print_stdout)] ++ ++use std::io::ErrorKind; ++use std::path::PathBuf; ++ ++use anyhow::Context; ++use codex_uds::UnixListener; ++use futures::SinkExt; ++use futures::StreamExt; ++use tokio::io::AsyncBufReadExt; ++use tokio::io::AsyncWriteExt; ++use tokio::io::BufReader; ++use tokio_tungstenite::accept_async; ++use tokio_tungstenite::tungstenite::Message; ++ ++struct SocketGuard(PathBuf); ++ ++impl Drop for SocketGuard { ++ fn drop(&mut self) { ++ if let Err(err) = std::fs::remove_file(&self.0) ++ && err.kind() != ErrorKind::NotFound ++ { ++ // Best effort only. The launcher removes the unique parent directory. ++ } ++ } ++} ++ ++async fn write_line(stdout: &mut tokio::io::Stdout, line: &str) -> anyhow::Result<()> { ++ stdout.write_all(line.as_bytes()).await?; ++ stdout.write_all(b"\n").await?; ++ stdout.flush().await?; ++ Ok(()) ++} ++ ++#[tokio::main] ++async fn main() -> anyhow::Result<()> { ++ let mut args = std::env::args_os().skip(1); ++ let Some(first) = args.next() else { ++ anyhow::bail!("usage: dshx-ipc-bridge "); ++ }; ++ if first == std::ffi::OsStr::new("--check") { ++ return Ok(()); ++ } ++ if args.next().is_some() { ++ anyhow::bail!("usage: dshx-ipc-bridge "); ++ } ++ ++ let socket_path = PathBuf::from(first); ++ if let Some(parent) = socket_path.parent() { ++ codex_uds::prepare_private_socket_directory(parent) ++ .await ++ .with_context(|| format!("failed to prepare {}", parent.display()))?; ++ } ++ let mut listener = UnixListener::bind(&socket_path) ++ .await ++ .with_context(|| format!("failed to bind {}", socket_path.display()))?; ++ let _guard = SocketGuard(socket_path.clone()); ++ ++ // Stdout is a private JSONL control channel to the Node presentation adapter. ++ // Never log to stdout from this process. ++ let mut stdout = tokio::io::stdout(); ++ write_line(&mut stdout, r#"{"dshxBridge":"ready"}"#).await?; ++ ++ let stream = listener ++ .accept() ++ .await ++ .with_context(|| format!("failed to accept {}", socket_path.display()))?; ++ let mut websocket = accept_async(stream) ++ .await ++ .context("failed to upgrade local DSHX IPC connection")?; ++ let mut stdin_lines = BufReader::new(tokio::io::stdin()).lines(); ++ ++ loop { ++ tokio::select! { ++ incoming = websocket.next() => { ++ match incoming { ++ Some(Ok(Message::Text(text))) => write_line(&mut stdout, &text.to_string()).await?, ++ Some(Ok(Message::Binary(bytes))) => { ++ let text = String::from_utf8(bytes.to_vec()).context("binary IPC frame was not UTF-8")?; ++ write_line(&mut stdout, &text).await?; ++ } ++ Some(Ok(Message::Ping(payload))) => websocket.send(Message::Pong(payload)).await?, ++ Some(Ok(Message::Close(_))) | None => break, ++ Some(Ok(_)) => {} ++ Some(Err(err)) => return Err(err).context("local DSHX IPC websocket failed"), ++ } ++ } ++ outbound = stdin_lines.next_line() => { ++ match outbound? { ++ Some(line) => websocket.send(Message::Text(line.into())).await?, ++ None => { ++ websocket.close(None).await?; ++ break; ++ } ++ } ++ } ++ } ++ } ++ ++ Ok(()) ++} +diff --git a/codex-rs/tui/src/main.rs b/codex-rs/tui/src/main.rs +--- a/codex-rs/tui/src/main.rs ++++ b/codex-rs/tui/src/main.rs +@@ -72,19 +72,13 @@ + "DSHX_APP_SERVER_ENDPOINT is required; DSHX never falls back to the Codex agent runtime" + ) + })?; +- let dshx_token = std::env::var("DSHX_APP_SERVER_TOKEN").map_err(|_| { +- anyhow::anyhow!( +- "DSHX_APP_SERVER_TOKEN is required; DSHX local transport is always authenticated" +- ) +- })?; +- let mut dshx_endpoint = resolve_remote_addr(&dshx_endpoint)?; +- match &mut dshx_endpoint { +- RemoteAppServerEndpoint::WebSocket { auth_token, .. } => { +- *auth_token = Some(dshx_token); +- } +- RemoteAppServerEndpoint::UnixSocket { .. } => { +- anyhow::bail!("DSHX production launcher requires authenticated loopback WebSocket transport") +- } ++ let dshx_endpoint = resolve_remote_addr(&dshx_endpoint) ++ .map_err(|err| anyhow::anyhow!("{err:#}"))?; ++ match &dshx_endpoint { ++ RemoteAppServerEndpoint::WebSocket { .. } => anyhow::bail!( ++ "DSHX production launcher forbids TCP WebSocket transport; use the packaged local IPC bridge" ++ ), ++ RemoteAppServerEndpoint::UnixSocket { .. } => {} + } + let exit_info = run_main( + inner, diff --git a/.release/dshx-linux-x64/upstream/patches/codex/0011-dshx-ipc-self-check.patch b/.release/dshx-linux-x64/upstream/patches/codex/0011-dshx-ipc-self-check.patch new file mode 100644 index 00000000..8fb1079f --- /dev/null +++ b/.release/dshx-linux-x64/upstream/patches/codex/0011-dshx-ipc-self-check.patch @@ -0,0 +1,100 @@ +diff --git a/codex-rs/stdio-to-uds/src/dshx_ipc_bridge.rs b/codex-rs/stdio-to-uds/src/dshx_ipc_bridge.rs +--- a/codex-rs/stdio-to-uds/src/dshx_ipc_bridge.rs ++++ b/codex-rs/stdio-to-uds/src/dshx_ipc_bridge.rs +@@ -2,16 +2,21 @@ + + use std::io::ErrorKind; + use std::path::PathBuf; ++use std::time::SystemTime; ++use std::time::UNIX_EPOCH; + + use anyhow::Context; + use codex_uds::UnixListener; ++use codex_uds::UnixStream; + use futures::SinkExt; + use futures::StreamExt; + use tokio::io::AsyncBufReadExt; + use tokio::io::AsyncWriteExt; + use tokio::io::BufReader; + use tokio_tungstenite::accept_async; ++use tokio_tungstenite::client_async; + use tokio_tungstenite::tungstenite::Message; ++use tokio_tungstenite::tungstenite::client::IntoClientRequest; + + struct SocketGuard(PathBuf); + +@@ -32,6 +37,65 @@ + Ok(()) + } + ++struct DirectoryGuard(PathBuf); ++ ++impl Drop for DirectoryGuard { ++ fn drop(&mut self) { ++ let _ = std::fs::remove_dir_all(&self.0); ++ } ++} ++ ++async fn self_check() -> anyhow::Result<()> { ++ let nonce = SystemTime::now() ++ .duration_since(UNIX_EPOCH) ++ .context("system clock is before Unix epoch")? ++ .as_nanos(); ++ let directory = std::env::temp_dir().join(format!( ++ "dshx-ipc-check-{}-{nonce}", ++ std::process::id() ++ )); ++ codex_uds::prepare_private_socket_directory(&directory) ++ .await ++ .with_context(|| format!("failed to prepare {}", directory.display()))?; ++ let _directory_guard = DirectoryGuard(directory.clone()); ++ let socket_path = directory.join("app.sock"); ++ let mut listener = UnixListener::bind(&socket_path) ++ .await ++ .with_context(|| format!("failed to bind {}", socket_path.display()))?; ++ ++ let server = tokio::spawn(async move { ++ let stream = listener.accept().await.context("self-check accept failed")?; ++ let mut websocket = accept_async(stream) ++ .await ++ .context("self-check server websocket handshake failed")?; ++ match websocket.next().await { ++ Some(Ok(Message::Text(text))) if text.as_str() == "ping" => { ++ websocket.send(Message::Text("pong".into())).await?; ++ } ++ other => anyhow::bail!("self-check server received unexpected frame: {other:?}"), ++ } ++ websocket.close(None).await?; ++ anyhow::Ok(()) ++ }); ++ ++ let stream = UnixStream::connect(&socket_path) ++ .await ++ .with_context(|| format!("failed to connect {}", socket_path.display()))?; ++ let request = "ws://localhost/rpc" ++ .into_client_request() ++ .context("failed to create self-check websocket request")?; ++ let (mut websocket, _) = client_async(request, stream) ++ .await ++ .context("self-check client websocket handshake failed")?; ++ websocket.send(Message::Text("ping".into())).await?; ++ match websocket.next().await { ++ Some(Ok(Message::Text(text))) if text.as_str() == "pong" => {} ++ other => anyhow::bail!("self-check client received unexpected frame: {other:?}"), ++ } ++ server.await.context("self-check server task failed")??; ++ Ok(()) ++} ++ + #[tokio::main] + async fn main() -> anyhow::Result<()> { + let mut args = std::env::args_os().skip(1); +@@ -39,7 +103,7 @@ + anyhow::bail!("usage: dshx-ipc-bridge "); + }; + if first == std::ffi::OsStr::new("--check") { +- return Ok(()); ++ return self_check().await; + } + if args.next().is_some() { + anyhow::bail!("usage: dshx-ipc-bridge "); diff --git a/.release/dshx-linux-x64/upstream/patches/codex/0012-dshx-rc5-presentation-fixes.patch b/.release/dshx-linux-x64/upstream/patches/codex/0012-dshx-rc5-presentation-fixes.patch new file mode 100644 index 00000000..e03017f7 --- /dev/null +++ b/.release/dshx-linux-x64/upstream/patches/codex/0012-dshx-rc5-presentation-fixes.patch @@ -0,0 +1,144 @@ +diff --git a/codex-rs/tui/src/model_catalog.rs b/codex-rs/tui/src/model_catalog.rs +--- a/codex-rs/tui/src/model_catalog.rs ++++ b/codex-rs/tui/src/model_catalog.rs +@@ -12,4 +12,10 @@ impl ModelCatalog { + pub(crate) fn try_list_models(&self) -> Result, Infallible> { + Ok(self.models.clone()) + } ++ ++ pub(crate) fn display_name_for(&self, model: &str) -> Option<&str> { ++ self.models ++ .iter() ++ .find(|preset| preset.model == model) ++ .map(|preset| preset.display_name.as_str()) ++ } + } +diff --git a/codex-rs/tui/src/chatwidget/settings.rs b/codex-rs/tui/src/chatwidget/settings.rs +--- a/codex-rs/tui/src/chatwidget/settings.rs ++++ b/codex-rs/tui/src/chatwidget/settings.rs +@@ -456,6 +456,10 @@ impl ChatWidget { + pub(super) fn refresh_model_display(&mut self) { + let effective = self.effective_collaboration_mode(); +- self.session_header.set_model(effective.model()); ++ let model_display_name = self ++ .model_catalog ++ .display_name_for(effective.model()) ++ .unwrap_or(effective.model()).to_string(); ++ self.session_header.set_model(&model_display_name); + // Keep composer paste affordances aligned with the currently effective model. + self.sync_image_paste_enabled(); + self.sync_service_tier_commands(); +@@ -569,6 +573,8 @@ impl ChatWidget { + if model.is_empty() { + DEFAULT_MODEL_DISPLAY_NAME + } else { +- model ++ self.model_catalog ++ .display_name_for(model) ++ .unwrap_or(model) + } + } +diff --git a/codex-rs/tui/src/chatwidget/session_flow.rs b/codex-rs/tui/src/chatwidget/session_flow.rs +--- a/codex-rs/tui/src/chatwidget/session_flow.rs ++++ b/codex-rs/tui/src/chatwidget/session_flow.rs +@@ -119,8 +119,12 @@ impl ChatWidget { + self.sync_personality_command_enabled(); + self.sync_plugins_command_enabled(); + self.sync_goal_command_enabled(); + self.refresh_plugin_mentions(); +- let model_for_header = self.current_model().to_string(); ++ let model_for_header = if crate::dshx_backend() { ++ self.model_display_name().to_string() ++ } else { ++ self.current_model().to_string() ++ }; + if matches!( + display, + SessionConfiguredDisplay::Normal | SessionConfiguredDisplay::PromptEdit +diff --git a/codex-rs/tui/src/history_cell/session.rs b/codex-rs/tui/src/history_cell/session.rs +--- a/codex-rs/tui/src/history_cell/session.rs ++++ b/codex-rs/tui/src/history_cell/session.rs +@@ -126,13 +126,23 @@ pub(crate) fn new_session_info( + auth_plan: Option, + show_fast_status: bool, + ) -> SessionInfoCell { ++ let header_model = if crate::dshx_backend() { ++ requested_model.to_string() ++ } else { ++ session.model.clone() ++ }; ++ let header_version = if crate::dshx_backend() { ++ option_env!("DSHX_VERSION").unwrap_or(CODEX_CLI_VERSION) ++ } else { ++ CODEX_CLI_VERSION ++ }; + // Header box rendered as history (so it appears at the very top) + let header = SessionHeaderHistoryCell::new( +- session.model.clone(), ++ header_model, + session.reasoning_effort.clone(), + show_fast_status, + config.cwd.to_path_buf(), +- CODEX_CLI_VERSION, ++ header_version, + ) + .with_yolo_mode(has_yolo_permissions( + session.approval_policy, +@@ -175,8 +185,8 @@ pub(crate) fn new_session_info( + .map(|tip| TooltipHistoryCell::new(tip, &config.cwd)) + { + parts.push(Box::new(tooltips)); + } +- if requested_model != session.model.as_str() { ++ if !crate::dshx_backend() && requested_model != session.model.as_str() { + let lines = vec![ + "model changed:".magenta().bold().into(), + format!("requested: {requested_model}").into(), +diff --git a/codex-rs/tui/src/chatwidget/status_surfaces.rs b/codex-rs/tui/src/chatwidget/status_surfaces.rs +--- a/codex-rs/tui/src/chatwidget/status_surfaces.rs ++++ b/codex-rs/tui/src/chatwidget/status_surfaces.rs +@@ -681,11 +681,18 @@ impl ChatWidget { + StatusLineItem::WeeklyLimit => { + let (window, is_secondary) = self + .rate_limit_snapshots_by_limit_id + .get("codex") + .and_then(weekly_status_window)?; + let label = limit_label_for_window(window.window_minutes, is_secondary); + self.status_line_limit_display(Some(window), &label) + } +- StatusLineItem::CodexVersion => Some(CODEX_CLI_VERSION.to_string()), ++ StatusLineItem::CodexVersion => Some( ++ if crate::dshx_backend() { ++ option_env!("DSHX_VERSION").unwrap_or(CODEX_CLI_VERSION) ++ } else { ++ CODEX_CLI_VERSION ++ } ++ .to_string(), ++ ), + StatusLineItem::ContextWindowSize => self + .status_line_context_window_size() + .map(|cws| format!("{} window", format_tokens_compact(cws))), +diff --git a/codex-rs/tui/src/startup_draft.rs b/codex-rs/tui/src/startup_draft.rs +--- a/codex-rs/tui/src/startup_draft.rs ++++ b/codex-rs/tui/src/startup_draft.rs +@@ -447,6 +447,12 @@ fn startup_session_header(config: Option<&Config>) -> Box { + || PathBuf::from("loading"), + |config| config.cwd.to_path_buf(), + ); ++ let header_version = if crate::dshx_backend() { ++ option_env!("DSHX_VERSION").unwrap_or(CODEX_CLI_VERSION) ++ } else { ++ CODEX_CLI_VERSION ++ }; + Box::new( + history_cell::SessionHeaderHistoryCell::new_with_style( + "loading".to_string(), +@@ -456,7 +462,7 @@ fn startup_session_header(config: Option<&Config>) -> Box { + /*reasoning_effort*/ None, + /*show_fast_status*/ false, + directory, +- CODEX_CLI_VERSION, ++ header_version, + ) + .with_yolo_mode(config.is_some_and(history_cell::is_yolo_mode)), + ) diff --git a/scripts/verify-bundle-install.mjs b/scripts/verify-bundle-install.mjs index a5c8ff3a..bb67627a 100644 --- a/scripts/verify-bundle-install.mjs +++ b/scripts/verify-bundle-install.mjs @@ -56,6 +56,70 @@ function fail(message) { process.exitCode = 1; } +/** + * Release-flavor proof: the published per-platform tarball must be a + * self-contained standard bundle — official install into a fresh profile, + * then loader activation with ZERO environment overrides, binaries resolving + * from the installed copy itself. + */ +async function verifyReleaseFlavor(tarball) { + const work = fs.mkdtempSync(path.join(os.tmpdir(), 'dshx-release-e2e-')); + const home = path.join(work, 'home'); + fs.mkdirSync(home, { recursive: true }); + const envR = { ...process.env, DSH_HOME: home }; + // Simulate a clean user environment: no dev overrides may leak in. + for (const key of ['DSHX_IPC_BRIDGE_BIN', 'DSHX_TUI_BIN', 'DSHX_TUI_ARGS', 'DSHX_ATTACH', 'DSHX_HEADLESS', 'DSH_TELEMETRY_DISABLED']) { + delete envR[key]; + } + envR.npm_config_cache = path.join(work, 'npm-cache'); + try { + const dsh = resolveDshInvocation(ROOT, envR); + const add = spawnSync(dsh.command, [...dsh.args, 'plugin', '--profile', PROFILE, 'add', tarball], { + cwd: work, env: envR, encoding: 'utf8' + }); + if (add.status !== 0) throw new Error(`official add failed:\n${add.stderr || add.stdout}`); + const manifest = JSON.parse(fs.readFileSync(path.join(home, 'profiles', PROFILE, 'package.json'), 'utf8')); + if (!manifest.dsh?.profile?.bundles?.includes(NAME)) throw new Error('reconcile missed the bundle layer'); + + // Probe must be a real file: the hmr row resolves process.argv[1]. + const probe = path.join(work, 'probe.mjs'); + fs.writeFileSync(probe, ` + import path from 'node:path'; + const { bootDshxRuntime } = await import(${JSON.stringify(path.join(ROOT, 'src', 'dsh', 'runtime-boot.mjs'))}); + const ctx = await bootDshxRuntime({ cwd: '/tmp', watch: false }); + try { + const s = ctx.get('dshxStartup'), p = ctx.get('dshxPresentation'), fs = await import('node:fs'); + const leafLibs = new Set(Object.keys(${JSON.stringify(PACKAGE.dependencies ?? {})})); + const pm = ${JSON.stringify(path.join(home, 'profiles', PROFILE, 'node_modules', '@deepseek-ai'))}; + const shadowed = fs.existsSync(pm) + ? fs.readdirSync(pm).filter((e) => /^dsh(-|$)/.test(e) && !leafLibs.has('@deepseek-ai/' + e)) + : []; + console.log(JSON.stringify({ + url: p?.url ?? null, + bridgeCommand: s?.bridgeCommand ?? null, + bridgeFromInstalledCopy: typeof s?.bridgeCommand === 'string' && s.bridgeCommand.includes('profiles' + path.sep + 'tui' + path.sep + 'node_modules'), + bridgeExists: typeof s?.bridgeCommand === 'string' && fs.existsSync(s.bridgeCommand), + shadowed + })); + } finally { await ctx.dispose?.(); } + `.replace(/\n {6}/g, '\n')); + const run = spawnSync(process.execPath, [probe], { cwd: work, env: envR, encoding: 'utf8', timeout: 180_000 }); + const lastLine = (run.stdout || '').trim().split('\n').pop(); + let result; + try { result = JSON.parse(lastLine); } catch { + throw new Error(`release probe printed no JSON verdict (exit ${run.status}):\n${(run.stderr || '') + (run.stdout || '')}`); + } + if (!String(result.url || '').startsWith('unix://')) throw new Error(`release activation produced no endpoint: ${lastLine}`); + if (!result.bridgeFromInstalledCopy || !result.bridgeExists) { + throw new Error(`bridge did not resolve from the installed copy: ${result.bridgeCommand}`); + } + if (result.shadowed.length > 0) throw new Error(`stateful runtime copies shadowed: ${result.shadowed.join(', ')}`); + console.log(`[verify-bundle] release ok: activated via ${tarball.split(path.sep).pop()} -> ${result.url}`); + } finally { + fs.rmSync(work, { recursive: true, force: true }); + } +} + try { // In-process boots must see the same DSH_HOME as the spawned CLI steps; // several official plugins (e.g. credentials) read the environment directly. @@ -203,10 +267,25 @@ try { await ctx.dispose?.(); } - console.log('\n[verify-bundle] ALL CHECKS PASSED'); } catch (error) { fail(error instanceof Error ? error.stack : String(error)); console.error(`[verify-bundle] temp workspace preserved for inspection: ${work}`); } finally { if (!process.exitCode) fs.rmSync(work, { recursive: true, force: true }); } + +// Release flavor: when a packaged artifact exists, prove the published +// tarball itself installs and activates with zero environment overrides. +if (!process.exitCode) { + const releaseDir = path.join(ROOT, 'dist', 'release'); + const tarballs = fs.existsSync(releaseDir) + ? fs.readdirSync(releaseDir).filter((f) => f.startsWith('dshx-') && f.endsWith('.tgz')).sort() + : []; + if (tarballs.length === 0) { + console.log('[verify-bundle] release flavor: skipped (build one via scripts/package-platform.mjs)'); + if (process.env.DSHX_REQUIRE_RELEASE === '1') process.exitCode = 1; + } else { + await verifyReleaseFlavor(path.join(releaseDir, tarballs.at(-1))); + } + if (!process.exitCode) console.log('[verify-bundle] ALL CHECKS PASSED'); +} diff --git a/test/dsh-app-server-adapter.test.mjs b/test/tui-protocol-adapter.test.mjs similarity index 100% rename from test/dsh-app-server-adapter.test.mjs rename to test/tui-protocol-adapter.test.mjs diff --git a/test/dsh-codex-shapes.test.mjs b/test/tui-protocol-shapes.test.mjs similarity index 100% rename from test/dsh-codex-shapes.test.mjs rename to test/tui-protocol-shapes.test.mjs From 67a970dea70e51adb26ad7669c6924adc4065a78 Mon Sep 17 00:00:00 2001 From: code-new-bie <245316967+code-new-bie@users.noreply.github.com> Date: Wed, 26 Aug 2026 16:32:14 +0800 Subject: [PATCH 14/60] refactor(tui-protocol): house the pure projection builders beside the dialect user-input, plan-presentation, session-fork, thread-title, history-pages and skills are DSH->Codex view builders consumed only by the protocol layer; they move under src/tui-protocol/ so src/dsh converges on true domain concerns. token-usage and tool-presentation stay shared with the domain-side thread-controller for now. --- src/tui-protocol/adapter.mjs | 12 ++++++------ src/{dsh => tui-protocol}/history-pages.mjs | 0 src/{dsh => tui-protocol}/plan-presentation.mjs | 0 src/{dsh => tui-protocol}/session-fork.mjs | 0 src/{dsh => tui-protocol}/skills.mjs | 0 src/{dsh => tui-protocol}/thread-title.mjs | 0 src/{dsh => tui-protocol}/user-input.mjs | 0 test/dsh-history-pages.test.mjs | 2 +- test/dsh-plan-presentation.test.mjs | 2 +- test/dsh-release-title.test.mjs | 2 +- test/dsh-session-fork.test.mjs | 2 +- 11 files changed, 10 insertions(+), 10 deletions(-) rename src/{dsh => tui-protocol}/history-pages.mjs (100%) rename src/{dsh => tui-protocol}/plan-presentation.mjs (100%) rename src/{dsh => tui-protocol}/session-fork.mjs (100%) rename src/{dsh => tui-protocol}/skills.mjs (100%) rename src/{dsh => tui-protocol}/thread-title.mjs (100%) rename src/{dsh => tui-protocol}/user-input.mjs (100%) diff --git a/src/tui-protocol/adapter.mjs b/src/tui-protocol/adapter.mjs index 2dfaa111..40d6cbf8 100644 --- a/src/tui-protocol/adapter.mjs +++ b/src/tui-protocol/adapter.mjs @@ -13,15 +13,15 @@ import { normalizeSessionHeaders } from './shapes.mjs'; import { executeDshCommand } from '../dsh/commands.mjs'; -import { dshThreadItemsPage, dshThreadTurnsPage } from '../dsh/history-pages.mjs'; +import { dshThreadItemsPage, dshThreadTurnsPage } from './history-pages.mjs'; import { DshHostApi } from '../dsh/host-api.mjs'; -import { codexPlanTarget, threadSettingsUpdatedNotification } from '../dsh/plan-presentation.mjs'; +import { codexPlanTarget, threadSettingsUpdatedNotification } from './plan-presentation.mjs'; import { DshPermissionView } from '../dsh/permissions.mjs'; -import { codexForkAtSeq } from '../dsh/session-fork.mjs'; -import { dshSkillsListEntry } from '../dsh/skills.mjs'; -import { foldDshSessionTitle, threadNameUpdatedNotification } from '../dsh/thread-title.mjs'; +import { codexForkAtSeq } from './session-fork.mjs'; +import { dshSkillsListEntry } from './skills.mjs'; +import { foldDshSessionTitle, threadNameUpdatedNotification } from './thread-title.mjs'; import { DshThreadController } from '../dsh/thread-controller.mjs'; -import { codexInputToDshContent, dshContentText } from '../dsh/user-input.mjs'; +import { codexInputToDshContent, dshContentText } from './user-input.mjs'; import { DshUserQuestionBridge } from '../dsh/user-question-bridge.mjs'; import { DshUserShellBridge } from '../dsh/user-shell.mjs'; import { persistedTokenUsageNotification } from '../dsh/token-usage.mjs'; diff --git a/src/dsh/history-pages.mjs b/src/tui-protocol/history-pages.mjs similarity index 100% rename from src/dsh/history-pages.mjs rename to src/tui-protocol/history-pages.mjs diff --git a/src/dsh/plan-presentation.mjs b/src/tui-protocol/plan-presentation.mjs similarity index 100% rename from src/dsh/plan-presentation.mjs rename to src/tui-protocol/plan-presentation.mjs diff --git a/src/dsh/session-fork.mjs b/src/tui-protocol/session-fork.mjs similarity index 100% rename from src/dsh/session-fork.mjs rename to src/tui-protocol/session-fork.mjs diff --git a/src/dsh/skills.mjs b/src/tui-protocol/skills.mjs similarity index 100% rename from src/dsh/skills.mjs rename to src/tui-protocol/skills.mjs diff --git a/src/dsh/thread-title.mjs b/src/tui-protocol/thread-title.mjs similarity index 100% rename from src/dsh/thread-title.mjs rename to src/tui-protocol/thread-title.mjs diff --git a/src/dsh/user-input.mjs b/src/tui-protocol/user-input.mjs similarity index 100% rename from src/dsh/user-input.mjs rename to src/tui-protocol/user-input.mjs diff --git a/test/dsh-history-pages.test.mjs b/test/dsh-history-pages.test.mjs index 94538a29..a3be5184 100644 --- a/test/dsh-history-pages.test.mjs +++ b/test/dsh-history-pages.test.mjs @@ -1,6 +1,6 @@ import assert from 'node:assert/strict'; import test from 'node:test'; -import { dshThreadItemsPage, dshThreadTurnsPage } from '../src/dsh/history-pages.mjs'; +import { dshThreadItemsPage, dshThreadTurnsPage } from '../src/tui-protocol/history-pages.mjs'; function controller() { const agent = { diff --git a/test/dsh-plan-presentation.test.mjs b/test/dsh-plan-presentation.test.mjs index 0c2170f2..c3bca0d4 100644 --- a/test/dsh-plan-presentation.test.mjs +++ b/test/dsh-plan-presentation.test.mjs @@ -5,7 +5,7 @@ import { codexPlanTarget, effectiveDshPlanState, threadSettingsUpdatedNotification -} from '../src/dsh/plan-presentation.mjs'; +} from '../src/tui-protocol/plan-presentation.mjs'; test('Codex plan/default modes map only to the DSH boolean plan target', () => { assert.equal(codexPlanTarget({ mode: 'plan', settings: {} }), true); diff --git a/test/dsh-release-title.test.mjs b/test/dsh-release-title.test.mjs index 35e507aa..17e34a67 100644 --- a/test/dsh-release-title.test.mjs +++ b/test/dsh-release-title.test.mjs @@ -1,7 +1,7 @@ import assert from 'node:assert/strict'; import test from 'node:test'; import { DshxPresentationAdapter } from '../src/tui-protocol/adapter.mjs'; -import { foldDshSessionTitle } from '../src/dsh/thread-title.mjs'; +import { foldDshSessionTitle } from '../src/tui-protocol/thread-title.mjs'; test('durable title fold is latest-wins over DSH session/title events', () => { assert.equal(foldDshSessionTitle([ diff --git a/test/dsh-session-fork.test.mjs b/test/dsh-session-fork.test.mjs index 098070a4..e2a1de21 100644 --- a/test/dsh-session-fork.test.mjs +++ b/test/dsh-session-fork.test.mjs @@ -1,6 +1,6 @@ import assert from 'node:assert/strict'; import test from 'node:test'; -import { codexForkAtSeq } from '../src/dsh/session-fork.mjs'; +import { codexForkAtSeq } from '../src/tui-protocol/session-fork.mjs'; const events = [ { seq: 1, type: 'turn/start', data: { turn: 1 } }, From 91735e6bc26c7dbe2f6ff9f9178c47f0863d00d5 Mon Sep 17 00:00:00 2001 From: code-new-bie <245316967+code-new-bie@users.noreply.github.com> Date: Wed, 26 Aug 2026 16:42:28 +0800 Subject: [PATCH 15/60] feat(ui): announce the listening endpoint on passive launches + repo metadata Bare `dsh --profile tui` mounts the surface and waits passively; mirror the official web surface's printUrl precedent so the state is always visible instead of a silent hang. Root manifest gains its repository field. --- package.json | 4 ++++ src/dsh/presentation-plugin.mjs | 5 +++++ 2 files changed, 9 insertions(+) diff --git a/package.json b/package.json index 1b2130e3..fc726235 100644 --- a/package.json +++ b/package.json @@ -2,6 +2,10 @@ "name": "@code-new-bie/dshx-tui", "version": "0.0.0-m1", "description": "Codex-grade TUI surface bundle for official DeepSeek Harness", + "repository": { + "type": "git", + "url": "git+https://github.com/code-new-bie/dsh-codex.git" + }, "private": true, "type": "module", "engines": { diff --git a/src/dsh/presentation-plugin.mjs b/src/dsh/presentation-plugin.mjs index 4f379347..3d428d28 100644 --- a/src/dsh/presentation-plugin.mjs +++ b/src/dsh/presentation-plugin.mjs @@ -64,6 +64,11 @@ export async function apply(ctx, config = {}) { close: server.close, tuiCommand: launch.tuiCommand }); + + // Passive launches (bare `dsh --profile tui`, scripts, CI) would otherwise + // sit silently on a live endpoint; mirror the official web surface's + // printUrl precedent so the listening state is always visible. + process.stderr.write(`[dshx] surface listening at ${server.url} — start the interactive TUI with \`dshx\`\n`); return server.close; } From 52e424dfac016843a27e2f6d674868a615999d53 Mon Sep 17 00:00:00 2001 From: code-new-bie <245316967+code-new-bie@users.noreply.github.com> Date: Wed, 26 Aug 2026 16:47:05 +0800 Subject: [PATCH 16/60] =?UTF-8?q?docs(roadmap):=20record=20milestone=205?= =?UTF-8?q?=20=E2=80=94=20standard=20profile-bundle=20delivery?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/ROADMAP.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/docs/ROADMAP.md b/docs/ROADMAP.md index 99c929fd..51919370 100644 --- a/docs/ROADMAP.md +++ b/docs/ROADMAP.md @@ -85,4 +85,17 @@ Implemented: - Codex/DSH pin + patch-queue sync model; - explicit RC promotion checklist in `RELEASE-READINESS.md`. +## Milestone 5 — Standard profile-bundle delivery — implementation complete, real-session acceptance pending + +The surface ships as a regular DSH profile bundle instead of a bespoke launcher runtime: + +- the package manifest declares `dsh.bundle.patch`; official `dsh plugin --profile

add/remove` installs, layers, reconciles and withdraws the surface; +- loader-mounted rows (`dshx-startup`, `dshx-presentation`) own launch parameters, transport and endpoint publication; lifecycle authority is the Cordis root Fiber; +- `bin/dshx` is a thin bootstrap over the same official command (idempotent, version-pinned), and bare `dsh --profile tui` serves the endpoint passively with a visible listening hint; +- the Codex dialect is confined to `src/tui-protocol/`, enforced structurally by the ownership guard; +- per-platform release tarballs embed the pinned TUI + bridge and activate with zero environment overrides; +- verification: `npm run verify:bundle` proves dev-flow and release-flavor delivery end to end (reconcile, composed-tree assertions, activation, single-instance rule); CI gates it in the Linux TUI job. + +Exit gate: one real interactive dogfooding session plus the Windows Terminal/CJK/IME acceptance already required for 1.0. + 1.0 may ship only when the exact candidate has green CI/release evidence and the manual Windows Terminal/CJK/IME UX acceptance is recorded as passing. From 8d18e2665f652e1c7e0b71fec25319395ff0c244 Mon Sep 17 00:00:00 2001 From: code-new-bie <245316967+code-new-bie@users.noreply.github.com> Date: Wed, 26 Aug 2026 16:50:38 +0800 Subject: [PATCH 17/60] ci(release): prove every tagged artifact installs and activates as a bundle MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit After each platform tarball is built, run verify-bundle-install with DSHX_REQUIRE_RELEASE=1: official install into a fresh profile, composed tree assertions, loader activation with zero environment overrides, and the single-instance rule — on Linux and Windows both. --- .github/workflows/release.yml | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 5732589e..a350c46b 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -119,10 +119,30 @@ jobs: if: runner.os != 'Windows' shell: bash run: node scripts/package-platform.mjs + - name: Enable pnpm for the official plugin machinery (Unix) + if: runner.os != 'Windows' + shell: bash + run: corepack enable pnpm + - name: Verify bundle install end to end (Unix) + if: runner.os != 'Windows' + shell: bash + env: + DSHX_REQUIRE_RELEASE: '1' + run: node scripts/verify-bundle-install.mjs - name: Build installable platform tarball (Windows) if: runner.os == 'Windows' shell: pwsh run: node scripts/package-platform.mjs + - name: Enable pnpm for the official plugin machinery (Windows) + if: runner.os == 'Windows' + shell: pwsh + run: corepack enable pnpm + - name: Verify bundle install end to end (Windows) + if: runner.os == 'Windows' + shell: pwsh + env: + DSHX_REQUIRE_RELEASE: '1' + run: node scripts/verify-bundle-install.mjs - name: Clean install smoke (Unix) if: runner.os != 'Windows' shell: bash From 49ef64d0025310604911c23dae6a94ca1c236dd0 Mon Sep 17 00:00:00 2001 From: code-new-bie <245316967+code-new-bie@users.noreply.github.com> Date: Wed, 26 Aug 2026 16:58:11 +0800 Subject: [PATCH 18/60] build: ship release artifacts without debug info Set CARGO_PROFILE_RELEASE_DEBUG=0 (user-overridable) and strip the copied Unix binaries. The Linux TUI drops from 1.1GB to 222MB and the platform tarball from 272MB to 85MB with identical behavior; Windows keeps its debug symbols beside the exe as before. --- .release/dshx-linux-x64/LICENSE | 201 - .release/dshx-linux-x64/NOTICE | 27 - .release/dshx-linux-x64/README.md | 174 - .release/dshx-linux-x64/bin/dshx.mjs | 376 - .release/dshx-linux-x64/cordis.patch.yml | 24 - .release/dshx-linux-x64/npm-shrinkwrap.json | 8299 ----------------- .release/dshx-linux-x64/package.json | 62 - .release/dshx-linux-x64/src/cli/arguments.mjs | 29 - .release/dshx-linux-x64/src/cli/runtime.mjs | 27 - .../dshx-linux-x64/src/dsh/agent-driver.mjs | 213 - .../src/dsh/approval-bridge.mjs | 88 - .release/dshx-linux-x64/src/dsh/commands.mjs | 27 - .../dshx-linux-x64/src/dsh/history-pages.mjs | 77 - .release/dshx-linux-x64/src/dsh/host-api.mjs | 61 - .release/dshx-linux-x64/src/dsh/index.mjs | 25 - .../dshx-linux-x64/src/dsh/local-server.mjs | 363 - .../dshx-linux-x64/src/dsh/permissions.mjs | 106 - .../src/dsh/plan-presentation.mjs | 55 - .../src/dsh/presentation-plugin.mjs | 71 - .../src/dsh/profile-bootstrap.mjs | 99 - .../dshx-linux-x64/src/dsh/runtime-boot.mjs | 270 - .../dshx-linux-x64/src/dsh/session-fork.mjs | 55 - .../src/dsh/session-projector.mjs | 427 - .release/dshx-linux-x64/src/dsh/skills.mjs | 67 - .../dshx-linux-x64/src/dsh/startup-plugin.mjs | 72 - .../src/dsh/thread-controller.mjs | 205 - .../dshx-linux-x64/src/dsh/thread-title.mjs | 19 - .../dshx-linux-x64/src/dsh/token-usage.mjs | 116 - .../src/dsh/tool-presentation.mjs | 219 - .../dshx-linux-x64/src/dsh/user-input.mjs | 106 - .../src/dsh/user-question-bridge.mjs | 101 - .../dshx-linux-x64/src/dsh/user-shell.mjs | 209 - .../src/dsh/workspace-command.mjs | 166 - .../src/protocol/request-broker.mjs | 79 - .../src/tui-protocol/adapter.mjs | 1302 --- .../src/tui-protocol/shapes.mjs | 419 - .release/dshx-linux-x64/upstream/CODEX_COMMIT | 1 - .release/dshx-linux-x64/upstream/DSH_COMMIT | 1 - .../codex/0001-dshx-force-ui-backend.patch | 65 - .../patches/codex/0002-dshx-branding.patch | 38 - .../codex/0003-dshx-approval-semantics.patch | 91 - .../codex/0004-dshx-permission-picker.patch | 60 - .../0005-dshx-skip-codex-onboarding.patch | 112 - .../codex/0006-dshx-config-ownership.patch | 13 - .../codex/0007-dshx-thread-ownership.patch | 46 - .../patches/codex/0008-dshx-resume-hint.patch | 17 - .../codex/0009-dshx-slash-capabilities.patch | 106 - .../codex/0010-dshx-local-ipc-bridge.patch | 187 - .../codex/0011-dshx-ipc-self-check.patch | 100 - .../0012-dshx-rc5-presentation-fixes.patch | 144 - scripts/build-codex-tui.ps1 | 2 + scripts/build-codex-tui.sh | 6 + 52 files changed, 8 insertions(+), 15217 deletions(-) delete mode 100644 .release/dshx-linux-x64/LICENSE delete mode 100644 .release/dshx-linux-x64/NOTICE delete mode 100644 .release/dshx-linux-x64/README.md delete mode 100644 .release/dshx-linux-x64/bin/dshx.mjs delete mode 100644 .release/dshx-linux-x64/cordis.patch.yml delete mode 100644 .release/dshx-linux-x64/npm-shrinkwrap.json delete mode 100644 .release/dshx-linux-x64/package.json delete mode 100644 .release/dshx-linux-x64/src/cli/arguments.mjs delete mode 100644 .release/dshx-linux-x64/src/cli/runtime.mjs delete mode 100644 .release/dshx-linux-x64/src/dsh/agent-driver.mjs delete mode 100644 .release/dshx-linux-x64/src/dsh/approval-bridge.mjs delete mode 100644 .release/dshx-linux-x64/src/dsh/commands.mjs delete mode 100644 .release/dshx-linux-x64/src/dsh/history-pages.mjs delete mode 100644 .release/dshx-linux-x64/src/dsh/host-api.mjs delete mode 100644 .release/dshx-linux-x64/src/dsh/index.mjs delete mode 100644 .release/dshx-linux-x64/src/dsh/local-server.mjs delete mode 100644 .release/dshx-linux-x64/src/dsh/permissions.mjs delete mode 100644 .release/dshx-linux-x64/src/dsh/plan-presentation.mjs delete mode 100644 .release/dshx-linux-x64/src/dsh/presentation-plugin.mjs delete mode 100644 .release/dshx-linux-x64/src/dsh/profile-bootstrap.mjs delete mode 100644 .release/dshx-linux-x64/src/dsh/runtime-boot.mjs delete mode 100644 .release/dshx-linux-x64/src/dsh/session-fork.mjs delete mode 100644 .release/dshx-linux-x64/src/dsh/session-projector.mjs delete mode 100644 .release/dshx-linux-x64/src/dsh/skills.mjs delete mode 100644 .release/dshx-linux-x64/src/dsh/startup-plugin.mjs delete mode 100644 .release/dshx-linux-x64/src/dsh/thread-controller.mjs delete mode 100644 .release/dshx-linux-x64/src/dsh/thread-title.mjs delete mode 100644 .release/dshx-linux-x64/src/dsh/token-usage.mjs delete mode 100644 .release/dshx-linux-x64/src/dsh/tool-presentation.mjs delete mode 100644 .release/dshx-linux-x64/src/dsh/user-input.mjs delete mode 100644 .release/dshx-linux-x64/src/dsh/user-question-bridge.mjs delete mode 100644 .release/dshx-linux-x64/src/dsh/user-shell.mjs delete mode 100644 .release/dshx-linux-x64/src/dsh/workspace-command.mjs delete mode 100644 .release/dshx-linux-x64/src/protocol/request-broker.mjs delete mode 100644 .release/dshx-linux-x64/src/tui-protocol/adapter.mjs delete mode 100644 .release/dshx-linux-x64/src/tui-protocol/shapes.mjs delete mode 100644 .release/dshx-linux-x64/upstream/CODEX_COMMIT delete mode 100644 .release/dshx-linux-x64/upstream/DSH_COMMIT delete mode 100644 .release/dshx-linux-x64/upstream/patches/codex/0001-dshx-force-ui-backend.patch delete mode 100644 .release/dshx-linux-x64/upstream/patches/codex/0002-dshx-branding.patch delete mode 100644 .release/dshx-linux-x64/upstream/patches/codex/0003-dshx-approval-semantics.patch delete mode 100644 .release/dshx-linux-x64/upstream/patches/codex/0004-dshx-permission-picker.patch delete mode 100644 .release/dshx-linux-x64/upstream/patches/codex/0005-dshx-skip-codex-onboarding.patch delete mode 100644 .release/dshx-linux-x64/upstream/patches/codex/0006-dshx-config-ownership.patch delete mode 100644 .release/dshx-linux-x64/upstream/patches/codex/0007-dshx-thread-ownership.patch delete mode 100644 .release/dshx-linux-x64/upstream/patches/codex/0008-dshx-resume-hint.patch delete mode 100644 .release/dshx-linux-x64/upstream/patches/codex/0009-dshx-slash-capabilities.patch delete mode 100644 .release/dshx-linux-x64/upstream/patches/codex/0010-dshx-local-ipc-bridge.patch delete mode 100644 .release/dshx-linux-x64/upstream/patches/codex/0011-dshx-ipc-self-check.patch delete mode 100644 .release/dshx-linux-x64/upstream/patches/codex/0012-dshx-rc5-presentation-fixes.patch diff --git a/.release/dshx-linux-x64/LICENSE b/.release/dshx-linux-x64/LICENSE deleted file mode 100644 index 4606e72e..00000000 --- a/.release/dshx-linux-x64/LICENSE +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - -TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - -1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - -2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - -3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - -4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - -5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - -6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - -7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - -8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - -9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - -END OF TERMS AND CONDITIONS - -APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - -Copyright 2025 OpenAI - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. diff --git a/.release/dshx-linux-x64/NOTICE b/.release/dshx-linux-x64/NOTICE deleted file mode 100644 index 33df6516..00000000 --- a/.release/dshx-linux-x64/NOTICE +++ /dev/null @@ -1,27 +0,0 @@ -DSHX / dsh-codex -Copyright 2026 dsh-codex contributors - -This distribution includes a modified build of OpenAI Codex TUI sourced from: -https://github.com/openai/codex -Pinned source commit: see upstream/CODEX_COMMIT - -OpenAI Codex -Copyright 2025 OpenAI -Licensed under the Apache License, Version 2.0. - -The upstream OpenAI Codex NOTICE states: - -OpenAI Codex -Copyright 2025 OpenAI - -This project includes code derived from Ratatui (https://github.com/ratatui/ratatui), licensed under the MIT license. -Copyright (c) 2016-2022 Florian Dehau -Copyright (c) 2023-2025 The Ratatui Developers - -DSHX modifies only a small presentation/launcher seam in the pinned Codex TUI. -The ordered source patches are distributed under upstream/patches/codex/. - -DeepSeek Harness is not forked or vendored by DSHX. It is installed as an -upstream npm dependency and remains the authoritative runtime for Agent, -Session, model routing, tools, sandboxing, approvals, skills and related -capabilities. Its own package license and notices remain with that dependency. diff --git a/.release/dshx-linux-x64/README.md b/.release/dshx-linux-x64/README.md deleted file mode 100644 index e4bf19e2..00000000 --- a/.release/dshx-linux-x64/README.md +++ /dev/null @@ -1,174 +0,0 @@ -# DSHX (`dsh-codex`) - -DSHX is a terminal frontend for **official DeepSeek Harness** that reuses a pinned Codex TUI thin fork instead of reimplementing a look-alike terminal UI. - -## Product contract - -From a code project, the normal user entry point is: - -```bash -dshx -``` - -No separate Codex installation, remote-mode command, bridge command, DSH WebUI, or manual profile plumbing is part of the production UX. - -The interaction target is the pinned Codex CLI/TUI: welcome screen, composer, slash commands, model and permission pickers, approvals, ask-user flows, tool/shell cells, diffs, plan/reasoning presentation, steering, Ctrl+C interrupt, resume, status/footer, scrolling, resize and mouse behavior. Windows Terminal and CJK/IME are first-class release gates. - -## Plugin usage - -DSHX ships as a standard DSH profile bundle: the package manifest declares -`dsh.bundle.patch`, so the official machinery installs, layers, hot-reloads -and withdraws it like any other composition row set. - -```bash -# Install into any profile (tarball from a release, or this checkout): -dsh plugin --profile tui add ./code-new-bie-dshx-tui-.tgz - -# Withdraw it again; the surface disappears on the next profile start: -dsh plugin --profile tui remove @code-new-bie/dshx-tui -``` - -The zero-argument `dshx` launcher is a thin bootstrap over the same command: -it ensures the selected profile carries this exact package version, boots the -official composition, and spawns the pinned TUI against the endpoint that the -loader-mounted surface rows publish. - -## Ownership boundary - -We maintain only: - -- the Codex TUI thin fork and upstream sync patches; -- TUI behavior and UX parity; -- the `dshx` launcher, local presentation transport and packaging; -- the thinnest practical projection from DSH **public APIs/events** into the TUI protocol. - -We do **not** maintain, fork or recreate DeepSeek Harness capabilities. DSH owns the agent loop, sessions, model routing, tools, sandbox, approval policy, skills, subagents, plugins, jobs/workflows and persistence. - -If DSH does not expose a capability, DSHX waits for upstream or explicitly hides/degrades the corresponding UI. It does not implement a replacement runtime. - -```text -pinned Codex TUI thin fork ← DSHX presentation - │ - │ WebSocket framing over private local UDS - ▼ -dshx-ipc-bridge ← tiny transport bridge; no runtime state - │ - │ JSONL over child stdio - ▼ -DSHX presentation adapter ← translation only - │ -════════════════ ownership boundary ════════════════ - │ official DSH public APIs/events - ▼ -Official DeepSeek Harness ← Agent / Session / tools / policy / persistence -``` - -There is **no TCP listener in the production launch path**. The bridge reuses Codex's own cross-platform `codex_uds` implementation so the Rust TUI and Node DSH composition can stay in separate processes without unsafe FFI. - -## Current integration status - -`release/1.0-rc` is the sole production release-candidate integration branch, reviewed directly against `main` in Draft PR #11. Older M0/M1/thin-launcher/transport PRs are historical workstreams rather than release dependencies. - -The selected production transport is the small local-IPC bridge above. The alternative experiment that added a larger direct-stdio transport implementation inside the Codex client is intentionally excluded from the 1.0 line to keep the maintained upstream diff smaller. - -The candidate implementation includes: - -- zero-argument `dshx` launch and `dshx resume` flows; -- official DSH runtime composition and exact supported DSH rc.8 release-closure checks; -- DSH-backed session/history, model, permissions, approvals, ask-user, tools/shell/diffs, plan/reasoning, steering/interrupt, rename, fork/compaction, skills and subagent presentation boundaries; -- pinned Codex TUI build plus packaged cross-platform local IPC bridge; -- an executable visible-slash-command contract so every runtime-owned command left visible is either DSH-backed or the build fails; -- release artifacts for Linux x64, Windows x64, macOS arm64 and macOS x64; -- clean-install `dshx doctor`, including a real local UDS + WebSocket-framing ping/pong data-plane self-check; -- Linux/macOS real-TUI PTY smoke and Windows real-TUI ConPTY + Chinese-text smoke through the production local-IPC topology; -- fail-closed ownership/security tests that keep DSH authoritative. - -A commit is not called 1.0-ready merely because these paths exist. The exact release candidate must pass the repository CI/release gates and the side-by-side Windows Terminal/CJK/IME acceptance pass described in `docs/RELEASE-READINESS.md` and `docs/UX-PARITY.md`. - -## Install a release artifact - -Production users should install the **platform-specific tarball generated by a published DSHX release**, not build the pinned Codex workspace themselves. - -1. Download the tarball for your platform from the chosen GitHub release and verify its SHA-256 against that release's `SHA256SUMS`. -2. Install the downloaded artifact globally with npm: - -```bash -npm install --global ./dshx---.tgz -``` - -3. Verify the installed product, then enter any code project and start it: - -```bash -dshx --version -dshx doctor -cd /path/to/project -dshx -``` - -Windows PowerShell uses the same npm install command. For a 1.0 release-candidate acceptance run, use `scripts/windows-rc-acceptance.ps1` so the tarball checksum, isolated install, `dshx --version` and `dshx doctor` are verified before the real Windows Terminal/IME comparison. - -The release tarball already contains the matching native `dshx-tui` and `dshx-ipc-bridge` binaries. A separate Codex install, DSH WebUI process, bridge command or remote-mode setup is not part of installation. - -## Build from source - -Source builds are for contributors and DSHX development. The pinned DSH runtime supports Node.js `^22.19.0 || >=24.0.0`; DSHX 1.0 standardizes dependency freezing, CI and release builds on **Node.js 24 LTS / npm 11**. Rust/Cargo, Git and the platform toolchain required by the pinned Codex workspace are also required for native TUI builds. - -The release dependency graph is frozen outside CI so GitHub Actions never mutates the candidate branch. On a trusted Node 24 LTS machine with npm-registry access, generate and verify the lock with: - -```bash -npm run freeze:deps -``` - -Review and commit the generated `package-lock.json`. Do not hand-edit or fabricate it. After the graph has been frozen, all contributor/CI installs use: - -```bash -npm ci -``` - -Linux/macOS: - -```bash -./scripts/build-codex-tui.sh -npm link -dshx doctor -dshx -``` - -Windows PowerShell: - -```powershell -.\scripts\build-codex-tui.ps1 -npm link -dshx doctor -dshx -``` - -`dshx doctor` checks the DSH-compatible Node runtime, the packaged TUI, the local IPC data plane, the `tui` surface profile (bootstrapped idempotently through the official plugin command), the official DSH composition with the loader-activated surface rows, and the isolated DSHX presentation home/IPC path. - -For the full plugin-delivery proof — pack → official install into a throwaway profile → composed-tree assertions → loader activation with a live transport — run: - -```bash -npm run verify:bundle -``` - -## Release model - -GitHub Actions is an automation surface rather than the authority for repository correctness. Ordinary PR/main CI is deliberately lean: one Node 24 core job followed by one Linux TUI job. `release/**` adds real Windows ConPTY and macOS PTY/CJK/resize gates. Only `v*` tags run the full platform packaging, clean-install, provenance, checksum and publication matrix. - -The release workflow builds platform-specific installable tarballs from the frozen npm graph, builds the pinned TUI and IPC bridge, clean-installs each artifact, runs `dshx doctor`, exercises Linux/macOS PTY and Windows ConPTY real-TUI gates, verifies cross-platform provenance, and publishes SHA-256 checksums for both tarballs and provenance sidecars. Release candidates containing `-` in the tag are published as prereleases. - -The publishable `npm-shrinkwrap.json` inside each artifact is derived from the reviewed source `package-lock.json`; packaging does not resolve a second dependency graph. Release sidecars record the source-lock SHA-256 plus the pinned Codex and DSH commits. - -## Design references - -- `docs/ARCHITECTURE.md` -- `docs/RUNTIME-INTEGRATION.md` -- `docs/DSH-CAPABILITY-MATRIX.md` -- `docs/ROADMAP.md` -- `docs/UX-PARITY.md` -- `docs/RELEASE-READINESS.md` -- `SECURITY.md` - -## License - -Apache-2.0 for project-owned code. Synchronized upstream code keeps its applicable upstream notices and license requirements. diff --git a/.release/dshx-linux-x64/bin/dshx.mjs b/.release/dshx-linux-x64/bin/dshx.mjs deleted file mode 100644 index f77847ed..00000000 --- a/.release/dshx-linux-x64/bin/dshx.mjs +++ /dev/null @@ -1,376 +0,0 @@ -#!/usr/bin/env node -import fs from 'node:fs'; -import os from 'node:os'; -import path from 'node:path'; -import process from 'node:process'; -import { spawn, spawnSync } from 'node:child_process'; -import { fileURLToPath } from 'node:url'; -import { parseCliInvocation } from '../src/cli/arguments.mjs'; -import { - DSHX_DOCTOR_BOOT_TIMEOUT_MS, - DSHX_DOCTOR_DISPOSE_TIMEOUT_MS, - isSupportedNodeVersion -} from '../src/cli/runtime.mjs'; -import { ensureProfileInstalled } from '../src/dsh/profile-bootstrap.mjs'; - -const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..'); -const PACKAGE = JSON.parse(fs.readFileSync(path.join(ROOT, 'package.json'), 'utf8')); -const VERSION = PACKAGE.version; -const REQUIRED_RUNTIME_SERVICES = [ - 'agents', - 'agentDefaultModel', - 'llm', - 'sessions', - 'sessionPersistence', - 'sessionQuery', - 'sessionProjections', - 'sessionTitle', - 'attachments', - 'tools', - 'commands', - 'compaction', - 'subagents', - 'permissionPresets', - 'approval', - 'userQuestions', - 'skills', - 'planMode', - // The surface rows themselves: their services exist only when the loader - // activated the bundle patch (dshx-startup / dshx-presentation). - 'dshxStartup', - 'dshxPresentation' -]; - -function usage() { - return `DSHX ${VERSION}\n\nUsage:\n dshx Start DSHX in the current project\n dshx Start with an initial prompt\n dshx resume Open the Codex-style DSH session picker\n dshx resume --last Resume the most recent DSH session\n dshx resume Resume a specific DSH session\n dshx doctor Check packaged TUI, local IPC and official DSH composition\n dshx --version Print version\n dshx --help Show this help\n\nEnvironment:\n DSHX_TUI_BIN Override the packaged DSHX TUI binary (development only)\n DSHX_IPC_BRIDGE_BIN Override the packaged local IPC bridge (development only)\n DSHX_TUI_HOME Override DSHX presentation-only Codex home (development only)\n DSHX_PROFILE Override the DSH profile surface (default: tui)\n DSHX_DEBUG=1 Print DSHX adapter diagnostics\n\nPlugin usage:\n The DSHX surface ships as a standard DSH profile bundle. Manage it through\n the official machinery, e.g.:\n dsh plugin --profile tui add ${PACKAGE.name}\n The zero-argument launcher only bootstraps the same profile via the same\n command, then hands control to the official DSH composition.\n\nProduct boundary:\n DSHX owns only the launcher, Codex TUI thin fork and presentation adapter.\n DeepSeek Harness remains the authoritative Agent/Session/Tool runtime.\n DSHX never reads or writes the user's ordinary CODEX_HOME.\n`; -} - -function commandDetail(command, result) { - if (result.status === 0) return (result.stdout || result.stderr).trim(); - if (result.error) return `${command} failed: ${result.error.message}`; - return `${command} is not runnable${result.stderr ? `: ${result.stderr.trim()}` : ''}`; -} - -function withTimeout(promise, timeoutMs, label) { - let timer; - return Promise.race([ - promise, - new Promise((_, reject) => { - timer = setTimeout(() => reject(new Error(`${label} exceeded ${timeoutMs}ms`)), timeoutMs); - }) - ]).finally(() => clearTimeout(timer)); -} - -function binaryCandidate(baseName) { - const fileName = process.platform === 'win32' ? `${baseName}.exe` : baseName; - return process.env[baseName === 'dshx-tui' ? 'DSHX_TUI_BIN' : 'DSHX_IPC_BRIDGE_BIN'] - || path.join(ROOT, 'dist', 'bin', fileName); -} - -function bootstrapSurfaceProfile(runtimeBoot) { - return ensureProfileInstalled({ - packageRoot: ROOT, - name: PACKAGE.name, - version: VERSION, - profile: process.env.DSHX_PROFILE || runtimeBoot.runtimeInternals.DEFAULT_PROFILE - }); -} - -async function loadRuntimeModules() { - try { - const runtimeBoot = await import('../src/dsh/runtime-boot.mjs'); - let localServerInternals; - try { - ({ localServerInternals } = await import('../src/dsh/local-server.mjs')); - } catch { - localServerInternals = undefined; - } - return { runtimeBoot, localServerInternals }; - } catch (error) { - return { loadError: error instanceof Error ? error.message : String(error) }; - } -} - -function presentationHomeCheck(localServerInternals) { - const home = path.resolve(process.env.DSHX_TUI_HOME || path.join(os.homedir(), '.dshx', 'codex-tui')); - try { - fs.mkdirSync(home, { recursive: true, mode: 0o700 }); - const stat = fs.statSync(home); - if (!stat.isDirectory()) throw new Error('path exists but is not a directory'); - fs.accessSync(home, fs.constants.R_OK | fs.constants.W_OK); - if (!localServerInternals) { - throw new Error('IPC policy unavailable because DSH modules failed to load'); - } - - // On Windows this also enforces that a custom DSHX_TUI_HOME stays below - // the current user's profile ACL boundary. Probe the fixed suffix used by - // the real random rendezvous directory so an obviously-too-long home fails - // in doctor before a runtime boot is attempted. - const socketRoot = localServerInternals.defaultSocketRoot({ home }); - const probeSocket = path.join(socketRoot, 'd-XXXXXX', 's'); - localServerInternals.assertSocketPathSupported(probeSocket); - return { ok: true, detail: home }; - } catch (error) { - return { ok: false, detail: `${home}: ${error instanceof Error ? error.message : String(error)}` }; - } -} - -async function officialRuntimeCheck(runtimeBoot) { - let ctx; - let primaryError; - let cleanupError; - try { - // Doctor deliberately exercises the same official composition and profile - // watcher path as production startup, including the loader-mounted surface - // rows (their services double as row-activation evidence). This catches - // missing native optional dependencies (for example sharp/koffi) that a - // static bundle-entry check cannot detect. The bounded timeout is - // intentionally generous enough for first-run Windows module/native - // initialization on supported hardware. - ctx = await withTimeout( - runtimeBoot.bootDshxRuntime({ cwd: process.cwd(), watch: true }), - DSHX_DOCTOR_BOOT_TIMEOUT_MS, - 'official DSH composition boot' - ); - const missing = REQUIRED_RUNTIME_SERVICES.filter((name) => ctx.get(name) == null); - if (missing.length > 0) { - throw new Error(`official DSH composition is missing required presentation services: ${missing.join(', ')}`); - } - } catch (error) { - primaryError = error; - } finally { - if (ctx) { - try { - await withTimeout( - Promise.resolve(ctx.dispose?.()), - DSHX_DOCTOR_DISPOSE_TIMEOUT_MS, - 'official DSH composition disposal' - ); - } catch (error) { - cleanupError = error; - } - } - } - - if (primaryError) { - const detail = primaryError instanceof Error ? primaryError.message : String(primaryError); - const cleanup = cleanupError - ? `; secondary cleanup failure: ${cleanupError instanceof Error ? cleanupError.message : String(cleanupError)}` - : ''; - return { ok: false, detail: `${detail}${cleanup}` }; - } - if (cleanupError) { - return { - ok: false, - detail: `official DSH composition disposal failed: ${cleanupError instanceof Error ? cleanupError.message : String(cleanupError)}` - }; - } - return { - ok: true, - detail: `official DSH composition boot/dispose (${REQUIRED_RUNTIME_SERVICES.length} required services, surface rows active)` - }; -} - -async function doctor(runtimeBoot) { - const executable = binaryCandidate('dshx-tui'); - const tuiCheck = fs.existsSync(executable) - ? spawnSync(executable, ['--version'], { encoding: 'utf8' }) - : { status: 127, stdout: '', stderr: '', error: null }; - const bridge = binaryCandidate('dshx-ipc-bridge'); - const bridgeCheck = fs.existsSync(bridge) - ? spawnSync(bridge, ['--check'], { encoding: 'utf8' }) - : { status: 127, stdout: '', stderr: '', error: null }; - - const { localServerInternals } = await loadRuntimeModules(); - const homeCheck = presentationHomeCheck(localServerInternals); - let profileDetail = ''; - let profileOk = true; - try { - const ensured = bootstrapSurfaceProfile(runtimeBoot); - profileDetail = `profile '${ensured.profile}' (${ensured.action})`; - } catch (error) { - profileOk = false; - profileDetail = error instanceof Error ? error.message : String(error); - } - const runtimeCheck = profileOk - ? await officialRuntimeCheck(runtimeBoot) - : { ok: false, detail: `skipped: ${profileDetail}` }; - - const rows = [ - ['Node', `${process.version} (required: ${PACKAGE.engines.node})`, isSupportedNodeVersion(process.versions.node)], - [ - 'Pinned Codex TUI', - tuiCheck.status === 0 ? commandDetail(executable, tuiCheck) : (executable ? commandDetail(executable, tuiCheck) : 'not found'), - tuiCheck.status === 0 - ], - [ - 'Local IPC bridge', - bridgeCheck.status === 0 ? `${bridge} (cross-platform Codex UDS)` : (bridge ? commandDetail(bridge, bridgeCheck) : 'not found'), - bridgeCheck.status === 0 - ], - ['Surface profile', profileDetail, profileOk], - ['DeepSeek Harness', runtimeCheck.detail, runtimeCheck.ok], - ['Presentation home / IPC path', homeCheck.detail, homeCheck.ok] - ]; - for (const [name, detail, ok] of rows) { - process.stdout.write(`${ok ? '✓' : '✗'} ${name}: ${detail}\n`); - } - if (rows.some((row) => !row[2])) { - process.stderr.write( - process.platform === 'win32' - ? 'For a source checkout, build the pinned TUI + IPC bridge with `.\\scripts\\build-codex-tui.ps1`; packaged releases include both.\n' - : 'For a source checkout, build the pinned TUI + IPC bridge with `./scripts/build-codex-tui.sh`; packaged releases include both.\n' - ); - process.exitCode = 1; - } -} - -async function run() { - const args = process.argv.slice(2); - let invocation; - - try { - invocation = parseCliInvocation(args); - } catch (error) { - process.stderr.write(`dshx: ${error.message}\n`); - process.exitCode = 2; - return; - } - - if (invocation.kind === 'help') { - process.stdout.write(usage()); - return; - } - if (invocation.kind === 'version') { - process.stdout.write(`${VERSION}\n`); - return; - } - if (invocation.kind === 'doctor') { - const [, runtimeBoot] = await loadRuntimeModules().then((m) => [m.loadError ? undefined : m.runtimeBoot, m.runtimeBoot]); - if (!runtimeBoot) { - process.stderr.write('dshx: failed to load official DeepSeek Harness runtime modules\n'); - process.exitCode = 1; - return; - } - await doctor(runtimeBoot); - return; - } - - if (!isSupportedNodeVersion(process.versions.node)) { - process.stderr.write(`dshx: unsupported Node ${process.version}; pinned DeepSeek Harness requires ${PACKAGE.engines.node}\n`); - process.stderr.write('Use Node 24 LTS for the DSHX 1.0 release baseline.\n'); - process.exitCode = 1; - return; - } - - const [, runtimeBoot] = await loadRuntimeModules().then((m) => [m.loadError ? undefined : m.runtimeBoot, m.runtimeBoot]); - if (!runtimeBoot) { - process.stderr.write('dshx: failed to load official DeepSeek Harness runtime modules\n'); - process.exitCode = 1; - return; - } - - const debug = process.env.DSHX_DEBUG === '1'; - let ctx; - try { - // Bootstrap the surface profile through the official plugin machinery, - // then hand control entirely to the official composition: the loader - // mounts the dshx-startup / dshx-presentation rows declared by the bundle - // patch, and the transport endpoint arrives as a provided service. - bootstrapSurfaceProfile(runtimeBoot); - ctx = await runtimeBoot.bootDshxRuntime({ cwd: process.cwd(), watch: true }); - } catch (error) { - process.stderr.write(`dshx: failed to boot DeepSeek Harness surface profile: ${error instanceof Error ? error.message : error}\n`); - process.exitCode = 1; - return; - } - - const startup = ctx.get('dshxStartup'); - const presentation = ctx.get('dshxPresentation'); - if (!startup || !presentation || typeof presentation.close !== 'function') { - process.stderr.write('dshx: surface rows did not publish dshxStartup/dshxPresentation services\n'); - try { await ctx.dispose?.(); } catch { /* primary failure already reported */ } - process.exitCode = 1; - return; - } - - const executable = startup.tuiCommand; - if (!executable || !fs.existsSync(executable)) { - process.stderr.write(`dshx: packaged TUI binary not found (${executable ?? 'unknown path'})\n`); - process.stderr.write('Run `dshx doctor` for build/install guidance.\n'); - try { await ctx.dispose?.(); } catch { /* ignore secondary */ } - process.exitCode = 127; - return; - } - - const tuiHome = startup.home; - try { - fs.mkdirSync(tuiHome, { recursive: true, mode: 0o700 }); - } catch (error) { - process.stderr.write(`dshx: cannot create presentation home ${tuiHome}: ${error instanceof Error ? error.message : error}\n`); - try { await ctx.dispose?.(); } catch { /* ignore secondary */ } - process.exitCode = 1; - return; - } - - let child; - try { - child = spawn(executable, invocation.tuiArgs, { - cwd: process.cwd(), - env: { - ...process.env, - // Do not inherit CODEX_HOME: DSHX uses Codex code as a presentation - // component only and must not read/write the user's ordinary Codex state. - CODEX_HOME: tuiHome, - ...invocation.resumeEnv, - DSHX_APP_SERVER_ENDPOINT: presentation.url - }, - stdio: 'inherit', - windowsHide: false - }); - } catch (error) { - process.stderr.write(`dshx: failed to launch pinned Codex TUI: ${error instanceof Error ? error.message : error}\n`); - try { await ctx.dispose?.(); } catch { /* ignore secondary */ } - process.exitCode = 127; - return; - } - - let closing = false; - const close = async (exitCode) => { - if (closing) return; - closing = true; - try { - // Root-fiber disposal unwinds the dshx-presentation plugin, whose - // disposer closes the transport; the Fiber remains the sole teardown - // authority. - await ctx.dispose?.(); - } catch (error) { - process.stderr.write(`dshx: shutdown cleanup failed: ${error instanceof Error ? error.message : error}\n`); - if (exitCode === 0) exitCode = 1; - } - process.exitCode = exitCode; - }; - - child.on('error', async (error) => { - process.stderr.write(`dshx: failed to launch pinned Codex TUI: ${error.message}\n`); - await close(127); - }); - child.on('exit', async (code, signal) => { - if (signal && debug) process.stderr.write(`[dshx] TUI exited via ${signal}\n`); - await close(code ?? (signal ? 1 : 0)); - }); - - // Process-lifecycle signals are forwarded to the TUI. Do not intercept - // SIGINT: Ctrl+C is an in-TUI interaction used by Codex to interrupt the - // active DSH turn. - process.once('SIGTERM', () => { - if (!child.killed) child.kill('SIGTERM'); - }); - if (process.platform !== 'win32') { - process.once('SIGHUP', () => { - if (!child.killed) child.kill('SIGHUP'); - }); - } -} - -await run(); diff --git a/.release/dshx-linux-x64/cordis.patch.yml b/.release/dshx-linux-x64/cordis.patch.yml deleted file mode 100644 index 207743f4..00000000 --- a/.release/dshx-linux-x64/cordis.patch.yml +++ /dev/null @@ -1,24 +0,0 @@ -# The DSHX surface bundle patch, riding over this profile's dsh-base layer. -# Loaded automatically because the package manifest declares -# `dsh.bundle.patch`; the loader applies it in `dsh.profile.bundles` order. -# -# Only the competing presentation rows are locked off; every runtime -# capability row remains user-authoritative (a targeted patch replaces a -# row's whole config, and these two carry no config of their own). -# -# Launch inputs flow through the official three-stage pattern: the -# dshx-startup row resolves the launcher/environment descriptor and provides -# the `dshxStartup` service; the dshx-presentation row injects it to start -# the local IPC transport and publish the `dshxPresentation` endpoint. -- id: headless-startup - disabled: true -- id: headless-runner - disabled: true - -- insert: - - id: dshx-startup - name: '@code-new-bie/dshx-tui/startup' - - - id: dshx-presentation - name: '@code-new-bie/dshx-tui/presentation' - inject: [dshxStartup] diff --git a/.release/dshx-linux-x64/npm-shrinkwrap.json b/.release/dshx-linux-x64/npm-shrinkwrap.json deleted file mode 100644 index 099477e2..00000000 --- a/.release/dshx-linux-x64/npm-shrinkwrap.json +++ /dev/null @@ -1,8299 +0,0 @@ -{ - "name": "@code-new-bie/dshx-tui", - "version": "0.0.0-m1", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "@code-new-bie/dshx-tui", - "version": "0.0.0-m1", - "dependencies": { - "@deepseek-ai/dsh-cmdline": "0.1.0-rc.8", - "@deepseek-ai/schemastery": "3.18.1" - }, - "bin": { - "dshx": "./bin/dshx.mjs" - }, - "engines": { - "node": "^22.19.0 || >=24.0.0" - }, - "peerDependencies": { - "@deepseek-ai/dsh": "0.1.0-rc.8", - "@deepseek-ai/dsh-agent": "0.1.0-rc.8", - "@deepseek-ai/dsh-app-boot": "0.1.0-rc.8", - "@deepseek-ai/dsh-host-apiproxy": "0.1.0-rc.8", - "@deepseek-ai/dsh-launch-environment": "0.1.0-rc.8", - "@deepseek-ai/dsh-llm": "0.1.0-rc.8", - "@deepseek-ai/dsh-session": "0.1.0-rc.8" - }, - "license": "Apache-2.0", - "os": [ - "linux" - ], - "cpu": [ - "x64" - ] - }, - "node_modules/@anthropic-ai/sdk": { - "version": "0.91.1", - "resolved": "https://registry.npmmirror.com/@anthropic-ai/sdk/-/sdk-0.91.1.tgz", - "integrity": "sha512-LAmu761tSN9r66ixvmciswUj/ZC+1Q4iAfpedTfSVLeswRwnY3n2Nb6Tsk+cLPP28aLOPWeMgIuTuCcMC6W/iw==", - "dev": true, - "license": "MIT", - "dependencies": { - "json-schema-to-ts": "^3.1.1" - }, - "bin": { - "anthropic-ai-sdk": "bin/cli" - }, - "peerDependencies": { - "zod": "^3.25.0 || ^4.0.0" - }, - "peerDependenciesMeta": { - "zod": { - "optional": true - } - } - }, - "node_modules/@aws-crypto/sha256-browser": { - "version": "5.2.0", - "resolved": "https://registry.npmmirror.com/@aws-crypto/sha256-browser/-/sha256-browser-5.2.0.tgz", - "integrity": "sha512-AXfN/lGotSQwu6HNcEsIASo7kWXZ5HYWvfOmSNKDsEqC4OashTp8alTmaz+F7TC2L083SFv5RdB+qU3Vs1kZqw==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@aws-crypto/sha256-js": "^5.2.0", - "@aws-crypto/supports-web-crypto": "^5.2.0", - "@aws-crypto/util": "^5.2.0", - "@aws-sdk/types": "^3.222.0", - "@aws-sdk/util-locate-window": "^3.0.0", - "@smithy/util-utf8": "^2.0.0", - "tslib": "^2.6.2" - } - }, - "node_modules/@aws-crypto/sha256-js": { - "version": "5.2.0", - "resolved": "https://registry.npmmirror.com/@aws-crypto/sha256-js/-/sha256-js-5.2.0.tgz", - "integrity": "sha512-FFQQyu7edu4ufvIZ+OadFpHHOt+eSTBaYaki44c+akjg7qZg9oOQeLlk77F6tSYqjDAFClrHJk9tMf0HdVyOvA==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@aws-crypto/util": "^5.2.0", - "@aws-sdk/types": "^3.222.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-crypto/supports-web-crypto": { - "version": "5.2.0", - "resolved": "https://registry.npmmirror.com/@aws-crypto/supports-web-crypto/-/supports-web-crypto-5.2.0.tgz", - "integrity": "sha512-iAvUotm021kM33eCdNfwIN//F77/IADDSs58i+MDaOqFrVjZo9bAal0NK7HurRuWLLpF1iLX7gbWrjHjeo+YFg==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "tslib": "^2.6.2" - } - }, - "node_modules/@aws-crypto/util": { - "version": "5.2.0", - "resolved": "https://registry.npmmirror.com/@aws-crypto/util/-/util-5.2.0.tgz", - "integrity": "sha512-4RkU9EsI6ZpBve5fseQlGNUWKMa1RLPQ1dnjnQoe07ldfIzcsGb5hC5W0Dm7u423KWzawlrpbjXBrXCEv9zazQ==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/types": "^3.222.0", - "@smithy/util-utf8": "^2.0.0", - "tslib": "^2.6.2" - } - }, - "node_modules/@aws-sdk/client-bedrock-runtime": { - "version": "3.1048.0", - "resolved": "https://registry.npmmirror.com/@aws-sdk/client-bedrock-runtime/-/client-bedrock-runtime-3.1048.0.tgz", - "integrity": "sha512-u+NT61JZEkRFtpL0CAw1N1dwxnaLgwVXQl/zjJxTGgLyS/jTIdg2SdoEoCTHxgDyCnqa1HEi9QOoE9/pYRNpOQ==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@aws-crypto/sha256-browser": "5.2.0", - "@aws-crypto/sha256-js": "5.2.0", - "@aws-sdk/core": "^3.974.11", - "@aws-sdk/credential-provider-node": "^3.972.42", - "@aws-sdk/eventstream-handler-node": "^3.972.16", - "@aws-sdk/middleware-eventstream": "^3.972.12", - "@aws-sdk/middleware-websocket": "^3.972.19", - "@aws-sdk/token-providers": "3.1048.0", - "@aws-sdk/types": "^3.973.8", - "@smithy/core": "^3.24.2", - "@smithy/fetch-http-handler": "^5.4.2", - "@smithy/node-http-handler": "^4.7.2", - "@smithy/types": "^4.14.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/core": { - "version": "3.977.8", - "resolved": "https://registry.npmmirror.com/@aws-sdk/core/-/core-3.977.8.tgz", - "integrity": "sha512-7+Kcrkvrk9lM/m7jRhHpT4jCdvzGHsuaSRbF8TdzzkY1mRzp/Ogwf9c7H29k4gGhey0BBWhCWr16+t0J61gwmg==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/types": "^3.974.4", - "@aws-sdk/xml-builder": "^3.972.39", - "@aws/lambda-invoke-store": "^0.3.0", - "@smithy/core": "^3.31.1", - "@smithy/signature-v4": "^5.6.12", - "@smithy/types": "^4.16.1", - "bowser": "^2.11.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-env": { - "version": "3.972.69", - "resolved": "https://registry.npmmirror.com/@aws-sdk/credential-provider-env/-/credential-provider-env-3.972.69.tgz", - "integrity": "sha512-AreCFzcB4kH2HF9031Ot0jSJr3KXvRg6e8uDeub20JEVdZU3Bv0sTq1plc7VsT3KiqutlzH7l0j50UcCWHUioA==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "^3.977.8", - "@aws-sdk/types": "^3.974.4", - "@smithy/core": "^3.31.1", - "@smithy/types": "^4.16.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-http": { - "version": "3.972.71", - "resolved": "https://registry.npmmirror.com/@aws-sdk/credential-provider-http/-/credential-provider-http-3.972.71.tgz", - "integrity": "sha512-A8ObcqVmDMnk4F9NozZ7JwmUu9Q4xyBJkmyq1C5U+wNM9ht9J7+EuuyabsLWXZnOoTqFaJuYBYTKf5CTipkEjA==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "^3.977.8", - "@aws-sdk/types": "^3.974.4", - "@smithy/core": "^3.31.1", - "@smithy/fetch-http-handler": "^5.6.13", - "@smithy/node-http-handler": "^4.9.13", - "@smithy/types": "^4.16.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-http/node_modules/@smithy/node-http-handler": { - "version": "4.11.2", - "resolved": "https://registry.npmmirror.com/@smithy/node-http-handler/-/node-http-handler-4.11.2.tgz", - "integrity": "sha512-avwAh9HM3h2lcfjvP3zYIZGf+XVgLQ91wOJ2qoFbNpW1UZeZb33aGlhTZvtkANHfcGhJroRY64525OjfgOg30g==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@smithy/core": "^3.33.2", - "@smithy/types": "^4.17.2", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-ini": { - "version": "3.973.14", - "resolved": "https://registry.npmmirror.com/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.973.14.tgz", - "integrity": "sha512-7c+Wti2LsERNWMfm7ySz3/6RPopFW3Nmn7s63Xpcq6R/tRuY5hpvkHA2xVgi5ukJbvok9l0IDtVEvqTtg+X7dw==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "^3.977.8", - "@aws-sdk/credential-provider-env": "^3.972.69", - "@aws-sdk/credential-provider-http": "^3.972.71", - "@aws-sdk/credential-provider-login": "^3.972.76", - "@aws-sdk/credential-provider-process": "^3.972.69", - "@aws-sdk/credential-provider-sso": "^3.973.13", - "@aws-sdk/credential-provider-web-identity": "^3.972.75", - "@aws-sdk/nested-clients": "^3.997.43", - "@aws-sdk/types": "^3.974.4", - "@smithy/core": "^3.31.1", - "@smithy/credential-provider-imds": "^4.4.16", - "@smithy/types": "^4.16.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-login": { - "version": "3.972.76", - "resolved": "https://registry.npmmirror.com/@aws-sdk/credential-provider-login/-/credential-provider-login-3.972.76.tgz", - "integrity": "sha512-LVixwOnEJfrrfKHeZjBA8pIMTZjNDq8ak8VpcoWUuCJDrSnBNU8POJksULMgvN089P0MXtQYH2Zs627/MK1K0g==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "^3.977.8", - "@aws-sdk/nested-clients": "^3.997.43", - "@aws-sdk/types": "^3.974.4", - "@smithy/core": "^3.31.1", - "@smithy/types": "^4.16.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-node": { - "version": "3.972.80", - "resolved": "https://registry.npmmirror.com/@aws-sdk/credential-provider-node/-/credential-provider-node-3.972.80.tgz", - "integrity": "sha512-bE2qh8ww4iClO1jHsBXdOE8FUgzDbdxbyorNjSCoPSkQd51k3jODItuPZfuwcLHZqDXsH+bI4AMHhqtuyR7mSg==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/credential-provider-env": "^3.972.69", - "@aws-sdk/credential-provider-http": "^3.972.71", - "@aws-sdk/credential-provider-ini": "^3.973.14", - "@aws-sdk/credential-provider-process": "^3.972.69", - "@aws-sdk/credential-provider-sso": "^3.973.13", - "@aws-sdk/credential-provider-web-identity": "^3.972.75", - "@aws-sdk/types": "^3.974.4", - "@smithy/core": "^3.31.1", - "@smithy/credential-provider-imds": "^4.4.16", - "@smithy/types": "^4.16.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-process": { - "version": "3.972.69", - "resolved": "https://registry.npmmirror.com/@aws-sdk/credential-provider-process/-/credential-provider-process-3.972.69.tgz", - "integrity": "sha512-9kpTNdZTrcqXTfhxM7fgl9Z68ek3Fu5oe3Yf+A/pJGibEqpgZxz2tSY7SinmyCIU2PJ+ygY4FPoBBnLpocMtrQ==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "^3.977.8", - "@aws-sdk/types": "^3.974.4", - "@smithy/core": "^3.31.1", - "@smithy/types": "^4.16.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-sso": { - "version": "3.973.13", - "resolved": "https://registry.npmmirror.com/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.973.13.tgz", - "integrity": "sha512-Oc81qauMPzUoTnAS2YKpNwY6sY/LUyQTEeaf6yP197WMxkEBQfcKLR1MFpD7+pNTubXnfkH6gwpji+Gc7iyD2Q==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "^3.977.8", - "@aws-sdk/nested-clients": "^3.997.43", - "@aws-sdk/token-providers": "3.1111.0", - "@aws-sdk/types": "^3.974.4", - "@smithy/core": "^3.31.1", - "@smithy/types": "^4.16.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-sso/node_modules/@aws-sdk/token-providers": { - "version": "3.1111.0", - "resolved": "https://registry.npmmirror.com/@aws-sdk/token-providers/-/token-providers-3.1111.0.tgz", - "integrity": "sha512-JfljgoVtl+s3Qy21n9a7Z48uCQaOXcN74KJ3TEQfPoB293GrXFSt6HSQJF1sTZ8c/5QedEvd3NjJQMO4u9qa5A==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "^3.977.8", - "@aws-sdk/nested-clients": "^3.997.43", - "@aws-sdk/types": "^3.974.4", - "@smithy/core": "^3.31.1", - "@smithy/types": "^4.16.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/credential-provider-web-identity": { - "version": "3.972.75", - "resolved": "https://registry.npmmirror.com/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.972.75.tgz", - "integrity": "sha512-YPN6uoGDgjjjeVFZrcOeCJqmB6zpXoeeNgIjqe+DexJaWqdjVfCCe+VAZwli9Z2h8KhFW8oxkO39emQ1tyz/Mw==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "^3.977.8", - "@aws-sdk/nested-clients": "^3.997.43", - "@aws-sdk/types": "^3.974.4", - "@smithy/core": "^3.31.1", - "@smithy/types": "^4.16.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/eventstream-handler-node": { - "version": "3.972.33", - "resolved": "https://registry.npmmirror.com/@aws-sdk/eventstream-handler-node/-/eventstream-handler-node-3.972.33.tgz", - "integrity": "sha512-1Dd5WyEE2Kb3HvY44u7Ob16ST2W6iutOqsQ8Y2hUmsL2mAH/STlGS1dS9h3IOE6L7Ld3AR2HzKJ6XeCMOw8Peg==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/types": "^3.974.4", - "@smithy/core": "^3.31.1", - "@smithy/types": "^4.16.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/middleware-eventstream": { - "version": "3.972.28", - "resolved": "https://registry.npmmirror.com/@aws-sdk/middleware-eventstream/-/middleware-eventstream-3.972.28.tgz", - "integrity": "sha512-Z1EDXnS01P7H5jVrUx+/dBqV0m7dta7bSxLclkOuDuS93pNNQm0IcT4YLUbuvWKPYNxbI8aTG0p5Br30GSKDgA==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/types": "^3.974.4", - "@smithy/core": "^3.31.1", - "@smithy/types": "^4.16.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/middleware-websocket": { - "version": "3.972.51", - "resolved": "https://registry.npmmirror.com/@aws-sdk/middleware-websocket/-/middleware-websocket-3.972.51.tgz", - "integrity": "sha512-jdgP3jR5Q96j1jjZ98GGwpGg1CBNFIO2YE+vXg8cg8PvNY4NvgQNYJsqDaRX2PYv5gSUX/+C0D58Fhspj9ELMQ==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "^3.977.8", - "@aws-sdk/types": "^3.974.4", - "@smithy/core": "^3.31.1", - "@smithy/fetch-http-handler": "^5.6.13", - "@smithy/signature-v4": "^5.6.12", - "@smithy/types": "^4.16.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">= 14.0.0" - } - }, - "node_modules/@aws-sdk/nested-clients": { - "version": "3.997.43", - "resolved": "https://registry.npmmirror.com/@aws-sdk/nested-clients/-/nested-clients-3.997.43.tgz", - "integrity": "sha512-bit+VpqWNyi3wHxFoTsTliNXimCSL2r2OeDTm7ZrG+YsTZ2D7ofDJ6r/t9PVBn80i6/v0X2h9Tgw6QP2MAKfPw==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "^3.977.8", - "@aws-sdk/signature-v4-multi-region": "^3.996.45", - "@aws-sdk/types": "^3.974.4", - "@smithy/core": "^3.31.1", - "@smithy/fetch-http-handler": "^5.6.13", - "@smithy/node-http-handler": "^4.9.13", - "@smithy/types": "^4.16.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/nested-clients/node_modules/@smithy/node-http-handler": { - "version": "4.11.2", - "resolved": "https://registry.npmmirror.com/@smithy/node-http-handler/-/node-http-handler-4.11.2.tgz", - "integrity": "sha512-avwAh9HM3h2lcfjvP3zYIZGf+XVgLQ91wOJ2qoFbNpW1UZeZb33aGlhTZvtkANHfcGhJroRY64525OjfgOg30g==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@smithy/core": "^3.33.2", - "@smithy/types": "^4.17.2", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@aws-sdk/signature-v4-multi-region": { - "version": "3.996.45", - "resolved": "https://registry.npmmirror.com/@aws-sdk/signature-v4-multi-region/-/signature-v4-multi-region-3.996.45.tgz", - "integrity": "sha512-bBuyztukzXq6plzFGHAWiQt0QXo+HL8b8lX5cFTzkez/74PtS1c0qPFCIVuHkyoT+miH2qOjAcm1/yoro2ESPA==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/types": "^3.974.4", - "@smithy/signature-v4": "^5.6.12", - "@smithy/types": "^4.16.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/token-providers": { - "version": "3.1048.0", - "resolved": "https://registry.npmmirror.com/@aws-sdk/token-providers/-/token-providers-3.1048.0.tgz", - "integrity": "sha512-k0y/GcuesuSfWyUM0WamrGyeZmltRYaPbHO82UDA6mZ/doB+FOHKutikPAtSXMn/hDz970cF+iRuuiYO9VEbAA==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/core": "^3.974.11", - "@aws-sdk/nested-clients": "^3.997.9", - "@aws-sdk/types": "^3.973.8", - "@smithy/core": "^3.24.2", - "@smithy/types": "^4.14.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/types": { - "version": "3.974.4", - "resolved": "https://registry.npmmirror.com/@aws-sdk/types/-/types-3.974.4.tgz", - "integrity": "sha512-dSFDNG00MEz0/xl5gxL62giLd1iYyJsTxZ1I1DOj6lC+bbgLB4TRsYClJg3b62dhXT1uATzsTNXPnC+33EJV3A==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@smithy/types": "^4.16.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/util-locate-window": { - "version": "3.965.10", - "resolved": "https://registry.npmmirror.com/@aws-sdk/util-locate-window/-/util-locate-window-3.965.10.tgz", - "integrity": "sha512-ycwH6Zd2GhuSqdXX9ihbCjeGTB6xOJs+O3+Jb8/zDG9978XU80qs75dfkPJRMNKe5MvBZPuNeFpd4JZKPoUF4g==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws-sdk/xml-builder": { - "version": "3.972.39", - "resolved": "https://registry.npmmirror.com/@aws-sdk/xml-builder/-/xml-builder-3.972.39.tgz", - "integrity": "sha512-FTti8DS5MMWXNUWiRwXAJeYS+0GHHiMy0+7XOhcwk63ILHmfS2UFy2z/HNpZCSOJJ3P3dnWY6hfYNW3DF0nXUA==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@smithy/types": "^4.16.1", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@aws/lambda-invoke-store": { - "version": "0.3.0", - "resolved": "https://registry.npmmirror.com/@aws/lambda-invoke-store/-/lambda-invoke-store-0.3.0.tgz", - "integrity": "sha512-sl4Bm6yiMNYrZKkqqDFWN0UfnWhlS8ivKxrYl+6t0gCLrqr8y3B2IqZZbFRkfaVVp7C/baApyh71P+LeE1A2sQ==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@babel/code-frame": { - "version": "7.29.7", - "resolved": "https://registry.npmmirror.com/@babel/code-frame/-/code-frame-7.29.7.tgz", - "integrity": "sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-validator-identifier": "^7.29.7", - "js-tokens": "^4.0.0", - "picocolors": "^1.1.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-identifier": { - "version": "7.29.7", - "resolved": "https://registry.npmmirror.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz", - "integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/runtime": { - "version": "7.29.7", - "resolved": "https://registry.npmmirror.com/@babel/runtime/-/runtime-7.29.7.tgz", - "integrity": "sha512-Nq8OhGWiZIZGV6hLHoyAKLLcJihP/xFeBMGJoUrxTX2psI8dCifzLhZISFb+VWS3wFMRDmCGw5R+dOySCqPLhw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@deepseek-ai/cordis": { - "version": "4.0.1", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/cordis/-/cordis-4.0.1.tgz", - "integrity": "sha512-YBdskTU2Po1kru3GgcUWUbkTsPMA9LkSQDAY8rBkFJeajdgcQad3QPJZE26JyK99Xb6HaASvoXg2DSUTeN/0Nw==", - "license": "MIT", - "dependencies": { - "@deepseek-ai/cosmokit": "^1.8.2", - "@standard-schema/spec": "^1.1.0" - }, - "bin": { - "cordis": "bin.js" - }, - "peerDependencies": { - "@deepseek-ai/cordis-plugin-include": "^1.0.6", - "@deepseek-ai/cordis-plugin-loader": "^1.0.2" - }, - "peerDependenciesMeta": { - "@deepseek-ai/cordis-plugin-include": { - "optional": true - }, - "@deepseek-ai/cordis-plugin-loader": { - "optional": true - } - } - }, - "node_modules/@deepseek-ai/cordis-plugin-group": { - "version": "1.0.1", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/cordis-plugin-group/-/cordis-plugin-group-1.0.1.tgz", - "integrity": "sha512-E1NThkFB3jn3TCqa6Oc++1zQHqLejF3W2wDwv2BlL3UEmgtBXL1K1j1koc+j676RuiOXtJkUJlPcOntRGKLWBQ==", - "dev": true, - "license": "MIT", - "peer": true, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/cordis-plugin-loader": "^1.0.2" - } - }, - "node_modules/@deepseek-ai/cordis-plugin-hmr": { - "version": "1.0.16", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/cordis-plugin-hmr/-/cordis-plugin-hmr-1.0.16.tgz", - "integrity": "sha512-S7VHfylDg1+Y5O6fdYYZu0KFRAj/snHywcFPnX3KmQYa/qv2Q8IXi4zAt9ABq0BJYqhNoqRlbpGMfIjabgXjKA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.29.0", - "@deepseek-ai/cosmokit": "^1.8.2", - "@deepseek-ai/schemastery": "^3.18.1", - "chokidar": "^4.0.3", - "picomatch": "^4.0.3" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/cordis-plugin-timer": "^1.1.3" - } - }, - "node_modules/@deepseek-ai/cordis-plugin-include": { - "version": "1.0.6", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/cordis-plugin-include/-/cordis-plugin-include-1.0.6.tgz", - "integrity": "sha512-i1VXrZCbv6tk/iUgedCNjrxxArbWT3IvRZGB5sdqJ3ectnihivXXQbRZ8JJ73DSmAPvlMGmrbtjFAfm10yvXRg==", - "devOptional": true, - "license": "MIT", - "dependencies": { - "@deepseek-ai/cosmokit": "^1.8.2", - "js-yaml": "^4.1.0" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/cordis-plugin-loader": "^1.0.2" - } - }, - "node_modules/@deepseek-ai/cordis-plugin-loader": { - "version": "1.0.2", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/cordis-plugin-loader/-/cordis-plugin-loader-1.0.2.tgz", - "integrity": "sha512-RIW9hoVyhYDWdCI9BsvtZccPde1ECLC4OAxupwowGTak78vwVTVdb3HezTSOK1Y1/Ax3Ru0LA1pYOB04CnTxIQ==", - "license": "MIT", - "dependencies": { - "@deepseek-ai/cosmokit": "^1.8.2" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "node-addon-require-builtin": "^0.1.4" - }, - "peerDependenciesMeta": { - "node-addon-require-builtin": { - "optional": true - } - } - }, - "node_modules/@deepseek-ai/cordis-plugin-timer": { - "version": "1.1.3", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/cordis-plugin-timer/-/cordis-plugin-timer-1.1.3.tgz", - "integrity": "sha512-IOkey1VNmJwYa5U8bksyMOnM7mtirqjjbWLr3xA8QybLMK0sMooG3a6iJwtvd8P3MFwo3FQibEg+JPixp37MEw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@deepseek-ai/cosmokit": "^1.8.2" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1" - } - }, - "node_modules/@deepseek-ai/cosmokit": { - "version": "1.8.2", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/cosmokit/-/cosmokit-1.8.2.tgz", - "integrity": "sha512-muBOKtSrUKU5m/xpq8ZXWL6hQ/jgd4PhU2PqH97bcxIiLEJfNwZOGQEx4t/aS/GgxRAR+ra9pMHPMtTHU4sqqA==", - "license": "MIT" - }, - "node_modules/@deepseek-ai/dsh": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh/-/dsh-0.1.0-rc.8.tgz", - "integrity": "sha512-VQU5NlomrKLRgcXuOf+sxWFvqxPA8q9vMhrKPlPPXiOJEhGlGlAdiyxZvZxkCVI+v0zbhe21cY3/luLyxpSzzA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/cordis-plugin-hmr": "^1.0.16", - "@deepseek-ai/cordis-plugin-include": "^1.0.6", - "@deepseek-ai/cordis-plugin-loader": "^1.0.2", - "@deepseek-ai/cordis-plugin-timer": "^1.1.3", - "@deepseek-ai/dsh-agent-instructions": "^0.1.0-rc.8", - "@deepseek-ai/dsh-agent-tool-presentation": "^0.1.0-rc.8", - "@deepseek-ai/dsh-app-boot": "^0.1.0-rc.8", - "@deepseek-ai/dsh-base": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-ui-agent-preset": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-ui-cordis": "^0.1.0-rc.8", - "@deepseek-ai/dsh-cmdline": "^0.1.0-rc.8", - "@deepseek-ai/dsh-command-compact": "^0.1.0-rc.8", - "@deepseek-ai/dsh-command-goal": "^0.1.0-rc.8", - "@deepseek-ai/dsh-compaction-basic": "^0.1.0-rc.8", - "@deepseek-ai/dsh-compaction-tool-result-pruner": "^0.1.0-rc.8", - "@deepseek-ai/dsh-cordis-client-runner": "^0.1.0-rc.8", - "@deepseek-ai/dsh-fs-local": "^0.1.0-rc.8", - "@deepseek-ai/dsh-goal": "^0.1.0-rc.8", - "@deepseek-ai/dsh-goal-round-driver": "^0.1.0-rc.8", - "@deepseek-ai/dsh-headless": "^0.1.0-rc.8", - "@deepseek-ai/dsh-home-paths": "^0.1.0-rc.8", - "@deepseek-ai/dsh-jobs-local": "^0.1.0-rc.8", - "@deepseek-ai/dsh-launch-environment": "^0.1.0-rc.8", - "@deepseek-ai/dsh-mcp-client": "^0.1.0-rc.8", - "@deepseek-ai/dsh-persona": "^0.1.0-rc.8", - "@deepseek-ai/dsh-plan-mode": "^0.1.0-rc.8", - "@deepseek-ai/dsh-pwsh-local": "^0.1.0-rc.8", - "@deepseek-ai/dsh-pwsh-sandbox": "^0.1.0-rc.8", - "@deepseek-ai/dsh-schedule": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session-projection": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session-reference": "^0.1.0-rc.8", - "@deepseek-ai/dsh-skill": "^0.1.0-rc.8", - "@deepseek-ai/dsh-skill-filesystem": "^0.1.0-rc.8", - "@deepseek-ai/dsh-terminal": "^0.1.0-rc.8", - "@deepseek-ai/dsh-terminal-bash": "^0.1.0-rc.8", - "@deepseek-ai/dsh-time-context": "^0.1.0-rc.8", - "@deepseek-ai/dsh-tmux-context": "^0.1.0-rc.8", - "@deepseek-ai/dsh-token-meter": "^0.1.0-rc.8", - "@deepseek-ai/dsh-tool-ask-user": "^0.1.0-rc.8", - "@deepseek-ai/dsh-tool-bash": "^0.1.0-rc.8", - "@deepseek-ai/dsh-tool-bash-persistent": "^0.1.0-rc.8", - "@deepseek-ai/dsh-tool-cordis": "^0.1.0-rc.8", - "@deepseek-ai/dsh-tool-fs": "^0.1.0-rc.8", - "@deepseek-ai/dsh-tool-fs-search": "^0.1.0-rc.8", - "@deepseek-ai/dsh-tool-goal": "^0.1.0-rc.8", - "@deepseek-ai/dsh-tool-jobs": "^0.1.0-rc.8", - "@deepseek-ai/dsh-tool-pwsh": "^0.1.0-rc.8", - "@deepseek-ai/dsh-tool-pwsh-persistent": "^0.1.0-rc.8", - "@deepseek-ai/dsh-tool-ralph": "^0.1.0-rc.8", - "@deepseek-ai/dsh-tool-skill": "^0.1.0-rc.8", - "@deepseek-ai/dsh-tool-str-replace-editor": "^0.1.0-rc.8", - "@deepseek-ai/dsh-tool-subagent": "^0.1.0-rc.8", - "@deepseek-ai/dsh-tool-subagent-control": "^0.1.0-rc.8", - "@deepseek-ai/dsh-tool-todo": "^0.1.0-rc.8", - "@deepseek-ai/dsh-tool-web": "^0.1.0-rc.8", - "@deepseek-ai/dsh-tool-workflow": "^0.1.0-rc.8", - "@deepseek-ai/dsh-web-app": "^0.1.0-rc.8", - "@deepseek-ai/dsh-workflow-worker-thread": "^0.1.0-rc.8", - "commander": "^15.0.0", - "js-yaml": "^4.2.0", - "node-addon-require-builtin": "^0.1.4" - }, - "bin": { - "dsh": "lib/bin.js" - } - }, - "node_modules/@deepseek-ai/dsh-agent": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-agent/-/dsh-agent-0.1.0-rc.8.tgz", - "integrity": "sha512-fOl46ZvzoYHalrlyfOJAHNhzyKeVDTUnZZKNSJEr9GY/98WJTjcV21agVEofTXldkJ7a/ws2HpJkVNJVFMtslg==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", - "@deepseek-ai/dsh-scope": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session": "^0.1.0-rc.8", - "@deepseek-ai/dsh-system-prompt": "^0.1.0-rc.8", - "@deepseek-ai/dsh-typert-protocol": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-agent-default-model": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-agent-default-model/-/dsh-agent-default-model-0.1.0-rc.8.tgz", - "integrity": "sha512-FSmgVy8yeVYx3krUwfWZR3JokLD202FSuEd/ZfGdxA+BhOKAOfhNv539kujatVqXyzCG3XiRNda7zWxCh2h7/A==", - "dev": true, - "license": "MIT", - "dependencies": { - "@deepseek-ai/schemastery": "^3.18.1" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", - "@deepseek-ai/dsh-settings": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-agent-instructions": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-agent-instructions/-/dsh-agent-instructions-0.1.0-rc.8.tgz", - "integrity": "sha512-T+JER2gUZbopOxNeHKUE7EfNof30yihsi7GXKB/lOLoy1XMvd5mlzjSHA/OzqjLxiZyyN4V7XAGURApVD3Z7sw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@deepseek-ai/schemastery": "^3.18.1" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", - "@deepseek-ai/dsh-fs": "^0.1.0-rc.8", - "@deepseek-ai/dsh-home-paths": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session": "^0.1.0-rc.8", - "@deepseek-ai/dsh-tools": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-agent-loop": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-agent-loop/-/dsh-agent-loop-0.1.0-rc.8.tgz", - "integrity": "sha512-6Vg5oLy3UZ6lJKMPxldqqBylKSMOpbV/FRrqzDqn3hGdksYBzt9K2hUJm/rE2RyguYKUKFPm2hExs0nn4HKmWA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@deepseek-ai/schemastery": "^3.18.1" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", - "@deepseek-ai/dsh-scope": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session-persistence": "^0.1.0-rc.8", - "@deepseek-ai/dsh-settings": "^0.1.0-rc.8", - "@deepseek-ai/dsh-system-prompt": "^0.1.0-rc.8", - "@deepseek-ai/dsh-tools": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-agent-presets": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-agent-presets/-/dsh-agent-presets-0.1.0-rc.8.tgz", - "integrity": "sha512-7h+kE0KDrJCk2Y8GAqF4fu4YqZmFi5U8/AarFkGUqRI3HDugD6oYf05c7ZWNF7lQXh1OmwmrSbuPhT/YXJapOg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@deepseek-ai/schemastery": "^3.18.1", - "js-yaml": "^4.1.0" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/cordis-plugin-include": "^1.0.6", - "@deepseek-ai/cordis-plugin-loader": "^1.0.2", - "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", - "@deepseek-ai/dsh-atomic-write": "^0.1.0-rc.8", - "@deepseek-ai/dsh-home-paths": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-scope": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session": "^0.1.0-rc.8", - "@deepseek-ai/dsh-settings": "^0.1.0-rc.8", - "@deepseek-ai/dsh-system-prompt": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-agent-tool-presentation": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-agent-tool-presentation/-/dsh-agent-tool-presentation-0.1.0-rc.8.tgz", - "integrity": "sha512-DQouZBh0yjKy8bi0EHQZrZ1B0E+Sc321o5oIyrrmL3hh1sbBsWVrnTvwKPP+SU7J6gnIzyITJ7qEV7pcCGOB2w==", - "dev": true, - "license": "MIT", - "dependencies": { - "@deepseek-ai/schemastery": "^3.18.1" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-tools": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-anonymous-user-id": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-anonymous-user-id/-/dsh-anonymous-user-id-0.1.0-rc.8.tgz", - "integrity": "sha512-vUESbXtDdqIyelCNqX3ijOfqNfw65iSaJaqzfiqQhmSd9ZrNJ1fPUHl8FoW1BdfK8FjrDyh32R6BtuVpI7Zdhw==", - "dev": true, - "license": "MIT", - "peer": true, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-brand": "^0.1.0-rc.8", - "@deepseek-ai/dsh-home-paths": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-api-gateway": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-api-gateway/-/dsh-api-gateway-0.1.0-rc.8.tgz", - "integrity": "sha512-rNA9+Sq3lXFDmyoFLpXNbcuWg7iFeepCwDi+jt1oGjwZTdZJ2nEWpU6GKlOiqadQjHYzfwEbCqmcuJy32qke/A==", - "dev": true, - "license": "MIT", - "dependencies": { - "@deepseek-ai/dsh-typert-protocol": "^0.1.0-rc.8" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-client-connection": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-typert-registry": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-api-remotes": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-api-remotes/-/dsh-api-remotes-0.1.0-rc.8.tgz", - "integrity": "sha512-s/zmFmU6R+dDxUWbHucIyfVgJG4v8kXa3YRjwjMO+Bu871ZG5Zsht6cvRqeSyu0A/Gs06ZfKYeKE0sdbCZ1NiA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@deepseek-ai/dsh-typert-protocol": "^0.1.0-rc.8" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", - "@deepseek-ai/dsh-agent-presets": "^0.1.0-rc.8", - "@deepseek-ai/dsh-api-gateway": "^0.1.0-rc.8", - "@deepseek-ai/dsh-commands": "^0.1.0-rc.8", - "@deepseek-ai/dsh-cordis-host-runner": "^0.1.0-rc.8", - "@deepseek-ai/dsh-credentials": "^0.1.0-rc.8", - "@deepseek-ai/dsh-file-reference": "^0.1.0-rc.8", - "@deepseek-ai/dsh-goal": "^0.1.0-rc.8", - "@deepseek-ai/dsh-host-plugin-inventory": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", - "@deepseek-ai/dsh-message-feedback": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session-persistence": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session-reference": "^0.1.0-rc.8", - "@deepseek-ai/dsh-settings": "^0.1.0-rc.8", - "@deepseek-ai/dsh-typert-registry": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-app-boot": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-app-boot/-/dsh-app-boot-0.1.0-rc.8.tgz", - "integrity": "sha512-DS63o1PhX2Gvqdgl6Wd8vZnLl0qo8gJ9LpSHXeJBJL9HITpLPhdVYE3X6S0icIYdbGO2plNyhxVJOSN6ibO7VA==", - "dev": true, - "license": "MIT", - "dependencies": { - "js-yaml": "^4.2.0" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/cordis-plugin-group": "^1.0.1", - "@deepseek-ai/cordis-plugin-hmr": "^1.0.16", - "@deepseek-ai/cordis-plugin-include": "^1.0.6", - "@deepseek-ai/cordis-plugin-loader": "^1.0.2", - "@deepseek-ai/dsh-home-paths": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-launch-environment": "^0.1.0-rc.8", - "@deepseek-ai/dsh-system-prompt": "^0.1.0-rc.8" - }, - "peerDependenciesMeta": { - "@deepseek-ai/cordis-plugin-hmr": { - "optional": true - } - } - }, - "node_modules/@deepseek-ai/dsh-atomic-write": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-atomic-write/-/dsh-atomic-write-0.1.0-rc.8.tgz", - "integrity": "sha512-SWP+NAat3oteaPi47zLPz4vxeYCHNVmFpN1aeKDuPHpe/ouNTl+WcyIONAJ+1MbZ+8APWhSaJIVu6ORJEUhVGw==", - "dev": true, - "license": "MIT", - "peer": true, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-attachment": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-attachment/-/dsh-attachment-0.1.0-rc.8.tgz", - "integrity": "sha512-cCrg4WWiav7pGtbdU8dJTpAG28cPnkWVB2YPOrlBCgBbhQziGcG9Dv67Ti6L3PI4OQKC55gYBFinQghFO/7FGg==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-brand": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-attachment-local": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-attachment-local/-/dsh-attachment-local-0.1.0-rc.8.tgz", - "integrity": "sha512-TPsDbDPA8yoE3hw1MtrW61AMh72oMiCY+rkO3bDnvc4MtGwKvXcHWtbNPeVpLgMeznaXsnTU3GUp9Fa6PXdp8A==", - "dev": true, - "license": "MIT", - "dependencies": { - "@deepseek-ai/schemastery": "^3.18.1", - "sharp": "^0.35.3" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-attachment": "^0.1.0-rc.8", - "@deepseek-ai/dsh-home-paths": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-base": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-base/-/dsh-base-0.1.0-rc.8.tgz", - "integrity": "sha512-aMjXT6d5t8SGQg24geOSX6O0ky+hJLijhzZklDcICrBvGSKXvuS8jxLOcL5u4s4pFCODXhuOpvTfFuUhN2RK3Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "@deepseek-ai/cordis-plugin-hmr": "^1.0.16", - "@deepseek-ai/cordis-plugin-timer": "^1.1.3", - "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", - "@deepseek-ai/dsh-agent-default-model": "^0.1.0-rc.8", - "@deepseek-ai/dsh-agent-instructions": "^0.1.0-rc.8", - "@deepseek-ai/dsh-agent-loop": "^0.1.0-rc.8", - "@deepseek-ai/dsh-api-gateway": "^0.1.0-rc.8", - "@deepseek-ai/dsh-attachment-local": "^0.1.0-rc.8", - "@deepseek-ai/dsh-bash-sandbox": "^0.1.0-rc.8", - "@deepseek-ai/dsh-command-compact": "^0.1.0-rc.8", - "@deepseek-ai/dsh-command-feedback": "^0.1.0-rc.8", - "@deepseek-ai/dsh-command-goal": "^0.1.0-rc.8", - "@deepseek-ai/dsh-commands": "^0.1.0-rc.8", - "@deepseek-ai/dsh-compaction-basic": "^0.1.0-rc.8", - "@deepseek-ai/dsh-compaction-tool-result-pruner": "^0.1.0-rc.8", - "@deepseek-ai/dsh-credentials-local": "^0.1.0-rc.8", - "@deepseek-ai/dsh-fs-local": "^0.1.0-rc.8", - "@deepseek-ai/dsh-fs-observation-policy": "^0.1.0-rc.8", - "@deepseek-ai/dsh-fs-sandbox": "^0.1.0-rc.8", - "@deepseek-ai/dsh-goal": "^0.1.0-rc.8", - "@deepseek-ai/dsh-goal-round-driver": "^0.1.0-rc.8", - "@deepseek-ai/dsh-jobs-local": "^0.1.0-rc.8", - "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", - "@deepseek-ai/dsh-llm-deepseek": "^0.1.0-rc.8", - "@deepseek-ai/dsh-llm-pi-ai": "^0.1.0-rc.8", - "@deepseek-ai/dsh-llm-retry": "^0.1.0-rc.8", - "@deepseek-ai/dsh-permission-presets": "^0.1.0-rc.8", - "@deepseek-ai/dsh-plan-mode": "^0.1.0-rc.8", - "@deepseek-ai/dsh-pwsh-sandbox": "^0.1.0-rc.8", - "@deepseek-ai/dsh-repeat-tool-reminder": "^0.1.0-rc.8", - "@deepseek-ai/dsh-sandbox-local": "^0.1.0-rc.8", - "@deepseek-ai/dsh-sandbox-policy": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session-checkpoint-policy": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session-persistence-jsonl": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session-projection": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session-query-sqlite": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session-telemetry-otel": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session-title": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session-title-first-prompt-llm": "^0.1.0-rc.8", - "@deepseek-ai/dsh-settings-file": "^0.1.0-rc.8", - "@deepseek-ai/dsh-shell-env": "^0.1.0-rc.8", - "@deepseek-ai/dsh-skill": "^0.1.0-rc.8", - "@deepseek-ai/dsh-skill-badge": "^0.1.0-rc.8", - "@deepseek-ai/dsh-skill-filesystem": "^0.1.0-rc.8", - "@deepseek-ai/dsh-spill-local": "^0.1.0-rc.8", - "@deepseek-ai/dsh-spill-policy": "^0.1.0-rc.8", - "@deepseek-ai/dsh-subagent": "^0.1.0-rc.8", - "@deepseek-ai/dsh-subagent-fork-in-process": "^0.1.0-rc.8", - "@deepseek-ai/dsh-subagent-spawn-in-process": "^0.1.0-rc.8", - "@deepseek-ai/dsh-subprocess-local": "^0.1.0-rc.8", - "@deepseek-ai/dsh-system-prompt": "^0.1.0-rc.8", - "@deepseek-ai/dsh-token-meter": "^0.1.0-rc.8", - "@deepseek-ai/dsh-tool-bash": "^0.1.0-rc.8", - "@deepseek-ai/dsh-tool-call-timeout-policy": "^0.1.0-rc.8", - "@deepseek-ai/dsh-tool-fs": "^0.1.0-rc.8", - "@deepseek-ai/dsh-tool-fs-search": "^0.1.0-rc.8", - "@deepseek-ai/dsh-tool-goal": "^0.1.0-rc.8", - "@deepseek-ai/dsh-tool-jobs": "^0.1.0-rc.8", - "@deepseek-ai/dsh-tool-pwsh": "^0.1.0-rc.8", - "@deepseek-ai/dsh-tool-ralph": "^0.1.0-rc.8", - "@deepseek-ai/dsh-tool-skill": "^0.1.0-rc.8", - "@deepseek-ai/dsh-tool-str-replace-editor": "^0.1.0-rc.8", - "@deepseek-ai/dsh-tool-subagent": "^0.1.0-rc.8", - "@deepseek-ai/dsh-tool-subagent-control": "^0.1.0-rc.8", - "@deepseek-ai/dsh-tool-subagent-report": "^0.1.0-rc.8", - "@deepseek-ai/dsh-tool-todo": "^0.1.0-rc.8", - "@deepseek-ai/dsh-tool-web": "^0.1.0-rc.8", - "@deepseek-ai/dsh-tool-workflow": "^0.1.0-rc.8", - "@deepseek-ai/dsh-tools": "^0.1.0-rc.8", - "@deepseek-ai/dsh-typert-loader": "^0.1.0-rc.8", - "@deepseek-ai/dsh-typert-registry": "^0.1.0-rc.8", - "@deepseek-ai/dsh-user-approval": "^0.1.0-rc.8", - "@deepseek-ai/dsh-user-questions": "^0.1.0-rc.8", - "@deepseek-ai/dsh-web": "^0.1.0-rc.8", - "@deepseek-ai/dsh-web-search-deepseek": "^0.1.0-rc.8", - "@deepseek-ai/dsh-workflow-worker-thread": "^0.1.0-rc.8" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-bash-local": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-bash-local/-/dsh-bash-local-0.1.0-rc.8.tgz", - "integrity": "sha512-vMf3dMRrvVvwWCLJxobYONSebPtWqy2ZZKpRZ6o5fBrZbM88irbvL6F/6r/mu4ADTIDigUtpoxlRpOEQKbSuTg==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@deepseek-ai/schemastery": "^3.18.1" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-settings": "^0.1.0-rc.8", - "@deepseek-ai/dsh-shell": "^0.1.0-rc.8", - "@deepseek-ai/dsh-subprocess": "^0.1.0-rc.8", - "@deepseek-ai/dsh-timeout": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-bash-sandbox": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-bash-sandbox/-/dsh-bash-sandbox-0.1.0-rc.8.tgz", - "integrity": "sha512-gCFrmFwYyxjXJsSRrzs5RbvCli0I0Tn9JAJEHCWSskE8x9iCVU7ljtmrKvgRYr0J4YeXwzteNSfNhlJqasu/QQ==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-bash-local": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-sandbox": "^0.1.0-rc.8", - "@deepseek-ai/dsh-sandbox-policy": "^0.1.0-rc.8", - "@deepseek-ai/dsh-shell": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-brand": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-brand/-/dsh-brand-0.1.0-rc.8.tgz", - "integrity": "sha512-402aUAfHxIZJrArBV4gDf0I/A/69A/By26FX6HTIOyFmCnB4wUBKh8jnglz1CorKWdZy8AKldAhh8HQhQEbGOQ==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-client-connection": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-client-connection/-/dsh-client-connection-0.1.0-rc.8.tgz", - "integrity": "sha512-O1Y1NmkvJjpR/rCYkzulRrKbFwUbpMlINR4G6fbpGXaLy0VzTqN+ptk0b3wJ4RrnKPi4WWLKNNdV647Fg/1sCw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@deepseek-ai/schemastery": "^3.18.1", - "ws": "^8.21.0" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-attachment": "^0.1.0-rc.8", - "@deepseek-ai/dsh-commands": "^0.1.0-rc.8", - "@deepseek-ai/dsh-host-apiproxy": "^0.1.0-rc.8", - "@deepseek-ai/dsh-host-webserver": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session": "^0.1.0-rc.8", - "@deepseek-ai/dsh-tools": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-client-hmr": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-client-hmr/-/dsh-client-hmr-0.1.0-rc.8.tgz", - "integrity": "sha512-Olzlpiw+2VIhNOZVEgi22b2U0jSv6HciAQpKj41TggI7oV+jhRDC2GuYFJoRQ8XBs3mcJCLG0DZtAcGrRP8n9Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "@deepseek-ai/schemastery": "^3.18.1" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/cordis-plugin-loader": "^1.0.2", - "@deepseek-ai/dsh-client-modules": "^0.1.0-rc.8", - "@deepseek-ai/dsh-host-webserver": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-client-locale": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-client-locale/-/dsh-client-locale-0.1.0-rc.8.tgz", - "integrity": "sha512-S8ztym/oFU1aWPDtSZLTGWfprUBIuhfOrRNlw/qMAwhavJiQU/Ag0plg19JffGiOMAQuz2BU2n2mW/xhbpA5Vw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@deepseek-ai/schemastery": "^3.18.1" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-api-remotes": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-connection": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-runtime": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-ui-settings": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-settings": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-client-modules": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-client-modules/-/dsh-client-modules-0.1.0-rc.8.tgz", - "integrity": "sha512-K+uDZSmSbpmHFpvrKkdctHHDIjimv1NWDZoc7CYy7QIk0Vuis4jShDau6H5L0B9TScWBDyXAz/R7rXttFlwseA==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/cordis-plugin-loader": "^1.0.2", - "@deepseek-ai/dsh-host-webserver": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-client-runtime": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-client-runtime/-/dsh-client-runtime-0.1.0-rc.8.tgz", - "integrity": "sha512-wW/nktO/GVbGO/k163NlyJab/rK4D6xS5EL0bhYw4ojF1mxmWfrb3RUEYR5LcEUpFx/yXUHsUSgeO1ezmgIrvw==", - "dev": true, - "license": "MIT", - "dependencies": { - "immer": "^10.1.1", - "zustand": "~4.4.7" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", - "@deepseek-ai/dsh-api-remotes": "^0.1.0-rc.8", - "@deepseek-ai/dsh-attachment": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-connection": "^0.1.0-rc.8", - "@deepseek-ai/dsh-commands": "^0.1.0-rc.8", - "@deepseek-ai/dsh-host-apiproxy": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", - "@deepseek-ai/dsh-llm-retry": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session-projection": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session-title": "^0.1.0-rc.8", - "@deepseek-ai/dsh-tools": "^0.1.0-rc.8", - "@deepseek-ai/dsh-typert-protocol": "^0.1.0-rc.8", - "@deepseek-ai/dsh-typert-registry": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-client-ui-agent-preset": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-client-ui-agent-preset/-/dsh-client-ui-agent-preset-0.1.0-rc.8.tgz", - "integrity": "sha512-z+okJSOT2/uAA4oomx1WNNl/2k9HsoNDmtewOeQVfSy9C8Ey9YBoVoiSQDsYyDHhesxxlBI8RMLU44Pj/w1uug==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-api-remotes": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-connection": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-locale": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-runtime": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-ui-conversation": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-ui-settings": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-client-ui-attachment": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-client-ui-attachment/-/dsh-client-ui-attachment-0.1.0-rc.8.tgz", - "integrity": "sha512-TiKZEUGd22AFxkWpgQCLW9VmuSgWQ11RlIQd0941wPAc4RDZxtkjQWDMOlvRS/m8Oqod/5oKr3U6WRCZKS81vA==", - "dev": true, - "license": "MIT", - "dependencies": { - "clsx": "^2.0.0" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-attachment": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-runtime": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-ui-conversation": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-client-ui-brand-official": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-client-ui-brand-official/-/dsh-client-ui-brand-official-0.1.0-rc.8.tgz", - "integrity": "sha512-eHzJkJGOKlQpap6uYaAZSh62MyJFEoPX8EvIp/kV3YHFDr4bZNc7Yg+ZLMaEXfIjPXKp26FhPiCIia9SP56n8A==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-client-runtime": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-ui-conversation": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-ui-sidebar": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-client-ui-commands": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-client-ui-commands/-/dsh-client-ui-commands-0.1.0-rc.8.tgz", - "integrity": "sha512-nMDF0MbRM03AEmQJzXCbXQWZxSfVPHBO0z+9DqR6LgGXshYLkzVMp1zkfvqLs5QwFAwDSci4vi/GONJOBSL5WA==", - "dev": true, - "license": "MIT", - "dependencies": { - "clsx": "^2.0.0" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-api-remotes": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-locale": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-runtime": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-ui-conversation": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-ui-input-trigger": "^0.1.0-rc.8", - "@deepseek-ai/dsh-commands": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-client-ui-conversation": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-client-ui-conversation/-/dsh-client-ui-conversation-0.1.0-rc.8.tgz", - "integrity": "sha512-GnQSE47/goSm1UzxQpYQrQnMJLyTmYFH6NENdrOxrVJxQnB55ruactgM1kVwfFnc/WUQVYy0599AK7pxjbxjMg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@deepseek-ai/schemastery": "^3.18.1", - "clsx": "^2.0.0" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", - "@deepseek-ai/dsh-api-remotes": "^0.1.0-rc.8", - "@deepseek-ai/dsh-attachment": "^0.1.0-rc.8", - "@deepseek-ai/dsh-brand": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-connection": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-locale": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-runtime": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-ui-input-trigger": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-ui-layout": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-ui-settings": "^0.1.0-rc.8", - "@deepseek-ai/dsh-commands": "^0.1.0-rc.8", - "@deepseek-ai/dsh-compaction": "^0.1.0-rc.8", - "@deepseek-ai/dsh-goal": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-llm-retry": "^0.1.0-rc.8", - "@deepseek-ai/dsh-permission-presets": "^0.1.0-rc.8", - "@deepseek-ai/dsh-plan-mode": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session-stats": "^0.1.0-rc.8", - "@deepseek-ai/dsh-settings": "^0.1.0-rc.8", - "@deepseek-ai/dsh-token-meter": "^0.1.0-rc.8", - "@deepseek-ai/dsh-tool-todo": "^0.1.0-rc.8", - "@deepseek-ai/dsh-tools": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-client-ui-cordis": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-client-ui-cordis/-/dsh-client-ui-cordis-0.1.0-rc.8.tgz", - "integrity": "sha512-NvaSJxqC+HNPLPYPINHzJGRHI427mHSB2aaTGoyc9EFrYVJjvKpNu1QusWwObae5Y/Tx43I2NpFKTAcNVPXkOw==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-api-remotes": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-connection": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-locale": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-runtime": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-ui-input-trigger": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-ui-sidebar": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-ui-tool": "^0.1.0-rc.8", - "@deepseek-ai/dsh-cordis-client-runner": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-client-ui-deliverables": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-client-ui-deliverables/-/dsh-client-ui-deliverables-0.1.0-rc.8.tgz", - "integrity": "sha512-b0XZ/V7FPpTTtmHoKNEVOgl9bJGXGqktzMNNJgifHGl/Us1nNnQVDhM9XDbuUV5iXFPnRrKsR29OTnuTB+txZA==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-client-connection": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-locale": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-runtime": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-ui-conversation": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-system-prompt": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-client-ui-directory-picker-browse": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-client-ui-directory-picker-browse/-/dsh-client-ui-directory-picker-browse-0.1.0-rc.8.tgz", - "integrity": "sha512-sjQcMuut8CRjqnFZHzX1Zzs1zISDlp/gYQVM9Wkyt9KF+XJfV5pHP0KTHZHwOslAqt2OJMnE38uW2yVncLg3sA==", - "dev": true, - "license": "MIT", - "dependencies": { - "clsx": "^2.0.0" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-client-locale": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-runtime": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-ui-workspace": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-client-ui-directory-picker-native": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-client-ui-directory-picker-native/-/dsh-client-ui-directory-picker-native-0.1.0-rc.8.tgz", - "integrity": "sha512-UPR5kSjfMGjLpO41fXXVxcen9Bq9eCzonStnhqMMk/6zC2EQUDkRs+KhYmaInkHI/CMjdTBBqBPRwjFG2iEsYQ==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-client-runtime": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-ui-workspace": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-client-ui-goal": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-client-ui-goal/-/dsh-client-ui-goal-0.1.0-rc.8.tgz", - "integrity": "sha512-kAs6DktlELshs27S3nnjzciK9bGhL2b6RXmZ/mUNYwgiYxeYY4/QYynSNbD0ZQINe0VeGy6yQTv9dbqDBArndA==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-api-remotes": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-locale": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-runtime": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-ui-conversation": "^0.1.0-rc.8", - "@deepseek-ai/dsh-commands": "^0.1.0-rc.8", - "@deepseek-ai/dsh-goal": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session": "^0.1.0-rc.8", - "@deepseek-ai/dsh-typert-protocol": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-client-ui-input-trigger": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-client-ui-input-trigger/-/dsh-client-ui-input-trigger-0.1.0-rc.8.tgz", - "integrity": "sha512-uVJEZ1ftUdMemLvNf17gzB6ThYw0DL4k+0kcQrUPc6LHNQ2ZeuuvOz/931OlqzzUKMtlAGZgy0LvWyJ62LlSog==", - "dev": true, - "license": "MIT", - "dependencies": { - "clsx": "^2.0.0" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-client-locale": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-runtime": "^0.1.0-rc.8", - "@deepseek-ai/dsh-file-reference": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-client-ui-jobs": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-client-ui-jobs/-/dsh-client-ui-jobs-0.1.0-rc.8.tgz", - "integrity": "sha512-gCJR9ymswAZa8OiyZQUKa9GpxRT2sP76tfqBGcF5pRN0xOKudlREM6xD3as2knY5EZELW5qQMVKlVVJZ2Uu7fA==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-client-locale": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-runtime": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-ui-conversation": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-client-ui-layout": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-client-ui-layout/-/dsh-client-ui-layout-0.1.0-rc.8.tgz", - "integrity": "sha512-tbHawbf8FsJqdwnXrU46V8u13bfAFVQQf0hA0OXH4k0PiLiThdZgQFn/T94+56JMUzD1QLqe7DLmNz29cwmjvQ==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-client-runtime": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-ui-theme": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-client-ui-message-feedback": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-client-ui-message-feedback/-/dsh-client-ui-message-feedback-0.1.0-rc.8.tgz", - "integrity": "sha512-tzm/vvhysNa3+1BlTnuj3WJit5+u8U1NDecLqMPTm6U1P2s2bjKtvUpmMNqk+AdeYGYcJjXPadLEuWSNsIWFlQ==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-api-remotes": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-connection": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-locale": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-runtime": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-ui-conversation": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-message-feedback": "^0.1.0-rc.8", - "@deepseek-ai/dsh-typert-protocol": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-client-ui-model-selection": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-client-ui-model-selection/-/dsh-client-ui-model-selection-0.1.0-rc.8.tgz", - "integrity": "sha512-ODRo7IX4VKkgy6C0ibElP5p1Ek6NBm6Qz6S95cZQH2J+PXWTb57/6UvNfxqyst8nFh1wll4oRb1m4fm6MU/fqA==", - "dev": true, - "license": "MIT", - "dependencies": { - "clsx": "^2.1.1" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-api-remotes": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-connection": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-locale": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-runtime": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-ui-commands": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-ui-conversation": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-ui-input-trigger": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-client-ui-permission-presets": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-client-ui-permission-presets/-/dsh-client-ui-permission-presets-0.1.0-rc.8.tgz", - "integrity": "sha512-mYF/TX4GVJgRxDYPIk/iQKkGXz8qHkfFJE3GqIw5E27g+Msfg8AEGqfWEPp4CZeIK/3zcgpMLzgjMLOliWZ2dA==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-api-remotes": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-connection": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-locale": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-runtime": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-ui-commands": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-ui-input-trigger": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-ui-settings": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-permission-presets": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-client-ui-plan": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-client-ui-plan/-/dsh-client-ui-plan-0.1.0-rc.8.tgz", - "integrity": "sha512-OmCuuYCqSlbYqd4s781WipQNKWdHGUn8TPIxrKrcbe94vJacuBtIUIJkDi48dy0IimI+ln/eHxD9WC/9+bJEmA==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-api-remotes": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-locale": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-runtime": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-ui-conversation": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-plan-mode": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-client-ui-reference": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-client-ui-reference/-/dsh-client-ui-reference-0.1.0-rc.8.tgz", - "integrity": "sha512-9qQYmOqG58qlsYNipOMsrL+Ay5Imx8lHJk9GV1rW++LGl6HMb6V1qZBHGIAwO/KOOInnJSEZE65DYB54r+z1Fw==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-api-remotes": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-locale": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-runtime": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-ui-input-trigger": "^0.1.0-rc.8", - "@deepseek-ai/dsh-file-reference": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session-reference": "^0.1.0-rc.8", - "@deepseek-ai/dsh-typert-protocol": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-client-ui-renderer": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-client-ui-renderer/-/dsh-client-ui-renderer-0.1.0-rc.8.tgz", - "integrity": "sha512-/MpR9i++feUFNzJgCChLfct1RphTPJ1WKfZrIsczjyOAZNBzAM5LRjpvM0ZO5Vg7rs7id+PLJYuUKy2e2V5aAA==", - "dev": true, - "license": "MIT", - "dependencies": { - "use-sync-external-store": "1.2.0" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-client-runtime": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-client-ui-settings": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-client-ui-settings/-/dsh-client-ui-settings-0.1.0-rc.8.tgz", - "integrity": "sha512-qSOjpmglOPsLzx6Q5yysrU4c4W6QWFOkyVyqePA5lNPOdny2MH19qbuNleQHbiBo4Zadh/dtBn/SuNRfSp+pjw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@deepseek-ai/schemastery": "^3.18.1" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-api-remotes": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-connection": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-runtime": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-settings": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-client-ui-settings-general": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-client-ui-settings-general/-/dsh-client-ui-settings-general-0.1.0-rc.8.tgz", - "integrity": "sha512-lGGLCV17yUhKTHFAL+LWNY6LICLHmL614TbgaTFC80HWqeduURKzHU7a2PoySyMC2AOvYGpKjIRNUfifhv3aZw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@deepseek-ai/schemastery": "^3.18.1", - "clsx": "^2.0.0" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-api-remotes": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-connection": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-locale": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-runtime": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-ui-settings": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-ui-sidebar": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-settings": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-client-ui-settings-models": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-client-ui-settings-models/-/dsh-client-ui-settings-models-0.1.0-rc.8.tgz", - "integrity": "sha512-6iTLiQ4+4ErqV2e0Lxeunr1Q0JLFJ3EcJ1KcxvT0mEy5xzZuilX7KJxsBWq11q3Wy/I0MYhbHZzZC+d42mFM4g==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-api-remotes": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-connection": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-locale": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-runtime": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-ui-settings": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-client-ui-settings-plugin-inventory": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-client-ui-settings-plugin-inventory/-/dsh-client-ui-settings-plugin-inventory-0.1.0-rc.8.tgz", - "integrity": "sha512-IiixKrJbNqn4D8kvpSIRbxsfetEEbYN5Z3Uz209UWLOiY8Ja9VdQaVbh6BZlecO9BXX1Lgo8l8q+tXlC0IpifA==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-api-remotes": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-locale": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-runtime": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-ui-settings": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-client-ui-settings-plugins": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-client-ui-settings-plugins/-/dsh-client-ui-settings-plugins-0.1.0-rc.8.tgz", - "integrity": "sha512-BLLFFxBz4TmnXXsR5bnQaLMboXBOvCfhoqSbdPFqkqrmJSD+3KGbg4SQJZPcfLL19Kq7qeDraPCXwxo3wpIULg==", - "dev": true, - "license": "MIT", - "dependencies": { - "clsx": "^2.0.0" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-api-remotes": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-connection": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-locale": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-runtime": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-ui-settings": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-client-ui-sidebar": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-client-ui-sidebar/-/dsh-client-ui-sidebar-0.1.0-rc.8.tgz", - "integrity": "sha512-7wcBnS27j8iIVDuai8BVifxcDZd5DIjlHgNHQKx8xQM+x92VKhiFOoMccjhXNaE6sExCUsER1OWRVp65MJvjqg==", - "dev": true, - "license": "MIT", - "dependencies": { - "clsx": "^2.0.0" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-client-locale": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-runtime": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-ui-layout": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-client-ui-skill": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-client-ui-skill/-/dsh-client-ui-skill-0.1.0-rc.8.tgz", - "integrity": "sha512-s9tW3tDQ/82TzZcUHC/dZy5zmPppFKbSXnBotQDvjAU+rkS3/4k4Y6u9LffyZ813OjCoCfs7GOfWHAyZ0VmBag==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-api-remotes": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-connection": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-locale": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-runtime": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-ui-input-trigger": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-ui-tool": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-client-ui-subagent": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-client-ui-subagent/-/dsh-client-ui-subagent-0.1.0-rc.8.tgz", - "integrity": "sha512-uK23jWwzFXbAELsnqS+7A4jL3Q/Ft8AI1hPrJE1ssldq535znexgdGAguZFC17fG+L0OWUtqwAKdXHmjyzqLiQ==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-client-locale": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-runtime": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-ui-conversation": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-ui-input-trigger": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-subagent": "^0.1.0-rc.8", - "@deepseek-ai/dsh-token-meter": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-client-ui-theme": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-client-ui-theme/-/dsh-client-ui-theme-0.1.0-rc.8.tgz", - "integrity": "sha512-orLl5eoWOnvjj76lI6xucE+lT+o+ouniRMSFsuYwF1DNH2pbyfVPQYJWL3iM55gE28yyZJGgmtmABnQBiEF5iA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@deepseek-ai/schemastery": "^3.18.1", - "clsx": "^2.0.0" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-api-remotes": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-connection": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-locale": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-runtime": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-ui-settings": "^0.1.0-rc.8", - "@deepseek-ai/dsh-host-webserver": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-settings": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-client-ui-tool": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-client-ui-tool/-/dsh-client-ui-tool-0.1.0-rc.8.tgz", - "integrity": "sha512-+Mtgx56PptrtoN4Q36yISe3u0lnVazdqV9s+1cLU2C2sAw7bB7o2Y/J9PBPiuBSsK8rmCLbUPYK6QefenwFE7Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "clsx": "^2.0.0" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-api-remotes": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-connection": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-locale": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-runtime": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-ui-conversation": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-client-ui-trajectory": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-client-ui-trajectory/-/dsh-client-ui-trajectory-0.1.0-rc.8.tgz", - "integrity": "sha512-nEKtvkbNhk1Qau8jpyvGfcGLCL2Tfmw6Oi72i2oiZ/DHIcsBaeD0JVWOraEmQp3jYVjuuLSdjdCiPkuNU9nwgw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@tanstack/react-virtual": "^3.14.9", - "diff": "^9.0.0" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-locale": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-runtime": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-ui-conversation": "^0.1.0-rc.8", - "@deepseek-ai/dsh-compaction": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-tools": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-client-ui-trajectory/node_modules/@tanstack/react-virtual": { - "version": "3.14.10", - "resolved": "https://registry.npmmirror.com/@tanstack/react-virtual/-/react-virtual-3.14.10.tgz", - "integrity": "sha512-SRyoUbdFMRHuYXMijV5H4ZarQWpXkj3iANq8OFre+pybeVap8ZJjZ3Nz9bVjx4d8PfobVUQUdKyyyHYk3E+djw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@tanstack/virtual-core": "3.17.8" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/tannerlinsley" - }, - "peerDependencies": { - "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", - "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" - } - }, - "node_modules/@deepseek-ai/dsh-client-ui-trajectory/node_modules/react": { - "version": "19.2.8", - "resolved": "https://registry.npmmirror.com/react/-/react-19.2.8.tgz", - "integrity": "sha512-PWaYA1L/q9u2u7xYQi+Y3L3Yfnie7XyLeaJICV1MGD6LprsBxcAqGjYyr0eY3p+QdsA+x/Irkt4Qif8D63+Sbw==", - "dev": true, - "license": "MIT", - "peer": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/@deepseek-ai/dsh-client-ui-trajectory/node_modules/react-dom": { - "version": "19.2.8", - "resolved": "https://registry.npmmirror.com/react-dom/-/react-dom-19.2.8.tgz", - "integrity": "sha512-rVprimfGBG3DR+Tq0IQG2DT5PxKth1WIGDmj5yPmlzr4YBe7uyE+Du4oVqTDXZSHGGGXRtTJEGSSePyQCMBglQ==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "scheduler": "^0.27.0" - }, - "peerDependencies": { - "react": "^19.2.8" - } - }, - "node_modules/@deepseek-ai/dsh-client-ui-user-questions": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-client-ui-user-questions/-/dsh-client-ui-user-questions-0.1.0-rc.8.tgz", - "integrity": "sha512-zv2U7Ur1ovGSU7j5mwsiCHUK/L20IXRcSFBis3kDZ9nMMl9m0N+56bXrZtJD1U9kTU7gtJ4Xat+rDpr3uTn0JA==", - "dev": true, - "license": "MIT", - "dependencies": { - "clsx": "^2.0.0" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-api-remotes": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-locale": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-runtime": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-ui-conversation": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-client-ui-workflow-run": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-client-ui-workflow-run/-/dsh-client-ui-workflow-run-0.1.0-rc.8.tgz", - "integrity": "sha512-lVvzaR66JwR2lgdURooLEyinUFu5cSaJLWBgdLetw0Z1B6N4RzBNwiIZxmIEZKwaVS7vhO9w6mphGV+4ujiypA==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-client-locale": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-runtime": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-ui-conversation": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session": "^0.1.0-rc.8", - "@deepseek-ai/dsh-tool-workflow": "^0.1.0-rc.8", - "@deepseek-ai/dsh-workflow": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-client-ui-workspace": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-client-ui-workspace/-/dsh-client-ui-workspace-0.1.0-rc.8.tgz", - "integrity": "sha512-Il4hRRV9cDXyZptVC/OKHHOPNd84SwtflHCJ6RP97+OYxnENftdKgHENX7Kqf1RsSXF8RwmOtEvZoHljvYD79A==", - "dev": true, - "license": "MIT", - "dependencies": { - "clsx": "^2.0.0" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-client-connection": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-locale": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-runtime": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-ui-conversation": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-ui-sidebar": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-cmdline": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-cmdline/-/dsh-cmdline-0.1.0-rc.8.tgz", - "integrity": "sha512-xsnNFm2XpMD9wpBBLq80x8yXTi664DHywkLwxgAhDsWyp9tB2aSWaWVKxugPWSWwrB3F4nfloWqaeUfgXRFtBQ==", - "license": "MIT", - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/cordis-plugin-loader": "^1.0.2", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-code-runtime": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-code-runtime/-/dsh-code-runtime-0.1.0-rc.8.tgz", - "integrity": "sha512-6ZKyEE7dHH1UkKe5b0lg18Byww/7ocZyrNMVjAoUWEWp5i96Brf9Eavu9q3zepBMDMZJErCfV0pyt7KDhBJSig==", - "dev": true, - "license": "MIT", - "peer": true, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-code-runtime-worker-thread": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-code-runtime-worker-thread/-/dsh-code-runtime-worker-thread-0.1.0-rc.8.tgz", - "integrity": "sha512-l9fsKYZN2qthnR8fbH8LrTbhWman8rjFCumIttahOKvQEjFMWImY1p8ypM3QtreAtUF8jyHdDnlV8xWQLfanmA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@deepseek-ai/schemastery": "^3.18.1" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-code-runtime": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session": "^0.1.0-rc.8", - "@deepseek-ai/dsh-timeout": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-command-compact": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-command-compact/-/dsh-command-compact-0.1.0-rc.8.tgz", - "integrity": "sha512-3Zlgw9ghDvj2/22/O7V4kvkxKRfknQw4t9ks5GtBEEVRuU9ullpFElAwq/EZ049zeCnmHnyskyJmwYZRIGaiRA==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-commands": "^0.1.0-rc.8", - "@deepseek-ai/dsh-compaction": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-command-feedback": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-command-feedback/-/dsh-command-feedback-0.1.0-rc.8.tgz", - "integrity": "sha512-RqEcutd+nHVGND/JobUybb8HsgRigr5iEowDk0D7aZeXFJ3tN/0pW67w7DOxdhAVnODIpWg5tSnFpCT8fS78kQ==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-anonymous-user-id": "^0.1.0-rc.8", - "@deepseek-ai/dsh-commands": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session-telemetry": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-command-goal": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-command-goal/-/dsh-command-goal-0.1.0-rc.8.tgz", - "integrity": "sha512-kMjRuGJA79czVNzx//JEMrjAqDvYpiaOSH95NUu+Mome76S34jmnhCnIyzcg02GcXelDbk9epELAz5HR1Yti/Q==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-commands": "^0.1.0-rc.8", - "@deepseek-ai/dsh-goal": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-llm": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-commands": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-commands/-/dsh-commands-0.1.0-rc.8.tgz", - "integrity": "sha512-/i99EDLrUyd4bUVn4d7XS46vg09ZE0ervbE/aQaVUWLjDYKrarb7hPx9slADAg5/cUlJsN6L6CP544h9qlUo4g==", - "dev": true, - "license": "MIT", - "dependencies": { - "zod": "^4.4.3" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", - "@deepseek-ai/dsh-attachment": "^0.1.0-rc.8", - "@deepseek-ai/dsh-brand": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", - "@deepseek-ai/dsh-scope": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session": "^0.1.0-rc.8", - "@deepseek-ai/dsh-typert-protocol": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-compaction": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-compaction/-/dsh-compaction-0.1.0-rc.8.tgz", - "integrity": "sha512-sWNqZqejzpKsnEMPsNVA/WYK4S59XlYJtnWw8wCPushzQdUt5zhf+g7LVx0cStSozEfwurxRvaZdOmNaa4WhNQ==", - "dev": true, - "license": "MIT", - "peer": true, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-brand": "^0.1.0-rc.8", - "@deepseek-ai/dsh-commands": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-compaction-basic": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-compaction-basic/-/dsh-compaction-basic-0.1.0-rc.8.tgz", - "integrity": "sha512-UWAUbJbxFQTI3m4LnwZDlcYOfzWNFN1WLjy0qNONNcz3BBa5Nu9kcz4C9jioSp6pg3KMfUNUOtbBRySigTIt7g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@deepseek-ai/schemastery": "^3.18.1" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", - "@deepseek-ai/dsh-commands": "^0.1.0-rc.8", - "@deepseek-ai/dsh-compaction": "^0.1.0-rc.8", - "@deepseek-ai/dsh-compaction-tool-result-pruner": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session": "^0.1.0-rc.8", - "@deepseek-ai/dsh-token-meter": "^0.1.0-rc.8" - }, - "peerDependenciesMeta": { - "@deepseek-ai/dsh-compaction-tool-result-pruner": { - "optional": true - } - } - }, - "node_modules/@deepseek-ai/dsh-compaction-tool-result-pruner": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-compaction-tool-result-pruner/-/dsh-compaction-tool-result-pruner-0.1.0-rc.8.tgz", - "integrity": "sha512-Mk1QE57HxCMScgQ9ury0o7AM14h6g41cDg1G2kiNqD4Z2LBwFTlZJJAgipyhts4mcr1hz2WZTc8Xgbl9067ONA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@deepseek-ai/schemastery": "^3.18.1" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-compaction": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session": "^0.1.0-rc.8", - "@deepseek-ai/dsh-token-meter": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-cordis-client-runner": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-cordis-client-runner/-/dsh-cordis-client-runner-0.1.0-rc.8.tgz", - "integrity": "sha512-UbV2zFdOCubLAjQkmYi+6aPxxDfFTSshiyL4EHRbZyqQTdhrnDMfkY48SiVz8s026+E8xxGRPU4kNf3lg5DGeA==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/cordis-plugin-loader": "^1.0.2", - "@deepseek-ai/dsh-api-remotes": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-connection": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-modules": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-runtime": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-ui-theme": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-cordis-host-runner": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-cordis-host-runner/-/dsh-cordis-host-runner-0.1.0-rc.8.tgz", - "integrity": "sha512-DCJr6INHCI0Dypr1JAJj/BnvN31tpIt3Y8+KQ3GDfHW6pUBsc9GnXHpKsuQ4sK/fTj80GjaDYPGdWeB/uKMMdw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@deepseek-ai/schemastery": "^3.18.1", - "zod": "^4.4.3" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", - "@deepseek-ai/dsh-brand": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", - "@deepseek-ai/dsh-scope": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session": "^0.1.0-rc.8", - "@deepseek-ai/dsh-tools": "^0.1.0-rc.8", - "@deepseek-ai/dsh-typert-protocol": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-credentials": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-credentials/-/dsh-credentials-0.1.0-rc.8.tgz", - "integrity": "sha512-VopOhtUEa/fSmJr3fyKbsEG043kX1oGuBrmELAbkhmuDigl1cN88g0VPb9rMG2/dJ1h08wg+h0RJP+Ex4LjRWw==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-brand": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-credentials-local": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-credentials-local/-/dsh-credentials-local-0.1.0-rc.8.tgz", - "integrity": "sha512-Msbz/+xNIHFXLjcDy2hZFpfV1qduuyjLl35BJOUqNz9eCEYv8b0lfKDI7nirv5E/TdxzLkO75WQ4f+8nifeUpQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@deepseek-ai/schemastery": "^3.18.1", - "chokidar": "^4.0.3", - "yaml": "^2.9.0" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-atomic-write": "^0.1.0-rc.8", - "@deepseek-ai/dsh-credentials": "^0.1.0-rc.8", - "@deepseek-ai/dsh-home-paths": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-launch-environment": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-file-reference": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-file-reference/-/dsh-file-reference-0.1.0-rc.8.tgz", - "integrity": "sha512-SoU4Zm7L8E9ud5nTs1tVAINFrgKvIKypCdOOMLBjJkjLUvXMYmKFxfCM7xaJjOmK/C5suEVUtpukZhZZvZALNA==", - "dev": true, - "license": "MIT", - "dependencies": { - "zod": "^4.4.3" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-typert-protocol": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-file-reference-local": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-file-reference-local/-/dsh-file-reference-local-0.1.0-rc.8.tgz", - "integrity": "sha512-dw3p1NmuDgJkse1J2RuLwgfiySEFiyRL40o3mo1ireGxXt85JfLns1FR2mdN6v7z6pBpIogGPKV//0U31BWTfg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@deepseek-ai/schemastery": "^3.18.1" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", - "@deepseek-ai/dsh-file-reference": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-system-prompt": "^0.1.0-rc.8", - "@deepseek-ai/dsh-tools": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-fs": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-fs/-/dsh-fs-0.1.0-rc.8.tgz", - "integrity": "sha512-ge5GW56+z20vYACQ2jqtevusdgMXa64laeU/Chql+VIA3+6xyJ8gLX+oj/1O5TlzhvmZ7ZPfZGBFBEVsEZzTQw==", - "dev": true, - "license": "MIT", - "peer": true, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-brand": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", - "@deepseek-ai/dsh-sandbox": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-fs-local": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-fs-local/-/dsh-fs-local-0.1.0-rc.8.tgz", - "integrity": "sha512-yWk6WrAHs8b6395XnZZOCf3wY90xYKjh/tyU3/rwFy4oU8zq9gzn/x8rdaZD0zUp+wE0XqfBf2AS4Jo03SKHyQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@deepseek-ai/schemastery": "^3.18.1", - "koffi": "^3.1.0" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-fs": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-fs-observation-policy": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-fs-observation-policy/-/dsh-fs-observation-policy-0.1.0-rc.8.tgz", - "integrity": "sha512-iarNlz2QoEROJUOHPjy7OKOwXuGeEhzk6nWj95F+UHNvKKaquagBE8YE1gzFqbg2U1wFVmPGoHBYl8q7hb5Z8Q==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-fs": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-fs-sandbox": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-fs-sandbox/-/dsh-fs-sandbox-0.1.0-rc.8.tgz", - "integrity": "sha512-JfNgZHFyUyqO5XV/KQ2msO9OQ+98WrGCyfQp34yqCbIXSGS2r471C35Sub+OyTlpCkavGFUjsxo3iT7PLGyVVw==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-fs": "^0.1.0-rc.8", - "@deepseek-ai/dsh-fs-local": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-sandbox": "^0.1.0-rc.8", - "@deepseek-ai/dsh-sandbox-policy": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-goal": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-goal/-/dsh-goal-0.1.0-rc.8.tgz", - "integrity": "sha512-PR/9JjRn2H/33eyAVbtYBxzRWQhFO5N0S/188eAV9gjUTtHe5oSOnPxYy8iNkkMXxr+VE8Nno25Sun8WYmS8lQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@deepseek-ai/schemastery": "^3.18.1", - "zod": "^4.4.3" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", - "@deepseek-ai/dsh-brand": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", - "@deepseek-ai/dsh-scope": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session-projection": "^0.1.0-rc.8", - "@deepseek-ai/dsh-typert-protocol": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-goal-round-driver": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-goal-round-driver/-/dsh-goal-round-driver-0.1.0-rc.8.tgz", - "integrity": "sha512-hCOOofSuqYxWo+Zc/vcF1C+qk38JEgzJ2ya4bBisWYiRwVFygHODquQllK5ffDjFM+SnX+CdmA+l2piiwCkzcA==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", - "@deepseek-ai/dsh-goal": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-headless": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-headless/-/dsh-headless-0.1.0-rc.8.tgz", - "integrity": "sha512-SfjPjyLeno7iScndgFI3s9s8focqXADLNgIxkFbsL0BdAY7v3A6TOe+iSxnYX0fMhDqFC1jT3FVYlEzbJBg0Kg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@deepseek-ai/dsh-cmdline": "^0.1.0-rc.8", - "@deepseek-ai/dsh-code-runtime-worker-thread": "^0.1.0-rc.8", - "@deepseek-ai/schemastery": "^3.18.1", - "commander": "^15.0.0" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/cordis-plugin-loader": "^1.0.2", - "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", - "@deepseek-ai/dsh-agent-default-model": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-home-paths": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-home-paths/-/dsh-home-paths-0.1.0-rc.8.tgz", - "integrity": "sha512-9cQhH9CZsw7Zi73VnZk7CcuEVA6yR/Ox+7lp3VHq53fFYSPi0RL+kMWmh5XCrZB4U1OM3+PVsWsA5II9tB+t0Q==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-host-apiproxy": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-host-apiproxy/-/dsh-host-apiproxy-0.1.0-rc.8.tgz", - "integrity": "sha512-viq2CoS6bRavSe1t9sLjgunykO+Vn/m83uSgONMH8O7QN0Pk3+FnZGHlPZ1lQ4auNJTwQjxFG6w372cGq9usWw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", - "@deepseek-ai/dsh-agent-default-model": "^0.1.0-rc.8", - "@deepseek-ai/dsh-api-remotes": "^0.1.0-rc.8", - "@deepseek-ai/dsh-attachment": "^0.1.0-rc.8", - "@deepseek-ai/dsh-brand": "^0.1.0-rc.8", - "@deepseek-ai/dsh-commands": "^0.1.0-rc.8", - "@deepseek-ai/dsh-credentials": "^0.1.0-rc.8", - "@deepseek-ai/dsh-goal": "^0.1.0-rc.8", - "@deepseek-ai/dsh-host-directory-picker": "^0.1.0-rc.8", - "@deepseek-ai/dsh-jobs": "^0.1.0-rc.8", - "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", - "@deepseek-ai/dsh-native-command": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session-persistence": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session-projection": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session-projection-cache": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session-query": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session-title": "^0.1.0-rc.8", - "@deepseek-ai/dsh-settings": "^0.1.0-rc.8", - "@deepseek-ai/dsh-skill": "^0.1.0-rc.8", - "@deepseek-ai/dsh-subagent": "^0.1.0-rc.8", - "@deepseek-ai/dsh-tools": "^0.1.0-rc.8", - "@deepseek-ai/dsh-user-approval": "^0.1.0-rc.8", - "@deepseek-ai/dsh-user-questions": "^0.1.0-rc.8", - "@deepseek-ai/dsh-workspace": "^0.1.0-rc.8", - "@deepseek-ai/schemastery": "^3.18.1", - "fflate": "^0.8.2", - "zod": "^4.4.3" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-agent-presets": "^0.1.0-rc.8", - "@deepseek-ai/dsh-cordis-host-runner": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-host-directory-picker": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-host-directory-picker/-/dsh-host-directory-picker-0.1.0-rc.8.tgz", - "integrity": "sha512-aOUaUX0MTl8oLIuL27OkATMm+x2oTANuhhHpeGizn7+kfOX5bRKB3tyi7h6lGZ9O7WDiDLl2JajRqzBXlIPAAg==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-host-directory-picker-auto": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-host-directory-picker-auto/-/dsh-host-directory-picker-auto-0.1.0-rc.8.tgz", - "integrity": "sha512-t6sn3AlcAARVCOgYMNZS/Yneiw+/2mDM6QOGxR6bu5E7DYTT/tllHe0PlHF1Wgh/LtfOTeDtcSPPfXjmrd+Lqw==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/cordis-plugin-loader": "^1.0.2", - "@deepseek-ai/dsh-client-ui-directory-picker-browse": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-ui-directory-picker-native": "^0.1.0-rc.8", - "@deepseek-ai/dsh-host-directory-picker-browse": "^0.1.0-rc.8", - "@deepseek-ai/dsh-host-directory-picker-native": "^0.1.0-rc.8", - "@deepseek-ai/dsh-host-webserver": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-host-directory-picker-browse": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-host-directory-picker-browse/-/dsh-host-directory-picker-browse-0.1.0-rc.8.tgz", - "integrity": "sha512-zEQ7Wnz953GWiR3Y9GaqPGmhntEdjmcD+x6cbYKXWyeOtMHvv7Lu9EWGNneFHXFt50nMinDBT5kyGzElZ+cajA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@deepseek-ai/dsh-host-directory-picker": "^0.1.0-rc.8", - "@deepseek-ai/schemastery": "^3.18.1" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-host-directory-picker-native": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-host-directory-picker-native/-/dsh-host-directory-picker-native-0.1.0-rc.8.tgz", - "integrity": "sha512-WUB4lW+ZmR743uH9LpFK0JrJU88601E7zvevffa93n7Bl4X7C5Y2yhbDK337H8W/brVlLNVgD2Fw2H/nIPZkDg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@deepseek-ai/dsh-host-directory-picker": "^0.1.0-rc.8", - "@deepseek-ai/dsh-native-command": "^0.1.0-rc.8", - "koffi": "^3.1.0" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-host-frontend-static": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-host-frontend-static/-/dsh-host-frontend-static-0.1.0-rc.8.tgz", - "integrity": "sha512-/ef1xAygNL9hyGtSDzJ04nM5WSNzSxsloSUD2MQfM0FU3Y6b/CbHkUNFYaS0MnhS1YVSulDAGRQvXSgES8vZkg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@deepseek-ai/schemastery": "^3.18.1" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-host-webserver": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-host-plugin-inventory": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-host-plugin-inventory/-/dsh-host-plugin-inventory-0.1.0-rc.8.tgz", - "integrity": "sha512-knPtxCDZn1jbwRfOUnskjaj8hSXUCfBcjD9LPFXnKffsM6TFOeQrFGhkNKlZteXAMSChtY6pV9bpJj17y3SPNg==", - "dev": true, - "license": "MIT", - "dependencies": { - "zod": "^4.4.3" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/cordis-plugin-loader": "^1.0.2", - "@deepseek-ai/dsh-brand": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-typert-protocol": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-host-webserver": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-host-webserver/-/dsh-host-webserver-0.1.0-rc.8.tgz", - "integrity": "sha512-MEKFrhvsYfj970QHLaKPpF/sIBpCe8NuSA0HGiWYJctX6TM9N3rLRhXx5p3zATDmXZclu1rbYhIbsqWw/twPig==", - "dev": true, - "license": "MIT", - "dependencies": { - "@deepseek-ai/schemastery": "^3.18.1" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-invariants": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-invariants/-/dsh-invariants-0.1.0-rc.8.tgz", - "integrity": "sha512-u0lYqyxOYwfsVnbsfGXZos5vFvA4cqFnBEW3/ezgljNwkYwzeUP/Y5wjPnQjP+ZzBn3CnVeIF6s2N2Vk3iA5mQ==", - "license": "MIT", - "peer": true, - "dependencies": { - "@deepseek-ai/schemastery": "^3.18.1" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1" - } - }, - "node_modules/@deepseek-ai/dsh-jobs": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-jobs/-/dsh-jobs-0.1.0-rc.8.tgz", - "integrity": "sha512-HqQudOA4VkjCMpxWiqTCMmuiTa/pehW6yG7dDsctO1vW5K48hWQ/h7czdJKgrh4SMuK4kchv3IipS1KaJmdaog==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", - "@deepseek-ai/dsh-brand": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-jobs-local": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-jobs-local/-/dsh-jobs-local-0.1.0-rc.8.tgz", - "integrity": "sha512-8/cr4rYVS2sLB/Z4lL/ERUn14iBqT9T85rJFxxhEKuT3gMcAkiJuKP7t+ZFWPYSSmcNqDPmMI1ExG+GzjxsLVQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@deepseek-ai/schemastery": "^3.18.1" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-jobs": "^0.1.0-rc.8", - "@deepseek-ai/dsh-scope": "^0.1.0-rc.8", - "@deepseek-ai/dsh-timeout": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-launch-environment": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-launch-environment/-/dsh-launch-environment-0.1.0-rc.8.tgz", - "integrity": "sha512-VvYo5R7tu4QhX/dsNpuBy3AaauizU6yPCeWQUNzI3ZjGA0VHkkZhInilcgxVJkPA1lwEXYB+OoCAo07PUy6D/w==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-llm": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-llm/-/dsh-llm-0.1.0-rc.8.tgz", - "integrity": "sha512-hf6RmX2Stn1UtzpktSHQLkIktQkBm9i/3yFfJlbGSkwyw5Cv9sTYJbyoHzsSnnh6i8nRRcMcBhvMgm23I00oIw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@deepseek-ai/schemastery": "^3.18.1" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-attachment": "^0.1.0-rc.8", - "@deepseek-ai/dsh-brand": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-timeout": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-llm-deepseek": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-llm-deepseek/-/dsh-llm-deepseek-0.1.0-rc.8.tgz", - "integrity": "sha512-s4LatnGbHwPJhcWGulO/7RsJBPHHBDB+2+1iRTJEn6vYPB0lOSRWtr91qdmAkUxBZmK5mwrf21IbuW+kWwtAZQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@deepseek-ai/schemastery": "^3.18.1", - "eventsource-parser": "^3.1.0" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-anonymous-user-id": "^0.1.0-rc.8", - "@deepseek-ai/dsh-attachment": "^0.1.0-rc.8", - "@deepseek-ai/dsh-credentials": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-launch-environment": "^0.1.0-rc.8", - "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", - "@deepseek-ai/dsh-settings": "^0.1.0-rc.8", - "@deepseek-ai/dsh-timeout": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-llm-pi-ai": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-llm-pi-ai/-/dsh-llm-pi-ai-0.1.0-rc.8.tgz", - "integrity": "sha512-r9dmHYy759gKtAG0S96wTCS6O8WFDqGLQu8t+zGY6LnfdT4qUJdmWtJ+GwCn+BGwq1AglBzjabvyRBp6BxXcMQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@deepseek-ai/schemastery": "^3.18.1", - "@earendil-works/pi-ai": "^0.82.1" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-attachment": "^0.1.0-rc.8", - "@deepseek-ai/dsh-credentials": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-launch-environment": "^0.1.0-rc.8", - "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", - "@deepseek-ai/dsh-settings": "^0.1.0-rc.8", - "@deepseek-ai/dsh-timeout": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-llm-retry": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-llm-retry/-/dsh-llm-retry-0.1.0-rc.8.tgz", - "integrity": "sha512-DmcOajgiku5l7aa5hU9DtwnIZu+i/XCGdb+Wego5W9bAswYeBAwbceloRNE3O6+jdRzy+K5U7KQ9V+olBsNqRQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@deepseek-ai/schemastery": "^3.18.1" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", - "@deepseek-ai/dsh-brand": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session": "^0.1.0-rc.8", - "@deepseek-ai/dsh-timeout": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-mcp-client": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-mcp-client/-/dsh-mcp-client-0.1.0-rc.8.tgz", - "integrity": "sha512-pcqXawjq9jRJQNHZTLN7pswJFMWjxCsEOdHUI9BdJqb9lRDsMi2cul1Hizfi51oKkcNo1u/K9Toqgh8o/ScAXg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@deepseek-ai/schemastery": "^3.18.1", - "@modelcontextprotocol/sdk": "^1.12.0", - "zod": "^4.4.3" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-attachment": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", - "@deepseek-ai/dsh-subprocess": "^0.1.0-rc.8", - "@deepseek-ai/dsh-timeout": "^0.1.0-rc.8", - "@deepseek-ai/dsh-tools": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-message-feedback": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-message-feedback/-/dsh-message-feedback-0.1.0-rc.8.tgz", - "integrity": "sha512-5DYXVLcnvTRs74Att52LGNR+x+RCf1X5s5+gOSUddsjnQ0wn4f3pzfc0o4F+91aE2zX3xzQ3/LhlW5UOJdkB0Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "@deepseek-ai/schemastery": "^3.18.1", - "zod": "^4.4.3" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-brand": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session-persistence": "^0.1.0-rc.8", - "@deepseek-ai/dsh-storage-domain": "^0.1.0-rc.8", - "@deepseek-ai/dsh-typert-protocol": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-native-command": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-native-command/-/dsh-native-command-0.1.0-rc.8.tgz", - "integrity": "sha512-bRaT8LOb2xmWQ88oSzM4+Y3N4Yy4J0tf15/kQTP53PY1FnOA5hGYWoRglQgfxIcJCrw4fEdUPie8Fff0dCOwdQ==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-output-retention": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-output-retention/-/dsh-output-retention-0.1.0-rc.8.tgz", - "integrity": "sha512-DeVjqZ9TtH2AEG57GBsHYT68274VygzuP9EqQLL01Ht1TrdK75xlVet1l3jdEbA7Eik4aSGDjAZD9/MsnlUIXg==", - "dev": true, - "license": "MIT", - "peer": true, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-permission-presets": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-permission-presets/-/dsh-permission-presets-0.1.0-rc.8.tgz", - "integrity": "sha512-EeTn8Av5kmb1Qj53D7myRnKcNQrrupGrM2m9LVUO8ieWvlIaYX7n2g0y8kg14SUpcD2YzaT40oGJ6VeDuhTZAA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@deepseek-ai/schemastery": "^3.18.1", - "zod": "^4.4.3" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-commands": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-sandbox": "^0.1.0-rc.8", - "@deepseek-ai/dsh-sandbox-policy": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session-projection": "^0.1.0-rc.8", - "@deepseek-ai/dsh-settings": "^0.1.0-rc.8", - "@deepseek-ai/dsh-shell": "^0.1.0-rc.8", - "@deepseek-ai/dsh-user-approval": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-persona": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-persona/-/dsh-persona-0.1.0-rc.8.tgz", - "integrity": "sha512-3COzIzZ5kBd+txuH418h9HG4feuVFyhdh02HWvzsWgaPsxjatuFS0OfS6qsejUTZrFDODQSr1WIOeSt80bDBtA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@deepseek-ai/schemastery": "^3.18.1" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-system-prompt": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-plan-mode": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-plan-mode/-/dsh-plan-mode-0.1.0-rc.8.tgz", - "integrity": "sha512-/SY/iil7KLDvveqKRUZxO4HiADwDlOX9u3xyG/93h785mWSfRXooiv4Zp2tiBjU+pJB0tJXMsQNAXDdg7DWtwA==", - "dev": true, - "license": "MIT", - "dependencies": { - "zod": "^4.4.3" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", - "@deepseek-ai/dsh-commands": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session-projection": "^0.1.0-rc.8", - "@deepseek-ai/dsh-system-prompt": "^0.1.0-rc.8", - "@deepseek-ai/dsh-tools": "^0.1.0-rc.8", - "@deepseek-ai/dsh-user-questions": "^0.1.0-rc.8" - }, - "peerDependenciesMeta": { - "@deepseek-ai/dsh-commands": { - "optional": true - } - } - }, - "node_modules/@deepseek-ai/dsh-pwsh-local": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-pwsh-local/-/dsh-pwsh-local-0.1.0-rc.8.tgz", - "integrity": "sha512-lHAEwC4pL5bVSKgwaeO2dMM9s/jnpDBRuTeVD2HkunpFfT1Kq4lFi+/YXj00L7mW9DBP6FMfwRRV/0Wgo1FtdA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@deepseek-ai/schemastery": "^3.18.1" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-settings": "^0.1.0-rc.8", - "@deepseek-ai/dsh-shell": "^0.1.0-rc.8", - "@deepseek-ai/dsh-subprocess": "^0.1.0-rc.8", - "@deepseek-ai/dsh-timeout": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-pwsh-sandbox": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-pwsh-sandbox/-/dsh-pwsh-sandbox-0.1.0-rc.8.tgz", - "integrity": "sha512-GVvj4zqpC/lwCGaRmIXIhFqOqewgoGOuokGFuv0QcjQUY3v9FnPor2dqDZr5pav8KFGb5GeGUzLoUbedmsWyZg==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-pwsh-local": "^0.1.0-rc.8", - "@deepseek-ai/dsh-sandbox": "^0.1.0-rc.8", - "@deepseek-ai/dsh-sandbox-policy": "^0.1.0-rc.8", - "@deepseek-ai/dsh-shell": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-repeat-tool-reminder": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-repeat-tool-reminder/-/dsh-repeat-tool-reminder-0.1.0-rc.8.tgz", - "integrity": "sha512-p7/g+NH6JJ0BnLx2V5o0hCm4wZr+dXQ9/Ev8LU6YyFRlcnma8TJuATL0wsA01xWfvvGLRxbe/tH41TRS1NVrJg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@deepseek-ai/schemastery": "^3.18.1" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-tools": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-sandbox": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-sandbox/-/dsh-sandbox-0.1.0-rc.8.tgz", - "integrity": "sha512-dJpy5p/KjKkHG9AnMKU4+/ilj/4DCglsq3kof/jhIwtsZJCix07TEXP9vV8LCv4fU8af7cK3antXw4eVMqkwuQ==", - "dev": true, - "license": "MIT", - "peer": true, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-sandbox-local": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-sandbox-local/-/dsh-sandbox-local-0.1.0-rc.8.tgz", - "integrity": "sha512-sTrKDXD74yG6B24uhCyN9DuGSpX0SCelN4o5DZylKxt56WRRyywAGdLN0Xt8enqiKCxrq+PJBi+hDh2GtXBj6w==", - "dev": true, - "license": "MIT", - "dependencies": { - "@deepseek-ai/dsh-sandbox-windows-acl": "^0.1.0-rc.8", - "@deepseek-ai/node-addon-landlock-run": "^0.1.1", - "@deepseek-ai/schemastery": "^3.18.1" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", - "@deepseek-ai/dsh-sandbox": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-sandbox-policy": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-sandbox-policy/-/dsh-sandbox-policy-0.1.0-rc.8.tgz", - "integrity": "sha512-xQOlYWbUr1Oj6cnRd5aHZIz52EOEAdSO1HJIfeDkQrVaOgohFsiiCIp6PNFumuGNWdCEnf4Q18ebafLNtazYlA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@deepseek-ai/schemastery": "^3.18.1" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-sandbox": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session": "^0.1.0-rc.8", - "@deepseek-ai/dsh-system-prompt": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-sandbox-windows-acl": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-sandbox-windows-acl/-/dsh-sandbox-windows-acl-0.1.0-rc.8.tgz", - "integrity": "sha512-3DeFPD+laUbXrzVpEJ0FrF5pMQCqeu7YCJAWgORGj1aju7sIjpineEnKpE6EXhbc8C9Jqu2y5S7B9z6ydOL/Zg==", - "dev": true, - "license": "MIT", - "dependencies": { - "koffi": "^3.1.0" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-schedule": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-schedule/-/dsh-schedule-0.1.0-rc.8.tgz", - "integrity": "sha512-L4GO1Bv3+SHIXafjGQcf0sJI9eTf9whxVmYlBxYHw7h7StOZJPMhG9HpsKz4mO9FZ7J4zhBtpYlFbhOQaJheqA==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", - "@deepseek-ai/dsh-brand": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session-persistence": "^0.1.0-rc.8", - "@deepseek-ai/dsh-tools": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-scope": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-scope/-/dsh-scope-0.1.0-rc.8.tgz", - "integrity": "sha512-/o+PxkVV2zUy9lYlMFr4TWSb+ESW4DE+fI891yIbsLzOJdFgfbmmLpGrlWgnz8/unIGJZxjeXdwyppV04Z277Q==", - "dev": true, - "license": "MIT", - "peer": true, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-session": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-session/-/dsh-session-0.1.0-rc.8.tgz", - "integrity": "sha512-Qs5Mgn32WPPVB4rKHjsZBgLOkh0TQurUAcc9GaDVudK4dUkpno2HDh++qu/PrwRA3CZ/iwPAoFHCpB3AMMaoLg==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-brand": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", - "@deepseek-ai/dsh-scope": "^0.1.0-rc.8", - "@deepseek-ai/dsh-typert-protocol": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-session-checkpoint-policy": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-session-checkpoint-policy/-/dsh-session-checkpoint-policy-0.1.0-rc.8.tgz", - "integrity": "sha512-9DpZhQN4MExSjbjBSmaH08DmFS/GHRrsVhO5e3WgTVuH13ugdl5yxc4MEb8qvOhEJUUtOx3fXHuMpSTa0Dxa7w==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session-persistence": "^0.1.0-rc.8", - "@deepseek-ai/dsh-tools": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-session-log-export": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-session-log-export/-/dsh-session-log-export-0.1.0-rc.8.tgz", - "integrity": "sha512-6vDC7uH0WZkwmlj/iql6AmSL9Uifiqi28OIZSDIi8/KRHDHnt5hvjobJecuIxhV9hQSDmNsstErHGx4ng2GJFQ==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-client-locale": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-runtime": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-ui-commands": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-ui-conversation": "^0.1.0-rc.8", - "@deepseek-ai/dsh-commands": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-session-persistence": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-session-persistence/-/dsh-session-persistence-0.1.0-rc.8.tgz", - "integrity": "sha512-JujorG/UCern0+zxJzNswyWl2tFG9sLzfVNvA5YkTLaRLZt7ZsEhxG4DxWZ6uj+3RJ8sf4bqdKqvpIn9t1pwUw==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-brand": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session": "^0.1.0-rc.8", - "@deepseek-ai/dsh-timeout": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-session-persistence-jsonl": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-session-persistence-jsonl/-/dsh-session-persistence-jsonl-0.1.0-rc.8.tgz", - "integrity": "sha512-T/Lvh76O2tpVw04FAhgLF3Qovq3SrUnzaywIbB+Uw67a2DD63Qg+cJY9WO6Pu/UowPxbpuUOd12c6iPY5x8d7Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "@deepseek-ai/schemastery": "^3.18.1", - "koffi": "^3.1.0" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session-persistence": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-session-projection": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-session-projection/-/dsh-session-projection-0.1.0-rc.8.tgz", - "integrity": "sha512-q00B+rl7WAuK0Bgh93SY2+ZpqaH2kJhfJ9n6Jg6R/m4plnH0Ip4oCAHl6u8rBzDgb1mniQGEQDz/7BN5Q3It8Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "zod": "^4.4.3" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-session-projection-cache": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-session-projection-cache/-/dsh-session-projection-cache-0.1.0-rc.8.tgz", - "integrity": "sha512-IPvO7k9FlekOJXn4XLWUwU5+JDQn7khu8Oa04GFDystU3c1CnOwoa7SGMHOfJau3r177M4ncXApwN5Ra6uhyXw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@deepseek-ai/schemastery": "^3.18.1", - "zod": "^4.4.3" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session-persistence": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session-projection": "^0.1.0-rc.8", - "@deepseek-ai/dsh-storage-domain": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-session-query": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-session-query/-/dsh-session-query-0.1.0-rc.8.tgz", - "integrity": "sha512-q8eyfpgPuJx24l1fEevDkc3Dux3lNp/yDzVkDL4nSTGNaDx/h9Y6iG7SZdqWM5nxOET3iwxi4AkPM7lYyLg3cQ==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-brand": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session-persistence": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session-title": "^0.1.0-rc.8" - }, - "peerDependenciesMeta": { - "@deepseek-ai/dsh-session-persistence": { - "optional": true - } - } - }, - "node_modules/@deepseek-ai/dsh-session-query-sqlite": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-session-query-sqlite/-/dsh-session-query-sqlite-0.1.0-rc.8.tgz", - "integrity": "sha512-jrNq2vgWIH7OzNMHXrKEjEMwy86I36I94a8X5u937xo2B2JD8ZIWfuWHC9YyLqabRwNf7VcQ6VZ6ruSgESRE7A==", - "dev": true, - "license": "MIT", - "dependencies": { - "@deepseek-ai/schemastery": "^3.18.1" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session-persistence": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session-query": "^0.1.0-rc.8" - }, - "peerDependenciesMeta": { - "@deepseek-ai/dsh-session-persistence": { - "optional": true - } - } - }, - "node_modules/@deepseek-ai/dsh-session-reference": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-session-reference/-/dsh-session-reference-0.1.0-rc.8.tgz", - "integrity": "sha512-meNS02BOkLc2SnF2qWvl5X1Psk59t0Q1vvwjfCkczD29g4nm7Y02EZ089HJKii0VAsSB39RYA2rf6MCSl6vhow==", - "dev": true, - "license": "MIT", - "dependencies": { - "@deepseek-ai/schemastery": "^3.18.1", - "zod": "^4.4.3" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", - "@deepseek-ai/dsh-compaction": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", - "@deepseek-ai/dsh-output-retention": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session-query": "^0.1.0-rc.8", - "@deepseek-ai/dsh-typert-protocol": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-session-stats": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-session-stats/-/dsh-session-stats-0.1.0-rc.8.tgz", - "integrity": "sha512-T+SEzBkMxZpQ31MaeJCjaLN3/xu8yyZ3Va5u6osfq0nsJz1tvuZ53MHMbApdwERHVV0t/1eILTUo1J6XdksUEA==", - "dev": true, - "license": "MIT", - "dependencies": { - "zod": "^4.4.3" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session-projection": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-session-telemetry": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-session-telemetry/-/dsh-session-telemetry-0.1.0-rc.8.tgz", - "integrity": "sha512-Rs7w+PP/uuOaa34RFY4q6Xjes/C32H0gPvZe/gV9M87y1EcJs+mFBzhnc/zyKeaAdT25RWIwO3KATmKlT/D0Dg==", - "dev": true, - "license": "MIT", - "peer": true, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-session-telemetry-otel": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-session-telemetry-otel/-/dsh-session-telemetry-otel-0.1.0-rc.8.tgz", - "integrity": "sha512-rpPwidBwKV53WM2bYW/eYOZ6j5U9VHOIVrITQkQtGDMAzD9UaqfAXfXfUlsw9vsfjED2gKmSf7vn+bVfy8Tjaw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@deepseek-ai/schemastery": "^3.18.1", - "@opentelemetry/api": "^1.9.1", - "@opentelemetry/api-logs": "^0.220.0", - "@opentelemetry/exporter-logs-otlp-http": "^0.220.0", - "@opentelemetry/otlp-exporter-base": "^0.220.0", - "@opentelemetry/resources": "^2.9.0", - "@opentelemetry/sdk-logs": "^0.220.0" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-anonymous-user-id": "^0.1.0-rc.8", - "@deepseek-ai/dsh-command-feedback": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session-telemetry": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-session-title": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-session-title/-/dsh-session-title-0.1.0-rc.8.tgz", - "integrity": "sha512-OFG9kHFGnM5ND4LCkqg8oZr57qgF6xMkBxR/4MRaJJ42QrPI9QKzoZVRpNpXEl3v3uw8oR7Jj0jbc7WClNl3ow==", - "dev": true, - "license": "MIT", - "dependencies": { - "@deepseek-ai/schemastery": "^3.18.1", - "zod": "^4.4.3" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-brand": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session-projection": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-session-title-first-prompt-llm": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-session-title-first-prompt-llm/-/dsh-session-title-first-prompt-llm-0.1.0-rc.8.tgz", - "integrity": "sha512-pFx2hPVYyRCRcbd4WJZVapVekLLEGMAG1KAcrixf3XOGDNaqVEPF8LWatx8iKQRfVSQlvIOwDO8uEsC0NZiPNA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@deepseek-ai/schemastery": "^3.18.1" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session-title": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session-title-llm": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-session-title-llm": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-session-title-llm/-/dsh-session-title-llm-0.1.0-rc.8.tgz", - "integrity": "sha512-6xz3umGBtGmM+t5O5wwlCwbH9gmBOlQBfg7qGnPJftWc4VWHG7l2VUYqd3DNTQVTHIA/hSN4qg/LXTm79rADGQ==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@deepseek-ai/schemastery": "^3.18.1" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session-title": "^0.1.0-rc.8", - "@deepseek-ai/dsh-timeout": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-settings": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-settings/-/dsh-settings-0.1.0-rc.8.tgz", - "integrity": "sha512-pqbMoiSP+Ieww9/4gcHYXcBCDlno1zYDu2OPq+5xdZ+McnK+5YBtHsiRpnR9cHQxGTH7lkfIv+adkOueQW0utg==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-brand": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/schemastery": "^3.18.1" - } - }, - "node_modules/@deepseek-ai/dsh-settings-file": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-settings-file/-/dsh-settings-file-0.1.0-rc.8.tgz", - "integrity": "sha512-2mCyAPkxA5r7Ezgt41XtJxRBsj5Dkl21e5v7w+6YE3C8/n9zRRlN4X5oInHcUKEmgoTrNLCBCgOs5DNrl+pErw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@deepseek-ai/schemastery": "^3.18.1", - "chokidar": "^4.0.3", - "yaml": "^2.9.0" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-atomic-write": "^0.1.0-rc.8", - "@deepseek-ai/dsh-home-paths": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-settings": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-shell": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-shell/-/dsh-shell-0.1.0-rc.8.tgz", - "integrity": "sha512-RNhp7Y25DXUH7o36X4GcN0lnOLg6NXTlWZpYNURT7aDj3UHcLLajRsyddiAh1EbwQnl0GRKRZhLaZHrrG6gMIw==", - "dev": true, - "license": "MIT", - "peer": true, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-sandbox": "^0.1.0-rc.8", - "@deepseek-ai/dsh-settings": "^0.1.0-rc.8", - "@deepseek-ai/dsh-subprocess": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-shell-env": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-shell-env/-/dsh-shell-env-0.1.0-rc.8.tgz", - "integrity": "sha512-E/Rlka8BnpB7GM67ZJPjvZyp0O9L5x28giyJhHWZcPHN4rsEQFVVqk0cH6iDT5STy+dMc9BAUW+im18kATIxsA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@deepseek-ai/schemastery": "^3.18.1" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-home-paths": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session-persistence": "^0.1.0-rc.8", - "@deepseek-ai/dsh-shell": "^0.1.0-rc.8", - "@deepseek-ai/dsh-tools": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-skill": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-skill/-/dsh-skill-0.1.0-rc.8.tgz", - "integrity": "sha512-MqcOzl4Y5pQEvFBNVAi5w0IZWH5kVbXmp1RYScrl+8HpVATZbgumDhztVnEc2kUrZu+o6LKb1hnbunK6JHUE5g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@deepseek-ai/schemastery": "^3.18.1" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", - "@deepseek-ai/dsh-scope": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-skill-badge": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-skill-badge/-/dsh-skill-badge-0.1.0-rc.8.tgz", - "integrity": "sha512-VjISwf5qDpkD+bxLuVXYL7IakhPoZudIOwWCFjTD++Tj8VQTN9ORCq1uCOatFLi5v/an8MzdZ91O2pXfQtb7dQ==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-skill": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-skill-filesystem": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-skill-filesystem/-/dsh-skill-filesystem-0.1.0-rc.8.tgz", - "integrity": "sha512-A87t/1+wxPiMkUXWVdf4DfgxA8rp1eLmStMvzfdthR/WxtGPzuEv2L5oyNDzKiCBwIcxBN6Fy2THNa2Xba2kQQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@deepseek-ai/schemastery": "^3.18.1", - "chokidar": "^5.0.0", - "yaml": "^2.4.2" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-fs": "^0.1.0-rc.8", - "@deepseek-ai/dsh-home-paths": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-skill": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-skill-filesystem/node_modules/chokidar": { - "version": "5.0.0", - "resolved": "https://registry.npmmirror.com/chokidar/-/chokidar-5.0.0.tgz", - "integrity": "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==", - "dev": true, - "license": "MIT", - "dependencies": { - "readdirp": "^5.0.0" - }, - "engines": { - "node": ">= 20.19.0" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@deepseek-ai/dsh-skill-filesystem/node_modules/readdirp": { - "version": "5.1.1", - "resolved": "https://registry.npmmirror.com/readdirp/-/readdirp-5.1.1.tgz", - "integrity": "sha512-Kko+Y5XQ6fM+Ce3dq3m9YGxnacYZYl9cA1wZjaF3Vbry2L3i1qVg8+CAgNPsXRArPMUMCaOR7oa9Nqntc43JKA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 20.19.0" - }, - "funding": { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@deepseek-ai/dsh-spill": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-spill/-/dsh-spill-0.1.0-rc.8.tgz", - "integrity": "sha512-LDfyBuRS/yfc+JYvSicEXYJDj5PFBfWN6vJ5G3wy14eMrq3OKoYip8lyIjEdR4qwCVh0s+oSi28AlcvkPuyOdw==", - "dev": true, - "license": "MIT", - "peer": true, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-brand": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-spill-local": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-spill-local/-/dsh-spill-local-0.1.0-rc.8.tgz", - "integrity": "sha512-4Ew3cBOQxW6wA4U8svXCjUyhX00+h0W/bK9CzTy/HoYrNJhP85euJVV7SfNlq6OfTeQBWn3U0wKwNlcc3gAyAg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@deepseek-ai/schemastery": "^3.18.1" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-spill": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-spill-policy": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-spill-policy/-/dsh-spill-policy-0.1.0-rc.8.tgz", - "integrity": "sha512-9y2IHaKowtqGxhYd59R3OfWv1sonIDv2h9WX/jhxbagMvORfRkhjWJP4YAxp+l4Ba1LhVLcuG/nb2p8hqGdO4g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@deepseek-ai/schemastery": "^3.18.1" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", - "@deepseek-ai/dsh-output-retention": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session": "^0.1.0-rc.8", - "@deepseek-ai/dsh-spill": "^0.1.0-rc.8", - "@deepseek-ai/dsh-tools": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-storage": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-storage/-/dsh-storage-0.1.0-rc.8.tgz", - "integrity": "sha512-KcxiNFAC1X0GhbS9yWGo7FLARBNsxoyU9JatxQtA23MuqOZaN4Nzy3bsMViK4/snzpPGwm//I+wfUywSjM6uBA==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-storage-domain": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-storage-domain/-/dsh-storage-domain-0.1.0-rc.8.tgz", - "integrity": "sha512-rHphQ0jveKoCurwh9TX+VAVFsMQivBgghQBOAsWdVDZ3W6boeXNhMZWuGWZ7WjMPD3iJKgiFCx+650hhsao+LQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@deepseek-ai/schemastery": "^3.18.1", - "zod": "^4.4.3" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-storage": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-storage-json": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-storage-json/-/dsh-storage-json-0.1.0-rc.8.tgz", - "integrity": "sha512-cTlqy+5bQH7/UOFqRoWSaY9DaaDpcx4jmvWcwY8ciMUBse8BXcEtchVr5zqqss+xA/+Z/l9VraH+diwwRuAWbg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@deepseek-ai/schemastery": "^3.18.1" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-storage": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-subagent": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-subagent/-/dsh-subagent-0.1.0-rc.8.tgz", - "integrity": "sha512-EI94+hYMfAe8BQkkH/FTcciGxajFfAdQe66Jhy2/eyR3dssRAZ+oJsV6SzU20x3m2yd0gmMaXzO1iV3gwYhY+g==", - "dev": true, - "license": "MIT", - "dependencies": { - "zod": "^4.4.3" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", - "@deepseek-ai/dsh-agent-presets": "^0.1.0-rc.8", - "@deepseek-ai/dsh-brand": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-jobs": "^0.1.0-rc.8", - "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", - "@deepseek-ai/dsh-sandbox": "^0.1.0-rc.8", - "@deepseek-ai/dsh-sandbox-policy": "^0.1.0-rc.8", - "@deepseek-ai/dsh-scope": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session-persistence": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session-projection": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session-projection-cache": "^0.1.0-rc.8", - "@deepseek-ai/dsh-tools": "^0.1.0-rc.8", - "@deepseek-ai/dsh-user-approval": "^0.1.0-rc.8" - }, - "peerDependenciesMeta": { - "@deepseek-ai/dsh-agent-presets": { - "optional": true - }, - "@deepseek-ai/dsh-jobs": { - "optional": true - }, - "@deepseek-ai/dsh-sandbox": { - "optional": true - }, - "@deepseek-ai/dsh-sandbox-policy": { - "optional": true - }, - "@deepseek-ai/dsh-session-persistence": { - "optional": true - }, - "@deepseek-ai/dsh-session-projection": { - "optional": true - }, - "@deepseek-ai/dsh-session-projection-cache": { - "optional": true - }, - "@deepseek-ai/dsh-user-approval": { - "optional": true - } - } - }, - "node_modules/@deepseek-ai/dsh-subagent-fork-in-process": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-subagent-fork-in-process/-/dsh-subagent-fork-in-process-0.1.0-rc.8.tgz", - "integrity": "sha512-CVen9Fu0TwiwuyTHmZeankN/v0EwdMwOAcq8fSTIyFGPG4ngtqQNSRMxwYTrz39kKyHv0VBW+r8tRd1LBdTAWA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@deepseek-ai/schemastery": "^3.18.1" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session": "^0.1.0-rc.8", - "@deepseek-ai/dsh-subagent": "^0.1.0-rc.8", - "@deepseek-ai/dsh-subagent-in-process-driver": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-subagent-in-process-driver": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-subagent-in-process-driver/-/dsh-subagent-in-process-driver-0.1.0-rc.8.tgz", - "integrity": "sha512-UJXwh484V/rEmRrvf5l0IWg2ceVOaSOU7Z6DEBq++bKOuFQ2BVkMm+Uj3dk4qFngeb10+/GXlRkbe3mqPwQDSA==", - "dev": true, - "license": "MIT", - "peer": true, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session": "^0.1.0-rc.8", - "@deepseek-ai/dsh-subagent": "^0.1.0-rc.8", - "@deepseek-ai/dsh-system-prompt": "^0.1.0-rc.8", - "@deepseek-ai/dsh-tools": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-subagent-spawn-in-process": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-subagent-spawn-in-process/-/dsh-subagent-spawn-in-process-0.1.0-rc.8.tgz", - "integrity": "sha512-+ZratMZJiNg0vDmaEauJpiNI9IzVwCWisbidow6AV8O5CLC9/XlcMTjFGxmxcbnPdNlVM9i8OLK8gY7/kZ7tTA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@deepseek-ai/schemastery": "^3.18.1" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-subagent": "^0.1.0-rc.8", - "@deepseek-ai/dsh-subagent-in-process-driver": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-subprocess": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-subprocess/-/dsh-subprocess-0.1.0-rc.8.tgz", - "integrity": "sha512-rTWwWCq/WrBTjaXhApu7gaho6UHwMZq0+l7nZ06YMUreNZoCHfg67pAXopMqTgr/iotphmXQdChrLgBabzL1gA==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-subprocess-local": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-subprocess-local/-/dsh-subprocess-local-0.1.0-rc.8.tgz", - "integrity": "sha512-2QMd6Nwjd+ARor4g+GSZ3dNyTvEf2IPOje47nQwa3UCmltLxn8K8gjDAN/5sGr/IF56P14FeF4xFag7tMK+Zdg==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "dependencies": { - "koffi": "^3.1.0", - "node-pty": "1.2.0-beta.15" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-subprocess": "^0.1.0-rc.8", - "@deepseek-ai/dsh-timeout": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-system-prompt": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-system-prompt/-/dsh-system-prompt-0.1.0-rc.8.tgz", - "integrity": "sha512-yk8Z85rzX2EwpKNWA5i+K3I3mqsIIUc9niwbDpXO8vlHvpC2qR3RNHjJIJN2EZYDqfSzTVtkbxHFsuMzDXIbew==", - "dev": true, - "license": "MIT", - "dependencies": { - "@deepseek-ai/schemastery": "^3.18.1" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", - "@deepseek-ai/dsh-scope": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-terminal": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-terminal/-/dsh-terminal-0.1.0-rc.8.tgz", - "integrity": "sha512-Vu73FrQGx8h7Mqq0QdKtzAiZ3xgVM4fB9wmf3fEl6OiJTcqfc8t4lgug3gE7uBeDVRaLn+aq7kHbEUOY0fsm1Q==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", - "@deepseek-ai/dsh-brand": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-terminal-bash": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-terminal-bash/-/dsh-terminal-bash-0.1.0-rc.8.tgz", - "integrity": "sha512-ehBMVr/0kZ15Vud7uE6PLobukwJi/BqGDbI1oonPPTOoTjDvuCqlKotNEQtS/G4NsvGshEABv+m5X5ELcRCWUA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@deepseek-ai/dsh-pwsh-local": "^0.1.0-rc.8", - "@deepseek-ai/schemastery": "^3.18.1" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-sandbox": "^0.1.0-rc.8", - "@deepseek-ai/dsh-sandbox-policy": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session": "^0.1.0-rc.8", - "@deepseek-ai/dsh-subprocess": "^0.1.0-rc.8", - "@deepseek-ai/dsh-terminal": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-time-context": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-time-context/-/dsh-time-context-0.1.0-rc.8.tgz", - "integrity": "sha512-9Rdse95S6Uk8OAHf78AQN/pxV6+29fCkIbF4ONP/F/6YBciKDORypRyMbHNSY81fBMHQPhW1xvZecGISdIHHiQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@deepseek-ai/schemastery": "^3.18.1" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-timeout": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-timeout/-/dsh-timeout-0.1.0-rc.8.tgz", - "integrity": "sha512-RwOC/qHribE6b+LStAO7aAgweefLE5sqDO7Uz6/mnTDyJxCt7HNQnE/Op8sAvRa33d752aUkPfO9S0mgzVAoFQ==", - "dev": true, - "license": "MIT", - "peer": true, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-tmux-context": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-tmux-context/-/dsh-tmux-context-0.1.0-rc.8.tgz", - "integrity": "sha512-ezhL3Wjpn4TqqvgSuKrJgNVG7jrWGekEWRYimqD1SvmAHQAS+Xr9q7DBl1uSFfJDWUOAPlAB8VAuo3k/CLUwKA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@deepseek-ai/schemastery": "^3.18.1" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session": "^0.1.0-rc.8", - "@deepseek-ai/dsh-shell": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-token-meter": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-token-meter/-/dsh-token-meter-0.1.0-rc.8.tgz", - "integrity": "sha512-ZcS6vuuJhoqjUrbyROuiiYk4nrvChkkYEfIoj7CjGbNArWOhbStmBaiPyahtcB1kThcnUKdu7vv7DaZJdLw8Lg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@deepseek-ai/schemastery": "^3.18.1", - "zod": "^4.4.3" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-compaction": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session-projection": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-tool-ask-user": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-tool-ask-user/-/dsh-tool-ask-user-0.1.0-rc.8.tgz", - "integrity": "sha512-PQVcuvNvTI18B2jSvgS20wX0GRnpom+6X6iNBL/WPLiicJeoxvDYj+M7SjdSsqBNv5t0i9VlYhO4NYicmluy+g==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-tools": "^0.1.0-rc.8", - "@deepseek-ai/dsh-user-questions": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-tool-bash": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-tool-bash/-/dsh-tool-bash-0.1.0-rc.8.tgz", - "integrity": "sha512-VvP8Ky8ifqS7Iy7XUxc6cWB7sse3X6gqr92m0hBuodwQblzrZq2b6IyzfTzXKZKLqt5mMUaLRt7IPIDOOG+WEQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@deepseek-ai/schemastery": "^3.18.1" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-jobs": "^0.1.0-rc.8", - "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", - "@deepseek-ai/dsh-sandbox": "^0.1.0-rc.8", - "@deepseek-ai/dsh-sandbox-policy": "^0.1.0-rc.8", - "@deepseek-ai/dsh-shell": "^0.1.0-rc.8", - "@deepseek-ai/dsh-shell-env": "^0.1.0-rc.8", - "@deepseek-ai/dsh-system-prompt": "^0.1.0-rc.8", - "@deepseek-ai/dsh-tools": "^0.1.0-rc.8", - "@deepseek-ai/dsh-user-approval": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-tool-bash-persistent": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-tool-bash-persistent/-/dsh-tool-bash-persistent-0.1.0-rc.8.tgz", - "integrity": "sha512-GySj2Nr7y4ewYTH0miD5DzfLEZNxAmWfSyJ5oOYVtzIbqkcU5WOjpsjQvDg0kuERXAq4MYcdc2QfrPet1/MkIQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@deepseek-ai/schemastery": "^3.18.1" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-terminal": "^0.1.0-rc.8", - "@deepseek-ai/dsh-timeout": "^0.1.0-rc.8", - "@deepseek-ai/dsh-tools": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-tool-call-timeout-policy": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-tool-call-timeout-policy/-/dsh-tool-call-timeout-policy-0.1.0-rc.8.tgz", - "integrity": "sha512-Z6M/nkcz40DisaOIHqUOjjjW4wCi+JqQNoUhOu+VAoBDWHl7SDmEvdWSQUwkyOETjcfdRSG4RTJ5z/rBUVCPHQ==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", - "@deepseek-ai/dsh-timeout": "^0.1.0-rc.8", - "@deepseek-ai/dsh-tools": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-tool-cordis": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-tool-cordis/-/dsh-tool-cordis-0.1.0-rc.8.tgz", - "integrity": "sha512-bIbkazp5xasqtJBFljOGVIdxyAAWIcKoxMuhDoUpfPFuEqZaXJumYJJ9+ugqr+KKkddjuf2SvlpE5XB4zWcNvg==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", - "@deepseek-ai/dsh-cordis-host-runner": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", - "@deepseek-ai/dsh-scope": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session": "^0.1.0-rc.8", - "@deepseek-ai/dsh-system-prompt": "^0.1.0-rc.8", - "@deepseek-ai/dsh-tools": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-tool-fs": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-tool-fs/-/dsh-tool-fs-0.1.0-rc.8.tgz", - "integrity": "sha512-pxo2YfVlqcw0sCA2+4DtqaaYsuxkx1QfvjT3VO+ckZMWn/UnGOUuzjJtKhVynwjm8prttGqK2LBXUTBZPlKTWg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@deepseek-ai/schemastery": "^3.18.1", - "diff": "^9.0.0" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-attachment": "^0.1.0-rc.8", - "@deepseek-ai/dsh-fs": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", - "@deepseek-ai/dsh-sandbox": "^0.1.0-rc.8", - "@deepseek-ai/dsh-sandbox-policy": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session": "^0.1.0-rc.8", - "@deepseek-ai/dsh-system-prompt": "^0.1.0-rc.8", - "@deepseek-ai/dsh-tools": "^0.1.0-rc.8", - "@deepseek-ai/dsh-user-approval": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-tool-fs-search": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-tool-fs-search/-/dsh-tool-fs-search-0.1.0-rc.8.tgz", - "integrity": "sha512-AZvESByrPbBIYIGDoTgVOHH48antHy2ZSaLfsVfz1Rw/jQIeiBKwt2LYIPhRGGvev6TXw95qWKt5cyv6WDXHlg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@deepseek-ai/schemastery": "^3.18.1", - "@vscode/ripgrep": "^1.18.0" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", - "@deepseek-ai/dsh-output-retention": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session": "^0.1.0-rc.8", - "@deepseek-ai/dsh-spill": "^0.1.0-rc.8", - "@deepseek-ai/dsh-subprocess": "^0.1.0-rc.8", - "@deepseek-ai/dsh-system-prompt": "^0.1.0-rc.8", - "@deepseek-ai/dsh-timeout": "^0.1.0-rc.8", - "@deepseek-ai/dsh-tools": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-tool-goal": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-tool-goal/-/dsh-tool-goal-0.1.0-rc.8.tgz", - "integrity": "sha512-EO8iqRV3R8YgdMGUVAp/20XCKbegdwZ7fqr7+oSg11lGHuTnXDz4im4HBXri/wmL9XHeBjmcAQ0BXESbhX2VOQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@deepseek-ai/schemastery": "^3.18.1" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", - "@deepseek-ai/dsh-goal": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session": "^0.1.0-rc.8", - "@deepseek-ai/dsh-system-prompt": "^0.1.0-rc.8", - "@deepseek-ai/dsh-tools": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-tool-jobs": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-tool-jobs/-/dsh-tool-jobs-0.1.0-rc.8.tgz", - "integrity": "sha512-p3gWi38ryJFRes1lTAdVkdZrUBB8RYPpy4XqZ9DgC2qcrLOJZnnsprIUxyDDmhbyargOgTGc3hEeRU5g8OQAIA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@deepseek-ai/schemastery": "^3.18.1" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-jobs": "^0.1.0-rc.8", - "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", - "@deepseek-ai/dsh-output-retention": "^0.1.0-rc.8", - "@deepseek-ai/dsh-system-prompt": "^0.1.0-rc.8", - "@deepseek-ai/dsh-tools": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-tool-pwsh": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-tool-pwsh/-/dsh-tool-pwsh-0.1.0-rc.8.tgz", - "integrity": "sha512-B5F08tsSD7DHqXDXjn/Q11FavHw1U8/WAEqp8AC47vDRymPJIgTM8zSlJ0Lx7aZaKPTW4zQYtSmwUhy93q6zfw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@deepseek-ai/schemastery": "^3.18.1" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-jobs": "^0.1.0-rc.8", - "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", - "@deepseek-ai/dsh-sandbox": "^0.1.0-rc.8", - "@deepseek-ai/dsh-sandbox-policy": "^0.1.0-rc.8", - "@deepseek-ai/dsh-shell": "^0.1.0-rc.8", - "@deepseek-ai/dsh-shell-env": "^0.1.0-rc.8", - "@deepseek-ai/dsh-system-prompt": "^0.1.0-rc.8", - "@deepseek-ai/dsh-tools": "^0.1.0-rc.8", - "@deepseek-ai/dsh-user-approval": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-tool-pwsh-persistent": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-tool-pwsh-persistent/-/dsh-tool-pwsh-persistent-0.1.0-rc.8.tgz", - "integrity": "sha512-OxQhywkvUTuGj26yaE1LyoADsCKttaIdiq2dJd+Xcbjc+tnI1gfoVrBj+Sta3/uT7x66kKjXZ1+gnw6gK5qISQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@deepseek-ai/schemastery": "^3.18.1" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-terminal": "^0.1.0-rc.8", - "@deepseek-ai/dsh-timeout": "^0.1.0-rc.8", - "@deepseek-ai/dsh-tools": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-tool-ralph": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-tool-ralph/-/dsh-tool-ralph-0.1.0-rc.8.tgz", - "integrity": "sha512-+kVCbLEBDxOCCHPdR5+hgQFbkTvTaJ3D7zTNxNEtS5Tr/7eGAU7/VmwNMMSZ4Z+eyHQQEm4vgT+O1pMTvLmb7g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@deepseek-ai/schemastery": "^3.18.1" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", - "@deepseek-ai/dsh-subagent": "^0.1.0-rc.8", - "@deepseek-ai/dsh-system-prompt": "^0.1.0-rc.8", - "@deepseek-ai/dsh-tools": "^0.1.0-rc.8", - "@deepseek-ai/dsh-workflow": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-tool-skill": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-tool-skill/-/dsh-tool-skill-0.1.0-rc.8.tgz", - "integrity": "sha512-oQAPyXiQDDZ73rZwST7KqwUAr0Al3U1dxWdtzETsMzvNSQE9fmMBz5jUObFIEjxxJcA07Pp1DFzuJdpkCIDeCw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@deepseek-ai/schemastery": "^3.18.1" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", - "@deepseek-ai/dsh-skill": "^0.1.0-rc.8", - "@deepseek-ai/dsh-tools": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-tool-str-replace-editor": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-tool-str-replace-editor/-/dsh-tool-str-replace-editor-0.1.0-rc.8.tgz", - "integrity": "sha512-2gyO5a5xNvBo9I5vmVSvgXRfxUfKGDu3WjjdK0aDWx/Y+C1r1mGVC7R5mN/oJstcUCIyKm483ux1pT9/O1QD8w==", - "dev": true, - "license": "MIT", - "dependencies": { - "@deepseek-ai/schemastery": "^3.18.1" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-fs": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-sandbox": "^0.1.0-rc.8", - "@deepseek-ai/dsh-sandbox-policy": "^0.1.0-rc.8", - "@deepseek-ai/dsh-tools": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-tool-subagent": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-tool-subagent/-/dsh-tool-subagent-0.1.0-rc.8.tgz", - "integrity": "sha512-mwNV8M7hsy9+OsSFCluv87FiDHaXO91m83xF/o34Ip9xrgkGs7LOCjvUdCpwjxFTJenWEcvEU90aa7vv3aT/Iw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@deepseek-ai/schemastery": "^3.18.1" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-jobs": "^0.1.0-rc.8", - "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", - "@deepseek-ai/dsh-subagent": "^0.1.0-rc.8", - "@deepseek-ai/dsh-system-prompt": "^0.1.0-rc.8", - "@deepseek-ai/dsh-tools": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-tool-subagent-control": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-tool-subagent-control/-/dsh-tool-subagent-control-0.1.0-rc.8.tgz", - "integrity": "sha512-zXF9iIzr96w/S3jNxkRcyV1ouwA1eUCSmvqhlSDkkcA8RH5jt5vWkTia8fwRs1pFS9m7OpbLtvbDxjC8D3nedw==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session": "^0.1.0-rc.8", - "@deepseek-ai/dsh-subagent": "^0.1.0-rc.8", - "@deepseek-ai/dsh-tools": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-tool-subagent-report": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-tool-subagent-report/-/dsh-tool-subagent-report-0.1.0-rc.8.tgz", - "integrity": "sha512-u0CzoSu7O1YyOpGyHfmT/P2hCfnepSzVKrs6MHFrzjbuiRFEcVme6/iLrc7QdLtg484Q1kcnqG2z0OZS24AnWQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@deepseek-ai/schemastery": "^3.18.1" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", - "@deepseek-ai/dsh-subagent": "^0.1.0-rc.8", - "@deepseek-ai/dsh-system-prompt": "^0.1.0-rc.8", - "@deepseek-ai/dsh-tools": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-tool-todo": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-tool-todo/-/dsh-tool-todo-0.1.0-rc.8.tgz", - "integrity": "sha512-eWxwTeX5WsQPSsz1qyJq+UMiASYB5UHLdObVd4vFLYKbFOoglUK0X+Ie5OjlAkFTP+OzCQMAzUl2gJMwJPWKig==", - "dev": true, - "license": "MIT", - "dependencies": { - "@deepseek-ai/schemastery": "^3.18.1", - "zod": "^4.4.3" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session-projection": "^0.1.0-rc.8", - "@deepseek-ai/dsh-tools": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-tool-web": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-tool-web/-/dsh-tool-web-0.1.0-rc.8.tgz", - "integrity": "sha512-MrTkQ2L52A13ysTM94bSW+5sXq3AyVNoo5q3bK47bsl+hg9Kga5gDgGAZ+SGVSQZAUEHXfuYGHaErdUp50bncw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@deepseek-ai/schemastery": "^3.18.1", - "@joplin/turndown-plugin-gfm": "^1.0.67", - "turndown": "^7.2.4" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", - "@deepseek-ai/dsh-system-prompt": "^0.1.0-rc.8", - "@deepseek-ai/dsh-tools": "^0.1.0-rc.8", - "@deepseek-ai/dsh-web": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-tool-workflow": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-tool-workflow/-/dsh-tool-workflow-0.1.0-rc.8.tgz", - "integrity": "sha512-Z3MCCLM28J/nqiqwHG9roGVUzwMKEADRsSNLPYNemXq5vVEYjm5sBwC+QcWtiQ7NxKXf5ViUu3eKXTe1Fh5TNg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@deepseek-ai/schemastery": "^3.18.1" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session": "^0.1.0-rc.8", - "@deepseek-ai/dsh-system-prompt": "^0.1.0-rc.8", - "@deepseek-ai/dsh-tools": "^0.1.0-rc.8", - "@deepseek-ai/dsh-workflow": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-tools": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-tools/-/dsh-tools-0.1.0-rc.8.tgz", - "integrity": "sha512-tvuGAVUS4yoPW9zH7CGWJgMlAzGjfu2UlRiricldlcwSKAaJZPZx/K/YfTivUyDTER6aK1DJUnIpVG7RD/DoHQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@deepseek-ai/schemastery": "^3.18.1" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", - "@deepseek-ai/dsh-code-runtime": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", - "@deepseek-ai/dsh-scope": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session": "^0.1.0-rc.8", - "@deepseek-ai/dsh-system-prompt": "^0.1.0-rc.8", - "@deepseek-ai/dsh-user-approval": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-typert-loader": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-typert-loader/-/dsh-typert-loader-0.1.0-rc.8.tgz", - "integrity": "sha512-IB2Bkv7UglS0y/Dt7buFq87bbUkD/njvuCp4/bRxlbb/8U02b7v18UXnYFoZjCusfzeYxaCBZihImv7aDMBhCA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@deepseek-ai/schemastery": "^3.18.1" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/cordis-plugin-loader": "^1.0.2", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-typert-registry": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-typert-protocol": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-typert-protocol/-/dsh-typert-protocol-0.1.0-rc.8.tgz", - "integrity": "sha512-scwEAefRBL7gRpaXiEdiHRMvlr8dLmUbiEvy0LOAX/8X3FZBd/5tHQ/8lCppAQNTDZMI/LSiSMpu5XrFId+7cQ==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-typert-registry": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-typert-registry/-/dsh-typert-registry-0.1.0-rc.8.tgz", - "integrity": "sha512-pxfRE5f1y81h2lNqj0uooYrErTVgpzKfYm4W+ppRafN5s/+1jlLIYWiG3wWD3bnxyoD2NLcTEhi/GXoaqiwdaw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@deepseek-ai/dsh-typert-protocol": "^0.1.0-rc.8", - "zod": "^4.4.3" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-user-approval": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-user-approval/-/dsh-user-approval-0.1.0-rc.8.tgz", - "integrity": "sha512-6SFCxp7dgNFEyzQIcs5i9C+5djgXsAeV0iKmZUCLlcIeVM1chcCMHyGcoXlw8yyB14qFMrMs+TPvhvpu2WWxAw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@deepseek-ai/schemastery": "^3.18.1" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", - "@deepseek-ai/dsh-brand": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", - "@deepseek-ai/dsh-scope": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session": "^0.1.0-rc.8", - "@deepseek-ai/dsh-system-prompt": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-user-questions": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-user-questions/-/dsh-user-questions-0.1.0-rc.8.tgz", - "integrity": "sha512-kiOAlpKKfB89iObWiiVpueD4XCaday203LGUs7+eGb2isolY6VppoGb7ZmcJQqsW63bjbAA7wZeJuN3CoxcvSQ==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-llm": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-web": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-web/-/dsh-web-0.1.0-rc.8.tgz", - "integrity": "sha512-YLraDwZTx0Y3Jqw2cu4eClv9ZgEJYoeSFzTe7c9JZ4Z3ThaNCCwEaXWEPMBiPKU6QlR8ahkPPj6xoU9+nPO66g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@deepseek-ai/schemastery": "^3.18.1" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-llm": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-web-app": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-web-app/-/dsh-web-app-0.1.0-rc.8.tgz", - "integrity": "sha512-Te/N+AxFmQF2267yMqama5Lp2evsBJeFsqhnEZPfvFhquLBBWgtO5DNZ2cxto5NhGGNNCk/JV25vHRxd7bZl8g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@deepseek-ai/dsh-agent-presets": "^0.1.0-rc.8", - "@deepseek-ai/dsh-api-remotes": "^0.1.0-rc.8", - "@deepseek-ai/dsh-app-boot": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-connection": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-hmr": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-locale": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-modules": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-runtime": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-ui-agent-preset": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-ui-attachment": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-ui-brand-official": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-ui-commands": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-ui-conversation": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-ui-cordis": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-ui-deliverables": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-ui-directory-picker-browse": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-ui-directory-picker-native": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-ui-goal": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-ui-input-trigger": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-ui-jobs": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-ui-layout": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-ui-message-feedback": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-ui-model-selection": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-ui-permission-presets": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-ui-plan": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-ui-reference": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-ui-renderer": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-ui-settings": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-ui-settings-general": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-ui-settings-models": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-ui-settings-plugin-inventory": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-ui-settings-plugins": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-ui-sidebar": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-ui-skill": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-ui-subagent": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-ui-theme": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-ui-tool": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-ui-trajectory": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-ui-user-questions": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-ui-workflow-run": "^0.1.0-rc.8", - "@deepseek-ai/dsh-client-ui-workspace": "^0.1.0-rc.8", - "@deepseek-ai/dsh-cmdline": "^0.1.0-rc.8", - "@deepseek-ai/dsh-code-runtime-worker-thread": "^0.1.0-rc.8", - "@deepseek-ai/dsh-cordis-client-runner": "^0.1.0-rc.8", - "@deepseek-ai/dsh-cordis-host-runner": "^0.1.0-rc.8", - "@deepseek-ai/dsh-file-reference": "^0.1.0-rc.8", - "@deepseek-ai/dsh-file-reference-local": "^0.1.0-rc.8", - "@deepseek-ai/dsh-host-apiproxy": "^0.1.0-rc.8", - "@deepseek-ai/dsh-host-directory-picker-auto": "^0.1.0-rc.8", - "@deepseek-ai/dsh-host-directory-picker-browse": "^0.1.0-rc.8", - "@deepseek-ai/dsh-host-directory-picker-native": "^0.1.0-rc.8", - "@deepseek-ai/dsh-host-frontend-static": "^0.1.0-rc.8", - "@deepseek-ai/dsh-host-plugin-inventory": "^0.1.0-rc.8", - "@deepseek-ai/dsh-host-webserver": "^0.1.0-rc.8", - "@deepseek-ai/dsh-launch-environment": "^0.1.0-rc.8", - "@deepseek-ai/dsh-message-feedback": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session-log-export": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session-projection-cache": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session-reference": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session-stats": "^0.1.0-rc.8", - "@deepseek-ai/dsh-storage": "^0.1.0-rc.8", - "@deepseek-ai/dsh-storage-domain": "^0.1.0-rc.8", - "@deepseek-ai/dsh-storage-json": "^0.1.0-rc.8", - "@deepseek-ai/dsh-subprocess": "^0.1.0-rc.8", - "@deepseek-ai/dsh-web-frontend": "^0.1.0-rc.8", - "@deepseek-ai/dsh-workspace": "^0.1.0-rc.8", - "@deepseek-ai/schemastery": "^3.18.1", - "commander": "^15.0.0", - "open": "^11.0.0" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/cordis-plugin-loader": "^1.0.2", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-shell-env": "^0.1.0-rc.8", - "@deepseek-ai/dsh-system-prompt": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-web-frontend": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-web-frontend/-/dsh-web-frontend-0.1.0-rc.8.tgz", - "integrity": "sha512-GxWJtkNEniYtSH19XWIJvMO2RSP2bMAZvs3Z6m9cEr9OFbngCY5XCXwqsJMYqOJIao0eSePp/eRCPeXNvqeGXA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@deepseek-ai/dsh-web-search-deepseek": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-web-search-deepseek/-/dsh-web-search-deepseek-0.1.0-rc.8.tgz", - "integrity": "sha512-ifaFw+Cil3yte/9r//3wwMWWPIMuYhvYAB0Hk56IVf+8RDbnRkTJY2foFNNgD91dq1ZL2gBijkdxv1c7wDt+EA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@deepseek-ai/schemastery": "^3.18.1" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", - "@deepseek-ai/dsh-credentials": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-launch-environment": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session": "^0.1.0-rc.8", - "@deepseek-ai/dsh-settings": "^0.1.0-rc.8", - "@deepseek-ai/dsh-web": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-workflow": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-workflow/-/dsh-workflow-0.1.0-rc.8.tgz", - "integrity": "sha512-a4UJKJAFOPQgVaWegk8MIh8BQjqerkGhHu2+uGF4wyGanzI7FHHY/OUmH4hHTVEx2qFcWh732Od/T8LgL6gcbg==", - "dev": true, - "license": "MIT", - "peer": true, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", - "@deepseek-ai/dsh-brand": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-workflow-worker-thread": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-workflow-worker-thread/-/dsh-workflow-worker-thread-0.1.0-rc.8.tgz", - "integrity": "sha512-QBkHJ8l174U3VqHRi2KyJIFey+Uxzo/OOFbTFx7TP5f761lPvqYiXlILuQJ9QvT7WJTyZO3QRLIIU6ZEBwxTIA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@deepseek-ai/schemastery": "^3.18.1" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-agent": "^0.1.0-rc.8", - "@deepseek-ai/dsh-brand": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-llm": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session": "^0.1.0-rc.8", - "@deepseek-ai/dsh-subagent": "^0.1.0-rc.8", - "@deepseek-ai/dsh-tools": "^0.1.0-rc.8", - "@deepseek-ai/dsh-workflow": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/dsh-workspace": { - "version": "0.1.0-rc.8", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-workspace/-/dsh-workspace-0.1.0-rc.8.tgz", - "integrity": "sha512-Uyw44WcYvXRQjb0kUstTEJmL83hkGQbWnJzglaGWcAvsZBjQHeBgKuLzOZin1yc/dRX2pKuk1InFwxKXpaHjBA==", - "dev": true, - "license": "MIT", - "dependencies": { - "zod": "^4.4.3" - }, - "peerDependencies": { - "@deepseek-ai/cordis": "^4.0.1", - "@deepseek-ai/dsh-brand": "^0.1.0-rc.8", - "@deepseek-ai/dsh-invariants": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session": "^0.1.0-rc.8", - "@deepseek-ai/dsh-session-persistence": "^0.1.0-rc.8", - "@deepseek-ai/dsh-storage": "^0.1.0-rc.8", - "@deepseek-ai/dsh-storage-domain": "^0.1.0-rc.8" - } - }, - "node_modules/@deepseek-ai/node-addon-landlock-run": { - "version": "0.1.1", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/node-addon-landlock-run/-/node-addon-landlock-run-0.1.1.tgz", - "integrity": "sha512-aHGhlQJEutfobKM/4K59SERbT7RmQdD2oMKzD8Bne/Ps7TeT8AweCN+dpdfuxQhMNbFcJMymrgPnID0WYQ30Tw==", - "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">=20" - }, - "optionalDependencies": { - "@deepseek-ai/node-addon-landlock-run-linux-arm64": "0.1.1", - "@deepseek-ai/node-addon-landlock-run-linux-x64": "0.1.1" - } - }, - "node_modules/@deepseek-ai/node-addon-landlock-run-linux-arm64": { - "version": "0.1.1", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/node-addon-landlock-run-linux-arm64/-/node-addon-landlock-run-linux-arm64-0.1.1.tgz", - "integrity": "sha512-lYY2RbcPW4rGRM5hVJbrXlvLqyBxeJBjBqvt+QTHTU+GtfUVVjTODKa4e3CRwMQoCEpOjoARdQBHbN7HvE72WQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "BSD-3-Clause", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=20" - } - }, - "node_modules/@deepseek-ai/node-addon-landlock-run-linux-x64": { - "version": "0.1.1", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/node-addon-landlock-run-linux-x64/-/node-addon-landlock-run-linux-x64-0.1.1.tgz", - "integrity": "sha512-OHAzPW2Coe/iYobAJAAA8CeVrBoKV4BnNHsgwvXwOfishxkUVSWSvdyxrZPiwYRXutpIGVrSo9zV3WOQy2euBA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "BSD-3-Clause", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=20" - } - }, - "node_modules/@deepseek-ai/schemastery": { - "version": "3.18.1", - "resolved": "https://registry.npmmirror.com/@deepseek-ai/schemastery/-/schemastery-3.18.1.tgz", - "integrity": "sha512-Qn0FCSwCQnpnj6SB31I6i2sIKgKWnkbJM8O0EU91Gv2UsYVvtZTl6IA0sCwk2e2MZf5S8w5hpq9QkeVvK9qwxg==", - "license": "MIT", - "dependencies": { - "@deepseek-ai/cosmokit": "^1.8.2", - "@standard-schema/spec": "^1.1.0" - } - }, - "node_modules/@earendil-works/pi-ai": { - "version": "0.82.1", - "resolved": "https://registry.npmmirror.com/@earendil-works/pi-ai/-/pi-ai-0.82.1.tgz", - "integrity": "sha512-3WFYRhEp3lQB3444EhPMBcM7zSaEUE3eJgHOR7s4081NLqbw/FsWilIKWXSua0Gv3sRr7m9xMidR3pPDE7jI/A==", - "dev": true, - "license": "MIT", - "dependencies": { - "@anthropic-ai/sdk": "0.91.1", - "@aws-sdk/client-bedrock-runtime": "3.1048.0", - "@google/genai": "1.52.0", - "@mistralai/mistralai": "2.2.6", - "@opentelemetry/api": "1.9.0", - "@smithy/node-http-handler": "4.7.3", - "http-proxy-agent": "7.0.2", - "https-proxy-agent": "7.0.6", - "openai": "6.26.0", - "partial-json": "0.1.7", - "typebox": "1.1.38" - }, - "bin": { - "pi-ai": "dist/cli.js" - }, - "engines": { - "node": ">=22.19.0" - } - }, - "node_modules/@earendil-works/pi-ai/node_modules/@opentelemetry/api": { - "version": "1.9.0", - "resolved": "https://registry.npmmirror.com/@opentelemetry/api/-/api-1.9.0.tgz", - "integrity": "sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/@emnapi/runtime": { - "version": "1.11.3", - "resolved": "https://registry.npmmirror.com/@emnapi/runtime/-/runtime-1.11.3.tgz", - "integrity": "sha512-Xz4Tpyki7XyrpbUK1jR1AhdAdaXyhhY4lZ3neLodmhpuWfy2PAQN5B46sAiU4liOXGLkHypn/qU+jvfWSCYYLA==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "tslib": "^2.4.0" - } - }, - "node_modules/@google/genai": { - "version": "1.52.0", - "resolved": "https://registry.npmmirror.com/@google/genai/-/genai-1.52.0.tgz", - "integrity": "sha512-gwSvbpiN/17O9TbsqSsE/OzZcpv5Fo4RQjdngGgogtuB9RsyJ8ZHhX5KjHj1bp5N9snN2eK8LDGXSaWW2hof8Q==", - "dev": true, - "hasInstallScript": true, - "license": "Apache-2.0", - "dependencies": { - "google-auth-library": "^10.3.0", - "p-retry": "^4.6.2", - "protobufjs": "^7.5.4", - "ws": "^8.18.0" - }, - "engines": { - "node": ">=20.0.0" - }, - "peerDependencies": { - "@modelcontextprotocol/sdk": "^1.25.2" - }, - "peerDependenciesMeta": { - "@modelcontextprotocol/sdk": { - "optional": true - } - } - }, - "node_modules/@hono/node-server": { - "version": "2.1.1", - "resolved": "https://registry.npmmirror.com/@hono/node-server/-/node-server-2.1.1.tgz", - "integrity": "sha512-ELuehkj5VCBdgEw9zs+ivkKwyzzUCSQuE96YmiPvn1ECBoZCczbFXJLeEGMTYjphP6gydh4pHMqEYPVMYUVgQg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=20" - }, - "peerDependencies": { - "hono": "^4" - } - }, - "node_modules/@img/colour": { - "version": "1.1.0", - "resolved": "https://registry.npmmirror.com/@img/colour/-/colour-1.1.0.tgz", - "integrity": "sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - } - }, - "node_modules/@img/sharp-darwin-arm64": { - "version": "0.35.3", - "resolved": "https://registry.npmmirror.com/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.35.3.tgz", - "integrity": "sha512-RMnFX7YQsMoh7lWfcM4NEHHymBX/rLuKNPVM84XE9ONPcaSCDgE7CHIHpSgPcO2xcRthgBy1HfNO319mwhIAkg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "Apache-2.0", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=20.9.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-darwin-arm64": "1.3.2" - } - }, - "node_modules/@img/sharp-darwin-x64": { - "version": "0.35.3", - "resolved": "https://registry.npmmirror.com/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.35.3.tgz", - "integrity": "sha512-Xo+5uFBtLN0BKqieTxiFzFPQAUlBbbH5iBKyRX/z1JrbnYsHTfKJnUfL8+p2TPXr1pXqao4eeL4Rl144uDpK9w==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "Apache-2.0", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=20.9.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-darwin-x64": "1.3.2" - } - }, - "node_modules/@img/sharp-freebsd-wasm32": { - "version": "0.35.3", - "resolved": "https://registry.npmmirror.com/@img/sharp-freebsd-wasm32/-/sharp-freebsd-wasm32-0.35.3.tgz", - "integrity": "sha512-lUxcqWIj2wMQ9BrwNjngcr1gWUr5xgaGThBRqPPalIC2n67Cqj1uPh8NnA/ZhAg8hUbKl+kVHKwgUIwe6ZYPrg==", - "dev": true, - "license": "Apache-2.0", - "optional": true, - "os": [ - "freebsd" - ], - "dependencies": { - "@img/sharp-wasm32": "0.35.3" - }, - "engines": { - "node": ">=20.9.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-darwin-arm64": { - "version": "1.3.2", - "resolved": "https://registry.npmmirror.com/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.3.2.tgz", - "integrity": "sha512-9J6ypZFpQBj4YnePGoq/S38w6nz+vqg5WZLrLGY4YuSemdMq47GMLBPO42MzwdGwpg/agZ7xzZcFHa48xlywfg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "darwin" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-darwin-x64": { - "version": "1.3.2", - "resolved": "https://registry.npmmirror.com/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.3.2.tgz", - "integrity": "sha512-m2pW1n6cns9VaubNwsZ+c3CRYjxNQWgJ5gPlnL1nbBcpkBvFm6SCFN5o0psFHI8w9n11NKhFkeEDns98tiqbEw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "darwin" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-linux-arm": { - "version": "1.3.2", - "resolved": "https://registry.npmmirror.com/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.3.2.tgz", - "integrity": "sha512-1eMLzy92I4J6rmi4mAT8yC3HxOtniyGELlzGbNMLLeqe052ahFQ0h6LFq+lh5DsDIdYViIDst08abvSbcEdLXQ==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-linux-arm64": { - "version": "1.3.2", - "resolved": "https://registry.npmmirror.com/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.3.2.tgz", - "integrity": "sha512-dqVSFynCox4C/J8kT16V7SIFAns0IjgLwkvYT7p8LQVmJ5OS5b6tI9IGflxTeuBS//zXeFIUbwt5dwxyZ17cnA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-linux-ppc64": { - "version": "1.3.2", - "resolved": "https://registry.npmmirror.com/@img/sharp-libvips-linux-ppc64/-/sharp-libvips-linux-ppc64-1.3.2.tgz", - "integrity": "sha512-3z0NHDxD6n5I9gc05U1eW1AyRm+Gznzq3naMrthPNqE6oYykcogW0l/jfpJdjYnuNl8R7yI9pNbE1XiUeyq0Aw==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-linux-riscv64": { - "version": "1.3.2", - "resolved": "https://registry.npmmirror.com/@img/sharp-libvips-linux-riscv64/-/sharp-libvips-linux-riscv64-1.3.2.tgz", - "integrity": "sha512-bsb4rI+NldGOsXuej2r8OdSS8+zXDVaCWxyWrcv6kneTOlgAHtZABRzBBCwdsPiD90J4myNJuHpg6kA20ImW/w==", - "cpu": [ - "riscv64" - ], - "dev": true, - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-linux-s390x": { - "version": "1.3.2", - "resolved": "https://registry.npmmirror.com/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.3.2.tgz", - "integrity": "sha512-/ABshyj8gCpyIrNXnHn4LorDJ0HHm1VhXPBlxZ8zAtfVPAaSafXPGn+sUSIRiwaSBy0mmFjSjiXI5mkcwdChKQ==", - "cpu": [ - "s390x" - ], - "dev": true, - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-linux-x64": { - "version": "1.3.2", - "resolved": "https://registry.npmmirror.com/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.3.2.tgz", - "integrity": "sha512-ITPEtgffGJ0S6G9dRyw/366tJQqFRcHWPHhC+Stpg3Z8AEMrDrTr2lhdz4f/Y/HMbRh//7Z5mBzEpVdi62Oc3w==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-linuxmusl-arm64": { - "version": "1.3.2", - "resolved": "https://registry.npmmirror.com/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.3.2.tgz", - "integrity": "sha512-zE9EdiUzUmg5mDT5a1rk5fYJ6GWPloTwWBYDS14naqHsL+EaMpDj1AWnpLgh3u0YCORv2Tt50wrcrpYqkP97Kw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-linuxmusl-x64": { - "version": "1.3.2", - "resolved": "https://registry.npmmirror.com/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.3.2.tgz", - "integrity": "sha512-m0lrLiUt+lBYnCFr8qV/65yMR4E/c7/wf78I5eKTdkEakFAlZ9QlzEM3QIhhAwVeUhLAHLcCq7a7Vszq/oFNZQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-linux-arm": { - "version": "0.35.3", - "resolved": "https://registry.npmmirror.com/@img/sharp-linux-arm/-/sharp-linux-arm-0.35.3.tgz", - "integrity": "sha512-affVWCTLooy8TSxbDx2qkzuDeaWLNVBA+P//FNBirHsXpP2fuBhk5AuboYUnrDnzoXes8GFjpTx0SBFOCRg+FA==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=20.9.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linux-arm": "1.3.2" - } - }, - "node_modules/@img/sharp-linux-arm64": { - "version": "0.35.3", - "resolved": "https://registry.npmmirror.com/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.35.3.tgz", - "integrity": "sha512-QgKDspHPnrU+GQ55XPhGwyhC8acLVOOSyAvo1oVfFmrIXLkDNmGWzAfDZ4xK8oSA1qBQrALcHX0G5UZni/SuFQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=20.9.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linux-arm64": "1.3.2" - } - }, - "node_modules/@img/sharp-linux-ppc64": { - "version": "0.35.3", - "resolved": "https://registry.npmmirror.com/@img/sharp-linux-ppc64/-/sharp-linux-ppc64-0.35.3.tgz", - "integrity": "sha512-sMd8rDxmpLOwv/7N44klFjOD5DUO7FLdjiXDI0hoxYaf7Ar262dQIEkosE98bps+5HPLtp/EvNqeqQtOycP/IA==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=20.9.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linux-ppc64": "1.3.2" - } - }, - "node_modules/@img/sharp-linux-riscv64": { - "version": "0.35.3", - "resolved": "https://registry.npmmirror.com/@img/sharp-linux-riscv64/-/sharp-linux-riscv64-0.35.3.tgz", - "integrity": "sha512-0Eob78yjlYPfL5vMNWAW55l3R9Y6BQS/gOfe0ZcP9mEz9ohhKSt4im1hayiknXgf8AWrFqMvJcKIdmLmEe7yeQ==", - "cpu": [ - "riscv64" - ], - "dev": true, - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=20.9.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linux-riscv64": "1.3.2" - } - }, - "node_modules/@img/sharp-linux-s390x": { - "version": "0.35.3", - "resolved": "https://registry.npmmirror.com/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.35.3.tgz", - "integrity": "sha512-KgAxQ0DxpNOq1rG2t5cgTgShJFGSuU7XO45cqC+1NVOuZnP6tlgZRuSYOfNupGkHID0o3cJOsw4DVeJpMovcGw==", - "cpu": [ - "s390x" - ], - "dev": true, - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=20.9.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linux-s390x": "1.3.2" - } - }, - "node_modules/@img/sharp-linux-x64": { - "version": "0.35.3", - "resolved": "https://registry.npmmirror.com/@img/sharp-linux-x64/-/sharp-linux-x64-0.35.3.tgz", - "integrity": "sha512-8pqvxubL2PGdhlPy6GLqzDYMUjyRmKAwKHYKixpdJYBUK7PJ0C029XdsnpFIdgRZG68fZiGdHVWcKPvtiPB4cA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=20.9.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linux-x64": "1.3.2" - } - }, - "node_modules/@img/sharp-linuxmusl-arm64": { - "version": "0.35.3", - "resolved": "https://registry.npmmirror.com/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.35.3.tgz", - "integrity": "sha512-Vz0iQjzzcSX3HCbfwFfCSG/9SCIqyO0mH2sXyiHaAYfBk0cRsCWXRyQYX0ovCK/PAQBbTzQ0dsPQHh5MAFL59w==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=20.9.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linuxmusl-arm64": "1.3.2" - } - }, - "node_modules/@img/sharp-linuxmusl-x64": { - "version": "0.35.3", - "resolved": "https://registry.npmmirror.com/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.35.3.tgz", - "integrity": "sha512-6O1NPKcDVj9QEdg7Hx549EX8U0rp6yXQERqru6yRN7fGBn32UvIRJUlWnk+8xDCiG76hXVBbX82NZ/ZKr0euIg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=20.9.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linuxmusl-x64": "1.3.2" - } - }, - "node_modules/@img/sharp-wasm32": { - "version": "0.35.3", - "resolved": "https://registry.npmmirror.com/@img/sharp-wasm32/-/sharp-wasm32-0.35.3.tgz", - "integrity": "sha512-cZ0XkcYGpHZkqW6iCkqTcmUC0CD9DhD5d/qeZlZkfRBn6GnHniZXLUo5+9xw8Iv76YE6LQFN9YNBlKREcCG76w==", - "dev": true, - "license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT", - "optional": true, - "dependencies": { - "@emnapi/runtime": "^1.11.1" - }, - "engines": { - "node": ">=20.9.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-webcontainers-wasm32": { - "version": "0.35.3", - "resolved": "https://registry.npmmirror.com/@img/sharp-webcontainers-wasm32/-/sharp-webcontainers-wasm32-0.35.3.tgz", - "integrity": "sha512-2rnq7bX3NzeR2T4YWgz8qiG4h3TSdMe+vN1iQXpJleSJ3SM5zQ8Fy2SyyXAWlbxpEZ2Y+Z4u1BePgJEYbSy80Q==", - "cpu": [ - "wasm32" - ], - "dev": true, - "license": "Apache-2.0", - "optional": true, - "dependencies": { - "@img/sharp-wasm32": "0.35.3" - }, - "engines": { - "node": ">=20.9.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-win32-arm64": { - "version": "0.35.3", - "resolved": "https://registry.npmmirror.com/@img/sharp-win32-arm64/-/sharp-win32-arm64-0.35.3.tgz", - "integrity": "sha512-4bPwFdMbeC4JQ8L8LOyWp6nsHcboP5fxkp6iPOXz2Vg49R42TuMs2whkJ5OAP4/Ul035qOzy0AecOF9VOscn4w==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "Apache-2.0 AND LGPL-3.0-or-later", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=20.9.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-win32-ia32": { - "version": "0.35.3", - "resolved": "https://registry.npmmirror.com/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.35.3.tgz", - "integrity": "sha512-r53mXsBN6lFUDiST764SvgwUdHAqM4rPAiDzAmf4fLoB6X/rkfyTrLCg6+g17wJJiCmB3JYgHuUldCWUIRFSXw==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "Apache-2.0 AND LGPL-3.0-or-later", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": "^20.9.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-win32-x64": { - "version": "0.35.3", - "resolved": "https://registry.npmmirror.com/@img/sharp-win32-x64/-/sharp-win32-x64-0.35.3.tgz", - "integrity": "sha512-D4y1vNeZrIIJCN+uHaWVtH86B+aCrdMYYjicy9pXHvbGZeGYLLSd3wdVuC37FxVXlU1ARsk84eKWfWMXGYEqvA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "Apache-2.0 AND LGPL-3.0-or-later", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=20.9.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@joplin/turndown-plugin-gfm": { - "version": "1.0.67", - "resolved": "https://registry.npmmirror.com/@joplin/turndown-plugin-gfm/-/turndown-plugin-gfm-1.0.67.tgz", - "integrity": "sha512-FZfW5EZfidhzd1IaY1uxHnIZPTVOxAdleMZ4/1U6Nt5b7+Qj5JThDnaIomuJtetnUBzuRNbe9FWMuqD4B3dlWA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@koromix/koffi-darwin-arm64": { - "version": "3.1.5", - "resolved": "https://registry.npmmirror.com/@koromix/koffi-darwin-arm64/-/koffi-darwin-arm64-3.1.5.tgz", - "integrity": "sha512-IpqITl2fJi3QN9bTtNnygWPdK7ScSjw3xtGu8e6feYGvimCysu+spgI5KyeslY2jTnqxGS9xr8pLAbLhGJ8edA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "funding": { - "url": "https://liberapay.com/Koromix" - } - }, - "node_modules/@koromix/koffi-darwin-x64": { - "version": "3.1.5", - "resolved": "https://registry.npmmirror.com/@koromix/koffi-darwin-x64/-/koffi-darwin-x64-3.1.5.tgz", - "integrity": "sha512-4Tia4BS5EV/+vN9eIrdToanVe+U/2VqTZCBgOzoUbPKjgky51eqM+3J4qdRUvmYJohcJNPob5/hsxeItUZrl1g==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "funding": { - "url": "https://liberapay.com/Koromix" - } - }, - "node_modules/@koromix/koffi-freebsd-arm64": { - "version": "3.1.5", - "resolved": "https://registry.npmmirror.com/@koromix/koffi-freebsd-arm64/-/koffi-freebsd-arm64-3.1.5.tgz", - "integrity": "sha512-bP94uzseFO79NG3flpU3WxfyvltD+jzC/kN8FDZLi8J0VUZNW1Wmu8yq87KEzjX1qT9KyX4Y+elVbGqHXHTv2Q==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "funding": { - "url": "https://liberapay.com/Koromix" - } - }, - "node_modules/@koromix/koffi-freebsd-ia32": { - "version": "3.1.5", - "resolved": "https://registry.npmmirror.com/@koromix/koffi-freebsd-ia32/-/koffi-freebsd-ia32-3.1.5.tgz", - "integrity": "sha512-raFXXAPHzvCQWhaoMUF+Cc2ZWgg2UBU0RVoowHZhaw9nQYPC1pERcPRH+JA+SNIN6g4d2GFW6uPFc+QbUhsagA==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "funding": { - "url": "https://liberapay.com/Koromix" - } - }, - "node_modules/@koromix/koffi-freebsd-x64": { - "version": "3.1.5", - "resolved": "https://registry.npmmirror.com/@koromix/koffi-freebsd-x64/-/koffi-freebsd-x64-3.1.5.tgz", - "integrity": "sha512-h6RyBZmPMBIDWTABkJIhzDdYwSnYAJvTacHpEjbT55Arkmw1H15Rl7CFtXuEuBrqh+uivoCrRgA6vszl9CsJ9g==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "funding": { - "url": "https://liberapay.com/Koromix" - } - }, - "node_modules/@koromix/koffi-linux-arm64": { - "version": "3.1.5", - "resolved": "https://registry.npmmirror.com/@koromix/koffi-linux-arm64/-/koffi-linux-arm64-3.1.5.tgz", - "integrity": "sha512-u0vCmKPu4yQDhl/ri1J6U3vDnvYtYjoZaIWb+oMbRXhVZeiqdE53MGPb+q2A7Dj2n9IbYloAfEICQbL6l0pmiQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://liberapay.com/Koromix" - } - }, - "node_modules/@koromix/koffi-linux-ia32": { - "version": "3.1.5", - "resolved": "https://registry.npmmirror.com/@koromix/koffi-linux-ia32/-/koffi-linux-ia32-3.1.5.tgz", - "integrity": "sha512-Xa5JbumWglwPVZgrJcLhqyC1wCWlfm7+C00p3FuOTNGp0qoYuf2/tOoAh0/q7+taVm30cMopu/6lRHwdmF6I/w==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://liberapay.com/Koromix" - } - }, - "node_modules/@koromix/koffi-linux-loong64": { - "version": "3.1.5", - "resolved": "https://registry.npmmirror.com/@koromix/koffi-linux-loong64/-/koffi-linux-loong64-3.1.5.tgz", - "integrity": "sha512-F3i2CeTcqVBUQiSRUBSEzX1VgtXmLLiZb/ouZtXHkWpTLhJNd9TH7s3CizTofci0VRqlKdexGUYhK5vzPDAAHA==", - "cpu": [ - "loong64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://liberapay.com/Koromix" - } - }, - "node_modules/@koromix/koffi-linux-riscv64": { - "version": "3.1.5", - "resolved": "https://registry.npmmirror.com/@koromix/koffi-linux-riscv64/-/koffi-linux-riscv64-3.1.5.tgz", - "integrity": "sha512-2TgQuzy+4PfDg+rw3kOmN6lywEWdzKT3eaLPbOp0b/9DaN7CLBJ/QIR5GhGsMNpeI30zU0YzFeYFxoVoJ/LqFw==", - "cpu": [ - "riscv64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://liberapay.com/Koromix" - } - }, - "node_modules/@koromix/koffi-linux-x64": { - "version": "3.1.5", - "resolved": "https://registry.npmmirror.com/@koromix/koffi-linux-x64/-/koffi-linux-x64-3.1.5.tgz", - "integrity": "sha512-2yaIg/1V0m4CiAUMzG4CIlWmq1WJ+QBMlFfaGr9su+OH5fuIqC7V3BbMiB03IwIl1VofIZO5JA4Db4lID8tpbw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://liberapay.com/Koromix" - } - }, - "node_modules/@koromix/koffi-openbsd-ia32": { - "version": "3.1.5", - "resolved": "https://registry.npmmirror.com/@koromix/koffi-openbsd-ia32/-/koffi-openbsd-ia32-3.1.5.tgz", - "integrity": "sha512-8/OXd+u9omMooykhvdJPEP7u6FFzzrrFo9gOmSHc9/DPt3XkVYOtSsE97PDk6zYaAzwIYHSKjHvIXsfFwFc7sg==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], - "funding": { - "url": "https://liberapay.com/Koromix" - } - }, - "node_modules/@koromix/koffi-openbsd-x64": { - "version": "3.1.5", - "resolved": "https://registry.npmmirror.com/@koromix/koffi-openbsd-x64/-/koffi-openbsd-x64-3.1.5.tgz", - "integrity": "sha512-SpeqldKkuDk2aTj5PVWumy7eq6Tr2GtBPAOI1NiDHhg8xe433KraxrA9V9UjEd+1+kSGJQGR04nQByN3MPA9PQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], - "funding": { - "url": "https://liberapay.com/Koromix" - } - }, - "node_modules/@koromix/koffi-win32-arm64": { - "version": "3.1.5", - "resolved": "https://registry.npmmirror.com/@koromix/koffi-win32-arm64/-/koffi-win32-arm64-3.1.5.tgz", - "integrity": "sha512-uej3YAEKAhlfVPoIo5sOwtxhTLRVJ01LgtWrKGpnnAQU3C+Ilmaxdh+Oc2xc1G3NK30N5eCVJpyO9r3pjKC6Vw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "funding": { - "url": "https://liberapay.com/Koromix" - } - }, - "node_modules/@koromix/koffi-win32-ia32": { - "version": "3.1.5", - "resolved": "https://registry.npmmirror.com/@koromix/koffi-win32-ia32/-/koffi-win32-ia32-3.1.5.tgz", - "integrity": "sha512-d42jv2f4PwtJGNJS19Xfn/BRtGsBNNVkw0O0K5tkIGI+yNq4MnPTSUsaGbDIkCLNsCgk/LFqAaE8BExyCdrujA==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "funding": { - "url": "https://liberapay.com/Koromix" - } - }, - "node_modules/@koromix/koffi-win32-x64": { - "version": "3.1.5", - "resolved": "https://registry.npmmirror.com/@koromix/koffi-win32-x64/-/koffi-win32-x64-3.1.5.tgz", - "integrity": "sha512-Pyo1WEHEP6Ek2NEn2pquwJzSPLOdY4vymoPSz0an1DgvFWSkOyBYYkGVoxL1ajfj5I1pPdXysYqixtVTzAtOfQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "funding": { - "url": "https://liberapay.com/Koromix" - } - }, - "node_modules/@mistralai/mistralai": { - "version": "2.2.6", - "resolved": "https://registry.npmmirror.com/@mistralai/mistralai/-/mistralai-2.2.6.tgz", - "integrity": "sha512-W8pX7zHxjJvMIpw8JMxeJEleapXX0Q9NPszdNzqkM3MIEoIGPObdodujj+WHteXEvGfaP/AMwlNyRfEzSY6dQQ==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/semantic-conventions": "^1.40.0", - "ws": "^8.18.0", - "zod": "^3.25.0 || ^4.0.0", - "zod-to-json-schema": "^3.25.0" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.9.0" - }, - "peerDependenciesMeta": { - "@opentelemetry/api": { - "optional": true - } - } - }, - "node_modules/@mixmark-io/domino": { - "version": "2.2.0", - "resolved": "https://registry.npmmirror.com/@mixmark-io/domino/-/domino-2.2.0.tgz", - "integrity": "sha512-Y28PR25bHXUg88kCV7nivXrP2Nj2RueZ3/l/jdx6J9f8J4nsEGcgX0Qe6lt7Pa+J79+kPiJU3LguR6O/6zrLOw==", - "dev": true, - "license": "BSD-2-Clause" - }, - "node_modules/@modelcontextprotocol/sdk": { - "version": "1.30.0", - "resolved": "https://registry.npmmirror.com/@modelcontextprotocol/sdk/-/sdk-1.30.0.tgz", - "integrity": "sha512-xKd8OIzlqNzcqcNumGAa6g+PW2kjD5vrpcKOnfldAUPP3j7lnqMPwlTXQm8gF+UwH72z0lqaRbjr9hqGz0eITA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@hono/node-server": "^1.19.9 || ^2.0.5", - "ajv": "^8.17.1", - "ajv-formats": "^3.0.1", - "content-type": "^1.0.5", - "cors": "^2.8.5", - "cross-spawn": "^7.0.5", - "eventsource": "^3.0.2", - "eventsource-parser": "^3.0.0", - "express": "^5.2.1", - "express-rate-limit": "^8.2.1", - "hono": "^4.11.4", - "jose": "^6.1.3", - "json-schema-typed": "^8.0.2", - "pkce-challenge": "^5.0.0", - "raw-body": "^3.0.0", - "zod": "^3.25 || ^4.0", - "zod-to-json-schema": "^3.25.1" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "@cfworker/json-schema": "^4.1.1", - "zod": "^3.25 || ^4.0" - }, - "peerDependenciesMeta": { - "@cfworker/json-schema": { - "optional": true - }, - "zod": { - "optional": false - } - } - }, - "node_modules/@opentelemetry/api": { - "version": "1.9.1", - "resolved": "https://registry.npmmirror.com/@opentelemetry/api/-/api-1.9.1.tgz", - "integrity": "sha512-gLyJlPHPZYdAk1JENA9LeHejZe1Ti77/pTeFm/nMXmQH/HFZlcS/O2XJB+L8fkbrNSqhdtlvjBVjxwUYanNH5Q==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/@opentelemetry/api-logs": { - "version": "0.220.0", - "resolved": "https://registry.npmmirror.com/@opentelemetry/api-logs/-/api-logs-0.220.0.tgz", - "integrity": "sha512-CmVa4ImJ+ynfrPMNaAXHET6Bhb44SwzmfyVJFq9ni2jgXJR/l7C6gfVFddNmHP+ZOkP9cf4f9DBe68qVLTHc9w==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/api": "^1.3.0" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/@opentelemetry/core": { - "version": "2.9.0", - "resolved": "https://registry.npmmirror.com/@opentelemetry/core/-/core-2.9.0.tgz", - "integrity": "sha512-m2nckMT80NnmjTYSPjJQObBJ+8dgkoajEOUbznL8AHZ3T3yHRk2P7gI1PhEBc1+lOnrYE9UWrWHqJDsmqjmNbw==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/semantic-conventions": "^1.29.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.0.0 <1.10.0" - } - }, - "node_modules/@opentelemetry/exporter-logs-otlp-http": { - "version": "0.220.0", - "resolved": "https://registry.npmmirror.com/@opentelemetry/exporter-logs-otlp-http/-/exporter-logs-otlp-http-0.220.0.tgz", - "integrity": "sha512-8186thl+pTw64iz/qEEen5oJZoZ/gO73XruChdaGlYdWOdBIQ42r+vHLf6a7vIDqTD4b8ZOoMlyxptanECaI9A==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/api-logs": "0.220.0", - "@opentelemetry/core": "2.9.0", - "@opentelemetry/otlp-exporter-base": "0.220.0", - "@opentelemetry/otlp-transformer": "0.220.0", - "@opentelemetry/sdk-logs": "0.220.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - } - }, - "node_modules/@opentelemetry/otlp-exporter-base": { - "version": "0.220.0", - "resolved": "https://registry.npmmirror.com/@opentelemetry/otlp-exporter-base/-/otlp-exporter-base-0.220.0.tgz", - "integrity": "sha512-CXYo8UD5Mn9YbgebO2EL4wejtA+gxLmLiu6HCk2KH2BR7XhFN6/6p1UlCb23DYCjeYkndevLHuejCCN1yx4+OQ==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "2.9.0", - "@opentelemetry/otlp-transformer": "0.220.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - } - }, - "node_modules/@opentelemetry/otlp-transformer": { - "version": "0.220.0", - "resolved": "https://registry.npmmirror.com/@opentelemetry/otlp-transformer/-/otlp-transformer-0.220.0.tgz", - "integrity": "sha512-lXGrv7KXZ0gNH9SVNUaa6vv6phVYGvJxfXAlMbzbakiXru75f5MZl8Z7oqiMMQD77riVHJCFlQvbZs/VVN2/4A==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/api-logs": "0.220.0", - "@opentelemetry/core": "2.9.0", - "@opentelemetry/resources": "2.9.0", - "@opentelemetry/sdk-logs": "0.220.0", - "@opentelemetry/sdk-metrics": "2.9.0", - "@opentelemetry/sdk-trace": "2.9.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - } - }, - "node_modules/@opentelemetry/otlp-transformer/node_modules/@opentelemetry/resources": { - "version": "2.9.0", - "resolved": "https://registry.npmmirror.com/@opentelemetry/resources/-/resources-2.9.0.tgz", - "integrity": "sha512-jyA5MBLQ+Dkl3+JsZkUoUvL7yHvU64kLsvpXKarWm6347Sl1t1bXFTFykUePNpT5WH5pm9a2Qtt03iIYQhZ1Fg==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "2.9.0", - "@opentelemetry/semantic-conventions": "^1.29.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.3.0 <1.10.0" - } - }, - "node_modules/@opentelemetry/resources": { - "version": "2.10.0", - "resolved": "https://registry.npmmirror.com/@opentelemetry/resources/-/resources-2.10.0.tgz", - "integrity": "sha512-q6MMm2zhggzsHVNbabYwut+a6nbuQQe3URUoxaojM/8K1IBfwwPzvxIjNi2/lI1TFe+fMHMW9MWhrtDLEXEnkA==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "2.10.0", - "@opentelemetry/semantic-conventions": "^1.29.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.3.0 <1.10.0" - } - }, - "node_modules/@opentelemetry/resources/node_modules/@opentelemetry/core": { - "version": "2.10.0", - "resolved": "https://registry.npmmirror.com/@opentelemetry/core/-/core-2.10.0.tgz", - "integrity": "sha512-/wNZ8twnEQQA4HoHu22+vcsdru6pWPWxW+7w+FlxT6Id7PE/WIbZmVKkte+PF72e0F2dnImFeHD2syyE1Mw6MQ==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/semantic-conventions": "^1.29.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.0.0 <1.10.0" - } - }, - "node_modules/@opentelemetry/sdk-logs": { - "version": "0.220.0", - "resolved": "https://registry.npmmirror.com/@opentelemetry/sdk-logs/-/sdk-logs-0.220.0.tgz", - "integrity": "sha512-WywcTkQtv2iNmt+6y5Kcd4rzvx9bLVsBa2Nwcmg01IUaBTkTow3W4d9KE5vNBpEDtb9tp21WcRBY/lANRrApYA==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/api-logs": "0.220.0", - "@opentelemetry/core": "2.9.0", - "@opentelemetry/resources": "2.9.0", - "@opentelemetry/semantic-conventions": "^1.29.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.4.0 <1.10.0" - } - }, - "node_modules/@opentelemetry/sdk-logs/node_modules/@opentelemetry/resources": { - "version": "2.9.0", - "resolved": "https://registry.npmmirror.com/@opentelemetry/resources/-/resources-2.9.0.tgz", - "integrity": "sha512-jyA5MBLQ+Dkl3+JsZkUoUvL7yHvU64kLsvpXKarWm6347Sl1t1bXFTFykUePNpT5WH5pm9a2Qtt03iIYQhZ1Fg==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "2.9.0", - "@opentelemetry/semantic-conventions": "^1.29.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.3.0 <1.10.0" - } - }, - "node_modules/@opentelemetry/sdk-metrics": { - "version": "2.9.0", - "resolved": "https://registry.npmmirror.com/@opentelemetry/sdk-metrics/-/sdk-metrics-2.9.0.tgz", - "integrity": "sha512-Xx8RGS4H5XEBl01WuCreMIpiah9cCXMbSkeuIePPdD2cUpq/vUzYmj8E/MK1OsbOc93FuAD4jfn2WOacKwLn7Q==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "2.9.0", - "@opentelemetry/resources": "2.9.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.9.0 <1.10.0" - } - }, - "node_modules/@opentelemetry/sdk-metrics/node_modules/@opentelemetry/resources": { - "version": "2.9.0", - "resolved": "https://registry.npmmirror.com/@opentelemetry/resources/-/resources-2.9.0.tgz", - "integrity": "sha512-jyA5MBLQ+Dkl3+JsZkUoUvL7yHvU64kLsvpXKarWm6347Sl1t1bXFTFykUePNpT5WH5pm9a2Qtt03iIYQhZ1Fg==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "2.9.0", - "@opentelemetry/semantic-conventions": "^1.29.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.3.0 <1.10.0" - } - }, - "node_modules/@opentelemetry/sdk-trace": { - "version": "2.9.0", - "resolved": "https://registry.npmmirror.com/@opentelemetry/sdk-trace/-/sdk-trace-2.9.0.tgz", - "integrity": "sha512-sGA19HvtrrSKYsseHphluH6j3p6Xa3fqc7c7y8f/7mYWejc1lyDFcpSdD1kYa50HCLUeEo4zA5bW0pniaPszuw==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "2.9.0", - "@opentelemetry/resources": "2.9.0", - "@opentelemetry/semantic-conventions": "^1.29.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.3.0 <1.10.0" - } - }, - "node_modules/@opentelemetry/sdk-trace/node_modules/@opentelemetry/resources": { - "version": "2.9.0", - "resolved": "https://registry.npmmirror.com/@opentelemetry/resources/-/resources-2.9.0.tgz", - "integrity": "sha512-jyA5MBLQ+Dkl3+JsZkUoUvL7yHvU64kLsvpXKarWm6347Sl1t1bXFTFykUePNpT5WH5pm9a2Qtt03iIYQhZ1Fg==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "2.9.0", - "@opentelemetry/semantic-conventions": "^1.29.0" - }, - "engines": { - "node": "^18.19.0 || >=20.6.0" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.3.0 <1.10.0" - } - }, - "node_modules/@opentelemetry/semantic-conventions": { - "version": "1.43.0", - "resolved": "https://registry.npmmirror.com/@opentelemetry/semantic-conventions/-/semantic-conventions-1.43.0.tgz", - "integrity": "sha512-eSYWTm620tTk45EKSedaUL8MFYI8hW164hIXsgIHyxu3VobUB3fFCu5t0hQby6OoWRPsG1KkKUG2M5UadiLiVg==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=14" - } - }, - "node_modules/@protobufjs/aspromise": { - "version": "1.1.2", - "resolved": "https://registry.npmmirror.com/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", - "integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==", - "dev": true, - "license": "BSD-3-Clause" - }, - "node_modules/@protobufjs/base64": { - "version": "1.1.2", - "resolved": "https://registry.npmmirror.com/@protobufjs/base64/-/base64-1.1.2.tgz", - "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==", - "dev": true, - "license": "BSD-3-Clause" - }, - "node_modules/@protobufjs/codegen": { - "version": "2.0.5", - "resolved": "https://registry.npmmirror.com/@protobufjs/codegen/-/codegen-2.0.5.tgz", - "integrity": "sha512-zgXFLzW3Ap33e6d0Wlj4MGIm6Ce8O89n/apUaGNB/jx+hw+ruWEp7EwGUshdLKVRCxZW12fp9r40E1mQrf/34g==", - "dev": true, - "license": "BSD-3-Clause" - }, - "node_modules/@protobufjs/eventemitter": { - "version": "1.1.1", - "resolved": "https://registry.npmmirror.com/@protobufjs/eventemitter/-/eventemitter-1.1.1.tgz", - "integrity": "sha512-vW1GmwMZNnL+gMRaovlh9yZX74kc+TTU3FObkkurpMaRtBfLP3ldjS9KQWlwZgraRE0+dheEEoAxdzcJQ8eXZg==", - "dev": true, - "license": "BSD-3-Clause" - }, - "node_modules/@protobufjs/fetch": { - "version": "1.1.1", - "resolved": "https://registry.npmmirror.com/@protobufjs/fetch/-/fetch-1.1.1.tgz", - "integrity": "sha512-GpptLrs57adMSuHi3VNj0mAF8dwh36LMaYF6XyJ6JMWlVsc+t42tm1HSEDmOs3A8fC9yyeisgLhsTVQokOZ0zw==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "@protobufjs/aspromise": "^1.1.1" - } - }, - "node_modules/@protobufjs/float": { - "version": "1.0.2", - "resolved": "https://registry.npmmirror.com/@protobufjs/float/-/float-1.0.2.tgz", - "integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==", - "dev": true, - "license": "BSD-3-Clause" - }, - "node_modules/@protobufjs/path": { - "version": "1.1.2", - "resolved": "https://registry.npmmirror.com/@protobufjs/path/-/path-1.1.2.tgz", - "integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==", - "dev": true, - "license": "BSD-3-Clause" - }, - "node_modules/@protobufjs/pool": { - "version": "1.1.0", - "resolved": "https://registry.npmmirror.com/@protobufjs/pool/-/pool-1.1.0.tgz", - "integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==", - "dev": true, - "license": "BSD-3-Clause" - }, - "node_modules/@protobufjs/utf8": { - "version": "1.1.2", - "resolved": "https://registry.npmmirror.com/@protobufjs/utf8/-/utf8-1.1.2.tgz", - "integrity": "sha512-b1UQwcEZ4yCnMCD8DAL1VlbvBJE9/IX4FTIp7BG1xYpf29SLazLSrqUkj4w7Y5y7cCVP6E5tcqqcI0xemPkHug==", - "dev": true, - "license": "BSD-3-Clause" - }, - "node_modules/@smithy/core": { - "version": "3.33.2", - "resolved": "https://registry.npmmirror.com/@smithy/core/-/core-3.33.2.tgz", - "integrity": "sha512-CUGXpnPkVdjUCbix+83sWLW9VFgQOm44MDOx/ihITJMAnOZKvL8YYIc7DR9pP/tZ8CIRvMiON/TucvygqbHO3w==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@smithy/types": "^4.17.2", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/credential-provider-imds": { - "version": "4.5.2", - "resolved": "https://registry.npmmirror.com/@smithy/credential-provider-imds/-/credential-provider-imds-4.5.2.tgz", - "integrity": "sha512-A9uSdn72ozbRUSit0eib0TW7nXuNPlaeM0zcGkJ+nE6tFcSDbnmtwoxbTCFBukVQcszDAyvsd7+rTduPTXpygg==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@smithy/core": "^3.33.2", - "@smithy/types": "^4.17.2", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/fetch-http-handler": { - "version": "5.7.2", - "resolved": "https://registry.npmmirror.com/@smithy/fetch-http-handler/-/fetch-http-handler-5.7.2.tgz", - "integrity": "sha512-nZyWTmSpJEXl6VtWVMBJve/7x12DZu6sIX1z1a+ZMaHlQQRs9Zpu6NbTe/gmxYXVRpkjxyDYpZ5gx2IM6f/Wkw==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@smithy/core": "^3.33.2", - "@smithy/types": "^4.17.2", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/is-array-buffer": { - "version": "2.2.0", - "resolved": "https://registry.npmmirror.com/@smithy/is-array-buffer/-/is-array-buffer-2.2.0.tgz", - "integrity": "sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@smithy/node-http-handler": { - "version": "4.7.3", - "resolved": "https://registry.npmmirror.com/@smithy/node-http-handler/-/node-http-handler-4.7.3.tgz", - "integrity": "sha512-/jPhevcTFPMVl6KNjbaI47iOg1zxC7IsnX4PQDGVZKMFceOXtB8IEYaB7a9VvkP/3oC60WzTeKocvSI7vLT0vA==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@smithy/core": "^3.24.3", - "@smithy/types": "^4.14.2", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/signature-v4": { - "version": "5.7.2", - "resolved": "https://registry.npmmirror.com/@smithy/signature-v4/-/signature-v4-5.7.2.tgz", - "integrity": "sha512-P7Ki6px6OOrxVtx8K7nLmyx4SlXUW/uTKDdMG44UHefmPGSRMBKe2v+TM59WdLcpUIrBrnuCsIqiM2MbsZjmhw==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@smithy/core": "^3.33.2", - "@smithy/types": "^4.17.2", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/types": { - "version": "4.17.2", - "resolved": "https://registry.npmmirror.com/@smithy/types/-/types-4.17.2.tgz", - "integrity": "sha512-FOKpVZob9MPTn2znRzGrnsMHv7BOsKVw3XiP/cOyYLDVZ9qKp4nifIiSCuUU/fIj5Vu0UOAxCFr+qRAtG0NUkA==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/util-buffer-from": { - "version": "2.2.0", - "resolved": "https://registry.npmmirror.com/@smithy/util-buffer-from/-/util-buffer-from-2.2.0.tgz", - "integrity": "sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@smithy/is-array-buffer": "^2.2.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@smithy/util-utf8": { - "version": "2.3.0", - "resolved": "https://registry.npmmirror.com/@smithy/util-utf8/-/util-utf8-2.3.0.tgz", - "integrity": "sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@smithy/util-buffer-from": "^2.2.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@standard-schema/spec": { - "version": "1.1.0", - "resolved": "https://registry.npmmirror.com/@standard-schema/spec/-/spec-1.1.0.tgz", - "integrity": "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==", - "license": "MIT" - }, - "node_modules/@tanstack/virtual-core": { - "version": "3.17.8", - "resolved": "https://registry.npmmirror.com/@tanstack/virtual-core/-/virtual-core-3.17.8.tgz", - "integrity": "sha512-BfEvehNpOT75r5Ksc5xW6NZuXujTfb7nlSEyVu4XHG3gdxNg1KqXruWbDewXOUaUYIo4oRbSfkjIajz4MAT8tA==", - "dev": true, - "license": "MIT", - "funding": { - "type": "github", - "url": "https://github.com/sponsors/tannerlinsley" - } - }, - "node_modules/@types/node": { - "version": "26.2.0", - "resolved": "https://registry.npmmirror.com/@types/node/-/node-26.2.0.tgz", - "integrity": "sha512-5IviulTZeRNp2vAJ514cc/HUlY5nZ9fCbq9DMyC52BrhFZACo3nI0R7qBxhQmo/d27NFe96ur/b7Wwxklda+kg==", - "dev": true, - "license": "MIT", - "dependencies": { - "undici-types": "~8.3.0" - } - }, - "node_modules/@types/retry": { - "version": "0.12.0", - "resolved": "https://registry.npmmirror.com/@types/retry/-/retry-0.12.0.tgz", - "integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@vscode/ripgrep": { - "version": "1.18.0", - "resolved": "https://registry.npmmirror.com/@vscode/ripgrep/-/ripgrep-1.18.0.tgz", - "integrity": "sha512-ns5lWe44tSfbTMbVUsyB+I1819PVSw4AdpgK0RNkzfWfwy6+3IUNSxwSrfTno1/oWaS/hERNz+XLWVyga2aJBQ==", - "dev": true, - "license": "MIT", - "optionalDependencies": { - "@vscode/ripgrep-darwin-arm64": "1.18.0", - "@vscode/ripgrep-darwin-x64": "1.18.0", - "@vscode/ripgrep-linux-arm": "1.18.0", - "@vscode/ripgrep-linux-arm64": "1.18.0", - "@vscode/ripgrep-linux-ia32": "1.18.0", - "@vscode/ripgrep-linux-ppc64": "1.18.0", - "@vscode/ripgrep-linux-riscv64": "1.18.0", - "@vscode/ripgrep-linux-s390x": "1.18.0", - "@vscode/ripgrep-linux-x64": "1.18.0", - "@vscode/ripgrep-win32-arm64": "1.18.0", - "@vscode/ripgrep-win32-ia32": "1.18.0", - "@vscode/ripgrep-win32-x64": "1.18.0" - } - }, - "node_modules/@vscode/ripgrep-darwin-arm64": { - "version": "1.18.0", - "resolved": "https://registry.npmmirror.com/@vscode/ripgrep-darwin-arm64/-/ripgrep-darwin-arm64-1.18.0.tgz", - "integrity": "sha512-r3ktHSvbFycQNF6sl7sNDPocpsI7J+mEzh1IaZFkY0spm3k2Z9t8hPAeOK7+p0l6p6/swkQC14XWX01low+94Q==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@vscode/ripgrep-darwin-x64": { - "version": "1.18.0", - "resolved": "https://registry.npmmirror.com/@vscode/ripgrep-darwin-x64/-/ripgrep-darwin-x64-1.18.0.tgz", - "integrity": "sha512-25b4gWbL138dGuQU244ebCKKc0q05ULBMoFSz9oAEUHNeqK/lOJViDS7DRvbDazzAzSEdan391Znks/R5mkaTQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@vscode/ripgrep-linux-arm": { - "version": "1.18.0", - "resolved": "https://registry.npmmirror.com/@vscode/ripgrep-linux-arm/-/ripgrep-linux-arm-1.18.0.tgz", - "integrity": "sha512-GDAvufNDHu8zqLEmXstalQF0Wh6wQvdsBi/Vg3Yi3CK4a8XoFXqqXVEHEZ9xQz3t0NfoSEc9JbvK9DDS6FxyxQ==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@vscode/ripgrep-linux-arm64": { - "version": "1.18.0", - "resolved": "https://registry.npmmirror.com/@vscode/ripgrep-linux-arm64/-/ripgrep-linux-arm64-1.18.0.tgz", - "integrity": "sha512-lQ/5zTG++U0E3IhVgS4EPTTn/U4okncaRMM5GOFfOYZywS4nuD31GhkHbNYlDk5CuDC68+hYJ0/eQeyCKJDA+g==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@vscode/ripgrep-linux-ia32": { - "version": "1.18.0", - "resolved": "https://registry.npmmirror.com/@vscode/ripgrep-linux-ia32/-/ripgrep-linux-ia32-1.18.0.tgz", - "integrity": "sha512-YWLkSUtFd4Jh5EepIhA9RJSfv3uMAVMo+2rBIGHPBnvgLrZciIs2cDKei1/p6Wc/aCzUoHyMAg2R6tw4ZCBKGg==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@vscode/ripgrep-linux-ppc64": { - "version": "1.18.0", - "resolved": "https://registry.npmmirror.com/@vscode/ripgrep-linux-ppc64/-/ripgrep-linux-ppc64-1.18.0.tgz", - "integrity": "sha512-quXVY8fwQ8O/lvU1yrSqSl3jlUzysRSb+AfUfCL/tRtphxsKlFvPAejryZ6vg4Bgvn8XL74xb4qMCDmWgYrT5w==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@vscode/ripgrep-linux-riscv64": { - "version": "1.18.0", - "resolved": "https://registry.npmmirror.com/@vscode/ripgrep-linux-riscv64/-/ripgrep-linux-riscv64-1.18.0.tgz", - "integrity": "sha512-f5kBQBrWfQt8Q7OhSORuNDei5dkYagBj3y4jImSUXGMy8B/Ke7SltSRcUtjPv166FAFfHCAmWuZp3+cWnX2/Vw==", - "cpu": [ - "riscv64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@vscode/ripgrep-linux-s390x": { - "version": "1.18.0", - "resolved": "https://registry.npmmirror.com/@vscode/ripgrep-linux-s390x/-/ripgrep-linux-s390x-1.18.0.tgz", - "integrity": "sha512-rTOcJFGGcl2c07RUOWUo4U1ndnemKhY6A9hnMB18uk7jSgJc0d/QLBGWMWpumdtoJtpizn/wIv5mXIisJukusQ==", - "cpu": [ - "s390x" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@vscode/ripgrep-linux-x64": { - "version": "1.18.0", - "resolved": "https://registry.npmmirror.com/@vscode/ripgrep-linux-x64/-/ripgrep-linux-x64-1.18.0.tgz", - "integrity": "sha512-mQ3bVrUpnD2vs7QT0vX90Lt0cnUq467uFtEktIdsJJmW296RoSULRGqWgzG1AKxyBpNDD6l4ZO4qKf6SgyC23Q==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@vscode/ripgrep-win32-arm64": { - "version": "1.18.0", - "resolved": "https://registry.npmmirror.com/@vscode/ripgrep-win32-arm64/-/ripgrep-win32-arm64-1.18.0.tgz", - "integrity": "sha512-vfTIjq1OHnzUjxZcHVQAMbnggp8dpGf+0QKFOZHwWPqFwXxQC8eCWM+5NUdoJ6yrElCeMzoUTXoK/LdZaniB+Q==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@vscode/ripgrep-win32-ia32": { - "version": "1.18.0", - "resolved": "https://registry.npmmirror.com/@vscode/ripgrep-win32-ia32/-/ripgrep-win32-ia32-1.18.0.tgz", - "integrity": "sha512-//rfAE+BOw5AC2EMmepmiE36jUuevtQYNQqqlw1s3m9FlRxjxEut97RkRPHAu9BG4mSojatZx+kXZXNdyI9caQ==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@vscode/ripgrep-win32-x64": { - "version": "1.18.0", - "resolved": "https://registry.npmmirror.com/@vscode/ripgrep-win32-x64/-/ripgrep-win32-x64-1.18.0.tgz", - "integrity": "sha512-KNPvtElldqILHdnAetujPaowkNbpqJy3ssIGGN6F6Kve9Qi+nNLI2DN01O83JjCEVQbCzl8Ov3QZ9Eov3BR8Dg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/accepts": { - "version": "2.0.0", - "resolved": "https://registry.npmmirror.com/accepts/-/accepts-2.0.0.tgz", - "integrity": "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==", - "dev": true, - "license": "MIT", - "dependencies": { - "mime-types": "^3.0.0", - "negotiator": "^1.0.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/agent-base": { - "version": "7.1.4", - "resolved": "https://registry.npmmirror.com/agent-base/-/agent-base-7.1.4.tgz", - "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 14" - } - }, - "node_modules/ajv": { - "version": "8.20.0", - "resolved": "https://registry.npmmirror.com/ajv/-/ajv-8.20.0.tgz", - "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==", - "dev": true, - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.3", - "fast-uri": "^3.0.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/ajv-formats": { - "version": "3.0.1", - "resolved": "https://registry.npmmirror.com/ajv-formats/-/ajv-formats-3.0.1.tgz", - "integrity": "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "ajv": "^8.0.0" - }, - "peerDependencies": { - "ajv": "^8.0.0" - }, - "peerDependenciesMeta": { - "ajv": { - "optional": true - } - } - }, - "node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmmirror.com/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "devOptional": true, - "license": "Python-2.0" - }, - "node_modules/base64-js": { - "version": "1.5.1", - "resolved": "https://registry.npmmirror.com/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, - "node_modules/bignumber.js": { - "version": "9.3.1", - "resolved": "https://registry.npmmirror.com/bignumber.js/-/bignumber.js-9.3.1.tgz", - "integrity": "sha512-Ko0uX15oIUS7wJ3Rb30Fs6SkVbLmPBAKdlm7q9+ak9bbIeFf0MwuBsQV6z7+X768/cHsfg+WlysDWJcmthjsjQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": "*" - } - }, - "node_modules/body-parser": { - "version": "2.3.0", - "resolved": "https://registry.npmmirror.com/body-parser/-/body-parser-2.3.0.tgz", - "integrity": "sha512-2cGmJupaNgg+QUwVLAucDuWuoMZ6EX9iHDRswZ5lsNYEmwPaRknMPCLZz07yTzVq/83p4o/wzbDZbBrTvGGTIw==", - "dev": true, - "license": "MIT", - "dependencies": { - "bytes": "^3.1.2", - "content-type": "^2.0.0", - "debug": "^4.4.3", - "http-errors": "^2.0.1", - "iconv-lite": "^0.7.2", - "on-finished": "^2.4.1", - "qs": "^6.15.2", - "raw-body": "^3.0.2", - "type-is": "^2.1.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/body-parser/node_modules/content-type": { - "version": "2.1.0", - "resolved": "https://registry.npmmirror.com/content-type/-/content-type-2.1.0.tgz", - "integrity": "sha512-mj7UPXE0jaqaOsukNZRUEfEi2AcL7C/vwmwcHV0O97eO1E1pxBZuyjlZrx5seTaNBg1U6+o35wpa35Qfcc+7ag==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/bowser": { - "version": "2.14.1", - "resolved": "https://registry.npmmirror.com/bowser/-/bowser-2.14.1.tgz", - "integrity": "sha512-tzPjzCxygAKWFOJP011oxFHs57HzIhOEracIgAePE4pqB3LikALKnSzUyU4MGs9/iCEUuHlAJTjTc5M+u7YEGg==", - "dev": true, - "license": "MIT" - }, - "node_modules/buffer-equal-constant-time": { - "version": "1.0.1", - "resolved": "https://registry.npmmirror.com/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", - "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==", - "dev": true, - "license": "BSD-3-Clause" - }, - "node_modules/bundle-name": { - "version": "4.1.0", - "resolved": "https://registry.npmmirror.com/bundle-name/-/bundle-name-4.1.0.tgz", - "integrity": "sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "run-applescript": "^7.0.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/bytes": { - "version": "3.1.2", - "resolved": "https://registry.npmmirror.com/bytes/-/bytes-3.1.2.tgz", - "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/call-bind-apply-helpers": { - "version": "1.0.2", - "resolved": "https://registry.npmmirror.com/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", - "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "function-bind": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/call-bound": { - "version": "1.0.4", - "resolved": "https://registry.npmmirror.com/call-bound/-/call-bound-1.0.4.tgz", - "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind-apply-helpers": "^1.0.2", - "get-intrinsic": "^1.3.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/chokidar": { - "version": "4.0.3", - "resolved": "https://registry.npmmirror.com/chokidar/-/chokidar-4.0.3.tgz", - "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", - "dev": true, - "license": "MIT", - "dependencies": { - "readdirp": "^4.0.1" - }, - "engines": { - "node": ">= 14.16.0" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/clsx": { - "version": "2.1.1", - "resolved": "https://registry.npmmirror.com/clsx/-/clsx-2.1.1.tgz", - "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/commander": { - "version": "15.0.0", - "resolved": "https://registry.npmmirror.com/commander/-/commander-15.0.0.tgz", - "integrity": "sha512-z67u4ZhzCL/Tydu1lJARtEZYWbWaN7oYLHbsuzocr6y4N6WZAagG3RQ4FW61V1/0+jImpj293XfrcYnd1qxtPg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=22.12.0" - } - }, - "node_modules/content-disposition": { - "version": "1.1.0", - "resolved": "https://registry.npmmirror.com/content-disposition/-/content-disposition-1.1.0.tgz", - "integrity": "sha512-5jRCH9Z/+DRP7rkvY83B+yGIGX96OYdJmzngqnw2SBSxqCFPd0w2km3s5iawpGX8krnwSGmF0FW5Nhr0Hfai3g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/content-type": { - "version": "1.0.5", - "resolved": "https://registry.npmmirror.com/content-type/-/content-type-1.0.5.tgz", - "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/cookie": { - "version": "0.7.2", - "resolved": "https://registry.npmmirror.com/cookie/-/cookie-0.7.2.tgz", - "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/cookie-signature": { - "version": "1.2.2", - "resolved": "https://registry.npmmirror.com/cookie-signature/-/cookie-signature-1.2.2.tgz", - "integrity": "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.6.0" - } - }, - "node_modules/cors": { - "version": "2.8.6", - "resolved": "https://registry.npmmirror.com/cors/-/cors-2.8.6.tgz", - "integrity": "sha512-tJtZBBHA6vjIAaF6EnIaq6laBBP9aq/Y3ouVJjEfoHbRBcHBAHYcMh/w8LDrk2PvIMMq8gmopa5D4V8RmbrxGw==", - "dev": true, - "license": "MIT", - "dependencies": { - "object-assign": "^4", - "vary": "^1" - }, - "engines": { - "node": ">= 0.10" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/cross-spawn": { - "version": "7.0.6", - "resolved": "https://registry.npmmirror.com/cross-spawn/-/cross-spawn-7.0.6.tgz", - "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", - "dev": true, - "license": "MIT", - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/data-uri-to-buffer": { - "version": "4.0.1", - "resolved": "https://registry.npmmirror.com/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz", - "integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 12" - } - }, - "node_modules/debug": { - "version": "4.4.3", - "resolved": "https://registry.npmmirror.com/debug/-/debug-4.4.3.tgz", - "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", - "dev": true, - "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/default-browser": { - "version": "5.5.1", - "resolved": "https://registry.npmmirror.com/default-browser/-/default-browser-5.5.1.tgz", - "integrity": "sha512-m1pAzaJgZ/gssEqlOhJkPJp8Xly7QyW6xcrkUa2KKcDeDSEMP7X8xipU3snUcfisTQx0w1AGae+9UtJSfVnXGw==", - "dev": true, - "license": "MIT", - "dependencies": { - "bundle-name": "^4.1.0", - "default-browser-id": "^5.0.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/default-browser-id": { - "version": "5.0.1", - "resolved": "https://registry.npmmirror.com/default-browser-id/-/default-browser-id-5.0.1.tgz", - "integrity": "sha512-x1VCxdX4t+8wVfd1so/9w+vQ4vx7lKd2Qp5tDRutErwmR85OgmfX7RlLRMWafRMY7hbEiXIbudNrjOAPa/hL8Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/define-lazy-prop": { - "version": "3.0.0", - "resolved": "https://registry.npmmirror.com/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz", - "integrity": "sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/depd": { - "version": "2.0.0", - "resolved": "https://registry.npmmirror.com/depd/-/depd-2.0.0.tgz", - "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/detect-libc": { - "version": "2.1.2", - "resolved": "https://registry.npmmirror.com/detect-libc/-/detect-libc-2.1.2.tgz", - "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=8" - } - }, - "node_modules/diff": { - "version": "9.0.0", - "resolved": "https://registry.npmmirror.com/diff/-/diff-9.0.0.tgz", - "integrity": "sha512-svtcdpS8CgJyqAjEQIXdb3OjhFVVYjzGAPO8WGCmRbrml64SPw/jJD4GoE98aR7r25A0XcgrK3F02yw9R/vhQw==", - "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.3.1" - } - }, - "node_modules/dunder-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmmirror.com/dunder-proto/-/dunder-proto-1.0.1.tgz", - "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind-apply-helpers": "^1.0.1", - "es-errors": "^1.3.0", - "gopd": "^1.2.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/ecdsa-sig-formatter": { - "version": "1.0.11", - "resolved": "https://registry.npmmirror.com/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", - "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "safe-buffer": "^5.0.1" - } - }, - "node_modules/ee-first": { - "version": "1.1.1", - "resolved": "https://registry.npmmirror.com/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", - "dev": true, - "license": "MIT" - }, - "node_modules/encodeurl": { - "version": "2.0.0", - "resolved": "https://registry.npmmirror.com/encodeurl/-/encodeurl-2.0.0.tgz", - "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/es-define-property": { - "version": "1.0.1", - "resolved": "https://registry.npmmirror.com/es-define-property/-/es-define-property-1.0.1.tgz", - "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-errors": { - "version": "1.3.0", - "resolved": "https://registry.npmmirror.com/es-errors/-/es-errors-1.3.0.tgz", - "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-object-atoms": { - "version": "1.1.2", - "resolved": "https://registry.npmmirror.com/es-object-atoms/-/es-object-atoms-1.1.2.tgz", - "integrity": "sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw==", - "dev": true, - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/escape-html": { - "version": "1.0.3", - "resolved": "https://registry.npmmirror.com/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", - "dev": true, - "license": "MIT" - }, - "node_modules/etag": { - "version": "1.8.1", - "resolved": "https://registry.npmmirror.com/etag/-/etag-1.8.1.tgz", - "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/eventsource": { - "version": "3.0.7", - "resolved": "https://registry.npmmirror.com/eventsource/-/eventsource-3.0.7.tgz", - "integrity": "sha512-CRT1WTyuQoD771GW56XEZFQ/ZoSfWid1alKGDYMmkt2yl8UXrVR4pspqWNEcqKvVIzg6PAltWjxcSSPrboA4iA==", - "dev": true, - "license": "MIT", - "dependencies": { - "eventsource-parser": "^3.0.1" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/eventsource-parser": { - "version": "3.1.1", - "resolved": "https://registry.npmmirror.com/eventsource-parser/-/eventsource-parser-3.1.1.tgz", - "integrity": "sha512-EKN1vKAMcZ8MlYMpaNuxN6R9yakzH6uajHcHVTqWJzvu5pWw9DyhbP35HH8MVBQ+dZjAfDxk+A8NiR9KWaXiyQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/express": { - "version": "5.2.1", - "resolved": "https://registry.npmmirror.com/express/-/express-5.2.1.tgz", - "integrity": "sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==", - "dev": true, - "license": "MIT", - "dependencies": { - "accepts": "^2.0.0", - "body-parser": "^2.2.1", - "content-disposition": "^1.0.0", - "content-type": "^1.0.5", - "cookie": "^0.7.1", - "cookie-signature": "^1.2.1", - "debug": "^4.4.0", - "depd": "^2.0.0", - "encodeurl": "^2.0.0", - "escape-html": "^1.0.3", - "etag": "^1.8.1", - "finalhandler": "^2.1.0", - "fresh": "^2.0.0", - "http-errors": "^2.0.0", - "merge-descriptors": "^2.0.0", - "mime-types": "^3.0.0", - "on-finished": "^2.4.1", - "once": "^1.4.0", - "parseurl": "^1.3.3", - "proxy-addr": "^2.0.7", - "qs": "^6.14.0", - "range-parser": "^1.2.1", - "router": "^2.2.0", - "send": "^1.1.0", - "serve-static": "^2.2.0", - "statuses": "^2.0.1", - "type-is": "^2.0.1", - "vary": "^1.1.2" - }, - "engines": { - "node": ">= 18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/express-rate-limit": { - "version": "8.6.2", - "resolved": "https://registry.npmmirror.com/express-rate-limit/-/express-rate-limit-8.6.2.tgz", - "integrity": "sha512-YH4ru+eOJxQABscKFfRCy9R7x9QFGdezclVMwwgFFndzS2Xnm0uo6B0ABZsLhcpeptGv2qvuJVWlQr9gQZoC3A==", - "dev": true, - "license": "MIT", - "dependencies": { - "debug": "^4.4.3", - "ip-address": "^10.2.0" - }, - "engines": { - "node": ">= 16" - }, - "funding": { - "url": "https://github.com/sponsors/express-rate-limit" - }, - "peerDependencies": { - "express": ">= 4.11" - } - }, - "node_modules/extend": { - "version": "3.0.2", - "resolved": "https://registry.npmmirror.com/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", - "dev": true, - "license": "MIT" - }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmmirror.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true, - "license": "MIT" - }, - "node_modules/fast-uri": { - "version": "3.1.5", - "resolved": "https://registry.npmmirror.com/fast-uri/-/fast-uri-3.1.5.tgz", - "integrity": "sha512-gHwA1O9LDIcKunMKhObS/HimwtehO1nPUECKAu5TpKgaO19fcWEl4bliWe1jWxVFvIXztJjjQ4L8XQ1EU9f7Jw==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/fastify" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/fastify" - } - ], - "license": "BSD-3-Clause" - }, - "node_modules/fetch-blob": { - "version": "3.2.0", - "resolved": "https://registry.npmmirror.com/fetch-blob/-/fetch-blob-3.2.0.tgz", - "integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/jimmywarting" - }, - { - "type": "paypal", - "url": "https://paypal.me/jimmywarting" - } - ], - "license": "MIT", - "dependencies": { - "node-domexception": "^1.0.0", - "web-streams-polyfill": "^3.0.3" - }, - "engines": { - "node": "^12.20 || >= 14.13" - } - }, - "node_modules/fflate": { - "version": "0.8.3", - "resolved": "https://registry.npmmirror.com/fflate/-/fflate-0.8.3.tgz", - "integrity": "sha512-tbZNuJrLwGUp3zshBtdy4W+ORxZuIh8a5ilyIEQDC5rY1f3U20JMry0Ll3WBzU58EZKsEuJFXhb5gwv8CsPvgA==", - "dev": true, - "license": "MIT" - }, - "node_modules/finalhandler": { - "version": "2.1.1", - "resolved": "https://registry.npmmirror.com/finalhandler/-/finalhandler-2.1.1.tgz", - "integrity": "sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA==", - "dev": true, - "license": "MIT", - "dependencies": { - "debug": "^4.4.0", - "encodeurl": "^2.0.0", - "escape-html": "^1.0.3", - "on-finished": "^2.4.1", - "parseurl": "^1.3.3", - "statuses": "^2.0.1" - }, - "engines": { - "node": ">= 18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/formdata-polyfill": { - "version": "4.0.10", - "resolved": "https://registry.npmmirror.com/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz", - "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==", - "dev": true, - "license": "MIT", - "dependencies": { - "fetch-blob": "^3.1.2" - }, - "engines": { - "node": ">=12.20.0" - } - }, - "node_modules/forwarded": { - "version": "0.2.0", - "resolved": "https://registry.npmmirror.com/forwarded/-/forwarded-0.2.0.tgz", - "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/fresh": { - "version": "2.0.0", - "resolved": "https://registry.npmmirror.com/fresh/-/fresh-2.0.0.tgz", - "integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/function-bind": { - "version": "1.1.2", - "resolved": "https://registry.npmmirror.com/function-bind/-/function-bind-1.1.2.tgz", - "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", - "dev": true, - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/gaxios": { - "version": "7.3.1", - "resolved": "https://registry.npmmirror.com/gaxios/-/gaxios-7.3.1.tgz", - "integrity": "sha512-kB3rzJV7d9juLZh8/56QTXCwQfxyhdOMdyYk1HdQKFtF8TJTDTZQJtixWIwXdE9Jji91mC41DUNpjleo4L4eAQ==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "extend": "^3.0.2", - "https-proxy-agent": "^7.0.1", - "node-fetch": "^3.3.2" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/gcp-metadata": { - "version": "8.1.2", - "resolved": "https://registry.npmmirror.com/gcp-metadata/-/gcp-metadata-8.1.2.tgz", - "integrity": "sha512-zV/5HKTfCeKWnxG0Dmrw51hEWFGfcF2xiXqcA3+J90WDuP0SvoiSO5ORvcBsifmx/FoIjgQN3oNOGaQ5PhLFkg==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "gaxios": "^7.0.0", - "google-logging-utils": "^1.0.0", - "json-bigint": "^1.0.0" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/get-intrinsic": { - "version": "1.3.0", - "resolved": "https://registry.npmmirror.com/get-intrinsic/-/get-intrinsic-1.3.0.tgz", - "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind-apply-helpers": "^1.0.2", - "es-define-property": "^1.0.1", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.1.1", - "function-bind": "^1.1.2", - "get-proto": "^1.0.1", - "gopd": "^1.2.0", - "has-symbols": "^1.1.0", - "hasown": "^2.0.2", - "math-intrinsics": "^1.1.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/get-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmmirror.com/get-proto/-/get-proto-1.0.1.tgz", - "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", - "dev": true, - "license": "MIT", - "dependencies": { - "dunder-proto": "^1.0.1", - "es-object-atoms": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/google-auth-library": { - "version": "10.9.1", - "resolved": "https://registry.npmmirror.com/google-auth-library/-/google-auth-library-10.9.1.tgz", - "integrity": "sha512-i1ydyHrqcIxXkWh/uBmVkzCvIuq5yiK2ATndIe5XxKholrG/MTYP9xGYka4sQhrbIAgGjL2B6NOE7rFaiF3fXw==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "base64-js": "^1.3.0", - "ecdsa-sig-formatter": "^1.0.11", - "gaxios": "^7.1.4", - "gcp-metadata": "8.1.2", - "google-logging-utils": "1.1.3", - "jws": "^4.0.0" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/google-logging-utils": { - "version": "1.1.3", - "resolved": "https://registry.npmmirror.com/google-logging-utils/-/google-logging-utils-1.1.3.tgz", - "integrity": "sha512-eAmLkjDjAFCVXg7A1unxHsLf961m6y17QFqXqAXGj/gVkKFrEICfStRfwUlGNfeCEjNRa32JEWOUTlYXPyyKvA==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=14" - } - }, - "node_modules/gopd": { - "version": "1.2.0", - "resolved": "https://registry.npmmirror.com/gopd/-/gopd-1.2.0.tgz", - "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-symbols": { - "version": "1.1.0", - "resolved": "https://registry.npmmirror.com/has-symbols/-/has-symbols-1.1.0.tgz", - "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/hasown": { - "version": "2.0.4", - "resolved": "https://registry.npmmirror.com/hasown/-/hasown-2.0.4.tgz", - "integrity": "sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==", - "dev": true, - "license": "MIT", - "dependencies": { - "function-bind": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/hono": { - "version": "4.13.3", - "resolved": "https://registry.npmmirror.com/hono/-/hono-4.13.3.tgz", - "integrity": "sha512-r8AO2mYHoLxSHkgafNeC/BXyb2vWRxD3jem4Ts+ptav8oTG5FIRifAjuJEmZI4bSvvc2ns0GxmIYiZnHqN3mMw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=16.9.0" - } - }, - "node_modules/http-errors": { - "version": "2.0.1", - "resolved": "https://registry.npmmirror.com/http-errors/-/http-errors-2.0.1.tgz", - "integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "depd": "~2.0.0", - "inherits": "~2.0.4", - "setprototypeof": "~1.2.0", - "statuses": "~2.0.2", - "toidentifier": "~1.0.1" - }, - "engines": { - "node": ">= 0.8" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/http-proxy-agent": { - "version": "7.0.2", - "resolved": "https://registry.npmmirror.com/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", - "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", - "dev": true, - "license": "MIT", - "dependencies": { - "agent-base": "^7.1.0", - "debug": "^4.3.4" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/https-proxy-agent": { - "version": "7.0.6", - "resolved": "https://registry.npmmirror.com/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", - "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", - "dev": true, - "license": "MIT", - "dependencies": { - "agent-base": "^7.1.2", - "debug": "4" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/iconv-lite": { - "version": "0.7.3", - "resolved": "https://registry.npmmirror.com/iconv-lite/-/iconv-lite-0.7.3.tgz", - "integrity": "sha512-IKXpvIzjnC9XTAUbVBcMfGS0EPaIXtW6v+zr+RRp+hqULEpo0owZax6wyRwPOJbWbzjYspQwusTsfVr0ifh4uQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - }, - "engines": { - "node": ">=0.10.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/immer": { - "version": "10.2.0", - "resolved": "https://registry.npmmirror.com/immer/-/immer-10.2.0.tgz", - "integrity": "sha512-d/+XTN3zfODyjr89gM3mPq1WNX2B8pYsu7eORitdwyA2sBubnTl3laYlBk4sXY5FUa5qTZGBDPJICVbvqzjlbw==", - "dev": true, - "license": "MIT", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/immer" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmmirror.com/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true, - "license": "ISC" - }, - "node_modules/ip-address": { - "version": "10.5.0", - "resolved": "https://registry.npmmirror.com/ip-address/-/ip-address-10.5.0.tgz", - "integrity": "sha512-R5SnVLJmgYYvf2F2ZgwSBnelz5G4q5AxIC277GDfUaNbrZKNANcBC7RHqYYePlszf4kBolVkJauG0ZjHHFh55g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 12" - } - }, - "node_modules/ipaddr.js": { - "version": "1.9.1", - "resolved": "https://registry.npmmirror.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz", - "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/is-docker": { - "version": "3.0.0", - "resolved": "https://registry.npmmirror.com/is-docker/-/is-docker-3.0.0.tgz", - "integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==", - "dev": true, - "license": "MIT", - "bin": { - "is-docker": "cli.js" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-in-ssh": { - "version": "1.0.0", - "resolved": "https://registry.npmmirror.com/is-in-ssh/-/is-in-ssh-1.0.0.tgz", - "integrity": "sha512-jYa6Q9rH90kR1vKB6NM7qqd1mge3Fx4Dhw5TVlK1MUBqhEOuCagrEHMevNuCcbECmXZ0ThXkRm+Ymr51HwEPAw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=20" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-inside-container": { - "version": "1.0.0", - "resolved": "https://registry.npmmirror.com/is-inside-container/-/is-inside-container-1.0.0.tgz", - "integrity": "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-docker": "^3.0.0" - }, - "bin": { - "is-inside-container": "cli.js" - }, - "engines": { - "node": ">=14.16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-promise": { - "version": "4.0.0", - "resolved": "https://registry.npmmirror.com/is-promise/-/is-promise-4.0.0.tgz", - "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/is-wsl": { - "version": "3.1.1", - "resolved": "https://registry.npmmirror.com/is-wsl/-/is-wsl-3.1.1.tgz", - "integrity": "sha512-e6rvdUCiQCAuumZslxRJWR/Doq4VpPR82kqclvcS0efgt430SlGIk05vdCN58+VrzgtIcfNODjozVielycD4Sw==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-inside-container": "^1.0.0" - }, - "engines": { - "node": ">=16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmmirror.com/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true, - "license": "ISC" - }, - "node_modules/jose": { - "version": "6.2.9", - "resolved": "https://registry.npmmirror.com/jose/-/jose-6.2.9.tgz", - "integrity": "sha512-XrchZOFZUl/T3vTwRe8XK+cJrGtMF4th1ARnDfwbBXFKThGhlsxEE4Zu03AD/bjJSt/9jT/mxrOCkJWOg77aPA==", - "dev": true, - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/panva" - } - }, - "node_modules/js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmmirror.com/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/js-yaml": { - "version": "4.3.1", - "resolved": "https://registry.npmmirror.com/js-yaml/-/js-yaml-4.3.1.tgz", - "integrity": "sha512-CY6crGq313MX8GkwvB7tzgp99vjQxY1++5y10/BKN/GUfHqWaOGQMNZkBvqSzsZKWk/ijwHlWzzkLulsGHhjWQ==", - "devOptional": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/puzrin" - }, - { - "type": "github", - "url": "https://github.com/sponsors/nodeca" - } - ], - "license": "MIT", - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/json-bigint": { - "version": "1.0.0", - "resolved": "https://registry.npmmirror.com/json-bigint/-/json-bigint-1.0.0.tgz", - "integrity": "sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "bignumber.js": "^9.0.0" - } - }, - "node_modules/json-schema-to-ts": { - "version": "3.1.1", - "resolved": "https://registry.npmmirror.com/json-schema-to-ts/-/json-schema-to-ts-3.1.1.tgz", - "integrity": "sha512-+DWg8jCJG2TEnpy7kOm/7/AxaYoaRbjVB4LFZLySZlWn8exGs3A4OLJR966cVvU26N7X9TWxl+Jsw7dzAqKT6g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/runtime": "^7.18.3", - "ts-algebra": "^2.0.0" - }, - "engines": { - "node": ">=16" - } - }, - "node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmmirror.com/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true, - "license": "MIT" - }, - "node_modules/json-schema-typed": { - "version": "8.0.2", - "resolved": "https://registry.npmmirror.com/json-schema-typed/-/json-schema-typed-8.0.2.tgz", - "integrity": "sha512-fQhoXdcvc3V28x7C7BMs4P5+kNlgUURe2jmUT1T//oBRMDrqy1QPelJimwZGo7Hg9VPV3EQV5Bnq4hbFy2vetA==", - "dev": true, - "license": "BSD-2-Clause" - }, - "node_modules/jwa": { - "version": "2.0.1", - "resolved": "https://registry.npmmirror.com/jwa/-/jwa-2.0.1.tgz", - "integrity": "sha512-hRF04fqJIP8Abbkq5NKGN0Bbr3JxlQ+qhZufXVr0DvujKy93ZCbXZMHDL4EOtodSbCWxOqR8MS1tXA5hwqCXDg==", - "dev": true, - "license": "MIT", - "dependencies": { - "buffer-equal-constant-time": "^1.0.1", - "ecdsa-sig-formatter": "1.0.11", - "safe-buffer": "^5.0.1" - } - }, - "node_modules/jws": { - "version": "4.0.1", - "resolved": "https://registry.npmmirror.com/jws/-/jws-4.0.1.tgz", - "integrity": "sha512-EKI/M/yqPncGUUh44xz0PxSidXFr/+r0pA70+gIYhjv+et7yxM+s29Y+VGDkovRofQem0fs7Uvf4+YmAdyRduA==", - "dev": true, - "license": "MIT", - "dependencies": { - "jwa": "^2.0.1", - "safe-buffer": "^5.0.1" - } - }, - "node_modules/koffi": { - "version": "3.1.5", - "resolved": "https://registry.npmmirror.com/koffi/-/koffi-3.1.5.tgz", - "integrity": "sha512-XVwwrxg0Ca6IEUQF4YtGIU4XN0LSselFYpYvgfhh8wafCunhEEx5hPr7LZhp5QyeFA/LcRsKHTqncCdjWjWAlg==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "funding": { - "url": "https://liberapay.com/Koromix" - }, - "optionalDependencies": { - "@koromix/koffi-darwin-arm64": "3.1.5", - "@koromix/koffi-darwin-x64": "3.1.5", - "@koromix/koffi-freebsd-arm64": "3.1.5", - "@koromix/koffi-freebsd-ia32": "3.1.5", - "@koromix/koffi-freebsd-x64": "3.1.5", - "@koromix/koffi-linux-arm64": "3.1.5", - "@koromix/koffi-linux-ia32": "3.1.5", - "@koromix/koffi-linux-loong64": "3.1.5", - "@koromix/koffi-linux-riscv64": "3.1.5", - "@koromix/koffi-linux-x64": "3.1.5", - "@koromix/koffi-openbsd-ia32": "3.1.5", - "@koromix/koffi-openbsd-x64": "3.1.5", - "@koromix/koffi-win32-arm64": "3.1.5", - "@koromix/koffi-win32-ia32": "3.1.5", - "@koromix/koffi-win32-x64": "3.1.5" - } - }, - "node_modules/long": { - "version": "5.3.2", - "resolved": "https://registry.npmmirror.com/long/-/long-5.3.2.tgz", - "integrity": "sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==", - "dev": true, - "license": "Apache-2.0" - }, - "node_modules/loose-envify": { - "version": "1.4.0", - "resolved": "https://registry.npmmirror.com/loose-envify/-/loose-envify-1.4.0.tgz", - "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "js-tokens": "^3.0.0 || ^4.0.0" - }, - "bin": { - "loose-envify": "cli.js" - } - }, - "node_modules/math-intrinsics": { - "version": "1.1.0", - "resolved": "https://registry.npmmirror.com/math-intrinsics/-/math-intrinsics-1.1.0.tgz", - "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/media-typer": { - "version": "1.1.1", - "resolved": "https://registry.npmmirror.com/media-typer/-/media-typer-1.1.1.tgz", - "integrity": "sha512-yz3xRaG20c6/BOzvYoDaGtPmGscs7YivItZEEqe6GbwNfHuxu9YNmvnEkMzKldAGY4/80pRcQRZSEnhquk9XuQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/merge-descriptors": { - "version": "2.0.0", - "resolved": "https://registry.npmmirror.com/merge-descriptors/-/merge-descriptors-2.0.0.tgz", - "integrity": "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/mime-db": { - "version": "1.54.0", - "resolved": "https://registry.npmmirror.com/mime-db/-/mime-db-1.54.0.tgz", - "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mime-types": { - "version": "3.0.2", - "resolved": "https://registry.npmmirror.com/mime-types/-/mime-types-3.0.2.tgz", - "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==", - "dev": true, - "license": "MIT", - "dependencies": { - "mime-db": "^1.54.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmmirror.com/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true, - "license": "MIT" - }, - "node_modules/negotiator": { - "version": "1.0.0", - "resolved": "https://registry.npmmirror.com/negotiator/-/negotiator-1.0.0.tgz", - "integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/node-addon-api": { - "version": "7.1.1", - "resolved": "https://registry.npmmirror.com/node-addon-api/-/node-addon-api-7.1.1.tgz", - "integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/node-addon-native-custom-loader": { - "version": "0.1.5", - "resolved": "https://registry.npmmirror.com/node-addon-native-custom-loader/-/node-addon-native-custom-loader-0.1.5.tgz", - "integrity": "sha512-rL0XXRytayIChYf1xaG9/1NzGBRTyFkQTIpn+MDz/hpr0PZw1a9PZIoH9HlYfagNawhXU+jfN650EvoSIvR7Vw==", - "devOptional": true, - "license": "MIT", - "engines": { - "node": ">=20" - } - }, - "node_modules/node-addon-require-builtin": { - "version": "0.1.5", - "resolved": "https://registry.npmmirror.com/node-addon-require-builtin/-/node-addon-require-builtin-0.1.5.tgz", - "integrity": "sha512-isaquiStlp7qdFpaffy+2ssJPUR/kLPRE5gqfeWbb0Ahph9H7O3BOFwThqkVaTrxfpnjrQauxlOEgvzD+snhUg==", - "devOptional": true, - "license": "MIT", - "dependencies": { - "node-addon-native-custom-loader": "0.1.5" - }, - "engines": { - "node": ">=20" - }, - "optionalDependencies": { - "node-addon-require-builtin-darwin-arm64": "0.1.5", - "node-addon-require-builtin-darwin-x64": "0.1.5", - "node-addon-require-builtin-linux-arm64-gnu": "0.1.5", - "node-addon-require-builtin-linux-x64-gnu": "0.1.5", - "node-addon-require-builtin-win32-arm64-msvc": "0.1.5", - "node-addon-require-builtin-win32-ia32-msvc": "0.1.5", - "node-addon-require-builtin-win32-x64-msvc": "0.1.5" - } - }, - "node_modules/node-addon-require-builtin-darwin-arm64": { - "version": "0.1.5", - "resolved": "https://registry.npmmirror.com/node-addon-require-builtin-darwin-arm64/-/node-addon-require-builtin-darwin-arm64-0.1.5.tgz", - "integrity": "sha512-MZ5RyGhuU7DTbwuNpOQW81/ep8n5Yd5YlZa6dWiEfJEh+01Dl4cCKGmMCWNgb0VtqAImRtAOtmZIPtwngiemKQ==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "dependencies": { - "node-addon-native-custom-loader": "0.1.5" - }, - "engines": { - "node": ">=20" - } - }, - "node_modules/node-addon-require-builtin-darwin-x64": { - "version": "0.1.5", - "resolved": "https://registry.npmmirror.com/node-addon-require-builtin-darwin-x64/-/node-addon-require-builtin-darwin-x64-0.1.5.tgz", - "integrity": "sha512-wdCSPn49AdNZ2EXHQqswiXk1cROFe9zSRaAX8PwQLxmjdLt+xZF7vZP6VlqgXm+VAOHv98q8kp9m7mO9jY3OgQ==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "dependencies": { - "node-addon-native-custom-loader": "0.1.5" - }, - "engines": { - "node": ">=20" - } - }, - "node_modules/node-addon-require-builtin-linux-arm64-gnu": { - "version": "0.1.5", - "resolved": "https://registry.npmmirror.com/node-addon-require-builtin-linux-arm64-gnu/-/node-addon-require-builtin-linux-arm64-gnu-0.1.5.tgz", - "integrity": "sha512-hCqzKpQiknDDv6rUdZqrxCBXROg/uUruO0geUuZsdM9M/Lds45gSb4bDE958HlPaCvrDyR0wTHl3II8A7yQeew==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "dependencies": { - "node-addon-native-custom-loader": "0.1.5" - }, - "engines": { - "node": ">=20" - } - }, - "node_modules/node-addon-require-builtin-linux-x64-gnu": { - "version": "0.1.5", - "resolved": "https://registry.npmmirror.com/node-addon-require-builtin-linux-x64-gnu/-/node-addon-require-builtin-linux-x64-gnu-0.1.5.tgz", - "integrity": "sha512-lgP+ruwWXbcXDslhp5uIc+dFgzITEGPZ4E50WdHGt/OzcoVhN6y5z72pRRvxy8DE661//QxqmCLe72rS3SVg+w==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "dependencies": { - "node-addon-native-custom-loader": "0.1.5" - }, - "engines": { - "node": ">=20" - } - }, - "node_modules/node-addon-require-builtin-win32-arm64-msvc": { - "version": "0.1.5", - "resolved": "https://registry.npmmirror.com/node-addon-require-builtin-win32-arm64-msvc/-/node-addon-require-builtin-win32-arm64-msvc-0.1.5.tgz", - "integrity": "sha512-KEO2eWS4lvZg6JmPPz04OdI4Ojrc7YzOs++4r6VnvwsqYN2r6mjGSGpouQkk8J2eLXBzC7X/D9wYTbUuQS8u1Q==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "dependencies": { - "node-addon-native-custom-loader": "0.1.5" - }, - "engines": { - "node": ">=20" - } - }, - "node_modules/node-addon-require-builtin-win32-ia32-msvc": { - "version": "0.1.5", - "resolved": "https://registry.npmmirror.com/node-addon-require-builtin-win32-ia32-msvc/-/node-addon-require-builtin-win32-ia32-msvc-0.1.5.tgz", - "integrity": "sha512-iSC988EqZm5XbKWp/giW6K6EBRTrHt/YQbAkKsZLglt7PplmvvrZ7C3tUsyh1wVxUTYAaxFdE2xbqSdpw0rb6g==", - "cpu": [ - "ia32" - ], - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "dependencies": { - "node-addon-native-custom-loader": "0.1.5" - }, - "engines": { - "node": ">=20 <23" - } - }, - "node_modules/node-addon-require-builtin-win32-x64-msvc": { - "version": "0.1.5", - "resolved": "https://registry.npmmirror.com/node-addon-require-builtin-win32-x64-msvc/-/node-addon-require-builtin-win32-x64-msvc-0.1.5.tgz", - "integrity": "sha512-pjuco/ESU3ChIp7WwacWfY2ENu2K5rGAgqjcXedoiFcTrjTf5Ln/miKSuNfE6IiuJ7tfMTJH6VH5hq+C1Y8JMQ==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "dependencies": { - "node-addon-native-custom-loader": "0.1.5" - }, - "engines": { - "node": ">=20" - } - }, - "node_modules/node-domexception": { - "version": "1.0.0", - "resolved": "https://registry.npmmirror.com/node-domexception/-/node-domexception-1.0.0.tgz", - "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==", - "deprecated": "Use your platform's native DOMException instead", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/jimmywarting" - }, - { - "type": "github", - "url": "https://paypal.me/jimmywarting" - } - ], - "license": "MIT", - "engines": { - "node": ">=10.5.0" - } - }, - "node_modules/node-fetch": { - "version": "3.3.2", - "resolved": "https://registry.npmmirror.com/node-fetch/-/node-fetch-3.3.2.tgz", - "integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==", - "dev": true, - "license": "MIT", - "dependencies": { - "data-uri-to-buffer": "^4.0.0", - "fetch-blob": "^3.1.4", - "formdata-polyfill": "^4.0.10" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/node-fetch" - } - }, - "node_modules/node-pty": { - "version": "1.2.0-beta.15", - "resolved": "https://registry.npmmirror.com/node-pty/-/node-pty-1.2.0-beta.15.tgz", - "integrity": "sha512-vORSzHXi4Ofl7HemVWpuudLqCPdaQb4LfpRCUpE5HPxhp4JYscl8zZwxh11p26v2wvW24WMwnMfLjhRLixrfxA==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "dependencies": { - "node-addon-api": "^7.1.0" - } - }, - "node_modules/object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmmirror.com/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object-inspect": { - "version": "1.13.4", - "resolved": "https://registry.npmmirror.com/object-inspect/-/object-inspect-1.13.4.tgz", - "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/on-finished": { - "version": "2.4.1", - "resolved": "https://registry.npmmirror.com/on-finished/-/on-finished-2.4.1.tgz", - "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", - "dev": true, - "license": "MIT", - "dependencies": { - "ee-first": "1.1.1" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmmirror.com/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dev": true, - "license": "ISC", - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/open": { - "version": "11.0.1", - "resolved": "https://registry.npmmirror.com/open/-/open-11.0.1.tgz", - "integrity": "sha512-NzwMUB6C1D0+Kd+9iMS/H4k+Ck3cTX6Ckyfr/gAGlmvSE1LUQZnEZvWBi4PYmMwH/S5SMeTXnE+9uAz8uF+pWw==", - "dev": true, - "license": "MIT", - "dependencies": { - "default-browser": "^5.4.0", - "define-lazy-prop": "^3.0.0", - "is-in-ssh": "^1.0.0", - "is-inside-container": "^1.0.0", - "powershell-utils": "^0.2.0", - "wsl-utils": "^1.0.0" - }, - "engines": { - "node": ">=20" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/openai": { - "version": "6.26.0", - "resolved": "https://registry.npmmirror.com/openai/-/openai-6.26.0.tgz", - "integrity": "sha512-zd23dbWTjiJ6sSAX6s0HrCZi41JwTA1bQVs0wLQPZ2/5o2gxOJA5wh7yOAUgwYybfhDXyhwlpeQf7Mlgx8EOCA==", - "dev": true, - "license": "Apache-2.0", - "bin": { - "openai": "bin/cli" - }, - "peerDependencies": { - "ws": "^8.18.0", - "zod": "^3.25 || ^4.0" - }, - "peerDependenciesMeta": { - "ws": { - "optional": true - }, - "zod": { - "optional": true - } - } - }, - "node_modules/p-retry": { - "version": "4.6.2", - "resolved": "https://registry.npmmirror.com/p-retry/-/p-retry-4.6.2.tgz", - "integrity": "sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/retry": "0.12.0", - "retry": "^0.13.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/parseurl": { - "version": "1.3.3", - "resolved": "https://registry.npmmirror.com/parseurl/-/parseurl-1.3.3.tgz", - "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/partial-json": { - "version": "0.1.7", - "resolved": "https://registry.npmmirror.com/partial-json/-/partial-json-0.1.7.tgz", - "integrity": "sha512-Njv/59hHaokb/hRUjce3Hdv12wd60MtM9Z5Olmn+nehe0QDAsRtRbJPvJ0Z91TusF0SuZRIvnM+S4l6EIP8leA==", - "dev": true, - "license": "MIT" - }, - "node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmmirror.com/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/path-to-regexp": { - "version": "8.4.2", - "resolved": "https://registry.npmmirror.com/path-to-regexp/-/path-to-regexp-8.4.2.tgz", - "integrity": "sha512-qRcuIdP69NPm4qbACK+aDogI5CBDMi1jKe0ry5rSQJz8JVLsC7jV8XpiJjGRLLol3N+R5ihGYcrPLTno6pAdBA==", - "dev": true, - "license": "MIT", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/picocolors": { - "version": "1.1.1", - "resolved": "https://registry.npmmirror.com/picocolors/-/picocolors-1.1.1.tgz", - "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", - "dev": true, - "license": "ISC" - }, - "node_modules/picomatch": { - "version": "4.0.5", - "resolved": "https://registry.npmmirror.com/picomatch/-/picomatch-4.0.5.tgz", - "integrity": "sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/pkce-challenge": { - "version": "5.0.1", - "resolved": "https://registry.npmmirror.com/pkce-challenge/-/pkce-challenge-5.0.1.tgz", - "integrity": "sha512-wQ0b/W4Fr01qtpHlqSqspcj3EhBvimsdh0KlHhH8HRZnMsEa0ea2fTULOXOS9ccQr3om+GcGRk4e+isrZWV8qQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=16.20.0" - } - }, - "node_modules/powershell-utils": { - "version": "0.2.0", - "resolved": "https://registry.npmmirror.com/powershell-utils/-/powershell-utils-0.2.0.tgz", - "integrity": "sha512-ZlsFlG7MtSFCoc5xreOvBAozCJ6Pf06opgJjh9ONEv418xpZSAzNjstD36C6+JwOnfSqOW/9uDkqKjezTdxZhw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=20" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/protobufjs": { - "version": "7.6.5", - "resolved": "https://registry.npmmirror.com/protobufjs/-/protobufjs-7.6.5.tgz", - "integrity": "sha512-/FPD0nUc9jH6rfFjji9IBqOz4pcSE3CsT1m7Ep6Mdb0LxSUMj8hgl6GomOvZzpNpAqqGaXA0P3VSrZLFzIhQrw==", - "dev": true, - "hasInstallScript": true, - "license": "BSD-3-Clause", - "dependencies": { - "@protobufjs/aspromise": "^1.1.2", - "@protobufjs/base64": "^1.1.2", - "@protobufjs/codegen": "^2.0.5", - "@protobufjs/eventemitter": "^1.1.1", - "@protobufjs/fetch": "^1.1.1", - "@protobufjs/float": "^1.0.2", - "@protobufjs/path": "^1.1.2", - "@protobufjs/pool": "^1.1.0", - "@protobufjs/utf8": "^1.1.1", - "@types/node": ">=13.7.0", - "long": "^5.3.2" - }, - "engines": { - "node": ">=12.0.0" - } - }, - "node_modules/proxy-addr": { - "version": "2.0.7", - "resolved": "https://registry.npmmirror.com/proxy-addr/-/proxy-addr-2.0.7.tgz", - "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", - "dev": true, - "license": "MIT", - "dependencies": { - "forwarded": "0.2.0", - "ipaddr.js": "1.9.1" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/qs": { - "version": "6.15.3", - "resolved": "https://registry.npmmirror.com/qs/-/qs-6.15.3.tgz", - "integrity": "sha512-O9gl3zCl5h5blw1KGUzQKhA5oUXSl8rwUIM5o0S3nCXMliSvy5Dzx7/DJcI+SwgICv+IneSZwhBh1oSyEHA71A==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "es-define-property": "^1.0.1", - "side-channel": "^1.1.1" - }, - "engines": { - "node": ">=0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/range-parser": { - "version": "1.3.0", - "resolved": "https://registry.npmmirror.com/range-parser/-/range-parser-1.3.0.tgz", - "integrity": "sha512-hek2mFQpPuI4E1BBKrSto+BU3e3x4xuarsbiwr3+lf7p44juvFMV0XFWQAP3xUyqXA4RrXLIoaSUGbSt056ZMw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.6" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/raw-body": { - "version": "3.0.2", - "resolved": "https://registry.npmmirror.com/raw-body/-/raw-body-3.0.2.tgz", - "integrity": "sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==", - "dev": true, - "license": "MIT", - "dependencies": { - "bytes": "~3.1.2", - "http-errors": "~2.0.1", - "iconv-lite": "~0.7.0", - "unpipe": "~1.0.0" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/react": { - "version": "18.3.1", - "resolved": "https://registry.npmmirror.com/react/-/react-18.3.1.tgz", - "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "loose-envify": "^1.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/readdirp": { - "version": "4.1.2", - "resolved": "https://registry.npmmirror.com/readdirp/-/readdirp-4.1.2.tgz", - "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 14.18.0" - }, - "funding": { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/require-from-string": { - "version": "2.0.2", - "resolved": "https://registry.npmmirror.com/require-from-string/-/require-from-string-2.0.2.tgz", - "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/retry": { - "version": "0.13.1", - "resolved": "https://registry.npmmirror.com/retry/-/retry-0.13.1.tgz", - "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 4" - } - }, - "node_modules/router": { - "version": "2.2.0", - "resolved": "https://registry.npmmirror.com/router/-/router-2.2.0.tgz", - "integrity": "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "debug": "^4.4.0", - "depd": "^2.0.0", - "is-promise": "^4.0.0", - "parseurl": "^1.3.3", - "path-to-regexp": "^8.0.0" - }, - "engines": { - "node": ">= 18" - } - }, - "node_modules/run-applescript": { - "version": "7.1.0", - "resolved": "https://registry.npmmirror.com/run-applescript/-/run-applescript-7.1.0.tgz", - "integrity": "sha512-DPe5pVFaAsinSaV6QjQ6gdiedWDcRCbUuiQfQa2wmWV7+xC9bGulGI8+TdRmoFkAPaBXk8CrAbnlY2ISniJ47Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmmirror.com/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, - "node_modules/safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmmirror.com/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "dev": true, - "license": "MIT" - }, - "node_modules/scheduler": { - "version": "0.27.0", - "resolved": "https://registry.npmmirror.com/scheduler/-/scheduler-0.27.0.tgz", - "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==", - "dev": true, - "license": "MIT", - "peer": true - }, - "node_modules/semver": { - "version": "7.8.5", - "resolved": "https://registry.npmmirror.com/semver/-/semver-7.8.5.tgz", - "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/send": { - "version": "1.2.1", - "resolved": "https://registry.npmmirror.com/send/-/send-1.2.1.tgz", - "integrity": "sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "debug": "^4.4.3", - "encodeurl": "^2.0.0", - "escape-html": "^1.0.3", - "etag": "^1.8.1", - "fresh": "^2.0.0", - "http-errors": "^2.0.1", - "mime-types": "^3.0.2", - "ms": "^2.1.3", - "on-finished": "^2.4.1", - "range-parser": "^1.2.1", - "statuses": "^2.0.2" - }, - "engines": { - "node": ">= 18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/serve-static": { - "version": "2.2.1", - "resolved": "https://registry.npmmirror.com/serve-static/-/serve-static-2.2.1.tgz", - "integrity": "sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw==", - "dev": true, - "license": "MIT", - "dependencies": { - "encodeurl": "^2.0.0", - "escape-html": "^1.0.3", - "parseurl": "^1.3.3", - "send": "^1.2.0" - }, - "engines": { - "node": ">= 18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/setprototypeof": { - "version": "1.2.0", - "resolved": "https://registry.npmmirror.com/setprototypeof/-/setprototypeof-1.2.0.tgz", - "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", - "dev": true, - "license": "ISC" - }, - "node_modules/sharp": { - "version": "0.35.3", - "resolved": "https://registry.npmmirror.com/sharp/-/sharp-0.35.3.tgz", - "integrity": "sha512-ej0zVHuZGHCiABXcNxeYhpRnPNPAcvbG8RMdBAhDAxLKkCRVSpK3Iyu7qbqw3JMzoj0REeM6f3tJLtVwl0023Q==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@img/colour": "^1.1.0", - "detect-libc": "^2.1.2", - "semver": "^7.8.5" - }, - "engines": { - "node": ">=20.9.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-darwin-arm64": "0.35.3", - "@img/sharp-darwin-x64": "0.35.3", - "@img/sharp-freebsd-wasm32": "0.35.3", - "@img/sharp-libvips-darwin-arm64": "1.3.2", - "@img/sharp-libvips-darwin-x64": "1.3.2", - "@img/sharp-libvips-linux-arm": "1.3.2", - "@img/sharp-libvips-linux-arm64": "1.3.2", - "@img/sharp-libvips-linux-ppc64": "1.3.2", - "@img/sharp-libvips-linux-riscv64": "1.3.2", - "@img/sharp-libvips-linux-s390x": "1.3.2", - "@img/sharp-libvips-linux-x64": "1.3.2", - "@img/sharp-libvips-linuxmusl-arm64": "1.3.2", - "@img/sharp-libvips-linuxmusl-x64": "1.3.2", - "@img/sharp-linux-arm": "0.35.3", - "@img/sharp-linux-arm64": "0.35.3", - "@img/sharp-linux-ppc64": "0.35.3", - "@img/sharp-linux-riscv64": "0.35.3", - "@img/sharp-linux-s390x": "0.35.3", - "@img/sharp-linux-x64": "0.35.3", - "@img/sharp-linuxmusl-arm64": "0.35.3", - "@img/sharp-linuxmusl-x64": "0.35.3", - "@img/sharp-webcontainers-wasm32": "0.35.3", - "@img/sharp-win32-arm64": "0.35.3", - "@img/sharp-win32-ia32": "0.35.3", - "@img/sharp-win32-x64": "0.35.3" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - } - } - }, - "node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmmirror.com/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, - "license": "MIT", - "dependencies": { - "shebang-regex": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmmirror.com/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/side-channel": { - "version": "1.1.1", - "resolved": "https://registry.npmmirror.com/side-channel/-/side-channel-1.1.1.tgz", - "integrity": "sha512-6x6dK6zJdpTzF4sQeNYxwtvBzf6Eg4GtlesS94HOvTudUeyK2WXAaIfmDgsyslYrRBeFIlsi54AYsFGUuhmvrQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "object-inspect": "^1.13.4", - "side-channel-list": "^1.0.1", - "side-channel-map": "^1.0.1", - "side-channel-weakmap": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/side-channel-list": { - "version": "1.0.1", - "resolved": "https://registry.npmmirror.com/side-channel-list/-/side-channel-list-1.0.1.tgz", - "integrity": "sha512-mjn/0bi/oUURjc5Xl7IaWi/OJJJumuoJFQJfDDyO46+hBWsfaVM65TBHq2eoZBhzl9EchxOijpkbRC8SVBQU0w==", - "dev": true, - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "object-inspect": "^1.13.4" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/side-channel-map": { - "version": "1.0.1", - "resolved": "https://registry.npmmirror.com/side-channel-map/-/side-channel-map-1.0.1.tgz", - "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.5", - "object-inspect": "^1.13.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/side-channel-weakmap": { - "version": "1.0.2", - "resolved": "https://registry.npmmirror.com/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", - "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.5", - "object-inspect": "^1.13.3", - "side-channel-map": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/statuses": { - "version": "2.0.2", - "resolved": "https://registry.npmmirror.com/statuses/-/statuses-2.0.2.tgz", - "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/toidentifier": { - "version": "1.0.1", - "resolved": "https://registry.npmmirror.com/toidentifier/-/toidentifier-1.0.1.tgz", - "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.6" - } - }, - "node_modules/ts-algebra": { - "version": "2.0.0", - "resolved": "https://registry.npmmirror.com/ts-algebra/-/ts-algebra-2.0.0.tgz", - "integrity": "sha512-FPAhNPFMrkwz76P7cdjdmiShwMynZYN6SgOujD1urY4oNm80Ou9oMdmbR45LotcKOXoy7wSmHkRFE6Mxbrhefw==", - "dev": true, - "license": "MIT" - }, - "node_modules/tslib": { - "version": "2.8.1", - "resolved": "https://registry.npmmirror.com/tslib/-/tslib-2.8.1.tgz", - "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", - "dev": true, - "license": "0BSD" - }, - "node_modules/turndown": { - "version": "7.2.4", - "resolved": "https://registry.npmmirror.com/turndown/-/turndown-7.2.4.tgz", - "integrity": "sha512-I8yFsfRzmzK0WV1pNNOA4A7y4RDfFxPRxb3t+e3ui14qSGOxGtiSP6GjeX+Y6CHb7HYaFj7ECUD7VE5kQMZWGQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@mixmark-io/domino": "^2.2.0" - }, - "engines": { - "node": ">=18", - "npm": ">=9" - } - }, - "node_modules/type-is": { - "version": "2.1.0", - "resolved": "https://registry.npmmirror.com/type-is/-/type-is-2.1.0.tgz", - "integrity": "sha512-faYHw0anBbc/kWF3zFTEnxSFOAGUX9GFbOBthvDdLsIlEoWOFOtS0zgCiQYwIskL9iGXZL3kAXD8OoZ4GmMATA==", - "dev": true, - "license": "MIT", - "dependencies": { - "content-type": "^2.0.0", - "media-typer": "^1.1.0", - "mime-types": "^3.0.0" - }, - "engines": { - "node": ">= 18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/type-is/node_modules/content-type": { - "version": "2.1.0", - "resolved": "https://registry.npmmirror.com/content-type/-/content-type-2.1.0.tgz", - "integrity": "sha512-mj7UPXE0jaqaOsukNZRUEfEi2AcL7C/vwmwcHV0O97eO1E1pxBZuyjlZrx5seTaNBg1U6+o35wpa35Qfcc+7ag==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/typebox": { - "version": "1.1.38", - "resolved": "https://registry.npmmirror.com/typebox/-/typebox-1.1.38.tgz", - "integrity": "sha512-pZ0aQPmMmXoUvSbeuWf/Hzsc+avNw/Zd6VeE8CFgkVGWyuHPJvqeJJDeJqLve+K70LvjYIoleGcoJHPT17cWoA==", - "dev": true, - "license": "MIT" - }, - "node_modules/undici-types": { - "version": "8.3.0", - "resolved": "https://registry.npmmirror.com/undici-types/-/undici-types-8.3.0.tgz", - "integrity": "sha512-j375ScV60dom+YkPFIfTLcOiPxkN/buHz5GobjLhixFuANaNs3C9l4GmrWqejgXWJ7BbJcFYpTEUkS1Ge8bpZQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/unpipe": { - "version": "1.0.0", - "resolved": "https://registry.npmmirror.com/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/use-sync-external-store": { - "version": "1.2.0", - "resolved": "https://registry.npmmirror.com/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz", - "integrity": "sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "react": "^16.8.0 || ^17.0.0 || ^18.0.0" - } - }, - "node_modules/vary": { - "version": "1.1.2", - "resolved": "https://registry.npmmirror.com/vary/-/vary-1.1.2.tgz", - "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/web-streams-polyfill": { - "version": "3.3.3", - "resolved": "https://registry.npmmirror.com/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz", - "integrity": "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 8" - } - }, - "node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmmirror.com/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "license": "ISC", - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmmirror.com/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "dev": true, - "license": "ISC" - }, - "node_modules/ws": { - "version": "8.21.3", - "resolved": "https://registry.npmmirror.com/ws/-/ws-8.21.3.tgz", - "integrity": "sha512-201TZ/kPWxoPr/OKWjquZR1SWKXcvxdH+e1xrx89b3YbmzLMFCLfnaG1HFIgWzJOEWZ7MvpK++odZufgYR50Rw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": ">=5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } - } - }, - "node_modules/wsl-utils": { - "version": "1.0.0", - "resolved": "https://registry.npmmirror.com/wsl-utils/-/wsl-utils-1.0.0.tgz", - "integrity": "sha512-Hl0ZOAs672vg+06kfujwRhoS6/jehvULrlFkuF2dRu6pHgA8U06h3xqNIqNNU1LTXPcedxByAR4GS6pwQK0mgA==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-wsl": "^3.1.0", - "powershell-utils": "^0.1.0" - }, - "engines": { - "node": ">=20" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/wsl-utils/node_modules/powershell-utils": { - "version": "0.1.0", - "resolved": "https://registry.npmmirror.com/powershell-utils/-/powershell-utils-0.1.0.tgz", - "integrity": "sha512-dM0jVuXJPsDN6DvRpea484tCUaMiXWjuCn++HGTqUWzGDjv5tZkEZldAJ/UMlqRYGFrD/etByo4/xOuC/snX2A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=20" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/yaml": { - "version": "2.9.0", - "resolved": "https://registry.npmmirror.com/yaml/-/yaml-2.9.0.tgz", - "integrity": "sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA==", - "dev": true, - "license": "ISC", - "bin": { - "yaml": "bin.mjs" - }, - "engines": { - "node": ">= 14.6" - }, - "funding": { - "url": "https://github.com/sponsors/eemeli" - } - }, - "node_modules/zod": { - "version": "4.4.3", - "resolved": "https://registry.npmmirror.com/zod/-/zod-4.4.3.tgz", - "integrity": "sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==", - "dev": true, - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/colinhacks" - } - }, - "node_modules/zod-to-json-schema": { - "version": "3.25.2", - "resolved": "https://registry.npmmirror.com/zod-to-json-schema/-/zod-to-json-schema-3.25.2.tgz", - "integrity": "sha512-O/PgfnpT1xKSDeQYSCfRI5Gy3hPf91mKVDuYLUHZJMiDFptvP41MSnWofm8dnCm0256ZNfZIM7DSzuSMAFnjHA==", - "dev": true, - "license": "ISC", - "peerDependencies": { - "zod": "^3.25.28 || ^4" - } - }, - "node_modules/zustand": { - "version": "4.4.7", - "resolved": "https://registry.npmmirror.com/zustand/-/zustand-4.4.7.tgz", - "integrity": "sha512-QFJWJMdlETcI69paJwhSMJz7PPWjVP8Sjhclxmxmxv/RYI7ZOvR5BHX+ktH0we9gTWQMxcne8q1OY8xxz604gw==", - "dev": true, - "license": "MIT", - "dependencies": { - "use-sync-external-store": "1.2.0" - }, - "engines": { - "node": ">=12.7.0" - }, - "peerDependencies": { - "@types/react": ">=16.8", - "immer": ">=9.0", - "react": ">=16.8" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "immer": { - "optional": true - }, - "react": { - "optional": true - } - } - } - } -} diff --git a/.release/dshx-linux-x64/package.json b/.release/dshx-linux-x64/package.json deleted file mode 100644 index 2b5da691..00000000 --- a/.release/dshx-linux-x64/package.json +++ /dev/null @@ -1,62 +0,0 @@ -{ - "name": "@code-new-bie/dshx-tui", - "version": "0.0.0-m1", - "description": "Codex-grade TUI surface bundle for official DeepSeek Harness", - "type": "module", - "license": "Apache-2.0", - "os": [ - "linux" - ], - "cpu": [ - "x64" - ], - "engines": { - "node": "^22.19.0 || >=24.0.0" - }, - "bin": { - "dshx": "./bin/dshx.mjs" - }, - "exports": { - ".": "./src/dsh/index.mjs", - "./presentation": "./src/dsh/presentation-plugin.mjs", - "./startup": "./src/dsh/startup-plugin.mjs", - "./cordis.patch.yml": "./cordis.patch.yml", - "./package.json": "./package.json" - }, - "dsh": { - "bundle": { - "patch": "./cordis.patch.yml" - } - }, - "peerDependencies": { - "@deepseek-ai/dsh": "0.1.0-rc.8", - "@deepseek-ai/dsh-agent": "0.1.0-rc.8", - "@deepseek-ai/dsh-app-boot": "0.1.0-rc.8", - "@deepseek-ai/dsh-host-apiproxy": "0.1.0-rc.8", - "@deepseek-ai/dsh-launch-environment": "0.1.0-rc.8", - "@deepseek-ai/dsh-llm": "0.1.0-rc.8", - "@deepseek-ai/dsh-session": "0.1.0-rc.8" - }, - "dependencies": { - "@deepseek-ai/dsh-cmdline": "0.1.0-rc.8", - "@deepseek-ai/schemastery": "3.18.1" - }, - "repository": { - "type": "git", - "url": "https://github.com/code-new-bie/dsh-codex.git" - }, - "files": [ - "bin/dshx.mjs", - "src/cli", - "src/dsh", - "src/tui-protocol", - "src/protocol", - "cordis.patch.yml", - "dist/bin", - "upstream", - "README.md", - "LICENSE", - "NOTICE", - "npm-shrinkwrap.json" - ] -} diff --git a/.release/dshx-linux-x64/src/cli/arguments.mjs b/.release/dshx-linux-x64/src/cli/arguments.mjs deleted file mode 100644 index 811ae5d0..00000000 --- a/.release/dshx-linux-x64/src/cli/arguments.mjs +++ /dev/null @@ -1,29 +0,0 @@ -export function parseLaunchArgs(args) { - if (args[0] !== 'resume') return { tuiArgs: args, resumeEnv: {} }; - const rest = args.slice(1); - if (rest.length === 0) return { tuiArgs: [], resumeEnv: { DSHX_RESUME_MODE: 'picker' } }; - if (rest.length === 1 && rest[0] === '--last') { - return { tuiArgs: [], resumeEnv: { DSHX_RESUME_MODE: 'last' } }; - } - if (rest.length === 1 && !rest[0].startsWith('-')) { - return { - tuiArgs: [], - resumeEnv: { DSHX_RESUME_MODE: 'id', DSHX_RESUME_SESSION_ID: rest[0] } - }; - } - throw new Error('Usage: dshx resume [--last|]'); -} - -export function parseCliInvocation(args) { - if (args.length === 1 && (args[0] === '--help' || args[0] === '-h')) { - return { kind: 'help' }; - } - if (args.length === 1 && (args[0] === '--version' || args[0] === '-V')) { - return { kind: 'version' }; - } - if (args[0] === 'doctor') { - if (args.length !== 1) throw new Error('Usage: dshx doctor'); - return { kind: 'doctor' }; - } - return { kind: 'launch', ...parseLaunchArgs(args) }; -} diff --git a/.release/dshx-linux-x64/src/cli/runtime.mjs b/.release/dshx-linux-x64/src/cli/runtime.mjs deleted file mode 100644 index e590597f..00000000 --- a/.release/dshx-linux-x64/src/cli/runtime.mjs +++ /dev/null @@ -1,27 +0,0 @@ -export const DSHX_NODE_ENGINE = '^22.19.0 || >=24.0.0'; -export const DSHX_RELEASE_NODE_MAJOR = 24; -// `dshx doctor` deliberately boots the full official DSH composition, including -// profile watchers. A fresh Windows install can incur one-time module/native -// initialization that exceeds 20s even though subsequent and normal product -// startup are healthy. Keep the diagnostic bounded, but allow realistic cold -// starts on supported desktop hardware. -export const DSHX_DOCTOR_BOOT_TIMEOUT_MS = 60_000; -export const DSHX_DOCTOR_DISPOSE_TIMEOUT_MS = 10_000; - -export function isSupportedNodeVersion(version) { - const match = /^(\d+)\.(\d+)\.(\d+)/.exec(String(version ?? '')); - if (!match) return false; - const major = Number(match[1]); - const minor = Number(match[2]); - return (major === 22 && minor >= 19) || major >= 24; -} - -export function assertReleaseNodeVersion(version = process.versions.node) { - const major = Number(String(version).split('.')[0]); - if (major !== DSHX_RELEASE_NODE_MAJOR) { - throw new Error( - `DSHX dependency freeze/release baseline requires Node ${DSHX_RELEASE_NODE_MAJOR}.x; got ${version}. ` + - `Runtime compatibility follows pinned DSH (${DSHX_NODE_ENGINE}).` - ); - } -} diff --git a/.release/dshx-linux-x64/src/dsh/agent-driver.mjs b/.release/dshx-linux-x64/src/dsh/agent-driver.mjs deleted file mode 100644 index 3641bc70..00000000 --- a/.release/dshx-linux-x64/src/dsh/agent-driver.mjs +++ /dev/null @@ -1,213 +0,0 @@ -import { randomUUID } from 'node:crypto'; -import { installModelSelection } from '@deepseek-ai/dsh-agent'; -import { createUserMessage } from '@deepseek-ai/dsh-llm'; -import { SessionId } from '@deepseek-ai/dsh-session'; - -function requireService(ctx, name) { - const service = ctx.get(name); - if (service === undefined) throw new Error(`DSHX requires DSH service: ${name}`); - return service; -} - -function userMessage(content) { - const blocks = Array.isArray(content) ? content : [{ type: 'text', text: String(content ?? '') }]; - return createUserMessage({ - source: { kind: 'user' }, - content: blocks - }); -} - -/** Thin delegation layer over official DeepSeek Harness public services. */ -export class DshAgentDriver { - constructor(ctx) { - if (!ctx || typeof ctx.get !== 'function') throw new Error('DshAgentDriver requires a Cordis Context'); - this.ctx = ctx; - this.selections = new WeakMap(); - this.externalSelections = new WeakMap(); - } - - async settleComposition() { - await this.ctx.get('loader')?.await?.(); - } - - persistedSelection(agent) { - const logged = agent.session.requestHeader?.()?.config; - if (logged === undefined) return undefined; - return { - provider: logged.provider, - model: logged.model, - ...(logged.reasoningEffort === undefined ? {} : { reasoningEffort: logged.reasoningEffort }) - }; - } - - restoredSelection(agent) { - return this.persistedSelection(agent) - ?? requireService(this.ctx, 'agentDefaultModel').currentSelection(); - } - - selectionFor(agent) { - const existing = this.selections.get(agent); - if (existing) return existing; - if (this.externalSelections.has(agent)) { - throw new Error('DSHX must not install a second model-selection listener on a Host-owned Agent'); - } - const driver = this; - let picked = this.persistedSelection(agent); - const selection = { - get current() { - return picked - ?? requireService(driver.ctx, 'agentDefaultModel').currentSelection(); - }, - set current(next) { picked = next; }, - assembled: undefined - }; - installModelSelection(agent.ctx, selection); - this.selections.set(agent, selection); - return selection; - } - - /** - * Attach presentation state to an Agent created by another official DSH - * entrypoint (currently Host sessions.fork). No routing listener is installed; - * writes must go back through the owning DSH API delegate. - */ - adoptExternalSelection(agent, { current, select } = {}) { - if (this.selections.has(agent)) { - throw new Error('Cannot adopt Host-owned selection after DSHX installed its own selection listener'); - } - const state = { - current: current ?? this.restoredSelection(agent), - select - }; - this.externalSelections.set(agent, state); - return state.current; - } - - installSelection(agentCtx) { - const agent = agentCtx.agent; - if (!agent) throw new Error('DSHX agent setup has no scoped DSH Agent'); - this.selectionFor(agent); - } - - async create({ cwd = process.cwd(), sessionId = `session-${randomUUID()}` } = {}) { - await this.settleComposition(); - const agents = requireService(this.ctx, 'agents'); - const selection = requireService(this.ctx, 'agentDefaultModel').currentSelection(); - return agents.create({ - sessionId: SessionId(sessionId), - meta: { cwd }, - agentOptions: { provider: selection.provider, model: selection.model }, - setup: (agentCtx) => this.installSelection(agentCtx) - }); - } - - async resume(sessionId) { - await this.settleComposition(); - const agents = requireService(this.ctx, 'agents'); - return agents.resume({ - resumeSessionId: SessionId(sessionId), - setup: (agentCtx) => this.installSelection(agentCtx) - }); - } - - currentModel(agent) { - return this.externalSelections.get(agent)?.current ?? this.selectionFor(agent).current; - } - - currentTitle(agent) { - return this.ctx.get('sessionTitle')?.get?.(agent.session); - } - - renameTitle(agent, title) { - const service = requireService(this.ctx, 'sessionTitle'); - return service.rename(agent.session, title); - } - - async readTitle(sessionId) { - const query = this.ctx.get('sessionQuery'); - if (query?.readTitle) return query.readTitle(SessionId(sessionId)); - const live = this.getLive(sessionId); - return live ? this.currentTitle(live) : undefined; - } - - async selectModel(agent, requested) { - const llm = requireService(this.ctx, 'llm'); - const resolved = await llm.resolveCallConfig({ - provider: requested.provider, - model: requested.model, - ...(requested.reasoningEffort === undefined ? {} : { reasoningEffort: requested.reasoningEffort }) - }); - const selected = { - provider: resolved.provider, - model: resolved.model, - ...(resolved.reasoningEffort === undefined ? {} : { reasoningEffort: resolved.reasoningEffort }) - }; - const external = this.externalSelections.get(agent); - if (external) { - if (typeof external.select !== 'function') { - throw new Error('Host-owned DSH Agent has no model-selection delegate'); - } - const committed = await external.select(selected); - external.current = committed ?? selected; - return external.current; - } - this.selectionFor(agent).current = selected; - return selected; - } - - async modelDirectory() { - const llm = requireService(this.ctx, 'llm'); - const providers = llm.listProviders(); - const settled = await Promise.all(providers.map(async (provider) => { - try { - const models = await llm.listModels(provider.id); - const entries = await Promise.all(models.map(async (model) => { - const exact = await llm.resolveModelInfo(provider.id, model.id); - return { - id: model.id, - name: model.name, - ...(model.description === undefined ? {} : { description: model.description }), - ...(exact.inputModalities === undefined ? {} : { inputModalities: [...exact.inputModalities] }), - ...(exact.context === undefined ? {} : { contextWindow: exact.context.contextWindow }), - ...(exact.reasoning === undefined ? {} : { - reasoning: { - efforts: exact.reasoning.efforts.map((effort) => ({ - id: effort.id, - name: effort.name, - ...(effort.description === undefined ? {} : { description: effort.description }) - })), - ...(exact.reasoning.defaultEffort === undefined ? {} : { defaultEffort: exact.reasoning.defaultEffort }) - } - }) - }; - })); - return { ok: true, group: { provider: provider.id, name: provider.name ?? provider.id, models: entries } }; - } catch (error) { - return { - ok: false, - failure: { provider: provider.id, message: error instanceof Error ? error.message : String(error) } - }; - } - })); - return { - groups: settled.filter((entry) => entry.ok && entry.group.models.length > 0).map((entry) => entry.group), - failures: settled.filter((entry) => !entry.ok).map((entry) => entry.failure) - }; - } - - followup(agent, content) { agent.followup(userMessage(content)); } - steer(agent, content) { agent.steer(userMessage(content)); } - interrupt(agent, { keepInbox = false } = {}) { agent.cancel({ kind: 'user' }, { keepInbox }); } - whenIdle(agent) { return agent.whenIdle(); } - getLive(sessionId) { return requireService(this.ctx, 'agents').get(SessionId(sessionId)); } - listLive() { return requireService(this.ctx, 'agents').list(); } - listRootAgents() { return requireService(this.ctx, 'agents').roots(); } - - async listSessions(signal) { - return requireService(this.ctx, 'sessionPersistence').list(signal); - } - - async inspectSession(sessionId, signal) { - return requireService(this.ctx, 'sessionPersistence').inspect(SessionId(sessionId), signal); - } -} diff --git a/.release/dshx-linux-x64/src/dsh/approval-bridge.mjs b/.release/dshx-linux-x64/src/dsh/approval-bridge.mjs deleted file mode 100644 index 20bd0319..00000000 --- a/.release/dshx-linux-x64/src/dsh/approval-bridge.mjs +++ /dev/null @@ -1,88 +0,0 @@ -import { mapCodexDecisionToDshApprovalOutcome } from './permissions.mjs'; - -function unavailable() { - return 'unavailable'; -} - -/** - * Presentation-only answerer for DSH `approval/request`. - * - * `classify(req)` must return a faithful presentation descriptor for a DSH - * tool that already has a matching Codex UI surface, or null when DSHX cannot - * represent the request. Null deliberately delegates to the next DSH answerer; - * if nobody owns it, DSH itself returns `unavailable` and callers fail closed. - */ -export class DshApprovalBridge { - constructor({ agent, broker, classify, diagnostics = () => {} }) { - if (!agent?.ctx) throw new Error('DshApprovalBridge requires a live DSH Agent'); - if (!broker) throw new Error('DshApprovalBridge requires a UiRequestBroker'); - if (typeof classify !== 'function') throw new Error('DshApprovalBridge requires classify(req)'); - this.agent = agent; - this.broker = broker; - this.classify = classify; - this.diagnostics = diagnostics; - this.disposeListener = agent.ctx.on('approval/request', (req, next) => this.answer(req, next)); - } - - async answer(req, next) { - const descriptor = this.classify(req); - if (!descriptor) return next(); - - const { kind, threadId, turnId, itemId } = descriptor; - if (!threadId || !turnId || !itemId) { - this.diagnostics('approval classifier returned an incomplete descriptor'); - return unavailable(); - } - - let method; - let params; - if (kind === 'command') { - method = 'item/commandExecution/requestApproval'; - params = { - threadId, - turnId, - itemId, - startedAtMs: Date.now(), - approvalId: null, - environmentId: null, - reason: req.reason ?? null, - networkApprovalContext: null, - command: descriptor.command ?? null, - cwd: descriptor.cwd ?? null, - commandActions: null, - proposedExecpolicyAmendment: null, - proposedNetworkPolicyAmendments: null - }; - } else if (kind === 'fileChange') { - method = 'item/fileChange/requestApproval'; - params = { - threadId, - turnId, - itemId, - startedAtMs: Date.now(), - reason: req.reason ?? null, - grantRoot: null - }; - } else { - this.diagnostics(`unsupported approval descriptor kind: ${String(kind)}`); - return unavailable(); - } - - try { - const result = await this.broker.request(method, params, { signal: req.signal }); - return mapCodexDecisionToDshApprovalOutcome(result?.decision); - } catch (error) { - // Any transport failure, abort, timeout, unsupported persistent grant or - // malformed decision fails closed. DSH remains the policy owner and logs - // the resulting `unavailable`/cancelled decision through its own service. - if (req.signal?.aborted || error?.name === 'AbortError') return 'cancelled'; - this.diagnostics(error instanceof Error ? error.message : String(error)); - return unavailable(); - } - } - - dispose() { - this.disposeListener?.(); - this.disposeListener = undefined; - } -} diff --git a/.release/dshx-linux-x64/src/dsh/commands.mjs b/.release/dshx-linux-x64/src/dsh/commands.mjs deleted file mode 100644 index d63bec35..00000000 --- a/.release/dshx-linux-x64/src/dsh/commands.mjs +++ /dev/null @@ -1,27 +0,0 @@ -function requireService(ctx, name) { - const service = ctx?.get?.(name); - if (service == null) throw new Error(`DSHX requires DSH service: ${name}`); - return service; -} - -/** - * Execute one human-facing DSH command through the official command plane. - * DSHX does not parse, implement, persist, or run the domain operation itself. - */ -export async function executeDshCommand({ ctx, agent, line, images = [], signal }) { - if (!agent) throw new Error('DSHX command execution requires a live DSH Agent'); - const commands = requireService(ctx, 'commands'); - const execution = await commands.execute(agent, line, images, signal); - if (execution == null) throw new Error(`DSH command is not registered: ${line}`); - if (execution.result?.kind === 'error') { - throw new Error(execution.result.text || `DSH command failed: ${line}`); - } - return execution; -} - -/** Read the current agent-scoped command catalog from DSH. */ -export function listDshCommands({ ctx, agent }) { - if (!agent) throw new Error('DSHX command discovery requires a live DSH Agent'); - const commands = requireService(ctx, 'commands'); - return commands.list(agent); -} diff --git a/.release/dshx-linux-x64/src/dsh/history-pages.mjs b/.release/dshx-linux-x64/src/dsh/history-pages.mjs deleted file mode 100644 index c4b9ada0..00000000 --- a/.release/dshx-linux-x64/src/dsh/history-pages.mjs +++ /dev/null @@ -1,77 +0,0 @@ -import { dshTurnsFromSession } from '../tui-protocol/shapes.mjs'; - -function cursorOffset(cursor) { - if (cursor == null) return 0; - const match = /^dshx:(\d+)$/.exec(String(cursor)); - if (!match) throw new Error(`invalid DSHX history cursor: ${JSON.stringify(cursor)}`); - const value = Number(match[1]); - if (!Number.isSafeInteger(value) || value < 0) throw new Error('invalid DSHX history cursor'); - return value; -} - -function pageSize(limit, fallback) { - if (limit == null) return fallback; - const value = Number(limit); - if (!Number.isSafeInteger(value) || value <= 0) throw new Error('history limit must be a positive integer'); - return Math.min(value, 1000); -} - -function page(values, { cursor, limit, sortDirection, fallbackLimit }) { - const ordered = sortDirection === 'asc' ? values : [...values].reverse(); - const start = cursorOffset(cursor); - const size = pageSize(limit, fallbackLimit); - const end = Math.min(ordered.length, start + size); - return { - data: ordered.slice(start, end), - nextCursor: end < ordered.length ? `dshx:${end}` : null, - // DSHX cursors are forward-only presentation cursors. The TUI only needs - // nextCursor for bounded backwards hydration; no durable cursor state is owned here. - backwardsCursor: null - }; -} - -function projectedTurns(controller, diagnostics) { - return dshTurnsFromSession({ - ctx: controller.agent.ctx, - agent: controller.agent, - diagnostics - }); -} - -function viewTurn(turn, requestedView) { - if (requestedView === 'notLoaded') { - return { ...turn, items: [], itemsView: 'notLoaded' }; - } - // DSHX has a faithful full presentation fold, not a second lossy summary - // algorithm. When Codex asks for summary, return full and label it honestly. - return { ...turn, itemsView: 'full' }; -} - -export function dshThreadTurnsPage({ controller, params = {}, diagnostics = () => {} }) { - const turns = projectedTurns(controller, diagnostics).map((turn) => viewTurn(turn, params.itemsView)); - return page(turns, { - cursor: params.cursor, - limit: params.limit, - sortDirection: params.sortDirection, - fallbackLimit: 5 - }); -} - -export function dshThreadItemsPage({ controller, params = {}, diagnostics = () => {} }) { - let turns = projectedTurns(controller, diagnostics); - if (params.turnId != null) { - turns = turns.filter((turn) => turn.id === String(params.turnId)); - } - const entries = []; - for (const turn of turns) { - for (const item of turn.items) entries.push({ turnId: turn.id, item }); - } - return page(entries, { - cursor: params.cursor, - limit: params.limit, - sortDirection: params.sortDirection, - fallbackLimit: 100 - }); -} - -export const historyInternals = { cursorOffset, pageSize, page, viewTurn }; diff --git a/.release/dshx-linux-x64/src/dsh/host-api.mjs b/.release/dshx-linux-x64/src/dsh/host-api.mjs deleted file mode 100644 index 287bd9fc..00000000 --- a/.release/dshx-linux-x64/src/dsh/host-api.mjs +++ /dev/null @@ -1,61 +0,0 @@ -import { randomUUID } from 'node:crypto'; -import { createApiProxy, RpcId } from '@deepseek-ai/dsh-host-apiproxy'; - -function requireService(ctx, name) { - const service = ctx?.get?.(name); - if (service == null) throw new Error(`DSHX requires DSH service: ${name}`); - return service; -} - -function rpcError(error, fallback) { - if (error?.message) return new Error(error.message); - return new Error(fallback); -} - -function value(response, fallback) { - if (!response?.result?.ok) throw rpcError(response?.result?.error, fallback); - return response.result.value; -} - -/** - * Very small façade over DSH's own transport-agnostic Host API. - * Domain semantics stay in @deepseek-ai/dsh-host-apiproxy; DSHX only adapts - * Codex presentation requests into that public API. - */ -export class DshHostApi { - constructor(ctx, { cwd = process.cwd() } = {}) { - if (!ctx || typeof ctx.get !== 'function') throw new Error('DshHostApi requires a Cordis Context'); - this.ctx = ctx; - this.api = createApiProxy(ctx, { - cwd, - defaultModelSelection: () => requireService(ctx, 'agentDefaultModel').currentSelection(), - saveDefaultModelSelection: (selection) => requireService(ctx, 'agentDefaultModel').saveSelection(selection) - }); - } - - request(payload) { - return { - rpcId: RpcId(`dshx-${randomUUID()}`), - payload - }; - } - - async forkSession({ sessionId, atSeq } = {}) { - const response = await this.api.sessions.fork(this.request({ - sessionId, - ...(atSeq == null ? {} : { atSeq }) - })); - return value(response, `DSH session fork failed for ${String(sessionId)}`); - } - - async selectModel({ sessionId, provider, model, reasoningEffort } = {}) { - const response = await this.api.sessions.selectModel(this.request({ - sessionId, - provider, - model, - ...(reasoningEffort == null ? {} : { reasoningEffort }) - })); - const result = value(response, `DSH model selection failed for ${String(sessionId)}`); - return result?.selected ?? result; - } -} diff --git a/.release/dshx-linux-x64/src/dsh/index.mjs b/.release/dshx-linux-x64/src/dsh/index.mjs deleted file mode 100644 index 06771846..00000000 --- a/.release/dshx-linux-x64/src/dsh/index.mjs +++ /dev/null @@ -1,25 +0,0 @@ -/** - * @code-new-bie/dshx-tui — Codex-TUI surface bundle for DeepSeek Harness. - * - * Programmatic entry point. The runtime capability lives in the two - * loader-mounted rows (`./startup`, `./presentation`); this index exists so - * tooling and tests can consume the contract metadata without importing the - * transport implementation. - */ -export { - name, - inject, - Config, - apply, - plugin, - SERVICE_KEY, - internals -} from './presentation-plugin.mjs'; -export { - name as startupName, - inject as startupInject, - Config as startupConfig, - apply as startupApply, - plugin as startupPlugin, - internals as startupInternals -} from './startup-plugin.mjs'; diff --git a/.release/dshx-linux-x64/src/dsh/local-server.mjs b/.release/dshx-linux-x64/src/dsh/local-server.mjs deleted file mode 100644 index c96fca06..00000000 --- a/.release/dshx-linux-x64/src/dsh/local-server.mjs +++ /dev/null @@ -1,363 +0,0 @@ -import fs from 'node:fs'; -import os from 'node:os'; -import path from 'node:path'; -import { spawn } from 'node:child_process'; -import { createInterface } from 'node:readline'; -import { fileURLToPath } from 'node:url'; -import { DshxPresentationAdapter } from '../tui-protocol/adapter.mjs'; -import { bootDshxRuntime } from './runtime-boot.mjs'; - -const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../..'); -const READY = 'ready'; -const WINDOWS_UNIX_PATH_MAX = 108; - -function packagedBridgeBinary() { - const name = process.platform === 'win32' ? 'dshx-ipc-bridge.exe' : 'dshx-ipc-bridge'; - return process.env.DSHX_IPC_BRIDGE_BIN || path.join(ROOT, 'dist', 'bin', name); -} - -function parseError(error) { - return { - id: null, - error: { - code: -32700, - message: `Parse error: ${error instanceof Error ? error.message : String(error)}` - } - }; -} - -function isPathWithin(root, candidate, pathApi = path) { - const relative = pathApi.relative(pathApi.resolve(root), pathApi.resolve(candidate)); - return relative === '' || ( - relative !== '..' && - !relative.startsWith(`..${pathApi.sep}`) && - !pathApi.isAbsolute(relative) - ); -} - -function defaultSocketRoot({ - home, - platform = process.platform, - temporaryDirectory = os.tmpdir(), - userHome = os.homedir() -} = {}) { - if (platform !== 'win32') return temporaryDirectory; - // codex_uds can enforce 0700 on Unix. Its Windows implementation inherits - // directory ACLs instead, so do not trust an arbitrary/shared %TEMP% root. - // Anchor the rendezvous below the current user's DSHX presentation home, - // whose parent in turn lives below the user's profile by default. Keep the - // Windows suffix deliberately short because sockaddr_un.sun_path is bounded. - const pathApi = path.win32; - const userProfile = pathApi.resolve(userHome); - const presentationHome = pathApi.resolve(home || pathApi.join(userProfile, '.dshx', 'codex-tui')); - if (!isPathWithin(userProfile, presentationHome, pathApi)) { - throw new Error( - `DSHX_TUI_HOME must remain under the Windows user profile (${userProfile}) so local IPC inherits private user ACLs; got ${presentationHome}` - ); - } - return pathApi.join(presentationHome, 'i'); -} - -function createSocketDirectory(root) { - fs.mkdirSync(root, { recursive: true, mode: 0o700 }); - const directory = fs.mkdtempSync(path.join(root, 'd-')); - if (process.platform !== 'win32') fs.chmodSync(directory, 0o700); - return directory; -} - -function assertSocketPathSupported(socketPath, { - platform = process.platform, - windowsUnixPathMax = WINDOWS_UNIX_PATH_MAX -} = {}) { - if (platform !== 'win32') return; - const bytes = Buffer.byteLength(socketPath, 'utf8'); - // sun_path needs one byte for the terminating NUL, so the pathname itself - // must remain strictly shorter than the fixed buffer. - if (bytes >= windowsUnixPathMax) { - throw new Error( - `DSHX local IPC path is ${bytes} UTF-8 bytes; Windows AF_UNIX requires fewer than ${windowsUnixPathMax}. ` + - 'Set DSHX_TUI_HOME to a shorter path under your user profile and retry.' - ); - } -} - -function waitForBridgeReady(lines, child, stderrText) { - return new Promise((resolve, reject) => { - const fail = (error) => { - cleanup(); - reject(error); - }; - const onLine = (line) => { - let message; - try { - message = JSON.parse(line); - } catch (error) { - fail(new Error(`DSHX IPC bridge emitted invalid readiness JSON: ${line}`, { cause: error })); - return; - } - if (message?.dshxBridge !== READY) { - fail(new Error(`DSHX IPC bridge emitted unexpected readiness message: ${line}`)); - return; - } - cleanup(); - resolve(message); - }; - const onError = (error) => fail(new Error(`failed to start DSHX IPC bridge: ${error.message}`, { cause: error })); - const onExit = (code, signal) => { - const detail = stderrText().trim(); - fail(new Error(`DSHX IPC bridge exited before ready (${signal ?? code ?? 'unknown'})${detail ? `: ${detail}` : ''}`)); - }; - const cleanup = () => { - lines.off('line', onLine); - child.off('error', onError); - child.off('exit', onExit); - }; - lines.once('line', onLine); - child.once('error', onError); - child.once('exit', onExit); - }); -} - -function waitForExit(child, timeoutMs = 750) { - if (!child || child.exitCode !== null || child.signalCode !== null) return Promise.resolve(); - return new Promise((resolve) => { - let done = false; - const finish = () => { - if (done) return; - done = true; - clearTimeout(timer); - child.off('exit', finish); - resolve(); - }; - const timer = setTimeout(() => { - if (child.exitCode === null && child.signalCode === null) child.kill('SIGTERM'); - finish(); - }, timeoutMs); - child.once('exit', finish); - }); -} - -function cleanupDiagnostic(log, scope, error) { - log(`${scope}: ${error instanceof Error ? error.message : String(error)}`); -} - -async function cleanupFailedStartup({ lines, bridge, ctx, socketDirectory, log }) { - try { - lines?.close(); - } catch (error) { - cleanupDiagnostic(log, 'startup rollback: readline cleanup failed', error); - } - if (bridge) { - try { - if (bridge.stdin?.writable) bridge.stdin.end(); - if (bridge.exitCode === null && bridge.signalCode === null) bridge.kill?.('SIGTERM'); - await waitForExit(bridge); - if (bridge.exitCode === null && bridge.signalCode === null) bridge.kill?.('SIGKILL'); - } catch (error) { - cleanupDiagnostic(log, 'startup rollback: bridge cleanup failed', error); - } - } - try { - await ctx?.dispose?.(); - } catch (error) { - cleanupDiagnostic(log, 'startup rollback: DSH dispose failed', error); - } - if (socketDirectory) { - try { - fs.rmSync(socketDirectory, { recursive: true, force: true }); - } catch (error) { - cleanupDiagnostic(log, 'startup rollback: rendezvous cleanup failed', error); - } - } -} - -/** - * Starts the production-local DSHX presentation transport. - * - * The official DeepSeek Harness runtime remains in-process in Node. The pinned - * Codex TUI connects only to a private cross-platform Unix-domain socket owned - * by the tiny packaged Rust bridge. JSON-RPC is relayed between that bridge and - * this adapter over child stdio; no TCP listener or Codex remote WebSocket mode - * exists in the production launch path. - */ -export async function startDshxLocalServer({ - cwd = process.cwd(), - home, - version = '0.1.0-dev', - runtime, - bootRuntime = bootDshxRuntime, - Adapter = DshxPresentationAdapter, - log = () => {}, - bridgeCommand = packagedBridgeBinary(), - bridgeArgs, - spawnBridge = spawn, - socketRoot, - disposeRuntimeOnClose = true -} = {}) { - const rendezvousRoot = path.resolve(socketRoot ?? defaultSocketRoot({ home })); - let socketDirectory; - let socketPath; - let ctx = runtime; - let bridge; - let lines; - let adapter; - let closing = false; - let closePromise; - let stderr = ''; - - const send = (message) => { - if (!bridge?.stdin?.writable) throw new Error('DSHX IPC bridge stdin is not writable'); - bridge.stdin.write(`${JSON.stringify(message)}\n`); - }; - const safeSend = (message) => { - try { - send(message); - return true; - } catch (error) { - log(`IPC response send failed: ${error instanceof Error ? error.message : String(error)}`); - return false; - } - }; - - try { - socketDirectory = createSocketDirectory(rendezvousRoot); - socketPath = path.join(socketDirectory, 's'); - assertSocketPathSupported(socketPath); - ctx ??= await bootRuntime({ cwd }); - const args = bridgeArgs ?? [socketPath]; - bridge = spawnBridge(bridgeCommand, args, { - cwd, - stdio: ['pipe', 'pipe', 'pipe'], - windowsHide: true - }); - bridge.stderr?.on('data', (chunk) => { - const text = chunk.toString('utf8'); - stderr = `${stderr}${text}`.slice(-8192); - if (process.env.DSHX_DEBUG === '1') log(`ipc bridge: ${text.trimEnd()}`); - }); - lines = createInterface({ input: bridge.stdout, crlfDelay: Infinity }); - await waitForBridgeReady(lines, bridge, () => stderr); - adapter = new Adapter({ - ctx, - cwd, - home, - version, - send, - diagnostics: log - }); - } catch (error) { - await cleanupFailedStartup({ lines, bridge, ctx, socketDirectory, log }); - throw error; - } - - lines.on('line', (line) => { - void (async () => { - let message; - try { - message = JSON.parse(line); - } catch (error) { - safeSend(parseError(error)); - return; - } - if (message?.dshxBridge) { - log(`IPC bridge control message: ${message.dshxBridge}`); - return; - } - try { - const handled = await adapter.handle(message); - if (!handled) return; - if (!safeSend(handled.response)) return; - await handled.afterResponse?.(); - } catch (error) { - log(`request handling failed: ${error instanceof Error ? error.stack ?? error.message : String(error)}`); - if (message?.id !== undefined) { - safeSend({ - id: message.id, - error: { - code: -32603, - message: error instanceof Error ? error.message : String(error) - } - }); - } - } - })(); - }); - - bridge.on('error', (error) => log(`IPC bridge error: ${error.message}`)); - bridge.on('exit', (code, signal) => { - if (!closing) log(`IPC bridge exited unexpectedly (${signal ?? code ?? 'unknown'})`); - }); - - const close = () => { - if (closePromise) return closePromise; - closing = true; - closePromise = (async () => { - let primaryError; - const capture = (scope, error) => { - if (!primaryError) { - primaryError = error; - return; - } - cleanupDiagnostic(log, `shutdown cleanup: ${scope}`, error); - }; - - try { - lines?.close(); - } catch (error) { - capture('readline cleanup failed', error); - } - - try { - await adapter?.close?.(); - } catch (error) { - capture('adapter close failed', error); - } - - try { - if (bridge?.stdin?.writable) bridge.stdin.end(); - await waitForExit(bridge); - if (bridge && bridge.exitCode === null && bridge.signalCode === null) bridge.kill?.('SIGKILL'); - } catch (error) { - capture('bridge cleanup failed', error); - } - - // When mounted as the dshx-presentation Cordis plugin, root-fiber - // disposal stays owned by the composition; only the transport closes - // here and the Fiber unwinds the plugin afterwards. - if (disposeRuntimeOnClose) { - try { - await ctx?.dispose?.(); - } catch (error) { - capture('DSH dispose failed', error); - } - } - - if (socketDirectory) { - try { - fs.rmSync(socketDirectory, { recursive: true, force: true }); - } catch (error) { - capture('rendezvous cleanup failed', error); - } - } - - if (primaryError) throw primaryError; - })(); - return closePromise; - }; - - return { - path: socketPath, - url: `unix://${socketPath}`, - context: ctx, - close - }; -} - -export const localServerInternals = { - WINDOWS_UNIX_PATH_MAX, - isPathWithin, - defaultSocketRoot, - createSocketDirectory, - assertSocketPathSupported, - cleanupFailedStartup -}; diff --git a/.release/dshx-linux-x64/src/dsh/permissions.mjs b/.release/dshx-linux-x64/src/dsh/permissions.mjs deleted file mode 100644 index f1f1b4df..00000000 --- a/.release/dshx-linux-x64/src/dsh/permissions.mjs +++ /dev/null @@ -1,106 +0,0 @@ -function requireService(ctx, name) { - const service = ctx.get(name); - if (service === undefined) throw new Error(`DSHX requires DSH service: ${name}`); - return service; -} - -function codexApprovalPolicy(policy) { - if (policy === 'ask') return 'on-request'; - if (policy === 'never') return 'never'; - throw new Error(`Unsupported DSH approval policy: ${String(policy)}`); -} - -/** - * Project official DSH permission state into Codex-facing presentation data. - * - * DSH sandbox modes govern filesystem effects only; Codex legacy sandbox - * shapes also encode network policy. To avoid claiming Codex-native sandbox - * semantics that DSH does not own, confined DSH modes are advertised as an - * external sandbox. `legacyNetworkAccess` describes only the legacy Codex - * field and never changes DSH enforcement. - */ -export class DshPermissionView { - constructor(ctx, { legacyNetworkAccess = 'enabled' } = {}) { - if (!ctx || typeof ctx.get !== 'function') throw new Error('DshPermissionView requires a Cordis Context'); - if (!['enabled', 'restricted'].includes(legacyNetworkAccess)) { - throw new Error('legacyNetworkAccess must be "enabled" or "restricted"'); - } - this.ctx = ctx; - this.legacyNetworkAccess = legacyNetworkAccess; - } - - current(agent) { - if (!agent?.session) throw new Error('DshPermissionView.current requires a live DSH Agent'); - const presets = requireService(this.ctx, 'permissionPresets'); - const sandboxPolicy = requireService(this.ctx, 'sandboxPolicy'); - const approval = requireService(this.ctx, 'approval'); - const session = agent.session; - - const preset = presets.current(session.events); - const options = [ - ...presets.names.map((name) => presets.optionOf(name)), - ...(preset === 'custom' ? [presets.optionOf('custom')] : []) - ]; - const resolvedSandbox = sandboxPolicy.resolve({ session }); - const approvalPolicy = approval.overrideOf(session) ?? approval.config?.policy ?? 'ask'; - - let sandbox; - if (resolvedSandbox.mode === 'danger-full-access') { - sandbox = { type: 'dangerFullAccess' }; - } else if (resolvedSandbox.mode === 'read-only' || resolvedSandbox.mode === 'workspace-write') { - sandbox = { type: 'externalSandbox', networkAccess: this.legacyNetworkAccess }; - } else { - throw new Error(`Unsupported DSH sandbox mode: ${String(resolvedSandbox.mode)}`); - } - - return { - preset, - options, - dsh: { - sandboxMode: resolvedSandbox.mode, - workspaceRoot: resolvedSandbox.workspaceRoot, - approvalPolicy - }, - codex: { - approvalPolicy: codexApprovalPolicy(approvalPolicy), - approvalsReviewer: 'user', - sandbox - } - }; - } - - set(agent, presetName) { - if (!agent?.session) throw new Error('DshPermissionView.set requires a live DSH Agent'); - const presets = requireService(this.ctx, 'permissionPresets'); - presets.set(agent.session, presetName); - } -} - -export function mapDshApprovalOutcomeToCodexDecision(outcome) { - switch (outcome) { - case 'allowed-once': - return 'accept'; - case 'rejected': - case 'unavailable': - return 'decline'; - case 'cancelled': - return 'cancel'; - default: - throw new Error(`Unknown DSH approval outcome: ${String(outcome)}`); - } -} - -export function mapCodexDecisionToDshApprovalOutcome(decision) { - switch (decision) { - case 'accept': - return 'allowed-once'; - case 'decline': - return 'rejected'; - case 'cancel': - return 'cancelled'; - case 'acceptForSession': - throw new Error('DSH has no session-wide approval grant; DSHX must not offer acceptForSession'); - default: - throw new Error('Codex approval decision has no faithful DSH one-shot mapping'); - } -} diff --git a/.release/dshx-linux-x64/src/dsh/plan-presentation.mjs b/.release/dshx-linux-x64/src/dsh/plan-presentation.mjs deleted file mode 100644 index e1d40893..00000000 --- a/.release/dshx-linux-x64/src/dsh/plan-presentation.mjs +++ /dev/null @@ -1,55 +0,0 @@ -export function codexPlanTarget(collaborationMode) { - if (!collaborationMode || typeof collaborationMode !== 'object' || Array.isArray(collaborationMode)) { - throw new Error('DSHX collaborationMode must be a Codex collaboration mode object'); - } - if (collaborationMode.mode === 'plan') return true; - if (collaborationMode.mode === 'default') return false; - throw new Error(`DSHX cannot map Codex collaboration mode ${JSON.stringify(collaborationMode.mode)} to DSH plan mode`); -} - -export function effectiveDshPlanState(state) { - if (typeof state?.pending === 'boolean') return state.pending; - return Boolean(state?.active); -} - -export function codexCollaborationMode({ model, reasoningEffort, active }) { - return { - mode: active ? 'plan' : 'default', - settings: { - model, - reasoning_effort: reasoningEffort ?? null, - // DSH owns plan guidance. Never copy Codex developer instructions into - // the Harness request just to satisfy a presentation protocol shape. - developer_instructions: null - } - }; -} - -export function threadSettingsUpdatedNotification({ threadId, response, planState }) { - const active = effectiveDshPlanState(planState); - return { - method: 'thread/settings/updated', - params: { - threadId, - threadSettings: { - cwd: response.cwd, - approvalPolicy: response.approvalPolicy, - approvalsReviewer: response.approvalsReviewer, - sandboxPolicy: response.sandbox, - activePermissionProfile: response.activePermissionProfile ?? null, - model: response.model, - modelProvider: response.modelProvider, - serviceTier: response.serviceTier ?? null, - effort: response.reasoningEffort ?? null, - summary: null, - collaborationMode: codexCollaborationMode({ - model: response.model, - reasoningEffort: response.reasoningEffort, - active - }), - multiAgentMode: response.multiAgentMode ?? 'explicitRequestOnly', - personality: null - } - } - }; -} diff --git a/.release/dshx-linux-x64/src/dsh/presentation-plugin.mjs b/.release/dshx-linux-x64/src/dsh/presentation-plugin.mjs deleted file mode 100644 index 4f379347..00000000 --- a/.release/dshx-linux-x64/src/dsh/presentation-plugin.mjs +++ /dev/null @@ -1,71 +0,0 @@ -import z from '@deepseek-ai/schemastery'; -import { startDshxLocalServer } from './local-server.mjs'; - -/** - * dshx-presentation — the surface's transport host row. - * - * Loaded by the Cordis loader through the bundle patch (no dynamic mounting): - * it starts the packaged bridge + adapter transport against the already-booted - * official composition Context, publishes the endpoint as the - * `dshxPresentation` service, and returns the transport closer as its - * disposer. Teardown authority remains the Cordis root Fiber. - * - * Launch inputs arrive exclusively from the injected `dshxStartup` service - * (see startup-plugin.mjs) — the official three-stage pattern — so this module - * carries no environment or path policy of its own. - */ - -/** Stable Cordis plugin name. */ -export const name = 'dshx-presentation'; - -/** The startup row's service is a hard prerequisite for the transport. */ -export const inject = ['dshxStartup']; - -/** Static overrides straight from the patch row; everything else flows via dshxStartup. */ -export const Config = z.object({ - socketRoot: z.string() -}); - -/** Service key published on the Context after the endpoint is ready. */ -export const SERVICE_KEY = 'dshxPresentation'; - -/** Test seam mirroring the official packages' `internals` convention. */ -export const internals = { start: startDshxLocalServer }; - -export async function apply(ctx, config = {}) { - if (!ctx || typeof ctx.provide !== 'function') { - throw new Error('dshx-presentation requires a Cordis Context with provide()'); - } - const launch = ctx.dshxStartup; - if (!launch || typeof launch.home !== 'string') { - throw new Error('dshx-presentation requires the dshxStartup service (mount the dshx-startup row first)'); - } - const debug = launch.debug === true; - const log = debug ? (message) => process.stderr.write(`[dshx] ${message}\n`) : () => {}; - - const server = await internals.start({ - cwd: launch.cwd, - home: launch.home, - version: launch.version, - bridgeCommand: launch.bridgeCommand, - socketRoot: config.socketRoot, - // The composition Context already exists; never double-boot. Root-fiber - // disposal stays owned by the composition, so the transport must not - // dispose the runtime it lives in (double teardown would re-enter the - // Fiber from inside its own disposer). - runtime: ctx, - disposeRuntimeOnClose: false, - log - }); - - ctx.provide(SERVICE_KEY, { - path: server.path, - url: server.url, - close: server.close, - tuiCommand: launch.tuiCommand - }); - return server.close; -} - -/** Bundle-shaped export consumed by the loader through the patch row. */ -export const plugin = { name, inject, Config, apply }; diff --git a/.release/dshx-linux-x64/src/dsh/profile-bootstrap.mjs b/.release/dshx-linux-x64/src/dsh/profile-bootstrap.mjs deleted file mode 100644 index 165b8b4e..00000000 --- a/.release/dshx-linux-x64/src/dsh/profile-bootstrap.mjs +++ /dev/null @@ -1,99 +0,0 @@ -import fs from 'node:fs'; -import os from 'node:os'; -import path from 'node:path'; -import process from 'node:process'; -import { spawnSync } from 'node:child_process'; -import { createRequire } from 'node:module'; - -/** - * Shared bootstrap over the official DSH plugin machinery. - * - * The surface ships as a standard profile bundle; every entry point (the - * zero-argument CLI, the smoke scripts, CI) ensures the selected profile - * carries this exact package version by running the official - * `dsh plugin --profile

add ` command, which owns profile - * initialization, pnpm installation and bundles reconciliation. - */ - -/** Resolve the DSH home directory exactly like the official launcher. */ -export function dshHomeDir(environment = process.env) { - return environment.DSH_HOME || path.join(os.homedir(), '.dsh'); -} - -export function profileManifestPath(profileName, environment = process.env) { - return path.join(dshHomeDir(environment), 'profiles', profileName, 'package.json'); -} - -/** - * How to invoke the official dsh CLI: an explicit override wins, a global - * `dsh` on PATH is next, and a dependency-local `lib/bin.js` (always present - * after npm ci) keeps CI and fresh checkouts working without any global - * installation. - */ -export function resolveDshInvocation(fromDirectory = process.cwd(), environment = process.env) { - if (environment.DSHX_DSH_BIN) { - return { command: process.execPath, args: [environment.DSHX_DSH_BIN] }; - } - try { - const anchor = createRequire(path.join(fromDirectory, 'package.json')).resolve( - '@deepseek-ai/dsh/package.json' - ); - const cli = path.join(path.dirname(anchor), 'lib', 'bin.js'); - if (fs.existsSync(cli)) return { command: process.execPath, args: [cli] }; - } catch { - // Not installed locally; fall through to PATH lookup. - } - return { command: 'dsh', args: [] }; -} - -/** A profile satisfies bootstrap when it pins this exact version as a bundle layer. */ -export function profileSatisfied(manifest, { name, version }) { - if (!manifest || typeof manifest !== 'object') return false; - const bundles = manifest.dsh?.profile?.bundles ?? []; - const dependencies = manifest.dependencies ?? {}; - return dependencies[name] === version && bundles.includes(name); -} - -/** - * Ensure `profileName` exists and carries `{name}@{version}` from - * `packageRoot` as an activated bundle layer. Idempotent: satisfied profiles - * are left untouched, honoring DSHX_SKIP_PROFILE_BOOTSTRAP=1 for offline runs. - */ -export function ensureProfileInstalled({ - packageRoot, - name, - version, - profile = 'tui', - environment = process.env, - spawnSyncImpl = spawnSync -} = {}) { - let satisfied = false; - try { - satisfied = profileSatisfied(JSON.parse(fs.readFileSync(profileManifestPath(profile, environment), 'utf8')), { - name, - version - }); - } catch { - // Missing or unreadable manifest: the official command initializes it. - } - if (satisfied) return { profile, action: 'already-installed' }; - if (environment.DSHX_SKIP_PROFILE_BOOTSTRAP === '1') { - return { profile, action: 'skipped' }; - } - - const { command, args } = resolveDshInvocation(packageRoot, environment); - const result = spawnSyncImpl( - command, - [...args, 'plugin', '--profile', profile, 'add', packageRoot], - { stdio: 'inherit', shell: process.platform === 'win32' } - ); - if (result.error?.code === 'ENOENT') { - throw new Error( - "official 'dsh' CLI not found (looked up DSHX_DSH_BIN, @deepseek-ai/dsh dependency and PATH); install DeepSeek Harness to manage the DSHX surface profile" - ); - } - if (result.status !== 0) { - throw new Error(`failed to install ${name} into profile '${profile}' via dsh plugin add (exit ${result.status ?? '?'})`); - } - return { profile, action: 'installed' }; -} diff --git a/.release/dshx-linux-x64/src/dsh/runtime-boot.mjs b/.release/dshx-linux-x64/src/dsh/runtime-boot.mjs deleted file mode 100644 index ab86e985..00000000 --- a/.release/dshx-linux-x64/src/dsh/runtime-boot.mjs +++ /dev/null @@ -1,270 +0,0 @@ -import { readFileSync, writeFileSync } from 'node:fs'; -import { createRequire } from 'node:module'; -import { dirname, join, resolve } from 'node:path'; -import { fileURLToPath } from 'node:url'; -import { - boot, - composeEntries, - healProfilesModuleFallback, - loadLayeredEnv, - loadOptionalPatches, - loadProfile, - PROFILE_PATCH_FILENAME, - watchUserPatches -} from '@deepseek-ai/dsh-app-boot'; -import { DSH_LAUNCH_ENVIRONMENT_KEY } from '@deepseek-ai/dsh-launch-environment'; - -const NAME = 'dshx'; -const DSH_PROFILE_BIN_NAME = 'dsh'; -const DEFAULT_PROFILE = 'tui'; -const PROFILE_ROOT_FILENAME = 'cordis.yml'; -// The supported official DSH line. Single source of truth: the exact -// @deepseek-ai/dsh peerDependency declared in this package manifest. -const PACKAGE_ROOT = resolve(dirname(fileURLToPath(import.meta.url)), '../..'); -const SUPPORTED_DSH_LINE = JSON.parse( - readFileSync(join(PACKAGE_ROOT, 'package.json'), 'utf8') -).peerDependencies['@deepseek-ai/dsh']; -// Match the official `dsh` launcher's profile-root contract: this file is only -// the Loader/include base anchor. The real user-owned configuration is carried -// by the profile's `cordis.patch.yml` plus `$DSH_HOME/cordis.patch.yml`. -// Rewriting this empty root on every boot is intentional DSH behavior and -// prevents Loader tree write-back from becoming a second persisted config. -const PROFILE_ROOT_CONFIG = `# DSHX uses the same empty profile root contract as the official dsh launcher.\n# The effective tree is composed from DSH bundle and patch layers.\n# Edit cordis.patch.yml, not this file.\n[]\n`; -// The DSHX surface arrives as a real bundle layer: the package manifest -// declares `dsh.bundle.patch`, so the official loader composes our rows and -// surface locks from the installed profile. This module owns no patch of its -// own; launcher patches stay limited to installation-equivalent environment -// wiring (agent preset roots, telemetry switch). - -function installationAnchor() { - return createRequire(import.meta.url).resolve('@deepseek-ai/dsh/package.json'); -} - -/** - * Report which official DSH line this surface was built and tested against, - * compared with the installation that will actually boot. Ecosystem - * convention: bundles declare compatibility through peer ranges and never - * block the host, so a mismatch is a loud one-shot warning, not an error. - */ -let dshLineWarned = false; -export function reportDshLineCompatibility( - anchor = installationAnchor(), - notify = (message) => process.stderr.write(`${message}\n`) -) { - let installed; - try { - installed = JSON.parse(readFileSync(anchor, 'utf8')).version; - } catch { - return { installed: undefined, supported: SUPPORTED_DSH_LINE, compatible: undefined }; - } - const compatible = installed === SUPPORTED_DSH_LINE; - if (!compatible && !dshLineWarned) { - dshLineWarned = true; - notify( - `[dshx] running against untested official DeepSeek Harness ${installed} ` + - `(tested line: ${SUPPORTED_DSH_LINE}); proceeding — report oddities upstream if any appear` - ); - } - return { installed, supported: SUPPORTED_DSH_LINE, compatible }; -} - -function selectedProfile(explicit) { - const value = explicit ?? process.env.DSHX_PROFILE ?? DEFAULT_PROFILE; - if (typeof value !== 'string' || value.trim().length === 0) { - throw new Error('dshx: DSH profile name must be non-empty'); - } - return value.trim(); -} - -function profileHome(profile) { - return dirname(dirname(profile.dir)); -} - -function homePatchPath(profile) { - return join(profileHome(profile), PROFILE_PATCH_FILENAME); -} - -function shippedAgentPresetPatch(entries, installAnchor) { - const agentPresets = entries.find((entry) => entry.id === 'agent-presets'); - if (!agentPresets) return []; - return [{ - id: 'agent-presets', - config: { - ...(agentPresets.config ?? {}), - roots: [{ path: join(dirname(installAnchor), 'config', 'agent-presets'), trust: 'system' }] - } - }]; -} - -function telemetryPatch(entries) { - if (!process.env.DSH_TELEMETRY_DISABLED) return []; - if (!entries.some((entry) => entry.id === 'session-telemetry-otel')) return []; - return [{ id: 'session-telemetry-otel', disabled: true }]; -} - -/** - * Load the exact official DSH profile layers that DSHX presents. - * - * Order remains DSH-owned: profile bundle layers -> profile user patch -> - * $DSH_HOME/cordis.patch.yml. The DSHX surface itself is one of the bundle - * layers (`dsh.bundle.patch`); the launcher adds only installation-equivalent - * environment patches on top. Out-of-tree profile plugins resolve from the - * profile directory through DSH's own healed module fallback. - */ -export function dshxRuntimeProfile({ - profile: explicitProfile, - installAnchor = installationAnchor(), - home, - overlays = [] -} = {}) { - const profileName = selectedProfile(explicitProfile); - reportDshLineCompatibility(installAnchor); - healProfilesModuleFallback(installAnchor, home); - const profile = loadProfile(DSH_PROFILE_BIN_NAME, profileName, installAnchor, home); - const rootConfig = join(profile.dir, PROFILE_ROOT_FILENAME); - // Official DSH deliberately rewrites this empty include root before boot. - // Never write `profile.patchPath` or the home patch here: those are the - // authoritative user configuration layers and are read-only to DSHX. - writeFileSync(rootConfig, PROFILE_ROOT_CONFIG); - - const bundlePatches = profile.layers.flatMap((layer) => layer.patches); - const homePatches = loadOptionalPatches(DSH_PROFILE_BIN_NAME, homePatchPath(profile)) ?? []; - const beforeLauncher = composeEntries([[...bundlePatches, ...profile.patches, ...homePatches]]); - const launcherPatches = [ - ...shippedAgentPresetPatch(beforeLauncher, installAnchor), - ...telemetryPatch(beforeLauncher), - ...structuredClone(overlays) - ]; - - return { - name: profileName, - profile, - rootConfig, - installAnchor, - homePatchPath: homePatchPath(profile), - patches: [ - ...structuredClone(bundlePatches), - ...structuredClone(profile.patches), - ...structuredClone(homePatches), - ...launcherPatches - ] - }; -} - -export function dshxRuntimePatches(options = {}) { - return dshxRuntimeProfile(options).patches; -} - -export function dshxRuntimeEntries(options = {}) { - return composeEntries([dshxRuntimePatches(options)]); -} - -async function installProfileWatchers(ctx, options) { - if (ctx.get('loader') == null) { - throw new Error('dshx: official DSH profile boot has no Loader for profile hot reload'); - } - if (ctx.get('hmr') == null) { - if (ctx.get('timer') == null) { - await ctx.loader.create({ name: '@deepseek-ai/cordis-plugin-timer' }); - } - await ctx.loader.create({ name: '@deepseek-ai/cordis-plugin-hmr', config: { root: [] } }); - } - - const current = () => dshxRuntimeProfile(options).patches; - const composition = dshxRuntimeProfile(options); - await watchUserPatches(ctx, { - binName: NAME, - filename: composition.profile.patchPath, - compose: () => current() - }); - await watchUserPatches(ctx, { - binName: NAME, - filename: composition.homePatchPath, - compose: () => current() - }); -} - -async function disposeOfficialContext(ctx) { - if (!ctx) return; - if (typeof ctx.fiber?.dispose !== 'function') { - throw new Error('dshx: official DSH Context has no root fiber disposal contract'); - } - await ctx.fiber.dispose(); -} - -function attachPresentationLifetime(ctx) { - // Cordis Context intentionally owns teardown through its root Fiber rather - // than a Context.dispose() method. DSHX keeps its launcher/local-server - // lifetime API small by exposing a non-enumerable alias that delegates to - // that official root-fiber contract; no runtime service is replaced. - Object.defineProperty(ctx, 'dispose', { - configurable: true, - enumerable: false, - value: () => disposeOfficialContext(ctx) - }); - return ctx; -} - -/** - * Boot the selected official Harness profile in-process and return its root Context. - * DSHX owns only presentation lifetime. Project and DSH-home environment and - * live patch behavior intentionally follow the official DSH profile launcher. - */ -export async function bootDshxRuntime({ - cwd = process.cwd(), - profile, - environment = loadLayeredEnv(DSH_PROFILE_BIN_NAME, cwd), - overlays = [], - home, - watch = true -} = {}) { - const options = { profile, overlays, home }; - const composition = dshxRuntimeProfile(options); - let ctx; - try { - ctx = await boot( - NAME, - composition.rootConfig, - structuredClone(composition.patches), - (hostCtx) => { - hostCtx.provide(DSH_LAUNCH_ENVIRONMENT_KEY, environment); - } - // No bareModuleBaseUrl: match the official CLI so row names resolve - // from the profile directory (Node walks /node_modules then - // the healed $DSH_HOME/profiles/node_modules fallback). Anchoring every - // import to the installation would make third-party surface bundles - // — including ours — unresolvable. - ); - attachPresentationLifetime(ctx); - if (watch) await installProfileWatchers(ctx, options); - return ctx; - } catch (error) { - if (ctx) { - try { - await disposeOfficialContext(ctx); - } catch (disposeError) { - if (error && typeof error === 'object') { - try { Object.defineProperty(error, 'dshxCleanupError', { value: disposeError }); } catch {} - } - } - } - throw error; - } -} - -export const runtimeInternals = { - NAME, - DSH_PROFILE_BIN_NAME, - DEFAULT_PROFILE, - PROFILE_ROOT_FILENAME, - PROFILE_ROOT_CONFIG, - SUPPORTED_DSH_LINE, - reportDshLineCompatibility, - installationAnchor, - selectedProfile, - profileHome, - homePatchPath, - installProfileWatchers, - disposeOfficialContext, - attachPresentationLifetime -}; diff --git a/.release/dshx-linux-x64/src/dsh/session-fork.mjs b/.release/dshx-linux-x64/src/dsh/session-fork.mjs deleted file mode 100644 index 0482b66e..00000000 --- a/.release/dshx-linux-x64/src/dsh/session-fork.mjs +++ /dev/null @@ -1,55 +0,0 @@ -function turnNumber(turnId) { - const match = /^dsh-turn-(\d+)$/.exec(String(turnId ?? '')); - if (!match) throw new Error(`DSHX cannot map Codex turn id to DSH turn: ${JSON.stringify(turnId)}`); - const value = Number(match[1]); - if (!Number.isSafeInteger(value) || value < 0) throw new Error(`Invalid DSH turn id: ${turnId}`); - return value; -} - -function completedTurnEnd(events, turn) { - return (events ?? []).find((event) => event?.type === 'turn/end' && event.data?.turn === turn); -} - -/** - * Translate Codex's fork presentation anchors into the one `atSeq` hint owned - * by DSH Host `sessions.fork`. This function deliberately does NOT select or - * copy a seed, decide lineage, inherit model state, or create a Session. - */ -export function codexForkAtSeq(events = [], { lastTurnId, beforeTurnId } = {}) { - if (lastTurnId != null && beforeTurnId != null) { - throw new Error('thread/fork lastTurnId and beforeTurnId are mutually exclusive'); - } - - if (lastTurnId != null) { - const turn = turnNumber(lastTurnId); - const end = completedTurnEnd(events, turn); - if (!end || !Number.isInteger(end.seq)) { - throw new Error(`DSH session has no completed ${lastTurnId}`); - } - return end.seq; - } - - if (beforeTurnId != null) { - const turn = turnNumber(beforeTurnId); - const start = (events ?? []).find((event) => event?.type === 'turn/start' && event.data?.turn === turn); - if (!start || !Number.isInteger(start.seq)) { - throw new Error(`DSH session has no ${beforeTurnId}`); - } - const priorEnds = (events ?? []).filter((event) => - event?.type === 'turn/end' - && Number.isInteger(event.seq) - && event.seq < start.seq - ); - const prior = priorEnds.at(-1); - if (!prior) { - throw new Error('DSH Host fork cannot represent a Codex beforeTurnId before the first completed turn'); - } - return prior.seq; - } - - // Omission is meaningful: the official DSH Host chooses the latest completed - // turn, including its own handling for live/cold sessions and open tails. - return undefined; -} - -export const forkInternals = { turnNumber, completedTurnEnd }; diff --git a/.release/dshx-linux-x64/src/dsh/session-projector.mjs b/.release/dshx-linux-x64/src/dsh/session-projector.mjs deleted file mode 100644 index 8fe644ab..00000000 --- a/.release/dshx-linux-x64/src/dsh/session-projector.mjs +++ /dev/null @@ -1,427 +0,0 @@ -const nowSeconds = () => Math.floor(Date.now() / 1000); -const nowMillis = () => Date.now(); - -function parseJsonOrString(value) { - if (typeof value !== 'string') return value ?? null; - try { return JSON.parse(value); } catch { return value; } -} - -function visibleText(message) { - return (message?.content ?? []) - .filter((block) => block?.type === 'text' && typeof block.text === 'string') - .map((block) => block.text) - .join(''); -} - -function reasoningContent(message) { - return (message?.content ?? []) - .filter((block) => block?.type === 'reasoning' && typeof block.text === 'string') - .map((block) => block.text); -} - -function toolResultCallId(data) { - const sourceId = data?.message?.source?.kind === 'tool' ? data.message.source.callId : undefined; - if (sourceId !== undefined) return sourceId; - const block = data?.message?.content?.find?.((entry) => entry?.type === 'tool-result'); - return block?.toolCallId; -} - -function toolResultFailed(data) { - const block = data?.message?.content?.find?.((entry) => entry?.type === 'tool-result'); - return Boolean(block?.isError ?? data?.error); -} - -function mapTurnStatus(reason) { - switch (reason?.kind) { - case 'completed': return 'completed'; - case 'aborted': - case 'interrupted': return 'interrupted'; - default: return 'failed'; - } -} - -function mapPlanStatus(status) { - if (status === 'in_progress') return 'inProgress'; - if (status === 'completed') return 'completed'; - return 'pending'; -} - -function turnRecord(id, status, startedAt, completedAt = null, error = null) { - return { - id, - items: [], - itemsView: 'full', - status, - error, - startedAt, - completedAt, - durationMs: startedAt != null && completedAt != null - ? Math.max(0, (completedAt - startedAt) * 1000) - : null - }; -} - -function compactionError(message) { - return message == null - ? null - : { message: String(message), codexErrorInfo: null, additionalDetails: null }; -} - -/** - * Stateful presentation projection of official DSH Session events. - * Durable truth stays in DSH; all maps here are disposable UI correlation. - */ -export class DshSessionProjector { - constructor({ threadId, sessionId = threadId, toolPresentation = null } = {}) { - if (!threadId) throw new Error('DshSessionProjector requires threadId'); - this.threadId = threadId; - this.sessionId = sessionId; - this.toolPresentation = toolPresentation; - this.turns = new Map(); - this.assistantItems = new Map(); - this.reasoningItems = new Map(); - this.tools = new Map(); - this.compactions = new Map(); - this.currentTurn = null; - this.latestHeader = null; - this.latestContext = null; - } - - project(event) { - if (!event || typeof event.type !== 'string') return []; - switch (event.type) { - case 'turn/start': return this.turnStarted(event); - case 'turn/end': return this.turnEnded(event); - case 'assistant/chunk': return this.assistantChunk(event); - case 'assistant/message': return this.assistantMessage(event); - case 'tool/call': return this.toolCall(event); - case 'tool/result': return this.toolResult(event); - case 'todo/write': return this.todoWrite(event); - case 'compaction/start': return this.compactionStarted(event); - case 'compaction/summary': return this.compactionSummarized(event); - case 'compaction/end': return this.compactionEnded(event); - case 'request/header': - this.latestHeader = event.data?.header ?? null; - return []; - case 'request/context': - this.latestContext = event.data ?? null; - return []; - default: - return []; - } - } - - turnStarted(event) { - const dshTurn = event.data?.turn; - if (!Number.isInteger(dshTurn)) return []; - const turnId = `dsh-turn-${dshTurn}`; - const startedAt = Number.isFinite(event.time) ? Math.floor(event.time / 1000) : nowSeconds(); - this.turns.set(dshTurn, { id: turnId, startedAt }); - this.currentTurn = dshTurn; - return [{ method: 'turn/started', params: { threadId: this.threadId, turn: turnRecord(turnId, 'inProgress', startedAt) } }]; - } - - turnEnded(event) { - const dshTurn = event.data?.turn; - const state = this.turns.get(dshTurn); - if (!state) return []; - const reason = event.data?.reason; - const status = mapTurnStatus(reason); - const completedAt = Number.isFinite(event.time) ? Math.floor(event.time / 1000) : nowSeconds(); - const error = status === 'failed' && reason?.kind === 'error' - ? { message: reason.error?.message ?? 'DSH turn failed', codexErrorInfo: null, additionalDetails: null } - : null; - if (this.currentTurn === dshTurn) this.currentTurn = null; - return [{ method: 'turn/completed', params: { threadId: this.threadId, turn: turnRecord(state.id, status, state.startedAt, completedAt, error) } }]; - } - - compactionStarted(event) { - const { compactionId, turn } = event.data ?? {}; - if (typeof compactionId !== 'string' || compactionId.length === 0) return []; - const startedAt = Number.isFinite(event.time) ? Math.floor(event.time / 1000) : nowSeconds(); - const startedAtMs = Number.isFinite(event.time) ? event.time : nowMillis(); - const item = { type: 'contextCompaction', id: `dsh-compaction-${compactionId}` }; - let turnId; - let manual = false; - const events = []; - if (Number.isInteger(turn)) { - const state = this.turns.get(turn); - if (!state) return []; - turnId = state.id; - } else if (turn === null) { - manual = true; - turnId = `dsh-maintenance-compaction-${compactionId}`; - events.push({ - method: 'turn/started', - params: { threadId: this.threadId, turn: turnRecord(turnId, 'inProgress', startedAt) } - }); - } else { - return []; - } - this.compactions.set(compactionId, { - compactionId, - turnId, - manual, - startedAt, - item, - summarized: false - }); - events.push({ - method: 'item/started', - params: { threadId: this.threadId, turnId, startedAtMs, item } - }); - return events; - } - - compactionSummarized(event) { - const compactionId = event.data?.compactionId; - const state = this.compactions.get(compactionId); - if (state) state.summarized = true; - return []; - } - - compactionEnded(event) { - const { compactionId, error } = event.data ?? {}; - const state = this.compactions.get(compactionId); - if (!state) return []; - this.compactions.delete(compactionId); - const completedAtMs = Number.isFinite(event.time) ? event.time : nowMillis(); - const completedAt = Math.floor(completedAtMs / 1000); - const events = [{ - method: 'item/completed', - params: { - threadId: this.threadId, - turnId: state.turnId, - completedAtMs, - item: state.item - } - }]; - if (state.manual) { - events.push({ - method: 'turn/completed', - params: { - threadId: this.threadId, - turn: turnRecord( - state.turnId, - error == null ? 'completed' : 'failed', - state.startedAt, - completedAt, - compactionError(error) - ) - } - }); - } - return events; - } - - assistantChunk(event) { - const { turn, step, chunk } = event.data ?? {}; - if (!Number.isInteger(turn) || !Number.isInteger(step) || !chunk) return []; - const turnState = this.turns.get(turn); - if (!turnState) return []; - - if (chunk.type === 'reasoning-delta' && typeof chunk.text === 'string') { - const key = `${turn}:${step}`; - let item = this.reasoningItems.get(key); - const events = []; - if (!item) { - item = { id: `dsh-reasoning-${turn}-${step}`, content: [] }; - this.reasoningItems.set(key, item); - events.push({ - method: 'item/started', - params: { - threadId: this.threadId, - turnId: turnState.id, - startedAtMs: Number.isFinite(event.time) ? event.time : nowMillis(), - item: { type: 'reasoning', id: item.id, summary: [], content: [] } - } - }); - } - const index = Number.isInteger(chunk.index) && chunk.index >= 0 ? chunk.index : 0; - item.content[index] = `${item.content[index] ?? ''}${chunk.text}`; - events.push({ - method: 'item/reasoning/textDelta', - params: { - threadId: this.threadId, - turnId: turnState.id, - itemId: item.id, - delta: chunk.text, - contentIndex: index - } - }); - return events; - } - - if (chunk.type !== 'text-delta' || typeof chunk.text !== 'string') return []; - const key = `${turn}:${step}`; - let item = this.assistantItems.get(key); - const events = []; - if (!item) { - item = { id: `dsh-assistant-${turn}-${step}`, text: '' }; - this.assistantItems.set(key, item); - events.push({ - method: 'item/started', - params: { - threadId: this.threadId, - turnId: turnState.id, - startedAtMs: Number.isFinite(event.time) ? event.time : nowMillis(), - item: { type: 'agentMessage', id: item.id, text: '', phase: null, memoryCitation: null, delivery: null } - } - }); - } - item.text += chunk.text; - events.push({ - method: 'item/agentMessage/delta', - params: { threadId: this.threadId, turnId: turnState.id, itemId: item.id, delta: chunk.text } - }); - return events; - } - - assistantMessage(event) { - const { turn, step, message } = event.data ?? {}; - if (!Number.isInteger(turn) || !Number.isInteger(step) || !message) return []; - const turnState = this.turns.get(turn); - if (!turnState) return []; - const key = `${turn}:${step}`; - const completedAtMs = Number.isFinite(event.time) ? event.time : nowMillis(); - const events = []; - - const finalReasoning = reasoningContent(message); - let reasoning = this.reasoningItems.get(key); - if (reasoning || finalReasoning.length > 0) { - if (!reasoning) { - reasoning = { id: `dsh-reasoning-${turn}-${step}`, content: [] }; - this.reasoningItems.set(key, reasoning); - events.push({ - method: 'item/started', - params: { - threadId: this.threadId, - turnId: turnState.id, - startedAtMs: completedAtMs, - item: { type: 'reasoning', id: reasoning.id, summary: [], content: [] } - } - }); - } - reasoning.content = finalReasoning.length > 0 ? finalReasoning : reasoning.content; - events.push({ - method: 'item/completed', - params: { - threadId: this.threadId, - turnId: turnState.id, - completedAtMs, - item: { type: 'reasoning', id: reasoning.id, summary: [], content: reasoning.content } - } - }); - } - - const finalText = visibleText(message); - let item = this.assistantItems.get(key); - if (!item && finalText.length > 0) { - item = { id: `dsh-assistant-${turn}-${step}`, text: '' }; - this.assistantItems.set(key, item); - events.push({ - method: 'item/started', - params: { - threadId: this.threadId, - turnId: turnState.id, - startedAtMs: completedAtMs, - item: { type: 'agentMessage', id: item.id, text: '', phase: null, memoryCitation: null, delivery: null } - } - }); - } - if (item) { - item.text = finalText; - events.push({ - method: 'item/completed', - params: { - threadId: this.threadId, - turnId: turnState.id, - completedAtMs, - item: { type: 'agentMessage', id: item.id, text: finalText, phase: null, memoryCitation: null, delivery: null } - } - }); - } - return events; - } - - toolCall(event) { - const { turn, callId, name, arguments: rawArguments } = event.data ?? {}; - const turnState = this.turns.get(turn); - if (!turnState || !callId || typeof name !== 'string') return []; - const startedAtMs = Number.isFinite(event.time) ? event.time : nowMillis(); - - let item; - if (this.toolPresentation) { - ({ item } = this.toolPresentation.start({ - turnId: turnState.id, - callId, - name, - rawArguments, - startedAtMs - })); - } else { - item = { - type: 'dynamicToolCall', - id: `dsh-tool-${String(callId)}`, - namespace: null, - tool: name, - arguments: parseJsonOrString(rawArguments), - status: 'inProgress', - contentItems: null, - success: null, - durationMs: null - }; - this.tools.set(String(callId), { item, turnId: turnState.id, startedAt: startedAtMs }); - } - - return [{ method: 'item/started', params: { threadId: this.threadId, turnId: turnState.id, startedAtMs, item } }]; - } - - toolResult(event) { - const callId = toolResultCallId(event.data); - if (callId === undefined) return []; - const completedAtMs = Number.isFinite(event.time) ? event.time : nowMillis(); - - if (this.toolPresentation) { - const completed = this.toolPresentation.complete({ callId, resultData: event.data, completedAtMs }); - if (!completed) return []; - return [{ - method: 'item/completed', - params: { - threadId: this.threadId, - turnId: completed.state.turnId, - completedAtMs, - item: completed.item - } - }]; - } - - const state = this.tools.get(String(callId)); - if (!state) return []; - const failed = toolResultFailed(event.data); - const completed = { - ...state.item, - status: failed ? 'failed' : 'completed', - success: !failed, - durationMs: Math.max(0, completedAtMs - state.startedAt) - }; - this.tools.delete(String(callId)); - return [{ method: 'item/completed', params: { threadId: this.threadId, turnId: state.turnId, completedAtMs, item: completed } }]; - } - - todoWrite(event) { - if (this.currentTurn == null) return []; - const turnState = this.turns.get(this.currentTurn); - if (!turnState) return []; - const todos = Array.isArray(event.data?.todos) ? event.data.todos : []; - return [{ - method: 'turn/plan/updated', - params: { - threadId: this.threadId, - turnId: turnState.id, - explanation: null, - plan: todos.map((todo) => ({ step: String(todo.content ?? ''), status: mapPlanStatus(todo.status) })) - } - }]; - } -} diff --git a/.release/dshx-linux-x64/src/dsh/skills.mjs b/.release/dshx-linux-x64/src/dsh/skills.mjs deleted file mode 100644 index a5ec249b..00000000 --- a/.release/dshx-linux-x64/src/dsh/skills.mjs +++ /dev/null @@ -1,67 +0,0 @@ -import path from 'node:path'; - -function requireSkills(ctx) { - const skills = ctx.get('skills'); - if (skills === undefined) throw new Error('DSHX requires DSH service: skills'); - return skills; -} - -function codexScope(source) { - if (source === 'project-dsh' || source === 'project-agents') return 'repo'; - if (source === 'user-dsh' || source === 'user-agents') return 'user'; - return 'system'; -} - -/** - * Project the subset of DSH skills that Codex's filesystem-oriented skill UI - * can represent faithfully. DSH remains the complete skill registry; a remote - * or runtime skill with no absolute file path is not fabricated into a path. - */ -export async function dshSkillsListEntry({ ctx, cwd, scope, diagnostics = () => {} }) { - const absoluteCwd = path.resolve(cwd); - const skills = requireSkills(ctx); - const options = { cwd: absoluteCwd, ...(scope === undefined ? {} : { scope }) }; - const snapshot = await skills.snapshot(options); - const data = []; - const errors = []; - - if (snapshot.complete !== true) { - errors.push({ - path: absoluteCwd, - message: 'DSH skill discovery was incomplete; available candidates are shown without claiming the catalog is authoritative' - }); - } - - for (const summary of snapshot.skills ?? []) { - if (summary?.invocation?.userInvocable !== true) continue; - try { - const definition = await skills.get(summary.name, options); - if (!definition) { - errors.push({ path: summary.name, message: 'DSH skill disappeared before it could be loaded' }); - continue; - } - if (typeof definition.path !== 'string' || !path.isAbsolute(definition.path)) { - // Codex SkillMetadata requires an absolute filesystem path. The DSH - // registry explicitly permits provider-managed skills without one. - diagnostics(`skill ${summary.name} is user-invocable but has no absolute filesystem path; omitted from Codex skill UI`); - continue; - } - data.push({ - name: definition.name, - description: definition.description, - path: definition.path, - scope: codexScope(definition.source), - enabled: true - }); - } catch (error) { - errors.push({ - path: summary.name, - message: error instanceof Error ? error.message : String(error) - }); - } - } - - return { cwd: absoluteCwd, skills: data, errors }; -} - -export const skillInternals = { codexScope }; diff --git a/.release/dshx-linux-x64/src/dsh/startup-plugin.mjs b/.release/dshx-linux-x64/src/dsh/startup-plugin.mjs deleted file mode 100644 index fedacfe3..00000000 --- a/.release/dshx-linux-x64/src/dsh/startup-plugin.mjs +++ /dev/null @@ -1,72 +0,0 @@ -import fs from 'node:fs'; -import os from 'node:os'; -import path from 'node:path'; -import { fileURLToPath } from 'node:url'; -import z from '@deepseek-ai/schemastery'; - -/** - * dshx-startup — the surface's command-line/environment resolution row. - * - * Mirrors the official three-stage launch pattern (see @deepseek-ai/dsh-headless - * `startup`): a tiny host-plane plugin that turns launcher-provided inputs into - * one provided service (`dshxStartup`) so downstream rows stay declarative. - * Inputs come from the documented DSHX_* environment overrides with packaged - * defaults; no argv parsing, so bare `dsh --profile tui` boots identically. - */ - -const PACKAGE_ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../..'); -let cachedVersion; - -/** Stable Cordis plugin name. */ -export const name = 'dshx-startup'; - -/** Environment + packaged defaults only; nothing is a hard service dependency. */ -export const inject = []; - -/** Reserved for future static overrides supplied straight from the patch row. */ -export const Config = z.object({}); - -/** Resolve the package version once from our own manifest. */ -export function resolveVersion() { - cachedVersion ??= JSON.parse(fs.readFileSync(path.join(PACKAGE_ROOT, 'package.json'), 'utf8')).version; - return cachedVersion; -} - -/** Packaged-binary resolution shared by the TUI and the IPC bridge. */ -export function resolvePackagedBinary(baseName, envValue) { - if (envValue) return envValue; - const fileName = process.platform === 'win32' ? `${baseName}.exe` : baseName; - return path.join(PACKAGE_ROOT, 'dist', 'bin', fileName); -} - -/** Compute the launch descriptor published as the `dshxStartup` service. */ -export function resolveLaunchDescriptor(environment = process.env) { - const home = path.resolve( - environment.DSHX_TUI_HOME || path.join(os.homedir(), '.dshx', 'codex-tui') - ); - return { - cwd: process.cwd(), - home, - version: resolveVersion(), - tuiCommand: resolvePackagedBinary('dshx-tui', environment.DSHX_TUI_BIN), - bridgeCommand: resolvePackagedBinary('dshx-ipc-bridge', environment.DSHX_IPC_BRIDGE_BIN), - debug: environment.DSHX_DEBUG === '1' - }; -} - -export function apply(ctx) { - const launch = resolveLaunchDescriptor(); - fs.mkdirSync(launch.home, { recursive: true, mode: 0o700 }); - ctx.provide('dshxStartup', launch); - return undefined; -} - -/** Bundle-shaped export consumed by the loader through the patch row. */ -export const plugin = { name, inject, Config, apply }; - -export const internals = { - PACKAGE_ROOT, - resolveLaunchDescriptor, - resolvePackagedBinary, - resolveVersion -}; diff --git a/.release/dshx-linux-x64/src/dsh/thread-controller.mjs b/.release/dshx-linux-x64/src/dsh/thread-controller.mjs deleted file mode 100644 index 23a550c0..00000000 --- a/.release/dshx-linux-x64/src/dsh/thread-controller.mjs +++ /dev/null @@ -1,205 +0,0 @@ -import { DshSessionProjector } from './session-projector.mjs'; -import { tokenUsageNotification } from './token-usage.mjs'; -import { DshToolPresentationResolver } from './tool-presentation.mjs'; - -function deferred(timeoutMs, label) { - let resolve; - let reject; - let timer; - const promise = new Promise((res, rej) => { - resolve = res; - reject = rej; - timer = setTimeout(() => rej(new Error(`Timed out waiting for ${label}`)), timeoutMs); - }); - return { - promise, - resolve(value) { clearTimeout(timer); resolve(value); }, - reject(error) { clearTimeout(timer); reject(error); } - }; -} - -function usageRelevant(event) { - return event?.type === 'assistant/message' - || event?.type === 'request/context' - || (event?.type === 'assistant/chunk' && event.data?.chunk?.type === 'usage'); -} - -/** - * Owns only the presentation lifetime for one already-created DSH Agent. - * The Agent and Session remain authoritative and are never reconstructed here. - */ -export class DshThreadController { - constructor({ handle, driver, emit = () => {}, turnStartTimeoutMs = 15_000, diagnostics = () => {} }) { - if (!handle?.agent) throw new Error('DshThreadController requires a DSH AgentHandle'); - this.handle = handle; - this.agent = handle.agent; - this.driver = driver; - this.emit = emit; - this.turnStartTimeoutMs = turnStartTimeoutMs; - this.diagnostics = diagnostics; - - this.toolPresentation = typeof this.agent.ctx?.get === 'function' - ? new DshToolPresentationResolver({ - ctx: this.agent.ctx, - agent: this.agent, - threadId: String(this.agent.id), - workspaceCwd: this.agent.session?.header?.cwd ?? process.cwd(), - diagnostics - }) - : null; - - this.projector = new DshSessionProjector({ - threadId: String(this.agent.id), - sessionId: String(this.agent.id), - toolPresentation: this.toolPresentation - }); - this.pendingTurnStart = null; - this.responseGate = null; - this.preparedUserContent = null; - this.lastTokenUsageSignature = null; - this.closed = false; - - const onSessionEvent = (session, event) => this.onSessionEvent(session, event); - this.disposeSessionListener = this.agent.ctx.on('session/event', onSessionEvent); - } - - get threadId() { - return String(this.agent.id); - } - - toolCorrelation(callId) { - return this.toolPresentation?.correlation(callId); - } - - currentLocation() { - const number = this.projector.currentTurn; - if (!Number.isInteger(number)) return undefined; - const turn = this.projector.turns.get(number); - if (!turn) return undefined; - return { threadId: this.threadId, turnId: turn.id }; - } - - /** - * Stage rich Codex input for exactly one existing base-adapter turn/steer call. - * The base adapter still owns all model/cwd/permission/sandbox validation. - */ - prepareUserContent(content) { - if (this.preparedUserContent != null) throw new Error('DSHX rich input slot is already occupied'); - const slot = { content }; - this.preparedUserContent = slot; - return () => { - if (this.preparedUserContent === slot) this.preparedUserContent = null; - }; - } - - consumeUserContent(fallback) { - const slot = this.preparedUserContent; - this.preparedUserContent = null; - return slot?.content ?? fallback; - } - - deliver(notification) { - if (this.responseGate && !this.responseGate.released) { - this.responseGate.buffered.push(notification); - return; - } - this.emit(notification); - } - - maybeProjectTokenUsage(event) { - if (!usageRelevant(event)) return; - const location = this.currentLocation(); - if (!location) return; - try { - const notification = tokenUsageNotification({ - ctx: this.agent.ctx, - session: this.agent.session, - threadId: location.threadId, - turnId: location.turnId - }); - if (!notification) return; - const signature = JSON.stringify(notification.params.tokenUsage); - if (signature === this.lastTokenUsageSignature) return; - this.lastTokenUsageSignature = signature; - this.deliver(notification); - } catch (error) { - this.diagnostics(`token usage projection failed: ${error instanceof Error ? error.message : error}`); - } - } - - onSessionEvent(session, event) { - if (this.closed || session !== this.agent.session) return; - const projected = this.projector.project(event); - for (const notification of projected) { - if (notification.method === 'turn/started' && this.pendingTurnStart) { - const pending = this.pendingTurnStart; - this.pendingTurnStart = null; - const gate = { - firstNotification: notification, - buffered: [], - released: false - }; - this.responseGate = gate; - pending.resolve({ turn: notification.params.turn, gate }); - continue; - } - this.deliver(notification); - } - this.maybeProjectTokenUsage(event); - } - - /** Submit a normal follow-up and wait until DSH itself commits turn/start. */ - async startTurn(fallbackContent) { - if (this.pendingTurnStart || (this.responseGate && !this.responseGate.released)) { - throw new Error('A turn/start request is already awaiting DSHX protocol release'); - } - const content = this.consumeUserContent(fallbackContent); - const pending = deferred(this.turnStartTimeoutMs, 'DSH turn/start'); - this.pendingTurnStart = pending; - try { - this.driver.followup(this.agent, content); - const { turn, gate } = await pending.promise; - return { - turn, - release: () => { - if (gate.released) return; - gate.released = true; - if (this.responseGate === gate) this.responseGate = null; - this.emit(gate.firstNotification); - for (const notification of gate.buffered) this.emit(notification); - gate.buffered.length = 0; - } - }; - } catch (error) { - if (this.pendingTurnStart === pending) this.pendingTurnStart = null; - throw error; - } - } - - steer(fallbackContent) { - this.driver.steer(this.agent, this.consumeUserContent(fallbackContent)); - } - - interrupt(options) { - this.driver.interrupt(this.agent, options); - } - - whenIdle() { - return this.driver.whenIdle(this.agent); - } - - async close() { - if (this.closed) return; - this.closed = true; - this.pendingTurnStart?.reject(new Error('DSHX thread controller closed')); - this.pendingTurnStart = null; - this.preparedUserContent = null; - if (this.responseGate && !this.responseGate.released) { - this.responseGate.released = true; - this.responseGate.buffered.length = 0; - } - this.responseGate = null; - this.disposeSessionListener?.(); - await this.handle.dispose?.(); - } -} diff --git a/.release/dshx-linux-x64/src/dsh/thread-title.mjs b/.release/dshx-linux-x64/src/dsh/thread-title.mjs deleted file mode 100644 index afda2f90..00000000 --- a/.release/dshx-linux-x64/src/dsh/thread-title.mjs +++ /dev/null @@ -1,19 +0,0 @@ -export function foldDshSessionTitle(events = []) { - for (let index = events.length - 1; index >= 0; index -= 1) { - const event = events[index]; - if (event?.type !== 'session/title') continue; - const title = event.data?.title; - if (typeof title === 'string' && title.length > 0) return title; - } - return null; -} - -export function threadNameUpdatedNotification(threadId, title) { - return { - method: 'thread/name/updated', - params: { - threadId: String(threadId), - threadName: title == null ? null : String(title) - } - }; -} diff --git a/.release/dshx-linux-x64/src/dsh/token-usage.mjs b/.release/dshx-linux-x64/src/dsh/token-usage.mjs deleted file mode 100644 index cafce57c..00000000 --- a/.release/dshx-linux-x64/src/dsh/token-usage.mjs +++ /dev/null @@ -1,116 +0,0 @@ -function finiteNonNegative(value) { - return Number.isFinite(value) && value >= 0 ? Number(value) : 0; -} - -function breakdown(usage = {}) { - const inputTokens = finiteNonNegative(usage.inputTokens ?? usage.uncachedInputTokens); - const cachedInputTokens = finiteNonNegative(usage.cacheReadTokens); - const cacheWriteInputTokens = finiteNonNegative(usage.cacheWriteTokens); - const outputTokens = finiteNonNegative(usage.outputTokens); - const reasoningOutputTokens = finiteNonNegative(usage.reasoningTokens); - return { - totalTokens: inputTokens + cachedInputTokens + cacheWriteInputTokens + outputTokens, - inputTokens, - cachedInputTokens, - cacheWriteInputTokens, - outputTokens, - reasoningOutputTokens - }; -} - -function usageSamples(events = []) { - const byStep = new Map(); - let last = null; - let lastTurn = null; - for (const event of events) { - const data = event?.data; - if (!Number.isInteger(data?.turn) || !Number.isInteger(data?.step)) continue; - let usage; - if (event.type === 'assistant/chunk' && data.chunk?.type === 'usage') { - usage = data.chunk.usage; - } else if (event.type === 'assistant/message' && data.usage) { - usage = data.usage; - } - if (!usage) continue; - const sample = { ...usage }; - byStep.set(`${data.turn}:${data.step}`, sample); - last = sample; - lastTurn = data.turn; - } - return { byStep, last, lastTurn }; -} - -function reasoningTotal(events = []) { - const { byStep } = usageSamples(events); - let total = 0; - for (const usage of byStep.values()) total += finiteNonNegative(usage.reasoningTokens); - return total; -} - -function latestContextWindow(events = []) { - for (let index = events.length - 1; index >= 0; index -= 1) { - const event = events[index]; - if (event?.type === 'request/context' && Number.isFinite(event.data?.contextWindow)) { - return Number(event.data.contextWindow); - } - } - return null; -} - -/** - * Read-only presentation snapshot over official DSH session projections. - * DSH token-meter owns accounting; this module only reshapes its values into - * the pinned Codex TUI contract. - */ -export function codexThreadTokenUsage({ ctx, session }) { - const projections = ctx?.get?.('sessionProjections'); - if (!session || !projections?.snapshot) return null; - const snapshot = projections.snapshot(session); - const cumulative = snapshot?.values?.tokenUsage; - if (!cumulative) return null; - - const events = session.events ?? []; - const { last } = usageSamples(events); - const total = breakdown({ - inputTokens: cumulative.uncachedInputTokens, - cacheReadTokens: cumulative.cacheReadTokens, - cacheWriteTokens: cumulative.cacheWriteTokens, - outputTokens: cumulative.outputTokens, - reasoningTokens: reasoningTotal(events) - }); - const contextWindow = Number.isFinite(snapshot?.values?.contextPressure?.contextWindow) - ? Number(snapshot.values.contextPressure.contextWindow) - : latestContextWindow(events); - - return { - total, - last: breakdown(last ?? {}), - modelContextWindow: contextWindow - }; -} - -export function latestTokenUsageTurnId(session) { - const { lastTurn } = usageSamples(session?.events ?? []); - return Number.isInteger(lastTurn) ? `dsh-turn-${lastTurn}` : null; -} - -export function tokenUsageNotification({ ctx, session, threadId, turnId }) { - const tokenUsage = codexThreadTokenUsage({ ctx, session }); - if (!tokenUsage || !threadId || !turnId) return null; - return { - method: 'thread/tokenUsage/updated', - params: { threadId, turnId, tokenUsage } - }; -} - -export function persistedTokenUsageNotification({ ctx, session, threadId }) { - const turnId = latestTokenUsageTurnId(session); - return tokenUsageNotification({ ctx, session, threadId, turnId }); -} - -export const tokenUsageInternals = { - breakdown, - usageSamples, - reasoningTotal, - latestContextWindow -}; diff --git a/.release/dshx-linux-x64/src/dsh/tool-presentation.mjs b/.release/dshx-linux-x64/src/dsh/tool-presentation.mjs deleted file mode 100644 index 4396c471..00000000 --- a/.release/dshx-linux-x64/src/dsh/tool-presentation.mjs +++ /dev/null @@ -1,219 +0,0 @@ -import path from 'node:path'; - -function parseArguments(raw) { - if (typeof raw !== 'string') return raw ?? {}; - try { return JSON.parse(raw); } catch { return { raw }; } -} - -function toolResultFromEvent(data) { - const block = data?.message?.content?.find?.((entry) => entry?.type === 'tool-result'); - return { - content: Array.isArray(block?.content) ? block.content : [], - isError: Boolean(block?.isError ?? data?.error), - ...(data?.meta === undefined ? {} : { meta: data.meta }) - }; -} - -function textContentItems(content) { - const items = []; - for (const block of content ?? []) { - if (block?.type === 'text' && typeof block.text === 'string') { - items.push({ type: 'inputText', text: block.text }); - } - } - return items.length === 0 ? null : items; -} - -function resolveCwd(workspaceCwd, candidate) { - if (!candidate) return workspaceCwd; - return path.isAbsolute(candidate) ? candidate : path.resolve(workspaceCwd, candidate); -} - -function lineCount(text) { - if (text === '') return 0; - return text.split(/\r?\n/).length; -} - -function displayDiff(file) { - // DSH FileDiff may represent a contextual hunk rather than whole-file text. - // Codex only needs display diff text here; avoid fabricating source line numbers. - const oldLines = String(file.oldText ?? '').split(/\r?\n/); - const newLines = String(file.newText ?? '').split(/\r?\n/); - const oldCount = lineCount(String(file.oldText ?? '')); - const newCount = lineCount(String(file.newText ?? '')); - return [ - `--- a/${file.path}`, - `+++ b/${file.path}`, - `@@ -1,${oldCount} +1,${newCount} @@`, - ...oldLines.map((line) => `-${line}`), - ...newLines.map((line) => `+${line}`) - ].join('\n'); -} - -function canUseCodexFileChange(view) { - return view?.card === 'diff' && - Array.isArray(view.diffs) && - view.diffs.length > 0 && - view.diffs.every((diff) => typeof diff?.path === 'string' && diff.oldText !== null); -} - -function fileChangeItem(id, view, status) { - return { - type: 'fileChange', - id, - changes: view.diffs.map((diff) => ({ - path: diff.path, - kind: { type: 'update', move_path: null }, - diff: displayDiff(diff) - })), - status - }; -} - -function dynamicItem(id, toolName, args, status, result = null, durationMs = null) { - return { - type: 'dynamicToolCall', - id, - namespace: null, - tool: toolName, - arguments: args, - status, - contentItems: result ? textContentItems(result.content) : null, - success: result ? !result.isError : null, - durationMs - }; -} - -/** - * Resolves UI semantics exclusively through DSH ToolDefinition presenters. - * - * No tool names or argument schemas are embedded here. `ctx.tools.get(name, - * agent)` is authoritative for the definition visible to this Agent; its pure - * `presentCall/presentResult` methods decide terminal/diff/generic intent. - */ -export class DshToolPresentationResolver { - constructor({ ctx, agent, threadId, workspaceCwd = process.cwd(), diagnostics = () => {} }) { - if (!ctx || typeof ctx.get !== 'function') throw new Error('DshToolPresentationResolver requires a Cordis Context'); - if (!agent) throw new Error('DshToolPresentationResolver requires a DSH Agent'); - this.ctx = ctx; - this.agent = agent; - this.threadId = String(threadId ?? agent.id); - this.workspaceCwd = path.resolve(workspaceCwd); - this.diagnostics = diagnostics; - this.calls = new Map(); - } - - definition(name) { - return this.ctx.get('tools')?.get?.(name, this.agent); - } - - start({ turnId, callId, name, rawArguments, startedAtMs = Date.now() }) { - const args = parseArguments(rawArguments); - const definition = this.definition(name); - let view; - try { view = definition?.presentCall?.(args); } - catch (error) { this.diagnostics(`presentCall(${name}): ${error instanceof Error ? error.message : error}`); } - - const id = `dsh-tool-${String(callId)}`; - let item; - let semantic = 'generic'; - if (view?.card === 'terminal') { - semantic = 'command'; - item = { - type: 'commandExecution', - id, - pluginId: null, - scriptPath: null, - command: view.title, - cwd: resolveCwd(this.workspaceCwd, view.cwd), - processId: null, - source: 'agent', - status: 'inProgress', - commandActions: [], - aggregatedOutput: null, - exitCode: null, - durationMs: null - }; - } else if (canUseCodexFileChange(view)) { - semantic = 'fileChange'; - item = fileChangeItem(id, view, 'inProgress'); - } else { - // DSH `oldText:null` is intentionally ambiguous between create and - // overwrite, while Codex requires add/delete/update. Stay generic rather - // than fabricate a PatchChangeKind. - item = dynamicItem(id, name, args, 'inProgress'); - } - - const state = { - callId: String(callId), - name, - args, - definition, - callView: view, - semantic, - item, - turnId, - startedAtMs - }; - this.calls.set(String(callId), state); - return { item, state }; - } - - complete({ callId, resultData, completedAtMs = Date.now() }) { - const state = this.calls.get(String(callId)); - if (!state) return undefined; - const result = toolResultFromEvent(resultData); - let view; - try { view = state.definition?.presentResult?.(state.args, result); } - catch (error) { this.diagnostics(`presentResult(${state.name}): ${error instanceof Error ? error.message : error}`); } - const durationMs = Math.max(0, completedAtMs - state.startedAtMs); - - let item; - if (state.semantic === 'command') { - const terminal = view?.card === 'terminal' ? view : undefined; - const failed = result.isError || Boolean(terminal?.signal) || - (terminal?.exitCode !== undefined && terminal.exitCode !== 0); - item = { - ...state.item, - status: failed ? 'failed' : 'completed', - aggregatedOutput: terminal?.output ?? textContentItems(result.content)?.map((entry) => entry.text).join('\n') ?? null, - exitCode: terminal?.exitCode ?? null, - durationMs - }; - } else if (state.semantic === 'fileChange') { - item = view?.card === 'diff' && canUseCodexFileChange(view) - ? fileChangeItem(state.item.id, view, result.isError ? 'failed' : 'completed') - : { ...state.item, status: result.isError ? 'failed' : 'completed' }; - } else { - item = dynamicItem( - state.item.id, - state.name, - state.args, - result.isError ? 'failed' : 'completed', - result, - durationMs - ); - } - - state.item = item; - state.resultView = view; - state.result = result; - return { item, state }; - } - - correlation(callId) { - const state = this.calls.get(String(callId)); - if (!state) return undefined; - return { - threadId: this.threadId, - turnId: state.turnId, - itemId: state.item.id, - semantic: state.semantic, - ...(state.semantic === 'command' - ? { kind: 'command', command: state.item.command, cwd: state.item.cwd } - : state.semantic === 'fileChange' - ? { kind: 'fileChange' } - : {}) - }; - } -} diff --git a/.release/dshx-linux-x64/src/dsh/user-input.mjs b/.release/dshx-linux-x64/src/dsh/user-input.mjs deleted file mode 100644 index b1084826..00000000 --- a/.release/dshx-linux-x64/src/dsh/user-input.mjs +++ /dev/null @@ -1,106 +0,0 @@ -import fs from 'node:fs/promises'; -import path from 'node:path'; - -const MEDIA_TYPES = new Map([ - ['.png', 'image/png'], - ['.jpg', 'image/jpeg'], - ['.jpeg', 'image/jpeg'], - ['.webp', 'image/webp'], - ['.gif', 'image/gif'] -]); - -function requireAttachments(ctx) { - const attachments = ctx?.get?.('attachments'); - if (!attachments?.saveImages) throw new Error('DSHX image input requires DSH service: attachments.saveImages'); - return attachments; -} - -function localMediaType(filePath) { - const mediaType = MEDIA_TYPES.get(path.extname(filePath).toLowerCase()); - if (!mediaType) throw new Error(`Unsupported local image type: ${path.extname(filePath) || ''}`); - return mediaType; -} - -function parseDataImage(url) { - const match = /^data:(image\/(?:png|jpeg|webp|gif));base64,([A-Za-z0-9+/=\r\n]+)$/i.exec(String(url ?? '')); - if (!match) return undefined; - return { - mediaType: match[1].toLowerCase(), - data: Buffer.from(match[2].replace(/[\r\n]/g, ''), 'base64') - }; -} - -function skillGesture(name) { - const value = String(name ?? ''); - if (!/^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(value)) { - throw new Error(`Invalid DSH skill name from Codex input: ${JSON.stringify(name)}`); - } - return `/${value}`; -} - -/** - * Convert pinned Codex UserInput into the public DSH UserContent vocabulary. - * Images are committed through DSH's attachment service before their refs are - * placed in the durable user message. User-explicit skills deliberately remain - * plain `/name` gestures because that is DSH's authoritative pre-step seam. - */ -export async function codexInputToDshContent(ctx, inputs = []) { - if (!Array.isArray(inputs)) throw new Error('Codex input must be an array'); - const plan = []; - const pendingImages = []; - - for (const input of inputs) { - switch (input?.type) { - case 'text': - if (typeof input.text !== 'string') throw new Error('Codex text input requires text'); - plan.push({ kind: 'content', block: { type: 'text', text: input.text } }); - break; - case 'skill': - plan.push({ kind: 'content', block: { type: 'text', text: skillGesture(input.name) } }); - break; - case 'localImage': { - if (typeof input.path !== 'string' || input.path.length === 0) { - throw new Error('Codex localImage input requires path'); - } - const filePath = path.resolve(input.path); - const mediaType = localMediaType(filePath); - const data = await fs.readFile(filePath); - const imageIndex = pendingImages.length; - pendingImages.push({ data, mediaType, name: path.basename(filePath) }); - plan.push({ kind: 'image', imageIndex }); - break; - } - case 'image': { - const inline = parseDataImage(input.url); - if (!inline) { - throw new Error('DSHX accepts Codex image input only as localImage or data:image/*; remote image URLs remain provider-owned'); - } - const imageIndex = pendingImages.length; - pendingImages.push({ ...inline, name: `pasted-image-${imageIndex + 1}` }); - plan.push({ kind: 'image', imageIndex }); - break; - } - case 'mention': - throw new Error('DSHX does not yet project Codex structured mentions into a DSH user message'); - default: - throw new Error(`Unsupported Codex user input type: ${JSON.stringify(input?.type)}`); - } - } - - const refs = pendingImages.length > 0 - ? await requireAttachments(ctx).saveImages(pendingImages) - : []; - return plan.map((entry) => entry.kind === 'image' - ? { type: 'image', ref: refs[entry.imageIndex] } - : entry.block); -} - -export function dshContentText(content = []) { - return content - .filter((block) => block?.type === 'text' && typeof block.text === 'string') - .map((block) => block.text) - .join('\n') - .trim(); -} - -export const inputInternals = { localMediaType, parseDataImage, skillGesture }; diff --git a/.release/dshx-linux-x64/src/dsh/user-question-bridge.mjs b/.release/dshx-linux-x64/src/dsh/user-question-bridge.mjs deleted file mode 100644 index 8e1a4b49..00000000 --- a/.release/dshx-linux-x64/src/dsh/user-question-bridge.mjs +++ /dev/null @@ -1,101 +0,0 @@ -function requireService(ctx, name) { - const service = ctx.get(name); - if (service === undefined) throw new Error(`DSHX requires DSH service: ${name}`); - return service; -} - -function codexQuestion(question) { - const prompt = question.detail === undefined - ? question.question - : `${question.question}\n\n${question.detail}`; - return { - id: question.id, - header: question.header ?? 'Question', - question: prompt, - isOther: true, - isSecret: false, - options: question.options === undefined - ? null - : question.options.map((option) => ({ - label: option.label, - description: option.description ?? '' - })) - }; -} - -function dshAnswer(question, response) { - const values = response?.answers?.[question.id]?.answers ?? []; - const labels = new Set((question.options ?? []).map((option) => option.label)); - const selected = values.filter((value) => labels.has(value)); - const custom = values.filter((value) => !labels.has(value)); - return { - id: question.id, - selected, - ...(custom.length === 0 ? {} : { custom: custom.join('\n') }) - }; -} - -/** - * UI provider for the official DSH `ctx.userQuestions` seam. - * - * DSH's public AskUserQuestionRequest deliberately has no tool call id. The - * bridge therefore asks its owner for a PRESENTATION interaction location; a - * Codex client may attach the dialog to a synthetic UI-only item for the live - * DSH turn instead of guessing which parallel tool call caused the question. - * No question/answer semantics or durable state are owned here. - */ -export class DshUserQuestionBridge { - constructor({ ctx, broker, locate, complete = () => {}, diagnostics = () => {} }) { - if (!ctx || typeof ctx.get !== 'function') throw new Error('DshUserQuestionBridge requires a Cordis Context'); - if (!broker) throw new Error('DshUserQuestionBridge requires a UiRequestBroker'); - if (typeof locate !== 'function') throw new Error('DshUserQuestionBridge requires locate(request)'); - if (typeof complete !== 'function') throw new Error('DshUserQuestionBridge complete must be a function'); - this.ctx = ctx; - this.broker = broker; - this.locate = locate; - this.complete = complete; - this.diagnostics = diagnostics; - this.disposeProvider = requireService(ctx, 'userQuestions').registerProvider({ - ask: (request) => this.ask(request) - }); - } - - async ask(request) { - if (request.questions.some((question) => question.multiSelect === true)) { - throw new Error('DSHX pinned Codex TUI does not yet represent DSH multi-select questions faithfully'); - } - const location = await this.locate(request); - if (!location?.threadId || !location?.turnId || !location?.itemId) { - throw new Error('DSHX could not open a Codex presentation item for the DSH user question'); - } - - try { - const response = await this.broker.request( - 'item/tool/requestUserInput', - { - threadId: location.threadId, - turnId: location.turnId, - itemId: location.itemId, - questions: request.questions.map(codexQuestion), - isBlocking: true, - autoResolutionMs: null - }, - { signal: request.signal } - ); - const answer = { answers: request.questions.map((question) => dshAnswer(question, response)) }; - await this.complete(location, { status: 'completed', answer }); - return answer; - } catch (error) { - this.diagnostics(error instanceof Error ? error.message : String(error)); - try { await this.complete(location, { status: 'failed', error }); } catch (completeError) { - this.diagnostics(completeError instanceof Error ? completeError.message : String(completeError)); - } - throw error; - } - } - - dispose() { - this.disposeProvider?.(); - this.disposeProvider = undefined; - } -} diff --git a/.release/dshx-linux-x64/src/dsh/user-shell.mjs b/.release/dshx-linux-x64/src/dsh/user-shell.mjs deleted file mode 100644 index 313dcd06..00000000 --- a/.release/dshx-linux-x64/src/dsh/user-shell.mjs +++ /dev/null @@ -1,209 +0,0 @@ -import { randomUUID } from 'node:crypto'; - -function seconds(ms = Date.now()) { - return Math.floor(ms / 1000); -} - -function turnRecord(id, status, startedAt, completedAt = null, error = null) { - return { - id, - items: [], - itemsView: 'full', - status, - error, - startedAt, - completedAt, - durationMs: completedAt == null ? null : Math.max(0, (completedAt - startedAt) * 1000) - }; -} - -function errorRecord(message) { - return { message: String(message), codexErrorInfo: null, additionalDetails: null }; -} - -function resultData(callId, result) { - return { - message: { - source: { kind: 'tool', callId }, - content: [{ - type: 'tool-result', - toolCallId: callId, - content: Array.isArray(result?.content) ? result.content : [], - isError: Boolean(result?.isError) - }] - }, - ...(result?.meta === undefined ? {} : { meta: result.meta }) - }; -} - -function pickTool(agent) { - const tools = agent.ctx?.get?.('tools'); - if (!tools) throw new Error('DSHX user shell requires DSH service: tools'); - const preferred = process.platform === 'win32' ? ['pwsh', 'bash'] : ['bash', 'pwsh']; - for (const name of preferred) { - if (tools.get?.(name, agent)) return { tools, name }; - } - throw new Error('No DSH shell tool is visible in the current Agent scope'); -} - -/** - * Presentation-only bridge for Codex `!` commands. Execution still goes through - * the official DSH ToolRuntime, so pre-execute policy, guards, approval, - * sandboxing, timeouts, post-policy and result normalization all remain DSH-owned. - * Like Codex's own user-shell action, these cells are intentionally not durable - * conversation history. - */ -export class DshUserShellBridge { - constructor({ send, diagnostics = () => {} } = {}) { - if (typeof send !== 'function') throw new Error('DshUserShellBridge requires send(message)'); - this.send = send; - this.diagnostics = diagnostics; - this.active = new Map(); - } - - start(controller, command) { - const threadId = String(controller?.threadId ?? controller?.agent?.id ?? ''); - if (!threadId) throw new Error('thread/shellCommand requires a resumed DSH thread'); - if (typeof command !== 'string' || command.trim().length === 0) { - throw new Error('thread/shellCommand requires a non-empty command'); - } - if (this.active.has(threadId)) throw new Error('A DSHX user-shell command is already active for this thread'); - - const existing = controller.currentLocation(); - const callId = `dshx-user-shell-${randomUUID()}`; - const turnId = existing?.turnId ?? `dsh-user-shell-turn-${randomUUID()}`; - const maintenance = existing == null; - const startedAtMs = Date.now(); - const abortController = new AbortController(); - const state = { - threadId, - turnId, - callId, - maintenance, - startedAtMs, - abortController, - controller, - command - }; - this.active.set(threadId, state); - - return { - result: {}, - afterResponse: () => { - void this.run(state); - } - }; - } - - async run(state) { - const { threadId, turnId, callId, maintenance, startedAtMs, abortController, controller, command } = state; - try { - if (maintenance) { - this.send({ - method: 'turn/started', - params: { threadId, turn: turnRecord(turnId, 'inProgress', seconds(startedAtMs)) } - }); - } - - const { tools, name } = pickTool(controller.agent); - const args = { - command, - description: 'Run command from interactive user shell', - workdir: controller.agent.session?.header?.cwd, - run_in_background: false - }; - const projected = controller.toolPresentation?.start({ - turnId, - callId, - name, - rawArguments: args, - startedAtMs - }); - if (!projected || projected.state.semantic !== 'command') { - throw new Error(`DSH shell tool ${name} does not expose terminal presentation semantics`); - } - projected.item.source = 'userShell'; - projected.state.item = projected.item; - this.send({ - method: 'item/started', - params: { threadId, turnId, startedAtMs, item: projected.item } - }); - - const result = await tools.execute({ - callId, - name, - arguments: args, - signal: abortController.signal, - agent: controller.agent - }); - const completedAtMs = Date.now(); - const completed = controller.toolPresentation.complete({ - callId, - resultData: resultData(callId, result), - completedAtMs - }); - if (!completed) throw new Error(`DSHX lost user-shell presentation correlation for ${callId}`); - completed.item.source = 'userShell'; - this.send({ - method: 'item/completed', - params: { threadId, turnId, completedAtMs, item: completed.item } - }); - if (maintenance) { - const completedAt = seconds(completedAtMs); - this.send({ - method: 'turn/completed', - params: { - threadId, - turn: turnRecord( - turnId, - result?.isError ? 'failed' : 'completed', - seconds(startedAtMs), - completedAt, - result?.isError ? errorRecord(result.error?.message ?? 'DSH shell command failed') : null - ) - } - }); - } - } catch (error) { - const message = error instanceof Error ? error.message : String(error); - this.diagnostics(`user shell ${threadId}: ${message}`); - if (maintenance) { - const completedAt = seconds(); - this.send({ - method: 'turn/completed', - params: { - threadId, - turn: turnRecord(turnId, 'failed', seconds(startedAtMs), completedAt, errorRecord(message)) - } - }); - } else { - this.send({ method: 'warning', params: { threadId, message } }); - } - } finally { - if (this.active.get(threadId) === state) this.active.delete(threadId); - } - } - - interrupt(threadId, turnId) { - const state = this.active.get(String(threadId)); - if (!state || state.turnId !== String(turnId)) return false; - state.abortController.abort(new Error('user cancelled DSHX shell command')); - return true; - } - - abortThread(threadId, reason = 'thread closed') { - const state = this.active.get(String(threadId)); - if (!state) return false; - state.abortController.abort(new Error(reason)); - return true; - } - - close() { - for (const state of this.active.values()) { - state.abortController.abort(new Error('DSHX adapter closing')); - } - this.active.clear(); - } -} - -export const userShellInternals = { pickTool, resultData, turnRecord }; diff --git a/.release/dshx-linux-x64/src/dsh/workspace-command.mjs b/.release/dshx-linux-x64/src/dsh/workspace-command.mjs deleted file mode 100644 index 89867393..00000000 --- a/.release/dshx-linux-x64/src/dsh/workspace-command.mjs +++ /dev/null @@ -1,166 +0,0 @@ -import path from 'node:path'; -import { randomUUID } from 'node:crypto'; - -function shellTool(agent) { - const tools = agent?.ctx?.get?.('tools'); - if (!tools) throw new Error('DSHX workspace command requires DSH service: tools'); - const preferred = process.platform === 'win32' ? ['pwsh', 'bash'] : ['bash', 'pwsh']; - for (const name of preferred) { - if (tools.get?.(name, agent)) return { tools, name }; - } - throw new Error('No DSH shell tool is visible in the active Agent scope'); -} - -function bashQuote(value) { - const text = String(value); - if (text.includes('\0')) throw new Error('command/exec argv cannot contain NUL'); - return `'${text.replaceAll("'", `'"'"'`)}'`; -} - -function pwshQuote(value) { - const text = String(value); - if (text.includes('\0')) throw new Error('command/exec argv cannot contain NUL'); - return `'${text.replaceAll("'", "''")}'`; -} - -function envName(name) { - if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(name)) { - throw new Error(`command/exec environment key is not portable: ${JSON.stringify(name)}`); - } - return name; -} - -function commandText(argv, env, dialect) { - const quote = dialect === 'pwsh' ? pwshQuote : bashQuote; - const invocation = dialect === 'pwsh' - ? `& ${argv.map(quote).join(' ')}` - : argv.map(quote).join(' '); - const entries = Object.entries(env ?? {}); - if (entries.length === 0) return invocation; - - if (dialect === 'pwsh') { - const prefix = entries.map(([rawName, value]) => { - const name = envName(rawName); - return value == null - ? `Remove-Item Env:${name} -ErrorAction SilentlyContinue` - : `$env:${name} = ${quote(value)}`; - }); - return `${prefix.join('; ')}; ${invocation}`; - } - - const prefix = entries.map(([rawName, value]) => { - const name = envName(rawName); - return value == null ? `unset ${name}` : `export ${name}=${quote(value)}`; - }); - return `${prefix.join('; ')}; ${invocation}`; -} - -function textError(result) { - return (result?.content ?? []) - .filter((block) => block?.type === 'text' && typeof block.text === 'string') - .map((block) => block.text) - .join('\n') - .trim(); -} - -function capUtf8(text, limit) { - if (!Number.isSafeInteger(limit) || limit < 0) return text; - const bytes = Buffer.from(String(text), 'utf8'); - if (bytes.length <= limit) return String(text); - let end = Math.min(limit, bytes.length); - while (end > 0 && (bytes[end] & 0b1100_0000) === 0b1000_0000) end -= 1; - return bytes.subarray(0, end).toString('utf8'); -} - -function bufferedResult(result, params) { - if (result?.isError) { - throw new Error(textError(result) || result.error?.message || 'DSH workspace command failed'); - } - const value = result?.value; - if (!value || value.kind !== 'foreground') { - throw new Error(`DSH shell returned non-foreground command/exec result: ${JSON.stringify(value?.kind)}`); - } - const exitCode = Number.isInteger(value.exitCode) ? value.exitCode : 1; - const cap = params.disableOutputCap === true ? undefined : params.outputBytesCap; - return { - exitCode, - stdout: capUtf8(value.stdout?.text ?? '', cap), - stderr: capUtf8(value.stderr?.text ?? '', cap) - }; -} - -function validateParams(params) { - if (!Array.isArray(params.command) || params.command.length === 0 || params.command.some((entry) => typeof entry !== 'string' || entry.length === 0)) { - throw new Error('command/exec requires a non-empty argv string array'); - } - if (params.processId != null || params.tty === true || params.streamStdin === true || params.streamStdoutStderr === true || params.size != null) { - throw new Error('DSHX command/exec supports buffered non-TTY workspace commands only'); - } - if (params.disableTimeout === true) { - throw new Error('DSHX command/exec does not override the DSH shell executor timeout policy'); - } - if (params.outputBytesCap != null && params.disableOutputCap === true) { - throw new Error('command/exec outputBytesCap and disableOutputCap are mutually exclusive'); - } - if (params.timeoutMs != null && (!Number.isSafeInteger(params.timeoutMs) || params.timeoutMs <= 0)) { - throw new Error('command/exec timeoutMs must be a positive integer'); - } - if (params.sandboxPolicy != null || params.permissionProfile != null) { - throw new Error('DSHX command/exec uses the active DSH session permission policy and rejects Codex policy overrides'); - } -} - -/** - * TUI-owned one-off workspace probes (`git`, `/diff`, status metadata) mapped - * onto the official DSH shell tool runtime. No process is spawned by DSHX. - */ -export class DshWorkspaceCommandBridge { - constructor({ driver } = {}) { - if (!driver?.listRootAgents) throw new Error('DshWorkspaceCommandBridge requires DshAgentDriver'); - this.driver = driver; - } - - agentFor(cwd) { - const roots = this.driver.listRootAgents(); - if (roots.length === 0) throw new Error('command/exec requires an active DSH root Agent'); - if (cwd != null) { - const wanted = path.resolve(cwd); - const matches = roots.filter((agent) => path.resolve(agent.session?.header?.cwd ?? process.cwd()) === wanted); - if (matches.length === 1) return matches[0]; - if (matches.length > 1) throw new Error(`command/exec cwd matches multiple active DSH Agents: ${wanted}`); - } - if (roots.length === 1) return roots[0]; - throw new Error('command/exec cannot choose among multiple active DSH root Agents without an exact cwd match'); - } - - async execute(params = {}) { - validateParams(params); - const agent = this.agentFor(params.cwd); - const { tools, name } = shellTool(agent); - const args = { - command: commandText(params.command, params.env, name), - description: 'Run DSHX TUI workspace command', - workdir: params.cwd ?? agent.session?.header?.cwd, - run_in_background: false, - ...(params.timeoutMs == null ? {} : { timeoutMs: params.timeoutMs }) - }; - const result = await tools.execute({ - callId: `dshx-workspace-${randomUUID()}`, - name, - arguments: args, - signal: new AbortController().signal, - agent - }); - return bufferedResult(result, params); - } -} - -export const workspaceCommandInternals = { - bashQuote, - pwshQuote, - commandText, - bufferedResult, - validateParams, - capUtf8, - shellTool -}; diff --git a/.release/dshx-linux-x64/src/protocol/request-broker.mjs b/.release/dshx-linux-x64/src/protocol/request-broker.mjs deleted file mode 100644 index dd4787fa..00000000 --- a/.release/dshx-linux-x64/src/protocol/request-broker.mjs +++ /dev/null @@ -1,79 +0,0 @@ -function makeAbortError(message = 'The request was aborted') { - const error = new Error(message); - error.name = 'AbortError'; - return error; -} - -/** - * Correlates app-server requests initiated by DSHX with responses from the TUI. - * The broker owns no approval policy: transport loss, timeout and cancellation - * reject the presentation request so the DSH answerer can fail closed. - */ -export class UiRequestBroker { - constructor({ send, timeoutMs = 120_000, idPrefix = 'dshx-ui' } = {}) { - if (typeof send !== 'function') throw new Error('UiRequestBroker requires send(message)'); - this.send = send; - this.timeoutMs = timeoutMs; - this.idPrefix = idPrefix; - this.nextId = 1; - this.pending = new Map(); - this.closed = false; - } - - request(method, params, { signal } = {}) { - if (this.closed) return Promise.reject(new Error('UI request broker is closed')); - if (signal?.aborted) return Promise.reject(makeAbortError()); - - const id = `${this.idPrefix}-${this.nextId++}`; - return new Promise((resolve, reject) => { - const cleanup = () => { - clearTimeout(entry.timer); - signal?.removeEventListener('abort', entry.onAbort); - this.pending.delete(id); - }; - const entry = { - resolve: (value) => { cleanup(); resolve(value); }, - reject: (error) => { cleanup(); reject(error); }, - onAbort: () => entry.reject(makeAbortError()), - timer: undefined - }; - entry.timer = setTimeout( - () => entry.reject(new Error(`UI request timed out: ${method}`)), - this.timeoutMs - ); - signal?.addEventListener('abort', entry.onAbort, { once: true }); - this.pending.set(id, entry); - - try { - this.send({ id, method, params }); - } catch (error) { - entry.reject(error instanceof Error ? error : new Error(String(error))); - } - }); - } - - /** - * Consume a client response (`{id,result}` or `{id,error}`). Returns false - * when the id does not belong to an outstanding server-initiated request. - */ - handleResponse(message) { - if (!message || message.id === undefined || message.method !== undefined) return false; - const entry = this.pending.get(String(message.id)); - if (!entry) return false; - if (message.error !== undefined) { - const error = new Error(message.error?.message ?? 'TUI request failed'); - error.code = message.error?.code; - entry.reject(error); - } else { - entry.resolve(message.result); - } - return true; - } - - close(reason = 'UI transport closed') { - if (this.closed) return; - this.closed = true; - const entries = [...this.pending.values()]; - for (const entry of entries) entry.reject(new Error(reason)); - } -} diff --git a/.release/dshx-linux-x64/src/tui-protocol/adapter.mjs b/.release/dshx-linux-x64/src/tui-protocol/adapter.mjs deleted file mode 100644 index 2dfaa111..00000000 --- a/.release/dshx-linux-x64/src/tui-protocol/adapter.mjs +++ /dev/null @@ -1,1302 +0,0 @@ -import crypto from 'node:crypto'; -import os from 'node:os'; -import path from 'node:path'; -import { DshAgentDriver } from '../dsh/agent-driver.mjs'; -import { DshApprovalBridge } from '../dsh/approval-bridge.mjs'; -import { - codexModelsFromDsh, - decodeDshModel, - dshThreadFromSnapshot, - dshTurnsFromSession, - encodeDshModel, - normalizeCodexEffort, - normalizeSessionHeaders -} from './shapes.mjs'; -import { executeDshCommand } from '../dsh/commands.mjs'; -import { dshThreadItemsPage, dshThreadTurnsPage } from '../dsh/history-pages.mjs'; -import { DshHostApi } from '../dsh/host-api.mjs'; -import { codexPlanTarget, threadSettingsUpdatedNotification } from '../dsh/plan-presentation.mjs'; -import { DshPermissionView } from '../dsh/permissions.mjs'; -import { codexForkAtSeq } from '../dsh/session-fork.mjs'; -import { dshSkillsListEntry } from '../dsh/skills.mjs'; -import { foldDshSessionTitle, threadNameUpdatedNotification } from '../dsh/thread-title.mjs'; -import { DshThreadController } from '../dsh/thread-controller.mjs'; -import { codexInputToDshContent, dshContentText } from '../dsh/user-input.mjs'; -import { DshUserQuestionBridge } from '../dsh/user-question-bridge.mjs'; -import { DshUserShellBridge } from '../dsh/user-shell.mjs'; -import { persistedTokenUsageNotification } from '../dsh/token-usage.mjs'; -import { DshWorkspaceCommandBridge } from '../dsh/workspace-command.mjs'; -import { UiRequestBroker } from '../protocol/request-broker.mjs'; - -const INVALID_REQUEST = -32600; -const METHOD_NOT_FOUND = -32601; -const INVALID_PARAMS = -32602; -const INTERNAL_ERROR = -32603; - -function platformFamily() { - return process.platform === 'win32' ? 'windows' : 'unix'; -} - -function platformOs() { - if (process.platform === 'darwin') return 'macos'; - if (process.platform === 'win32') return 'windows'; - if (process.platform === 'linux') return 'linux'; - return process.platform; -} - -function codexApprovalToDsh(value) { - if (value == null) return undefined; - if (value === 'on-request') return 'ask'; - if (value === 'never') return 'never'; - throw new Error(`DSHX cannot map Codex approval policy ${JSON.stringify(value)} to DSH`); -} - -// Base turn input validation. Distinct from the steer variant below because -// the two historically reported different unsupported-input messages. -function turnTextInput(params) { - const inputs = Array.isArray(params?.input) ? params.input : []; - const unsupported = inputs.filter((item) => item?.type !== 'text'); - if (unsupported.length > 0) { - throw new Error(`DSHX turn input currently supports Codex text items only; got ${unsupported.map((item) => item?.type).join(', ')}`); - } - return inputs.map((item) => item.text ?? '').join('\n').trim(); -} - -function steerTextInput(params) { - const inputs = Array.isArray(params?.input) ? params.input : []; - const unsupported = inputs.filter((item) => item?.type !== 'text'); - if (unsupported.length > 0) { - throw new Error(`DSHX steer currently supports Codex text items only; got ${unsupported.map((item) => item?.type).join(', ')}`); - } - return inputs.map((item) => item.text ?? '').join('\n').trim(); -} - -function pagination(value, total, defaultLimit = 50) { - const cursor = value?.cursor == null ? 0 : Number(value.cursor); - if (!Number.isSafeInteger(cursor) || cursor < 0) throw new Error('invalid pagination cursor'); - const requested = value?.limit == null ? defaultLimit : Number(value.limit); - if (!Number.isSafeInteger(requested) || requested <= 0) throw new Error('limit must be a positive integer'); - const end = Math.min(total, cursor + requested); - return { start: cursor, end, nextCursor: end < total ? String(end) : null }; -} - -function sandboxMatchesCurrent(sandbox, permission) { - if (sandbox == null) return true; - if (sandbox.type === 'dangerFullAccess') return permission.dsh.sandboxMode === 'danger-full-access'; - if (sandbox.type === 'externalSandbox') { - return permission.dsh.sandboxMode === 'read-only' || permission.dsh.sandboxMode === 'workspace-write'; - } - return false; -} - -function fullThreadSnapshot(agent, { includeTurns = false, cliVersion = 'dshx' } = {}) { - const turns = includeTurns ? dshTurnsFromSession({ ctx: agent.ctx, agent }) : []; - return dshThreadFromSnapshot({ - meta: agent.session.header, - events: agent.session.events, - model: agent.session.requestHeader?.()?.config, - turns, - loaded: true, - cliVersion - }); -} - -function dshPermissionPreset(ctx, codexId) { - const presets = ctx.get('permissionPresets'); - if (!presets) throw new Error('DSHX requires DSH service: permissionPresets'); - const mapped = codexId === ':workspace' - ? 'workspace-write' - : codexId === ':danger-full-access' - ? 'danger-full-access' - : codexId === ':read-only' - ? 'read-only' - : codexId; - if (!presets.names.includes(mapped)) { - throw new Error(`DSH has no permission preset corresponding to Codex profile ${JSON.stringify(codexId)}`); - } - return mapped; -} - -function codexPermissionProfileId(preset) { - if (preset === 'workspace-write') return ':workspace'; - if (preset === 'danger-full-access') return ':danger-full-access'; - if (preset === 'read-only') return ':read-only'; - if (preset === 'custom' || preset == null) return null; - return preset; -} - -function hasSupportedThreadSetting(params) { - return params.model != null - || params.effort != null - || params.permissions != null - || params.approvalPolicy != null; -} - -function snapshotTitle(snapshot) { - return typeof snapshot?.title === 'string' && snapshot.title.length > 0 ? snapshot.title : null; -} - -function isDshSubagent(agent) { - return agent?.session?.header?.origin === 'subagent'; -} - -/** - * Single presentation adapter from pinned Codex app-server JSON-RPC to - * official DSH public services. - * - * This class is the linearization of the former three-layer inheritance chain - * (app-server-adapter -> product-adapter -> release-adapter). Method bodies - * are kept verbatim per layer; `_Base` / `_ProductLayer` - * helpers preserve the exact call order the old `super.*` chain executed, so - * behavior is unchanged while "which dispatch actually runs" no longer spans - * three files. It owns no Agent loop, provider routing, tool dispatch, - * persistence, sandbox enforcement, approval policy or user-question semantics. - */ -export class DshxPresentationAdapter { - constructor({ - ctx, - send, - cwd = process.cwd(), - home = path.join(os.homedir(), '.dshx'), - version = '0.1.0-dev', - diagnostics = () => {} - }) { - if (!ctx || typeof ctx.get !== 'function') throw new Error('DshAppServerAdapter requires a Cordis Context'); - if (typeof send !== 'function') throw new Error('DshAppServerAdapter requires send(message)'); - this.ctx = ctx; - this.send = send; - this.cwd = path.resolve(cwd); - this.home = path.resolve(home); - this.version = version; - this.diagnostics = diagnostics; - this.driver = new DshAgentDriver(ctx); - this.permissions = new DshPermissionView(ctx); - this.broker = new UiRequestBroker({ send }); - this.controllers = new Map(); - this.approvals = new Map(); - this.syntheticInteractions = new Map(); - this.readyPromise = null; - this.userQuestions = null; - this.closed = false; - } - - // ── readiness ──────────────────────────────────────────────────────────── - - async ensureReady() { - await this.ensureReadyBase(); - if (this._agentPresentationDisposers) return; - this._agentPresentationDisposers = [ - this.ctx.on('agent/created', ({ agent }) => { - if (!isDshSubagent(agent)) return; - try { - this.send({ method: 'thread/started', params: { thread: this.liveAgentThread(agent) } }); - } catch (error) { - this.diagnostics(`subagent thread/started projection failed for ${String(agent?.id ?? '')}: ${error instanceof Error ? error.message : error}`); - } - }), - this.ctx.on('agent/status', ({ agent, status }) => { - try { - this.send({ - method: 'thread/status/changed', - params: { - threadId: String(agent.id), - status: status === 'running' ? { type: 'active', activeFlags: [] } : { type: 'idle' } - } - }); - } catch (error) { - this.diagnostics(`agent status projection failed for ${String(agent?.id ?? '')}: ${error instanceof Error ? error.message : error}`); - } - }), - this.ctx.on('agent/disposed', ({ agent }) => { - try { - this.send({ - method: 'thread/status/changed', - params: { threadId: String(agent.id), status: { type: 'notLoaded' } } - }); - } catch (error) { - this.diagnostics(`agent disposal projection failed for ${String(agent?.id ?? '')}: ${error instanceof Error ? error.message : error}`); - } - }) - ]; - } - - async ensureReadyBase() { - if (this.readyPromise) return this.readyPromise; - this.readyPromise = (async () => { - const loader = this.ctx.get('loader'); - if (loader?.await) await loader.await(); - if (!this.userQuestions && this.ctx.get('userQuestions')) { - this.userQuestions = new DshUserQuestionBridge({ - ctx: this.ctx, - broker: this.broker, - locate: (request) => this.openSyntheticInteraction(request), - complete: (location, outcome) => this.completeSyntheticInteraction(location, outcome), - diagnostics: this.diagnostics - }); - } - })(); - return this.readyPromise; - } - - // ── protocol entry ─────────────────────────────────────────────────────── - - async handle(message) { - if (this.broker.handleResponse(message)) return null; - if (!message || message.id === undefined || typeof message.method !== 'string') { - if (message?.id === undefined && typeof message?.method === 'string') return null; - return { response: this.error(message?.id ?? null, INVALID_REQUEST, 'Invalid Request') }; - } - try { - await this.ensureReady(); - const dispatched = await this.dispatch(message.method, message.params ?? {}); - return { - response: { id: message.id, result: dispatched?.result }, - afterResponse: dispatched?.afterResponse - }; - } catch (error) { - const code = error?.code === METHOD_NOT_FOUND ? METHOD_NOT_FOUND - : error?.code === INVALID_PARAMS ? INVALID_PARAMS - : INTERNAL_ERROR; - return { - response: this.error(message.id, code, error instanceof Error ? error.message : String(error)) - }; - } - } - - /** - * Merged dispatch table. Case order mirrors the former inheritance - * linearization: release-layer routing first, then product-layer routing, - * then the base protocol surface. The base layer's dead `skills/list` stub - * (empty data) is gone — the product layer's DSH-backed skillsList owns it. - */ - async dispatch(method, params) { - switch (method) { - // release-layer routing - case 'command/exec': - return this.commandExec(params); - case 'config/batchWrite': - return this.configBatchWrite(params); - case 'thread/name/set': - return this.threadNameSet(params); - case 'thread/shellCommand': - return this.threadShellCommand(params); - case 'thread/fork': - return this.threadForkPresentation(params); - case 'thread/settings/update': - return this.threadSettingsUpdatePresentation(params); - case 'thread/compact/start': - this.directController(params?.threadId, 'direct compaction'); - return this.threadCompactStart(params); - case 'turn/start': - case 'turn/steer': - return this.richUserTurn(method, params); - case 'turn/interrupt': { - if (this.userShell().interrupt(params?.threadId, params?.turnId)) return { result: {} }; - const controller = this.controllers.get(String(params?.threadId ?? '')); - if (controller && isDshSubagent(controller.agent)) return this.interruptSubagent(controller); - return this.turnInterruptProduct(params); - } - case 'thread/unsubscribe': { - const threadId = String(params?.threadId ?? ''); - this.userShell().abortThread(threadId, 'thread unsubscribed'); - this.planListeners().get(threadId)?.(); - this.planListeners().delete(threadId); - this.planMutationSuppressed().delete(threadId); - return this.threadUnsubscribeWithStatus(params); - } - // product-layer routing - case 'account/usage/read': - return this.accountUsageRead(params); - case 'skills/list': - return this.skillsList(params); - case 'thread/turns/list': - return this.threadTurnsList(params); - case 'thread/items/list': - return this.threadItemsList(params); - // base-layer routing (most-derived implementations win at call time) - case 'initialize': - return { - result: { - userAgent: `dshx/${this.version}`, - codexHome: this.home, - platformFamily: platformFamily(), - platformOs: platformOs() - } - }; - case 'account/read': - return { result: { account: null, requiresOpenaiAuth: false } }; - case 'configRequirements/read': - return { result: { requirements: null } }; - case 'model/list': - return this.modelList(params); - case 'thread/list': - return this.threadList(params); - case 'thread/loaded/list': - return this.loadedThreadList(); - case 'thread/start': - return this.threadStart(params); - case 'thread/resume': - return this.threadResume(params); - case 'thread/read': - return this.threadRead(params); - default: { - const error = new Error(`Method not found: ${method}`); - error.code = METHOD_NOT_FOUND; - throw error; - } - } - } - - // ── models and listings ────────────────────────────────────────────────── - - async modelList(params) { - const directory = await this.driver.modelDirectory(); - for (const failure of directory.failures ?? []) { - this.diagnostics(`DSH model catalog ${failure.provider}: ${failure.message}`); - } - const active = this.driver.listRootAgents()[0]; - const current = active - ? this.driver.currentModel(active) - : this.ctx.get('agentDefaultModel')?.currentSelection?.(); - const all = codexModelsFromDsh(directory, current); - const visible = params.includeHidden ? all : all.filter((model) => !model.hidden); - const page = pagination(params, visible.length); - return { result: { data: visible.slice(page.start, page.end), nextCursor: page.nextCursor } }; - } - - async threadList(params = {}) { - const response = await this.threadListBase(params); - const data = await Promise.all(response.result.data.map(async (thread) => { - try { - const snapshot = await this.driver.readTitle(thread.id); - return { ...thread, name: snapshotTitle(snapshot) ?? thread.name ?? null }; - } catch (error) { - this.diagnostics(`title read ${thread.id}: ${error instanceof Error ? error.message : error}`); - return thread; - } - })); - return { result: { ...response.result, data } }; - } - - async threadListBase(params) { - const headers = normalizeSessionHeaders(await this.driver.listSessions()); - const snapshots = await Promise.all(headers.map(async (header) => { - try { - const inspected = await this.driver.inspectSession(String(header.id)); - const meta = inspected?.meta ?? header; - const events = inspected?.events ?? []; - return dshThreadFromSnapshot({ - meta, - events, - loaded: Boolean(this.controllers.has(String(meta.id)) || this.driver.getLive(String(meta.id))), - cliVersion: this.version - }); - } catch (error) { - this.diagnostics(`inspect ${String(header.id)}: ${error instanceof Error ? error.message : error}`); - return undefined; - } - })); - let threads = snapshots.filter(Boolean); - if (params.cwd != null) { - const wanted = new Set((Array.isArray(params.cwd) ? params.cwd : [params.cwd]).map((entry) => path.resolve(entry))); - threads = threads.filter((thread) => wanted.has(path.resolve(thread.cwd))); - } - if (params.searchTerm) { - const needle = String(params.searchTerm).toLowerCase(); - threads = threads.filter((thread) => `${thread.name ?? ''}\n${thread.preview}`.toLowerCase().includes(needle)); - } - if (Array.isArray(params.modelProviders) && params.modelProviders.length > 0) { - const providers = new Set(params.modelProviders); - threads = threads.filter((thread) => providers.has(thread.modelProvider)); - } - threads.sort((a, b) => (params.sortDirection === 'asc' ? 1 : -1) * (a.recencyAt - b.recencyAt)); - const page = pagination(params, threads.length); - return { - result: { - data: threads.slice(page.start, page.end).map((thread) => ({ ...thread, turns: [] })), - nextCursor: page.nextCursor, - backwardsCursor: null - } - }; - } - - loadedThreadList() { - // Pinned Codex ThreadLoadedListResponse.data is Array. Keep rich - // thread metadata on thread/list/read/started and expose only live IDs here. - return { - result: { - data: this.driver.listLive().map((agent) => String(agent.id)) - } - }; - } - - // ── permissions ────────────────────────────────────────────────────────── - - async applyStartPermissions(agent, params = {}) { - if (params.permissions == null) return this.applyStartPermissionsBase(agent, params); - if (params.sandbox != null) { - throw new Error('Codex thread/start permissions and sandbox cannot both be selected for DSHX'); - } - const preset = dshPermissionPreset(this.ctx, String(params.permissions)); - this.permissions.set(agent, preset); - const current = this.permissions.current(agent); - if (params.approvalPolicy != null && current.codex.approvalPolicy !== params.approvalPolicy) { - throw new Error( - `DSH preset ${preset} does not match requested Codex approval policy ${JSON.stringify(params.approvalPolicy)}` - ); - } - return current; - } - - async applyStartPermissionsBase(agent, params) { - const desiredSandbox = params.sandbox; - const desiredApproval = codexApprovalToDsh(params.approvalPolicy); - if (desiredSandbox == null && desiredApproval == null) return this.permissions.current(agent); - - const current = this.permissions.current(agent); - const sandboxMode = desiredSandbox ?? current.dsh.sandboxMode; - const approvalPolicy = desiredApproval ?? current.dsh.approvalPolicy; - const presets = this.ctx.get('permissionPresets'); - const match = presets?.names?.find((name) => { - const preset = presets.resolve(name); - return preset.sandbox === sandboxMode && preset.approval === approvalPolicy; - }); - if (!match) { - throw new Error(`DSHX refuses to synthesize a DSH custom permission bundle (${sandboxMode}, ${approvalPolicy})`); - } - this.permissions.set(agent, match); - return this.permissions.current(agent); - } - - async applyModelOverride(agent, { model, modelProvider, effort } = {}) { - if (model == null && effort == null) return this.driver.currentModel(agent); - let selection; - if (model != null) { - selection = decodeDshModel(model); - if (!selection && modelProvider) selection = { provider: modelProvider, model }; - if (!selection) throw new Error('DSHX accepts model switches only from its DSH-backed model catalog'); - } else { - selection = this.driver.currentModel(agent); - } - const normalizedEffort = normalizeCodexEffort(effort); - if (normalizedEffort !== undefined) selection = { ...selection, reasoningEffort: normalizedEffort }; - return this.driver.selectModel(agent, selection); - } - - installController(handle) { - const controller = this.installControllerBase(handle); - const threadId = String(controller.agent.id); - if (!this.planListeners().has(threadId)) { - const dispose = controller.agent.ctx.on('session/event', (session, event) => { - if (session !== controller.agent.session || event?.type !== 'plan/mode') return; - if (this.planMutationSuppressed().has(threadId)) return; - try { - this.send(this.planSettingsNotification(controller.agent)); - } catch (error) { - this.diagnostics(`plan settings projection failed for ${threadId}: ${error instanceof Error ? error.message : error}`); - } - }); - this.planListeners().set(threadId, dispose); - } - return controller; - } - - installControllerBase(handle) { - const threadId = String(handle.agent.id); - const existing = this.controllers.get(threadId); - if (existing) return existing; - const controller = new DshThreadController({ - handle, - driver: this.driver, - emit: this.send, - diagnostics: this.diagnostics - }); - this.controllers.set(threadId, controller); - const approval = new DshApprovalBridge({ - agent: handle.agent, - broker: this.broker, - classify: (req) => req.callId == null ? null : controller.toolCorrelation(req.callId), - diagnostics: this.diagnostics - }); - this.approvals.set(threadId, approval); - return controller; - } - - // ── thread responses ──────────────────────────────────────────────────── - - threadResponse(agent, options = {}) { - const response = this.threadResponseProductLayer(agent, options); - const folded = this.driver.currentTitle(agent); - const name = snapshotTitle(folded) ?? foldDshSessionTitle(agent.session?.events ?? []); - return { - ...response, - thread: { ...response.thread, name } - }; - } - - threadResponseProductLayer(agent, options = {}) { - const response = this.threadResponseCore(agent, options); - const permission = this.permissions.current(agent); - const id = codexPermissionProfileId(permission.preset); - return { - ...response, - runtimeWorkspaceRoots: [], - activePermissionProfile: id == null ? null : { id, extends: null }, - multiAgentMode: 'explicitRequestOnly', - initialTurnsPage: null, - turnsBackwardsCursor: null, - itemsBackwardsCursor: null - }; - } - - threadResponseCore(agent, { includeTurns = false } = {}) { - const selection = this.driver.currentModel(agent); - const permission = this.permissions.current(agent); - const thread = fullThreadSnapshot(agent, { includeTurns, cliVersion: this.version }); - return { - thread, - model: encodeDshModel(selection), - modelProvider: selection.provider, - serviceTier: null, - cwd: thread.cwd, - instructionSources: [], - approvalPolicy: permission.codex.approvalPolicy, - approvalsReviewer: permission.codex.approvalsReviewer, - sandbox: permission.codex.sandbox, - reasoningEffort: selection.reasoningEffort ?? null - }; - } - - // ── thread lifecycle ───────────────────────────────────────────────────── - - async threadStart(params) { - const sessionId = crypto.randomUUID(); - const cwd = path.resolve(params.cwd ?? this.cwd); - const handle = await this.driver.create({ cwd, sessionId }); - try { - await this.applyModelOverride(handle.agent, params); - await this.applyStartPermissions(handle.agent, params); - this.installController(handle); - const result = this.threadResponse(handle.agent); - return { - result, - afterResponse: () => this.send({ method: 'thread/started', params: { thread: result.thread } }) - }; - } catch (error) { - await handle.dispose?.(); - throw error; - } - } - - async threadResume(params = {}) { - const response = await this.threadResumeProduct(params); - const threadId = String(params.threadId ?? response.result.thread?.id ?? ''); - const agent = this.controllers.get(threadId)?.agent; - const prior = response.afterResponse; - return { - ...response, - afterResponse: () => { - prior?.(); - if (agent) this.send(this.planSettingsNotification(agent)); - } - }; - } - - async threadResumeProduct(params = {}) { - if (!params.threadId) throw new Error('thread/resume requires threadId'); - const threadId = String(params.threadId); - let controller = this.controllers.get(threadId); - if (!controller) { - const live = this.driver.getLive(threadId); - const handle = live - ? { agent: live, dispose: async () => {} } - : await this.driver.resume(threadId); - controller = this.installController(handle); - } - const agent = controller.agent; - if (params.cwd != null && path.resolve(params.cwd) !== path.resolve(agent.session.header?.cwd ?? this.cwd)) { - throw new Error('DSHX does not override a persisted DSH session cwd during resume'); - } - await this.applyModelOverride(agent, params); - await this.applyStartPermissions(agent, params); - const result = this.threadResponse(agent, { - includeTurns: params.excludeTurns !== true - }); - const replay = persistedTokenUsageNotification({ - ctx: this.ctx, - session: agent.session, - threadId - }); - return { - result, - afterResponse: replay ? () => this.send(replay) : undefined - }; - } - - async threadRead(params = {}) { - const response = await this.threadReadBase(params); - const thread = response.result.thread; - try { - const snapshot = await this.driver.readTitle(thread.id); - return { - result: { - ...response.result, - thread: { ...thread, name: snapshotTitle(snapshot) ?? thread.name ?? null } - } - }; - } catch (error) { - this.diagnostics(`title read ${thread.id}: ${error instanceof Error ? error.message : error}`); - return response; - } - } - - async threadReadBase(params) { - if (!params.threadId) throw new Error('thread/read requires threadId'); - const live = this.driver.getLive(String(params.threadId)); - if (live) { - return { result: { thread: fullThreadSnapshot(live, { includeTurns: Boolean(params.includeTurns), cliVersion: this.version }) } }; - } - const inspected = await this.driver.inspectSession(String(params.threadId)); - if (!inspected) throw new Error(`Unknown DSH session: ${String(params.threadId)}`); - return { - result: { - thread: dshThreadFromSnapshot({ - meta: inspected.meta, - events: inspected.events, - loaded: false, - cliVersion: this.version, - // A cold persisted session cannot faithfully use tool presenters - // without a composed Agent. The TUI resumes before requesting rich - // history; avoid fabricating tool semantics on a cold read. - turns: [] - }) - } - }; - } - - async turnStart(params) { - const controller = this.controllers.get(String(params.threadId)); - if (!controller) throw new Error(`Thread is not resumed in DSHX: ${String(params.threadId)}`); - if (params.cwd != null && path.resolve(params.cwd) !== path.resolve(controller.agent.session.header?.cwd ?? this.cwd)) { - throw new Error('DSHX does not own per-turn cwd mutation; resume/start the DSH session in the desired cwd'); - } - if (params.outputSchema != null) throw new Error('DSHX has no faithful public DSH mapping for Codex outputSchema yet'); - - await this.applyModelOverride(controller.agent, { model: params.model, effort: params.effort }); - const permission = this.permissions.current(controller.agent); - const desiredApproval = codexApprovalToDsh(params.approvalPolicy); - if (desiredApproval != null && desiredApproval !== permission.dsh.approvalPolicy) { - throw new Error('Turn-level approval changes must use a DSH permission preset'); - } - if (!sandboxMatchesCurrent(params.sandboxPolicy, permission)) { - throw new Error('Turn-level sandbox changes must use a DSH permission preset'); - } - - const started = await controller.startTurn(turnTextInput(params)); - return { result: { turn: started.turn }, afterResponse: started.release }; - } - - turnInterrupt(params) { - const controller = this.controllers.get(String(params.threadId)); - if (!controller) return { result: {} }; - controller.interrupt({ keepInbox: true }); - return { result: {} }; - } - - async threadUnsubscribe(params) { - const threadId = String(params.threadId ?? ''); - const controller = this.controllers.get(threadId); - if (controller) { - this.approvals.get(threadId)?.dispose(); - this.approvals.delete(threadId); - this.controllers.delete(threadId); - await controller.close(); - } - return { result: {} }; - } - - async threadUnsubscribeWithStatus(params = {}) { - const threadId = String(params.threadId ?? ''); - this.manualCompactions().get(threadId)?.abort(new Error('thread unsubscribed')); - const subscribed = this.controllers.has(threadId); - const loaded = Boolean(this.driver.getLive(threadId)); - await this.threadUnsubscribe(params); - return { - result: { - status: subscribed ? 'unsubscribed' : loaded ? 'notSubscribed' : 'notLoaded' - } - }; - } - - // ── product-layer features ─────────────────────────────────────────────── - - accountUsageRead(_params = {}) { - return { - result: { - summary: { - lifetimeTokens: null, - peakDailyTokens: null, - longestRunningTurnSec: null, - currentStreakDays: null, - longestStreakDays: null - }, - dailyUsageBuckets: null, - threadUsage: null - } - }; - } - - manualCompactions() { - return this._manualCompactions ??= new Map(); - } - - hostApi() { - return this._hostApi ??= new DshHostApi(this.ctx, { cwd: this.cwd }); - } - - warnThread(threadId, message) { - this.send({ method: 'warning', params: { threadId, message } }); - } - - async skillsList(params = {}) { - if (params.forceReload === true) { - this.diagnostics('Codex requested skills forceReload; DSHX is reading the current DSH registry snapshot without overriding provider-owned cache policy'); - } - const cwds = Array.isArray(params.cwds) && params.cwds.length > 0 - ? params.cwds.map((cwd) => path.resolve(cwd)) - : [this.cwd]; - const data = await Promise.all(cwds.map((cwd) => dshSkillsListEntry({ - ctx: this.ctx, - cwd, - diagnostics: this.diagnostics - }))); - return { result: { data } }; - } - - threadCompactStart(params = {}) { - const threadId = String(params.threadId ?? ''); - const controller = this.controllers.get(threadId); - if (!controller) throw new Error(`Thread is not resumed in DSHX: ${threadId}`); - const active = this.manualCompactions(); - if (active.has(threadId)) { - throw new Error('Compaction is unavailable because this thread already has an active manual compaction'); - } - const abortController = new AbortController(); - active.set(threadId, abortController); - return { - result: {}, - afterResponse: () => { - void this.runManualCompaction({ threadId, controller, abortController }); - } - }; - } - - async runManualCompaction({ threadId, controller, abortController }) { - try { - const execution = await executeDshCommand({ - ctx: controller.agent.ctx ?? this.ctx, - agent: controller.agent, - line: '/compact', - signal: abortController.signal - }); - if (execution.result?.sourceEventSeq == null && execution.result?.text) { - this.warnThread(threadId, execution.result.text); - } - } catch (error) { - if (abortController.signal.aborted) { - this.warnThread(threadId, 'Compaction cancelled.'); - } else { - const message = error instanceof Error ? error.message : String(error); - this.warnThread(threadId, message); - this.diagnostics(`manual compaction failed for ${threadId}: ${message}`); - } - } finally { - if (this.manualCompactions().get(threadId) === abortController) { - this.manualCompactions().delete(threadId); - } - } - } - - turnInterruptProduct(params = {}) { - const threadId = String(params.threadId ?? ''); - if (String(params.turnId ?? '').startsWith('dsh-maintenance-compaction-')) { - const active = this.manualCompactions().get(threadId); - if (active) { - active.abort(new Error('user cancelled DSH compaction')); - return { result: {} }; - } - } - return this.turnInterrupt(params); - } - - async forkSourceEvents(sourceId) { - const live = this.controllers.get(sourceId)?.agent ?? this.driver.getLive(sourceId); - if (live?.session) return live.session.events ?? []; - const inspected = await this.driver.inspectSession(sourceId); - if (!inspected) throw new Error(`Unknown DSH session: ${sourceId}`); - return inspected.events ?? []; - } - - async threadFork(params = {}) { - const sourceId = String(params.threadId ?? ''); - if (!sourceId) throw new Error('thread/fork requires threadId'); - if (params.path != null) throw new Error('DSHX forks DSH sessions by threadId, not Codex rollout paths'); - if (params.deferGoalContinuation === true) { - throw new Error('DSH has no Codex thread-goal continuation state for DSHX to defer'); - } - if (params.ephemeral === true) { - throw new Error('DSHX does not expose ephemeral Codex forks over durable DSH sessions'); - } - - const events = await this.forkSourceEvents(sourceId); - const atSeq = codexForkAtSeq(events, { - lastTurnId: params.lastTurnId, - beforeTurnId: params.beforeTurnId - }); - const forked = await this.hostApi().forkSession({ sessionId: sourceId, atSeq }); - const childId = String(forked?.sessionId ?? ''); - if (!childId) throw new Error('DSH Host fork returned no child session id'); - - const childAgent = this.driver.getLive(childId); - if (!childAgent) throw new Error(`DSH Host fork did not publish child Agent ${childId}`); - this.driver.adoptExternalSelection(childAgent, { - select: (selection) => this.hostApi().selectModel({ sessionId: childId, ...selection }) - }); - const controller = this.installController({ agent: childAgent, dispose: async () => {} }); - const result = this.threadResponse(controller.agent, { - includeTurns: params.excludeTurns !== true - }); - return { - result, - afterResponse: () => this.send({ method: 'thread/started', params: { thread: result.thread } }) - }; - } - - historyController(threadId) { - const controller = this.controllers.get(String(threadId ?? '')); - if (!controller) { - throw new Error(`Thread must be resumed before paginated DSH history is rendered: ${String(threadId ?? '')}`); - } - return controller; - } - - threadTurnsList(params = {}) { - const controller = this.historyController(params.threadId); - return { - result: dshThreadTurnsPage({ - controller, - params, - diagnostics: this.diagnostics - }) - }; - } - - threadItemsList(params = {}) { - const controller = this.historyController(params.threadId); - return { - result: dshThreadItemsPage({ - controller, - params, - diagnostics: this.diagnostics - }) - }; - } - - async saveDefaultModelSelection(selection) { - const defaults = this.ctx.get('agentDefaultModel'); - if (!defaults?.saveSelection) { - this.diagnostics('DSH agentDefaultModel service has no saveSelection(); current session selection remains valid but deployment default was not persisted'); - return; - } - await defaults.saveSelection({ - provider: selection.provider, - model: selection.model, - ...(selection.reasoningEffort == null ? {} : { reasoningEffort: selection.reasoningEffort }) - }); - } - - async threadSettingsUpdate(params = {}) { - const threadId = String(params.threadId ?? ''); - const controller = this.controllers.get(threadId); - if (!controller) throw new Error(`Thread is not resumed in DSHX: ${threadId}`); - const agent = controller.agent; - - if (params.cwd != null) { - const currentCwd = path.resolve(agent.session.header?.cwd ?? this.cwd); - if (path.resolve(params.cwd) !== currentCwd) { - throw new Error('DSHX does not retarget a live DSH session cwd from the TUI'); - } - } - if (params.sandboxPolicy != null) { - throw new Error('DSHX changes permissions through DSH named permission presets, not Codex legacy sandboxPolicy'); - } - if (params.serviceTier !== undefined) { - throw new Error('DSH has no public thread service-tier setter for DSHX to project'); - } - if (params.summary != null) { - throw new Error('DSH has no equivalent public reasoning-summary thread setting'); - } - if (params.personality != null) { - throw new Error('DSH has no equivalent public personality thread setting'); - } - if (params.approvalsReviewer != null && params.approvalsReviewer !== 'user') { - throw new Error('DSH approval review is user-owned; DSHX cannot select a Codex-specific reviewer'); - } - - const supported = hasSupportedThreadSetting(params); - if (params.collaborationMode != null && !supported) { - throw new Error('DSH has no equivalent public collaboration-mode thread setting'); - } - - if (params.permissions != null || params.approvalPolicy != null) { - await this.applyStartPermissions(agent, { - permissions: params.permissions, - approvalPolicy: params.approvalPolicy - }); - } - if (params.model != null || params.effort != null) { - const selection = await this.applyModelOverride(agent, { - model: params.model, - effort: params.effort - }); - await this.saveDefaultModelSelection(selection); - } - - return { result: {} }; - } - - turnSteer(params = {}) { - const threadId = String(params.threadId ?? ''); - const controller = this.controllers.get(threadId); - if (!controller) throw new Error(`Thread is not resumed in DSHX: ${threadId}`); - const location = controller.currentLocation(); - if (!location) throw new Error(`Thread has no active DSH turn to steer: ${threadId}`); - if (typeof params.expectedTurnId !== 'string' || params.expectedTurnId !== location.turnId) { - throw new Error( - `DSHX steer expectedTurnId ${JSON.stringify(params.expectedTurnId)} does not match active DSH turn ${location.turnId}` - ); - } - controller.steer(steerTextInput(params)); - return { result: { turnId: location.turnId } }; - } - - // ── release-layer presentation surfaces ────────────────────────────────── - - userShell() { - return this._userShell ??= new DshUserShellBridge({ - send: this.send, - diagnostics: this.diagnostics - }); - } - - workspaceCommands() { - return this._workspaceCommands ??= new DshWorkspaceCommandBridge({ driver: this.driver }); - } - - planListeners() { - return this._planListeners ??= new Map(); - } - - planMutationSuppressed() { - return this._planMutationSuppressed ??= new Set(); - } - - planMode(agent) { - const service = agent?.ctx?.get?.('planMode') ?? this.ctx.get('planMode'); - if (!service?.set || !service?.get) throw new Error('DSHX requires DSH service: planMode'); - return service; - } - - planSettingsNotification(agent) { - const response = this.threadResponse(agent); - return threadSettingsUpdatedNotification({ - threadId: String(agent.id), - response, - planState: this.planMode(agent).get(agent) - }); - } - - liveAgentThread(agent) { - const thread = dshThreadFromSnapshot({ - meta: agent.session.header, - events: agent.session.events ?? [], - model: agent.session.requestHeader?.()?.config, - loaded: true, - cliVersion: this.version - }); - const title = snapshotTitle(this.driver.currentTitle(agent)) ?? foldDshSessionTitle(agent.session.events ?? []); - return { - ...thread, - status: agent.status === 'running' ? { type: 'active', activeFlags: [] } : { type: 'idle' }, - name: title, - turns: [] - }; - } - - directController(threadId, operation) { - const controller = this.controllers.get(String(threadId ?? '')); - if (!controller) throw new Error(`Thread is not resumed in DSHX: ${String(threadId ?? '')}`); - if (isDshSubagent(controller.agent)) { - throw new Error(`DSHX refuses ${operation} on a DSH subagent; child runtime control remains owned by ctx.subagents`); - } - return controller; - } - - async interruptSubagent(controller) { - const parentSessionId = controller.agent.session.header?.parentSession; - if (parentSessionId == null) throw new Error('DSH subagent is missing durable parentSession authority'); - const subagents = this.ctx.get('subagents'); - if (!subagents?.interrupt) throw new Error('DSHX requires DSH service: subagents.interrupt'); - await subagents.interrupt(String(controller.agent.id), { - kind: 'user', - parentSessionId: String(parentSessionId) - }); - return { result: {} }; - } - - async commandExec(params = {}) { - return { result: await this.workspaceCommands().execute(params) }; - } - - async configBatchWrite(params = {}) { - const edits = Array.isArray(params.edits) ? params.edits : []; - if (edits.length === 0) throw new Error('DSHX config/batchWrite requires at least one model-selection edit'); - - const supported = new Set(['model', 'model_reasoning_effort']); - for (const edit of edits) { - if (!supported.has(edit?.keyPath)) { - throw new Error(`DSHX config/batchWrite refuses Codex-owned setting: ${String(edit?.keyPath ?? '')}`); - } - if (edit?.mergeStrategy != null && edit.mergeStrategy !== 'replace') { - throw new Error(`DSHX config/batchWrite supports replace semantics only: ${String(edit.keyPath)}`); - } - } - - const defaults = this.ctx.get('agentDefaultModel'); - const llm = this.ctx.get('llm'); - if (!defaults?.currentSelection || !defaults?.saveSelection) { - throw new Error('DSHX requires DSH service: agentDefaultModel.saveSelection'); - } - if (!llm?.resolveCallConfig) throw new Error('DSHX requires DSH service: llm.resolveCallConfig'); - - const current = defaults.currentSelection(); - let requested = { provider: current.provider, model: current.model }; - if (current.reasoningEffort !== undefined) requested.reasoningEffort = current.reasoningEffort; - - const modelEdit = edits.find((edit) => edit.keyPath === 'model'); - if (modelEdit) { - const decoded = decodeDshModel(modelEdit.value); - if (!decoded) throw new Error('DSHX persists default models only from its DSH-backed opaque model catalog'); - requested = { ...decoded }; - } - - const effortEdit = edits.find((edit) => edit.keyPath === 'model_reasoning_effort'); - if (effortEdit) { - const effort = effortEdit.value == null ? undefined : normalizeCodexEffort(effortEdit.value); - requested = { provider: requested.provider, model: requested.model }; - if (effort !== undefined) requested.reasoningEffort = effort; - } - - const resolved = await llm.resolveCallConfig(requested); - const persisted = { provider: resolved.provider, model: resolved.model }; - // Preserve provider-default semantics when the TUI clears its reasoning - // setting; otherwise persist the DSH-resolved explicit effort. - if (requested.reasoningEffort !== undefined) { - persisted.reasoningEffort = resolved.reasoningEffort ?? requested.reasoningEffort; - } - await defaults.saveSelection(persisted); - - this._configRevision = (this._configRevision ?? 0) + 1; - return { - result: { - status: 'ok', - version: `dshx-${this._configRevision}`, - // Codex requires an absolute path in ConfigWriteResponse. Persistence is - // actually owned by DSH settings; this marker stays inside presentation home. - filePath: path.join(this.home, 'dsh-settings'), - overriddenMetadata: null - } - }; - } - - async richUserTurn(method, params = {}) { - const threadId = String(params.threadId ?? ''); - const controller = this.controllers.get(threadId); - if (!controller) { - // Formerly `super.dispatch(method, params)`: the inherited tail routed - // turn/start to the base turnStart and turn/steer to the product - // turnSteer validator. Route directly to those most-derived methods. - return method === 'turn/steer' ? this.turnSteer(params) : this.turnStart(params); - } - if (isDshSubagent(controller.agent)) { - throw new Error(`DSHX refuses ${method} on a DSH subagent; send/steer authority remains owned by ctx.subagents`); - } - const content = await codexInputToDshContent(this.ctx, params.input ?? []); - const clear = controller.prepareUserContent(content); - try { - // Pinned Codex serializes an unset reasoning effort as JSON null. DSH - // interprets absence as provider default, so never forward null as an - // explicit provider effort. - const normalizedParams = params.effort == null ? { ...params, effort: undefined } : params; - // Preserve the original base/product validation path. The fallback text is - // consumed only if no prepared rich content exists; it also keeps the - // base adapter's expected text-only parameter shape intact. - const forwarded = { ...normalizedParams, input: [{ type: 'text', text: dshContentText(content) }] }; - return method === 'turn/steer' ? this.turnSteer(forwarded) : this.turnStart(forwarded); - } finally { - clear(); - } - } - - async threadForkPresentation(params = {}) { - const response = await this.threadFork(params); - const startedThread = { ...response.result.thread, turns: [] }; - const agent = this.controllers.get(String(response.result.thread.id))?.agent; - return { - ...response, - // Pinned Codex emits copied history only in the fork response. The - // thread/started notification introduces metadata/live state and must not - // replay those copied turns a second time before paginated hydration. - afterResponse: () => { - this.send({ - method: 'thread/started', - params: { thread: startedThread } - }); - if (agent) this.send(this.planSettingsNotification(agent)); - } - }; - } - - async threadSettingsUpdatePresentation(params = {}) { - const threadId = String(params.threadId ?? ''); - const controller = this.controllers.get(threadId); - if (controller && isDshSubagent(controller.agent)) { - throw new Error('DSHX refuses direct model/permission/plan changes on a DSH subagent; composition remains DSH-owned'); - } - if (params.collaborationMode == null) return this.threadSettingsUpdate(params); - if (!controller) throw new Error(`Thread is not resumed in DSHX: ${threadId}`); - const active = codexPlanTarget(params.collaborationMode); - const { collaborationMode: _ignored, ...ordinary } = params; - - // Let the existing DSH-backed settings adapter validate/apply every other - // supported field. The collaboration payload's model/reasoning/instructions - // are intentionally not treated as DSH model or prompt configuration. - await this.threadSettingsUpdate(ordinary); - - this.planMutationSuppressed().add(threadId); - try { - await this.planMode(controller.agent).set(controller.agent, active); - } finally { - this.planMutationSuppressed().delete(threadId); - } - - return { - result: {}, - afterResponse: () => this.send(this.planSettingsNotification(controller.agent)) - }; - } - - threadShellCommand(params = {}) { - const controller = this.directController(params.threadId, 'direct shell execution'); - return this.userShell().start(controller, params.command); - } - - async threadNameSet(params = {}) { - const threadId = String(params.threadId ?? ''); - if (!threadId) throw new Error('thread/name/set requires threadId'); - if (typeof params.name !== 'string') throw new Error('thread/name/set requires name'); - - let temporaryHandle; - let agent = this.controllers.get(threadId)?.agent ?? this.driver.getLive(threadId); - if (!agent) { - temporaryHandle = await this.driver.resume(threadId); - agent = temporaryHandle.agent; - } - - try { - const snapshot = this.driver.renameTitle(agent, params.name); - const threadName = snapshotTitle(snapshot); - if (threadName == null) throw new Error('DSH sessionTitle.rename returned no accepted title'); - return { - result: {}, - afterResponse: () => this.send(threadNameUpdatedNotification(threadId, threadName)) - }; - } finally { - await temporaryHandle?.dispose?.(); - } - } - - // ── synthetic interactions (base) ──────────────────────────────────────── - - openSyntheticInteraction(request) { - const agentId = request?.agent?.id; - if (!agentId) return undefined; - const controller = this.controllers.get(String(agentId)); - const location = controller?.currentLocation(); - if (!location) return undefined; - const itemId = `dshx-interaction-${crypto.randomUUID()}`; - const startedAtMs = Date.now(); - const item = { - type: 'dynamicToolCall', - id: itemId, - namespace: 'dshx', - tool: 'userInteraction', - arguments: { questionCount: request.questions?.length ?? 0 }, - status: 'inProgress', - contentItems: null, - success: null, - durationMs: null - }; - this.syntheticInteractions.set(itemId, { ...location, item, startedAtMs }); - this.send({ - method: 'item/started', - params: { ...location, item, startedAtMs } - }); - return { ...location, itemId }; - } - - completeSyntheticInteraction(location, outcome) { - const state = this.syntheticInteractions.get(location.itemId); - if (!state) return; - this.syntheticInteractions.delete(location.itemId); - const completedAtMs = Date.now(); - const item = { - ...state.item, - status: outcome.status === 'completed' ? 'completed' : 'failed', - success: outcome.status === 'completed', - durationMs: Math.max(0, completedAtMs - state.startedAtMs) - }; - this.send({ - method: 'item/completed', - params: { threadId: state.threadId, turnId: state.turnId, item, completedAtMs } - }); - } - - error(id, code, message, data = undefined) { - const error = { code, message }; - if (data !== undefined) error.data = data; - return { id, error }; - } - - // ── teardown (linearized release → product → base) ────────────────────── - - async close() { - this._userShell?.close(); - for (const dispose of this._agentPresentationDisposers ?? []) dispose?.(); - this._agentPresentationDisposers = []; - for (const dispose of this.planListeners().values()) dispose?.(); - this.planListeners().clear(); - this.planMutationSuppressed().clear(); - for (const controller of this.manualCompactions().values()) { - controller.abort(new Error('DSHX adapter closing')); - } - this.manualCompactions().clear(); - this.userQuestions?.dispose(); - this.userQuestions = null; - this.broker.close(); - const ids = [...this.controllers.keys()]; - for (const id of ids) await this.threadUnsubscribe({ threadId: id }); - } -} - -export const releaseAdapterInternals = { snapshotTitle, isDshSubagent }; diff --git a/.release/dshx-linux-x64/src/tui-protocol/shapes.mjs b/.release/dshx-linux-x64/src/tui-protocol/shapes.mjs deleted file mode 100644 index 3f99f45c..00000000 --- a/.release/dshx-linux-x64/src/tui-protocol/shapes.mjs +++ /dev/null @@ -1,419 +0,0 @@ -import { DshToolPresentationResolver } from '../dsh/tool-presentation.mjs'; - -const MODEL_PREFIX = 'dshx:'; -const DEFAULT_REASONING_SENTINEL = 'dsh-default'; -const DSH_SUBAGENT_DESCRIPTOR_VERSION = 2; - -function seconds(timeMs, fallback = Math.floor(Date.now() / 1000)) { - return Number.isFinite(timeMs) ? Math.floor(timeMs / 1000) : fallback; -} - -function visibleText(content) { - return (content ?? []) - .filter((block) => block?.type === 'text' && typeof block.text === 'string') - .map((block) => block.text) - .join(''); -} - -function visibleReasoning(content) { - return (content ?? []) - .filter((block) => block?.type === 'reasoning' && typeof block.text === 'string') - .map((block) => block.text); -} - -function latestRequestConfig(events) { - for (let index = (events?.length ?? 0) - 1; index >= 0; index -= 1) { - const event = events[index]; - if (event?.type === 'request/header') return event.data?.header?.config ?? null; - } - return null; -} - -function firstHumanPreview(events) { - for (const event of events ?? []) { - if (event?.type !== 'user/message' || event.data?.source?.kind !== 'user') continue; - const text = visibleText(event.data.content).trim(); - if (text) return text.slice(0, 240); - } - return ''; -} - -function turnStatus(reason) { - switch (reason?.kind) { - case 'completed': return 'completed'; - case 'aborted': - case 'interrupted': return 'interrupted'; - default: return 'failed'; - } -} - -function turnError(reason) { - if (reason?.kind !== 'error') return null; - return { - message: reason.error?.message ?? 'DSH turn failed', - codexErrorInfo: null, - additionalDetails: null - }; -} - -function compactionError(message) { - return message == null - ? null - : { message: String(message), codexErrorInfo: null, additionalDetails: null }; -} - -function normalizeList(value) { - if (Array.isArray(value)) return value; - if (Array.isArray(value?.entries)) return value.entries; - return []; -} - -function subagentDescriptor(events = []) { - const event = events.find((candidate) => candidate?.type === 'subagent/descriptor'); - const value = event?.data; - if (!value || value.version !== DSH_SUBAGENT_DESCRIPTOR_VERSION) return null; - if ((value.mode !== 'one-shot' && value.mode !== 'continuable') || typeof value.provider !== 'string') return null; - return { - mode: value.mode, - provider: value.provider, - label: typeof value.label === 'string' && value.label.length > 0 ? value.label : null - }; -} - -function sourceForHeader(header, events = []) { - if (header?.origin === 'subagent' && header.parentSession != null) { - const descriptor = subagentDescriptor(events); - return { - subagent: { - thread_spawn: { - parent_thread_id: String(header.parentSession), - depth: Number.isInteger(header.delegationDepth) ? header.delegationDepth : 1, - agent_path: null, - agent_nickname: descriptor?.label ?? null, - agent_role: null - } - } - }; - } - return { custom: 'dshx' }; -} - -function inputFromDshMessage(message) { - const content = []; - for (const block of message?.content ?? []) { - if (block?.type === 'text' && typeof block.text === 'string') { - content.push({ type: 'text', text: block.text, text_elements: [] }); - } - } - return content; -} - -function historyTurn(id, startedAt) { - return { - id, - items: [], - itemsView: 'full', - status: 'inProgress', - error: null, - startedAt, - completedAt: null, - durationMs: null - }; -} - -export function encodeDshModel(selection) { - if (!selection?.provider || !selection?.model) throw new Error('DSHX model selection requires provider and model'); - const payload = Buffer.from(JSON.stringify([selection.provider, selection.model]), 'utf8').toString('base64url'); - return `${MODEL_PREFIX}${payload}`; -} - -export function decodeDshModel(value) { - if (typeof value !== 'string' || !value.startsWith(MODEL_PREFIX)) return undefined; - try { - const decoded = JSON.parse(Buffer.from(value.slice(MODEL_PREFIX.length), 'base64url').toString('utf8')); - if (!Array.isArray(decoded) || decoded.length !== 2 || decoded.some((part) => typeof part !== 'string' || !part)) { - return undefined; - } - return { provider: decoded[0], model: decoded[1] }; - } catch { - return undefined; - } -} - -export function normalizeCodexEffort(value) { - return value === DEFAULT_REASONING_SENTINEL ? undefined : value; -} - -/** - * Translate the public DSH LLM registry into Codex's provider-less model picker. - * Provider identity is encoded only in the opaque `model`/`id` value and decoded - * again by DSHX before calling `ctx.llm.resolveCallConfig()`. - */ -export function codexModelsFromDsh(directory, currentSelection) { - const groups = directory?.groups ?? []; - const multipleProviders = groups.length > 1; - const models = []; - for (const group of groups) { - for (const model of group.models ?? []) { - const encoded = encodeDshModel({ provider: group.provider, model: model.id }); - const efforts = model.reasoning?.efforts ?? []; - const supportedReasoningEfforts = efforts.length > 0 - ? efforts.map((effort) => ({ - reasoningEffort: effort.id, - description: effort.description ?? effort.name ?? effort.id - })) - : [{ reasoningEffort: DEFAULT_REASONING_SENTINEL, description: 'Use the DSH provider default' }]; - const defaultReasoningEffort = model.reasoning?.defaultEffort ?? DEFAULT_REASONING_SENTINEL; - const displayName = multipleProviders - ? `${model.name ?? model.id} · ${group.name ?? group.provider}` - : (model.name ?? model.id); - models.push({ - id: encoded, - model: encoded, - upgrade: null, - upgradeInfo: null, - availabilityNux: null, - displayName, - description: model.description ?? `${group.name ?? group.provider} / ${model.id}`, - modelSpecialty: null, - hidden: false, - supportedReasoningEfforts, - defaultReasoningEffort, - inputModalities: (model.inputModalities ?? []).filter((entry) => entry === 'text' || entry === 'image'), - supportsPersonality: false, - multiAgentVersion: null, - additionalSpeedTiers: [], - serviceTiers: [], - defaultServiceTier: null, - isDefault: currentSelection?.provider === group.provider && currentSelection?.model === model.id - }); - } - } - return models; -} - -export function dshThreadFromSnapshot({ meta, events = [], model, turns = [], loaded = false, cliVersion = 'dshx' }) { - if (!meta?.id) throw new Error('DSHX thread projection requires SessionHeader.id'); - const config = model ?? latestRequestConfig(events) ?? {}; - const createdAt = seconds(meta.createdAt); - const lastTime = events.length > 0 ? events[events.length - 1]?.time : meta.createdAt; - const isSubagent = meta.origin === 'subagent'; - const descriptor = isSubagent ? subagentDescriptor(events) : null; - let openTurn = false; - for (const event of events) { - if (event?.type === 'turn/start') openTurn = true; - else if (event?.type === 'turn/end') openTurn = false; - } - return { - id: String(meta.id), - extra: null, - sessionId: String(meta.id), - forkedFromId: !isSubagent && meta.parentSession ? String(meta.parentSession) : null, - parentThreadId: isSubagent && meta.parentSession ? String(meta.parentSession) : null, - preview: firstHumanPreview(events), - ephemeral: false, - section: null, - sectionEnteredAt: null, - projectId: null, - historyMode: 'paginated', - modelProvider: config.provider ?? 'dsh', - createdAt, - updatedAt: seconds(lastTime, createdAt), - recencyAt: seconds(lastTime, createdAt), - status: loaded ? (openTurn ? { type: 'active', activeFlags: [] } : { type: 'idle' }) : { type: 'notLoaded' }, - path: null, - cwd: meta.cwd ?? process.cwd(), - cliVersion, - source: sourceForHeader(meta, events), - // DSH continuation authority belongs to ctx.subagents. Showing a child in - // Codex navigation must never create a presentation-side bypass that sends - // a user turn directly to the child Agent. - canAcceptDirectInput: isSubagent ? false : loaded ? true : null, - threadSource: null, - agentNickname: descriptor?.label ?? null, - agentRole: null, - gitInfo: null, - name: null, - turns - }; -} - -/** - * Replay the authoritative DSH raw log as a human transcript. This intentionally - * does not fold the model surface: DSH's own terminal/web transcript contract - * keeps messages shadowed by compaction visible to the human and inserts a - * compaction marker at the landed checkpoint. The plugin-sourced replacement - * user/message is therefore ignored as model-only framing. - */ -export function dshTurnsFromSession({ ctx, agent, diagnostics = () => {} }) { - const session = agent?.session; - if (!session) return []; - const turns = new Map(); - const compactions = new Map(); - let currentTurn; - const toolPresenter = new DshToolPresentationResolver({ - ctx: agent.ctx ?? ctx, - agent, - threadId: String(agent.id), - workspaceCwd: session.header?.cwd ?? process.cwd(), - diagnostics - }); - - for (const event of session.events ?? []) { - switch (event.type) { - case 'turn/start': { - const number = event.data?.turn; - if (!Number.isInteger(number)) break; - const startedAt = seconds(event.time); - turns.set(number, historyTurn(`dsh-turn-${number}`, startedAt)); - currentTurn = number; - break; - } - case 'user/message': { - const turn = turns.get(currentTurn); - const message = event.data; - if (!turn || message?.source?.kind !== 'user') break; - const content = inputFromDshMessage(message); - if (content.length === 0) break; - turn.items.push({ type: 'userMessage', id: String(message.id), clientId: null, content }); - break; - } - case 'assistant/message': { - const turn = turns.get(event.data?.turn); - const message = event.data?.message; - if (!turn || !message) break; - const reasoning = visibleReasoning(message.content); - if (reasoning.length > 0) { - turn.items.push({ - type: 'reasoning', - id: `dsh-reasoning-${event.data.turn}-${event.data.step}`, - summary: [], - content: reasoning - }); - } - const text = visibleText(message.content); - if (text.length > 0) { - turn.items.push({ - type: 'agentMessage', - id: String(message.id ?? `dsh-assistant-${event.data.turn}-${event.data.step}`), - text, - phase: null, - memoryCitation: null, - delivery: null - }); - } - break; - } - case 'tool/call': { - const turn = turns.get(event.data?.turn); - if (!turn) break; - const projected = toolPresenter.start({ - turnId: turn.id, - callId: event.data.callId, - name: event.data.name, - rawArguments: event.data.arguments, - startedAtMs: event.time - }); - turn.items.push(projected.item); - break; - } - case 'tool/result': { - const callId = event.data?.message?.source?.callId - ?? event.data?.message?.content?.find?.((block) => block?.type === 'tool-result')?.toolCallId; - if (!callId) break; - const completed = toolPresenter.complete({ callId, resultData: event.data, completedAtMs: event.time }); - if (!completed) break; - for (const turn of turns.values()) { - const index = turn.items.findIndex((item) => item.id === completed.item.id); - if (index >= 0) { - turn.items[index] = completed.item; - break; - } - } - break; - } - case 'compaction/start': { - const { compactionId, turn } = event.data ?? {}; - if (typeof compactionId !== 'string' || compactionId.length === 0) break; - let turnKey; - let target; - let manual = false; - if (Number.isInteger(turn)) { - turnKey = turn; - target = turns.get(turnKey); - if (!target) break; - } else if (turn === null) { - manual = true; - turnKey = `compact:${compactionId}`; - target = historyTurn(`dsh-maintenance-compaction-${compactionId}`, seconds(event.time)); - turns.set(turnKey, target); - } else { - break; - } - compactions.set(compactionId, { - turnKey, - turn: target, - manual, - summarized: false, - itemId: `dsh-compaction-${compactionId}` - }); - break; - } - case 'compaction/summary': { - const state = compactions.get(event.data?.compactionId); - if (!state) break; - state.summarized = true; - state.turn.items.push({ type: 'contextCompaction', id: state.itemId }); - break; - } - case 'compaction/end': { - const state = compactions.get(event.data?.compactionId); - if (!state) break; - compactions.delete(event.data.compactionId); - if (state.manual) { - if (!state.summarized) { - turns.delete(state.turnKey); - break; - } - const completedAt = seconds(event.time); - state.turn.status = event.data?.error == null ? 'completed' : 'failed'; - state.turn.error = compactionError(event.data?.error); - state.turn.completedAt = completedAt; - state.turn.durationMs = state.turn.startedAt == null - ? null - : Math.max(0, (completedAt - state.turn.startedAt) * 1000); - } - break; - } - case 'turn/end': { - const number = event.data?.turn; - const turn = turns.get(number); - if (!turn) break; - const completedAt = seconds(event.time); - turn.status = turnStatus(event.data.reason); - turn.error = turnError(event.data.reason); - turn.completedAt = completedAt; - turn.durationMs = turn.startedAt == null ? null : Math.max(0, (completedAt - turn.startedAt) * 1000); - if (currentTurn === number) currentTurn = undefined; - break; - } - default: - break; - } - } - return [...turns.values()]; -} - -export function normalizeSessionHeaders(value) { - return normalizeList(value); -} - -export const internals = { - DEFAULT_REASONING_SENTINEL, - latestRequestConfig, - firstHumanPreview, - inputFromDshMessage, - visibleReasoning, - subagentDescriptor, - sourceForHeader -}; diff --git a/.release/dshx-linux-x64/upstream/CODEX_COMMIT b/.release/dshx-linux-x64/upstream/CODEX_COMMIT deleted file mode 100644 index c4d68c85..00000000 --- a/.release/dshx-linux-x64/upstream/CODEX_COMMIT +++ /dev/null @@ -1 +0,0 @@ -fde2156057c38c0227ce94c8514d04c7498df60d diff --git a/.release/dshx-linux-x64/upstream/DSH_COMMIT b/.release/dshx-linux-x64/upstream/DSH_COMMIT deleted file mode 100644 index cbba87c8..00000000 --- a/.release/dshx-linux-x64/upstream/DSH_COMMIT +++ /dev/null @@ -1 +0,0 @@ -141eb6fef83422698aef7a981029e843e8161534 diff --git a/.release/dshx-linux-x64/upstream/patches/codex/0001-dshx-force-ui-backend.patch b/.release/dshx-linux-x64/upstream/patches/codex/0001-dshx-force-ui-backend.patch deleted file mode 100644 index f2a8bb2c..00000000 --- a/.release/dshx-linux-x64/upstream/patches/codex/0001-dshx-force-ui-backend.patch +++ /dev/null @@ -1,65 +0,0 @@ -diff --git a/codex-rs/tui/src/main.rs b/codex-rs/tui/src/main.rs ---- a/codex-rs/tui/src/main.rs -+++ b/codex-rs/tui/src/main.rs -@@ -1,10 +1,12 @@ - use clap::Parser; -+use codex_app_server_client::RemoteAppServerEndpoint; - use codex_arg0::Arg0DispatchPaths; - use codex_arg0::arg0_dispatch_or_else; - use codex_config::LoaderOverrides; - use codex_tui::AppExitInfo; - use codex_tui::Cli; - use codex_tui::ExitReason; -+use codex_tui::resolve_remote_addr; - use codex_tui::run_main; - use codex_utils_cli::CliConfigOverrides; - use std::io::Write; -@@ -47,6 +49,42 @@ fn main() -> anyhow::Result<()> { - inner - .config_overrides - .raw_overrides - .splice(0..0, top_cli.config_overrides.raw_overrides); -+ if let Ok(mode) = std::env::var("DSHX_RESUME_MODE") { -+ match mode.as_str() { -+ "picker" => inner.resume_picker = true, -+ "last" => inner.resume_last = true, -+ "id" => { -+ inner.resume_session_id = Some( -+ std::env::var("DSHX_RESUME_SESSION_ID").map_err(|_| { -+ anyhow::anyhow!( -+ "DSHX_RESUME_SESSION_ID is required when DSHX_RESUME_MODE=id" -+ ) -+ })?, -+ ); -+ } -+ other => anyhow::bail!("invalid DSHX_RESUME_MODE: {other}"), -+ } -+ } -+ let dshx_endpoint = std::env::var("DSHX_APP_SERVER_ENDPOINT").map_err(|_| { -+ anyhow::anyhow!( -+ "DSHX_APP_SERVER_ENDPOINT is required; DSHX never falls back to the Codex agent runtime" -+ ) -+ })?; -+ let dshx_token = std::env::var("DSHX_APP_SERVER_TOKEN").map_err(|_| { -+ anyhow::anyhow!( -+ "DSHX_APP_SERVER_TOKEN is required; DSHX local transport is always authenticated" -+ ) -+ })?; -+ let mut dshx_endpoint = resolve_remote_addr(&dshx_endpoint)?; -+ match &mut dshx_endpoint { -+ RemoteAppServerEndpoint::WebSocket { auth_token, .. } => { -+ *auth_token = Some(dshx_token); -+ } -+ RemoteAppServerEndpoint::UnixSocket { .. } => { -+ anyhow::bail!("DSHX production launcher requires authenticated loopback WebSocket transport") -+ } -+ } - let exit_info = run_main( - inner, - arg0_paths, - LoaderOverrides::default(), -- /*explicit_remote_endpoint*/ None, -+ /*explicit_remote_endpoint*/ Some(dshx_endpoint), - ) - .await?; - let is_fatal = match &exit_info.exit_reason { diff --git a/.release/dshx-linux-x64/upstream/patches/codex/0002-dshx-branding.patch b/.release/dshx-linux-x64/upstream/patches/codex/0002-dshx-branding.patch deleted file mode 100644 index ed950523..00000000 --- a/.release/dshx-linux-x64/upstream/patches/codex/0002-dshx-branding.patch +++ /dev/null @@ -1,38 +0,0 @@ -diff --git a/codex-rs/tui/src/history_cell/session.rs b/codex-rs/tui/src/history_cell/session.rs ---- a/codex-rs/tui/src/history_cell/session.rs -+++ b/codex-rs/tui/src/history_cell/session.rs -@@ -142,7 +142,7 @@ pub(crate) fn new_session_info( - Line::from(vec![ - " ".into(), - "/init".into(), -- " - create an AGENTS.md file with instructions for Codex".dim(), -+ " - create an AGENTS.md file with instructions for DeepSeek Harness".dim(), - ]), -@@ -152,7 +152,7 @@ pub(crate) fn new_session_info( - Line::from(vec![ - " ".into(), - "/permissions".into(), -- " - choose what Codex is allowed to do".dim(), -+ " - choose what DeepSeek Harness is allowed to do".dim(), - ]), -@@ -269,10 +269,10 @@ impl HistoryCell for SessionHeaderHistoryCell { - let make_row = |spans: Vec>| Line::from(spans); - -- // Title line rendered inside the box: ">_ OpenAI Codex (vX)" -+ // DSHX changes branding only; layout and interaction stay upstream Codex. - let title_spans: Vec> = vec![ - Span::from(">_ ").dim(), -- Span::from("OpenAI Codex").bold(), -+ Span::from("DeepSeek Harness").bold(), - Span::from(" ").dim(), - Span::from(format!("(v{})", self.version)).dim(), - ]; -@@ -335,7 +335,7 @@ impl HistoryCell for SessionHeaderHistoryCell { - - fn raw_lines(&self) -> Vec> { - let mut lines = vec![ -- Line::from(format!("OpenAI Codex (v{})", self.version)), -+ Line::from(format!("DeepSeek Harness (v{})", self.version)), - Line::from(format!( - "model: {}{}", - self.model, diff --git a/.release/dshx-linux-x64/upstream/patches/codex/0003-dshx-approval-semantics.patch b/.release/dshx-linux-x64/upstream/patches/codex/0003-dshx-approval-semantics.patch deleted file mode 100644 index a54067df..00000000 --- a/.release/dshx-linux-x64/upstream/patches/codex/0003-dshx-approval-semantics.patch +++ /dev/null @@ -1,91 +0,0 @@ -diff --git a/codex-rs/tui/src/bottom_pane/approval_overlay.rs b/codex-rs/tui/src/bottom_pane/approval_overlay.rs ---- a/codex-rs/tui/src/bottom_pane/approval_overlay.rs -+++ b/codex-rs/tui/src/bottom_pane/approval_overlay.rs -@@ -796,6 +796,10 @@ struct ApprovalOption { - shortcuts: Vec, - } - -+fn dshx_backend() -> bool { -+ std::env::var_os("DSHX_APP_SERVER_ENDPOINT").is_some() -+} -+ - fn command_decision_to_review_decision( - decision: &CommandExecutionApprovalDecision, - ) -> ReviewDecision { -@@ -855,6 +859,7 @@ fn exec_options( - }) - } -+ CommandExecutionApprovalDecision::AcceptForSession if dshx_backend() => None, - CommandExecutionApprovalDecision::AcceptForSession => Some(ApprovalOption { - label: if network_approval_context.is_some() { - "Yes, and allow this host for this conversation".to_string() -@@ -951,24 +956,27 @@ fn patch_options(keymap: &ApprovalKeymap) -> Vec { -- vec![ -+ let mut options = vec![ - ApprovalOption { - label: "Yes, proceed".to_string(), - decision: ApprovalDecision::FileChange(FileChangeApprovalDecision::Accept), - shortcuts: keymap.approve.clone(), - }, -- ApprovalOption { -- label: "Yes, and don't ask again for these files".to_string(), -- decision: ApprovalDecision::FileChange(FileChangeApprovalDecision::AcceptForSession), -- shortcuts: keymap.approve_for_session.clone(), -- }, - ApprovalOption { -- label: "No, and tell Codex what to do differently".to_string(), -+ label: if dshx_backend() { -+ "No, and tell DeepSeek Harness what to do differently".to_string() -+ } else { -+ "No, and tell Codex what to do differently".to_string() -+ }, - decision: ApprovalDecision::FileChange(FileChangeApprovalDecision::Cancel), - shortcuts: keymap.decline.clone(), - }, -- ] -+ ]; -+ if !dshx_backend() { -+ options.insert(1, ApprovalOption { -+ label: "Yes, and don't ask again for these files".to_string(), -+ decision: ApprovalDecision::FileChange(FileChangeApprovalDecision::AcceptForSession), -+ shortcuts: keymap.approve_for_session.clone(), -+ }); -+ } -+ options - } - - fn permissions_options(keymap: &ApprovalKeymap) -> Vec { -@@ -978,7 +986,7 @@ fn permissions_options(keymap: &ApprovalKeymap) -> Vec { - .filter(|shortcut| shortcut.parts() != (KeyCode::Esc, KeyModifiers::NONE)) - .collect(); - -- vec![ -+ let mut options = vec![ - ApprovalOption { - label: "Yes, grant these permissions for this turn".to_string(), - decision: ApprovalDecision::Permissions(PermissionsDecision::GrantForTurn), -@@ -991,16 +999,19 @@ fn permissions_options(keymap: &ApprovalKeymap) -> Vec { - ), - shortcuts: vec![key_hint::plain(KeyCode::Char('r'))], - }, -- ApprovalOption { -- label: "Yes, grant these permissions for this session".to_string(), -- decision: ApprovalDecision::Permissions(PermissionsDecision::GrantForSession), -- shortcuts: keymap.approve_for_session.clone(), -- }, - ApprovalOption { - label: "No, continue without permissions".to_string(), - decision: ApprovalDecision::Permissions(PermissionsDecision::Deny), - shortcuts: deny_shortcuts, - }, -- ] -+ ]; -+ if !dshx_backend() { -+ options.insert(2, ApprovalOption { -+ label: "Yes, grant these permissions for this session".to_string(), -+ decision: ApprovalDecision::Permissions(PermissionsDecision::GrantForSession), -+ shortcuts: keymap.approve_for_session.clone(), -+ }); -+ } -+ options - } diff --git a/.release/dshx-linux-x64/upstream/patches/codex/0004-dshx-permission-picker.patch b/.release/dshx-linux-x64/upstream/patches/codex/0004-dshx-permission-picker.patch deleted file mode 100644 index 14366be2..00000000 --- a/.release/dshx-linux-x64/upstream/patches/codex/0004-dshx-permission-picker.patch +++ /dev/null @@ -1,60 +0,0 @@ -diff --git a/codex-rs/tui/src/chatwidget/permission_popups.rs b/codex-rs/tui/src/chatwidget/permission_popups.rs ---- a/codex-rs/tui/src/chatwidget/permission_popups.rs -+++ b/codex-rs/tui/src/chatwidget/permission_popups.rs -@@ -7,33 +7,39 @@ - use super::*; - use codex_protocol::openai_models::MODEL_SPECIALTY_CYBER; - -+fn dshx_backend() -> bool { -+ std::env::var_os("DSHX_APP_SERVER_ENDPOINT").is_some() -+} -+ - impl ChatWidget { - /// Open the permissions popup. - pub(crate) fn open_approvals_popup(&mut self) { - self.open_permissions_popup(); - } - - /// Open a popup to choose the permissions mode. - pub(crate) fn open_permissions_popup(&mut self) { - if self.config.explicit_permission_profile_mode { - self.open_permission_profiles_popup(); - return; - } - - let include_read_only = cfg!(target_os = "windows"); - let current_approval = - AskForApproval::from(self.config.permissions.approval_policy.value()); - let current_permission_profile = self.config.permissions.permission_profile().clone(); -- let guardian_approval_enabled = self.config.features.enabled(Feature::GuardianApproval); -+ let guardian_approval_enabled = !dshx_backend() -+ && self.config.features.enabled(Feature::GuardianApproval); - let current_review_policy = self.config.approvals_reviewer; - let mut items: Vec = Vec::new(); - let presets: Vec = builtin_approval_presets(); - - #[cfg(target_os = "windows")] - let windows_sandbox_level = crate::windows_sandbox::level_from_config(&self.config); - #[cfg(target_os = "windows")] - let windows_degraded_sandbox_enabled = -- matches!(windows_sandbox_level, WindowsSandboxLevel::RestrictedToken); -+ !dshx_backend() -+ && matches!(windows_sandbox_level, WindowsSandboxLevel::RestrictedToken); - #[cfg(not(target_os = "windows"))] - let windows_degraded_sandbox_enabled = false; - - let show_elevate_sandbox_hint = - windows_degraded_sandbox_enabled && presets.iter().any(|preset| preset.id == "auto"); -@@ -313,7 +319,11 @@ impl ChatWidget { - }); - })]; - } -- if approvals_reviewer == ApprovalsReviewer::User && preset.id == "auto" { -+ // DSHX never enables or configures Codex's local Windows sandbox. The -+ // selected workspace preset is sent to the DSH app-server adapter and -+ // DSH remains the enforcement owner. -+ if !dshx_backend() -+ && approvals_reviewer == ApprovalsReviewer::User && preset.id == "auto" { - #[cfg(target_os = "windows")] - { - if crate::windows_sandbox::level_from_config(&self.config) diff --git a/.release/dshx-linux-x64/upstream/patches/codex/0005-dshx-skip-codex-onboarding.patch b/.release/dshx-linux-x64/upstream/patches/codex/0005-dshx-skip-codex-onboarding.patch deleted file mode 100644 index d55e8ef2..00000000 --- a/.release/dshx-linux-x64/upstream/patches/codex/0005-dshx-skip-codex-onboarding.patch +++ /dev/null @@ -1,112 +0,0 @@ -diff --git a/codex-rs/tui/src/lib.rs b/codex-rs/tui/src/lib.rs ---- a/codex-rs/tui/src/lib.rs -+++ b/codex-rs/tui/src/lib.rs -@@ -232,8 +232,12 @@ - const TUI_LOG_FILE_NAME: &str = "codex-tui.log"; - const INTERACTIVE_OTEL_SHUTDOWN_TIMEOUT: Duration = Duration::from_millis(/*millis*/ 500); - -+fn dshx_backend() -> bool { -+ std::env::var_os("DSHX_APP_SERVER_ENDPOINT").is_some() -+} -+ - #[cfg(unix)] - const AUTO_CONNECT_DAEMON_CONNECT_TIMEOUT: std::time::Duration = - std::time::Duration::from_millis(50); - -@@ -1068,7 +1072,9 @@ - } - } - let remote_project_trust = -- if uses_remote_workspace && let Some(remote_cwd) = remote_cwd_override.as_deref() { -+ if !dshx_backend() -+ && uses_remote_workspace -+ && let Some(remote_cwd) = remote_cwd_override.as_deref() { - match startup_draft - .run_until( - &mut tui, -@@ -1094,10 +1100,11 @@ - } else { - None - }; - let mut app_server = Some(app_server_session); -- let should_show_trust_screen_flag = remote_project_trust.is_some() -- || (!uses_remote_workspace && should_show_trust_screen(&initial_config)); -+ let should_show_trust_screen_flag = !dshx_backend() -+ && (remote_project_trust.is_some() -+ || (!uses_remote_workspace && should_show_trust_screen(&initial_config))); - #[cfg(target_os = "windows")] - let mut trust_decision_was_made = false; - let startup_model_provider = initial_config.model_provider_id.clone(); - let (login_status, mut startup_account) = if workload_identity_selected { - (LoginStatus::AuthMode(AuthMode::Chatgpt), None) -- } else if initial_config.model_provider.requires_openai_auth { -+ } else if !dshx_backend() && initial_config.model_provider.requires_openai_auth { - let Some(active_app_server) = app_server.as_mut() else { - unreachable!("app server should exist when auth is required"); - }; -@@ -1128,8 +1135,9 @@ - } else { - (LoginStatus::NotAuthenticated, None) - }; - let should_show_onboarding = -- should_show_onboarding(login_status, &initial_config, should_show_trust_screen_flag); -+ !dshx_backend() -+ && should_show_onboarding(login_status, &initial_config, should_show_trust_screen_flag); - - let config = if should_show_onboarding { - if let Err(err) = startup_draft.flush_pending_events(&mut tui).await { - shutdown_startup_session(app_server.take(), &mut terminal_restore_guard).await; -diff --git a/codex-rs/tui/src/app/startup.rs b/codex-rs/tui/src/app/startup.rs ---- a/codex-rs/tui/src/app/startup.rs -+++ b/codex-rs/tui/src/app/startup.rs -@@ -4,9 +4,12 @@ - //! remains isolated from protected interactive requests until the initialized composer owns it. - - use super::*; - - async fn resolve_runtime_model_provider_base_url(provider: &ModelProviderInfo) -> Option { -+ if crate::dshx_backend() { -+ return None; -+ } - let provider = create_model_provider(provider.clone(), /*auth_manager*/ None); - match provider.runtime_base_url().await { - Ok(base_url) => base_url, - Err(err) => { -@@ -384,8 +387,9 @@ - chat_widget.note_rendered_width(tui.terminal.last_known_screen_size.width); - chat_widget.remote_connection = remote_connection; - let thread_and_widget_ms = thread_and_widget_started_at.elapsed().as_millis(); -- chat_widget -- .maybe_prompt_windows_sandbox_enable(should_prompt_windows_sandbox_nux_at_startup); -+ chat_widget.maybe_prompt_windows_sandbox_enable( -+ should_prompt_windows_sandbox_nux_at_startup && !crate::dshx_backend(), -+ ); - - let file_search = FileSearchManager::new(config.cwd.to_path_buf(), app_event_tx.clone()); - let runtime_keymap = RuntimeKeymap::from_config(&config.tui_keymap).map_err(|err| { -@@ -399,7 +403,11 @@ - See the Codex keymap documentation for supported actions and examples." - ) - })?; - #[cfg(not(debug_assertions))] -- let upgrade_version = crate::updates::get_upgrade_version(&config); -+ let upgrade_version = if crate::dshx_backend() { -+ None -+ } else { -+ crate::updates::get_upgrade_version(&config) -+ }; - - let mut app = Self { - model_catalog, -@@ -488,8 +496,9 @@ - // world-writable dirs on Windows. - #[cfg(target_os = "windows")] - { - let startup_permission_profile = app.config.permissions.effective_permission_profile(); -- let should_check = crate::windows_sandbox::level_from_config(&app.config) -+ let should_check = !crate::dshx_backend() -+ && crate::windows_sandbox::level_from_config(&app.config) - != WindowsSandboxLevel::Disabled - && managed_filesystem_sandbox_is_restricted(&startup_permission_profile) - && !app - .config diff --git a/.release/dshx-linux-x64/upstream/patches/codex/0006-dshx-config-ownership.patch b/.release/dshx-linux-x64/upstream/patches/codex/0006-dshx-config-ownership.patch deleted file mode 100644 index 456486b7..00000000 --- a/.release/dshx-linux-x64/upstream/patches/codex/0006-dshx-config-ownership.patch +++ /dev/null @@ -1,13 +0,0 @@ -diff --git a/codex-rs/tui/src/app/event_dispatch.rs b/codex-rs/tui/src/app/event_dispatch.rs ---- a/codex-rs/tui/src/app/event_dispatch.rs -+++ b/codex-rs/tui/src/app/event_dispatch.rs -@@ -1518,7 +1518,8 @@ impl App { - self.sync_active_thread_service_tier_to_cached_session() - .await; - -- if let Some(default_effort) = default_effort.as_ref() -+ if !crate::dshx_backend() -+ && let Some(default_effort) = default_effort.as_ref() - && let Err(err) = crate::config_update::write_config_batch( - app_server.request_handle(), - crate::config_update::build_model_selection_edits( diff --git a/.release/dshx-linux-x64/upstream/patches/codex/0007-dshx-thread-ownership.patch b/.release/dshx-linux-x64/upstream/patches/codex/0007-dshx-thread-ownership.patch deleted file mode 100644 index 41161174..00000000 --- a/.release/dshx-linux-x64/upstream/patches/codex/0007-dshx-thread-ownership.patch +++ /dev/null @@ -1,46 +0,0 @@ -diff --git a/codex-rs/tui/src/app_server_session.rs b/codex-rs/tui/src/app_server_session.rs ---- a/codex-rs/tui/src/app_server_session.rs -+++ b/codex-rs/tui/src/app_server_session.rs -@@ -1660,6 +1660,18 @@ fn thread_start_params_from_config( - remote_cwd_override: Option<&std::path::Path>, - session_start_source: Option, - ) -> ThreadStartParams { -+ if crate::dshx_backend() && matches!(thread_params_mode, ThreadParamsMode::Remote) { -+ return ThreadStartParams { -+ cwd: thread_cwd_from_config(config, thread_params_mode, remote_cwd_override), -+ ephemeral: Some(config.ephemeral), -+ history_mode: (!config.ephemeral).then_some(ThreadHistoryMode::Paginated), -+ session_start_source, -+ thread_source: Some(ThreadSource::User), -+ ..ThreadStartParams::default() -+ }; -+ } - let permissions = permissions_selection_from_config(config, thread_params_mode); - let sandbox = permissions - .is_none() -@@ -1703,6 +1715,12 @@ fn thread_resume_params_from_config( - remote_cwd_override: Option<&std::path::Path>, - model_settings: ResumeModelSettings, - ) -> ThreadResumeParams { -+ if crate::dshx_backend() && matches!(thread_params_mode, ThreadParamsMode::Remote) { -+ return ThreadResumeParams { -+ thread_id: thread_id.to_string(), -+ ..ThreadResumeParams::default() -+ }; -+ } - if model_settings == ResumeModelSettings::PreserveExistingThread { - return ThreadResumeParams { - thread_id: thread_id.to_string(), -@@ -1755,6 +1773,12 @@ fn thread_fork_params_from_config( - thread_params_mode: ThreadParamsMode, - remote_cwd_override: Option<&std::path::Path>, - ) -> ThreadForkParams { -+ if crate::dshx_backend() && matches!(thread_params_mode, ThreadParamsMode::Remote) { -+ return ThreadForkParams { -+ thread_id: thread_id.to_string(), -+ ..ThreadForkParams::default() -+ }; -+ } - let permissions = permissions_selection_from_config(&config, thread_params_mode); - let sandbox = permissions - .is_none() diff --git a/.release/dshx-linux-x64/upstream/patches/codex/0008-dshx-resume-hint.patch b/.release/dshx-linux-x64/upstream/patches/codex/0008-dshx-resume-hint.patch deleted file mode 100644 index 117c9ffc..00000000 --- a/.release/dshx-linux-x64/upstream/patches/codex/0008-dshx-resume-hint.patch +++ /dev/null @@ -1,17 +0,0 @@ -diff --git a/codex-rs/tui/src/app.rs b/codex-rs/tui/src/app.rs ---- a/codex-rs/tui/src/app.rs -+++ b/codex-rs/tui/src/app.rs -@@ -471,7 +471,12 @@ fn resume_hint_for_resumable_thread( - rollout_path: Option<&Path>, - ) -> Option { - let thread = resumable_thread(thread_id, thread_name, rollout_path)?; -- codex_utils_cli::resume_hint(thread.thread_name.as_deref(), Some(thread.thread_id)) -+ let hint = codex_utils_cli::resume_hint(thread.thread_name.as_deref(), Some(thread.thread_id)); -+ if crate::dshx_backend() { -+ hint.map(|hint| hint.replacen("codex", "dshx", 1)) -+ } else { -+ hint -+ } - } - - fn rollout_path_is_resumable(rollout_path: &Path) -> bool { diff --git a/.release/dshx-linux-x64/upstream/patches/codex/0009-dshx-slash-capabilities.patch b/.release/dshx-linux-x64/upstream/patches/codex/0009-dshx-slash-capabilities.patch deleted file mode 100644 index df2eb2a3..00000000 --- a/.release/dshx-linux-x64/upstream/patches/codex/0009-dshx-slash-capabilities.patch +++ /dev/null @@ -1,106 +0,0 @@ -diff --git a/codex-rs/tui/src/slash_command.rs b/codex-rs/tui/src/slash_command.rs ---- a/codex-rs/tui/src/slash_command.rs -+++ b/codex-rs/tui/src/slash_command.rs -@@ -86,48 +86,48 @@ impl SlashCommand { - pub fn description(self) -> &'static str { - match self { - SlashCommand::Feedback => "send logs to maintainers", - SlashCommand::New => "start a new chat during a conversation", -- SlashCommand::Init => "create an AGENTS.md file with instructions for Codex", -+ SlashCommand::Init => "create an AGENTS.md file with instructions for DeepSeek Harness", - SlashCommand::Compact => "summarize conversation to prevent hitting the context limit", - SlashCommand::Review => "review my current changes and find issues", - SlashCommand::Rename => "rename the current thread", - SlashCommand::Resume => "resume a saved chat", - SlashCommand::Archive => "archive this session and exit", - SlashCommand::Delete => "permanently delete this session and exit", - SlashCommand::Clear => "clear the terminal and start a new chat", - SlashCommand::Fork => "fork the current chat", - SlashCommand::App => "continue this session in the Desktop app", -- SlashCommand::Quit | SlashCommand::Exit => "exit Codex", -+ SlashCommand::Quit | SlashCommand::Exit => "exit DSHX", - SlashCommand::Copy => "copy last response as markdown", - SlashCommand::Export => "export the conversation as markdown", - SlashCommand::Raw => "toggle raw scrollback mode for copy-friendly terminal selection", - SlashCommand::Diff => "show git diff (including untracked files)", - SlashCommand::Mention => "mention a file", -- SlashCommand::Skills => "use skills to improve how Codex performs specific tasks", -+ SlashCommand::Skills => "use skills to improve how DeepSeek Harness performs specific tasks", - SlashCommand::Import => "import setup, this project, and recent chats from Claude Code", - SlashCommand::Hooks => "view and manage lifecycle hooks", - SlashCommand::Status => "show current session configuration and token usage", - SlashCommand::Cd => "change the current working directory", - SlashCommand::Pwd => "show the current working directory", - SlashCommand::Usage => "view account usage or use a usage limit reset", - SlashCommand::DebugConfig => "show config layers and requirement sources for debugging", - SlashCommand::Title => "configure which items appear in the terminal title", - SlashCommand::Statusline => "configure which items appear in the status line", - SlashCommand::Theme => "choose a syntax highlighting theme", - SlashCommand::Pets => "choose or hide the terminal pet", - SlashCommand::Ps => "list background terminals", - SlashCommand::Stop => "stop all background terminals", - SlashCommand::MemoryDrop => "DO NOT USE", - SlashCommand::MemoryUpdate => "DO NOT USE", - SlashCommand::Model => "choose what model and reasoning effort to use", - SlashCommand::Ide => { - "include current selection, open files, and other context from your IDE" - } - SlashCommand::Personality => "choose a communication style for Codex", - SlashCommand::Plan => "switch to Plan mode", - SlashCommand::Goal => "set or view the goal for a long-running task", - SlashCommand::Agents => "view and switch between all active agent sessions", - SlashCommand::MultiAgents => "switch between this session's subagents", - SlashCommand::Side | SlashCommand::Btw => { - "start a side conversation in an ephemeral fork" - } -- SlashCommand::Permissions => "choose what Codex is allowed to do", -+ SlashCommand::Permissions => "choose what DeepSeek Harness is allowed to do", - SlashCommand::Keymap => "remap TUI shortcuts", - SlashCommand::Vim => "toggle Vim mode for the composer", - SlashCommand::ElevateSandbox => "set up elevated agent sandbox", - SlashCommand::SandboxReadRoot => { -@@ -260,7 +260,40 @@ impl SlashCommand { - } - - fn is_visible(self) -> bool { -+ if crate::dshx_backend() -+ && matches!( -+ self, -+ SlashCommand::Ide -+ | SlashCommand::ElevateSandbox -+ | SlashCommand::SandboxReadRoot -+ | SlashCommand::Experimental -+ | SlashCommand::AutoReview -+ | SlashCommand::Memories -+ | SlashCommand::Import -+ | SlashCommand::Hooks -+ | SlashCommand::Review -+ | SlashCommand::Archive -+ | SlashCommand::Delete -+ | SlashCommand::App -+ | SlashCommand::Goal -+ | SlashCommand::MultiAgents -+ | SlashCommand::Side -+ | SlashCommand::Btw -+ | SlashCommand::Cd -+ | SlashCommand::Usage -+ | SlashCommand::DebugConfig -+ | SlashCommand::Ps -+ | SlashCommand::Stop -+ | SlashCommand::Mcp -+ | SlashCommand::Apps -+ | SlashCommand::Plugins -+ | SlashCommand::Logout -+ | SlashCommand::Feedback -+ | SlashCommand::Personality -+ | SlashCommand::MemoryDrop -+ | SlashCommand::MemoryUpdate -+ ) -+ { -+ return false; -+ } - match self { - SlashCommand::SandboxReadRoot => cfg!(target_os = "windows"), - SlashCommand::Copy => !cfg!(target_os = "android"), - SlashCommand::App => cfg!(any(target_os = "macos", target_os = "windows")), - SlashCommand::Rollout | SlashCommand::TestApproval => cfg!(debug_assertions), diff --git a/.release/dshx-linux-x64/upstream/patches/codex/0010-dshx-local-ipc-bridge.patch b/.release/dshx-linux-x64/upstream/patches/codex/0010-dshx-local-ipc-bridge.patch deleted file mode 100644 index 153d959a..00000000 --- a/.release/dshx-linux-x64/upstream/patches/codex/0010-dshx-local-ipc-bridge.patch +++ /dev/null @@ -1,187 +0,0 @@ -diff --git a/codex-rs/Cargo.lock b/codex-rs/Cargo.lock ---- a/codex-rs/Cargo.lock -+++ b/codex-rs/Cargo.lock -@@ -4250,16 +4250,18 @@ - [[package]] - name = "codex-stdio-to-uds" - version = "0.0.0" - dependencies = [ - "anyhow", - "codex-uds", - "codex-utils-cargo-bin", -+ "futures", - "pretty_assertions", - "tempfile", - "tokio", -+ "tokio-tungstenite", - ] - - [[package]] - name = "codex-terminal-detection" - version = "0.0.0" - dependencies = [ -diff --git a/codex-rs/stdio-to-uds/Cargo.toml b/codex-rs/stdio-to-uds/Cargo.toml ---- a/codex-rs/stdio-to-uds/Cargo.toml -+++ b/codex-rs/stdio-to-uds/Cargo.toml -@@ -7,6 +7,10 @@ - [[bin]] - name = "codex-stdio-to-uds" - path = "src/main.rs" -+ -+[[bin]] -+name = "dshx-ipc-bridge" -+path = "src/dshx_ipc_bridge.rs" - - [lib] - name = "codex_stdio_to_uds" -@@ -20,12 +24,14 @@ - [dependencies] - anyhow = { workspace = true } - codex-uds = { workspace = true } -+futures = { workspace = true } - tokio = { workspace = true, features = [ - "io-std", - "io-util", - "macros", - "rt-multi-thread", - ] } -+tokio-tungstenite = { workspace = true } - - [dev-dependencies] - codex-utils-cargo-bin = { workspace = true } -diff --git a/codex-rs/stdio-to-uds/src/dshx_ipc_bridge.rs b/codex-rs/stdio-to-uds/src/dshx_ipc_bridge.rs -new file mode 100644 ---- /dev/null -+++ b/codex-rs/stdio-to-uds/src/dshx_ipc_bridge.rs -@@ -0,0 +1,101 @@ -+#![deny(clippy::print_stdout)] -+ -+use std::io::ErrorKind; -+use std::path::PathBuf; -+ -+use anyhow::Context; -+use codex_uds::UnixListener; -+use futures::SinkExt; -+use futures::StreamExt; -+use tokio::io::AsyncBufReadExt; -+use tokio::io::AsyncWriteExt; -+use tokio::io::BufReader; -+use tokio_tungstenite::accept_async; -+use tokio_tungstenite::tungstenite::Message; -+ -+struct SocketGuard(PathBuf); -+ -+impl Drop for SocketGuard { -+ fn drop(&mut self) { -+ if let Err(err) = std::fs::remove_file(&self.0) -+ && err.kind() != ErrorKind::NotFound -+ { -+ // Best effort only. The launcher removes the unique parent directory. -+ } -+ } -+} -+ -+async fn write_line(stdout: &mut tokio::io::Stdout, line: &str) -> anyhow::Result<()> { -+ stdout.write_all(line.as_bytes()).await?; -+ stdout.write_all(b"\n").await?; -+ stdout.flush().await?; -+ Ok(()) -+} -+ -+#[tokio::main] -+async fn main() -> anyhow::Result<()> { -+ let mut args = std::env::args_os().skip(1); -+ let Some(first) = args.next() else { -+ anyhow::bail!("usage: dshx-ipc-bridge "); -+ }; -+ if first == std::ffi::OsStr::new("--check") { -+ return Ok(()); -+ } -+ if args.next().is_some() { -+ anyhow::bail!("usage: dshx-ipc-bridge "); -+ } -+ -+ let socket_path = PathBuf::from(first); -+ if let Some(parent) = socket_path.parent() { -+ codex_uds::prepare_private_socket_directory(parent) -+ .await -+ .with_context(|| format!("failed to prepare {}", parent.display()))?; -+ } -+ let mut listener = UnixListener::bind(&socket_path) -+ .await -+ .with_context(|| format!("failed to bind {}", socket_path.display()))?; -+ let _guard = SocketGuard(socket_path.clone()); -+ -+ // Stdout is a private JSONL control channel to the Node presentation adapter. -+ // Never log to stdout from this process. -+ let mut stdout = tokio::io::stdout(); -+ write_line(&mut stdout, r#"{"dshxBridge":"ready"}"#).await?; -+ -+ let stream = listener -+ .accept() -+ .await -+ .with_context(|| format!("failed to accept {}", socket_path.display()))?; -+ let mut websocket = accept_async(stream) -+ .await -+ .context("failed to upgrade local DSHX IPC connection")?; -+ let mut stdin_lines = BufReader::new(tokio::io::stdin()).lines(); -+ -+ loop { -+ tokio::select! { -+ incoming = websocket.next() => { -+ match incoming { -+ Some(Ok(Message::Text(text))) => write_line(&mut stdout, &text.to_string()).await?, -+ Some(Ok(Message::Binary(bytes))) => { -+ let text = String::from_utf8(bytes.to_vec()).context("binary IPC frame was not UTF-8")?; -+ write_line(&mut stdout, &text).await?; -+ } -+ Some(Ok(Message::Ping(payload))) => websocket.send(Message::Pong(payload)).await?, -+ Some(Ok(Message::Close(_))) | None => break, -+ Some(Ok(_)) => {} -+ Some(Err(err)) => return Err(err).context("local DSHX IPC websocket failed"), -+ } -+ } -+ outbound = stdin_lines.next_line() => { -+ match outbound? { -+ Some(line) => websocket.send(Message::Text(line.into())).await?, -+ None => { -+ websocket.close(None).await?; -+ break; -+ } -+ } -+ } -+ } -+ } -+ -+ Ok(()) -+} -diff --git a/codex-rs/tui/src/main.rs b/codex-rs/tui/src/main.rs ---- a/codex-rs/tui/src/main.rs -+++ b/codex-rs/tui/src/main.rs -@@ -72,19 +72,13 @@ - "DSHX_APP_SERVER_ENDPOINT is required; DSHX never falls back to the Codex agent runtime" - ) - })?; -- let dshx_token = std::env::var("DSHX_APP_SERVER_TOKEN").map_err(|_| { -- anyhow::anyhow!( -- "DSHX_APP_SERVER_TOKEN is required; DSHX local transport is always authenticated" -- ) -- })?; -- let mut dshx_endpoint = resolve_remote_addr(&dshx_endpoint)?; -- match &mut dshx_endpoint { -- RemoteAppServerEndpoint::WebSocket { auth_token, .. } => { -- *auth_token = Some(dshx_token); -- } -- RemoteAppServerEndpoint::UnixSocket { .. } => { -- anyhow::bail!("DSHX production launcher requires authenticated loopback WebSocket transport") -- } -+ let dshx_endpoint = resolve_remote_addr(&dshx_endpoint) -+ .map_err(|err| anyhow::anyhow!("{err:#}"))?; -+ match &dshx_endpoint { -+ RemoteAppServerEndpoint::WebSocket { .. } => anyhow::bail!( -+ "DSHX production launcher forbids TCP WebSocket transport; use the packaged local IPC bridge" -+ ), -+ RemoteAppServerEndpoint::UnixSocket { .. } => {} - } - let exit_info = run_main( - inner, diff --git a/.release/dshx-linux-x64/upstream/patches/codex/0011-dshx-ipc-self-check.patch b/.release/dshx-linux-x64/upstream/patches/codex/0011-dshx-ipc-self-check.patch deleted file mode 100644 index 8fb1079f..00000000 --- a/.release/dshx-linux-x64/upstream/patches/codex/0011-dshx-ipc-self-check.patch +++ /dev/null @@ -1,100 +0,0 @@ -diff --git a/codex-rs/stdio-to-uds/src/dshx_ipc_bridge.rs b/codex-rs/stdio-to-uds/src/dshx_ipc_bridge.rs ---- a/codex-rs/stdio-to-uds/src/dshx_ipc_bridge.rs -+++ b/codex-rs/stdio-to-uds/src/dshx_ipc_bridge.rs -@@ -2,16 +2,21 @@ - - use std::io::ErrorKind; - use std::path::PathBuf; -+use std::time::SystemTime; -+use std::time::UNIX_EPOCH; - - use anyhow::Context; - use codex_uds::UnixListener; -+use codex_uds::UnixStream; - use futures::SinkExt; - use futures::StreamExt; - use tokio::io::AsyncBufReadExt; - use tokio::io::AsyncWriteExt; - use tokio::io::BufReader; - use tokio_tungstenite::accept_async; -+use tokio_tungstenite::client_async; - use tokio_tungstenite::tungstenite::Message; -+use tokio_tungstenite::tungstenite::client::IntoClientRequest; - - struct SocketGuard(PathBuf); - -@@ -32,6 +37,65 @@ - Ok(()) - } - -+struct DirectoryGuard(PathBuf); -+ -+impl Drop for DirectoryGuard { -+ fn drop(&mut self) { -+ let _ = std::fs::remove_dir_all(&self.0); -+ } -+} -+ -+async fn self_check() -> anyhow::Result<()> { -+ let nonce = SystemTime::now() -+ .duration_since(UNIX_EPOCH) -+ .context("system clock is before Unix epoch")? -+ .as_nanos(); -+ let directory = std::env::temp_dir().join(format!( -+ "dshx-ipc-check-{}-{nonce}", -+ std::process::id() -+ )); -+ codex_uds::prepare_private_socket_directory(&directory) -+ .await -+ .with_context(|| format!("failed to prepare {}", directory.display()))?; -+ let _directory_guard = DirectoryGuard(directory.clone()); -+ let socket_path = directory.join("app.sock"); -+ let mut listener = UnixListener::bind(&socket_path) -+ .await -+ .with_context(|| format!("failed to bind {}", socket_path.display()))?; -+ -+ let server = tokio::spawn(async move { -+ let stream = listener.accept().await.context("self-check accept failed")?; -+ let mut websocket = accept_async(stream) -+ .await -+ .context("self-check server websocket handshake failed")?; -+ match websocket.next().await { -+ Some(Ok(Message::Text(text))) if text.as_str() == "ping" => { -+ websocket.send(Message::Text("pong".into())).await?; -+ } -+ other => anyhow::bail!("self-check server received unexpected frame: {other:?}"), -+ } -+ websocket.close(None).await?; -+ anyhow::Ok(()) -+ }); -+ -+ let stream = UnixStream::connect(&socket_path) -+ .await -+ .with_context(|| format!("failed to connect {}", socket_path.display()))?; -+ let request = "ws://localhost/rpc" -+ .into_client_request() -+ .context("failed to create self-check websocket request")?; -+ let (mut websocket, _) = client_async(request, stream) -+ .await -+ .context("self-check client websocket handshake failed")?; -+ websocket.send(Message::Text("ping".into())).await?; -+ match websocket.next().await { -+ Some(Ok(Message::Text(text))) if text.as_str() == "pong" => {} -+ other => anyhow::bail!("self-check client received unexpected frame: {other:?}"), -+ } -+ server.await.context("self-check server task failed")??; -+ Ok(()) -+} -+ - #[tokio::main] - async fn main() -> anyhow::Result<()> { - let mut args = std::env::args_os().skip(1); -@@ -39,7 +103,7 @@ - anyhow::bail!("usage: dshx-ipc-bridge "); - }; - if first == std::ffi::OsStr::new("--check") { -- return Ok(()); -+ return self_check().await; - } - if args.next().is_some() { - anyhow::bail!("usage: dshx-ipc-bridge "); diff --git a/.release/dshx-linux-x64/upstream/patches/codex/0012-dshx-rc5-presentation-fixes.patch b/.release/dshx-linux-x64/upstream/patches/codex/0012-dshx-rc5-presentation-fixes.patch deleted file mode 100644 index e03017f7..00000000 --- a/.release/dshx-linux-x64/upstream/patches/codex/0012-dshx-rc5-presentation-fixes.patch +++ /dev/null @@ -1,144 +0,0 @@ -diff --git a/codex-rs/tui/src/model_catalog.rs b/codex-rs/tui/src/model_catalog.rs ---- a/codex-rs/tui/src/model_catalog.rs -+++ b/codex-rs/tui/src/model_catalog.rs -@@ -12,4 +12,10 @@ impl ModelCatalog { - pub(crate) fn try_list_models(&self) -> Result, Infallible> { - Ok(self.models.clone()) - } -+ -+ pub(crate) fn display_name_for(&self, model: &str) -> Option<&str> { -+ self.models -+ .iter() -+ .find(|preset| preset.model == model) -+ .map(|preset| preset.display_name.as_str()) -+ } - } -diff --git a/codex-rs/tui/src/chatwidget/settings.rs b/codex-rs/tui/src/chatwidget/settings.rs ---- a/codex-rs/tui/src/chatwidget/settings.rs -+++ b/codex-rs/tui/src/chatwidget/settings.rs -@@ -456,6 +456,10 @@ impl ChatWidget { - pub(super) fn refresh_model_display(&mut self) { - let effective = self.effective_collaboration_mode(); -- self.session_header.set_model(effective.model()); -+ let model_display_name = self -+ .model_catalog -+ .display_name_for(effective.model()) -+ .unwrap_or(effective.model()).to_string(); -+ self.session_header.set_model(&model_display_name); - // Keep composer paste affordances aligned with the currently effective model. - self.sync_image_paste_enabled(); - self.sync_service_tier_commands(); -@@ -569,6 +573,8 @@ impl ChatWidget { - if model.is_empty() { - DEFAULT_MODEL_DISPLAY_NAME - } else { -- model -+ self.model_catalog -+ .display_name_for(model) -+ .unwrap_or(model) - } - } -diff --git a/codex-rs/tui/src/chatwidget/session_flow.rs b/codex-rs/tui/src/chatwidget/session_flow.rs ---- a/codex-rs/tui/src/chatwidget/session_flow.rs -+++ b/codex-rs/tui/src/chatwidget/session_flow.rs -@@ -119,8 +119,12 @@ impl ChatWidget { - self.sync_personality_command_enabled(); - self.sync_plugins_command_enabled(); - self.sync_goal_command_enabled(); - self.refresh_plugin_mentions(); -- let model_for_header = self.current_model().to_string(); -+ let model_for_header = if crate::dshx_backend() { -+ self.model_display_name().to_string() -+ } else { -+ self.current_model().to_string() -+ }; - if matches!( - display, - SessionConfiguredDisplay::Normal | SessionConfiguredDisplay::PromptEdit -diff --git a/codex-rs/tui/src/history_cell/session.rs b/codex-rs/tui/src/history_cell/session.rs ---- a/codex-rs/tui/src/history_cell/session.rs -+++ b/codex-rs/tui/src/history_cell/session.rs -@@ -126,13 +126,23 @@ pub(crate) fn new_session_info( - auth_plan: Option, - show_fast_status: bool, - ) -> SessionInfoCell { -+ let header_model = if crate::dshx_backend() { -+ requested_model.to_string() -+ } else { -+ session.model.clone() -+ }; -+ let header_version = if crate::dshx_backend() { -+ option_env!("DSHX_VERSION").unwrap_or(CODEX_CLI_VERSION) -+ } else { -+ CODEX_CLI_VERSION -+ }; - // Header box rendered as history (so it appears at the very top) - let header = SessionHeaderHistoryCell::new( -- session.model.clone(), -+ header_model, - session.reasoning_effort.clone(), - show_fast_status, - config.cwd.to_path_buf(), -- CODEX_CLI_VERSION, -+ header_version, - ) - .with_yolo_mode(has_yolo_permissions( - session.approval_policy, -@@ -175,8 +185,8 @@ pub(crate) fn new_session_info( - .map(|tip| TooltipHistoryCell::new(tip, &config.cwd)) - { - parts.push(Box::new(tooltips)); - } -- if requested_model != session.model.as_str() { -+ if !crate::dshx_backend() && requested_model != session.model.as_str() { - let lines = vec![ - "model changed:".magenta().bold().into(), - format!("requested: {requested_model}").into(), -diff --git a/codex-rs/tui/src/chatwidget/status_surfaces.rs b/codex-rs/tui/src/chatwidget/status_surfaces.rs ---- a/codex-rs/tui/src/chatwidget/status_surfaces.rs -+++ b/codex-rs/tui/src/chatwidget/status_surfaces.rs -@@ -681,11 +681,18 @@ impl ChatWidget { - StatusLineItem::WeeklyLimit => { - let (window, is_secondary) = self - .rate_limit_snapshots_by_limit_id - .get("codex") - .and_then(weekly_status_window)?; - let label = limit_label_for_window(window.window_minutes, is_secondary); - self.status_line_limit_display(Some(window), &label) - } -- StatusLineItem::CodexVersion => Some(CODEX_CLI_VERSION.to_string()), -+ StatusLineItem::CodexVersion => Some( -+ if crate::dshx_backend() { -+ option_env!("DSHX_VERSION").unwrap_or(CODEX_CLI_VERSION) -+ } else { -+ CODEX_CLI_VERSION -+ } -+ .to_string(), -+ ), - StatusLineItem::ContextWindowSize => self - .status_line_context_window_size() - .map(|cws| format!("{} window", format_tokens_compact(cws))), -diff --git a/codex-rs/tui/src/startup_draft.rs b/codex-rs/tui/src/startup_draft.rs ---- a/codex-rs/tui/src/startup_draft.rs -+++ b/codex-rs/tui/src/startup_draft.rs -@@ -447,6 +447,12 @@ fn startup_session_header(config: Option<&Config>) -> Box { - || PathBuf::from("loading"), - |config| config.cwd.to_path_buf(), - ); -+ let header_version = if crate::dshx_backend() { -+ option_env!("DSHX_VERSION").unwrap_or(CODEX_CLI_VERSION) -+ } else { -+ CODEX_CLI_VERSION -+ }; - Box::new( - history_cell::SessionHeaderHistoryCell::new_with_style( - "loading".to_string(), -@@ -456,7 +462,7 @@ fn startup_session_header(config: Option<&Config>) -> Box { - /*reasoning_effort*/ None, - /*show_fast_status*/ false, - directory, -- CODEX_CLI_VERSION, -+ header_version, - ) - .with_yolo_mode(config.is_some_and(history_cell::is_yolo_mode)), - ) diff --git a/scripts/build-codex-tui.ps1 b/scripts/build-codex-tui.ps1 index 2ea797e0..68fe6f8a 100644 --- a/scripts/build-codex-tui.ps1 +++ b/scripts/build-codex-tui.ps1 @@ -10,6 +10,8 @@ $OutDir = if ($env:DSHX_TUI_OUT_DIR) { $env:DSHX_TUI_OUT_DIR } else { Join-Path New-Item -ItemType Directory -Force $OutDir | Out-Null $env:CARGO_TARGET_DIR = $TargetDir +# Ship without debug info: smaller artifacts, identical behavior. +if (-not $env:CARGO_PROFILE_RELEASE_DEBUG) { $env:CARGO_PROFILE_RELEASE_DEBUG = '0' } cargo build --manifest-path (Join-Path $CodeXDir 'codex-rs\Cargo.toml') --locked --release -p codex-tui --bin codex-tui cargo build --manifest-path (Join-Path $CodeXDir 'codex-rs\Cargo.toml') --locked --release -p codex-stdio-to-uds --bin dshx-ipc-bridge $TuiSource = Join-Path $TargetDir 'release\codex-tui.exe' diff --git a/scripts/build-codex-tui.sh b/scripts/build-codex-tui.sh index c391076e..d9857cb1 100755 --- a/scripts/build-codex-tui.sh +++ b/scripts/build-codex-tui.sh @@ -9,6 +9,9 @@ TARGET_DIR="${CARGO_TARGET_DIR:-$ROOT/.build/codex}" OUT_DIR="${DSHX_TUI_OUT_DIR:-$ROOT/dist/bin}" mkdir -p "$OUT_DIR" +# Ship without debug info: ~4x smaller artifacts, identical behavior. The +# override stays user-controlled for anyone who needs a debuggable build. +export CARGO_PROFILE_RELEASE_DEBUG="${CARGO_PROFILE_RELEASE_DEBUG:-0}" CARGO_TARGET_DIR="$TARGET_DIR" cargo build \ --manifest-path "$CODEX_DIR/codex-rs/Cargo.toml" \ --locked --release -p codex-tui --bin codex-tui @@ -18,5 +21,8 @@ CARGO_TARGET_DIR="$TARGET_DIR" cargo build \ cp "$TARGET_DIR/release/codex-tui" "$OUT_DIR/dshx-tui" cp "$TARGET_DIR/release/dshx-ipc-bridge" "$OUT_DIR/dshx-ipc-bridge" +if command -v strip >/dev/null 2>&1; then + strip "$OUT_DIR/dshx-tui" "$OUT_DIR/dshx-ipc-bridge" +fi chmod +x "$OUT_DIR/dshx-tui" "$OUT_DIR/dshx-ipc-bridge" printf '%s\n' "$OUT_DIR/dshx-tui" "$OUT_DIR/dshx-ipc-bridge" From fff7000044192fbb9e481bd37ad712dc455d9177 Mon Sep 17 00:00:00 2001 From: code-new-bie <245316967+code-new-bie@users.noreply.github.com> Date: Wed, 26 Aug 2026 17:01:45 +0800 Subject: [PATCH 19/60] chore: ignore regenerable release staging directory --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 86fca400..02ad6351 100644 --- a/.gitignore +++ b/.gitignore @@ -11,3 +11,4 @@ coverage/ .idea/ .build/ .upstream/ +.release/ From b8d40efd60ba80087b399069dc4b71db010ae96a Mon Sep 17 00:00:00 2001 From: code-new-bie <245316967+code-new-bie@users.noreply.github.com> Date: Wed, 26 Aug 2026 19:42:33 +0800 Subject: [PATCH 20/60] =?UTF-8?q?feat!:=20host-version=20agnostic=20delive?= =?UTF-8?q?ry=20=E2=80=94=20ride=20the=20user's=20DSH=20installation?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The production launcher no longer imports or boots any harness build from our package: bin/dshx bootstraps the surface profile via the official plugin command, then spawns the user's own 'dsh --profile tui'. The loader mounts our rows inside THAT installation, so credentials parsing, service registries and every other harness behavior come from a single build — the user's — eliminating the dual-build divergence this machine demonstrated (system vs registry copies of the same version string). Interactive attachment moved into the presentation row (opt-in via DSHX_ATTACH set only by our launcher): raw-mode TUI turns Ctrl+C into a key event, so the host's SIGINT handler never fires during interaction; non-TTY contexts degrade gracefully to a passive endpoint with a visible listening hint. local-server drops its runtime-boot import edge, keeping row-module graphs free of package-side harness builds. Adoptive compatibility stance: peerDependencies become an advisory floor ('>=0.1.0-rc.8', no upper bound); the exact tested line stays as an explicit constant surfaced through a one-shot startup warning on any other installed release. --- bin/dshx.mjs | 355 +++++++++++--------------- docs/RUNTIME-INTEGRATION.md | 5 +- package.json | 2 +- scripts/verify-ownership-boundary.mjs | 9 +- src/dsh/local-server.mjs | 12 +- src/dsh/presentation-plugin.mjs | 98 ++++++- src/dsh/runtime-boot.mjs | 20 +- src/dsh/startup-plugin.mjs | 8 +- test/dsh-runtime-boot.test.mjs | 2 +- 9 files changed, 270 insertions(+), 241 deletions(-) diff --git a/bin/dshx.mjs b/bin/dshx.mjs index f77847ed..12f5a642 100755 --- a/bin/dshx.mjs +++ b/bin/dshx.mjs @@ -1,4 +1,10 @@ #!/usr/bin/env node +// DSHX launcher — a thin, version-agnostic bootstrap over the official DSH +// machinery. This file deliberately imports NO DeepSeek Harness code: the +// composition is booted by the user's own `dsh` installation, our bundle rows +// are loaded by that installation's loader, and the pinned Codex TUI is +// attached from inside the surface row. Zero harness builds ship or load from +// this launcher, which is what keeps the plugin host-version agnostic. import fs from 'node:fs'; import os from 'node:os'; import path from 'node:path'; @@ -6,43 +12,20 @@ import process from 'node:process'; import { spawn, spawnSync } from 'node:child_process'; import { fileURLToPath } from 'node:url'; import { parseCliInvocation } from '../src/cli/arguments.mjs'; +import { isSupportedNodeVersion } from '../src/cli/runtime.mjs'; import { - DSHX_DOCTOR_BOOT_TIMEOUT_MS, - DSHX_DOCTOR_DISPOSE_TIMEOUT_MS, - isSupportedNodeVersion -} from '../src/cli/runtime.mjs'; -import { ensureProfileInstalled } from '../src/dsh/profile-bootstrap.mjs'; + ensureProfileInstalled, + profileManifestPath, + resolveDshInvocation +} from '../src/dsh/profile-bootstrap.mjs'; const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..'); const PACKAGE = JSON.parse(fs.readFileSync(path.join(ROOT, 'package.json'), 'utf8')); const VERSION = PACKAGE.version; -const REQUIRED_RUNTIME_SERVICES = [ - 'agents', - 'agentDefaultModel', - 'llm', - 'sessions', - 'sessionPersistence', - 'sessionQuery', - 'sessionProjections', - 'sessionTitle', - 'attachments', - 'tools', - 'commands', - 'compaction', - 'subagents', - 'permissionPresets', - 'approval', - 'userQuestions', - 'skills', - 'planMode', - // The surface rows themselves: their services exist only when the loader - // activated the bundle patch (dshx-startup / dshx-presentation). - 'dshxStartup', - 'dshxPresentation' -]; +const DEFAULT_PROFILE = 'tui'; function usage() { - return `DSHX ${VERSION}\n\nUsage:\n dshx Start DSHX in the current project\n dshx Start with an initial prompt\n dshx resume Open the Codex-style DSH session picker\n dshx resume --last Resume the most recent DSH session\n dshx resume Resume a specific DSH session\n dshx doctor Check packaged TUI, local IPC and official DSH composition\n dshx --version Print version\n dshx --help Show this help\n\nEnvironment:\n DSHX_TUI_BIN Override the packaged DSHX TUI binary (development only)\n DSHX_IPC_BRIDGE_BIN Override the packaged local IPC bridge (development only)\n DSHX_TUI_HOME Override DSHX presentation-only Codex home (development only)\n DSHX_PROFILE Override the DSH profile surface (default: tui)\n DSHX_DEBUG=1 Print DSHX adapter diagnostics\n\nPlugin usage:\n The DSHX surface ships as a standard DSH profile bundle. Manage it through\n the official machinery, e.g.:\n dsh plugin --profile tui add ${PACKAGE.name}\n The zero-argument launcher only bootstraps the same profile via the same\n command, then hands control to the official DSH composition.\n\nProduct boundary:\n DSHX owns only the launcher, Codex TUI thin fork and presentation adapter.\n DeepSeek Harness remains the authoritative Agent/Session/Tool runtime.\n DSHX never reads or writes the user's ordinary CODEX_HOME.\n`; + return `DSHX ${VERSION}\n\nUsage:\n dshx Start DSHX in the current project\n dshx Start with an initial prompt\n dshx resume Open the Codex-style DSH session picker\n dshx resume --last Resume the most recent DSH session\n dshx resume Resume a specific DSH session\n dshx doctor Check packaged TUI, local IPC and official DSH composition\n dshx --version Print version\n dshx --help Show this help\n\nEnvironment:\n DSHX_TUI_BIN Override the packaged DSHX TUI binary (development only)\n DSHX_IPC_BRIDGE_BIN Override the packaged local IPC bridge (development only)\n DSHX_TUI_HOME Override DSHX presentation-only Codex home (development only)\n DSHX_PROFILE Override the DSH profile surface (default: ${DEFAULT_PROFILE})\n DSHX_DEBUG=1 Print DSHX adapter diagnostics\n\nPlugin usage:\n The DSHX surface ships as a standard DSH profile bundle. Manage it through\n the official machinery, e.g.:\n dsh plugin --profile ${DEFAULT_PROFILE} add ${PACKAGE.name}\n\nCompatibility:\n Runs against whatever DeepSeek Harness installation hosts the profile; the\n tested line is announced at startup when they differ. No harness builds are\n loaded from this launcher.\n\nProduct boundary:\n DSHX owns only the launcher, Codex TUI thin fork and presentation adapter.\n DeepSeek Harness remains the authoritative Agent/Session/Tool runtime.\n DSHX never reads or writes the user's ordinary CODEX_HOME.\n`; } function commandDetail(command, result) { @@ -51,43 +34,59 @@ function commandDetail(command, result) { return `${command} is not runnable${result.stderr ? `: ${result.stderr.trim()}` : ''}`; } -function withTimeout(promise, timeoutMs, label) { - let timer; - return Promise.race([ - promise, - new Promise((_, reject) => { - timer = setTimeout(() => reject(new Error(`${label} exceeded ${timeoutMs}ms`)), timeoutMs); - }) - ]).finally(() => clearTimeout(timer)); -} - function binaryCandidate(baseName) { const fileName = process.platform === 'win32' ? `${baseName}.exe` : baseName; return process.env[baseName === 'dshx-tui' ? 'DSHX_TUI_BIN' : 'DSHX_IPC_BRIDGE_BIN'] || path.join(ROOT, 'dist', 'bin', fileName); } -function bootstrapSurfaceProfile(runtimeBoot) { - return ensureProfileInstalled({ - packageRoot: ROOT, - name: PACKAGE.name, - version: VERSION, - profile: process.env.DSHX_PROFILE || runtimeBoot.runtimeInternals.DEFAULT_PROFILE - }); +function selectedProfile() { + const value = process.env.DSHX_PROFILE || DEFAULT_PROFILE; + if (!value.trim()) throw new Error('DSH profile name must be non-empty'); + return value.trim(); } -async function loadRuntimeModules() { +/** Bootstrap the surface profile through the official plugin machinery. */ +export function bootstrapSurfaceProfile() { + const profile = selectedProfile(); + const manifestPath = profileManifestPath(profile); + let satisfied = false; try { - const runtimeBoot = await import('../src/dsh/runtime-boot.mjs'); - let localServerInternals; - try { - ({ localServerInternals } = await import('../src/dsh/local-server.mjs')); - } catch { - localServerInternals = undefined; - } - return { runtimeBoot, localServerInternals }; - } catch (error) { - return { loadError: error instanceof Error ? error.message : String(error) }; + const manifest = JSON.parse(fs.readFileSync(manifestPath, 'utf8')); + satisfied = + manifest.dependencies?.[PACKAGE.name] === VERSION && + manifest.dsh?.profile?.bundles?.includes(PACKAGE.name); + } catch { + // Missing or unreadable manifest: the official command initializes it. + } + if (satisfied) return { profile, action: 'already-installed' }; + if (process.env.DSHX_SKIP_PROFILE_BOOTSTRAP === '1') { + return { profile, action: 'skipped' }; + } + + const dsh = resolveDshInvocation(ROOT); + const result = spawnSync( + dsh.command, + [...dsh.args, 'plugin', '--profile', profile, 'add', ROOT], + { stdio: 'inherit', shell: process.platform === 'win32' } + ); + if (result.error?.code === 'ENOENT') { + throw new Error( + "official 'dsh' CLI not found (looked up DSHX_DSH_BIN, the @deepseek-ai/dsh dependency and PATH)" + ); + } + if (result.status !== 0) { + throw new Error(`failed to install ${PACKAGE.name} into profile '${profile}' via dsh plugin add (exit ${result.status ?? '?'})`); + } + return { profile, action: 'installed' }; +} + +async function loadLocalServerInternals() { + try { + const { localServerInternals } = await import('../src/dsh/local-server.mjs'); + return localServerInternals; + } catch { + return undefined; } } @@ -104,8 +103,8 @@ function presentationHomeCheck(localServerInternals) { // On Windows this also enforces that a custom DSHX_TUI_HOME stays below // the current user's profile ACL boundary. Probe the fixed suffix used by - // the real random rendezvous directory so an obviously-too-long home fails - // in doctor before a runtime boot is attempted. + // the real random rendezvous directory so an obviously-too-long home + // fails in doctor before a launch is attempted. const socketRoot = localServerInternals.defaultSocketRoot({ home }); const probeSocket = path.join(socketRoot, 'd-XXXXXX', 's'); localServerInternals.assertSocketPathSupported(probeSocket); @@ -115,63 +114,48 @@ function presentationHomeCheck(localServerInternals) { } } -async function officialRuntimeCheck(runtimeBoot) { - let ctx; - let primaryError; - let cleanupError; - try { - // Doctor deliberately exercises the same official composition and profile - // watcher path as production startup, including the loader-mounted surface - // rows (their services double as row-activation evidence). This catches - // missing native optional dependencies (for example sharp/koffi) that a - // static bundle-entry check cannot detect. The bounded timeout is - // intentionally generous enough for first-run Windows module/native - // initialization on supported hardware. - ctx = await withTimeout( - runtimeBoot.bootDshxRuntime({ cwd: process.cwd(), watch: true }), - DSHX_DOCTOR_BOOT_TIMEOUT_MS, - 'official DSH composition boot' +/** + * Probe the user's real installation end to end: launch the official CLI for + * the surface profile in headless-passive mode and wait until the loader has + * activated the surface rows (visible via the listening hint), proving the + * whole plugin chain works against THIS machine's actual DSH build. + */ +function surfaceActivationProbe(dsh, profile, timeoutMs = 90_000) { + return new Promise((resolve) => { + const child = spawn( + dsh.command, + [...dsh.args, '--profile', profile], + { + cwd: process.cwd(), + env: { ...process.env, DSHX_ATTACH: '1', DSHX_HEADLESS: '1' }, + stdio: ['ignore', 'pipe', 'pipe'] + } ); - const missing = REQUIRED_RUNTIME_SERVICES.filter((name) => ctx.get(name) == null); - if (missing.length > 0) { - throw new Error(`official DSH composition is missing required presentation services: ${missing.join(', ')}`); - } - } catch (error) { - primaryError = error; - } finally { - if (ctx) { - try { - await withTimeout( - Promise.resolve(ctx.dispose?.()), - DSHX_DOCTOR_DISPOSE_TIMEOUT_MS, - 'official DSH composition disposal' - ); - } catch (error) { - cleanupError = error; + let collected = ''; + let settled = false; + const finish = (ok, detail) => { + if (settled) return; + settled = true; + clearTimeout(timer); + try { child.kill('SIGTERM'); } catch { /* already exiting */ } + resolve({ ok, detail }); + }; + const timer = setTimeout(() => finish(false, `no activation within ${timeoutMs}ms`), timeoutMs); + const onData = (chunk) => { + collected += chunk.toString('utf8'); + if (collected.includes('surface listening at')) finish(true, 'surface rows active on your installation'); + if (/credentials-local|does not exist|Cannot find package/.test(collected)) { + finish(false, collected.trim().split('\n').slice(-3).join(' | ')); } - } - } - - if (primaryError) { - const detail = primaryError instanceof Error ? primaryError.message : String(primaryError); - const cleanup = cleanupError - ? `; secondary cleanup failure: ${cleanupError instanceof Error ? cleanupError.message : String(cleanupError)}` - : ''; - return { ok: false, detail: `${detail}${cleanup}` }; - } - if (cleanupError) { - return { - ok: false, - detail: `official DSH composition disposal failed: ${cleanupError instanceof Error ? cleanupError.message : String(cleanupError)}` }; - } - return { - ok: true, - detail: `official DSH composition boot/dispose (${REQUIRED_RUNTIME_SERVICES.length} required services, surface rows active)` - }; + child.stdout.on('data', onData); + child.stderr.on('data', onData); + child.on('error', (error) => finish(false, error.message)); + child.on('exit', (code) => finish(false, `official CLI exited early (code ${code ?? '?'})`)); + }); } -async function doctor(runtimeBoot) { +async function doctor() { const executable = binaryCandidate('dshx-tui'); const tuiCheck = fs.existsSync(executable) ? spawnSync(executable, ['--version'], { encoding: 'utf8' }) @@ -181,20 +165,32 @@ async function doctor(runtimeBoot) { ? spawnSync(bridge, ['--check'], { encoding: 'utf8' }) : { status: 127, stdout: '', stderr: '', error: null }; - const { localServerInternals } = await loadRuntimeModules(); + const localServerInternals = await loadLocalServerInternals(); const homeCheck = presentationHomeCheck(localServerInternals); + let profileDetail = ''; let profileOk = true; + let dsh; try { - const ensured = bootstrapSurfaceProfile(runtimeBoot); + const ensured = bootstrapSurfaceProfile(); profileDetail = `profile '${ensured.profile}' (${ensured.action})`; + dsh = resolveDshInvocation(ROOT); } catch (error) { profileOk = false; profileDetail = error instanceof Error ? error.message : String(error); } - const runtimeCheck = profileOk - ? await officialRuntimeCheck(runtimeBoot) - : { ok: false, detail: `skipped: ${profileDetail}` }; + + // The strongest compatibility evidence possible: activate the surface rows + // against the user's ACTUAL installed build (headless-passive probe). + let harnessDetail = ''; + let harnessOk = false; + if (profileOk && bridgeCheck.status === 0) { + const probe = surfaceActivationProbe(dsh, selectedProfile()); + harnessDetail = probe.detail; + harnessOk = probe.ok; + } else { + harnessDetail = 'skipped: packaged IPC bridge missing'; + } const rows = [ ['Node', `${process.version} (required: ${PACKAGE.engines.node})`, isSupportedNodeVersion(process.versions.node)], @@ -209,7 +205,7 @@ async function doctor(runtimeBoot) { bridgeCheck.status === 0 ], ['Surface profile', profileDetail, profileOk], - ['DeepSeek Harness', runtimeCheck.detail, runtimeCheck.ok], + ['DeepSeek Harness (your installation)', harnessDetail, harnessOk], ['Presentation home / IPC path', homeCheck.detail, homeCheck.ok] ]; for (const [name, detail, ok] of rows) { @@ -246,13 +242,7 @@ async function run() { return; } if (invocation.kind === 'doctor') { - const [, runtimeBoot] = await loadRuntimeModules().then((m) => [m.loadError ? undefined : m.runtimeBoot, m.runtimeBoot]); - if (!runtimeBoot) { - process.stderr.write('dshx: failed to load official DeepSeek Harness runtime modules\n'); - process.exitCode = 1; - return; - } - await doctor(runtimeBoot); + await doctor(); return; } @@ -263,114 +253,61 @@ async function run() { return; } - const [, runtimeBoot] = await loadRuntimeModules().then((m) => [m.loadError ? undefined : m.runtimeBoot, m.runtimeBoot]); - if (!runtimeBoot) { - process.stderr.write('dshx: failed to load official DeepSeek Harness runtime modules\n'); - process.exitCode = 1; - return; - } - - const debug = process.env.DSHX_DEBUG === '1'; - let ctx; - try { - // Bootstrap the surface profile through the official plugin machinery, - // then hand control entirely to the official composition: the loader - // mounts the dshx-startup / dshx-presentation rows declared by the bundle - // patch, and the transport endpoint arrives as a provided service. - bootstrapSurfaceProfile(runtimeBoot); - ctx = await runtimeBoot.bootDshxRuntime({ cwd: process.cwd(), watch: true }); - } catch (error) { - process.stderr.write(`dshx: failed to boot DeepSeek Harness surface profile: ${error instanceof Error ? error.message : error}\n`); - process.exitCode = 1; - return; - } - - const startup = ctx.get('dshxStartup'); - const presentation = ctx.get('dshxPresentation'); - if (!startup || !presentation || typeof presentation.close !== 'function') { - process.stderr.write('dshx: surface rows did not publish dshxStartup/dshxPresentation services\n'); - try { await ctx.dispose?.(); } catch { /* primary failure already reported */ } - process.exitCode = 1; + const executable = binaryCandidate('dshx-tui'); + if (!fs.existsSync(executable)) { + process.stderr.write(`dshx: packaged TUI binary not found (${executable})\n`); + process.stderr.write('Run `dshx doctor` for build/install guidance.\n'); + process.exitCode = 127; return; } - - const executable = startup.tuiCommand; - if (!executable || !fs.existsSync(executable)) { - process.stderr.write(`dshx: packaged TUI binary not found (${executable ?? 'unknown path'})\n`); + const bridge = binaryCandidate('dshx-ipc-bridge'); + if (!fs.existsSync(bridge)) { + process.stderr.write(`dshx: packaged local IPC bridge not found (${bridge})\n`); process.stderr.write('Run `dshx doctor` for build/install guidance.\n'); - try { await ctx.dispose?.(); } catch { /* ignore secondary */ } process.exitCode = 127; return; } - const tuiHome = startup.home; + const debug = process.env.DSHX_DEBUG === '1'; + let profile; try { - fs.mkdirSync(tuiHome, { recursive: true, mode: 0o700 }); + profile = bootstrapSurfaceProfile().profile; } catch (error) { - process.stderr.write(`dshx: cannot create presentation home ${tuiHome}: ${error instanceof Error ? error.message : error}\n`); - try { await ctx.dispose?.(); } catch { /* ignore secondary */ } + process.stderr.write(`dshx: ${error instanceof Error ? error.message : error}\n`); process.exitCode = 1; return; } - let child; - try { - child = spawn(executable, invocation.tuiArgs, { + // Hand over to the user's own official DSH installation. The loader mounts + // our surface rows; the presentation row attaches the pinned TUI because + // DSHX_ATTACH marks this launching context as interactive. + const tuiHome = path.resolve(process.env.DSHX_TUI_HOME || path.join(os.homedir(), '.dshx', 'codex-tui')); + const dsh = resolveDshInvocation(ROOT); + const child = spawn( + dsh.command, + [...dsh.args, '--profile', profile], + { cwd: process.cwd(), env: { ...process.env, - // Do not inherit CODEX_HOME: DSHX uses Codex code as a presentation - // component only and must not read/write the user's ordinary Codex state. CODEX_HOME: tuiHome, - ...invocation.resumeEnv, - DSHX_APP_SERVER_ENDPOINT: presentation.url + ...(invocation.resumeEnv ?? {}), + DSHX_ATTACH: '1', + DSHX_TUI_ARGS: JSON.stringify(invocation.tuiArgs ?? []) }, stdio: 'inherit', windowsHide: false - }); - } catch (error) { - process.stderr.write(`dshx: failed to launch pinned Codex TUI: ${error instanceof Error ? error.message : error}\n`); - try { await ctx.dispose?.(); } catch { /* ignore secondary */ } - process.exitCode = 127; - return; - } - - let closing = false; - const close = async (exitCode) => { - if (closing) return; - closing = true; - try { - // Root-fiber disposal unwinds the dshx-presentation plugin, whose - // disposer closes the transport; the Fiber remains the sole teardown - // authority. - await ctx.dispose?.(); - } catch (error) { - process.stderr.write(`dshx: shutdown cleanup failed: ${error instanceof Error ? error.message : error}\n`); - if (exitCode === 0) exitCode = 1; } - process.exitCode = exitCode; - }; + ); - child.on('error', async (error) => { - process.stderr.write(`dshx: failed to launch pinned Codex TUI: ${error.message}\n`); - await close(127); - }); - child.on('exit', async (code, signal) => { - if (signal && debug) process.stderr.write(`[dshx] TUI exited via ${signal}\n`); - await close(code ?? (signal ? 1 : 0)); + child.on('error', (error) => { + process.stderr.write(`dshx: failed to start official DSH CLI: ${error.message}\n`); + process.exitCode = 127; }); - - // Process-lifecycle signals are forwarded to the TUI. Do not intercept - // SIGINT: Ctrl+C is an in-TUI interaction used by Codex to interrupt the - // active DSH turn. - process.once('SIGTERM', () => { - if (!child.killed) child.kill('SIGTERM'); + child.on('exit', (code, signal) => { + if (signal && debug) process.stderr.write(`[dshx] official DSH exited via ${signal}\n`); + process.exitCode = code ?? (signal ? 1 : 0); }); - if (process.platform !== 'win32') { - process.once('SIGHUP', () => { - if (!child.killed) child.kill('SIGHUP'); - }); - } } await run(); diff --git a/docs/RUNTIME-INTEGRATION.md b/docs/RUNTIME-INTEGRATION.md index 972ee915..ab87e8a9 100644 --- a/docs/RUNTIME-INTEGRATION.md +++ b/docs/RUNTIME-INTEGRATION.md @@ -6,7 +6,10 @@ DSHX reuses the same architectural seam that official DeepSeek Harness uses for The TUI remains project-owned. DeepSeek Harness remains upstream-owned. -Supported DSH package line for the current release branch: `0.1.0-rc.8`. +Tested official DSH line for the current release branch: `0.1.0-rc.8`. The +plugin is host-version agnostic at runtime — it composes inside whatever +DeepSeek Harness installation hosts the profile, and an untested line only +produces a one-shot startup warning (never a block). Pinned DSH source reference: `141eb6fef83422698aef7a981029e843e8161534`. The official runtime owns Agent creation/resume, Session persistence, model selection/routing, tools, approvals, permission policy, skills, subagents and every other capability surface. DSHX generalizes only the **presentation lifetime** from a headless/one-shot consumer into an interactive terminal frontend. diff --git a/package.json b/package.json index fc726235..0c11317c 100644 --- a/package.json +++ b/package.json @@ -49,7 +49,7 @@ "@deepseek-ai/schemastery": "3.18.1" }, "peerDependencies": { - "@deepseek-ai/dsh": "0.1.0-rc.8", + "@deepseek-ai/dsh": ">=0.1.0-rc.8", "@deepseek-ai/dsh-agent": "0.1.0-rc.8", "@deepseek-ai/dsh-app-boot": "0.1.0-rc.8", "@deepseek-ai/dsh-host-apiproxy": "0.1.0-rc.8", diff --git a/scripts/verify-ownership-boundary.mjs b/scripts/verify-ownership-boundary.mjs index 57935c29..50b7de2e 100644 --- a/scripts/verify-ownership-boundary.mjs +++ b/scripts/verify-ownership-boundary.mjs @@ -72,10 +72,17 @@ forbidText('src/dsh/runtime-boot.mjs', 'bootDshxPresentationRuntime'); // delegated to Cordis/DSH root-fiber ownership rather than a DSHX runtime. requireText('src/dsh/runtime-boot.mjs', 'ctx.fiber.dispose()'); requireText('src/dsh/runtime-boot.mjs', 'attachPresentationLifetime(ctx)'); -// The declared supported DSH line is ecosystem-honest metadata: warn once at +// The declared tested DSH line is ecosystem-honest metadata: warn once at // boot, never block the host (official bundles carry peer ranges, no gates). requireText('src/dsh/runtime-boot.mjs', 'reportDshLineCompatibility'); requireText('src/dsh/runtime-boot.mjs', 'proceeding'); +// Host-version agnosticism: the production launcher and row modules must not +// import harness builds from our package — at runtime everything rides the +// user's installed DSH via the profile loader and its healed fallback. +forbidText('bin/dshx.mjs', /(?:from\s+|import\s+\(\s*|require\()\s*["']@deepseek-ai\//, 'importing harness builds'); +forbidText('src/dsh/presentation-plugin.mjs', 'runtime-boot'); +forbidText('src/dsh/local-server.mjs', "from './runtime-boot.mjs'"); +requireText('src/dsh/startup-plugin.mjs', 'DSHX_ATTACH'); for (const path of ['src/dsh/user-shell.mjs', 'src/dsh/workspace-command.mjs']) { forbidText(path, /execFile|execSync|spawn\(/, 'local process execution'); diff --git a/src/dsh/local-server.mjs b/src/dsh/local-server.mjs index c96fca06..2db6cb44 100644 --- a/src/dsh/local-server.mjs +++ b/src/dsh/local-server.mjs @@ -5,7 +5,10 @@ import { spawn } from 'node:child_process'; import { createInterface } from 'node:readline'; import { fileURLToPath } from 'node:url'; import { DshxPresentationAdapter } from '../tui-protocol/adapter.mjs'; -import { bootDshxRuntime } from './runtime-boot.mjs'; +// Intentionally NO import of runtime-boot here: this module is loaded inside +// the user's DSH installation via the profile loader, so pulling any harness +// build from our own package would fork the runtime into two builds. Hosts +// that need self-booting inject `bootRuntime` explicitly (tests, dev tooling). const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../..'); const READY = 'ready'; @@ -185,14 +188,14 @@ export async function startDshxLocalServer({ home, version = '0.1.0-dev', runtime, - bootRuntime = bootDshxRuntime, Adapter = DshxPresentationAdapter, log = () => {}, bridgeCommand = packagedBridgeBinary(), bridgeArgs, spawnBridge = spawn, socketRoot, - disposeRuntimeOnClose = true + disposeRuntimeOnClose = true, + bootRuntime } = {}) { const rendezvousRoot = path.resolve(socketRoot ?? defaultSocketRoot({ home })); let socketDirectory; @@ -223,6 +226,9 @@ export async function startDshxLocalServer({ socketDirectory = createSocketDirectory(rendezvousRoot); socketPath = path.join(socketDirectory, 's'); assertSocketPathSupported(socketPath); + if (!ctx && typeof bootRuntime !== 'function') { + throw new Error('startDshxLocalServer requires either a runtime Context or an injected bootRuntime'); + } ctx ??= await bootRuntime({ cwd }); const args = bridgeArgs ?? [socketPath]; bridge = spawnBridge(bridgeCommand, args, { diff --git a/src/dsh/presentation-plugin.mjs b/src/dsh/presentation-plugin.mjs index 3d428d28..432e595c 100644 --- a/src/dsh/presentation-plugin.mjs +++ b/src/dsh/presentation-plugin.mjs @@ -1,3 +1,6 @@ +import fs from 'node:fs'; +import { spawn } from 'node:child_process'; +import process from 'node:process'; import z from '@deepseek-ai/schemastery'; import { startDshxLocalServer } from './local-server.mjs'; @@ -5,14 +8,15 @@ import { startDshxLocalServer } from './local-server.mjs'; * dshx-presentation — the surface's transport host row. * * Loaded by the Cordis loader through the bundle patch (no dynamic mounting): - * it starts the packaged bridge + adapter transport against the already-booted - * official composition Context, publishes the endpoint as the - * `dshxPresentation` service, and returns the transport closer as its - * disposer. Teardown authority remains the Cordis root Fiber. + * it starts the packaged bridge + adapter transport against the ALREADY-BOOTED + * composition of whatever DSH installation hosts this profile — zero harness + * builds are imported from our own package, so the surface is version-agnostic + * and rides the user's installation like any official row. * - * Launch inputs arrive exclusively from the injected `dshxStartup` service - * (see startup-plugin.mjs) — the official three-stage pattern — so this module - * carries no environment or path policy of its own. + * Interactive attachment (spawning the pinned Codex TUI on this terminal) is + * opt-in per launching context via `launch.attach`: entries with TUI-correct + * signal semantics set it; bare passive launches serve the endpoint with a + * visible listening hint instead. */ /** Stable Cordis plugin name. */ @@ -29,8 +33,56 @@ export const Config = z.object({ /** Service key published on the Context after the endpoint is ready. */ export const SERVICE_KEY = 'dshxPresentation'; -/** Test seam mirroring the official packages' `internals` convention. */ -export const internals = { start: startDshxLocalServer }; +/** Test seams mirroring the official packages' `internals` convention. */ +export const internals = { + start: startDshxLocalServer, + spawn, + isInteractive: () => process.stdout.isTTY === true && process.stdin.isTTY === true +}; + +function parseTuiArgs(environment) { + if (!environment.DSHX_TUI_ARGS) return []; + try { + const parsed = JSON.parse(environment.DSHX_TUI_ARGS); + return Array.isArray(parsed) ? parsed.map(String) : []; + } catch { + return []; + } +} + +function attachTui(launch, server, log) { + if (!launch.tuiCommand || !fs.existsSync(launch.tuiCommand)) { + throw new Error(`dshx: packaged TUI binary not found (${launch.tuiCommand ?? 'unknown path'}); run \`dshx doctor\``); + } + const child = internals.spawn(launch.tuiCommand, parseTuiArgs(process.env), { + cwd: launch.cwd, + env: { + ...process.env, + // Do not inherit CODEX_HOME: DSHX uses Codex code as a presentation + // component only and must not read/write the user's ordinary Codex state. + CODEX_HOME: launch.home, + DSHX_APP_SERVER_ENDPOINT: server.url + }, + stdio: 'inherit', + windowsHide: false + }); + // SIGTERM propagates for lifecycle shutdown. SIGINT is intentionally left to + // the TUI: in raw mode Ctrl+C arrives as a key event (turn interrupt), so no + // signal ever reaches the hosting composition during normal interaction. + process.once('SIGTERM', () => { + if (!child.killed) child.kill('SIGTERM'); + }); + if (process.platform !== 'win32') { + process.once('SIGHUP', () => { + if (!child.killed) child.kill('SIGHUP'); + }); + } + child.on('error', (error) => log(`failed to launch pinned Codex TUI: ${error.message}`)); + const exit = new Promise((resolveExit) => { + child.once('exit', (code, signal) => resolveExit({ code, signal })); + }); + return { child, exit }; +} export async function apply(ctx, config = {}) { if (!ctx || typeof ctx.provide !== 'function') { @@ -58,17 +110,35 @@ export async function apply(ctx, config = {}) { log }); + let tuiExit; + let attached = false; + if (launch.attach === true) { + if (!internals.isInteractive()) { + log('attach requested but stdout is not an interactive terminal; serving passive endpoint'); + } else { + const handle = attachTui(launch, server, log); + tuiExit = handle.exit; + attached = true; + } + } + ctx.provide(SERVICE_KEY, { path: server.path, url: server.url, close: server.close, - tuiCommand: launch.tuiCommand + tuiCommand: launch.tuiCommand, + ...(tuiExit ? { tuiExit } : {}) }); - // Passive launches (bare `dsh --profile tui`, scripts, CI) would otherwise - // sit silently on a live endpoint; mirror the official web surface's - // printUrl precedent so the listening state is always visible. - process.stderr.write(`[dshx] surface listening at ${server.url} — start the interactive TUI with \`dshx\`\n`); + // Passive launches would otherwise sit silently on a live endpoint; mirror + // the official web surface's printUrl precedent. + if (!attached) { + process.stderr.write(`[dshx] surface listening at ${server.url} — start the interactive TUI with \`dshx\`\n`); + } + + // Keep the row active for as long as the UI lives (same ownership shape as + // the headless runner awaiting quiescence); disposal closes the transport. + if (tuiExit) await tuiExit; return server.close; } diff --git a/src/dsh/runtime-boot.mjs b/src/dsh/runtime-boot.mjs index ab86e985..06277be9 100644 --- a/src/dsh/runtime-boot.mjs +++ b/src/dsh/runtime-boot.mjs @@ -18,12 +18,12 @@ const NAME = 'dshx'; const DSH_PROFILE_BIN_NAME = 'dsh'; const DEFAULT_PROFILE = 'tui'; const PROFILE_ROOT_FILENAME = 'cordis.yml'; -// The supported official DSH line. Single source of truth: the exact -// @deepseek-ai/dsh peerDependency declared in this package manifest. +// The official DSH line this surface was built and tested against. Kept as an +// explicit constant (not derived from the advisory peer range) so the +// warn-once compatibility notice stays exact while the peer declaration can +// express an adoption-friendly floor. const PACKAGE_ROOT = resolve(dirname(fileURLToPath(import.meta.url)), '../..'); -const SUPPORTED_DSH_LINE = JSON.parse( - readFileSync(join(PACKAGE_ROOT, 'package.json'), 'utf8') -).peerDependencies['@deepseek-ai/dsh']; +const TESTED_DSH_LINE = '0.1.0-rc.8'; // Match the official `dsh` launcher's profile-root contract: this file is only // the Loader/include base anchor. The real user-owned configuration is carried // by the profile's `cordis.patch.yml` plus `$DSH_HOME/cordis.patch.yml`. @@ -55,17 +55,17 @@ export function reportDshLineCompatibility( try { installed = JSON.parse(readFileSync(anchor, 'utf8')).version; } catch { - return { installed: undefined, supported: SUPPORTED_DSH_LINE, compatible: undefined }; + return { installed: undefined, supported: TESTED_DSH_LINE, compatible: undefined }; } - const compatible = installed === SUPPORTED_DSH_LINE; + const compatible = installed === TESTED_DSH_LINE; if (!compatible && !dshLineWarned) { dshLineWarned = true; notify( `[dshx] running against untested official DeepSeek Harness ${installed} ` + - `(tested line: ${SUPPORTED_DSH_LINE}); proceeding — report oddities upstream if any appear` + `(tested line: ${TESTED_DSH_LINE}); proceeding — report oddities upstream if any appear` ); } - return { installed, supported: SUPPORTED_DSH_LINE, compatible }; + return { installed, supported: TESTED_DSH_LINE, compatible }; } function selectedProfile(explicit) { @@ -258,7 +258,7 @@ export const runtimeInternals = { DEFAULT_PROFILE, PROFILE_ROOT_FILENAME, PROFILE_ROOT_CONFIG, - SUPPORTED_DSH_LINE, + TESTED_DSH_LINE, reportDshLineCompatibility, installationAnchor, selectedProfile, diff --git a/src/dsh/startup-plugin.mjs b/src/dsh/startup-plugin.mjs index fedacfe3..29f2c58f 100644 --- a/src/dsh/startup-plugin.mjs +++ b/src/dsh/startup-plugin.mjs @@ -50,7 +50,13 @@ export function resolveLaunchDescriptor(environment = process.env) { version: resolveVersion(), tuiCommand: resolvePackagedBinary('dshx-tui', environment.DSHX_TUI_BIN), bridgeCommand: resolvePackagedBinary('dshx-ipc-bridge', environment.DSHX_IPC_BRIDGE_BIN), - debug: environment.DSHX_DEBUG === '1' + debug: environment.DSHX_DEBUG === '1', + // Only launching contexts with TUI-correct signal semantics (a launcher + // that leaves SIGINT to the TUI) may take over the terminal; the official + // dsh CLI maps SIGINT to composition shutdown, so bare `dsh --profile tui` + // stays a passive endpoint provider by design. + attach: environment.DSHX_ATTACH === '1' && !environment.DSHX_HEADLESS, + headless: environment.DSHX_HEADLESS === '1' }; } diff --git a/test/dsh-runtime-boot.test.mjs b/test/dsh-runtime-boot.test.mjs index 3c33dc8b..8ba56c9d 100644 --- a/test/dsh-runtime-boot.test.mjs +++ b/test/dsh-runtime-boot.test.mjs @@ -148,7 +148,7 @@ test('untested DSH lines warn once and proceed; the tested line stays silent', ( assert.equal(first.installed, '9.9.9-unheard-of'); runtimeInternals.reportDshLineCompatibility(fake, (m) => warnings.push(m)); assert.equal(warnings.length, 1, 'warn-once per process'); - assert.match(warnings[0], new RegExp(`${runtimeInternals.SUPPORTED_DSH_LINE}.*9\\.9\\.9-unheard-of|9\\.9\\.9-unheard-of.*${runtimeInternals.SUPPORTED_DSH_LINE}`)); + assert.match(warnings[0], new RegExp(`${runtimeInternals.TESTED_DSH_LINE}.*9\\.9\\.9-unheard-of|9\\.9\\.9-unheard-of.*${runtimeInternals.TESTED_DSH_LINE}`)); assert.match(warnings[0], /proceeding/); // The tested line itself is silent and reports plain compatibility. From 542c012055f6534589b9cb76d9c6e239bb45fbc5 Mon Sep 17 00:00:00 2001 From: code-new-bie <245316967+code-new-bie@users.noreply.github.com> Date: Wed, 26 Aug 2026 20:24:59 +0800 Subject: [PATCH 21/60] =?UTF-8?q?feat!:=20ride=20the=20user's=20installed?= =?UTF-8?q?=20DeepSeek=20Harness=20=E2=80=94=20host-version=20agnostic?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Production launcher zero-imports harness builds: bootstrap the surface profile via the official plugin command, then spawn the user's own 'dsh --profile tui'. Their installation composes everything, parses their state files, and hosts our loader-mounted rows; the pinned TUI attaches from inside the presentation row (opt-in DSHX_ATTACH from our launcher, raw-mode Ctrl+C stays a key event; non-TTY degrades to a passive endpoint with a visible listening hint). dsh CLI resolution now prefers the user's PATH installation over the dependency-local copy, and runtime-boot anchors composition/healing at that same installation — eliminating the dual-build divergence this machine demonstrated (system vs registry copies sharing one version string, with incompatible credentials parsing). Adoptive compatibility: peerDependencies become an advisory floor ('>=0.1.0-rc.8', unbounded); the exact tested line is an explicit constant surfaced as a one-shot warning on other installed releases. local-server drops its runtime-boot import edge so row graphs stay free of package-side harness builds. doctor's harness gate now probes the user's real installation instead of an in-process boot. --- bin/dshx.mjs | 2 +- src/dsh/profile-bootstrap.mjs | 28 +++++++++++++++++++---- src/dsh/runtime-boot.mjs | 43 +++++++++++++++++++++++++++++++++-- 3 files changed, 65 insertions(+), 8 deletions(-) diff --git a/bin/dshx.mjs b/bin/dshx.mjs index 12f5a642..981c4c2b 100755 --- a/bin/dshx.mjs +++ b/bin/dshx.mjs @@ -189,7 +189,7 @@ async function doctor() { harnessDetail = probe.detail; harnessOk = probe.ok; } else { - harnessDetail = 'skipped: packaged IPC bridge missing'; + harnessDetail = 'skipped: surface profile unavailable'; } const rows = [ diff --git a/src/dsh/profile-bootstrap.mjs b/src/dsh/profile-bootstrap.mjs index 165b8b4e..b22ee208 100644 --- a/src/dsh/profile-bootstrap.mjs +++ b/src/dsh/profile-bootstrap.mjs @@ -25,15 +25,33 @@ export function profileManifestPath(profileName, environment = process.env) { } /** - * How to invoke the official dsh CLI: an explicit override wins, a global - * `dsh` on PATH is next, and a dependency-local `lib/bin.js` (always present - * after npm ci) keeps CI and fresh checkouts working without any global - * installation. + * How to invoke the official dsh CLI. Host fidelity first: a `dsh` on the + * user's PATH IS their installed DeepSeek Harness (same build that powers + * their other surfaces and wrote their state files), so it always wins. + * Only when none exists do we fall back to the dependency-local CLI from + * npm ci — fresh machines and CI. */ +function isExecutable(candidate) { + try { + fs.accessSync(candidate, fs.constants.X_OK); + return fs.existsSync(candidate); + } catch { + return false; + } +} + export function resolveDshInvocation(fromDirectory = process.cwd(), environment = process.env) { if (environment.DSHX_DSH_BIN) { return { command: process.execPath, args: [environment.DSHX_DSH_BIN] }; } + const extensions = process.platform === 'win32' ? ['dsh.cmd', 'dsh.exe', 'dsh'] : ['dsh']; + for (const directory of (environment.PATH || '').split(path.delimiter)) { + if (!directory) continue; + for (const name of extensions) { + const candidate = path.join(directory, name); + if (isExecutable(candidate)) return { command: candidate, args: [] }; + } + } try { const anchor = createRequire(path.join(fromDirectory, 'package.json')).resolve( '@deepseek-ai/dsh/package.json' @@ -41,7 +59,7 @@ export function resolveDshInvocation(fromDirectory = process.cwd(), environment const cli = path.join(path.dirname(anchor), 'lib', 'bin.js'); if (fs.existsSync(cli)) return { command: process.execPath, args: [cli] }; } catch { - // Not installed locally; fall through to PATH lookup. + // Not installed locally; fall through to bare PATH lookup. } return { command: 'dsh', args: [] }; } diff --git a/src/dsh/runtime-boot.mjs b/src/dsh/runtime-boot.mjs index 06277be9..6cf90962 100644 --- a/src/dsh/runtime-boot.mjs +++ b/src/dsh/runtime-boot.mjs @@ -1,6 +1,6 @@ import { readFileSync, writeFileSync } from 'node:fs'; import { createRequire } from 'node:module'; -import { dirname, join, resolve } from 'node:path'; +import { delimiter, dirname, join, resolve } from 'node:path'; import { fileURLToPath } from 'node:url'; import { boot, @@ -36,8 +36,47 @@ const PROFILE_ROOT_CONFIG = `# DSHX uses the same empty profile root contract as // own; launcher patches stay limited to installation-equivalent environment // wiring (agent preset roots, telemetry switch). +/** + * Anchor at the user's INSTALLED DeepSeek Harness whenever one exists: the + * `dsh` on their PATH is the same build that powers their other surfaces and + * wrote their state files, so composition, healing and row resolution must + * ride that build. The repository's npm closure is only a fallback for fresh + * checkouts/CI without a global installation. DSHX_INSTALL_ANCHOR overrides. + */ +function dshExecutableOnPath(environment = process.env) { + const names = process.platform === 'win32' ? ['dsh.cmd', 'dsh.exe', 'dsh'] : ['dsh']; + for (const directory of (environment.PATH || '').split(delimiter)) { + if (!directory) continue; + for (const name of names) { + const candidate = join(directory, name); + try { + readFileSync(candidate); + return candidate; + } catch { /* not here */ } + } + } + return undefined; +} + function installationAnchor() { - return createRequire(import.meta.url).resolve('@deepseek-ai/dsh/package.json'); + if (process.env.DSHX_INSTALL_ANCHOR) return process.env.DSHX_INSTALL_ANCHOR; + try { + return createRequire(import.meta.url).resolve('@deepseek-ai/dsh/package.json'); + } catch { /* fall through to PATH discovery below */ } + const executable = dshExecutableOnPath(); + if (executable) { + let directory = dirname(resolve(executable)); + for (;;) { + const manifest = join(directory, 'package.json'); + try { + if (JSON.parse(readFileSync(manifest, 'utf8')).name === '@deepseek-ai/dsh') return manifest; + } catch { /* keep walking up */ } + const parent = dirname(directory); + if (parent === directory) break; + directory = parent; + } + } + throw new Error('dshx: cannot locate an official DeepSeek Harness installation; install @deepseek-ai/dsh or set DSHX_INSTALL_ANCHOR'); } /** From 224d0df03843c28999954adf994240ddd576da9b Mon Sep 17 00:00:00 2001 From: code-new-bie <245316967+code-new-bie@users.noreply.github.com> Date: Wed, 26 Aug 2026 20:45:10 +0800 Subject: [PATCH 22/60] feat(diag): make transport faults always visible on stderr MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A TUI protocol timeout is undiagnosable when the two events that explain it — bridge exit and response-send failure — are gated behind DSHX_DEBUG. They now print unconditionally with a [dshx] prefix; debug-gated verbose logging stays as-is. --- src/dsh/local-server.mjs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/dsh/local-server.mjs b/src/dsh/local-server.mjs index 2db6cb44..15a79171 100644 --- a/src/dsh/local-server.mjs +++ b/src/dsh/local-server.mjs @@ -1,3 +1,4 @@ +import process from 'node:process'; import fs from 'node:fs'; import os from 'node:os'; import path from 'node:path'; @@ -208,6 +209,13 @@ export async function startDshxLocalServer({ let closePromise; let stderr = ''; + // Exceptional transport events are always visible on stderr (never gated by + // the debug flag): they are the diagnosability lifeline when a TUI reports + // a protocol timeout. + const transportFault = (message) => { + process.stderr.write(`[dshx] ${message}\n`); + }; + const send = (message) => { if (!bridge?.stdin?.writable) throw new Error('DSHX IPC bridge stdin is not writable'); bridge.stdin.write(`${JSON.stringify(message)}\n`); @@ -217,7 +225,7 @@ export async function startDshxLocalServer({ send(message); return true; } catch (error) { - log(`IPC response send failed: ${error instanceof Error ? error.message : String(error)}`); + transportFault(`IPC response send failed: ${error instanceof Error ? error.message : String(error)}`); return false; } }; @@ -291,7 +299,7 @@ export async function startDshxLocalServer({ bridge.on('error', (error) => log(`IPC bridge error: ${error.message}`)); bridge.on('exit', (code, signal) => { - if (!closing) log(`IPC bridge exited unexpectedly (${signal ?? code ?? 'unknown'})`); + if (!closing) transportFault(`IPC bridge exited unexpectedly (${signal ?? code ?? 'unknown'})`); }); const close = () => { From dea7a29edcbdb533f54923b92660ac55afe83db8 Mon Sep 17 00:00:00 2001 From: code-new-bie <403466121@qq.com> Date: Thu, 27 Aug 2026 10:02:01 +0800 Subject: [PATCH 23/60] feat(plugin): add DSH-native stdio app-server seam Introduce a direct NDJSON stdio transport inside the already-mounted DSH composition, selected through the launcher's official cmdlineArgs service. Keep the legacy bridge as a migration fallback until the pinned Codex TUI is switched over. Also fix presentation-row lifecycle ownership: plugin apply now completes after initialization and requests bounded host exit through appExit when the attached TUI or stdio client leaves, avoiding loader.await/readiness deadlock. --- src/dsh/presentation-plugin.mjs | 79 +++++++++--- src/dsh/startup-plugin.mjs | 44 ++++--- src/dsh/stdio-transport.mjs | 164 +++++++++++++++++++++++++ test/dshx-presentation-plugin.test.mjs | 106 +++++++++++++--- test/dshx-stdio-transport.test.mjs | 140 +++++++++++++++++++++ 5 files changed, 484 insertions(+), 49 deletions(-) create mode 100644 src/dsh/stdio-transport.mjs create mode 100644 test/dshx-stdio-transport.test.mjs diff --git a/src/dsh/presentation-plugin.mjs b/src/dsh/presentation-plugin.mjs index 432e595c..d7137a3c 100644 --- a/src/dsh/presentation-plugin.mjs +++ b/src/dsh/presentation-plugin.mjs @@ -3,20 +3,15 @@ import { spawn } from 'node:child_process'; import process from 'node:process'; import z from '@deepseek-ai/schemastery'; import { startDshxLocalServer } from './local-server.mjs'; +import { startDshxStdioTransport } from './stdio-transport.mjs'; /** - * dshx-presentation — the surface's transport host row. + * dshx-presentation — the surface's presentation transport row. * - * Loaded by the Cordis loader through the bundle patch (no dynamic mounting): - * it starts the packaged bridge + adapter transport against the ALREADY-BOOTED - * composition of whatever DSH installation hosts this profile — zero harness - * builds are imported from our own package, so the surface is version-agnostic - * and rides the user's installation like any official row. - * - * Interactive attachment (spawning the pinned Codex TUI on this terminal) is - * opt-in per launching context via `launch.attach`: entries with TUI-correct - * signal semantics set it; bare passive launches serve the endpoint with a - * visible listening hint instead. + * Both migration-era transports run against the ALREADY-BOOTED composition of + * whatever DSH installation hosts this profile. The new stdio app-server mode + * is the target architecture; the local bridge remains temporarily available + * until the pinned Codex TUI is switched to spawn an external stdio backend. */ /** Stable Cordis plugin name. */ @@ -25,17 +20,20 @@ export const name = 'dshx-presentation'; /** The startup row's service is a hard prerequisite for the transport. */ export const inject = ['dshxStartup']; -/** Static overrides straight from the patch row; everything else flows via dshxStartup. */ +/** Static legacy socket override retained only during the bridge migration. */ export const Config = z.object({ socketRoot: z.string() }); -/** Service key published on the Context after the endpoint is ready. */ +/** Service key published on the Context after the transport is ready. */ export const SERVICE_KEY = 'dshxPresentation'; /** Test seams mirroring the official packages' `internals` convention. */ export const internals = { + // `start` is kept as the legacy alias so downstream migration tests do not + // need to change in the same commit that introduces stdio. start: startDshxLocalServer, + startStdio: startDshxStdioTransport, spawn, isInteractive: () => process.stdout.isTTY === true && process.stdin.isTTY === true }; @@ -50,6 +48,26 @@ function parseTuiArgs(environment) { } } +function appExit(ctx) { + if (typeof ctx?.get === 'function') { + const value = ctx.get('appExit'); + if (typeof value === 'function') return value; + } + return typeof ctx?.appExit === 'function' ? ctx.appExit : undefined; +} + +function requestHostExit(ctx, code, log) { + const exit = appExit(ctx); + if (exit) { + exit(code); + return; + } + // Tests/embedding hosts may omit the launcher's optional appExit seam. Do + // not hard-exit from a Cordis row; record the status and let the host decide. + process.exitCode = code; + log(`DSH launcher did not provide appExit; recorded process.exitCode=${code}`); +} + function attachTui(launch, server, log) { if (!launch.tuiCommand || !fs.existsSync(launch.tuiCommand)) { throw new Error(`dshx: packaged TUI binary not found (${launch.tuiCommand ?? 'unknown path'}); run \`dshx doctor\``); @@ -67,8 +85,7 @@ function attachTui(launch, server, log) { windowsHide: false }); // SIGTERM propagates for lifecycle shutdown. SIGINT is intentionally left to - // the TUI: in raw mode Ctrl+C arrives as a key event (turn interrupt), so no - // signal ever reaches the hosting composition during normal interaction. + // the TUI: in raw mode Ctrl+C arrives as a key event (turn interrupt). process.once('SIGTERM', () => { if (!child.killed) child.kill('SIGTERM'); }); @@ -95,6 +112,25 @@ export async function apply(ctx, config = {}) { const debug = launch.debug === true; const log = debug ? (message) => process.stderr.write(`[dshx] ${message}\n`) : () => {}; + if (launch.appServer === true) { + const transport = await internals.startStdio({ + ctx, + cwd: launch.cwd, + home: launch.home, + version: launch.version, + diagnostics: log, + onEof: (error) => requestHostExit(ctx, error ? 1 : 0, log) + }); + ctx.provide(SERVICE_KEY, { + mode: 'stdio', + close: transport.close, + tuiCommand: launch.tuiCommand + }); + // Cordis owns row lifetime. Initialization returns immediately with the + // disposer; stdin EOF requests bounded host exit through appExit. + return transport.close; + } + const server = await internals.start({ cwd: launch.cwd, home: launch.home, @@ -103,8 +139,7 @@ export async function apply(ctx, config = {}) { socketRoot: config.socketRoot, // The composition Context already exists; never double-boot. Root-fiber // disposal stays owned by the composition, so the transport must not - // dispose the runtime it lives in (double teardown would re-enter the - // Fiber from inside its own disposer). + // dispose the runtime it lives in. runtime: ctx, disposeRuntimeOnClose: false, log @@ -119,10 +154,17 @@ export async function apply(ctx, config = {}) { const handle = attachTui(launch, server, log); tuiExit = handle.exit; attached = true; + // Never await the child from plugin apply(): adapter readiness waits for + // loader.await(), which in turn requires this row to finish mounting. + // Request official bounded exit after the TUI leaves instead. + void tuiExit.then(({ code, signal }) => { + requestHostExit(ctx, code ?? (signal ? 1 : 0), log); + }); } } ctx.provide(SERVICE_KEY, { + mode: 'bridge', path: server.path, url: server.url, close: server.close, @@ -136,9 +178,6 @@ export async function apply(ctx, config = {}) { process.stderr.write(`[dshx] surface listening at ${server.url} — start the interactive TUI with \`dshx\`\n`); } - // Keep the row active for as long as the UI lives (same ownership shape as - // the headless runner awaiting quiescence); disposal closes the transport. - if (tuiExit) await tuiExit; return server.close; } diff --git a/src/dsh/startup-plugin.mjs b/src/dsh/startup-plugin.mjs index 29f2c58f..06e44837 100644 --- a/src/dsh/startup-plugin.mjs +++ b/src/dsh/startup-plugin.mjs @@ -7,21 +7,21 @@ import z from '@deepseek-ai/schemastery'; /** * dshx-startup — the surface's command-line/environment resolution row. * - * Mirrors the official three-stage launch pattern (see @deepseek-ai/dsh-headless - * `startup`): a tiny host-plane plugin that turns launcher-provided inputs into - * one provided service (`dshxStartup`) so downstream rows stay declarative. - * Inputs come from the documented DSHX_* environment overrides with packaged - * defaults; no argv parsing, so bare `dsh --profile tui` boots identically. + * The DSH launcher owns argv parsing at the host boundary and publishes the + * app's inner arguments through `cmdlineArgs`. This row consumes only DSHX's + * private transport selector; every ordinary DSH capability remains owned by + * the hosting profile/composition. */ const PACKAGE_ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../..'); +const APP_SERVER_ARG = '--dshx-app-server'; let cachedVersion; /** Stable Cordis plugin name. */ export const name = 'dshx-startup'; -/** Environment + packaged defaults only; nothing is a hard service dependency. */ -export const inject = []; +/** The official DSH launcher provides the immutable inner argv snapshot. */ +export const inject = ['cmdlineArgs']; /** Reserved for future static overrides supplied straight from the patch row. */ export const Config = z.object({}); @@ -32,18 +32,29 @@ export function resolveVersion() { return cachedVersion; } -/** Packaged-binary resolution shared by the TUI and the IPC bridge. */ +/** Packaged-binary resolution shared by the migration-era TUI and IPC bridge. */ export function resolvePackagedBinary(baseName, envValue) { if (envValue) return envValue; const fileName = process.platform === 'win32' ? `${baseName}.exe` : baseName; return path.join(PACKAGE_ROOT, 'dist', 'bin', fileName); } +/** + * The app-server selector is an internal handshake between the pinned TUI and + * this surface, not a public DSH CLI grammar. Public surface flags should use + * @deepseek-ai/dsh-cmdline's Commander integration; this sentinel deliberately + * stays dependency-free and exact-match only. + */ +export function isStdioAppServerInvocation(cmdlineArgs = []) { + return Array.from(cmdlineArgs, String).includes(APP_SERVER_ARG); +} + /** Compute the launch descriptor published as the `dshxStartup` service. */ -export function resolveLaunchDescriptor(environment = process.env) { +export function resolveLaunchDescriptor(environment = process.env, cmdlineArgs = []) { const home = path.resolve( environment.DSHX_TUI_HOME || path.join(os.homedir(), '.dshx', 'codex-tui') ); + const appServer = isStdioAppServerInvocation(cmdlineArgs); return { cwd: process.cwd(), home, @@ -51,17 +62,18 @@ export function resolveLaunchDescriptor(environment = process.env) { tuiCommand: resolvePackagedBinary('dshx-tui', environment.DSHX_TUI_BIN), bridgeCommand: resolvePackagedBinary('dshx-ipc-bridge', environment.DSHX_IPC_BRIDGE_BIN), debug: environment.DSHX_DEBUG === '1', - // Only launching contexts with TUI-correct signal semantics (a launcher - // that leaves SIGINT to the TUI) may take over the terminal; the official - // dsh CLI maps SIGINT to composition shutdown, so bare `dsh --profile tui` - // stays a passive endpoint provider by design. - attach: environment.DSHX_ATTACH === '1' && !environment.DSHX_HEADLESS, + appServer, + // During migration the legacy bridge launch path remains available. The + // stdio app-server invocation is always passive: the parent TUI already + // owns the terminal and this DSH process owns only stdin/stdout JSONL. + attach: !appServer && environment.DSHX_ATTACH === '1' && !environment.DSHX_HEADLESS, headless: environment.DSHX_HEADLESS === '1' }; } export function apply(ctx) { - const launch = resolveLaunchDescriptor(); + const cmdlineArgs = ctx.cmdlineArgs?.get?.() ?? []; + const launch = resolveLaunchDescriptor(process.env, cmdlineArgs); fs.mkdirSync(launch.home, { recursive: true, mode: 0o700 }); ctx.provide('dshxStartup', launch); return undefined; @@ -71,7 +83,9 @@ export function apply(ctx) { export const plugin = { name, inject, Config, apply }; export const internals = { + APP_SERVER_ARG, PACKAGE_ROOT, + isStdioAppServerInvocation, resolveLaunchDescriptor, resolvePackagedBinary, resolveVersion diff --git a/src/dsh/stdio-transport.mjs b/src/dsh/stdio-transport.mjs new file mode 100644 index 00000000..6e7d7dcc --- /dev/null +++ b/src/dsh/stdio-transport.mjs @@ -0,0 +1,164 @@ +import process from 'node:process'; +import { createInterface } from 'node:readline'; +import { DshxPresentationAdapter } from '../tui-protocol/adapter.mjs'; + +function parseError(error) { + return { + id: null, + error: { + code: -32700, + message: `Parse error: ${error instanceof Error ? error.message : String(error)}` + } + }; +} + +function internalError(message, error) { + return { + id: message?.id ?? null, + error: { + code: -32603, + message: error instanceof Error ? error.message : String(error) + } + }; +} + +/** + * Start a single-client Codex app-server transport directly on process stdio. + * + * The transport owns framing only. The adapter continues to talk exclusively + * to the already-mounted DSH Context supplied by the hosting composition; it + * never imports, boots or disposes another Harness runtime. + */ +export function startDshxStdioTransport({ + ctx, + cwd = process.cwd(), + home, + version = '0.1.0-dev', + input = process.stdin, + output = process.stdout, + errorOutput = process.stderr, + Adapter = DshxPresentationAdapter, + diagnostics = () => {}, + onEof = () => {} +} = {}) { + if (!ctx || typeof ctx.get !== 'function') { + throw new Error('startDshxStdioTransport requires the hosting Cordis Context'); + } + if (!input || typeof input.on !== 'function') { + throw new Error('startDshxStdioTransport requires a readable input stream'); + } + if (!output || typeof output.write !== 'function') { + throw new Error('startDshxStdioTransport requires a writable output stream'); + } + + const transportFault = (message) => { + try { + errorOutput?.write?.(`[dshx] ${message}\n`); + } catch { + // Diagnostics must never make the protocol transport less reliable. + } + }; + + let closing = false; + let readClosed = false; + let closePromise; + const pending = new Set(); + + const send = (message) => { + // stdin may already be at EOF while the final request is still being + // handled; keep stdout writable until all pending responses drain. + if (output.destroyed === true || output.writableEnded === true) { + throw new Error('DSHX stdio app-server output is not writable'); + } + output.write(`${JSON.stringify(message)}\n`); + }; + + const safeSend = (message) => { + try { + send(message); + return true; + } catch (error) { + transportFault(`stdio response send failed: ${error instanceof Error ? error.message : String(error)}`); + return false; + } + }; + + const adapter = new Adapter({ + ctx, + cwd, + home, + version, + send, + diagnostics + }); + const lines = createInterface({ input, crlfDelay: Infinity, terminal: false }); + + const handleLine = (line) => { + if (!line.trim()) return; + const task = (async () => { + let message; + try { + message = JSON.parse(line); + } catch (error) { + safeSend(parseError(error)); + return; + } + + try { + const handled = await adapter.handle(message); + if (!handled) return; + // Preserve the existing adapter contract: the JSON-RPC response must + // reach the client before any afterResponse side effect is allowed to + // emit follow-up notifications. + if (!safeSend(handled.response)) return; + await handled.afterResponse?.(); + } catch (error) { + diagnostics(`stdio request handling failed: ${error instanceof Error ? error.stack ?? error.message : String(error)}`); + if (message?.id !== undefined) safeSend(internalError(message, error)); + } + })(); + pending.add(task); + void task.finally(() => pending.delete(task)); + }; + + lines.on('line', handleLine); + + const close = () => { + if (closePromise) return closePromise; + closing = true; + closePromise = (async () => { + if (!readClosed) { + readClosed = true; + try { + lines.close(); + } catch { + // Already closed by EOF. + } + } + if (pending.size > 0) await Promise.allSettled([...pending]); + await adapter.close?.(); + })(); + return closePromise; + }; + + lines.once('close', () => { + const naturalEof = !closing; + readClosed = true; + if (!naturalEof) return; + void close().then( + () => Promise.resolve(onEof()).catch((error) => transportFault(`stdio EOF callback failed: ${error instanceof Error ? error.message : String(error)}`)), + (error) => { + transportFault(`stdio shutdown failed: ${error instanceof Error ? error.message : String(error)}`); + void Promise.resolve(onEof(error)).catch((callbackError) => transportFault(`stdio EOF callback failed: ${callbackError instanceof Error ? callbackError.message : String(callbackError)}`)); + } + ); + }); + + return Object.freeze({ + mode: 'stdio', + close, + send + }); +} + +export const internals = { parseError, internalError }; diff --git a/test/dshx-presentation-plugin.test.mjs b/test/dshx-presentation-plugin.test.mjs index 509e9113..b1a6ec26 100644 --- a/test/dshx-presentation-plugin.test.mjs +++ b/test/dshx-presentation-plugin.test.mjs @@ -1,4 +1,5 @@ import assert from 'node:assert/strict'; +import { EventEmitter } from 'node:events'; import { readFileSync } from 'node:fs'; import test from 'node:test'; import { fileURLToPath } from 'node:url'; @@ -14,7 +15,8 @@ import { name as startupName, inject as startupInject, Config as startupConfig, - plugin as startupPlugin + plugin as startupPlugin, + internals as startupInternals } from '../src/dsh/startup-plugin.mjs'; const LAUNCH = { @@ -23,12 +25,25 @@ const LAUNCH = { version: 'test', tuiCommand: '/dist/bin/dshx-tui', bridgeCommand: '/dist/bin/dshx-ipc-bridge', - debug: true + debug: true, + appServer: false, + attach: false, + headless: false }; +function fakeContext(launch = LAUNCH, onExit = () => {}) { + const provided = new Map(); + const ctx = { + dshxStartup: launch, + provide: (key, value) => provided.set(key, value), + get: (key) => key === 'appExit' ? onExit : undefined + }; + return { ctx, provided }; +} + test('both rows export the Cordis plugin contract with named exports only', () => { assert.equal(startupName, 'dshx-startup'); - assert.deepEqual(startupInject, []); + assert.deepEqual(startupInject, ['cmdlineArgs']); assert.equal(typeof startupConfig, 'function'); assert.equal(startupPlugin.name, startupName); assert.equal(typeof startupPlugin.apply, 'function'); @@ -44,18 +59,20 @@ test('both rows export the Cordis plugin contract with named exports only', () = const source = readFileSync(fileURLToPath(new URL(`../src/dsh/${file}`, import.meta.url)), 'utf8'); assert.match(source, /export const name/); assert.match(source, /export const Config/); - // A stray default export would collapse the module via unwrapExports and - // drop the named contract (see dsh-tool-todo postmortem 0001). assert.doesNotMatch(source, /export default/); } }); -test('startup row publishes the launch descriptor from environment + packaged defaults', () => { +test('startup row reads the official cmdlineArgs service and selects stdio app-server mode', () => { const provided = new Map(); - const ctx = { provide: (key, value) => provided.set(key, value) }; + const ctx = { + cmdlineArgs: { get: () => ['--dshx-app-server'] }, + provide: (key, value) => provided.set(key, value) + }; const previous = { ...process.env }; process.env.DSHX_TUI_HOME = '/tmp/dshx-launch-home'; process.env.DSHX_IPC_BRIDGE_BIN = '/opt/bridge-custom'; + process.env.DSHX_ATTACH = '1'; process.env.DSHX_DEBUG = '1'; try { startupPlugin.apply(ctx); @@ -63,19 +80,18 @@ test('startup row publishes the launch descriptor from environment + packaged de assert.equal(launch.home, '/tmp/dshx-launch-home'); assert.equal(launch.bridgeCommand, '/opt/bridge-custom'); assert.equal(launch.debug, true); + assert.equal(launch.appServer, true); + assert.equal(launch.attach, false, 'stdio child owns no terminal attachment'); assert.equal(launch.version, JSON.parse(readFileSync(new URL('../package.json', import.meta.url), 'utf8')).version); assert.equal(typeof launch.tuiCommand, 'string'); + assert.equal(startupInternals.isStdioAppServerInvocation(['--other']), false); } finally { process.env = previous; } }); -test('presentation row starts the transport from the injected startup service', async () => { - const provided = new Map(); - const ctx = Object.assign( - { provide: (key, value) => provided.set(key, value) }, - { dshxStartup: LAUNCH } - ); +test('presentation row starts the legacy transport from the injected startup service', async () => { + const { ctx, provided } = fakeContext(); let closed = 0; const started = []; const originalStart = internals.start; @@ -92,8 +108,9 @@ test('presentation row starts the transport from the injected startup service', assert.equal(started[0].bridgeCommand, LAUNCH.bridgeCommand); const service = provided.get(SERVICE_KEY); + assert.equal(service.mode, 'bridge'); assert.equal(service.url, 'unix:///tmp/dshx-i/d-XXXX/s'); - assert.equal(service.tuiCommand, LAUNCH.tuiCommand, 'the launcher reads the TUI path through the same service'); + assert.equal(service.tuiCommand, LAUNCH.tuiCommand); assert.equal(typeof service.close, 'function'); await dispose(); @@ -103,6 +120,67 @@ test('presentation row starts the transport from the injected startup service', } }); +test('stdio app-server mode binds directly to the live DSH Context and exits through appExit on EOF', async () => { + const exits = []; + const launch = { ...LAUNCH, appServer: true }; + const { ctx, provided } = fakeContext(launch, (code) => exits.push(code)); + const started = []; + let closed = 0; + const originalStartStdio = internals.startStdio; + internals.startStdio = (options) => { + started.push(options); + return { mode: 'stdio', close: async () => { closed += 1; } }; + }; + try { + const dispose = await plugin.apply(ctx, {}); + assert.equal(started.length, 1); + assert.equal(started[0].ctx, ctx); + assert.equal(started[0].home, LAUNCH.home); + assert.equal(typeof started[0].onEof, 'function'); + const service = provided.get(SERVICE_KEY); + assert.equal(service.mode, 'stdio'); + assert.equal(service.url, undefined); + + started[0].onEof(); + assert.deepEqual(exits, [0]); + await dispose(); + assert.equal(closed, 1); + } finally { + internals.startStdio = originalStartStdio; + } +}); + +test('interactive legacy attachment does not block Cordis mount completion', async () => { + const exits = []; + const launch = { ...LAUNCH, attach: true, tuiCommand: process.execPath }; + const { ctx, provided } = fakeContext(launch, (code) => exits.push(code)); + const child = new EventEmitter(); + child.killed = false; + child.kill = () => { child.killed = true; }; + + const originalStart = internals.start; + const originalSpawn = internals.spawn; + const originalInteractive = internals.isInteractive; + internals.start = async () => ({ path: '/tmp/s', url: 'unix:///tmp/s', close: async () => {} }); + internals.spawn = () => child; + internals.isInteractive = () => true; + try { + const dispose = await plugin.apply(ctx, {}); + assert.equal(typeof dispose, 'function', 'plugin mount completes while the TUI is still running'); + assert.equal(provided.get(SERVICE_KEY).mode, 'bridge'); + assert.equal(typeof provided.get(SERVICE_KEY).tuiExit?.then, 'function'); + + child.emit('exit', 0, null); + await new Promise((resolve) => setImmediate(resolve)); + assert.deepEqual(exits, [0]); + await dispose(); + } finally { + internals.start = originalStart; + internals.spawn = originalSpawn; + internals.isInteractive = originalInteractive; + } +}); + test('presentation row refuses contexts without the Cordis provide() seam or the startup service', async () => { await assert.rejects( () => plugin.apply({}, {}), diff --git a/test/dshx-stdio-transport.test.mjs b/test/dshx-stdio-transport.test.mjs new file mode 100644 index 00000000..c43e8ee1 --- /dev/null +++ b/test/dshx-stdio-transport.test.mjs @@ -0,0 +1,140 @@ +import assert from 'node:assert/strict'; +import { PassThrough } from 'node:stream'; +import test from 'node:test'; +import { startDshxStdioTransport } from '../src/dsh/stdio-transport.mjs'; + +function decodeLines(chunks) { + return chunks + .join('') + .split('\n') + .filter(Boolean) + .map((line) => JSON.parse(line)); +} + +class FakeAdapter { + static instances = []; + + constructor(options) { + this.options = options; + this.closed = 0; + FakeAdapter.instances.push(this); + } + + async handle(message) { + if (message.method === 'notification') { + this.options.send({ method: 'server/notification', params: { seen: true } }); + return null; + } + return { + response: { id: message.id, result: { echoed: message.method } }, + afterResponse: async () => { + this.options.send({ method: 'after/response', params: { id: message.id } }); + } + }; + } + + async close() { + this.closed += 1; + } +} + +test('stdio transport preserves response-before-afterResponse ordering and closes on EOF', async () => { + FakeAdapter.instances.length = 0; + const input = new PassThrough(); + const output = new PassThrough(); + const errors = new PassThrough(); + const chunks = []; + output.on('data', (chunk) => chunks.push(chunk.toString('utf8'))); + + let resolveEof; + const eof = new Promise((resolve) => { resolveEof = resolve; }); + const ctx = { get: () => undefined }; + const transport = startDshxStdioTransport({ + ctx, + cwd: '/workspace', + home: '/tmp/dshx-home', + version: 'test', + input, + output, + errorOutput: errors, + Adapter: FakeAdapter, + onEof: resolveEof + }); + + input.write(`${JSON.stringify({ id: 7, method: 'initialize', params: {} })}\n`); + input.end(); + await eof; + + const messages = decodeLines(chunks); + assert.deepEqual(messages, [ + { id: 7, result: { echoed: 'initialize' } }, + { method: 'after/response', params: { id: 7 } } + ]); + assert.equal(FakeAdapter.instances.length, 1); + assert.equal(FakeAdapter.instances[0].options.ctx, ctx); + assert.equal(FakeAdapter.instances[0].closed, 1); + await transport.close(); + assert.equal(FakeAdapter.instances[0].closed, 1, 'close is idempotent'); +}); + +test('stdio transport returns JSON-RPC parse errors without contaminating stdout with diagnostics', async () => { + FakeAdapter.instances.length = 0; + const input = new PassThrough(); + const output = new PassThrough(); + const errors = new PassThrough(); + const chunks = []; + const errorChunks = []; + output.on('data', (chunk) => chunks.push(chunk.toString('utf8'))); + errors.on('data', (chunk) => errorChunks.push(chunk.toString('utf8'))); + + let resolveEof; + const eof = new Promise((resolve) => { resolveEof = resolve; }); + startDshxStdioTransport({ + ctx: { get: () => undefined }, + input, + output, + errorOutput: errors, + Adapter: FakeAdapter, + onEof: resolveEof + }); + + input.write('{not-json}\n'); + input.end(); + await eof; + + const messages = decodeLines(chunks); + assert.equal(messages.length, 1); + assert.equal(messages[0].id, null); + assert.equal(messages[0].error.code, -32700); + assert.match(messages[0].error.message, /^Parse error:/); + assert.equal(errorChunks.join(''), ''); +}); + +test('stdio transport keeps adapter notifications on stdout and diagnostics on stderr', async () => { + FakeAdapter.instances.length = 0; + const input = new PassThrough(); + const output = new PassThrough(); + const errors = new PassThrough(); + const chunks = []; + output.on('data', (chunk) => chunks.push(chunk.toString('utf8'))); + + let resolveEof; + const eof = new Promise((resolve) => { resolveEof = resolve; }); + startDshxStdioTransport({ + ctx: { get: () => undefined }, + input, + output, + errorOutput: errors, + Adapter: FakeAdapter, + diagnostics: (message) => errors.write(`[debug] ${message}\n`), + onEof: resolveEof + }); + + input.write(`${JSON.stringify({ method: 'notification', params: {} })}\n`); + input.end(); + await eof; + + assert.deepEqual(decodeLines(chunks), [ + { method: 'server/notification', params: { seen: true } } + ]); +}); From 7a571e3d881d5fca5b2e190b9ebf1d6f4e4ce2bb Mon Sep 17 00:00:00 2001 From: code-new-bie <403466121@qq.com> Date: Thu, 27 Aug 2026 11:03:29 +0800 Subject: [PATCH 24/60] refactor(plugin): make DSH stdio the only production backend Switch the pinned Codex TUI to spawn the user's official dsh profile as a local NDJSON stdio app-server. Classify that child as a local backend so Codex remote-workspace semantics never leak into DSHX. Remove the Unix-socket/WebSocket bridge, Node socket host and self-boot runtime helpers. Rework smoke and bundle verification to exercise only official dsh plugin/profile machinery, including initialize and bounded EOF/appExit shutdown. --- .github/workflows/ci.yml | 11 +- bin/dshx-stub-local.mjs | 33 +- bin/dshx.mjs | 276 +++---- scripts/build-codex-tui.ps1 | 6 - scripts/build-codex-tui.sh | 12 +- scripts/runtime-smoke.mjs | 148 ++-- scripts/verify-bundle-install.mjs | 406 ++++------ scripts/verify-tui-invariants.mjs | 59 +- src/dsh/local-server.mjs | 377 --------- src/dsh/presentation-plugin.mjs | 162 +--- src/dsh/runtime-boot.mjs | 309 -------- src/dsh/startup-plugin.mjs | 48 +- test/dsh-local-server-close.test.mjs | 119 --- test/dsh-local-server.test.mjs | 311 -------- test/dsh-runtime-boot.test.mjs | 182 ----- test/dshx-presentation-plugin.test.mjs | 115 +-- test/tui_smoke.py | 65 +- .../codex/0001-dshx-force-ui-backend.patch | 35 +- .../codex/0010-dshx-local-ipc-bridge.patch | 187 ----- .../codex/0010-dshx-stdio-backend.patch | 732 ++++++++++++++++++ .../codex/0011-dshx-ipc-self-check.patch | 100 --- 21 files changed, 1165 insertions(+), 2528 deletions(-) delete mode 100644 src/dsh/local-server.mjs delete mode 100644 src/dsh/runtime-boot.mjs delete mode 100644 test/dsh-local-server-close.test.mjs delete mode 100644 test/dsh-local-server.test.mjs delete mode 100644 test/dsh-runtime-boot.test.mjs delete mode 100644 upstream/patches/codex/0010-dshx-local-ipc-bridge.patch create mode 100644 upstream/patches/codex/0010-dshx-stdio-backend.patch delete mode 100644 upstream/patches/codex/0011-dshx-ipc-self-check.patch diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ad5119a1..520921fc 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -58,7 +58,7 @@ jobs: run: python3 -m py_compile test/tui_smoke.py linux-tui: - name: Linux TUI / pinned Codex / local IPC + name: Linux TUI / pinned Codex / DSH stdio needs: core runs-on: ubuntu-latest timeout-minutes: 60 @@ -85,19 +85,16 @@ jobs: run: npm ci - name: Verify exact DeepSeek Harness release closure run: node scripts/verify-dsh-closure.mjs - - name: Build pinned Codex TUI + local IPC bridge + - name: Build pinned Codex TUI shell: bash env: DSHX_VERSION: 1.0.0-ci run: bash scripts/build-codex-tui.sh - - name: Verify thin-fork and transport invariants + - name: Verify thin-fork and stdio transport invariants run: node scripts/verify-tui-invariants.mjs - - name: Verify local IPC data plane - shell: bash - run: dist/bin/dshx-ipc-bridge --check - name: Enable pnpm for the official plugin machinery run: corepack enable pnpm - - name: Verify bundle install end to end + - name: Verify bundle install and stdio activation end to end run: node scripts/verify-bundle-install.mjs - name: Exercise real TUI through Linux PTY + CJK + resize shell: bash diff --git a/bin/dshx-stub-local.mjs b/bin/dshx-stub-local.mjs index a43b56a2..6af6a2bb 100644 --- a/bin/dshx-stub-local.mjs +++ b/bin/dshx-stub-local.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node import fs from 'node:fs'; -import { startDshxLocalServer } from '../src/dsh/local-server.mjs'; +import { startDshxStdioTransport } from '../src/dsh/stdio-transport.mjs'; import { ProtocolStub, normalizeDispatchResult } from '../devtools/protocol-poc.mjs'; const delayMs = Number(process.env.DSHX_STUB_EVENT_DELAY_MS || 18); @@ -38,10 +38,9 @@ class LocalStubAdapter { for (const event of events) { const threadId = event?.params?.threadId ?? event?.params?.thread?.id; const turnId = event?.params?.turnId ?? event?.params?.turn?.id; - const belongsToActiveTurn = - typeof threadId === 'string' && - typeof turnId === 'string' && - event.method !== 'turn/completed'; + const belongsToActiveTurn = typeof threadId === 'string' + && typeof turnId === 'string' + && event.method !== 'turn/completed'; if (belongsToActiveTurn && !this.stub.isTurnActive(threadId, turnId)) { trace({ direction: 'drop', method: event.method, threadId, turnId, reason: 'inactive-before-delay' }); break; @@ -53,11 +52,7 @@ class LocalStubAdapter { } this.send(event); trace({ direction: 'out', kind: 'notification', method: event.method, threadId: threadId ?? null, turnId: turnId ?? null }); - if ( - event.method === 'turn/completed' && - typeof threadId === 'string' && - typeof turnId === 'string' - ) { + if (event.method === 'turn/completed' && typeof threadId === 'string' && typeof turnId === 'string') { this.stub.completeTurn(threadId, turnId); } } @@ -68,20 +63,8 @@ class LocalStubAdapter { async close() {} } -const server = await startDshxLocalServer({ - runtime: { async dispose() {} }, +startDshxStdioTransport({ + ctx: { get: () => undefined }, Adapter: LocalStubAdapter, - log: (message) => process.stderr.write(`[dshx-local-stub] ${message}\n`) + diagnostics: (message) => process.stderr.write(`[dshx-stdio-stub] ${message}\n`) }); -process.stdout.write(`${server.url}\n`); - -async function shutdown() { - try { - await server.close(); - } finally { - process.exit(0); - } -} - -process.on('SIGINT', shutdown); -process.on('SIGTERM', shutdown); diff --git a/bin/dshx.mjs b/bin/dshx.mjs index 981c4c2b..88f4fae8 100755 --- a/bin/dshx.mjs +++ b/bin/dshx.mjs @@ -1,23 +1,17 @@ #!/usr/bin/env node -// DSHX launcher — a thin, version-agnostic bootstrap over the official DSH -// machinery. This file deliberately imports NO DeepSeek Harness code: the -// composition is booted by the user's own `dsh` installation, our bundle rows -// are loaded by that installation's loader, and the pinned Codex TUI is -// attached from inside the surface row. Zero harness builds ship or load from -// this launcher, which is what keeps the plugin host-version agnostic. +// DSHX launcher: presentation-only bootstrap over the user's own official DSH +// installation. The pinned Codex TUI owns the terminal; it spawns DSH as a +// local stdio app-server child through DSHX_APP_SERVER_CMD. import fs from 'node:fs'; import os from 'node:os'; import path from 'node:path'; import process from 'node:process'; import { spawn, spawnSync } from 'node:child_process'; +import { createInterface } from 'node:readline'; import { fileURLToPath } from 'node:url'; import { parseCliInvocation } from '../src/cli/arguments.mjs'; import { isSupportedNodeVersion } from '../src/cli/runtime.mjs'; -import { - ensureProfileInstalled, - profileManifestPath, - resolveDshInvocation -} from '../src/dsh/profile-bootstrap.mjs'; +import { ensureProfileInstalled, resolveDshInvocation } from '../src/dsh/profile-bootstrap.mjs'; const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..'); const PACKAGE = JSON.parse(fs.readFileSync(path.join(ROOT, 'package.json'), 'utf8')); @@ -25,7 +19,7 @@ const VERSION = PACKAGE.version; const DEFAULT_PROFILE = 'tui'; function usage() { - return `DSHX ${VERSION}\n\nUsage:\n dshx Start DSHX in the current project\n dshx Start with an initial prompt\n dshx resume Open the Codex-style DSH session picker\n dshx resume --last Resume the most recent DSH session\n dshx resume Resume a specific DSH session\n dshx doctor Check packaged TUI, local IPC and official DSH composition\n dshx --version Print version\n dshx --help Show this help\n\nEnvironment:\n DSHX_TUI_BIN Override the packaged DSHX TUI binary (development only)\n DSHX_IPC_BRIDGE_BIN Override the packaged local IPC bridge (development only)\n DSHX_TUI_HOME Override DSHX presentation-only Codex home (development only)\n DSHX_PROFILE Override the DSH profile surface (default: ${DEFAULT_PROFILE})\n DSHX_DEBUG=1 Print DSHX adapter diagnostics\n\nPlugin usage:\n The DSHX surface ships as a standard DSH profile bundle. Manage it through\n the official machinery, e.g.:\n dsh plugin --profile ${DEFAULT_PROFILE} add ${PACKAGE.name}\n\nCompatibility:\n Runs against whatever DeepSeek Harness installation hosts the profile; the\n tested line is announced at startup when they differ. No harness builds are\n loaded from this launcher.\n\nProduct boundary:\n DSHX owns only the launcher, Codex TUI thin fork and presentation adapter.\n DeepSeek Harness remains the authoritative Agent/Session/Tool runtime.\n DSHX never reads or writes the user's ordinary CODEX_HOME.\n`; + return `DSHX ${VERSION}\n\nUsage:\n dshx Start DSHX in the current project\n dshx Start with an initial prompt\n dshx resume Open the DSH session picker\n dshx resume --last Resume the most recent DSH session\n dshx resume Resume a specific DSH session\n dshx doctor Check the TUI and official DSH stdio composition\n dshx --version Print version\n dshx --help Show this help\n\nEnvironment:\n DSHX_TUI_BIN Override the packaged DSHX TUI binary (development only)\n DSHX_TUI_HOME Override DSHX presentation-only Codex home\n DSHX_DSH_BIN Override the official dsh JavaScript entrypoint\n DSHX_PROFILE Override the DSH profile (default: ${DEFAULT_PROFILE})\n DSHX_DEBUG=1 Print DSHX adapter diagnostics\n\nPlugin usage:\n The surface is a standard DSH profile bundle managed by the official CLI:\n dsh plugin --profile ${DEFAULT_PROFILE} add ${PACKAGE.name}\n\nProduct boundary:\n DSHX owns the launcher, a thin Codex TUI fork and a presentation adapter.\n DeepSeek Harness remains authoritative for Agent/Session/Tool/Approval state.\n No Harness runtime is bundled or booted by DSHX itself.\n`; } function commandDetail(command, result) { @@ -34,10 +28,14 @@ function commandDetail(command, result) { return `${command} is not runnable${result.stderr ? `: ${result.stderr.trim()}` : ''}`; } -function binaryCandidate(baseName) { - const fileName = process.platform === 'win32' ? `${baseName}.exe` : baseName; - return process.env[baseName === 'dshx-tui' ? 'DSHX_TUI_BIN' : 'DSHX_IPC_BRIDGE_BIN'] - || path.join(ROOT, 'dist', 'bin', fileName); +function tuiBinary() { + if (process.env.DSHX_TUI_BIN) return process.env.DSHX_TUI_BIN; + const name = process.platform === 'win32' ? 'dshx-tui.exe' : 'dshx-tui'; + return path.join(ROOT, 'dist', 'bin', name); +} + +function tuiHome() { + return path.resolve(process.env.DSHX_TUI_HOME || path.join(os.homedir(), '.dshx', 'codex-tui')); } function selectedProfile() { @@ -46,229 +44,140 @@ function selectedProfile() { return value.trim(); } -/** Bootstrap the surface profile through the official plugin machinery. */ export function bootstrapSurfaceProfile() { - const profile = selectedProfile(); - const manifestPath = profileManifestPath(profile); - let satisfied = false; - try { - const manifest = JSON.parse(fs.readFileSync(manifestPath, 'utf8')); - satisfied = - manifest.dependencies?.[PACKAGE.name] === VERSION && - manifest.dsh?.profile?.bundles?.includes(PACKAGE.name); - } catch { - // Missing or unreadable manifest: the official command initializes it. - } - if (satisfied) return { profile, action: 'already-installed' }; - if (process.env.DSHX_SKIP_PROFILE_BOOTSTRAP === '1') { - return { profile, action: 'skipped' }; - } - - const dsh = resolveDshInvocation(ROOT); - const result = spawnSync( - dsh.command, - [...dsh.args, 'plugin', '--profile', profile, 'add', ROOT], - { stdio: 'inherit', shell: process.platform === 'win32' } - ); - if (result.error?.code === 'ENOENT') { - throw new Error( - "official 'dsh' CLI not found (looked up DSHX_DSH_BIN, the @deepseek-ai/dsh dependency and PATH)" - ); - } - if (result.status !== 0) { - throw new Error(`failed to install ${PACKAGE.name} into profile '${profile}' via dsh plugin add (exit ${result.status ?? '?'})`); - } - return { profile, action: 'installed' }; -} - -async function loadLocalServerInternals() { - try { - const { localServerInternals } = await import('../src/dsh/local-server.mjs'); - return localServerInternals; - } catch { - return undefined; - } + return ensureProfileInstalled({ + packageRoot: ROOT, + name: PACKAGE.name, + version: VERSION, + profile: selectedProfile() + }); } -function presentationHomeCheck(localServerInternals) { - const home = path.resolve(process.env.DSHX_TUI_HOME || path.join(os.homedir(), '.dshx', 'codex-tui')); +function presentationHomeCheck() { + const home = tuiHome(); try { fs.mkdirSync(home, { recursive: true, mode: 0o700 }); - const stat = fs.statSync(home); - if (!stat.isDirectory()) throw new Error('path exists but is not a directory'); + if (!fs.statSync(home).isDirectory()) throw new Error('path exists but is not a directory'); fs.accessSync(home, fs.constants.R_OK | fs.constants.W_OK); - if (!localServerInternals) { - throw new Error('IPC policy unavailable because DSH modules failed to load'); - } - - // On Windows this also enforces that a custom DSHX_TUI_HOME stays below - // the current user's profile ACL boundary. Probe the fixed suffix used by - // the real random rendezvous directory so an obviously-too-long home - // fails in doctor before a launch is attempted. - const socketRoot = localServerInternals.defaultSocketRoot({ home }); - const probeSocket = path.join(socketRoot, 'd-XXXXXX', 's'); - localServerInternals.assertSocketPathSupported(probeSocket); return { ok: true, detail: home }; } catch (error) { return { ok: false, detail: `${home}: ${error instanceof Error ? error.message : String(error)}` }; } } -/** - * Probe the user's real installation end to end: launch the official CLI for - * the surface profile in headless-passive mode and wait until the loader has - * activated the surface rows (visible via the listening hint), proving the - * whole plugin chain works against THIS machine's actual DSH build. - */ -function surfaceActivationProbe(dsh, profile, timeoutMs = 90_000) { +/** Probe the real installed profile through the same stdio protocol used by the TUI. */ +function backendActivationProbe(dsh, profile, timeoutMs = 90_000) { return new Promise((resolve) => { - const child = spawn( - dsh.command, - [...dsh.args, '--profile', profile], - { - cwd: process.cwd(), - env: { ...process.env, DSHX_ATTACH: '1', DSHX_HEADLESS: '1' }, - stdio: ['ignore', 'pipe', 'pipe'] - } - ); - let collected = ''; + const child = spawn(dsh.command, [...dsh.args, '--profile', profile, '--dshx-app-server'], { + cwd: process.cwd(), + env: process.env, + stdio: ['pipe', 'pipe', 'pipe'], + windowsHide: true + }); + const lines = createInterface({ input: child.stdout, crlfDelay: Infinity, terminal: false }); + let stderr = ''; let settled = false; const finish = (ok, detail) => { if (settled) return; settled = true; clearTimeout(timer); - try { child.kill('SIGTERM'); } catch { /* already exiting */ } + lines.close(); + try { child.stdin.end(); } catch {} + try { child.kill('SIGTERM'); } catch {} resolve({ ok, detail }); }; - const timer = setTimeout(() => finish(false, `no activation within ${timeoutMs}ms`), timeoutMs); - const onData = (chunk) => { - collected += chunk.toString('utf8'); - if (collected.includes('surface listening at')) finish(true, 'surface rows active on your installation'); - if (/credentials-local|does not exist|Cannot find package/.test(collected)) { - finish(false, collected.trim().split('\n').slice(-3).join(' | ')); + const timer = setTimeout(() => finish(false, `no stdio activation within ${timeoutMs}ms`), timeoutMs); + child.stderr.on('data', (chunk) => { stderr = `${stderr}${chunk.toString('utf8')}`.slice(-8192); }); + lines.on('line', (line) => { + let message; + try { message = JSON.parse(line); } catch { return; } + if (message?.id === 'dshx-doctor' && message?.result) { + finish(true, `stdio surface active (${message.result.userAgent ?? 'DSH'})`); + } else if (message?.id === 'dshx-doctor' && message?.error) { + finish(false, message.error.message || 'initialize rejected'); } - }; - child.stdout.on('data', onData); - child.stderr.on('data', onData); + }); child.on('error', (error) => finish(false, error.message)); - child.on('exit', (code) => finish(false, `official CLI exited early (code ${code ?? '?'})`)); + child.on('exit', (code) => { + if (!settled) finish(false, `official CLI exited before initialize (code ${code ?? '?'})${stderr.trim() ? `: ${stderr.trim().split('\n').slice(-3).join(' | ')}` : ''}`); + }); + child.stdin.write(`${JSON.stringify({ + id: 'dshx-doctor', + method: 'initialize', + params: { clientInfo: { name: 'dshx-doctor', version: VERSION } } + })}\n`); }); } async function doctor() { - const executable = binaryCandidate('dshx-tui'); + const executable = tuiBinary(); const tuiCheck = fs.existsSync(executable) ? spawnSync(executable, ['--version'], { encoding: 'utf8' }) : { status: 127, stdout: '', stderr: '', error: null }; - const bridge = binaryCandidate('dshx-ipc-bridge'); - const bridgeCheck = fs.existsSync(bridge) - ? spawnSync(bridge, ['--check'], { encoding: 'utf8' }) - : { status: 127, stdout: '', stderr: '', error: null }; - - const localServerInternals = await loadLocalServerInternals(); - const homeCheck = presentationHomeCheck(localServerInternals); + const homeCheck = presentationHomeCheck(); let profileDetail = ''; let profileOk = true; let dsh; + let profile; try { const ensured = bootstrapSurfaceProfile(); - profileDetail = `profile '${ensured.profile}' (${ensured.action})`; + profile = ensured.profile; + profileDetail = `profile '${profile}' (${ensured.action})`; dsh = resolveDshInvocation(ROOT); } catch (error) { profileOk = false; profileDetail = error instanceof Error ? error.message : String(error); } - // The strongest compatibility evidence possible: activate the surface rows - // against the user's ACTUAL installed build (headless-passive probe). - let harnessDetail = ''; - let harnessOk = false; - if (profileOk && bridgeCheck.status === 0) { - const probe = surfaceActivationProbe(dsh, selectedProfile()); - harnessDetail = probe.detail; - harnessOk = probe.ok; - } else { - harnessDetail = 'skipped: surface profile unavailable'; - } + let harness = { ok: false, detail: 'skipped: surface profile unavailable' }; + if (profileOk) harness = await backendActivationProbe(dsh, profile); const rows = [ ['Node', `${process.version} (required: ${PACKAGE.engines.node})`, isSupportedNodeVersion(process.versions.node)], - [ - 'Pinned Codex TUI', - tuiCheck.status === 0 ? commandDetail(executable, tuiCheck) : (executable ? commandDetail(executable, tuiCheck) : 'not found'), - tuiCheck.status === 0 - ], - [ - 'Local IPC bridge', - bridgeCheck.status === 0 ? `${bridge} (cross-platform Codex UDS)` : (bridge ? commandDetail(bridge, bridgeCheck) : 'not found'), - bridgeCheck.status === 0 - ], + ['Pinned Codex TUI', tuiCheck.status === 0 ? commandDetail(executable, tuiCheck) : commandDetail(executable, tuiCheck), tuiCheck.status === 0], ['Surface profile', profileDetail, profileOk], - ['DeepSeek Harness (your installation)', harnessDetail, harnessOk], - ['Presentation home / IPC path', homeCheck.detail, homeCheck.ok] + ['DeepSeek Harness stdio surface', harness.detail, harness.ok], + ['Presentation home', homeCheck.detail, homeCheck.ok] ]; - for (const [name, detail, ok] of rows) { - process.stdout.write(`${ok ? '✓' : '✗'} ${name}: ${detail}\n`); - } + for (const [name, detail, ok] of rows) process.stdout.write(`${ok ? '✓' : '✗'} ${name}: ${detail}\n`); if (rows.some((row) => !row[2])) { process.stderr.write( process.platform === 'win32' - ? 'For a source checkout, build the pinned TUI + IPC bridge with `.\\scripts\\build-codex-tui.ps1`; packaged releases include both.\n' - : 'For a source checkout, build the pinned TUI + IPC bridge with `./scripts/build-codex-tui.sh`; packaged releases include both.\n' + ? 'For a source checkout, build the pinned TUI with `.\\scripts\\build-codex-tui.ps1`.\n' + : 'For a source checkout, build the pinned TUI with `./scripts/build-codex-tui.sh`.\n' ); process.exitCode = 1; } } async function run() { - const args = process.argv.slice(2); let invocation; - try { - invocation = parseCliInvocation(args); + invocation = parseCliInvocation(process.argv.slice(2)); } catch (error) { process.stderr.write(`dshx: ${error.message}\n`); process.exitCode = 2; return; } - if (invocation.kind === 'help') { - process.stdout.write(usage()); - return; - } - if (invocation.kind === 'version') { - process.stdout.write(`${VERSION}\n`); - return; - } - if (invocation.kind === 'doctor') { - await doctor(); - return; - } + if (invocation.kind === 'help') return void process.stdout.write(usage()); + if (invocation.kind === 'version') return void process.stdout.write(`${VERSION}\n`); + if (invocation.kind === 'doctor') return void await doctor(); if (!isSupportedNodeVersion(process.versions.node)) { - process.stderr.write(`dshx: unsupported Node ${process.version}; pinned DeepSeek Harness requires ${PACKAGE.engines.node}\n`); - process.stderr.write('Use Node 24 LTS for the DSHX 1.0 release baseline.\n'); + process.stderr.write(`dshx: unsupported Node ${process.version}; required ${PACKAGE.engines.node}\n`); process.exitCode = 1; return; } - const executable = binaryCandidate('dshx-tui'); + const executable = tuiBinary(); if (!fs.existsSync(executable)) { - process.stderr.write(`dshx: packaged TUI binary not found (${executable})\n`); - process.stderr.write('Run `dshx doctor` for build/install guidance.\n'); - process.exitCode = 127; - return; - } - const bridge = binaryCandidate('dshx-ipc-bridge'); - if (!fs.existsSync(bridge)) { - process.stderr.write(`dshx: packaged local IPC bridge not found (${bridge})\n`); - process.stderr.write('Run `dshx doctor` for build/install guidance.\n'); + process.stderr.write(`dshx: packaged TUI binary not found (${executable}); run \`dshx doctor\`\n`); process.exitCode = 127; return; } - const debug = process.env.DSHX_DEBUG === '1'; let profile; try { profile = bootstrapSurfaceProfile().profile; @@ -278,34 +187,25 @@ async function run() { return; } - // Hand over to the user's own official DSH installation. The loader mounts - // our surface rows; the presentation row attaches the pinned TUI because - // DSHX_ATTACH marks this launching context as interactive. - const tuiHome = path.resolve(process.env.DSHX_TUI_HOME || path.join(os.homedir(), '.dshx', 'codex-tui')); const dsh = resolveDshInvocation(ROOT); - const child = spawn( - dsh.command, - [...dsh.args, '--profile', profile], - { - cwd: process.cwd(), - env: { - ...process.env, - CODEX_HOME: tuiHome, - ...(invocation.resumeEnv ?? {}), - DSHX_ATTACH: '1', - DSHX_TUI_ARGS: JSON.stringify(invocation.tuiArgs ?? []) - }, - stdio: 'inherit', - windowsHide: false - } - ); - + const backendCommand = [dsh.command, ...dsh.args, '--profile', profile, '--dshx-app-server']; + const child = spawn(executable, invocation.tuiArgs ?? [], { + cwd: process.cwd(), + env: { + ...process.env, + CODEX_HOME: tuiHome(), + DSHX_APP_SERVER_CMD: JSON.stringify(backendCommand), + ...(invocation.resumeEnv ?? {}) + }, + stdio: 'inherit', + windowsHide: false + }); child.on('error', (error) => { - process.stderr.write(`dshx: failed to start official DSH CLI: ${error.message}\n`); + process.stderr.write(`dshx: failed to start pinned TUI: ${error.message}\n`); process.exitCode = 127; }); child.on('exit', (code, signal) => { - if (signal && debug) process.stderr.write(`[dshx] official DSH exited via ${signal}\n`); + if (signal && process.env.DSHX_DEBUG === '1') process.stderr.write(`[dshx] TUI exited via ${signal}\n`); process.exitCode = code ?? (signal ? 1 : 0); }); } diff --git a/scripts/build-codex-tui.ps1 b/scripts/build-codex-tui.ps1 index 68fe6f8a..ded28c69 100644 --- a/scripts/build-codex-tui.ps1 +++ b/scripts/build-codex-tui.ps1 @@ -10,15 +10,9 @@ $OutDir = if ($env:DSHX_TUI_OUT_DIR) { $env:DSHX_TUI_OUT_DIR } else { Join-Path New-Item -ItemType Directory -Force $OutDir | Out-Null $env:CARGO_TARGET_DIR = $TargetDir -# Ship without debug info: smaller artifacts, identical behavior. if (-not $env:CARGO_PROFILE_RELEASE_DEBUG) { $env:CARGO_PROFILE_RELEASE_DEBUG = '0' } cargo build --manifest-path (Join-Path $CodeXDir 'codex-rs\Cargo.toml') --locked --release -p codex-tui --bin codex-tui -cargo build --manifest-path (Join-Path $CodeXDir 'codex-rs\Cargo.toml') --locked --release -p codex-stdio-to-uds --bin dshx-ipc-bridge $TuiSource = Join-Path $TargetDir 'release\codex-tui.exe' $TuiDestination = Join-Path $OutDir 'dshx-tui.exe' -$BridgeSource = Join-Path $TargetDir 'release\dshx-ipc-bridge.exe' -$BridgeDestination = Join-Path $OutDir 'dshx-ipc-bridge.exe' Copy-Item -Force $TuiSource $TuiDestination -Copy-Item -Force $BridgeSource $BridgeDestination Write-Host $TuiDestination -Write-Host $BridgeDestination diff --git a/scripts/build-codex-tui.sh b/scripts/build-codex-tui.sh index d9857cb1..ad47062f 100755 --- a/scripts/build-codex-tui.sh +++ b/scripts/build-codex-tui.sh @@ -9,20 +9,14 @@ TARGET_DIR="${CARGO_TARGET_DIR:-$ROOT/.build/codex}" OUT_DIR="${DSHX_TUI_OUT_DIR:-$ROOT/dist/bin}" mkdir -p "$OUT_DIR" -# Ship without debug info: ~4x smaller artifacts, identical behavior. The -# override stays user-controlled for anyone who needs a debuggable build. export CARGO_PROFILE_RELEASE_DEBUG="${CARGO_PROFILE_RELEASE_DEBUG:-0}" CARGO_TARGET_DIR="$TARGET_DIR" cargo build \ --manifest-path "$CODEX_DIR/codex-rs/Cargo.toml" \ --locked --release -p codex-tui --bin codex-tui -CARGO_TARGET_DIR="$TARGET_DIR" cargo build \ - --manifest-path "$CODEX_DIR/codex-rs/Cargo.toml" \ - --locked --release -p codex-stdio-to-uds --bin dshx-ipc-bridge cp "$TARGET_DIR/release/codex-tui" "$OUT_DIR/dshx-tui" -cp "$TARGET_DIR/release/dshx-ipc-bridge" "$OUT_DIR/dshx-ipc-bridge" if command -v strip >/dev/null 2>&1; then - strip "$OUT_DIR/dshx-tui" "$OUT_DIR/dshx-ipc-bridge" + strip "$OUT_DIR/dshx-tui" fi -chmod +x "$OUT_DIR/dshx-tui" "$OUT_DIR/dshx-ipc-bridge" -printf '%s\n' "$OUT_DIR/dshx-tui" "$OUT_DIR/dshx-ipc-bridge" +chmod +x "$OUT_DIR/dshx-tui" +printf '%s\n' "$OUT_DIR/dshx-tui" diff --git a/scripts/runtime-smoke.mjs b/scripts/runtime-smoke.mjs index 3b7183ad..05c3cdd0 100644 --- a/scripts/runtime-smoke.mjs +++ b/scripts/runtime-smoke.mjs @@ -2,90 +2,76 @@ import fs from 'node:fs'; import path from 'node:path'; import process from 'node:process'; +import { spawn } from 'node:child_process'; +import { createInterface } from 'node:readline'; import { fileURLToPath } from 'node:url'; -import { bootDshxRuntime } from '../src/dsh/runtime-boot.mjs'; -import { ensureProfileInstalled } from '../src/dsh/profile-bootstrap.mjs'; +import { ensureProfileInstalled, resolveDshInvocation } from '../src/dsh/profile-bootstrap.mjs'; -const PACKAGE_ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..'); -const PACKAGE = JSON.parse(fs.readFileSync(path.join(PACKAGE_ROOT, 'package.json'), 'utf8')); +const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..'); +const PACKAGE = JSON.parse(fs.readFileSync(path.join(ROOT, 'package.json'), 'utf8')); +const TIMEOUT_MS = Number(process.env.DSHX_SMOKE_BOOT_TIMEOUT_MS ?? 90_000); -const REQUIRED_SERVICES = [ - 'agents', - 'agentDefaultModel', - 'llm', - 'sessions', - 'sessionPersistence', - 'sessionQuery', - 'sessionProjections', - 'sessionTitle', - 'attachments', - 'tools', - 'commands', - 'compaction', - 'subagents', - 'permissionPresets', - 'approval', - 'userQuestions', - 'skills', - 'planMode' -]; +const ensured = ensureProfileInstalled({ + packageRoot: ROOT, + name: PACKAGE.name, + version: PACKAGE.version, + profile: process.env.DSHX_PROFILE || 'tui' +}); +process.stdout.write(`surface profile '${ensured.profile}' ${ensured.action}\n`); -// CI-grade disks boot well inside these defaults; slow checkouts (for example -// a WSL /mnt/c mount) can raise them without touching the script. -const BOOT_TIMEOUT_MS = Number(process.env.DSHX_SMOKE_BOOT_TIMEOUT_MS ?? 20_000); -const DISPOSE_TIMEOUT_MS = Number(process.env.DSHX_SMOKE_DISPOSE_TIMEOUT_MS ?? 10_000); - -function withTimeout(promise, timeoutMs, label) { - let timer; - return Promise.race([ - promise, - new Promise((_, reject) => { - timer = setTimeout(() => reject(new Error(`${label} exceeded ${timeoutMs}ms`)), timeoutMs); - }) - ]).finally(() => clearTimeout(timer)); -} - -let ctx; -let primaryError; -try { - // The smoke targets the production surface profile; make sure the official - // plugin machinery has it installed before composing. - const ensured = ensureProfileInstalled({ - packageRoot: PACKAGE_ROOT, - name: PACKAGE.name, - version: PACKAGE.version +const dsh = resolveDshInvocation(ROOT); +await new Promise((resolve, reject) => { + const child = spawn(dsh.command, [...dsh.args, '--profile', ensured.profile, '--dshx-app-server'], { + cwd: process.cwd(), + env: process.env, + stdio: ['pipe', 'pipe', 'pipe'], + windowsHide: true }); - process.stdout.write(`surface profile '${ensured.profile}' ${ensured.action}\n`); - process.stdout.write('booting official DSH composition with production patch watchers enabled\n'); - ctx = await withTimeout( - bootDshxRuntime({ cwd: process.cwd(), watch: true }), - BOOT_TIMEOUT_MS, - 'official DSH composition boot' - ); - process.stdout.write('official DSH composition boot completed\n'); - - const missing = REQUIRED_SERVICES.filter((name) => ctx.get(name) == null); - if (missing.length > 0) { - throw new Error(`official DSH composition is missing required presentation services: ${missing.join(', ')}`); - } - // Workspace command probes are Agent-scoped and use the official `tools` - // service. `workspaceRegistry` was an older composition detail and is not a - // DSHX product dependency. Command discovery is likewise Agent-scoped in - // DSH rc.8, so do not invent a fake Agent merely to inspect /compact here. - process.stdout.write(`official DSH runtime booted: ${REQUIRED_SERVICES.join(', ')}\n`); -} catch (error) { - primaryError = error; -} finally { - if (ctx) { - process.stdout.write('disposing official DSH composition\n'); - try { - await withTimeout(Promise.resolve(ctx.dispose?.()), DISPOSE_TIMEOUT_MS, 'official DSH composition disposal'); - process.stdout.write('official DSH composition disposed\n'); - } catch (disposeError) { - if (!primaryError) primaryError = disposeError; - else process.stderr.write(`secondary DSH disposal failure: ${disposeError instanceof Error ? disposeError.stack : disposeError}\n`); + const lines = createInterface({ input: child.stdout, crlfDelay: Infinity, terminal: false }); + let initialized = false; + let stderr = ''; + let settled = false; + const finish = (error) => { + if (settled) return; + settled = true; + clearTimeout(timer); + lines.close(); + if (error) { + try { child.kill('SIGTERM'); } catch {} + reject(error); + } else { + resolve(); } - } -} - -if (primaryError) throw primaryError; + }; + const timer = setTimeout(() => finish(new Error(`official DSH stdio smoke exceeded ${TIMEOUT_MS}ms${stderr ? `:\n${stderr}` : ''}`)), TIMEOUT_MS); + child.stderr.on('data', (chunk) => { stderr = `${stderr}${chunk.toString('utf8')}`.slice(-16384); }); + child.on('error', finish); + lines.on('line', (line) => { + let message; + try { message = JSON.parse(line); } catch { return; } + if (message?.id !== 'runtime-smoke') return; + if (message.error) { + finish(new Error(`initialize rejected: ${message.error.message || JSON.stringify(message.error)}`)); + return; + } + initialized = true; + process.stdout.write(`official DSH composition mounted: ${message.result?.userAgent ?? 'dshx'}\n`); + child.stdin.write(`${JSON.stringify({ method: 'initialized', params: {} })}\n`); + child.stdin.end(); + }); + child.on('exit', (code, signal) => { + if (!initialized) { + finish(new Error(`official DSH exited before initialize (${signal ?? code ?? 'unknown'})${stderr ? `:\n${stderr}` : ''}`)); + } else if (code !== 0) { + finish(new Error(`official DSH EOF disposal failed (code ${code ?? '?'} signal ${signal ?? '-'})${stderr ? `:\n${stderr}` : ''}`)); + } else { + process.stdout.write('official DSH composition disposed through appExit\n'); + finish(); + } + }); + child.stdin.write(`${JSON.stringify({ + id: 'runtime-smoke', + method: 'initialize', + params: { clientInfo: { name: 'dshx-runtime-smoke', version: PACKAGE.version } } + })}\n`); +}); diff --git a/scripts/verify-bundle-install.mjs b/scripts/verify-bundle-install.mjs index bb67627a..809afa33 100644 --- a/scripts/verify-bundle-install.mjs +++ b/scripts/verify-bundle-install.mjs @@ -1,21 +1,14 @@ #!/usr/bin/env node /** - * End-to-end proof that DSHX installs and activates as a real DSH profile - * bundle, using only official machinery: - * - * 1. npm pack -> platform-agnostic bundle tarball - * 2. dsh plugin add -> profile init + pnpm install + bundles reconcile - * 3. dsh --dump-config -> composed tree contains the surface rows - * 4. bootDshxRuntime -> loader activates the rows; services publish - * 5. single-instance -> profile copy never shadows healed symlinks - * - * Everything runs inside one temporary DSH_HOME; no global state is touched. + * End-to-end DSH bundle compliance proof using only official host machinery: + * npm pack -> dsh plugin add -> dsh --dump-config -> stdio initialize/EOF. */ import fs from 'node:fs'; import os from 'node:os'; import path from 'node:path'; import process from 'node:process'; -import { spawnSync } from 'node:child_process'; +import { spawn, spawnSync } from 'node:child_process'; +import { createInterface } from 'node:readline'; import { fileURLToPath } from 'node:url'; import { resolveDshInvocation } from '../src/dsh/profile-bootstrap.mjs'; @@ -24,268 +17,185 @@ const PACKAGE = JSON.parse(fs.readFileSync(path.join(ROOT, 'package.json'), 'utf const NAME = PACKAGE.name; const PROFILE = 'tui'; -const work = fs.mkdtempSync(path.join(os.tmpdir(), 'dshx-bundle-e2e-')); -const home = path.join(work, 'home'); -const packDir = path.join(work, 'pack'); -fs.mkdirSync(home, { recursive: true }); -fs.mkdirSync(packDir, { recursive: true }); - -// Keep every toolchain cache inside the temp area so repeated runs stay hermetic. -const isolatedEnv = { - ...process.env, - DSH_HOME: home, - npm_config_cache: path.join(work, 'npm-cache'), - XDG_CACHE_HOME: path.join(work, 'cache'), - XDG_DATA_HOME: path.join(work, 'data'), - XDG_STATE_HOME: path.join(work, 'state') -}; - -function run(label, command, args, options = {}) { - const result = spawnSync(command, args, { - cwd: options.cwd ?? ROOT, - env: isolatedEnv, - encoding: 'utf8', - ...(options.spawn ?? {}) - }); - if (result.status === 0 || !options.check) return result; - throw new Error(`${label} failed (exit ${result.status}):\n${result.stderr || result.stdout}`); -} - function fail(message) { console.error(`\n[verify-bundle] FAIL: ${message}`); process.exitCode = 1; } -/** - * Release-flavor proof: the published per-platform tarball must be a - * self-contained standard bundle — official install into a fresh profile, - * then loader activation with ZERO environment overrides, binaries resolving - * from the installed copy itself. - */ -async function verifyReleaseFlavor(tarball) { - const work = fs.mkdtempSync(path.join(os.tmpdir(), 'dshx-release-e2e-')); - const home = path.join(work, 'home'); - fs.mkdirSync(home, { recursive: true }); - const envR = { ...process.env, DSH_HOME: home }; - // Simulate a clean user environment: no dev overrides may leak in. - for (const key of ['DSHX_IPC_BRIDGE_BIN', 'DSHX_TUI_BIN', 'DSHX_TUI_ARGS', 'DSHX_ATTACH', 'DSHX_HEADLESS', 'DSH_TELEMETRY_DISABLED']) { - delete envR[key]; +function run(command, args, { cwd = ROOT, env = process.env, check = true } = {}) { + const result = spawnSync(command, args, { cwd, env, encoding: 'utf8' }); + if (check && result.status !== 0) { + throw new Error(`${command} ${args.join(' ')} failed (exit ${result.status}):\n${result.stderr || result.stdout}`); } - envR.npm_config_cache = path.join(work, 'npm-cache'); - try { - const dsh = resolveDshInvocation(ROOT, envR); - const add = spawnSync(dsh.command, [...dsh.args, 'plugin', '--profile', PROFILE, 'add', tarball], { - cwd: work, env: envR, encoding: 'utf8' + return result; +} + +async function probeStdioSurface({ dsh, cwd, env, profile = PROFILE, timeoutMs = 90_000 }) { + return await new Promise((resolve, reject) => { + const child = spawn(dsh.command, [...dsh.args, '--profile', profile, '--dshx-app-server'], { + cwd, + env, + stdio: ['pipe', 'pipe', 'pipe'], + windowsHide: true }); - if (add.status !== 0) throw new Error(`official add failed:\n${add.stderr || add.stdout}`); - const manifest = JSON.parse(fs.readFileSync(path.join(home, 'profiles', PROFILE, 'package.json'), 'utf8')); - if (!manifest.dsh?.profile?.bundles?.includes(NAME)) throw new Error('reconcile missed the bundle layer'); + const lines = createInterface({ input: child.stdout, crlfDelay: Infinity, terminal: false }); + let stderr = ''; + let initialized; + let settled = false; + const finish = (error, result) => { + if (settled) return; + settled = true; + clearTimeout(timer); + lines.close(); + if (error) { + try { child.kill('SIGTERM'); } catch {} + reject(error); + } else { + resolve(result); + } + }; + const timer = setTimeout(() => { + finish(new Error(`stdio surface timed out after ${timeoutMs}ms${stderr ? `:\n${stderr}` : ''}`)); + }, timeoutMs); + child.stderr.on('data', (chunk) => { stderr = `${stderr}${chunk.toString('utf8')}`.slice(-16384); }); + child.on('error', (error) => finish(error)); + lines.on('line', (line) => { + let message; + try { message = JSON.parse(line); } catch { return; } + if (message?.id !== 'verify-bundle') return; + if (message.error) { + finish(new Error(`stdio initialize rejected: ${message.error.message || JSON.stringify(message.error)}`)); + return; + } + initialized = message.result; + child.stdin.write(`${JSON.stringify({ method: 'initialized', params: {} })}\n`); + child.stdin.end(); + }); + child.on('exit', (code, signal) => { + if (!initialized) { + finish(new Error(`stdio surface exited before initialize (${signal ?? code ?? 'unknown'})${stderr ? `:\n${stderr}` : ''}`)); + return; + } + if (code !== 0) { + finish(new Error(`stdio surface did not honor bounded EOF exit (code ${code ?? '?'} signal ${signal ?? '-'})${stderr ? `:\n${stderr}` : ''}`)); + return; + } + finish(null, initialized); + }); + child.stdin.write(`${JSON.stringify({ + id: 'verify-bundle', + method: 'initialize', + params: { clientInfo: { name: 'dshx-bundle-verifier', version: PACKAGE.version } } + })}\n`); + }); +} - // Probe must be a real file: the hmr row resolves process.argv[1]. - const probe = path.join(work, 'probe.mjs'); - fs.writeFileSync(probe, ` - import path from 'node:path'; - const { bootDshxRuntime } = await import(${JSON.stringify(path.join(ROOT, 'src', 'dsh', 'runtime-boot.mjs'))}); - const ctx = await bootDshxRuntime({ cwd: '/tmp', watch: false }); - try { - const s = ctx.get('dshxStartup'), p = ctx.get('dshxPresentation'), fs = await import('node:fs'); - const leafLibs = new Set(Object.keys(${JSON.stringify(PACKAGE.dependencies ?? {})})); - const pm = ${JSON.stringify(path.join(home, 'profiles', PROFILE, 'node_modules', '@deepseek-ai'))}; - const shadowed = fs.existsSync(pm) - ? fs.readdirSync(pm).filter((e) => /^dsh(-|$)/.test(e) && !leafLibs.has('@deepseek-ai/' + e)) - : []; - console.log(JSON.stringify({ - url: p?.url ?? null, - bridgeCommand: s?.bridgeCommand ?? null, - bridgeFromInstalledCopy: typeof s?.bridgeCommand === 'string' && s.bridgeCommand.includes('profiles' + path.sep + 'tui' + path.sep + 'node_modules'), - bridgeExists: typeof s?.bridgeCommand === 'string' && fs.existsSync(s.bridgeCommand), - shadowed - })); - } finally { await ctx.dispose?.(); } - `.replace(/\n {6}/g, '\n')); - const run = spawnSync(process.execPath, [probe], { cwd: work, env: envR, encoding: 'utf8', timeout: 180_000 }); - const lastLine = (run.stdout || '').trim().split('\n').pop(); - let result; - try { result = JSON.parse(lastLine); } catch { - throw new Error(`release probe printed no JSON verdict (exit ${run.status}):\n${(run.stderr || '') + (run.stdout || '')}`); - } - if (!String(result.url || '').startsWith('unix://')) throw new Error(`release activation produced no endpoint: ${lastLine}`); - if (!result.bridgeFromInstalledCopy || !result.bridgeExists) { - throw new Error(`bridge did not resolve from the installed copy: ${result.bridgeCommand}`); +function assertComposition(dumpText) { + return import('@deepseek-ai/dsh-app-boot').then(({ loadOptionalPatches }) => { + const temp = path.join(os.tmpdir(), `dshx-dump-${process.pid}-${Date.now()}.yml`); + fs.writeFileSync(temp, dumpText); + try { + const tree = loadOptionalPatches('dsh', temp); + const rows = []; + const walk = (node) => { + if (Array.isArray(node)) return node.forEach(walk); + if (!node || typeof node !== 'object') return; + if (typeof node.id === 'string') rows.push(node); + for (const value of Object.values(node)) walk(value); + }; + walk(tree); + const byId = new Map(rows.map((row) => [row.id, row])); + for (const id of ['dshx-startup', 'dshx-presentation']) { + if (!byId.has(id)) throw new Error(`composed tree is missing '${id}'`); + } + if (byId.get('headless-runner')?.disabled !== true) { + throw new Error('competing headless-runner must be disabled by the DSHX bundle patch'); + } + } finally { + fs.rmSync(temp, { force: true }); } - if (result.shadowed.length > 0) throw new Error(`stateful runtime copies shadowed: ${result.shadowed.join(', ')}`); - console.log(`[verify-bundle] release ok: activated via ${tarball.split(path.sep).pop()} -> ${result.url}`); - } finally { - fs.rmSync(work, { recursive: true, force: true }); - } + }); } -try { - // In-process boots must see the same DSH_HOME as the spawned CLI steps; - // several official plugins (e.g. credentials) read the environment directly. - process.env.DSH_HOME = home; - - // Binaries ship with the companion CLI (dist/bin), not the bundle tarball; - // the documented environment overrides point the surface at them. - for (const [envName, fileName] of [ - ['DSHX_IPC_BRIDGE_BIN', 'dshx-ipc-bridge'], - ['DSHX_TUI_BIN', 'dshx-tui'] - ]) { - const candidate = path.join(ROOT, 'dist', 'bin', process.platform === 'win32' ? `${fileName}.exe` : fileName); - if (fs.existsSync(candidate)) process.env[envName] = candidate; - } - - // ── 1. pack ──────────────────────────────────────────────────────────── - const packed = run('npm pack', 'npm', ['pack', '--pack-destination', packDir, '--loglevel', 'error'], { check: true }); - const tarballName = (packed.stdout.trim().split('\n').pop() || '').trim(); - const tarball = path.join(packDir, tarballName); - if (!tarballName.endsWith('.tgz') || !fs.existsSync(tarball)) { - throw new Error(`npm pack did not produce a tarball: ${packed.stdout}`); - } - console.log(`[verify-bundle] packed ${tarballName}`); - - // ── 2. official install into a brand-new profile ────────────────────── - const dsh = resolveDshInvocation(ROOT, isolatedEnv); - const add = run( - 'dsh plugin add', - dsh.command, - [...dsh.args, 'plugin', '--profile', PROFILE, 'add', `./${tarballName}`], - { cwd: packDir, check: true } +function assertSingleRuntime(home) { + const ownLeafLibs = new Set( + Object.keys(PACKAGE.dependencies ?? {}) + .filter((name) => name.startsWith('@deepseek-ai/dsh')) + .map((name) => name.slice('@deepseek-ai/'.length)) ); - if (!add.stdout.includes(`initialized profile ${PROFILE}`) && !add.stdout.includes('already')) { - // First use prints the init line; tolerate either shape but require success. - console.log('[verify-bundle] (profile init message not on stdout; continuing)'); + const profileModules = path.join(home, 'profiles', PROFILE, 'node_modules', '@deepseek-ai'); + const shadowed = fs.existsSync(profileModules) + ? fs.readdirSync(profileModules) + .filter((entry) => /^dsh(-|$)/.test(entry)) + .filter((entry) => !ownLeafLibs.has(entry)) + : []; + if (shadowed.length > 0) { + throw new Error(`profile shadows stateful DSH runtime packages: ${shadowed.join(', ')}`); } +} - const manifestPath = path.join(home, 'profiles', PROFILE, 'package.json'); - const manifest = JSON.parse(fs.readFileSync(manifestPath, 'utf8')); - const bundles = manifest.dsh?.profile?.bundles ?? []; - if (!bundles.includes(NAME)) { - fail(`reconcile did not append ${NAME} to dsh.profile.bundles: ${JSON.stringify(bundles)}`); - process.exit(process.exitCode || 1); - } - if (manifest.dependencies?.[NAME] == null) { - fail(`pnpm did not record ${NAME} in profile dependencies`); - process.exit(process.exitCode || 1); - } - console.log(`[verify-bundle] reconcile ok: bundles=${JSON.stringify(bundles)}`); +async function verifyInstall(specifier, label) { + const work = fs.mkdtempSync(path.join(os.tmpdir(), `dshx-${label}-e2e-`)); + const home = path.join(work, 'home'); + fs.mkdirSync(home, { recursive: true }); + const env = { + ...process.env, + DSH_HOME: home, + npm_config_cache: path.join(work, 'npm-cache'), + XDG_CACHE_HOME: path.join(work, 'cache'), + XDG_DATA_HOME: path.join(work, 'data'), + XDG_STATE_HOME: path.join(work, 'state') + }; + for (const key of [ + 'DSHX_APP_SERVER_CMD', 'DSHX_APP_SERVER_ENDPOINT', 'DSHX_APP_SERVER_TOKEN', + 'DSHX_IPC_BRIDGE_BIN', 'DSHX_ATTACH', 'DSHX_HEADLESS', 'DSHX_TUI_ARGS' + ]) delete env[key]; - // ── 3. composed tree contains the surface rows ───────────────────────── - // --dump-config emits the composed tree as YAML in the same dialect as - // patch files (including !!js nodes), so we reuse DSH's own parser. - const { loadOptionalPatches } = await import('@deepseek-ai/dsh-app-boot'); - const dumpPath = path.join(work, 'dump-config.yml'); - const dump = run('dsh --dump-config', dsh.command, [...dsh.args, '--profile', PROFILE, '--dump-config']); - if (dump.status !== 0) { - throw new Error(`--dump-config failed: ${dump.stderr || dump.stdout}`); - } - fs.writeFileSync(dumpPath, dump.stdout); - let tree; try { - tree = loadOptionalPatches('dsh', dumpPath); - } catch { - throw new Error(`--dump-config output did not parse as an entry list:\n${dump.stdout.slice(0, 2000)}`); - } - const flat = []; - const walk = (node) => { - if (Array.isArray(node)) { - node.forEach(walk); - } else if (node && typeof node === 'object') { - if (typeof node.id === 'string') flat.push(node); - for (const value of Object.values(node)) { - if (Array.isArray(value) || (value && typeof value === 'object' && value.constructor === Object)) walk(value); - } - } - }; - walk(tree); - const byId = new Map(flat.map((entry) => [entry.id, entry])); - for (const id of ['dshx-startup', 'dshx-presentation']) { - if (!byId.has(id)) { - fail(`composed tree is missing row '${id}'. Dumped ids: ${[...byId.keys()].join(', ')}`); - process.exit(process.exitCode || 1); + const dsh = resolveDshInvocation(ROOT, env); + run(dsh.command, [...dsh.args, 'plugin', '--profile', PROFILE, 'add', specifier], { + cwd: path.dirname(specifier), env + }); + const manifest = JSON.parse(fs.readFileSync(path.join(home, 'profiles', PROFILE, 'package.json'), 'utf8')); + if (!manifest.dsh?.profile?.bundles?.includes(NAME)) throw new Error('bundle reconcile did not activate DSHX'); + if (manifest.dependencies?.[NAME] == null) throw new Error('profile manifest did not record DSHX dependency'); + + const dump = run(dsh.command, [...dsh.args, '--profile', PROFILE, '--dump-config'], { cwd: work, env }); + await assertComposition(dump.stdout); + const initialized = await probeStdioSurface({ dsh, cwd: work, env }); + if (!String(initialized?.userAgent ?? '').startsWith('dshx/')) { + throw new Error(`unexpected initialize identity: ${JSON.stringify(initialized)}`); } + assertSingleRuntime(home); + console.log(`[verify-bundle] ${label} ok: official profile -> stdio -> ${initialized.userAgent}`); + } finally { + fs.rmSync(work, { recursive: true, force: true }); } - const headlessRunner = byId.get('headless-runner'); - if (headlessRunner && headlessRunner.disabled !== true) { - fail('competing headless-runner row is present but not disabled'); - process.exit(process.exitCode || 1); - } - console.log('[verify-bundle] dump-config ok: surface rows composed, locks applied'); +} - // ── 4. real boot: loader activates rows and services publish ─────────── - const { bootDshxRuntime } = await import('../src/dsh/runtime-boot.mjs'); - let ctx; - try { - ctx = await bootDshxRuntime({ cwd: ROOT, home, watch: false }); - } catch (error) { - // Surface the per-entry failures the AggregateError wraps. - const dump = (e, depth = 0) => { - if (!e || depth > 4) return; - const line = (e.message ?? String(e)).split('\n')[0]; - console.error(`${' '.repeat(depth)}- ${line}`); - if (Array.isArray(e.errors)) e.errors.forEach((sub) => dump(sub, depth + 1)); - if (e.cause && e.cause !== e) dump(e.cause, depth + 1); - }; - console.error('[verify-bundle] boot failure breakdown:'); - dump(error); - throw error; - } +try { + const packDir = fs.mkdtempSync(path.join(os.tmpdir(), 'dshx-source-pack-')); try { - const startup = ctx.get('dshxStartup'); - const presentation = ctx.get('dshxPresentation'); - if (!startup || startup.home !== path.resolve(process.env.DSHX_TUI_HOME || path.join(os.homedir(), '.dshx', 'codex-tui'))) { - throw new Error(`dshxStartup missing or unexpected home: ${JSON.stringify(startup)}`); - } - if (!presentation?.url?.startsWith('unix://')) { - throw new Error(`dshxPresentation missing or bad endpoint: ${JSON.stringify(presentation)}`); - } - if (!fs.existsSync(startup.bridgeCommand ?? '')) { - throw new Error('packaged bridge binary not found; build it before running this verifier'); - } - console.log(`[verify-bundle] boot ok: transport live at ${presentation.url}`); - - // ── 5. single-instance rule ────────────────────────────────────────── - // Leaf parser libraries declared as real dependencies (official bundle - // convention) may live in the profile; stateful runtime services must - // not — they would shadow the healed installation symlinks. - const ownLeafLibs = new Set( - Object.keys(PACKAGE.dependencies ?? {}) - .filter((name) => name.startsWith('@deepseek-ai/dsh')) - .map((name) => name.slice('@deepseek-ai/'.length)) - ); - const profileModules = path.join(home, 'profiles', PROFILE, 'node_modules', '@deepseek-ai'); - const shadowed = fs.existsSync(profileModules) - ? fs.readdirSync(profileModules) - .filter((entry) => /^dsh(-|$)/.test(entry)) - .filter((entry) => !ownLeafLibs.has(entry)) - : []; - if (shadowed.length > 0) { - throw new Error(`profile node_modules shadows stateful dsh runtime packages: ${shadowed.join(', ')}`); - } - console.log('[verify-bundle] single-instance ok: no stateful dsh runtime copies shadow the healed fallback'); + const packed = run('npm', ['pack', '--pack-destination', packDir, '--loglevel', 'error']); + const name = packed.stdout.trim().split('\n').pop()?.trim(); + if (!name?.endsWith('.tgz')) throw new Error(`npm pack returned no tarball: ${packed.stdout}`); + await verifyInstall(path.join(packDir, name), 'source bundle'); } finally { - await ctx.dispose?.(); + fs.rmSync(packDir, { recursive: true, force: true }); } -} catch (error) { - fail(error instanceof Error ? error.stack : String(error)); - console.error(`[verify-bundle] temp workspace preserved for inspection: ${work}`); -} finally { - if (!process.exitCode) fs.rmSync(work, { recursive: true, force: true }); -} - -// Release flavor: when a packaged artifact exists, prove the published -// tarball itself installs and activates with zero environment overrides. -if (!process.exitCode) { const releaseDir = path.join(ROOT, 'dist', 'release'); - const tarballs = fs.existsSync(releaseDir) - ? fs.readdirSync(releaseDir).filter((f) => f.startsWith('dshx-') && f.endsWith('.tgz')).sort() + const releases = fs.existsSync(releaseDir) + ? fs.readdirSync(releaseDir).filter((file) => file.startsWith('dshx-') && file.endsWith('.tgz')).sort() : []; - if (tarballs.length === 0) { - console.log('[verify-bundle] release flavor: skipped (build one via scripts/package-platform.mjs)'); - if (process.env.DSHX_REQUIRE_RELEASE === '1') process.exitCode = 1; + if (releases.length > 0) { + await verifyInstall(path.join(releaseDir, releases.at(-1)), 'release bundle'); + } else if (process.env.DSHX_REQUIRE_RELEASE === '1') { + throw new Error('release flavor required but no dist/release/dshx-*.tgz exists'); } else { - await verifyReleaseFlavor(path.join(releaseDir, tarballs.at(-1))); + console.log('[verify-bundle] release flavor skipped (no platform artifact present)'); } - if (!process.exitCode) console.log('[verify-bundle] ALL CHECKS PASSED'); + console.log('[verify-bundle] ALL CHECKS PASSED'); +} catch (error) { + fail(error instanceof Error ? error.stack : String(error)); } diff --git a/scripts/verify-tui-invariants.mjs b/scripts/verify-tui-invariants.mjs index 2a578f29..180ca4b3 100644 --- a/scripts/verify-tui-invariants.mjs +++ b/scripts/verify-tui-invariants.mjs @@ -1,42 +1,48 @@ -import { readFileSync } from 'node:fs'; - -function read(path) { - return readFileSync(path, 'utf8'); -} +import { existsSync, readFileSync } from 'node:fs'; +function read(path) { return readFileSync(path, 'utf8'); } function requireText(path, needle) { const text = read(path); - if (!text.includes(needle)) { - throw new Error(`${path} is missing required invariant: ${needle}`); - } + if (!text.includes(needle)) throw new Error(`${path} is missing required invariant: ${needle}`); } - function forbidText(path, needle, label = needle) { const text = read(path); - if (text.includes(needle)) { - throw new Error(`${path} violates TUI invariant: ${label}`); - } + if (text.includes(needle)) throw new Error(`${path} violates TUI invariant: ${label}`); } const main = '.upstream/codex/codex-rs/tui/src/main.rs'; const lib = '.upstream/codex/codex-rs/tui/src/lib.rs'; +const client = '.upstream/codex/codex-rs/app-server-client/src/lib.rs'; +const stdio = '.upstream/codex/codex-rs/app-server-client/src/stdio.rs'; const app = '.upstream/codex/codex-rs/tui/src/app.rs'; const session = '.upstream/codex/codex-rs/tui/src/app_server_session.rs'; const slash = '.upstream/codex/codex-rs/tui/src/slash_command.rs'; const startup = '.upstream/codex/codex-rs/tui/src/app/startup.rs'; const event = '.upstream/codex/codex-rs/tui/src/app/event_dispatch.rs'; -const bridge = '.upstream/codex/codex-rs/stdio-to-uds/src/dshx_ipc_bridge.rs'; for (const needle of [ - 'DSHX_APP_SERVER_ENDPOINT is required', - 'DSHX production launcher forbids TCP WebSocket transport', - 'RemoteAppServerEndpoint::UnixSocket', + 'DSHX_APP_SERVER_CMD is required', + 'RemoteAppServerEndpoint::StdioChild', 'Some(dshx_endpoint)', 'DSHX_RESUME_MODE', ]) requireText(main, needle); -forbidText(main, 'DSHX_APP_SERVER_TOKEN', 'legacy TCP bearer-token transport'); +forbidText(main, 'DSHX_APP_SERVER_ENDPOINT', 'legacy socket endpoint transport'); +forbidText(main, 'DSHX_APP_SERVER_TOKEN', 'legacy bearer-token transport'); + +for (const needle of [ + 'pub struct StdioAppServerClient', + 'Command::new(executable)', + 'JSONRPCMessage', + 'stdin.shutdown()', +]) requireText(stdio, needle); +requireText(client, 'Stdio(StdioAppServerClient)'); +requireText(lib, 'Some(endpoint @ RemoteAppServerEndpoint::StdioChild'); +requireText(lib, 'AppServerTarget::LocalDaemon { endpoint }'); + +const legacyBridge = '.upstream/codex/codex-rs/stdio-to-uds/src/dshx_ipc_bridge.rs'; +if (existsSync(legacyBridge)) throw new Error('legacy dshx-ipc-bridge must not be materialized'); +if (existsSync('src/dsh/local-server.mjs')) throw new Error('legacy Node socket host must not ship'); -for (const needle of ['UnixListener', 'UnixStream', 'dshxBridge']) requireText(bridge, needle); requireText('.upstream/codex/codex-rs/tui/src/history_cell/session.rs', 'DeepSeek Harness'); requireText('.upstream/codex/codex-rs/tui/src/bottom_pane/approval_overlay.rs', 'fn dshx_backend'); requireText('.upstream/codex/codex-rs/tui/src/chatwidget/permission_popups.rs', 'fn dshx_backend'); @@ -49,21 +55,14 @@ requireText(app, 'dshx'); requireText(slash, 'if crate::dshx_backend()'); requireText(slash, 'DeepSeek Harness'); -forbidText('src/dsh/local-server.mjs', 'WebSocketServer', 'production TCP WebSocket server'); -requireText('src/dsh/local-server.mjs', 'unix://'); -requireText('scripts/package-platform.mjs', 'local-uds-via-stdio-bridge'); - -const pkg = JSON.parse(read('package.json')); -if (pkg.dependencies?.ws) throw new Error('ws must not be a production dependency'); -if (!pkg.devDependencies?.ws) throw new Error('development protocol stub still requires ws'); - const slashText = read(slash); const hiddenStart = slashText.indexOf('if crate::dshx_backend()'); const hiddenEnd = slashText.indexOf('return false;', hiddenStart); if (hiddenStart < 0 || hiddenEnd < 0) throw new Error('DSHX slash hidden block not found'); -const hidden = slashText.slice(hiddenStart, hiddenEnd); -if (hidden.includes('SlashCommand::Diff')) { - throw new Error('/diff must remain visible in DSHX now that command/exec is DSH-backed'); +if (slashText.slice(hiddenStart, hiddenEnd).includes('SlashCommand::Diff')) { + throw new Error('/diff must remain visible in DSHX'); } -console.log('DSHX pinned TUI invariants verified'); +const pkg = JSON.parse(read('package.json')); +if (pkg.dependencies?.ws) throw new Error('ws must not be a production dependency'); +console.log('DSHX pinned TUI stdio invariants verified'); diff --git a/src/dsh/local-server.mjs b/src/dsh/local-server.mjs deleted file mode 100644 index 15a79171..00000000 --- a/src/dsh/local-server.mjs +++ /dev/null @@ -1,377 +0,0 @@ -import process from 'node:process'; -import fs from 'node:fs'; -import os from 'node:os'; -import path from 'node:path'; -import { spawn } from 'node:child_process'; -import { createInterface } from 'node:readline'; -import { fileURLToPath } from 'node:url'; -import { DshxPresentationAdapter } from '../tui-protocol/adapter.mjs'; -// Intentionally NO import of runtime-boot here: this module is loaded inside -// the user's DSH installation via the profile loader, so pulling any harness -// build from our own package would fork the runtime into two builds. Hosts -// that need self-booting inject `bootRuntime` explicitly (tests, dev tooling). - -const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../..'); -const READY = 'ready'; -const WINDOWS_UNIX_PATH_MAX = 108; - -function packagedBridgeBinary() { - const name = process.platform === 'win32' ? 'dshx-ipc-bridge.exe' : 'dshx-ipc-bridge'; - return process.env.DSHX_IPC_BRIDGE_BIN || path.join(ROOT, 'dist', 'bin', name); -} - -function parseError(error) { - return { - id: null, - error: { - code: -32700, - message: `Parse error: ${error instanceof Error ? error.message : String(error)}` - } - }; -} - -function isPathWithin(root, candidate, pathApi = path) { - const relative = pathApi.relative(pathApi.resolve(root), pathApi.resolve(candidate)); - return relative === '' || ( - relative !== '..' && - !relative.startsWith(`..${pathApi.sep}`) && - !pathApi.isAbsolute(relative) - ); -} - -function defaultSocketRoot({ - home, - platform = process.platform, - temporaryDirectory = os.tmpdir(), - userHome = os.homedir() -} = {}) { - if (platform !== 'win32') return temporaryDirectory; - // codex_uds can enforce 0700 on Unix. Its Windows implementation inherits - // directory ACLs instead, so do not trust an arbitrary/shared %TEMP% root. - // Anchor the rendezvous below the current user's DSHX presentation home, - // whose parent in turn lives below the user's profile by default. Keep the - // Windows suffix deliberately short because sockaddr_un.sun_path is bounded. - const pathApi = path.win32; - const userProfile = pathApi.resolve(userHome); - const presentationHome = pathApi.resolve(home || pathApi.join(userProfile, '.dshx', 'codex-tui')); - if (!isPathWithin(userProfile, presentationHome, pathApi)) { - throw new Error( - `DSHX_TUI_HOME must remain under the Windows user profile (${userProfile}) so local IPC inherits private user ACLs; got ${presentationHome}` - ); - } - return pathApi.join(presentationHome, 'i'); -} - -function createSocketDirectory(root) { - fs.mkdirSync(root, { recursive: true, mode: 0o700 }); - const directory = fs.mkdtempSync(path.join(root, 'd-')); - if (process.platform !== 'win32') fs.chmodSync(directory, 0o700); - return directory; -} - -function assertSocketPathSupported(socketPath, { - platform = process.platform, - windowsUnixPathMax = WINDOWS_UNIX_PATH_MAX -} = {}) { - if (platform !== 'win32') return; - const bytes = Buffer.byteLength(socketPath, 'utf8'); - // sun_path needs one byte for the terminating NUL, so the pathname itself - // must remain strictly shorter than the fixed buffer. - if (bytes >= windowsUnixPathMax) { - throw new Error( - `DSHX local IPC path is ${bytes} UTF-8 bytes; Windows AF_UNIX requires fewer than ${windowsUnixPathMax}. ` + - 'Set DSHX_TUI_HOME to a shorter path under your user profile and retry.' - ); - } -} - -function waitForBridgeReady(lines, child, stderrText) { - return new Promise((resolve, reject) => { - const fail = (error) => { - cleanup(); - reject(error); - }; - const onLine = (line) => { - let message; - try { - message = JSON.parse(line); - } catch (error) { - fail(new Error(`DSHX IPC bridge emitted invalid readiness JSON: ${line}`, { cause: error })); - return; - } - if (message?.dshxBridge !== READY) { - fail(new Error(`DSHX IPC bridge emitted unexpected readiness message: ${line}`)); - return; - } - cleanup(); - resolve(message); - }; - const onError = (error) => fail(new Error(`failed to start DSHX IPC bridge: ${error.message}`, { cause: error })); - const onExit = (code, signal) => { - const detail = stderrText().trim(); - fail(new Error(`DSHX IPC bridge exited before ready (${signal ?? code ?? 'unknown'})${detail ? `: ${detail}` : ''}`)); - }; - const cleanup = () => { - lines.off('line', onLine); - child.off('error', onError); - child.off('exit', onExit); - }; - lines.once('line', onLine); - child.once('error', onError); - child.once('exit', onExit); - }); -} - -function waitForExit(child, timeoutMs = 750) { - if (!child || child.exitCode !== null || child.signalCode !== null) return Promise.resolve(); - return new Promise((resolve) => { - let done = false; - const finish = () => { - if (done) return; - done = true; - clearTimeout(timer); - child.off('exit', finish); - resolve(); - }; - const timer = setTimeout(() => { - if (child.exitCode === null && child.signalCode === null) child.kill('SIGTERM'); - finish(); - }, timeoutMs); - child.once('exit', finish); - }); -} - -function cleanupDiagnostic(log, scope, error) { - log(`${scope}: ${error instanceof Error ? error.message : String(error)}`); -} - -async function cleanupFailedStartup({ lines, bridge, ctx, socketDirectory, log }) { - try { - lines?.close(); - } catch (error) { - cleanupDiagnostic(log, 'startup rollback: readline cleanup failed', error); - } - if (bridge) { - try { - if (bridge.stdin?.writable) bridge.stdin.end(); - if (bridge.exitCode === null && bridge.signalCode === null) bridge.kill?.('SIGTERM'); - await waitForExit(bridge); - if (bridge.exitCode === null && bridge.signalCode === null) bridge.kill?.('SIGKILL'); - } catch (error) { - cleanupDiagnostic(log, 'startup rollback: bridge cleanup failed', error); - } - } - try { - await ctx?.dispose?.(); - } catch (error) { - cleanupDiagnostic(log, 'startup rollback: DSH dispose failed', error); - } - if (socketDirectory) { - try { - fs.rmSync(socketDirectory, { recursive: true, force: true }); - } catch (error) { - cleanupDiagnostic(log, 'startup rollback: rendezvous cleanup failed', error); - } - } -} - -/** - * Starts the production-local DSHX presentation transport. - * - * The official DeepSeek Harness runtime remains in-process in Node. The pinned - * Codex TUI connects only to a private cross-platform Unix-domain socket owned - * by the tiny packaged Rust bridge. JSON-RPC is relayed between that bridge and - * this adapter over child stdio; no TCP listener or Codex remote WebSocket mode - * exists in the production launch path. - */ -export async function startDshxLocalServer({ - cwd = process.cwd(), - home, - version = '0.1.0-dev', - runtime, - Adapter = DshxPresentationAdapter, - log = () => {}, - bridgeCommand = packagedBridgeBinary(), - bridgeArgs, - spawnBridge = spawn, - socketRoot, - disposeRuntimeOnClose = true, - bootRuntime -} = {}) { - const rendezvousRoot = path.resolve(socketRoot ?? defaultSocketRoot({ home })); - let socketDirectory; - let socketPath; - let ctx = runtime; - let bridge; - let lines; - let adapter; - let closing = false; - let closePromise; - let stderr = ''; - - // Exceptional transport events are always visible on stderr (never gated by - // the debug flag): they are the diagnosability lifeline when a TUI reports - // a protocol timeout. - const transportFault = (message) => { - process.stderr.write(`[dshx] ${message}\n`); - }; - - const send = (message) => { - if (!bridge?.stdin?.writable) throw new Error('DSHX IPC bridge stdin is not writable'); - bridge.stdin.write(`${JSON.stringify(message)}\n`); - }; - const safeSend = (message) => { - try { - send(message); - return true; - } catch (error) { - transportFault(`IPC response send failed: ${error instanceof Error ? error.message : String(error)}`); - return false; - } - }; - - try { - socketDirectory = createSocketDirectory(rendezvousRoot); - socketPath = path.join(socketDirectory, 's'); - assertSocketPathSupported(socketPath); - if (!ctx && typeof bootRuntime !== 'function') { - throw new Error('startDshxLocalServer requires either a runtime Context or an injected bootRuntime'); - } - ctx ??= await bootRuntime({ cwd }); - const args = bridgeArgs ?? [socketPath]; - bridge = spawnBridge(bridgeCommand, args, { - cwd, - stdio: ['pipe', 'pipe', 'pipe'], - windowsHide: true - }); - bridge.stderr?.on('data', (chunk) => { - const text = chunk.toString('utf8'); - stderr = `${stderr}${text}`.slice(-8192); - if (process.env.DSHX_DEBUG === '1') log(`ipc bridge: ${text.trimEnd()}`); - }); - lines = createInterface({ input: bridge.stdout, crlfDelay: Infinity }); - await waitForBridgeReady(lines, bridge, () => stderr); - adapter = new Adapter({ - ctx, - cwd, - home, - version, - send, - diagnostics: log - }); - } catch (error) { - await cleanupFailedStartup({ lines, bridge, ctx, socketDirectory, log }); - throw error; - } - - lines.on('line', (line) => { - void (async () => { - let message; - try { - message = JSON.parse(line); - } catch (error) { - safeSend(parseError(error)); - return; - } - if (message?.dshxBridge) { - log(`IPC bridge control message: ${message.dshxBridge}`); - return; - } - try { - const handled = await adapter.handle(message); - if (!handled) return; - if (!safeSend(handled.response)) return; - await handled.afterResponse?.(); - } catch (error) { - log(`request handling failed: ${error instanceof Error ? error.stack ?? error.message : String(error)}`); - if (message?.id !== undefined) { - safeSend({ - id: message.id, - error: { - code: -32603, - message: error instanceof Error ? error.message : String(error) - } - }); - } - } - })(); - }); - - bridge.on('error', (error) => log(`IPC bridge error: ${error.message}`)); - bridge.on('exit', (code, signal) => { - if (!closing) transportFault(`IPC bridge exited unexpectedly (${signal ?? code ?? 'unknown'})`); - }); - - const close = () => { - if (closePromise) return closePromise; - closing = true; - closePromise = (async () => { - let primaryError; - const capture = (scope, error) => { - if (!primaryError) { - primaryError = error; - return; - } - cleanupDiagnostic(log, `shutdown cleanup: ${scope}`, error); - }; - - try { - lines?.close(); - } catch (error) { - capture('readline cleanup failed', error); - } - - try { - await adapter?.close?.(); - } catch (error) { - capture('adapter close failed', error); - } - - try { - if (bridge?.stdin?.writable) bridge.stdin.end(); - await waitForExit(bridge); - if (bridge && bridge.exitCode === null && bridge.signalCode === null) bridge.kill?.('SIGKILL'); - } catch (error) { - capture('bridge cleanup failed', error); - } - - // When mounted as the dshx-presentation Cordis plugin, root-fiber - // disposal stays owned by the composition; only the transport closes - // here and the Fiber unwinds the plugin afterwards. - if (disposeRuntimeOnClose) { - try { - await ctx?.dispose?.(); - } catch (error) { - capture('DSH dispose failed', error); - } - } - - if (socketDirectory) { - try { - fs.rmSync(socketDirectory, { recursive: true, force: true }); - } catch (error) { - capture('rendezvous cleanup failed', error); - } - } - - if (primaryError) throw primaryError; - })(); - return closePromise; - }; - - return { - path: socketPath, - url: `unix://${socketPath}`, - context: ctx, - close - }; -} - -export const localServerInternals = { - WINDOWS_UNIX_PATH_MAX, - isPathWithin, - defaultSocketRoot, - createSocketDirectory, - assertSocketPathSupported, - cleanupFailedStartup -}; diff --git a/src/dsh/presentation-plugin.mjs b/src/dsh/presentation-plugin.mjs index d7137a3c..d270b5d4 100644 --- a/src/dsh/presentation-plugin.mjs +++ b/src/dsh/presentation-plugin.mjs @@ -1,53 +1,24 @@ -import fs from 'node:fs'; -import { spawn } from 'node:child_process'; import process from 'node:process'; import z from '@deepseek-ai/schemastery'; -import { startDshxLocalServer } from './local-server.mjs'; import { startDshxStdioTransport } from './stdio-transport.mjs'; /** - * dshx-presentation — the surface's presentation transport row. + * dshx-presentation — the DSHX surface row. * - * Both migration-era transports run against the ALREADY-BOOTED composition of - * whatever DSH installation hosts this profile. The new stdio app-server mode - * is the target architecture; the local bridge remains temporarily available - * until the pinned Codex TUI is switched to spawn an external stdio backend. + * It owns only protocol framing against the ALREADY-MOUNTED DSH composition. + * No Harness runtime is imported or booted here and no network/socket bridge is + * created. The pinned TUI launches this composition as its local stdio backend. */ -/** Stable Cordis plugin name. */ export const name = 'dshx-presentation'; - -/** The startup row's service is a hard prerequisite for the transport. */ export const inject = ['dshxStartup']; - -/** Static legacy socket override retained only during the bridge migration. */ -export const Config = z.object({ - socketRoot: z.string() -}); - -/** Service key published on the Context after the transport is ready. */ +export const Config = z.object({}); export const SERVICE_KEY = 'dshxPresentation'; -/** Test seams mirroring the official packages' `internals` convention. */ export const internals = { - // `start` is kept as the legacy alias so downstream migration tests do not - // need to change in the same commit that introduces stdio. - start: startDshxLocalServer, - startStdio: startDshxStdioTransport, - spawn, - isInteractive: () => process.stdout.isTTY === true && process.stdin.isTTY === true + startStdio: startDshxStdioTransport }; -function parseTuiArgs(environment) { - if (!environment.DSHX_TUI_ARGS) return []; - try { - const parsed = JSON.parse(environment.DSHX_TUI_ARGS); - return Array.isArray(parsed) ? parsed.map(String) : []; - } catch { - return []; - } -} - function appExit(ctx) { if (typeof ctx?.get === 'function') { const value = ctx.get('appExit'); @@ -62,124 +33,45 @@ function requestHostExit(ctx, code, log) { exit(code); return; } - // Tests/embedding hosts may omit the launcher's optional appExit seam. Do - // not hard-exit from a Cordis row; record the status and let the host decide. + // Embedding tests may omit appExit. A Cordis row must never call + // process.exit(); recording the status leaves final process ownership to the + // embedding host while preserving failure information. process.exitCode = code; log(`DSH launcher did not provide appExit; recorded process.exitCode=${code}`); } -function attachTui(launch, server, log) { - if (!launch.tuiCommand || !fs.existsSync(launch.tuiCommand)) { - throw new Error(`dshx: packaged TUI binary not found (${launch.tuiCommand ?? 'unknown path'}); run \`dshx doctor\``); - } - const child = internals.spawn(launch.tuiCommand, parseTuiArgs(process.env), { - cwd: launch.cwd, - env: { - ...process.env, - // Do not inherit CODEX_HOME: DSHX uses Codex code as a presentation - // component only and must not read/write the user's ordinary Codex state. - CODEX_HOME: launch.home, - DSHX_APP_SERVER_ENDPOINT: server.url - }, - stdio: 'inherit', - windowsHide: false - }); - // SIGTERM propagates for lifecycle shutdown. SIGINT is intentionally left to - // the TUI: in raw mode Ctrl+C arrives as a key event (turn interrupt). - process.once('SIGTERM', () => { - if (!child.killed) child.kill('SIGTERM'); - }); - if (process.platform !== 'win32') { - process.once('SIGHUP', () => { - if (!child.killed) child.kill('SIGHUP'); - }); - } - child.on('error', (error) => log(`failed to launch pinned Codex TUI: ${error.message}`)); - const exit = new Promise((resolveExit) => { - child.once('exit', (code, signal) => resolveExit({ code, signal })); - }); - return { child, exit }; -} - -export async function apply(ctx, config = {}) { +export async function apply(ctx) { if (!ctx || typeof ctx.provide !== 'function') { throw new Error('dshx-presentation requires a Cordis Context with provide()'); } const launch = ctx.dshxStartup; if (!launch || typeof launch.home !== 'string') { - throw new Error('dshx-presentation requires the dshxStartup service (mount the dshx-startup row first)'); + throw new Error('dshx-presentation requires the dshxStartup service (mount dshx-startup first)'); } - const debug = launch.debug === true; - const log = debug ? (message) => process.stderr.write(`[dshx] ${message}\n`) : () => {}; - - if (launch.appServer === true) { - const transport = await internals.startStdio({ - ctx, - cwd: launch.cwd, - home: launch.home, - version: launch.version, - diagnostics: log, - onEof: (error) => requestHostExit(ctx, error ? 1 : 0, log) - }); - ctx.provide(SERVICE_KEY, { - mode: 'stdio', - close: transport.close, - tuiCommand: launch.tuiCommand - }); - // Cordis owns row lifetime. Initialization returns immediately with the - // disposer; stdin EOF requests bounded host exit through appExit. - return transport.close; + if (launch.appServer !== true) { + throw new Error('dshx-presentation is a stdio app-server surface; launch it through `dshx`'); } - const server = await internals.start({ + const log = launch.debug === true + ? (message) => process.stderr.write(`[dshx] ${message}\n`) + : () => {}; + const transport = internals.startStdio({ + ctx, cwd: launch.cwd, home: launch.home, version: launch.version, - bridgeCommand: launch.bridgeCommand, - socketRoot: config.socketRoot, - // The composition Context already exists; never double-boot. Root-fiber - // disposal stays owned by the composition, so the transport must not - // dispose the runtime it lives in. - runtime: ctx, - disposeRuntimeOnClose: false, - log + diagnostics: log, + onEof: (error) => requestHostExit(ctx, error ? 1 : 0, log) }); - let tuiExit; - let attached = false; - if (launch.attach === true) { - if (!internals.isInteractive()) { - log('attach requested but stdout is not an interactive terminal; serving passive endpoint'); - } else { - const handle = attachTui(launch, server, log); - tuiExit = handle.exit; - attached = true; - // Never await the child from plugin apply(): adapter readiness waits for - // loader.await(), which in turn requires this row to finish mounting. - // Request official bounded exit after the TUI leaves instead. - void tuiExit.then(({ code, signal }) => { - requestHostExit(ctx, code ?? (signal ? 1 : 0), log); - }); - } - } - - ctx.provide(SERVICE_KEY, { - mode: 'bridge', - path: server.path, - url: server.url, - close: server.close, - tuiCommand: launch.tuiCommand, - ...(tuiExit ? { tuiExit } : {}) - }); - - // Passive launches would otherwise sit silently on a live endpoint; mirror - // the official web surface's printUrl precedent. - if (!attached) { - process.stderr.write(`[dshx] surface listening at ${server.url} — start the interactive TUI with \`dshx\`\n`); - } + ctx.provide(SERVICE_KEY, Object.freeze({ + mode: 'stdio', + close: transport.close + })); - return server.close; + // Cordis owns lifetime. Mount completes immediately; stdin EOF closes the + // adapter and asks the official launcher for bounded composition shutdown. + return transport.close; } -/** Bundle-shaped export consumed by the loader through the patch row. */ export const plugin = { name, inject, Config, apply }; diff --git a/src/dsh/runtime-boot.mjs b/src/dsh/runtime-boot.mjs deleted file mode 100644 index 6cf90962..00000000 --- a/src/dsh/runtime-boot.mjs +++ /dev/null @@ -1,309 +0,0 @@ -import { readFileSync, writeFileSync } from 'node:fs'; -import { createRequire } from 'node:module'; -import { delimiter, dirname, join, resolve } from 'node:path'; -import { fileURLToPath } from 'node:url'; -import { - boot, - composeEntries, - healProfilesModuleFallback, - loadLayeredEnv, - loadOptionalPatches, - loadProfile, - PROFILE_PATCH_FILENAME, - watchUserPatches -} from '@deepseek-ai/dsh-app-boot'; -import { DSH_LAUNCH_ENVIRONMENT_KEY } from '@deepseek-ai/dsh-launch-environment'; - -const NAME = 'dshx'; -const DSH_PROFILE_BIN_NAME = 'dsh'; -const DEFAULT_PROFILE = 'tui'; -const PROFILE_ROOT_FILENAME = 'cordis.yml'; -// The official DSH line this surface was built and tested against. Kept as an -// explicit constant (not derived from the advisory peer range) so the -// warn-once compatibility notice stays exact while the peer declaration can -// express an adoption-friendly floor. -const PACKAGE_ROOT = resolve(dirname(fileURLToPath(import.meta.url)), '../..'); -const TESTED_DSH_LINE = '0.1.0-rc.8'; -// Match the official `dsh` launcher's profile-root contract: this file is only -// the Loader/include base anchor. The real user-owned configuration is carried -// by the profile's `cordis.patch.yml` plus `$DSH_HOME/cordis.patch.yml`. -// Rewriting this empty root on every boot is intentional DSH behavior and -// prevents Loader tree write-back from becoming a second persisted config. -const PROFILE_ROOT_CONFIG = `# DSHX uses the same empty profile root contract as the official dsh launcher.\n# The effective tree is composed from DSH bundle and patch layers.\n# Edit cordis.patch.yml, not this file.\n[]\n`; -// The DSHX surface arrives as a real bundle layer: the package manifest -// declares `dsh.bundle.patch`, so the official loader composes our rows and -// surface locks from the installed profile. This module owns no patch of its -// own; launcher patches stay limited to installation-equivalent environment -// wiring (agent preset roots, telemetry switch). - -/** - * Anchor at the user's INSTALLED DeepSeek Harness whenever one exists: the - * `dsh` on their PATH is the same build that powers their other surfaces and - * wrote their state files, so composition, healing and row resolution must - * ride that build. The repository's npm closure is only a fallback for fresh - * checkouts/CI without a global installation. DSHX_INSTALL_ANCHOR overrides. - */ -function dshExecutableOnPath(environment = process.env) { - const names = process.platform === 'win32' ? ['dsh.cmd', 'dsh.exe', 'dsh'] : ['dsh']; - for (const directory of (environment.PATH || '').split(delimiter)) { - if (!directory) continue; - for (const name of names) { - const candidate = join(directory, name); - try { - readFileSync(candidate); - return candidate; - } catch { /* not here */ } - } - } - return undefined; -} - -function installationAnchor() { - if (process.env.DSHX_INSTALL_ANCHOR) return process.env.DSHX_INSTALL_ANCHOR; - try { - return createRequire(import.meta.url).resolve('@deepseek-ai/dsh/package.json'); - } catch { /* fall through to PATH discovery below */ } - const executable = dshExecutableOnPath(); - if (executable) { - let directory = dirname(resolve(executable)); - for (;;) { - const manifest = join(directory, 'package.json'); - try { - if (JSON.parse(readFileSync(manifest, 'utf8')).name === '@deepseek-ai/dsh') return manifest; - } catch { /* keep walking up */ } - const parent = dirname(directory); - if (parent === directory) break; - directory = parent; - } - } - throw new Error('dshx: cannot locate an official DeepSeek Harness installation; install @deepseek-ai/dsh or set DSHX_INSTALL_ANCHOR'); -} - -/** - * Report which official DSH line this surface was built and tested against, - * compared with the installation that will actually boot. Ecosystem - * convention: bundles declare compatibility through peer ranges and never - * block the host, so a mismatch is a loud one-shot warning, not an error. - */ -let dshLineWarned = false; -export function reportDshLineCompatibility( - anchor = installationAnchor(), - notify = (message) => process.stderr.write(`${message}\n`) -) { - let installed; - try { - installed = JSON.parse(readFileSync(anchor, 'utf8')).version; - } catch { - return { installed: undefined, supported: TESTED_DSH_LINE, compatible: undefined }; - } - const compatible = installed === TESTED_DSH_LINE; - if (!compatible && !dshLineWarned) { - dshLineWarned = true; - notify( - `[dshx] running against untested official DeepSeek Harness ${installed} ` + - `(tested line: ${TESTED_DSH_LINE}); proceeding — report oddities upstream if any appear` - ); - } - return { installed, supported: TESTED_DSH_LINE, compatible }; -} - -function selectedProfile(explicit) { - const value = explicit ?? process.env.DSHX_PROFILE ?? DEFAULT_PROFILE; - if (typeof value !== 'string' || value.trim().length === 0) { - throw new Error('dshx: DSH profile name must be non-empty'); - } - return value.trim(); -} - -function profileHome(profile) { - return dirname(dirname(profile.dir)); -} - -function homePatchPath(profile) { - return join(profileHome(profile), PROFILE_PATCH_FILENAME); -} - -function shippedAgentPresetPatch(entries, installAnchor) { - const agentPresets = entries.find((entry) => entry.id === 'agent-presets'); - if (!agentPresets) return []; - return [{ - id: 'agent-presets', - config: { - ...(agentPresets.config ?? {}), - roots: [{ path: join(dirname(installAnchor), 'config', 'agent-presets'), trust: 'system' }] - } - }]; -} - -function telemetryPatch(entries) { - if (!process.env.DSH_TELEMETRY_DISABLED) return []; - if (!entries.some((entry) => entry.id === 'session-telemetry-otel')) return []; - return [{ id: 'session-telemetry-otel', disabled: true }]; -} - -/** - * Load the exact official DSH profile layers that DSHX presents. - * - * Order remains DSH-owned: profile bundle layers -> profile user patch -> - * $DSH_HOME/cordis.patch.yml. The DSHX surface itself is one of the bundle - * layers (`dsh.bundle.patch`); the launcher adds only installation-equivalent - * environment patches on top. Out-of-tree profile plugins resolve from the - * profile directory through DSH's own healed module fallback. - */ -export function dshxRuntimeProfile({ - profile: explicitProfile, - installAnchor = installationAnchor(), - home, - overlays = [] -} = {}) { - const profileName = selectedProfile(explicitProfile); - reportDshLineCompatibility(installAnchor); - healProfilesModuleFallback(installAnchor, home); - const profile = loadProfile(DSH_PROFILE_BIN_NAME, profileName, installAnchor, home); - const rootConfig = join(profile.dir, PROFILE_ROOT_FILENAME); - // Official DSH deliberately rewrites this empty include root before boot. - // Never write `profile.patchPath` or the home patch here: those are the - // authoritative user configuration layers and are read-only to DSHX. - writeFileSync(rootConfig, PROFILE_ROOT_CONFIG); - - const bundlePatches = profile.layers.flatMap((layer) => layer.patches); - const homePatches = loadOptionalPatches(DSH_PROFILE_BIN_NAME, homePatchPath(profile)) ?? []; - const beforeLauncher = composeEntries([[...bundlePatches, ...profile.patches, ...homePatches]]); - const launcherPatches = [ - ...shippedAgentPresetPatch(beforeLauncher, installAnchor), - ...telemetryPatch(beforeLauncher), - ...structuredClone(overlays) - ]; - - return { - name: profileName, - profile, - rootConfig, - installAnchor, - homePatchPath: homePatchPath(profile), - patches: [ - ...structuredClone(bundlePatches), - ...structuredClone(profile.patches), - ...structuredClone(homePatches), - ...launcherPatches - ] - }; -} - -export function dshxRuntimePatches(options = {}) { - return dshxRuntimeProfile(options).patches; -} - -export function dshxRuntimeEntries(options = {}) { - return composeEntries([dshxRuntimePatches(options)]); -} - -async function installProfileWatchers(ctx, options) { - if (ctx.get('loader') == null) { - throw new Error('dshx: official DSH profile boot has no Loader for profile hot reload'); - } - if (ctx.get('hmr') == null) { - if (ctx.get('timer') == null) { - await ctx.loader.create({ name: '@deepseek-ai/cordis-plugin-timer' }); - } - await ctx.loader.create({ name: '@deepseek-ai/cordis-plugin-hmr', config: { root: [] } }); - } - - const current = () => dshxRuntimeProfile(options).patches; - const composition = dshxRuntimeProfile(options); - await watchUserPatches(ctx, { - binName: NAME, - filename: composition.profile.patchPath, - compose: () => current() - }); - await watchUserPatches(ctx, { - binName: NAME, - filename: composition.homePatchPath, - compose: () => current() - }); -} - -async function disposeOfficialContext(ctx) { - if (!ctx) return; - if (typeof ctx.fiber?.dispose !== 'function') { - throw new Error('dshx: official DSH Context has no root fiber disposal contract'); - } - await ctx.fiber.dispose(); -} - -function attachPresentationLifetime(ctx) { - // Cordis Context intentionally owns teardown through its root Fiber rather - // than a Context.dispose() method. DSHX keeps its launcher/local-server - // lifetime API small by exposing a non-enumerable alias that delegates to - // that official root-fiber contract; no runtime service is replaced. - Object.defineProperty(ctx, 'dispose', { - configurable: true, - enumerable: false, - value: () => disposeOfficialContext(ctx) - }); - return ctx; -} - -/** - * Boot the selected official Harness profile in-process and return its root Context. - * DSHX owns only presentation lifetime. Project and DSH-home environment and - * live patch behavior intentionally follow the official DSH profile launcher. - */ -export async function bootDshxRuntime({ - cwd = process.cwd(), - profile, - environment = loadLayeredEnv(DSH_PROFILE_BIN_NAME, cwd), - overlays = [], - home, - watch = true -} = {}) { - const options = { profile, overlays, home }; - const composition = dshxRuntimeProfile(options); - let ctx; - try { - ctx = await boot( - NAME, - composition.rootConfig, - structuredClone(composition.patches), - (hostCtx) => { - hostCtx.provide(DSH_LAUNCH_ENVIRONMENT_KEY, environment); - } - // No bareModuleBaseUrl: match the official CLI so row names resolve - // from the profile directory (Node walks /node_modules then - // the healed $DSH_HOME/profiles/node_modules fallback). Anchoring every - // import to the installation would make third-party surface bundles - // — including ours — unresolvable. - ); - attachPresentationLifetime(ctx); - if (watch) await installProfileWatchers(ctx, options); - return ctx; - } catch (error) { - if (ctx) { - try { - await disposeOfficialContext(ctx); - } catch (disposeError) { - if (error && typeof error === 'object') { - try { Object.defineProperty(error, 'dshxCleanupError', { value: disposeError }); } catch {} - } - } - } - throw error; - } -} - -export const runtimeInternals = { - NAME, - DSH_PROFILE_BIN_NAME, - DEFAULT_PROFILE, - PROFILE_ROOT_FILENAME, - PROFILE_ROOT_CONFIG, - TESTED_DSH_LINE, - reportDshLineCompatibility, - installationAnchor, - selectedProfile, - profileHome, - homePatchPath, - installProfileWatchers, - disposeOfficialContext, - attachPresentationLifetime -}; diff --git a/src/dsh/startup-plugin.mjs b/src/dsh/startup-plugin.mjs index 06e44837..1bd4df3d 100644 --- a/src/dsh/startup-plugin.mjs +++ b/src/dsh/startup-plugin.mjs @@ -5,69 +5,36 @@ import { fileURLToPath } from 'node:url'; import z from '@deepseek-ai/schemastery'; /** - * dshx-startup — the surface's command-line/environment resolution row. - * - * The DSH launcher owns argv parsing at the host boundary and publishes the - * app's inner arguments through `cmdlineArgs`. This row consumes only DSHX's - * private transport selector; every ordinary DSH capability remains owned by - * the hosting profile/composition. + * dshx-startup — resolve the private app-server launch handshake supplied by + * the official DSH launcher. The host owns argv and publishes the immutable + * inner arguments through cmdlineArgs; this row only recognizes DSHX's private + * stdio sentinel and publishes the presentation launch descriptor. */ const PACKAGE_ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../..'); const APP_SERVER_ARG = '--dshx-app-server'; let cachedVersion; -/** Stable Cordis plugin name. */ export const name = 'dshx-startup'; - -/** The official DSH launcher provides the immutable inner argv snapshot. */ export const inject = ['cmdlineArgs']; - -/** Reserved for future static overrides supplied straight from the patch row. */ export const Config = z.object({}); -/** Resolve the package version once from our own manifest. */ export function resolveVersion() { cachedVersion ??= JSON.parse(fs.readFileSync(path.join(PACKAGE_ROOT, 'package.json'), 'utf8')).version; return cachedVersion; } -/** Packaged-binary resolution shared by the migration-era TUI and IPC bridge. */ -export function resolvePackagedBinary(baseName, envValue) { - if (envValue) return envValue; - const fileName = process.platform === 'win32' ? `${baseName}.exe` : baseName; - return path.join(PACKAGE_ROOT, 'dist', 'bin', fileName); -} - -/** - * The app-server selector is an internal handshake between the pinned TUI and - * this surface, not a public DSH CLI grammar. Public surface flags should use - * @deepseek-ai/dsh-cmdline's Commander integration; this sentinel deliberately - * stays dependency-free and exact-match only. - */ export function isStdioAppServerInvocation(cmdlineArgs = []) { return Array.from(cmdlineArgs, String).includes(APP_SERVER_ARG); } -/** Compute the launch descriptor published as the `dshxStartup` service. */ export function resolveLaunchDescriptor(environment = process.env, cmdlineArgs = []) { - const home = path.resolve( - environment.DSHX_TUI_HOME || path.join(os.homedir(), '.dshx', 'codex-tui') - ); - const appServer = isStdioAppServerInvocation(cmdlineArgs); return { cwd: process.cwd(), - home, + home: path.resolve(environment.DSHX_TUI_HOME || path.join(os.homedir(), '.dshx', 'codex-tui')), version: resolveVersion(), - tuiCommand: resolvePackagedBinary('dshx-tui', environment.DSHX_TUI_BIN), - bridgeCommand: resolvePackagedBinary('dshx-ipc-bridge', environment.DSHX_IPC_BRIDGE_BIN), debug: environment.DSHX_DEBUG === '1', - appServer, - // During migration the legacy bridge launch path remains available. The - // stdio app-server invocation is always passive: the parent TUI already - // owns the terminal and this DSH process owns only stdin/stdout JSONL. - attach: !appServer && environment.DSHX_ATTACH === '1' && !environment.DSHX_HEADLESS, - headless: environment.DSHX_HEADLESS === '1' + appServer: isStdioAppServerInvocation(cmdlineArgs) }; } @@ -76,10 +43,8 @@ export function apply(ctx) { const launch = resolveLaunchDescriptor(process.env, cmdlineArgs); fs.mkdirSync(launch.home, { recursive: true, mode: 0o700 }); ctx.provide('dshxStartup', launch); - return undefined; } -/** Bundle-shaped export consumed by the loader through the patch row. */ export const plugin = { name, inject, Config, apply }; export const internals = { @@ -87,6 +52,5 @@ export const internals = { PACKAGE_ROOT, isStdioAppServerInvocation, resolveLaunchDescriptor, - resolvePackagedBinary, resolveVersion }; diff --git a/test/dsh-local-server-close.test.mjs b/test/dsh-local-server-close.test.mjs deleted file mode 100644 index c8ce6136..00000000 --- a/test/dsh-local-server-close.test.mjs +++ /dev/null @@ -1,119 +0,0 @@ -import assert from 'node:assert/strict'; -import { EventEmitter } from 'node:events'; -import { existsSync, mkdtempSync, rmSync } from 'node:fs'; -import { tmpdir } from 'node:os'; -import { dirname, join } from 'node:path'; -import { PassThrough } from 'node:stream'; -import test from 'node:test'; -import { startDshxLocalServer } from '../src/dsh/local-server.mjs'; - -class FakeChild extends EventEmitter { - constructor() { - super(); - this.stdin = new PassThrough(); - this.stdout = new PassThrough(); - this.stderr = new PassThrough(); - this.exitCode = null; - this.signalCode = null; - this.stdin.once('finish', () => this.exit(0, null)); - } - exit(code, signal) { - if (this.exitCode !== null || this.signalCode !== null) return; - this.exitCode = code; - this.signalCode = signal; - queueMicrotask(() => this.emit('exit', code, signal)); - } - kill(signal = 'SIGTERM') { - this.exit(null, signal); - return true; - } -} - -function bridgeSpawner() { - return () => { - const child = new FakeChild(); - queueMicrotask(() => child.stdout.write('{"dshxBridge":"ready"}\n')); - return child; - }; -} - -function deferred() { - let resolve; - const promise = new Promise((done) => { resolve = done; }); - return { promise, resolve }; -} - -test('concurrent close callers await the same shutdown transaction', async () => { - const root = mkdtempSync(join(tmpdir(), 'dshx-ipc-concurrent-close-test-')); - const gate = deferred(); - let adapterCloses = 0; - let disposed = 0; - - class SlowAdapter { - async handle() {} - async close() { - adapterCloses += 1; - await gate.promise; - } - } - - const server = await startDshxLocalServer({ - runtime: { async dispose() { disposed += 1; } }, - Adapter: SlowAdapter, - bridgeCommand: 'fake-dshx-ipc-bridge', - spawnBridge: bridgeSpawner(), - socketRoot: root - }); - const rendezvousDirectory = dirname(server.path); - - try { - const first = server.close(); - const second = server.close(); - assert.equal(first, second); - assert.equal(adapterCloses, 1); - assert.equal(existsSync(rendezvousDirectory), true); - - gate.resolve(); - await Promise.all([first, second]); - assert.equal(adapterCloses, 1); - assert.equal(disposed, 1); - assert.equal(existsSync(rendezvousDirectory), false); - } finally { - gate.resolve(); - rmSync(root, { recursive: true, force: true }); - } -}); - -test('shutdown preserves the first failure while logging later cleanup failures and removing rendezvous state', async () => { - const root = mkdtempSync(join(tmpdir(), 'dshx-ipc-close-root-cause-test-')); - const logs = []; - - class ThrowingAdapter { - async handle() {} - async close() { - throw new Error('primary adapter close failure'); - } - } - - const server = await startDshxLocalServer({ - runtime: { - async dispose() { - throw new Error('secondary DSH dispose failure'); - } - }, - Adapter: ThrowingAdapter, - bridgeCommand: 'fake-dshx-ipc-bridge', - spawnBridge: bridgeSpawner(), - socketRoot: root, - log: (message) => logs.push(message) - }); - const rendezvousDirectory = dirname(server.path); - - try { - await assert.rejects(server.close(), /primary adapter close failure/); - assert.ok(logs.some((message) => message.includes('shutdown cleanup: DSH dispose failed: secondary DSH dispose failure'))); - assert.equal(existsSync(rendezvousDirectory), false); - } finally { - rmSync(root, { recursive: true, force: true }); - } -}); diff --git a/test/dsh-local-server.test.mjs b/test/dsh-local-server.test.mjs deleted file mode 100644 index 37ac1532..00000000 --- a/test/dsh-local-server.test.mjs +++ /dev/null @@ -1,311 +0,0 @@ -import assert from 'node:assert/strict'; -import { EventEmitter } from 'node:events'; -import { existsSync, mkdtempSync, readdirSync, rmSync, writeFileSync } from 'node:fs'; -import { tmpdir } from 'node:os'; -import { dirname, join, win32 } from 'node:path'; -import { PassThrough } from 'node:stream'; -import test from 'node:test'; -import { localServerInternals, startDshxLocalServer } from '../src/dsh/local-server.mjs'; - -class FakeChild extends EventEmitter { - constructor() { - super(); - this.stdin = new PassThrough(); - this.stdout = new PassThrough(); - this.stderr = new PassThrough(); - this.exitCode = null; - this.signalCode = null; - this.killed = false; - this.stdin.once('finish', () => this.exit(0, null)); - } - exit(code, signal) { - if (this.exitCode !== null || this.signalCode !== null) return; - this.exitCode = code; - this.signalCode = signal; - queueMicrotask(() => this.emit('exit', code, signal)); - } - kill(signal = 'SIGTERM') { - this.killed = true; - this.exit(null, signal); - return true; - } -} - -function fakeBridgeSpawner() { - let child; - return { - spawn() { - child = new FakeChild(); - queueMicrotask(() => child.stdout.write('{"dshxBridge":"ready"}\n')); - return child; - }, - child() { - return child; - } - }; -} - -function readJsonLine(stream) { - return new Promise((resolve, reject) => { - let buffer = ''; - const onData = (chunk) => { - buffer += chunk.toString('utf8'); - const newline = buffer.indexOf('\n'); - if (newline < 0) return; - stream.off('data', onData); - try { - resolve(JSON.parse(buffer.slice(0, newline))); - } catch (error) { - reject(error); - } - }; - stream.on('data', onData); - }); -} - -class FakeAdapter { - static closes = 0; - constructor({ send }) { - this.send = send; - } - async handle(message) { - return { response: { id: message.id, result: { echoed: message.method } } }; - } - async close() { - FakeAdapter.closes += 1; - } -} - -test('Windows default local IPC root is anchored below DSHX user presentation home, not TEMP', () => { - const root = localServerInternals.defaultSocketRoot({ - platform: 'win32', - home: 'C:\\Users\\Alice\\.dshx\\codex-tui', - temporaryDirectory: 'C:\\shared-temp', - userHome: 'C:\\Users\\Alice' - }); - assert.equal(root, win32.resolve('C:\\Users\\Alice\\.dshx\\codex-tui', 'i')); - assert.doesNotMatch(root.toLowerCase(), /shared-temp/); -}); - -test('Windows fallback IPC root remains below the current user home when no presentation home is supplied', () => { - const root = localServerInternals.defaultSocketRoot({ - platform: 'win32', - temporaryDirectory: 'C:\\shared-temp', - userHome: 'C:\\Users\\Alice' - }); - assert.equal(root, win32.resolve('C:\\Users\\Alice', '.dshx', 'codex-tui', 'i')); -}); - -test('Windows custom presentation home cannot escape the current user profile ACL boundary', () => { - assert.throws(() => localServerInternals.defaultSocketRoot({ - platform: 'win32', - home: 'C:\\shared-temp\\dshx', - userHome: 'C:\\Users\\Alice' - }), /must remain under the Windows user profile/); - assert.throws(() => localServerInternals.defaultSocketRoot({ - platform: 'win32', - home: 'D:\\dshx', - userHome: 'C:\\Users\\Alice' - }), /must remain under the Windows user profile/); - assert.equal( - localServerInternals.isPathWithin('C:\\Users\\Alice', 'c:\\users\\alice\\.dshx', win32), - true - ); -}); - -test('Windows local IPC path guard measures UTF-8 bytes and reserves the terminating NUL', () => { - const max = localServerInternals.WINDOWS_UNIX_PATH_MAX; - assert.equal(max, 108); - assert.doesNotThrow(() => localServerInternals.assertSocketPathSupported( - `C:\\${'a'.repeat(104)}`, - { platform: 'win32' } - )); - assert.throws(() => localServerInternals.assertSocketPathSupported( - `C:\\${'a'.repeat(105)}`, - { platform: 'win32' } - ), /requires fewer than 108/); - assert.throws(() => localServerInternals.assertSocketPathSupported( - `C:\\${'你'.repeat(35)}`, - { platform: 'win32' } - ), /108 UTF-8 bytes/); -}); - -test('Unix default local IPC root stays in tmp; createSocketDirectory enforces an ephemeral subdirectory', () => { - const root = mkdtempSync(join(tmpdir(), 'dshx-ipc-root-test-')); - try { - assert.equal(localServerInternals.defaultSocketRoot({ platform: 'linux', temporaryDirectory: root }), root); - const child = localServerInternals.createSocketDirectory(root); - assert.match(child, /^.*d-/); - assert.notEqual(child, root); - } finally { - rmSync(root, { recursive: true, force: true }); - } -}); - -test('local production transport exposes only a unix endpoint and relays RPC over bridge stdio', async () => { - let disposed = 0; - FakeAdapter.closes = 0; - const fake = fakeBridgeSpawner(); - const runtime = { async dispose() { disposed += 1; } }; - const server = await startDshxLocalServer({ - runtime, - Adapter: FakeAdapter, - bridgeCommand: 'fake-dshx-ipc-bridge', - spawnBridge: (...args) => fake.spawn(...args) - }); - try { - assert.match(server.url, /^unix:\/\//); - assert.equal('token' in server, false); - - const response = readJsonLine(fake.child().stdin); - fake.child().stdout.write(`${JSON.stringify({ id: 7, method: 'initialize', params: {} })}\n`); - assert.deepEqual(await response, { id: 7, result: { echoed: 'initialize' } }); - } finally { - await server.close(); - } - assert.equal(FakeAdapter.closes, 1); - assert.equal(disposed, 1); -}); - -test('startup rollback disposes DSH, terminates the bridge, and removes rendezvous state when Adapter construction fails', async () => { - const root = mkdtempSync(join(tmpdir(), 'dshx-ipc-adapter-startup-test-')); - const fake = fakeBridgeSpawner(); - let disposed = 0; - class ThrowingAdapter { - constructor() { - throw new Error('synthetic Adapter constructor failure'); - } - } - const runtime = { async dispose() { disposed += 1; } }; - try { - await assert.rejects(startDshxLocalServer({ - runtime, - Adapter: ThrowingAdapter, - bridgeCommand: 'fake-dshx-ipc-bridge', - spawnBridge: (...args) => fake.spawn(...args), - socketRoot: root - }), /synthetic Adapter constructor failure/); - assert.equal(disposed, 1); - assert.ok(fake.child().exitCode !== null || fake.child().signalCode !== null); - assert.deepEqual(readdirSync(root), []); - } finally { - rmSync(root, { recursive: true, force: true }); - } -}); - -test('startup rollback removes the rendezvous directory when official DSH boot fails before bridge spawn', async () => { - const root = mkdtempSync(join(tmpdir(), 'dshx-ipc-boot-startup-test-')); - let spawnCount = 0; - try { - await assert.rejects(startDshxLocalServer({ - bootRuntime: async () => { - throw new Error('synthetic DSH boot failure'); - }, - spawnBridge: () => { - spawnCount += 1; - return new FakeChild(); - }, - socketRoot: root - }), /synthetic DSH boot failure/); - assert.equal(spawnCount, 0); - assert.deepEqual(readdirSync(root), []); - } finally { - rmSync(root, { recursive: true, force: true }); - } -}); - -test('startup rollback disposes an injected runtime when socket-root creation fails and preserves the filesystem error', async () => { - const parent = mkdtempSync(join(tmpdir(), 'dshx-ipc-root-failure-test-')); - const blockedRoot = join(parent, 'not-a-directory'); - writeFileSync(blockedRoot, 'block mkdir'); - let disposed = 0; - const runtime = { async dispose() { disposed += 1; } }; - try { - await assert.rejects(startDshxLocalServer({ - runtime, - socketRoot: blockedRoot - }), (error) => { - assert.ok(['EEXIST', 'ENOTDIR'].includes(error?.code), `unexpected error code: ${error?.code}`); - return true; - }); - assert.equal(disposed, 1); - assert.equal(existsSync(blockedRoot), true); - } finally { - rmSync(parent, { recursive: true, force: true }); - } -}); - -test('startup rollback keeps the original failure when DSH disposal also fails', async () => { - const root = mkdtempSync(join(tmpdir(), 'dshx-ipc-double-failure-test-')); - const fake = fakeBridgeSpawner(); - const logs = []; - class ThrowingAdapter { - constructor() { - throw new Error('primary startup failure'); - } - } - const runtime = { - async dispose() { - throw new Error('secondary dispose failure'); - } - }; - try { - await assert.rejects(startDshxLocalServer({ - runtime, - Adapter: ThrowingAdapter, - bridgeCommand: 'fake-dshx-ipc-bridge', - spawnBridge: (...args) => fake.spawn(...args), - socketRoot: root, - log: (message) => logs.push(message) - }), /primary startup failure/); - assert.ok(logs.some((message) => message.includes('startup rollback: DSH dispose failed: secondary dispose failure'))); - assert.deepEqual(readdirSync(root), []); - } finally { - rmSync(root, { recursive: true, force: true }); - } -}); - -test('close removes the private rendezvous directory even when DSH disposal fails', async () => { - const root = mkdtempSync(join(tmpdir(), 'dshx-ipc-close-test-')); - const fake = fakeBridgeSpawner(); - const runtime = { - async dispose() { - throw new Error('synthetic DSH dispose failure'); - } - }; - const server = await startDshxLocalServer({ - runtime, - Adapter: FakeAdapter, - bridgeCommand: 'fake-dshx-ipc-bridge', - spawnBridge: (...args) => fake.spawn(...args), - socketRoot: root - }); - const rendezvousDirectory = dirname(server.path); - assert.equal(existsSync(rendezvousDirectory), true); - try { - await assert.rejects(server.close(), /synthetic DSH dispose failure/); - assert.equal(existsSync(rendezvousDirectory), false); - } finally { - rmSync(root, { recursive: true, force: true }); - } -}); - -test('local production transport returns JSON-RPC parse errors through bridge stdio', async () => { - const fake = fakeBridgeSpawner(); - const runtime = { async dispose() {} }; - const server = await startDshxLocalServer({ - runtime, - Adapter: FakeAdapter, - bridgeCommand: 'fake-dshx-ipc-bridge', - spawnBridge: (...args) => fake.spawn(...args) - }); - try { - const response = readJsonLine(fake.child().stdin); - fake.child().stdout.write('{not-json}\n'); - const parsed = await response; - assert.equal(parsed.id, null); - assert.equal(parsed.error.code, -32700); - } finally { - await server.close(); - } -}); diff --git a/test/dsh-runtime-boot.test.mjs b/test/dsh-runtime-boot.test.mjs deleted file mode 100644 index 8ba56c9d..00000000 --- a/test/dsh-runtime-boot.test.mjs +++ /dev/null @@ -1,182 +0,0 @@ -import assert from 'node:assert/strict'; -import { mkdtempSync, mkdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs'; -import { tmpdir } from 'node:os'; -import { dirname, join } from 'node:path'; -import test from 'node:test'; -import { dshxRuntimeEntries, dshxRuntimeProfile, runtimeInternals } from '../src/dsh/runtime-boot.mjs'; - -function temporaryDshHome(run) { - const home = mkdtempSync(join(tmpdir(), 'dshx-profile-test-')); - try { - return run(home); - } finally { - rmSync(home, { recursive: true, force: true }); - } -} - -/** - * Replicate the official `initProfile` skeleton (the documented format written - * by `dsh plugin --profile ` on first use) so composition tests can - * target the non-template `tui` profile without running pnpm. - */ -function seedSurfaceProfile(home) { - const dir = join(home, 'profiles', 'tui'); - mkdirSync(dir, { recursive: true }); - writeFileSync( - join(dir, 'package.json'), - `${JSON.stringify({ - name: 'dsh-profile-tui', - private: true, - dependencies: {}, - dsh: { profile: { bundles: ['@deepseek-ai/dsh-base'] } } - }, null, 2)}\n` - ); - writeFileSync(join(dir, 'cordis.patch.yml'), '[]\n'); - writeFileSync(join(dir, 'pnpm-workspace.yaml'), 'packages:\n - .\nnodeLinker: hoisted\nautoInstallPeers: false\n'); - return dir; -} - -test('runtime targets the tui surface profile over the official dsh-base layer', () => { - temporaryDshHome((home) => { - assert.equal(runtimeInternals.DEFAULT_PROFILE, 'tui'); - seedSurfaceProfile(home); - const composition = dshxRuntimeProfile({ home }); - assert.equal(composition.name, 'tui'); - - const manifest = JSON.parse(readFileSync(join(home, 'profiles', 'tui', 'package.json'), 'utf8')); - assert.deepEqual(manifest.dsh.profile.bundles, ['@deepseek-ai/dsh-base']); - - assert.equal( - readFileSync(composition.rootConfig, 'utf8'), - runtimeInternals.PROFILE_ROOT_CONFIG, - 'DSHX may only rewrite the same empty Loader root role used by official dsh' - ); - - const entries = dshxRuntimeEntries({ home }); - const byId = new Map(entries.map((entry) => [entry.id, entry])); - // The surface rows come exclusively from the installed bundle; an empty - // dsh-base-only profile must not fabricate them here. - assert.equal(byId.get('dshx-presentation'), undefined); - assert.equal(byId.get('dshx-startup'), undefined); - }); -}); - -test('bundle patch declares the surface rows and locks the competing runner', () => { - const source = readFileSync(new URL('../cordis.patch.yml', import.meta.url), 'utf8'); - assert.match(source, /id: headless-startup/); - assert.match(source, /id: headless-runner/); - assert.match(source, /name: '@code-new-bie\/dshx-tui\/startup'/); - assert.match(source, /name: '@code-new-bie\/dshx-tui\/presentation'/); - assert.match(source, /inject: \[dshxStartup\]/); - // Locks carry no config: a targeted patch replaces a row's whole config, - // so any config key here would silently wipe the official row settings. - assert.doesNotMatch(source, /- id: headless-(startup|runner)\n\s+config:/); - - const manifest = JSON.parse(readFileSync(new URL('../package.json', import.meta.url), 'utf8')); - assert.equal(manifest.dsh?.bundle?.patch, './cordis.patch.yml'); - assert.equal(manifest.exports['./presentation'], './src/dsh/presentation-plugin.mjs'); - assert.equal(manifest.exports['./startup'], './src/dsh/startup-plugin.mjs'); - assert.ok(manifest.peerDependencies['@deepseek-ai/dsh']); - // Single-instance rule: dsh runtime packages must never become real - // dependencies, or the profile copy shadows the healed installation - // symlinks and splits every service registry in two. - assert.equal(manifest.dependencies['@deepseek-ai/dsh'], undefined); -}); - -test('profile-local and DSH-home user patch layers remain authoritative and byte-for-byte untouched', () => { - temporaryDshHome((home) => { - seedSurfaceProfile(home); - const initial = dshxRuntimeProfile({ home }); - const profilePatchPath = initial.profile.patchPath; - const homePatchPath = initial.homePatchPath; - const profilePatch = `# user profile layer - DSHX must never rewrite this byte stream\n- id: tools\n config:\n dshxProfileProbe: profile\n`; - const homePatch = `# machine DSH layer - DSHX must never rewrite this byte stream\n- id: llm\n config:\n dshxHomeProbe: home\n`; - writeFileSync(profilePatchPath, profilePatch); - writeFileSync(homePatchPath, homePatch); - - const entries = dshxRuntimeEntries({ home }); - // The user layers apply verbatim even when they reference rows the - // current bundle stack does not provide: unmatched targeted patches are - // warn-and-skip by design (applyEntryPatches semantics). - assert.ok(Array.isArray(entries)); - - assert.equal(readFileSync(profilePatchPath, 'utf8'), profilePatch); - assert.equal(readFileSync(homePatchPath, 'utf8'), homePatch); - assert.equal(readFileSync(initial.rootConfig, 'utf8'), runtimeInternals.PROFILE_ROOT_CONFIG); - }); -}); - -test('recomposition rewrites only the generated empty root, never either user patch layer', () => { - temporaryDshHome((home) => { - seedSurfaceProfile(home); - const initial = dshxRuntimeProfile({ home }); - const profilePatch = '- id: tools\n config: { probe: keep-profile }\n'; - const homePatch = '- id: llm\n config: { probe: keep-home }\n'; - writeFileSync(initial.profile.patchPath, profilePatch); - writeFileSync(initial.homePatchPath, homePatch); - writeFileSync(initial.rootConfig, 'this is generated state and must be reset\n'); - - const recomposed = dshxRuntimeProfile({ home }); - assert.equal(readFileSync(recomposed.rootConfig, 'utf8'), runtimeInternals.PROFILE_ROOT_CONFIG); - assert.equal(readFileSync(recomposed.profile.patchPath, 'utf8'), profilePatch); - assert.equal(readFileSync(recomposed.homePatchPath, 'utf8'), homePatch); - }); -}); - -test('missing surface profile fails loud instead of silently composing nothing', () => { - temporaryDshHome((home) => { - assert.throws( - () => dshxRuntimeProfile({ home }), - /plugin|Cannot find|ENOENT|profile/i, - 'the official loadProfile contract refuses unknown profiles' - ); - }); -}); - -test('untested DSH lines warn once and proceed; the tested line stays silent', () => { - temporaryDshHome((home) => { - seedSurfaceProfile(home); - const fake = join(home, 'fake-dsh', 'package.json'); - mkdirSync(dirname(fake), { recursive: true }); - writeFileSync(fake, JSON.stringify({ name: '@deepseek-ai/dsh', version: '9.9.9-unheard-of' })); - - // Ecosystem convention: bundles never block the host. A mismatch warns - // exactly once with both versions, then lets every boot proceed. - const warnings = []; - const first = runtimeInternals.reportDshLineCompatibility(fake, (m) => warnings.push(m)); - assert.equal(first.compatible, false); - assert.equal(first.installed, '9.9.9-unheard-of'); - runtimeInternals.reportDshLineCompatibility(fake, (m) => warnings.push(m)); - assert.equal(warnings.length, 1, 'warn-once per process'); - assert.match(warnings[0], new RegExp(`${runtimeInternals.TESTED_DSH_LINE}.*9\\.9\\.9-unheard-of|9\\.9\\.9-unheard-of.*${runtimeInternals.TESTED_DSH_LINE}`)); - assert.match(warnings[0], /proceeding/); - - // The tested line itself is silent and reports plain compatibility. - const quiet = []; - const real = runtimeInternals.reportDshLineCompatibility( - new URL('../node_modules/@deepseek-ai/dsh/package.json', import.meta.url), - (m) => quiet.push(m) - ); - assert.equal(real.compatible, true); - assert.deepEqual(quiet, []); - }); -}); - -test('presentation lifetime delegates disposal to the official DSH root Fiber', async () => { - let disposals = 0; - const ctx = { - fiber: { - async dispose() { - disposals += 1; - } - } - }; - - const decorated = runtimeInternals.attachPresentationLifetime(ctx); - assert.equal(decorated, ctx); - assert.equal(typeof ctx.dispose, 'function'); - assert.equal(Object.prototype.propertyIsEnumerable.call(ctx, 'dispose'), false); - - await ctx.dispose(); - assert.equal(disposals, 1); -}); diff --git a/test/dshx-presentation-plugin.test.mjs b/test/dshx-presentation-plugin.test.mjs index b1a6ec26..1831c1c1 100644 --- a/test/dshx-presentation-plugin.test.mjs +++ b/test/dshx-presentation-plugin.test.mjs @@ -1,5 +1,4 @@ import assert from 'node:assert/strict'; -import { EventEmitter } from 'node:events'; import { readFileSync } from 'node:fs'; import test from 'node:test'; import { fileURLToPath } from 'node:url'; @@ -23,12 +22,8 @@ const LAUNCH = { cwd: '/workspace', home: '/home/test/.dshx/codex-tui', version: 'test', - tuiCommand: '/dist/bin/dshx-tui', - bridgeCommand: '/dist/bin/dshx-ipc-bridge', debug: true, - appServer: false, - attach: false, - headless: false + appServer: true }; function fakeContext(launch = LAUNCH, onExit = () => {}) { @@ -41,15 +36,14 @@ function fakeContext(launch = LAUNCH, onExit = () => {}) { return { ctx, provided }; } -test('both rows export the Cordis plugin contract with named exports only', () => { +test('both rows expose named Cordis plugin contracts', () => { assert.equal(startupName, 'dshx-startup'); assert.deepEqual(startupInject, ['cmdlineArgs']); assert.equal(typeof startupConfig, 'function'); assert.equal(startupPlugin.name, startupName); - assert.equal(typeof startupPlugin.apply, 'function'); assert.equal(name, 'dshx-presentation'); - assert.deepEqual(inject, ['dshxStartup'], 'transport inputs flow exclusively via the startup row'); + assert.deepEqual(inject, ['dshxStartup']); assert.equal(typeof Config, 'function'); assert.equal(plugin.name, name); assert.deepEqual(plugin.inject, inject); @@ -63,70 +57,35 @@ test('both rows export the Cordis plugin contract with named exports only', () = } }); -test('startup row reads the official cmdlineArgs service and selects stdio app-server mode', () => { +test('startup consumes the official cmdlineArgs service and selects stdio mode', () => { const provided = new Map(); const ctx = { cmdlineArgs: { get: () => ['--dshx-app-server'] }, provide: (key, value) => provided.set(key, value) }; - const previous = { ...process.env }; + const previous = process.env.DSHX_TUI_HOME; process.env.DSHX_TUI_HOME = '/tmp/dshx-launch-home'; - process.env.DSHX_IPC_BRIDGE_BIN = '/opt/bridge-custom'; - process.env.DSHX_ATTACH = '1'; - process.env.DSHX_DEBUG = '1'; try { startupPlugin.apply(ctx); const launch = provided.get('dshxStartup'); assert.equal(launch.home, '/tmp/dshx-launch-home'); - assert.equal(launch.bridgeCommand, '/opt/bridge-custom'); - assert.equal(launch.debug, true); assert.equal(launch.appServer, true); - assert.equal(launch.attach, false, 'stdio child owns no terminal attachment'); assert.equal(launch.version, JSON.parse(readFileSync(new URL('../package.json', import.meta.url), 'utf8')).version); - assert.equal(typeof launch.tuiCommand, 'string'); assert.equal(startupInternals.isStdioAppServerInvocation(['--other']), false); + assert.equal('bridgeCommand' in launch, false); + assert.equal('tuiCommand' in launch, false); } finally { - process.env = previous; + if (previous === undefined) delete process.env.DSHX_TUI_HOME; + else process.env.DSHX_TUI_HOME = previous; } }); -test('presentation row starts the legacy transport from the injected startup service', async () => { - const { ctx, provided } = fakeContext(); - let closed = 0; - const started = []; - const originalStart = internals.start; - internals.start = async (options) => { - started.push(options); - return { path: '/tmp/dshx-i/d-XXXX/s', url: 'unix:///tmp/dshx-i/d-XXXX/s', close: async () => { closed += 1; } }; - }; - try { - const dispose = await plugin.apply(ctx, {}); - assert.equal(started.length, 1); - assert.equal(started[0].runtime, ctx, 'plugin must never boot a second runtime'); - assert.equal(started[0].disposeRuntimeOnClose, false, 'root-fiber disposal stays owned by the composition'); - assert.equal(started[0].home, LAUNCH.home); - assert.equal(started[0].bridgeCommand, LAUNCH.bridgeCommand); - - const service = provided.get(SERVICE_KEY); - assert.equal(service.mode, 'bridge'); - assert.equal(service.url, 'unix:///tmp/dshx-i/d-XXXX/s'); - assert.equal(service.tuiCommand, LAUNCH.tuiCommand); - assert.equal(typeof service.close, 'function'); - - await dispose(); - assert.equal(closed, 1, 'the returned disposer closes the transport exactly once'); - } finally { - internals.start = originalStart; - } -}); - -test('stdio app-server mode binds directly to the live DSH Context and exits through appExit on EOF', async () => { +test('presentation binds stdio directly to the live DSH Context and exits through appExit', async () => { const exits = []; - const launch = { ...LAUNCH, appServer: true }; - const { ctx, provided } = fakeContext(launch, (code) => exits.push(code)); + const { ctx, provided } = fakeContext(LAUNCH, (code) => exits.push(code)); const started = []; let closed = 0; - const originalStartStdio = internals.startStdio; + const original = internals.startStdio; internals.startStdio = (options) => { started.push(options); return { mode: 'stdio', close: async () => { closed += 1; } }; @@ -134,60 +93,30 @@ test('stdio app-server mode binds directly to the live DSH Context and exits thr try { const dispose = await plugin.apply(ctx, {}); assert.equal(started.length, 1); - assert.equal(started[0].ctx, ctx); + assert.equal(started[0].ctx, ctx, 'the row must use the already-mounted composition'); assert.equal(started[0].home, LAUNCH.home); assert.equal(typeof started[0].onEof, 'function'); + const service = provided.get(SERVICE_KEY); assert.equal(service.mode, 'stdio'); assert.equal(service.url, undefined); + assert.equal(typeof service.close, 'function'); started[0].onEof(); assert.deepEqual(exits, [0]); await dispose(); assert.equal(closed, 1); } finally { - internals.startStdio = originalStartStdio; + internals.startStdio = original; } }); -test('interactive legacy attachment does not block Cordis mount completion', async () => { - const exits = []; - const launch = { ...LAUNCH, attach: true, tuiCommand: process.execPath }; - const { ctx, provided } = fakeContext(launch, (code) => exits.push(code)); - const child = new EventEmitter(); - child.killed = false; - child.kill = () => { child.killed = true; }; - - const originalStart = internals.start; - const originalSpawn = internals.spawn; - const originalInteractive = internals.isInteractive; - internals.start = async () => ({ path: '/tmp/s', url: 'unix:///tmp/s', close: async () => {} }); - internals.spawn = () => child; - internals.isInteractive = () => true; - try { - const dispose = await plugin.apply(ctx, {}); - assert.equal(typeof dispose, 'function', 'plugin mount completes while the TUI is still running'); - assert.equal(provided.get(SERVICE_KEY).mode, 'bridge'); - assert.equal(typeof provided.get(SERVICE_KEY).tuiExit?.then, 'function'); - - child.emit('exit', 0, null); - await new Promise((resolve) => setImmediate(resolve)); - assert.deepEqual(exits, [0]); - await dispose(); - } finally { - internals.start = originalStart; - internals.spawn = originalSpawn; - internals.isInteractive = originalInteractive; - } +test('presentation rejects accidental non-app-server profile launches', async () => { + const { ctx } = fakeContext({ ...LAUNCH, appServer: false }); + await assert.rejects(() => plugin.apply(ctx, {}), /launch it through `dshx`/); }); -test('presentation row refuses contexts without the Cordis provide() seam or the startup service', async () => { - await assert.rejects( - () => plugin.apply({}, {}), - /requires a Cordis Context with provide/ - ); - await assert.rejects( - () => plugin.apply({ provide: () => {} }, {}), - /requires the dshxStartup service/ - ); +test('presentation refuses contexts without the Cordis seams', async () => { + await assert.rejects(() => plugin.apply({}, {}), /requires a Cordis Context with provide/); + await assert.rejects(() => plugin.apply({ provide: () => {} }, {}), /requires the dshxStartup service/); }); diff --git a/test/tui_smoke.py b/test/tui_smoke.py index c49f9ea0..b7d2fba9 100644 --- a/test/tui_smoke.py +++ b/test/tui_smoke.py @@ -2,7 +2,6 @@ import json import os import pathlib -import subprocess import tempfile import time @@ -10,26 +9,12 @@ ROOT = pathlib.Path(__file__).resolve().parents[1] PROMPT = "你好,DSHX PTY resize" -# Ratatui redraws a line with cursor-addressing writes. On some terminals/runners, -# the visible prompt can therefore arrive as multiple printable spans separated by -# ANSI cursor moves rather than one contiguous raw PTY substring. Validate the -# visible content in order without weakening the CJK/ASCII prompt contract. PROMPT_TOKENS = ("你", "好", ",", "DSHX", "PTY", "resize") EXPECTED_TUI_VERSION = os.environ.get("DSHX_VERSION", "1.0.0-ci") EXPECTED_MODEL_DISPLAY_NAME = "DSHX Protocol Stub" trace_fd, trace_name = tempfile.mkstemp(prefix="dshx-protocol-trace-", suffix=".jsonl") os.close(trace_fd) trace_path = pathlib.Path(trace_name) -server_env = os.environ.copy() -server_env["DSHX_STUB_TRACE_FILE"] = str(trace_path) -server = subprocess.Popen( - ["node", "bin/dshx-stub-local.mjs"], - cwd=ROOT, - env=server_env, - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, - text=True, -) def wait_for_protocol_notification(method, timeout=10): @@ -55,7 +40,6 @@ def wait_for_protocol_notification(method, timeout=10): def expect_rendered_tokens(child, tokens): - """Consume printable tokens in visible order while tolerating ANSI redraws between them.""" rendered = [] for token in tokens: child.expect_exact(token) @@ -64,11 +48,6 @@ def expect_rendered_tokens(child, tokens): try: - endpoint = server.stdout.readline().strip() - if not endpoint.startswith("unix://"): - stderr = server.stderr.read() - raise RuntimeError(f"local stub did not produce a unix endpoint: {endpoint!r}\n{stderr}") - binary = ROOT / "dist" / "bin" / "dshx-tui" if not binary.exists(): raise RuntimeError(f"built TUI missing: {binary}") @@ -78,11 +57,12 @@ def expect_rendered_tokens(child, tokens): env.update({ "TERM": "xterm-256color", "CODEX_HOME": codex_home, - "DSHX_APP_SERVER_ENDPOINT": endpoint, - # pexpect provides a PTY transport, not a terminal emulator that can - # negotiate kitty keyboard enhancement modes. Use Codex's supported - # fallback so this gate measures TUI/local-IPC/CJK/resize behavior - # consistently on Linux and macOS rather than terminal emulation. + "DSHX_STUB_TRACE_FILE": str(trace_path), + "DSHX_APP_SERVER_CMD": json.dumps([ + os.environ.get("NODE", "node"), + str(ROOT / "bin" / "dshx-stub-local.mjs"), + ]), + # pexpect is a PTY transport rather than a full terminal emulator. "CODEX_TUI_DISABLE_KEYBOARD_ENHANCEMENT": "1", }) child = pexpect.spawn( @@ -95,43 +75,24 @@ def expect_rendered_tokens(child, tokens): ) transcript = [] try: - # Ratatui can place ANSI style transitions between the product name - # and the version suffix. Assert them independently so the smoke - # validates visible content rather than terminal styling bytes. child.expect("DeepSeek Harness") transcript.append(child.before + child.after) child.expect(f"v{EXPECTED_TUI_VERSION}") transcript.append(child.before + child.after) wait_for_protocol_notification("thread/started") - # Startup is asynchronous: thread/started can arrive while the model - # banner still says "loading". Wait for the human-readable model label, - # not the provider-aware internal wire id. child.expect(EXPECTED_MODEL_DISPLAY_NAME) transcript.append(child.before + child.after) rendered_startup = "".join(transcript) if "v0.0.0" in rendered_startup: - raise AssertionError( - "Codex crate version leaked into DSHX startup presentation:\n" + rendered_startup - ) + raise AssertionError("Codex crate version leaked into DSHX startup presentation:\n" + rendered_startup) if "dshx:Wy" in rendered_startup: - raise AssertionError( - "opaque DSHX model wire id leaked into TUI presentation:\n" + rendered_startup - ) + raise AssertionError("opaque DSHX model wire id leaked into TUI presentation:\n" + rendered_startup) + child.setwinsize(40, 100) child.send(PROMPT) - # A PTY write completing does not mean the TUI has consumed the - # bytes. On slower macOS runners, a fixed delay measured from write - # completion can expire while the prompt is still queued, making - # Enter arrive immediately after the paste-like burst is processed. - # Wait until every visible CJK/ASCII prompt token has been rendered - # in order. Cursor-addressing escape sequences may occur between - # tokens, so raw contiguous-string matching is intentionally wrong. transcript.append(expect_rendered_tokens(child, PROMPT_TOKENS)) time.sleep(0.25) child.send("\r") - # "received:" is unique to the stub response, so it establishes that - # the submitted turn reached the TUI response path. Then verify the - # echoed prompt using the same rendered-token semantics as the input. child.expect_exact("received:") transcript.append(child.before + child.after) transcript.append(expect_rendered_tokens(child, PROMPT_TOKENS)) @@ -139,17 +100,11 @@ def expect_rendered_tokens(child, tokens): transcript.append(child.before or "") trace = trace_path.read_text(encoding="utf-8") if trace_path.exists() else "" raise AssertionError( - "Pinned DSHX TUI local-IPC/CJK/resize smoke failed.\n" + "Pinned DSHX TUI stdio/CJK/resize smoke failed.\n" f"Protocol trace:\n{trace}\n" "Transcript:\n" + "".join(transcript) ) finally: child.close(force=True) finally: - server.terminate() - try: - server.wait(timeout=5) - except subprocess.TimeoutExpired: - server.kill() - server.wait(timeout=5) trace_path.unlink(missing_ok=True) diff --git a/upstream/patches/codex/0001-dshx-force-ui-backend.patch b/upstream/patches/codex/0001-dshx-force-ui-backend.patch index f2a8bb2c..43bad9a9 100644 --- a/upstream/patches/codex/0001-dshx-force-ui-backend.patch +++ b/upstream/patches/codex/0001-dshx-force-ui-backend.patch @@ -1,20 +1,13 @@ diff --git a/codex-rs/tui/src/main.rs b/codex-rs/tui/src/main.rs --- a/codex-rs/tui/src/main.rs +++ b/codex-rs/tui/src/main.rs -@@ -1,10 +1,12 @@ +@@ -1,4 +1,5 @@ use clap::Parser; +use codex_app_server_client::RemoteAppServerEndpoint; use codex_arg0::Arg0DispatchPaths; use codex_arg0::arg0_dispatch_or_else; use codex_config::LoaderOverrides; - use codex_tui::AppExitInfo; - use codex_tui::Cli; - use codex_tui::ExitReason; -+use codex_tui::resolve_remote_addr; - use codex_tui::run_main; - use codex_utils_cli::CliConfigOverrides; - use std::io::Write; -@@ -47,6 +49,42 @@ fn main() -> anyhow::Result<()> { +@@ -47,6 +48,42 @@ fn main() -> anyhow::Result<()> { inner .config_overrides .raw_overrides @@ -35,25 +28,19 @@ diff --git a/codex-rs/tui/src/main.rs b/codex-rs/tui/src/main.rs + other => anyhow::bail!("invalid DSHX_RESUME_MODE: {other}"), + } + } -+ let dshx_endpoint = std::env::var("DSHX_APP_SERVER_ENDPOINT").map_err(|_| { ++ let dshx_command_json = std::env::var("DSHX_APP_SERVER_CMD").map_err(|_| { + anyhow::anyhow!( -+ "DSHX_APP_SERVER_ENDPOINT is required; DSHX never falls back to the Codex agent runtime" ++ "DSHX_APP_SERVER_CMD is required; DSHX never falls back to the Codex agent runtime" + ) + })?; -+ let dshx_token = std::env::var("DSHX_APP_SERVER_TOKEN").map_err(|_| { -+ anyhow::anyhow!( -+ "DSHX_APP_SERVER_TOKEN is required; DSHX local transport is always authenticated" -+ ) -+ })?; -+ let mut dshx_endpoint = resolve_remote_addr(&dshx_endpoint)?; -+ match &mut dshx_endpoint { -+ RemoteAppServerEndpoint::WebSocket { auth_token, .. } => { -+ *auth_token = Some(dshx_token); -+ } -+ RemoteAppServerEndpoint::UnixSocket { .. } => { -+ anyhow::bail!("DSHX production launcher requires authenticated loopback WebSocket transport") -+ } ++ let dshx_command: Vec = serde_json::from_str(&dshx_command_json) ++ .map_err(|err| anyhow::anyhow!("invalid DSHX_APP_SERVER_CMD JSON: {err}"))?; ++ if dshx_command.is_empty() || dshx_command[0].is_empty() { ++ anyhow::bail!("DSHX_APP_SERVER_CMD must contain a non-empty executable argv[0]"); + } ++ let dshx_endpoint = RemoteAppServerEndpoint::StdioChild { ++ command: dshx_command, ++ }; let exit_info = run_main( inner, arg0_paths, diff --git a/upstream/patches/codex/0010-dshx-local-ipc-bridge.patch b/upstream/patches/codex/0010-dshx-local-ipc-bridge.patch deleted file mode 100644 index 153d959a..00000000 --- a/upstream/patches/codex/0010-dshx-local-ipc-bridge.patch +++ /dev/null @@ -1,187 +0,0 @@ -diff --git a/codex-rs/Cargo.lock b/codex-rs/Cargo.lock ---- a/codex-rs/Cargo.lock -+++ b/codex-rs/Cargo.lock -@@ -4250,16 +4250,18 @@ - [[package]] - name = "codex-stdio-to-uds" - version = "0.0.0" - dependencies = [ - "anyhow", - "codex-uds", - "codex-utils-cargo-bin", -+ "futures", - "pretty_assertions", - "tempfile", - "tokio", -+ "tokio-tungstenite", - ] - - [[package]] - name = "codex-terminal-detection" - version = "0.0.0" - dependencies = [ -diff --git a/codex-rs/stdio-to-uds/Cargo.toml b/codex-rs/stdio-to-uds/Cargo.toml ---- a/codex-rs/stdio-to-uds/Cargo.toml -+++ b/codex-rs/stdio-to-uds/Cargo.toml -@@ -7,6 +7,10 @@ - [[bin]] - name = "codex-stdio-to-uds" - path = "src/main.rs" -+ -+[[bin]] -+name = "dshx-ipc-bridge" -+path = "src/dshx_ipc_bridge.rs" - - [lib] - name = "codex_stdio_to_uds" -@@ -20,12 +24,14 @@ - [dependencies] - anyhow = { workspace = true } - codex-uds = { workspace = true } -+futures = { workspace = true } - tokio = { workspace = true, features = [ - "io-std", - "io-util", - "macros", - "rt-multi-thread", - ] } -+tokio-tungstenite = { workspace = true } - - [dev-dependencies] - codex-utils-cargo-bin = { workspace = true } -diff --git a/codex-rs/stdio-to-uds/src/dshx_ipc_bridge.rs b/codex-rs/stdio-to-uds/src/dshx_ipc_bridge.rs -new file mode 100644 ---- /dev/null -+++ b/codex-rs/stdio-to-uds/src/dshx_ipc_bridge.rs -@@ -0,0 +1,101 @@ -+#![deny(clippy::print_stdout)] -+ -+use std::io::ErrorKind; -+use std::path::PathBuf; -+ -+use anyhow::Context; -+use codex_uds::UnixListener; -+use futures::SinkExt; -+use futures::StreamExt; -+use tokio::io::AsyncBufReadExt; -+use tokio::io::AsyncWriteExt; -+use tokio::io::BufReader; -+use tokio_tungstenite::accept_async; -+use tokio_tungstenite::tungstenite::Message; -+ -+struct SocketGuard(PathBuf); -+ -+impl Drop for SocketGuard { -+ fn drop(&mut self) { -+ if let Err(err) = std::fs::remove_file(&self.0) -+ && err.kind() != ErrorKind::NotFound -+ { -+ // Best effort only. The launcher removes the unique parent directory. -+ } -+ } -+} -+ -+async fn write_line(stdout: &mut tokio::io::Stdout, line: &str) -> anyhow::Result<()> { -+ stdout.write_all(line.as_bytes()).await?; -+ stdout.write_all(b"\n").await?; -+ stdout.flush().await?; -+ Ok(()) -+} -+ -+#[tokio::main] -+async fn main() -> anyhow::Result<()> { -+ let mut args = std::env::args_os().skip(1); -+ let Some(first) = args.next() else { -+ anyhow::bail!("usage: dshx-ipc-bridge "); -+ }; -+ if first == std::ffi::OsStr::new("--check") { -+ return Ok(()); -+ } -+ if args.next().is_some() { -+ anyhow::bail!("usage: dshx-ipc-bridge "); -+ } -+ -+ let socket_path = PathBuf::from(first); -+ if let Some(parent) = socket_path.parent() { -+ codex_uds::prepare_private_socket_directory(parent) -+ .await -+ .with_context(|| format!("failed to prepare {}", parent.display()))?; -+ } -+ let mut listener = UnixListener::bind(&socket_path) -+ .await -+ .with_context(|| format!("failed to bind {}", socket_path.display()))?; -+ let _guard = SocketGuard(socket_path.clone()); -+ -+ // Stdout is a private JSONL control channel to the Node presentation adapter. -+ // Never log to stdout from this process. -+ let mut stdout = tokio::io::stdout(); -+ write_line(&mut stdout, r#"{"dshxBridge":"ready"}"#).await?; -+ -+ let stream = listener -+ .accept() -+ .await -+ .with_context(|| format!("failed to accept {}", socket_path.display()))?; -+ let mut websocket = accept_async(stream) -+ .await -+ .context("failed to upgrade local DSHX IPC connection")?; -+ let mut stdin_lines = BufReader::new(tokio::io::stdin()).lines(); -+ -+ loop { -+ tokio::select! { -+ incoming = websocket.next() => { -+ match incoming { -+ Some(Ok(Message::Text(text))) => write_line(&mut stdout, &text.to_string()).await?, -+ Some(Ok(Message::Binary(bytes))) => { -+ let text = String::from_utf8(bytes.to_vec()).context("binary IPC frame was not UTF-8")?; -+ write_line(&mut stdout, &text).await?; -+ } -+ Some(Ok(Message::Ping(payload))) => websocket.send(Message::Pong(payload)).await?, -+ Some(Ok(Message::Close(_))) | None => break, -+ Some(Ok(_)) => {} -+ Some(Err(err)) => return Err(err).context("local DSHX IPC websocket failed"), -+ } -+ } -+ outbound = stdin_lines.next_line() => { -+ match outbound? { -+ Some(line) => websocket.send(Message::Text(line.into())).await?, -+ None => { -+ websocket.close(None).await?; -+ break; -+ } -+ } -+ } -+ } -+ } -+ -+ Ok(()) -+} -diff --git a/codex-rs/tui/src/main.rs b/codex-rs/tui/src/main.rs ---- a/codex-rs/tui/src/main.rs -+++ b/codex-rs/tui/src/main.rs -@@ -72,19 +72,13 @@ - "DSHX_APP_SERVER_ENDPOINT is required; DSHX never falls back to the Codex agent runtime" - ) - })?; -- let dshx_token = std::env::var("DSHX_APP_SERVER_TOKEN").map_err(|_| { -- anyhow::anyhow!( -- "DSHX_APP_SERVER_TOKEN is required; DSHX local transport is always authenticated" -- ) -- })?; -- let mut dshx_endpoint = resolve_remote_addr(&dshx_endpoint)?; -- match &mut dshx_endpoint { -- RemoteAppServerEndpoint::WebSocket { auth_token, .. } => { -- *auth_token = Some(dshx_token); -- } -- RemoteAppServerEndpoint::UnixSocket { .. } => { -- anyhow::bail!("DSHX production launcher requires authenticated loopback WebSocket transport") -- } -+ let dshx_endpoint = resolve_remote_addr(&dshx_endpoint) -+ .map_err(|err| anyhow::anyhow!("{err:#}"))?; -+ match &dshx_endpoint { -+ RemoteAppServerEndpoint::WebSocket { .. } => anyhow::bail!( -+ "DSHX production launcher forbids TCP WebSocket transport; use the packaged local IPC bridge" -+ ), -+ RemoteAppServerEndpoint::UnixSocket { .. } => {} - } - let exit_info = run_main( - inner, diff --git a/upstream/patches/codex/0010-dshx-stdio-backend.patch b/upstream/patches/codex/0010-dshx-stdio-backend.patch new file mode 100644 index 00000000..52fbf2ca --- /dev/null +++ b/upstream/patches/codex/0010-dshx-stdio-backend.patch @@ -0,0 +1,732 @@ +diff --git a/codex-rs/app-server-client/Cargo.toml b/codex-rs/app-server-client/Cargo.toml +--- a/codex-rs/app-server-client/Cargo.toml ++++ b/codex-rs/app-server-client/Cargo.toml +@@ -30,7 +30,7 @@ serde = { workspace = true } + serde_json = { workspace = true } +-tokio = { workspace = true, features = ["sync", "time", "rt"] } ++tokio = { workspace = true, features = ["sync", "time", "rt", "io-util", "process"] } + tokio-tungstenite = { workspace = true } + toml = { workspace = true } + tracing = { workspace = true } +diff --git a/codex-rs/app-server-client/src/lib.rs b/codex-rs/app-server-client/src/lib.rs +--- a/codex-rs/app-server-client/src/lib.rs ++++ b/codex-rs/app-server-client/src/lib.rs +@@ -8,6 +8,7 @@ + + mod path; + mod remote; ++mod stdio; +@@ -51,6 +52,9 @@ pub use crate::remote::RemoteAppServerClient; + pub use crate::remote::RemoteAppServerConnectArgs; + pub use crate::remote::RemoteAppServerEndpoint; ++pub use crate::stdio::StdioAppServerClient; ++pub use crate::stdio::StdioAppServerConnectArgs; ++pub use crate::stdio::StdioAppServerRequestHandle; +@@ -237,10 +241,12 @@ pub enum AppServerRequestHandle { + InProcess(InProcessAppServerRequestHandle), + Remote(crate::remote::RemoteAppServerRequestHandle), ++ Stdio(StdioAppServerRequestHandle), + } + + pub enum AppServerClient { + InProcess(InProcessAppServerClient), + Remote(RemoteAppServerClient), ++ Stdio(StdioAppServerClient), + } +@@ -468,6 +474,7 @@ impl AppServerRequestHandle { + match self { + Self::InProcess(handle) => handle.request(request).await, + Self::Remote(handle) => handle.request(request).await, ++ Self::Stdio(handle) => handle.request(request).await, + } + } +@@ -478,6 +485,7 @@ impl AppServerRequestHandle { + match self { + Self::InProcess(handle) => handle.request_typed(request).await, + Self::Remote(handle) => handle.request_typed(request).await, ++ Self::Stdio(handle) => handle.request_typed(request).await, + } + } + } +@@ -490,6 +498,7 @@ impl AppServerClient { + )), + Self::Remote(client) => client.codex_home().map(AppServerPath::from_app_server), ++ Self::Stdio(client) => client.codex_home().map(AppServerPath::from_app_server), + } + } +@@ -498,6 +507,7 @@ impl AppServerClient { + match self { + Self::InProcess(client) => client.request(request).await, + Self::Remote(client) => client.request(request).await, ++ Self::Stdio(client) => client.request(request).await, + } + } +@@ -508,6 +518,7 @@ impl AppServerClient { + match self { + Self::InProcess(client) => client.request_typed(request).await, + Self::Remote(client) => client.request_typed(request).await, ++ Self::Stdio(client) => client.request_typed(request).await, + } + } +@@ -516,6 +527,7 @@ impl AppServerClient { + match self { + Self::InProcess(client) => client.notify(notification).await, + Self::Remote(client) => client.notify(notification).await, ++ Self::Stdio(client) => client.notify(notification).await, + } + } +@@ -528,6 +540,7 @@ impl AppServerClient { + match self { + Self::InProcess(client) => client.resolve_server_request(request_id, result).await, + Self::Remote(client) => client.resolve_server_request(request_id, result).await, ++ Self::Stdio(client) => client.resolve_server_request(request_id, result).await, + } + } +@@ -540,6 +553,7 @@ impl AppServerClient { + match self { + Self::InProcess(client) => client.reject_server_request(request_id, error).await, + Self::Remote(client) => client.reject_server_request(request_id, error).await, ++ Self::Stdio(client) => client.reject_server_request(request_id, error).await, + } + } +@@ -548,6 +562,7 @@ impl AppServerClient { + match self { + Self::InProcess(client) => client.next_event().await.map(Into::into), + Self::Remote(client) => client.next_event().await, ++ Self::Stdio(client) => client.next_event().await, + } + } +@@ -556,6 +571,7 @@ impl AppServerClient { + match self { + Self::InProcess(client) => client.shutdown().await, + Self::Remote(client) => client.shutdown().await, ++ Self::Stdio(client) => client.shutdown().await, + } + } +@@ -564,6 +580,7 @@ impl AppServerClient { + match self { + Self::InProcess(client) => AppServerRequestHandle::InProcess(client.request_handle()), + Self::Remote(client) => AppServerRequestHandle::Remote(client.request_handle()), ++ Self::Stdio(client) => AppServerRequestHandle::Stdio(client.request_handle()), + } + } + } +diff --git a/codex-rs/app-server-client/src/remote.rs b/codex-rs/app-server-client/src/remote.rs +--- a/codex-rs/app-server-client/src/remote.rs ++++ b/codex-rs/app-server-client/src/remote.rs +@@ -68,6 +68,9 @@ pub enum RemoteAppServerEndpoint { + UnixSocket { + socket_path: AbsolutePathBuf, + }, ++ StdioChild { ++ command: Vec, ++ }, + } +@@ -143,6 +146,12 @@ impl RemoteAppServerClient { + Self::connect_with_stream(channel_capacity, endpoint, stream, initialize_params) + .await + } ++ RemoteAppServerEndpoint::StdioChild { .. } => Err(IoError::new( ++ ErrorKind::InvalidInput, ++ "stdio child endpoints must be opened with StdioAppServerClient", ++ )), + } + } +diff --git a/codex-rs/app-server-client/src/stdio.rs b/codex-rs/app-server-client/src/stdio.rs +new file mode 100644 +--- /dev/null ++++ b/codex-rs/app-server-client/src/stdio.rs +@@ -0,0 +1,459 @@ ++//! Local child-process app-server transport using one JSON-RPC object per line. ++//! ++//! This is intentionally local-process only. It exists so presentation clients ++//! can reuse the normal app-server API while delegating runtime ownership to an ++//! external host process without introducing a socket or WebSocket server. ++ ++use std::collections::HashMap; ++use std::collections::VecDeque; ++use std::io::Error as IoError; ++use std::io::ErrorKind; ++use std::io::Result as IoResult; ++use std::process::Stdio; ++ ++use crate::AppServerEvent; ++use crate::RequestResult; ++use crate::SHUTDOWN_TIMEOUT; ++use crate::TypedRequestError; ++use codex_app_server_protocol::ClientInfo; ++use codex_app_server_protocol::ClientNotification; ++use codex_app_server_protocol::ClientRequest; ++use codex_app_server_protocol::InitializeCapabilities; ++use codex_app_server_protocol::InitializeParams; ++use codex_app_server_protocol::JSONRPCError; ++use codex_app_server_protocol::JSONRPCErrorError; ++use codex_app_server_protocol::JSONRPCMessage; ++use codex_app_server_protocol::JSONRPCNotification; ++use codex_app_server_protocol::JSONRPCRequest; ++use codex_app_server_protocol::JSONRPCResponse; ++use codex_app_server_protocol::RequestId; ++use codex_app_server_protocol::Result as JsonRpcResult; ++use codex_app_server_protocol::ServerNotification; ++use codex_app_server_protocol::ServerRequest; ++use serde::de::DeserializeOwned; ++use tokio::io::AsyncBufReadExt; ++use tokio::io::AsyncWriteExt; ++use tokio::io::BufReader; ++use tokio::process::ChildStdin; ++use tokio::process::Command; ++use tokio::sync::mpsc; ++use tokio::sync::oneshot; ++use tokio::time::timeout; ++use tracing::warn; ++ ++const INITIALIZE_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(30); ++ ++#[derive(Debug, Clone)] ++pub struct StdioAppServerConnectArgs { ++ pub command: Vec, ++ pub client_name: String, ++ pub client_version: String, ++ pub experimental_api: bool, ++ pub mcp_server_openai_form_elicitation: bool, ++ pub opt_out_notification_methods: Vec, ++ pub channel_capacity: usize, ++} ++ ++impl StdioAppServerConnectArgs { ++ fn initialize_params(&self) -> InitializeParams { ++ InitializeParams { ++ client_info: ClientInfo { ++ name: self.client_name.clone(), ++ title: None, ++ version: self.client_version.clone(), ++ }, ++ capabilities: Some(InitializeCapabilities { ++ experimental_api: self.experimental_api, ++ request_attestation: false, ++ extensions: None, ++ opt_out_notification_methods: if self.opt_out_notification_methods.is_empty() { ++ None ++ } else { ++ Some(self.opt_out_notification_methods.clone()) ++ }, ++ mcp_server_openai_form_elicitation: self.mcp_server_openai_form_elicitation, ++ }), ++ } ++ } ++} ++ ++enum StdioClientCommand { ++ Request { ++ request: Box, ++ response_tx: oneshot::Sender>, ++ }, ++ Notify { ++ notification: ClientNotification, ++ response_tx: oneshot::Sender>, ++ }, ++ ResolveServerRequest { ++ request_id: RequestId, ++ result: JsonRpcResult, ++ response_tx: oneshot::Sender>, ++ }, ++ RejectServerRequest { ++ request_id: RequestId, ++ error: JSONRPCErrorError, ++ response_tx: oneshot::Sender>, ++ }, ++ Shutdown { ++ response_tx: oneshot::Sender>, ++ }, ++} ++ ++pub struct StdioAppServerClient { ++ command_tx: mpsc::Sender, ++ event_rx: mpsc::UnboundedReceiver, ++ pending_events: VecDeque, ++ server_version: Option, ++ codex_home: Option, ++ worker_handle: tokio::task::JoinHandle<()>, ++} ++ ++#[derive(Clone)] ++pub struct StdioAppServerRequestHandle { ++ command_tx: mpsc::Sender, ++} ++ ++impl StdioAppServerClient { ++ pub async fn connect(args: StdioAppServerConnectArgs) -> IoResult { ++ let executable = args.command.first().filter(|value| !value.is_empty()).ok_or_else(|| { ++ IoError::new(ErrorKind::InvalidInput, "stdio app-server command must not be empty") ++ })?; ++ let mut command = Command::new(executable); ++ command ++ .args(&args.command[1..]) ++ .stdin(Stdio::piped()) ++ .stdout(Stdio::piped()) ++ .stderr(Stdio::inherit()) ++ .kill_on_drop(true); ++ let mut child = command.spawn().map_err(|err| { ++ IoError::new( ++ err.kind(), ++ format!("failed to spawn stdio app server `{executable}`: {err}"), ++ ) ++ })?; ++ let mut stdin = child.stdin.take().ok_or_else(|| { ++ IoError::new(ErrorKind::BrokenPipe, "stdio app-server stdin was not piped") ++ })?; ++ let stdout = child.stdout.take().ok_or_else(|| { ++ IoError::new(ErrorKind::BrokenPipe, "stdio app-server stdout was not piped") ++ })?; ++ let mut lines = BufReader::new(stdout).lines(); ++ let endpoint = format!("stdio://{}", executable); ++ let initialize_params = args.initialize_params(); ++ let (pending_events, server_version, codex_home) = initialize_stdio_connection( ++ &mut stdin, ++ &mut lines, ++ &endpoint, ++ initialize_params, ++ ) ++ .await?; ++ ++ let channel_capacity = args.channel_capacity.max(1); ++ let (command_tx, mut command_rx) = mpsc::channel::(channel_capacity); ++ let (event_tx, event_rx) = mpsc::unbounded_channel::(); ++ let worker_handle = tokio::spawn(async move { ++ let mut pending_requests = ++ HashMap::>>::new(); ++ let mut worker_exit_error: Option<(ErrorKind, String)> = None; ++ let mut clean_shutdown = false; ++ ++ loop { ++ tokio::select! { ++ command = command_rx.recv() => { ++ let Some(command) = command else { ++ break; ++ }; ++ match command { ++ StdioClientCommand::Request { request, response_tx } => { ++ let request_id = request.id.clone(); ++ if pending_requests.contains_key(&request_id) { ++ let _ = response_tx.send(Err(IoError::new( ++ ErrorKind::InvalidInput, ++ format!("duplicate stdio app-server request id `{request_id}`"), ++ ))); ++ continue; ++ } ++ pending_requests.insert(request_id.clone(), response_tx); ++ if let Err(err) = write_jsonrpc_line( ++ &mut stdin, ++ JSONRPCMessage::Request(*request), ++ &endpoint, ++ ).await { ++ let message = err.to_string(); ++ if let Some(response_tx) = pending_requests.remove(&request_id) { ++ let _ = response_tx.send(Err(err)); ++ } ++ let _ = deliver_event(&event_tx, AppServerEvent::Disconnected { ++ message: message.clone(), ++ }); ++ worker_exit_error = Some((ErrorKind::BrokenPipe, message)); ++ break; ++ } ++ } ++ StdioClientCommand::Notify { notification, response_tx } => { ++ let result = write_jsonrpc_line( ++ &mut stdin, ++ JSONRPCMessage::Notification( ++ jsonrpc_notification_from_client_notification(notification), ++ ), ++ &endpoint, ++ ).await; ++ let _ = response_tx.send(result); ++ } ++ StdioClientCommand::ResolveServerRequest { request_id, result, response_tx } => { ++ let result = write_jsonrpc_line( ++ &mut stdin, ++ JSONRPCMessage::Response(JSONRPCResponse { id: request_id, result }), ++ &endpoint, ++ ).await; ++ let _ = response_tx.send(result); ++ } ++ StdioClientCommand::RejectServerRequest { request_id, error, response_tx } => { ++ let result = write_jsonrpc_line( ++ &mut stdin, ++ JSONRPCMessage::Error(JSONRPCError { id: request_id, error }), ++ &endpoint, ++ ).await; ++ let _ = response_tx.send(result); ++ } ++ StdioClientCommand::Shutdown { response_tx } => { ++ let mut result = stdin.shutdown().await; ++ if result.is_ok() { ++ result = match timeout(SHUTDOWN_TIMEOUT, child.wait()).await { ++ Ok(Ok(_status)) => Ok(()), ++ Ok(Err(err)) => Err(err), ++ Err(_) => { ++ let _ = child.kill().await; ++ Err(IoError::new( ++ ErrorKind::TimedOut, ++ format!("timed out shutting down stdio app server `{endpoint}`"), ++ )) ++ } ++ }; ++ } ++ clean_shutdown = result.is_ok(); ++ let _ = response_tx.send(result); ++ break; ++ } ++ } ++ } ++ line = lines.next_line() => { ++ match line { ++ Ok(Some(line)) if line.trim().is_empty() => continue, ++ Ok(Some(line)) => { ++ let message = match serde_json::from_str::(&line) { ++ Ok(message) => message, ++ Err(err) => { ++ let detail = format!("stdio app server `{endpoint}` sent invalid JSON-RPC: {err}"); ++ let _ = deliver_event(&event_tx, AppServerEvent::Disconnected { message: detail.clone() }); ++ worker_exit_error = Some((ErrorKind::InvalidData, detail)); ++ break; ++ } ++ }; ++ match message { ++ JSONRPCMessage::Response(response) => { ++ if let Some(response_tx) = pending_requests.remove(&response.id) { ++ let _ = response_tx.send(Ok(Ok(response.result))); ++ } ++ } ++ JSONRPCMessage::Error(error) => { ++ if let Some(response_tx) = pending_requests.remove(&error.id) { ++ let _ = response_tx.send(Ok(Err(error.error))); ++ } ++ } ++ JSONRPCMessage::Notification(notification) => { ++ if let Some(event) = app_server_event_from_notification(notification) ++ && let Err(err) = deliver_event(&event_tx, event) ++ { ++ warn!(%err, "failed to deliver stdio app-server event"); ++ break; ++ } ++ } ++ JSONRPCMessage::Request(request) => { ++ let request_id = request.id.clone(); ++ let method = request.method.clone(); ++ match ServerRequest::try_from(request) { ++ Ok(request) => { ++ if let Err(err) = deliver_event( ++ &event_tx, ++ AppServerEvent::ServerRequest(Box::new(request)), ++ ) { ++ warn!(%err, "failed to deliver stdio app-server server request"); ++ break; ++ } ++ } ++ Err(err) => { ++ warn!(%err, method, "rejecting unknown stdio app-server request"); ++ if let Err(write_err) = write_jsonrpc_line( ++ &mut stdin, ++ JSONRPCMessage::Error(JSONRPCError { ++ id: request_id, ++ error: JSONRPCErrorError { ++ code: -32601, ++ message: format!("unsupported stdio app-server request `{method}`"), ++ data: None, ++ }, ++ }), ++ &endpoint, ++ ).await { ++ worker_exit_error = Some((ErrorKind::BrokenPipe, write_err.to_string())); ++ break; ++ } ++ } ++ } ++ } ++ } ++ } ++ Ok(None) => { ++ let detail = format!("stdio app server `{endpoint}` closed stdout"); ++ let _ = deliver_event(&event_tx, AppServerEvent::Disconnected { message: detail.clone() }); ++ worker_exit_error = Some((ErrorKind::UnexpectedEof, detail)); ++ break; ++ } ++ Err(err) => { ++ let detail = format!("stdio app server `{endpoint}` read failed: {err}"); ++ let _ = deliver_event(&event_tx, AppServerEvent::Disconnected { message: detail.clone() }); ++ worker_exit_error = Some((err.kind(), detail)); ++ break; ++ } ++ } ++ } ++ } ++ } ++ ++ if !clean_shutdown { ++ let _ = stdin.shutdown().await; ++ if child.try_wait().ok().flatten().is_none() { ++ let _ = child.kill().await; ++ } ++ } ++ let (kind, message) = worker_exit_error.unwrap_or_else(|| { ++ (ErrorKind::BrokenPipe, "stdio app-server worker channel is closed".to_string()) ++ }); ++ for (_, response_tx) in pending_requests { ++ let _ = response_tx.send(Err(IoError::new(kind, message.clone()))); ++ } ++ }); ++ ++ Ok(Self { ++ command_tx, ++ event_rx, ++ pending_events: pending_events.into(), ++ server_version, ++ codex_home, ++ worker_handle, ++ }) ++ } ++ ++ pub fn server_version(&self) -> Option<&str> { self.server_version.as_deref() } ++ pub fn codex_home(&self) -> Option<&str> { self.codex_home.as_deref() } ++ pub fn request_handle(&self) -> StdioAppServerRequestHandle { ++ StdioAppServerRequestHandle { command_tx: self.command_tx.clone() } ++ } ++ pub async fn request(&self, request: ClientRequest) -> IoResult { ++ self.request_handle().request(request).await ++ } ++ pub async fn request_typed(&self, request: ClientRequest) -> Result ++ where T: DeserializeOwned { ++ self.request_handle().request_typed(request).await ++ } ++ pub async fn notify(&self, notification: ClientNotification) -> IoResult<()> { ++ let (response_tx, response_rx) = oneshot::channel(); ++ self.command_tx.send(StdioClientCommand::Notify { notification, response_tx }).await ++ .map_err(|_| IoError::new(ErrorKind::BrokenPipe, "stdio app-server worker is closed"))?; ++ response_rx.await.map_err(|_| IoError::new(ErrorKind::BrokenPipe, "stdio notify response channel is closed"))? ++ } ++ pub async fn resolve_server_request(&self, request_id: RequestId, result: JsonRpcResult) -> IoResult<()> { ++ let (response_tx, response_rx) = oneshot::channel(); ++ self.command_tx.send(StdioClientCommand::ResolveServerRequest { request_id, result, response_tx }).await ++ .map_err(|_| IoError::new(ErrorKind::BrokenPipe, "stdio app-server worker is closed"))?; ++ response_rx.await.map_err(|_| IoError::new(ErrorKind::BrokenPipe, "stdio resolve response channel is closed"))? ++ } ++ pub async fn reject_server_request(&self, request_id: RequestId, error: JSONRPCErrorError) -> IoResult<()> { ++ let (response_tx, response_rx) = oneshot::channel(); ++ self.command_tx.send(StdioClientCommand::RejectServerRequest { request_id, error, response_tx }).await ++ .map_err(|_| IoError::new(ErrorKind::BrokenPipe, "stdio app-server worker is closed"))?; ++ response_rx.await.map_err(|_| IoError::new(ErrorKind::BrokenPipe, "stdio reject response channel is closed"))? ++ } ++ pub async fn next_event(&mut self) -> Option { ++ if let Some(event) = self.pending_events.pop_front() { return Some(event); } ++ self.event_rx.recv().await ++ } ++ pub async fn shutdown(self) -> IoResult<()> { ++ let Self { command_tx, event_rx, pending_events: _, server_version: _, codex_home: _, worker_handle } = self; ++ let mut worker_handle = worker_handle; ++ drop(event_rx); ++ let (response_tx, response_rx) = oneshot::channel(); ++ if command_tx.send(StdioClientCommand::Shutdown { response_tx }).await.is_ok() ++ && let Ok(Ok(result)) = timeout(SHUTDOWN_TIMEOUT, response_rx).await ++ { ++ result?; ++ } ++ if timeout(SHUTDOWN_TIMEOUT, &mut worker_handle).await.is_err() { ++ worker_handle.abort(); ++ let _ = worker_handle.await; ++ } ++ Ok(()) ++ } ++} ++ ++impl StdioAppServerRequestHandle { ++ pub async fn request(&self, request: ClientRequest) -> IoResult { ++ let request = jsonrpc_request_from_client_request(request); ++ let (response_tx, response_rx) = oneshot::channel(); ++ self.command_tx.send(StdioClientCommand::Request { request: Box::new(request), response_tx }).await ++ .map_err(|_| IoError::new(ErrorKind::BrokenPipe, "stdio app-server worker is closed"))?; ++ response_rx.await.map_err(|_| IoError::new(ErrorKind::BrokenPipe, "stdio request response channel is closed"))? ++ } ++ pub async fn request_typed(&self, request: ClientRequest) -> Result ++ where T: DeserializeOwned { ++ let method = request.method_name().to_string(); ++ let response = self.request(request).await.map_err(|source| TypedRequestError::Transport { ++ method: method.clone(), source, ++ })?; ++ let result = response.map_err(|source| TypedRequestError::Server { method: method.clone(), source })?; ++ serde_json::from_value(result).map_err(|source| TypedRequestError::Deserialize { method, source }) ++ } ++} ++ ++async fn initialize_stdio_connection( ++ stdin: &mut ChildStdin, ++ lines: &mut tokio::io::Lines>, ++ endpoint: &str, ++ params: InitializeParams, ++) -> IoResult<(Vec, Option, Option)> { ++ let initialize_id = RequestId::String("initialize".to_string()); ++ write_jsonrpc_line( ++ stdin, ++ JSONRPCMessage::Request(jsonrpc_request_from_client_request(ClientRequest::Initialize { ++ request_id: initialize_id.clone(), ++ params, ++ })), ++ endpoint, ++ ).await?; ++ let mut pending_events = Vec::new(); ++ let mut server_version = None; ++ let mut codex_home = None; ++ timeout(INITIALIZE_TIMEOUT, async { ++ loop { ++ let Some(line) = lines.next_line().await? else { ++ return Err(IoError::new(ErrorKind::UnexpectedEof, format!("{endpoint} closed during initialize"))); ++ }; ++ if line.trim().is_empty() { continue; } ++ let message = serde_json::from_str::(&line).map_err(|err| { ++ IoError::new(ErrorKind::InvalidData, format!("{endpoint} sent invalid initialize JSON-RPC: {err}")) ++ })?; ++ match message { ++ JSONRPCMessage::Response(response) if response.id == initialize_id => { ++ server_version = response.result.get("userAgent") ++ .and_then(serde_json::Value::as_str) ++ .and_then(|value| value.split_once('/').map(|(_, rest)| rest)) ++ .and_then(|rest| rest.split_whitespace().next()) ++ .map(str::to_string); ++ codex_home = response.result.get("codexHome") ++ .and_then(serde_json::Value::as_str) ++ .filter(|value| !value.is_empty()) ++ .map(str::to_string); ++ break Ok(()); ++ } ++ JSONRPCMessage::Error(error) if error.id == initialize_id => { ++ break Err(IoError::other(format!("{endpoint} rejected initialize: {}", error.error.message))); ++ } ++ JSONRPCMessage::Notification(notification) => { ++ if let Some(event) = app_server_event_from_notification(notification) { pending_events.push(event); } ++ } ++ JSONRPCMessage::Request(request) => { ++ let request_id = request.id.clone(); ++ let method = request.method.clone(); ++ match ServerRequest::try_from(request) { ++ Ok(request) => pending_events.push(AppServerEvent::ServerRequest(Box::new(request))), ++ Err(_) => write_jsonrpc_line( ++ stdin, ++ JSONRPCMessage::Error(JSONRPCError { ++ id: request_id, ++ error: JSONRPCErrorError { ++ code: -32601, ++ message: format!("unsupported stdio app-server request `{method}`"), ++ data: None, ++ }, ++ }), ++ endpoint, ++ ).await?, ++ } ++ } ++ JSONRPCMessage::Response(_) | JSONRPCMessage::Error(_) => {} ++ } ++ } ++ }).await.map_err(|_| IoError::new(ErrorKind::TimedOut, format!("timed out waiting for initialize response from `{endpoint}`")))??; ++ write_jsonrpc_line( ++ stdin, ++ JSONRPCMessage::Notification(jsonrpc_notification_from_client_notification(ClientNotification::Initialized)), ++ endpoint, ++ ).await?; ++ Ok((pending_events, server_version, codex_home)) ++} ++ ++async fn write_jsonrpc_line(stdin: &mut ChildStdin, message: JSONRPCMessage, endpoint: &str) -> IoResult<()> { ++ let payload = serde_json::to_string(&message).map_err(IoError::other)?; ++ stdin.write_all(payload.as_bytes()).await.map_err(|err| IoError::new(err.kind(), format!("failed to write to `{endpoint}`: {err}")))?; ++ stdin.write_all(b"\n").await?; ++ stdin.flush().await?; ++ Ok(()) ++} ++ ++fn app_server_event_from_notification(notification: JSONRPCNotification) -> Option { ++ ServerNotification::try_from(notification).ok().map(|notification| { ++ AppServerEvent::ServerNotification(Box::new(notification)) ++ }) ++} ++ ++fn deliver_event(event_tx: &mpsc::UnboundedSender, event: AppServerEvent) -> IoResult<()> { ++ event_tx.send(event).map_err(|_| IoError::new(ErrorKind::BrokenPipe, "stdio app-server event consumer is closed")) ++} ++ ++fn jsonrpc_request_from_client_request(request: ClientRequest) -> JSONRPCRequest { ++ let value = serde_json::to_value(request).expect("client request should serialize"); ++ serde_json::from_value(value).expect("client request should encode as JSON-RPC request") ++} ++ ++fn jsonrpc_notification_from_client_notification(notification: ClientNotification) -> JSONRPCNotification { ++ let value = serde_json::to_value(notification).expect("client notification should serialize"); ++ serde_json::from_value(value).expect("client notification should encode as JSON-RPC notification") ++} +diff --git a/codex-rs/tui/src/lib.rs b/codex-rs/tui/src/lib.rs +--- a/codex-rs/tui/src/lib.rs ++++ b/codex-rs/tui/src/lib.rs +@@ -32,6 +32,8 @@ use codex_app_server_client::RemoteAppServerClient; + use codex_app_server_client::RemoteAppServerConnectArgs; + pub use codex_app_server_client::RemoteAppServerEndpoint; ++use codex_app_server_client::StdioAppServerClient; ++use codex_app_server_client::StdioAppServerConnectArgs; +@@ -445,6 +447,7 @@ pub fn remote_addr_supports_auth_token(endpoint: &RemoteAppServerEndpoint) -> bool { + } + RemoteAppServerEndpoint::UnixSocket { .. } => false, ++ RemoteAppServerEndpoint::StdioChild { .. } => false, + } + } +@@ -454,17 +457,31 @@ async fn connect_remote_app_server( + endpoint: RemoteAppServerEndpoint, + ) -> color_eyre::Result { +- let app_server = RemoteAppServerClient::connect(RemoteAppServerConnectArgs { +- endpoint, +- client_name: "codex-tui".to_string(), +- client_version: env!("CARGO_PKG_VERSION").to_string(), +- experimental_api: true, +- mcp_server_openai_form_elicitation: false, +- opt_out_notification_methods: Vec::new(), +- channel_capacity: DEFAULT_IN_PROCESS_CHANNEL_CAPACITY, +- }) +- .await +- .wrap_err("failed to connect to remote app server")?; +- Ok(AppServerClient::Remote(app_server)) ++ let client_name = "codex-tui".to_string(); ++ let client_version = env!("CARGO_PKG_VERSION").to_string(); ++ match endpoint { ++ RemoteAppServerEndpoint::StdioChild { command } => { ++ let app_server = StdioAppServerClient::connect(StdioAppServerConnectArgs { ++ command, ++ client_name, ++ client_version, ++ experimental_api: true, ++ mcp_server_openai_form_elicitation: false, ++ opt_out_notification_methods: Vec::new(), ++ channel_capacity: DEFAULT_IN_PROCESS_CHANNEL_CAPACITY, ++ }).await.wrap_err("failed to start local stdio app server")?; ++ Ok(AppServerClient::Stdio(app_server)) ++ } ++ endpoint => { ++ let app_server = RemoteAppServerClient::connect(RemoteAppServerConnectArgs { ++ endpoint, ++ client_name, ++ client_version, ++ experimental_api: true, ++ mcp_server_openai_form_elicitation: false, ++ opt_out_notification_methods: Vec::new(), ++ channel_capacity: DEFAULT_IN_PROCESS_CHANNEL_CAPACITY, ++ }).await.wrap_err("failed to connect to remote app server")?; ++ Ok(AppServerClient::Remote(app_server)) ++ } ++ } + } +@@ -2280,7 +2297,10 @@ fn app_server_target_for_launch( + } + return Ok(AppServerTarget::Embedded); + } + Ok(match explicit_remote_endpoint { ++ Some(endpoint @ RemoteAppServerEndpoint::StdioChild { .. }) => { ++ AppServerTarget::LocalDaemon { endpoint } ++ } + Some(endpoint) => AppServerTarget::Remote { endpoint }, + None if can_reuse_implicit_local_daemon => { + default_daemon_socket.map_or(AppServerTarget::Embedded, |socket_path| { diff --git a/upstream/patches/codex/0011-dshx-ipc-self-check.patch b/upstream/patches/codex/0011-dshx-ipc-self-check.patch deleted file mode 100644 index 8fb1079f..00000000 --- a/upstream/patches/codex/0011-dshx-ipc-self-check.patch +++ /dev/null @@ -1,100 +0,0 @@ -diff --git a/codex-rs/stdio-to-uds/src/dshx_ipc_bridge.rs b/codex-rs/stdio-to-uds/src/dshx_ipc_bridge.rs ---- a/codex-rs/stdio-to-uds/src/dshx_ipc_bridge.rs -+++ b/codex-rs/stdio-to-uds/src/dshx_ipc_bridge.rs -@@ -2,16 +2,21 @@ - - use std::io::ErrorKind; - use std::path::PathBuf; -+use std::time::SystemTime; -+use std::time::UNIX_EPOCH; - - use anyhow::Context; - use codex_uds::UnixListener; -+use codex_uds::UnixStream; - use futures::SinkExt; - use futures::StreamExt; - use tokio::io::AsyncBufReadExt; - use tokio::io::AsyncWriteExt; - use tokio::io::BufReader; - use tokio_tungstenite::accept_async; -+use tokio_tungstenite::client_async; - use tokio_tungstenite::tungstenite::Message; -+use tokio_tungstenite::tungstenite::client::IntoClientRequest; - - struct SocketGuard(PathBuf); - -@@ -32,6 +37,65 @@ - Ok(()) - } - -+struct DirectoryGuard(PathBuf); -+ -+impl Drop for DirectoryGuard { -+ fn drop(&mut self) { -+ let _ = std::fs::remove_dir_all(&self.0); -+ } -+} -+ -+async fn self_check() -> anyhow::Result<()> { -+ let nonce = SystemTime::now() -+ .duration_since(UNIX_EPOCH) -+ .context("system clock is before Unix epoch")? -+ .as_nanos(); -+ let directory = std::env::temp_dir().join(format!( -+ "dshx-ipc-check-{}-{nonce}", -+ std::process::id() -+ )); -+ codex_uds::prepare_private_socket_directory(&directory) -+ .await -+ .with_context(|| format!("failed to prepare {}", directory.display()))?; -+ let _directory_guard = DirectoryGuard(directory.clone()); -+ let socket_path = directory.join("app.sock"); -+ let mut listener = UnixListener::bind(&socket_path) -+ .await -+ .with_context(|| format!("failed to bind {}", socket_path.display()))?; -+ -+ let server = tokio::spawn(async move { -+ let stream = listener.accept().await.context("self-check accept failed")?; -+ let mut websocket = accept_async(stream) -+ .await -+ .context("self-check server websocket handshake failed")?; -+ match websocket.next().await { -+ Some(Ok(Message::Text(text))) if text.as_str() == "ping" => { -+ websocket.send(Message::Text("pong".into())).await?; -+ } -+ other => anyhow::bail!("self-check server received unexpected frame: {other:?}"), -+ } -+ websocket.close(None).await?; -+ anyhow::Ok(()) -+ }); -+ -+ let stream = UnixStream::connect(&socket_path) -+ .await -+ .with_context(|| format!("failed to connect {}", socket_path.display()))?; -+ let request = "ws://localhost/rpc" -+ .into_client_request() -+ .context("failed to create self-check websocket request")?; -+ let (mut websocket, _) = client_async(request, stream) -+ .await -+ .context("self-check client websocket handshake failed")?; -+ websocket.send(Message::Text("ping".into())).await?; -+ match websocket.next().await { -+ Some(Ok(Message::Text(text))) if text.as_str() == "pong" => {} -+ other => anyhow::bail!("self-check client received unexpected frame: {other:?}"), -+ } -+ server.await.context("self-check server task failed")??; -+ Ok(()) -+} -+ - #[tokio::main] - async fn main() -> anyhow::Result<()> { - let mut args = std::env::args_os().skip(1); -@@ -39,7 +103,7 @@ - anyhow::bail!("usage: dshx-ipc-bridge "); - }; - if first == std::ffi::OsStr::new("--check") { -- return Ok(()); -+ return self_check().await; - } - if args.next().is_some() { - anyhow::bail!("usage: dshx-ipc-bridge "); From 3fa6aeead23f7837aa9a3ac7a695375391746b2f Mon Sep 17 00:00:00 2001 From: code-new-bie <403466121@qq.com> Date: Thu, 27 Aug 2026 11:08:27 +0800 Subject: [PATCH 25/60] test(plugin): enforce host-compatible single-runtime closure Separate the compatible DSH peer range from the exact CI baseline, update ownership assertions for the official-host-only architecture, and move platform PTY gates to the stdio backend. --- .github/workflows/rc-platform.yml | 37 +++---- scripts/verify-dsh-closure.mjs | 39 ++++--- scripts/verify-ownership-boundary.mjs | 140 +++++++++++--------------- test/tui_smoke_windows.mjs | 105 +++---------------- 4 files changed, 110 insertions(+), 211 deletions(-) diff --git a/.github/workflows/rc-platform.yml b/.github/workflows/rc-platform.yml index 553f5bad..221e6689 100644 --- a/.github/workflows/rc-platform.yml +++ b/.github/workflows/rc-platform.yml @@ -15,7 +15,7 @@ concurrency: jobs: windows: if: github.event_name == 'workflow_dispatch' || startsWith(github.head_ref, 'release/') - name: Windows ConPTY / CJK / local IPC + name: Windows ConPTY / CJK / DSH stdio runs-on: windows-latest timeout-minutes: 150 steps: @@ -28,37 +28,30 @@ jobs: EXPECTED_SHA: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.sha }} run: | $actual = (git rev-parse HEAD).Trim() - if ($actual -ne $env:EXPECTED_SHA) { - throw "wrong source checkout: expected=$env:EXPECTED_SHA actual=$actual" - } + if ($actual -ne $env:EXPECTED_SHA) { throw "wrong source checkout: expected=$env:EXPECTED_SHA actual=$actual" } Write-Host "exact source checkout: $actual" - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 with: node-version: 24 - name: Install frozen dependency graph run: npm ci --include=optional --ignore-scripts=false - - name: Verify exact DeepSeek Harness release closure + - name: Verify DSH release closure run: node scripts/verify-dsh-closure.mjs - - name: Boot and dispose official DeepSeek Harness composition + - name: Verify official DSH stdio lifecycle run: node scripts/runtime-smoke.mjs - - name: Build pinned Codex TUI + local IPC bridge + - name: Build pinned Codex TUI shell: pwsh env: DSHX_VERSION: 1.0.0-ci run: ./scripts/build-codex-tui.ps1 - - name: Verify thin-fork and transport invariants + - name: Verify thin-fork and stdio invariants run: node scripts/verify-tui-invariants.mjs - - name: Verify Windows local IPC data plane - shell: pwsh - run: | - & .\dist\bin\dshx-ipc-bridge.exe --check - if ($LASTEXITCODE -ne 0) { throw 'local IPC data-plane self-check failed' } - name: Exercise real TUI through Windows ConPTY + CJK text run: node test/tui_smoke_windows.mjs macos: if: github.event_name == 'workflow_dispatch' || startsWith(github.head_ref, 'release/') - name: macOS PTY / CJK / resize / local IPC + name: macOS PTY / CJK / resize / DSH stdio runs-on: macos-26 timeout-minutes: 120 steps: @@ -72,30 +65,24 @@ jobs: run: | set -euo pipefail actual="$(git rev-parse HEAD)" - if [[ "$actual" != "$EXPECTED_SHA" ]]; then - echo "wrong source checkout: expected=$EXPECTED_SHA actual=$actual" >&2 - exit 1 - fi + if [[ "$actual" != "$EXPECTED_SHA" ]]; then echo "wrong source checkout: expected=$EXPECTED_SHA actual=$actual" >&2; exit 1; fi echo "exact source checkout: $actual" - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 with: node-version: 24 - name: Install frozen dependency graph run: npm ci --include=optional --ignore-scripts=false - - name: Verify exact DeepSeek Harness release closure + - name: Verify DSH release closure run: node scripts/verify-dsh-closure.mjs - - name: Boot and dispose official DeepSeek Harness composition + - name: Verify official DSH stdio lifecycle run: node scripts/runtime-smoke.mjs - - name: Build pinned Codex TUI + local IPC bridge + - name: Build pinned Codex TUI shell: bash env: DSHX_VERSION: 1.0.0-ci run: bash scripts/build-codex-tui.sh - - name: Verify thin-fork and transport invariants + - name: Verify thin-fork and stdio invariants run: node scripts/verify-tui-invariants.mjs - - name: Verify macOS local IPC data plane - shell: bash - run: dist/bin/dshx-ipc-bridge --check - name: Exercise real TUI through macOS PTY + CJK + resize shell: bash run: | diff --git a/scripts/verify-dsh-closure.mjs b/scripts/verify-dsh-closure.mjs index 45f7cec7..3e167988 100644 --- a/scripts/verify-dsh-closure.mjs +++ b/scripts/verify-dsh-closure.mjs @@ -13,11 +13,29 @@ if (!fs.existsSync(packagePath)) throw new Error(`Missing package.json at ${pack if (!fs.existsSync(lockPath)) throw new Error(`Missing npm lockfile at ${lockPath}`); const pkg = JSON.parse(fs.readFileSync(packagePath, 'utf8')); -// Host services are declared as peerDependencies (official bundle shape); -// either field may pin them, but one must pin an exact release. -const expected = pkg.dependencies?.['@deepseek-ai/dsh'] ?? pkg.peerDependencies?.['@deepseek-ai/dsh']; -if (typeof expected !== 'string' || !/^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?$/.test(expected)) { - throw new Error('DSHX requires an exact @deepseek-ai/dsh dependency or peerDependency version'); +const exactVersion = /^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?$/; + +// Host compatibility and test reproducibility are separate contracts. The +// host-facing @deepseek-ai/dsh peer may be a range, while the source/test graph +// pins one exact DSH release line for every stateful package in the lockfile. +const hostSpec = pkg.dependencies?.['@deepseek-ai/dsh'] ?? pkg.peerDependencies?.['@deepseek-ai/dsh']; +if (typeof hostSpec !== 'string') { + throw new Error('DSHX requires an @deepseek-ai/dsh dependency or peerDependency host contract'); +} +const exactCandidates = [ + pkg.devDependencies?.['@deepseek-ai/dsh'], + pkg.dependencies?.['@deepseek-ai/dsh'], + ...Object.entries(pkg.peerDependencies ?? {}) + .filter(([name]) => name.startsWith('@deepseek-ai/dsh-')) + .map(([, value]) => value) +].filter((value) => typeof value === 'string' && exactVersion.test(value)); +const uniqueCandidates = [...new Set(exactCandidates)]; +if (uniqueCandidates.length !== 1) { + throw new Error(`DSHX requires one exact tested DSH release baseline; found ${JSON.stringify(uniqueCandidates)}`); +} +const expected = uniqueCandidates[0]; +if (hostSpec !== expected && !hostSpec.includes(expected)) { + throw new Error(`@deepseek-ai/dsh host range ${hostSpec} does not include tested baseline ${expected}`); } const lock = JSON.parse(fs.readFileSync(lockPath, 'utf8')); @@ -25,17 +43,10 @@ const packages = lock.packages ?? {}; const mismatches = []; let count = 0; for (const [location, record] of Object.entries(packages)) { - // package-lock `packages` keys identify the package by the final - // node_modules segment. Match only the actual @deepseek-ai/dsh* record, - // never an arbitrary transitive dependency nested below a DSH package. - // Example that must NOT match: - // node_modules/@deepseek-ai/dsh-client-ui-trajectory/node_modules/react if (!/(?:^|\/)node_modules\/@deepseek-ai\/dsh(?:-[^/]+)?$/.test(location)) continue; if (!record || typeof record.version !== 'string') continue; count += 1; - if (record.version !== expected) { - mismatches.push(`${location}: ${record.version}`); - } + if (record.version !== expected) mismatches.push(`${location}: ${record.version}`); } if (count === 0) throw new Error('npm lockfile contains no @deepseek-ai/dsh* packages'); if (mismatches.length > 0) { @@ -43,4 +54,4 @@ if (mismatches.length > 0) { `DSHX refuses a mixed DeepSeek Harness release closure; expected every @deepseek-ai/dsh* package at ${expected}:\n${mismatches.join('\n')}` ); } -process.stdout.write(`Verified ${count} DeepSeek Harness packages at ${expected}\n`); +process.stdout.write(`Verified ${count} DeepSeek Harness packages at ${expected} (host contract ${hostSpec})\n`); diff --git a/scripts/verify-ownership-boundary.mjs b/scripts/verify-ownership-boundary.mjs index 50b7de2e..4c90985e 100644 --- a/scripts/verify-ownership-boundary.mjs +++ b/scripts/verify-ownership-boundary.mjs @@ -1,119 +1,95 @@ -import { readFileSync, readdirSync } from 'node:fs'; - -function read(path) { - return readFileSync(path, 'utf8'); -} +import { existsSync, readFileSync, readdirSync } from 'node:fs'; +function read(path) { return readFileSync(path, 'utf8'); } function requireText(path, needle) { - const text = read(path); - if (!text.includes(needle)) { - throw new Error(`${path} is missing required invariant: ${needle}`); - } + if (!read(path).includes(needle)) throw new Error(`${path} is missing required invariant: ${needle}`); } - function forbidText(path, pattern, label = String(pattern)) { const text = read(path); const hit = pattern instanceof RegExp ? pattern.test(text) : text.includes(pattern); - if (hit) { - throw new Error(`${path} violates ownership invariant: ${label}`); - } + if (hit) throw new Error(`${path} violates ownership invariant: ${label}`); } -requireText('docs/ARCHITECTURE.md', 'must not grow into an agent framework'); -requireText('docs/TEAM.md', 'DeepSeek Harness remains an upstream dependency'); - -// Runtime composition must stay on the official DSH app-boot/profile plane. -// Do not key this guard to historical bundle row ids such as `dsh-base`: -// those are upstream implementation details, not the ownership boundary. -requireText('src/dsh/runtime-boot.mjs', "from '@deepseek-ai/dsh-app-boot'"); -requireText('src/dsh/runtime-boot.mjs', "const DEFAULT_PROFILE = 'tui'"); -requireText('src/dsh/runtime-boot.mjs', 'loadProfile('); -requireText('src/dsh/runtime-boot.mjs', 'composeEntries('); -requireText('src/dsh/runtime-boot.mjs', 'ctx = await boot('); -requireText('src/dsh/runtime-boot.mjs', 'profile.layers.flatMap((layer) => layer.patches)'); -requireText('src/dsh/runtime-boot.mjs', 'profile.patches'); -requireText('src/dsh/runtime-boot.mjs', 'homePatches'); -// The surface is a real bundle: the manifest declares dsh.bundle.patch and the -// shipped patch carries the surface rows plus the competing-runner locks. +// Bundle/profile ownership: activation is declared, never mounted by DSHX. requireText('cordis.patch.yml', 'id: headless-startup'); requireText('cordis.patch.yml', 'id: headless-runner'); requireText('cordis.patch.yml', "name: '@code-new-bie/dshx-tui/startup'"); requireText('cordis.patch.yml', "name: '@code-new-bie/dshx-tui/presentation'"); -{ - const manifest = JSON.parse(read('package.json')); - if (manifest.dsh?.bundle?.patch !== './cordis.patch.yml') { - throw new Error('package.json must declare dsh.bundle.patch -> ./cordis.patch.yml for loader activation'); - } - if (!manifest.exports['./presentation'] || !manifest.exports['./startup']) { - throw new Error('package.json exports must expose the surface row modules'); - } - // Single-instance rule: shadowing healed installation symlinks with profile - // copies of dsh runtime packages would split every service registry in two. - const runtimePeers = Object.keys(manifest.peerDependencies ?? {}).filter((name) => name.startsWith('@deepseek-ai/dsh')); - if (runtimePeers.length === 0) throw new Error('dsh runtime packages must stay declared as peerDependencies'); - for (const name of runtimePeers) { - if (manifest.dependencies?.[name] !== undefined) { - throw new Error(`${name} must not be a real dependency; it would shadow the healed fallback symlinks`); - } +const manifest = JSON.parse(read('package.json')); +if (manifest.dsh?.bundle?.patch !== './cordis.patch.yml') { + throw new Error('package.json must declare dsh.bundle.patch -> ./cordis.patch.yml'); +} +if (!manifest.exports?.['./presentation'] || !manifest.exports?.['./startup']) { + throw new Error('package exports must expose the two Cordis surface rows'); +} + +// Stateful DSH runtime packages are host peers; only leaf helper libraries may +// be real dependencies in the profile package. +const runtimePeers = Object.keys(manifest.peerDependencies ?? {}).filter((name) => name.startsWith('@deepseek-ai/dsh')); +if (runtimePeers.length === 0) throw new Error('DSH runtime packages must be peerDependencies'); +for (const name of runtimePeers) { + if (manifest.dependencies?.[name] !== undefined) { + throw new Error(`${name} must not be a production dependency (single-instance rule)`); } } -// The presentation lifetime mounts as a Cordis-contract plugin row. -requireText('src/dsh/presentation-plugin.mjs', 'export const name'); -requireText('src/dsh/presentation-plugin.mjs', 'ctx.provide(SERVICE_KEY'); -requireText('src/dsh/presentation-plugin.mjs', "inject = ['dshxStartup']"); -requireText('src/dsh/startup-plugin.mjs', "provide('dshxStartup'"); -// The launcher only bootstraps via the official plugin command, never mounts -// rows itself; the shared bootstrap module owns the command assembly and -// resolves the dsh CLI without requiring a global installation. + +// There is exactly one runtime owner: the official dsh launcher/profile. +for (const retired of ['src/dsh/runtime-boot.mjs', 'src/dsh/local-server.mjs']) { + if (existsSync(retired)) throw new Error(`${retired} must stay deleted; DSHX cannot own a runtime/socket host`); +} requireText('src/dsh/profile-bootstrap.mjs', "'plugin', '--profile'"); requireText('src/dsh/profile-bootstrap.mjs', 'resolveDshInvocation'); -forbidText('src/dsh/runtime-boot.mjs', 'bootDshxPresentationRuntime'); -// Presentation lifetime may adapt the Context shape, but teardown must remain -// delegated to Cordis/DSH root-fiber ownership rather than a DSHX runtime. -requireText('src/dsh/runtime-boot.mjs', 'ctx.fiber.dispose()'); -requireText('src/dsh/runtime-boot.mjs', 'attachPresentationLifetime(ctx)'); -// The declared tested DSH line is ecosystem-honest metadata: warn once at -// boot, never block the host (official bundles carry peer ranges, no gates). -requireText('src/dsh/runtime-boot.mjs', 'reportDshLineCompatibility'); -requireText('src/dsh/runtime-boot.mjs', 'proceeding'); -// Host-version agnosticism: the production launcher and row modules must not -// import harness builds from our package — at runtime everything rides the -// user's installed DSH via the profile loader and its healed fallback. -forbidText('bin/dshx.mjs', /(?:from\s+|import\s+\(\s*|require\()\s*["']@deepseek-ai\//, 'importing harness builds'); +requireText('bin/dshx.mjs', 'DSHX_APP_SERVER_CMD'); +requireText('bin/dshx.mjs', "'--dshx-app-server'"); +forbidText('bin/dshx.mjs', /(?:from\s+|import\s+\(\s*|require\()\s*["']@deepseek-ai\//, 'importing Harness runtime builds'); +forbidText('bin/dshx.mjs', 'DSHX_APP_SERVER_ENDPOINT', 'socket endpoint launch path'); +forbidText('bin/dshx.mjs', 'DSHX_IPC_BRIDGE_BIN', 'bridge launch path'); + +// Cordis rows consume launcher facts and bind only NDJSON stdio to the live ctx. +requireText('src/dsh/startup-plugin.mjs', "inject = ['cmdlineArgs']"); +requireText('src/dsh/startup-plugin.mjs', '--dshx-app-server'); +requireText('src/dsh/startup-plugin.mjs', "provide('dshxStartup'"); +requireText('src/dsh/presentation-plugin.mjs', 'startDshxStdioTransport'); +requireText('src/dsh/presentation-plugin.mjs', 'ctx.provide(SERVICE_KEY'); +requireText('src/dsh/presentation-plugin.mjs', "inject = ['dshxStartup']"); +forbidText('src/dsh/presentation-plugin.mjs', 'spawn('); forbidText('src/dsh/presentation-plugin.mjs', 'runtime-boot'); -forbidText('src/dsh/local-server.mjs', "from './runtime-boot.mjs'"); -requireText('src/dsh/startup-plugin.mjs', 'DSHX_ATTACH'); +requireText('src/dsh/stdio-transport.mjs', 'already-mounted DSH Context'); +forbidText('src/dsh/stdio-transport.mjs', /WebSocket|unix:\/\//, 'network/socket framing'); +// The thin fork must spawn a local stdio backend and must not materialize the +// historical Rust UDS bridge. +requireText('upstream/patches/codex/0001-dshx-force-ui-backend.patch', 'DSHX_APP_SERVER_CMD'); +requireText('upstream/patches/codex/0010-dshx-stdio-backend.patch', 'StdioAppServerClient'); +for (const file of readdirSync('upstream/patches/codex')) { + if (!file.endsWith('.patch')) continue; + forbidText(`upstream/patches/codex/${file}`, 'dshx-ipc-bridge', 'legacy Rust bridge'); +} +forbidText('scripts/build-codex-tui.sh', 'dshx-ipc-bridge'); +forbidText('scripts/build-codex-tui.ps1', 'dshx-ipc-bridge'); + +// Domain capabilities delegate to DSH public services rather than local OS or +// shadow runtime state. for (const path of ['src/dsh/user-shell.mjs', 'src/dsh/workspace-command.mjs']) { forbidText(path, /execFile|execSync|spawn\(/, 'local process execution'); requireText(path, 'tools.execute'); } requireText('src/dsh/user-shell.mjs', 'agent: controller.agent'); requireText('src/dsh/workspace-command.mjs', 'agent'); -requireText('src/tui-protocol/adapter.mjs', "case 'command/exec'"); - requireText('src/dsh/host-api.mjs', '@deepseek-ai/dsh-host-apiproxy'); requireText('src/dsh/host-api.mjs', 'api.sessions.fork'); +requireText('src/tui-protocol/adapter.mjs', "case 'command/exec'"); requireText('src/tui-protocol/adapter.mjs', 'executeDshCommand'); requireText('src/dsh/commands.mjs', 'commands.execute'); forbidText('src/tui-protocol/adapter.mjs', 'compactNow'); forbidText('src/dsh/agent-driver.mjs', /seedLength|parentSession|dshForkSeed/, 'shadow fork/session seed state'); -// The unified adapter may read DSH's durable `parentSession` header field to -// delegate subagent interruption back to ctx.subagents, but it must never -// keep shadow fork/session seed state of its own. forbidText('src/tui-protocol/adapter.mjs', /seedLength|dshForkSeed/, 'shadow fork/session seed state'); requireText('src/tui-protocol/adapter.mjs', 'subagents.interrupt'); forbidText('src/dsh/agent-driver.mjs', 'fork(sourceAgent'); -forbidText('src/dsh/local-server.mjs', 'WebSocketServer', 'production TCP WebSocket server'); -requireText('src/dsh/local-server.mjs', 'unix://'); -requireText('scripts/build-codex-tui.sh', 'dshx-ipc-bridge'); - -// The Codex dialect lives only in the protocol namespace; domain modules in -// src/dsh stay DSH-vocabulary (gradual cleanup tracked for residual field -// mappings, enforced structurally by these two placement checks). -try { readFileSync('src/tui-protocol/shapes.mjs'); readFileSync('src/tui-protocol/adapter.mjs'); } catch { - throw new Error('Codex protocol dictionary must live under src/tui-protocol/'); +// Codex is only a presentation dialect. +for (const required of ['src/tui-protocol/shapes.mjs', 'src/tui-protocol/adapter.mjs']) { + if (!existsSync(required)) throw new Error(`missing protocol projection module: ${required}`); } for (const entry of readdirSync('src/dsh')) { if (/codex/i.test(entry)) throw new Error(`src/dsh must not carry codex-named modules; found ${entry}`); diff --git a/test/tui_smoke_windows.mjs b/test/tui_smoke_windows.mjs index 55699f02..390075da 100644 --- a/test/tui_smoke_windows.mjs +++ b/test/tui_smoke_windows.mjs @@ -3,9 +3,7 @@ import fs from 'node:fs'; import os from 'node:os'; import path from 'node:path'; import process from 'node:process'; -import { spawn } from 'node:child_process'; import { fileURLToPath } from 'node:url'; -import { createInterface } from 'node:readline'; import * as pty from 'node-pty'; const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..'); @@ -36,11 +34,10 @@ function waitForOutput(state, needle, timeoutMs = 30_000) { if (transcript.includes(needle)) { clearInterval(poll); resolve(); - return; + } else if (Date.now() - started >= timeoutMs) { + clearInterval(poll); + reject(new Error(`Timed out waiting for ${JSON.stringify(needle)}. Transcript:\n${transcript}`)); } - if (Date.now() - started < timeoutMs) return; - clearInterval(poll); - reject(new Error(`Timed out waiting for ${JSON.stringify(needle)}. Transcript:\n${transcript}`)); }, 50); }); } @@ -66,92 +63,31 @@ function waitForProtocolNotification(traceFile, method, timeoutMs = 10_000) { } } } - if (Date.now() - started < timeoutMs) return; - clearInterval(poll); - const trace = fs.existsSync(traceFile) ? fs.readFileSync(traceFile, 'utf8') : ''; - reject(new Error(`Timed out waiting for protocol notification ${JSON.stringify(method)}.\nProtocol trace:\n${trace}`)); + if (Date.now() - started >= timeoutMs) { + clearInterval(poll); + const trace = fs.existsSync(traceFile) ? fs.readFileSync(traceFile, 'utf8') : ''; + reject(new Error(`Timed out waiting for protocol notification ${JSON.stringify(method)}.\nProtocol trace:\n${trace}`)); + } }, 50); }); } -function firstLine(stream, child, stderrText, timeoutMs = 15_000) { - const lines = createInterface({ input: stream, crlfDelay: Infinity }); - return new Promise((resolve, reject) => { - const timer = setTimeout(() => fail(new Error(`Timed out waiting for local IPC stub: ${stderrText()}`)), timeoutMs); - const cleanup = () => { - clearTimeout(timer); - child.off('error', onError); - child.off('exit', onExit); - }; - const fail = (error) => { - cleanup(); - lines.close(); - reject(error); - }; - const onError = (error) => fail(error); - const onExit = (code, signal) => fail(new Error(`local IPC stub exited before ready (${signal ?? code ?? 'unknown'}): ${stderrText()}`)); - child.once('error', onError); - child.once('exit', onExit); - lines.once('line', (line) => { - cleanup(); - lines.close(); - resolve(line); - }); - }); -} - -function sleep(ms) { - return new Promise((resolve) => setTimeout(resolve, ms)); -} - -async function stopChild(child) { - if (!child || child.exitCode !== null || child.signalCode !== null) return; - const exited = new Promise((resolve) => child.once('exit', resolve)); - child.kill('SIGTERM'); - const timer = new Promise((resolve) => setTimeout(resolve, 5_000, 'timeout')); - if (await Promise.race([exited.then(() => 'exit'), timer]) === 'timeout') { - child.kill('SIGKILL'); - await exited; - } -} - -if (process.platform !== 'win32') { - throw new Error('tui_smoke_windows.mjs must run on Windows/ConPTY'); -} +function sleep(ms) { return new Promise((resolve) => setTimeout(resolve, ms)); } +if (process.platform !== 'win32') throw new Error('tui_smoke_windows.mjs must run on Windows/ConPTY'); const nodePtyPackage = JSON.parse(fs.readFileSync(path.join(ROOT, 'node_modules', 'node-pty', 'package.json'), 'utf8')); if (nodePtyPackage.version !== EXPECTED_NODE_PTY_VERSION) { - throw new Error( - `Windows ConPTY smoke must use frozen node-pty ${EXPECTED_NODE_PTY_VERSION}; got ${nodePtyPackage.version}` - ); + throw new Error(`Windows ConPTY smoke must use frozen node-pty ${EXPECTED_NODE_PTY_VERSION}; got ${nodePtyPackage.version}`); } const binary = path.join(ROOT, 'dist', 'bin', 'dshx-tui.exe'); -const bridge = path.join(ROOT, 'dist', 'bin', 'dshx-ipc-bridge.exe'); if (!fs.existsSync(binary)) throw new Error(`built DSHX TUI missing: ${binary}`); -if (!fs.existsSync(bridge)) throw new Error(`built DSHX IPC bridge missing: ${bridge}`); const codexHome = fs.mkdtempSync(path.join(os.tmpdir(), 'dshx-conpty-home-')); const traceFile = path.join(os.tmpdir(), `dshx-conpty-trace-${process.pid}-${Date.now()}.jsonl`); -let server; -let serverStderr = ''; let term; let dataDisposable; try { - server = spawn(process.execPath, [path.join(ROOT, 'bin', 'dshx-stub-local.mjs')], { - cwd: ROOT, - env: stringEnv({ DSHX_IPC_BRIDGE_BIN: bridge, DSHX_STUB_TRACE_FILE: traceFile }), - stdio: ['ignore', 'pipe', 'pipe'], - windowsHide: true - }); - server.stderr.on('data', (chunk) => { - serverStderr = `${serverStderr}${chunk.toString('utf8')}`.slice(-8192); - }); - const endpoint = await firstLine(server.stdout, server, () => serverStderr); - if (!endpoint.startsWith('unix://')) { - throw new Error(`local IPC stub returned non-local endpoint ${JSON.stringify(endpoint)}: ${serverStderr}`); - } - term = pty.spawn(binary, [], { name: 'xterm-256color', cols: 120, @@ -160,10 +96,8 @@ try { env: stringEnv({ TERM: 'xterm-256color', CODEX_HOME: codexHome, - DSHX_APP_SERVER_ENDPOINT: endpoint, - // node-pty provides a ConPTY transport, not a terminal emulator capable - // of negotiating Codex's keyboard enhancement protocol. Use Codex's - // supported fallback and exercise canonical terminal key bytes instead. + DSHX_STUB_TRACE_FILE: traceFile, + DSHX_APP_SERVER_CMD: JSON.stringify([process.execPath, path.join(ROOT, 'bin', 'dshx-stub-local.mjs')]), CODEX_TUI_DISABLE_KEYBOARD_ENHANCEMENT: '1' }) }); @@ -172,8 +106,6 @@ try { await waitForOutput(state, `DeepSeek Harness (v${EXPECTED_TUI_VERSION})`); await waitForProtocolNotification(traceFile, 'thread/started'); - // thread/started precedes the asynchronous model/banner refresh. Wait for - // the human-readable model label, not the provider-aware internal wire id. await waitForOutput(state, EXPECTED_MODEL_DISPLAY_NAME); const startupTranscript = stripTerminalControl(state.output); if (startupTranscript.includes('v0.0.0')) { @@ -182,26 +114,19 @@ try { if (startupTranscript.includes('dshx:Wy')) { throw new Error(`opaque DSHX model wire id leaked into TUI presentation:\n${startupTranscript}`); } + term.resize(100, 40); const prompt = '你好,DSHX ConPTY resize'; term.write(prompt); - // ConPTY writes this UTF-8 prompt as a burst. Codex deliberately suppresses - // Enter for 120 ms after paste-like input; wait safely beyond that product - // behavior before submitting. Real keyboard/IME fidelity is gate #12. await sleep(250); term.write('\r'); await waitForOutput(state, 'DSHX protocol stub received:'); - // Validate the echoed assistant response rather than requiring the input - // composer's ANSI redraws to contain one contiguous copy of the prompt. await waitForOutput(state, prompt); - process.stdout.write('Windows ConPTY DSHX local-IPC + CJK + resize smoke passed\n'); + process.stdout.write('Windows ConPTY DSHX stdio + CJK + resize smoke passed\n'); } finally { dataDisposable?.dispose?.(); try { term?.kill(); } catch {} - // Give ConPTY/TUI a bounded moment to close the local socket cleanly before - // terminating the deterministic adapter process. await sleep(100); - await stopChild(server); fs.rmSync(codexHome, { recursive: true, force: true }); fs.rmSync(traceFile, { force: true }); } From 9aea17a2c3b496397f5bae3291587dce40a764d4 Mon Sep 17 00:00:00 2001 From: code-new-bie <403466121@qq.com> Date: Thu, 27 Aug 2026 11:10:32 +0800 Subject: [PATCH 26/60] build(release): remove bridge from platform artifacts Package only the pinned TUI and standard DSH bundle, record the local stdio transport in provenance, and align release verification with the official-host-only runtime boundary. --- .github/workflows/release.yml | 67 +++++++++-------------------------- cordis.patch.yml | 18 +++++----- scripts/package-platform.mjs | 60 ++++++++++--------------------- 3 files changed, 44 insertions(+), 101 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index a350c46b..be5d5d5c 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -55,21 +55,13 @@ jobs: shell: bash run: | set -euo pipefail - if [[ "$GITHUB_REF_NAME" != "v1.0.0" ]]; then - exit 0 - fi + if [[ "$GITHUB_REF_NAME" != "v1.0.0" ]]; then exit 0; fi for issue in 12 13 14 15; do state="$(gh issue view "$issue" --repo "$GITHUB_REPOSITORY" --json state --jq .state)" - if [[ "$state" != "CLOSED" ]]; then - echo "stable 1.0 is blocked: release-gate issue #$issue is $state" >&2 - exit 1 - fi + if [[ "$state" != "CLOSED" ]]; then echo "stable 1.0 is blocked: release-gate issue #$issue is $state" >&2; exit 1; fi done merged="$(gh pr view 11 --repo "$GITHUB_REPOSITORY" --json mergedAt --jq '.mergedAt != null')" - if [[ "$merged" != "true" ]]; then - echo 'stable 1.0 is blocked: PR #11 has not been merged' >&2 - exit 1 - fi + if [[ "$merged" != "true" ]]; then echo 'stable 1.0 is blocked: PR #11 has not been merged' >&2; exit 1; fi - name: Resolve release version (Unix) if: runner.os != 'Windows' shell: bash @@ -83,27 +75,20 @@ jobs: npm ci --include=optional --ignore-scripts=false node scripts/verify-dsh-closure.mjs npm test - - name: Boot official DSH runtime + node scripts/verify-ownership-boundary.mjs + - name: Verify official DSH stdio lifecycle run: node scripts/runtime-smoke.mjs - - name: Build pinned TUI and local IPC bridge (Unix) + - name: Build pinned TUI (Unix) if: runner.os != 'Windows' shell: bash run: bash scripts/build-codex-tui.sh - - name: Build pinned TUI and local IPC bridge (Windows) + - name: Build pinned TUI (Windows) if: runner.os == 'Windows' shell: pwsh run: ./scripts/build-codex-tui.ps1 - - name: Verify local IPC data plane (Unix) - if: runner.os != 'Windows' - shell: bash - run: dist/bin/dshx-ipc-bridge --check - - name: Verify local IPC data plane (Windows) - if: runner.os == 'Windows' - shell: pwsh - run: | - & .\dist\bin\dshx-ipc-bridge.exe --check - if ($LASTEXITCODE -ne 0) { throw 'local IPC data-plane self-check failed' } - - name: Real pinned TUI local-IPC PTY + CJK + resize smoke + - name: Verify stdio thin-fork invariants + run: node scripts/verify-tui-invariants.mjs + - name: Real pinned TUI stdio PTY + CJK + resize smoke if: runner.os != 'Windows' shell: bash run: | @@ -112,34 +97,14 @@ jobs: python3 -m venv "$VENV" "$VENV/bin/python" -m pip install --disable-pip-version-check pexpect "$VENV/bin/python" test/tui_smoke.py - - name: Real pinned TUI Windows ConPTY + CJK local-IPC smoke + - name: Real pinned TUI Windows ConPTY + CJK stdio smoke if: runner.os == 'Windows' run: node test/tui_smoke_windows.mjs - - name: Build installable platform tarball (Unix) - if: runner.os != 'Windows' - shell: bash + - name: Build installable platform tarball run: node scripts/package-platform.mjs - - name: Enable pnpm for the official plugin machinery (Unix) - if: runner.os != 'Windows' - shell: bash + - name: Enable pnpm for official plugin machinery run: corepack enable pnpm - - name: Verify bundle install end to end (Unix) - if: runner.os != 'Windows' - shell: bash - env: - DSHX_REQUIRE_RELEASE: '1' - run: node scripts/verify-bundle-install.mjs - - name: Build installable platform tarball (Windows) - if: runner.os == 'Windows' - shell: pwsh - run: node scripts/package-platform.mjs - - name: Enable pnpm for the official plugin machinery (Windows) - if: runner.os == 'Windows' - shell: pwsh - run: corepack enable pnpm - - name: Verify bundle install end to end (Windows) - if: runner.os == 'Windows' - shell: pwsh + - name: Verify release bundle install and stdio activation env: DSHX_REQUIRE_RELEASE: '1' run: node scripts/verify-bundle-install.mjs @@ -198,10 +163,12 @@ jobs: with open(filename, encoding='utf-8') as handle: records.append((filename, json.load(handle))) expected_version = os.environ['GITHUB_REF_NAME'].removeprefix('v') - keys = ('version', 'dshVersion', 'codexCommit', 'dshCommit', 'transport', 'dependencyGraph', 'sourceLockSha256') + keys = ('version', 'dshVersion', 'dshHostRange', 'codexCommit', 'dshCommit', 'transport', 'dependencyGraph', 'sourceLockSha256') baseline = {key: records[0][1].get(key) for key in keys} if baseline['version'] != expected_version: raise SystemExit(f"artifact version mismatch: expected {expected_version}, got {baseline['version']}") + if baseline['transport'] != 'local-stdio-child': + raise SystemExit(f"unexpected transport provenance: {baseline['transport']}") if baseline['dependencyGraph'] != 'source-package-lock': raise SystemExit(f"unexpected dependency graph provenance: {baseline['dependencyGraph']}") lock_hash = baseline['sourceLockSha256'] diff --git a/cordis.patch.yml b/cordis.patch.yml index 207743f4..50ecf87c 100644 --- a/cordis.patch.yml +++ b/cordis.patch.yml @@ -1,15 +1,13 @@ -# The DSHX surface bundle patch, riding over this profile's dsh-base layer. -# Loaded automatically because the package manifest declares -# `dsh.bundle.patch`; the loader applies it in `dsh.profile.bundles` order. +# The DSHX presentation bundle rides on the profile's official DSH base. +# The package manifest declares `dsh.bundle.patch`; the loader applies this +# patch in `dsh.profile.bundles` order and owns row lifecycle. # -# Only the competing presentation rows are locked off; every runtime -# capability row remains user-authoritative (a targeted patch replaces a -# row's whole config, and these two carry no config of their own). +# Only competing headless presentation rows are disabled. Runtime capability +# rows remain entirely host-owned and user-authoritative. # -# Launch inputs flow through the official three-stage pattern: the -# dshx-startup row resolves the launcher/environment descriptor and provides -# the `dshxStartup` service; the dshx-presentation row injects it to start -# the local IPC transport and publish the `dshxPresentation` endpoint. +# The launcher hands the private `--dshx-app-server` sentinel through the +# official cmdlineArgs service. dshx-startup publishes that launch fact and +# dshx-presentation binds NDJSON stdio directly to the already-mounted Context. - id: headless-startup disabled: true - id: headless-runner diff --git a/scripts/package-platform.mjs b/scripts/package-platform.mjs index aedca39d..b067c1e0 100644 --- a/scripts/package-platform.mjs +++ b/scripts/package-platform.mjs @@ -22,15 +22,10 @@ const version = process.env.DSHX_VERSION || rootPackage.version; const platform = process.platform; const arch = process.arch; const tuiExe = platform === 'win32' ? 'dshx-tui.exe' : 'dshx-tui'; -const bridgeExe = platform === 'win32' ? 'dshx-ipc-bridge.exe' : 'dshx-ipc-bridge'; const tuiSource = path.join(root, 'dist', 'bin', tuiExe); -const bridgeSource = path.join(root, 'dist', 'bin', bridgeExe); if (!fs.existsSync(tuiSource)) { throw new Error(`Missing built TUI at ${tuiSource}; build the pinned Codex TUI first`); } -if (!fs.existsSync(bridgeSource)) { - throw new Error(`Missing built IPC bridge at ${bridgeSource}; build the pinned Codex transport bridge first`); -} assertDependencyMap('dependencies', sourceLockRoot.dependencies, rootPackage.dependencies); assertDependencyMap('devDependencies', sourceLockRoot.devDependencies, rootPackage.devDependencies); @@ -50,9 +45,9 @@ function copy(relative) { fs.cpSync(from, to, { recursive: true }); } -// Ship only the production presentation closure. Early TCP/WebSocket protocol -// stubs remain source-tree development fixtures and are deliberately excluded -// from installable artifacts. +// Ship the presentation closure only. The user's installed DSH owns every +// stateful runtime service; DSHX contributes Cordis rows, protocol projection +// code and the pinned TUI binary. There is no socket/bridge executable. copy('bin/dshx.mjs'); copy('src/cli'); copy('src/dsh'); @@ -66,18 +61,13 @@ copy('upstream/patches/codex'); fs.mkdirSync(path.join(stage, 'dist', 'bin'), { recursive: true }); fs.copyFileSync(tuiSource, path.join(stage, 'dist', 'bin', tuiExe)); -fs.copyFileSync(bridgeSource, path.join(stage, 'dist', 'bin', bridgeExe)); -if (platform !== 'win32') { - fs.chmodSync(path.join(stage, 'dist', 'bin', tuiExe), 0o755); - fs.chmodSync(path.join(stage, 'dist', 'bin', bridgeExe), 0o755); -} +if (platform !== 'win32') fs.chmodSync(path.join(stage, 'dist', 'bin', tuiExe), 0o755); const codexLicense = path.join(root, '.upstream', 'codex', 'LICENSE'); if (!fs.existsSync(codexLicense)) { throw new Error('Pinned Codex LICENSE is missing; materialize Codex before packaging'); } fs.copyFileSync(codexLicense, path.join(stage, 'LICENSE')); - fs.copyFileSync(path.join(root, 'cordis.patch.yml'), path.join(stage, 'cordis.patch.yml')); const packageJson = { @@ -90,10 +80,6 @@ const packageJson = { cpu: [arch], engines: rootPackage.engines, bin: { dshx: './bin/dshx.mjs' }, - // Bundle flavor: host services stay peers so profile installs never pull - // stateful runtime copies (single-instance rule) nor trip pnpm build-script - // gates; only leaf parser libraries ship as real dependencies. Binaries are - // embedded below via dist/bin, resolved as file paths at runtime. exports: rootPackage.exports, dsh: rootPackage.dsh, peerDependencies: rootPackage.peerDependencies, @@ -116,25 +102,21 @@ const packageJson = { }; fs.writeFileSync(path.join(stage, 'package.json'), `${JSON.stringify(packageJson, null, 2)}\n`); -// Every relative import in the release closure must resolve inside the staged -// package. Cover static `from`, side-effect `import`, and dynamic `import()` so -// a source-tree-only helper cannot hide behind a lazy code path and leak into -// 1.0 packaging. +// Every relative production import must resolve from the staged package. const localImportPattern = /(?:from\s+|import\s*(?:\(\s*)?)["'](\.{1,2}\/[^"']+)["']/g; for (const file of walkJs(stage)) { const source = fs.readFileSync(file, 'utf8'); for (const match of source.matchAll(localImportPattern)) { const target = resolveLocalImport(path.dirname(file), match[1]); - if (!target) throw new Error(`Release package has unresolved local import ${match[1]} from ${path.relative(stage, file)}`); + if (!target) { + throw new Error(`Release package has unresolved local import ${match[1]} from ${path.relative(stage, file)}`); + } } } -// npm-shrinkwrap.json is the publishable form of package-lock.json. Derive the -// artifact lock from the trusted source lock so packaging cannot silently -// resolve a different transitive graph. The source lock may contain dev-only -// nodes for repository tests; the publishable root deliberately exposes only -// production dependencies, so those nodes are not reachable from the shipped -// package even though their resolved records remain frozen in the lockfile. +// Derive the publishable shrinkwrap from the source lock; do not resolve a new +// graph during packaging. Dev nodes may remain recorded but are unreachable +// because the staged root exposes production dependencies only. const shrinkwrap = structuredClone(sourceLock); shrinkwrap.name = packageJson.name; shrinkwrap.version = packageJson.version; @@ -162,13 +144,8 @@ const packArgs = ['pack', stage, '--pack-destination', out, '--json']; let npmExecutable = 'npm'; let npmArgs = packArgs; if (platform === 'win32') { - // Node 24 no longer reliably spawns .cmd launchers through execFileSync. - // setup-node ships npm's JavaScript CLI beside node.exe, so execute that - // directly with the exact Node runtime used by the release job. const npmCli = path.join(path.dirname(process.execPath), 'node_modules', 'npm', 'bin', 'npm-cli.js'); - if (!fs.existsSync(npmCli)) { - throw new Error(`Bundled npm CLI is missing: ${npmCli}`); - } + if (!fs.existsSync(npmCli)) throw new Error(`Bundled npm CLI is missing: ${npmCli}`); npmExecutable = process.execPath; npmArgs = [npmCli, ...packArgs]; } @@ -178,8 +155,6 @@ const packOutput = execFileSync( { cwd: root, encoding: 'utf8', stdio: ['ignore', 'pipe', 'inherit'] } ); const packed = JSON.parse(packOutput); -// npm <10 returns a top-level array; newer npm keys the record by package -// name (mandatory for scoped names like @code-new-bie/dshx-tui). const packRecord = Array.isArray(packed) ? packed[0] : packed[Object.keys(packed)[0]]; const filename = packRecord?.filename; if (!filename) throw new Error(`npm pack did not return a filename: ${packOutput}`); @@ -190,17 +165,20 @@ if (path.resolve(sourceTarball) !== path.resolve(targetTarball)) { fs.renameSync(sourceTarball, targetTarball); } -// Keep metadata deterministic for a given source/version/platform. Wall clock -// and builder hostname belong in CI provenance, not the distributable sidecar. +const testedDshVersion = rootPackage.devDependencies?.['@deepseek-ai/dsh'] + ?? Object.entries(rootPackage.peerDependencies ?? {}) + .find(([name, value]) => name.startsWith('@deepseek-ai/dsh-') && /^\d/.test(String(value)))?.[1] + ?? rootPackage.peerDependencies?.['@deepseek-ai/dsh']; const metadata = { version, platform, arch, node: process.version, - dshVersion: rootPackage.dependencies['@deepseek-ai/dsh'], + dshVersion: testedDshVersion, + dshHostRange: rootPackage.peerDependencies?.['@deepseek-ai/dsh'] ?? null, codexCommit: fs.readFileSync(path.join(root, 'upstream', 'CODEX_COMMIT'), 'utf8').trim(), dshCommit: fs.readFileSync(path.join(root, 'upstream', 'DSH_COMMIT'), 'utf8').trim(), - transport: 'local-uds-via-stdio-bridge', + transport: 'local-stdio-child', dependencyGraph: 'source-package-lock', sourceLockSha256, tarball: path.basename(targetTarball) From a449ea6996f963e55e69147931da3fee1c91e19d Mon Sep 17 00:00:00 2001 From: code-new-bie <403466121@qq.com> Date: Thu, 27 Aug 2026 11:16:57 +0800 Subject: [PATCH 27/60] fix(lifecycle): drive host exit from stdin EOF Treat the underlying stdin end event as the authoritative stdio EOF signal, drain pending protocol work, then request the official DSH appExit. Keep readline close as a fallback and make the integration smoke expose the EOF/appExit stages with a bounded shutdown deadline. --- scripts/runtime-smoke.mjs | 13 ++++-- src/dsh/presentation-plugin.mjs | 24 +++-------- src/dsh/stdio-transport.mjs | 75 +++++++++++++++------------------ 3 files changed, 50 insertions(+), 62 deletions(-) diff --git a/scripts/runtime-smoke.mjs b/scripts/runtime-smoke.mjs index 05c3cdd0..0ecceb93 100644 --- a/scripts/runtime-smoke.mjs +++ b/scripts/runtime-smoke.mjs @@ -9,7 +9,8 @@ import { ensureProfileInstalled, resolveDshInvocation } from '../src/dsh/profile const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..'); const PACKAGE = JSON.parse(fs.readFileSync(path.join(ROOT, 'package.json'), 'utf8')); -const TIMEOUT_MS = Number(process.env.DSHX_SMOKE_BOOT_TIMEOUT_MS ?? 90_000); +const BOOT_TIMEOUT_MS = Number(process.env.DSHX_SMOKE_BOOT_TIMEOUT_MS ?? 90_000); +const EXIT_TIMEOUT_MS = Number(process.env.DSHX_SMOKE_EXIT_TIMEOUT_MS ?? 15_000); const ensured = ensureProfileInstalled({ packageRoot: ROOT, @@ -23,7 +24,7 @@ const dsh = resolveDshInvocation(ROOT); await new Promise((resolve, reject) => { const child = spawn(dsh.command, [...dsh.args, '--profile', ensured.profile, '--dshx-app-server'], { cwd: process.cwd(), - env: process.env, + env: { ...process.env, DSHX_DEBUG: '1' }, stdio: ['pipe', 'pipe', 'pipe'], windowsHide: true }); @@ -31,6 +32,11 @@ await new Promise((resolve, reject) => { let initialized = false; let stderr = ''; let settled = false; + let timer; + const arm = (timeoutMs, label) => { + clearTimeout(timer); + timer = setTimeout(() => finish(new Error(`official DSH stdio ${label} exceeded ${timeoutMs}ms${stderr ? `:\n${stderr}` : ''}`)), timeoutMs); + }; const finish = (error) => { if (settled) return; settled = true; @@ -43,7 +49,7 @@ await new Promise((resolve, reject) => { resolve(); } }; - const timer = setTimeout(() => finish(new Error(`official DSH stdio smoke exceeded ${TIMEOUT_MS}ms${stderr ? `:\n${stderr}` : ''}`)), TIMEOUT_MS); + arm(BOOT_TIMEOUT_MS, 'boot'); child.stderr.on('data', (chunk) => { stderr = `${stderr}${chunk.toString('utf8')}`.slice(-16384); }); child.on('error', finish); lines.on('line', (line) => { @@ -58,6 +64,7 @@ await new Promise((resolve, reject) => { process.stdout.write(`official DSH composition mounted: ${message.result?.userAgent ?? 'dshx'}\n`); child.stdin.write(`${JSON.stringify({ method: 'initialized', params: {} })}\n`); child.stdin.end(); + arm(EXIT_TIMEOUT_MS, 'EOF/appExit shutdown'); }); child.on('exit', (code, signal) => { if (!initialized) { diff --git a/src/dsh/presentation-plugin.mjs b/src/dsh/presentation-plugin.mjs index d270b5d4..906fbe96 100644 --- a/src/dsh/presentation-plugin.mjs +++ b/src/dsh/presentation-plugin.mjs @@ -3,21 +3,15 @@ import z from '@deepseek-ai/schemastery'; import { startDshxStdioTransport } from './stdio-transport.mjs'; /** - * dshx-presentation — the DSHX surface row. - * - * It owns only protocol framing against the ALREADY-MOUNTED DSH composition. - * No Harness runtime is imported or booted here and no network/socket bridge is - * created. The pinned TUI launches this composition as its local stdio backend. + * dshx-presentation — presentation framing over the live DSH composition. + * No Harness runtime or network/socket host is created by this row. */ - export const name = 'dshx-presentation'; export const inject = ['dshxStartup']; export const Config = z.object({}); export const SERVICE_KEY = 'dshxPresentation'; -export const internals = { - startStdio: startDshxStdioTransport -}; +export const internals = { startStdio: startDshxStdioTransport }; function appExit(ctx) { if (typeof ctx?.get === 'function') { @@ -30,12 +24,10 @@ function appExit(ctx) { function requestHostExit(ctx, code, log) { const exit = appExit(ctx); if (exit) { + log(`requesting official DSH appExit(${code})`); exit(code); return; } - // Embedding tests may omit appExit. A Cordis row must never call - // process.exit(); recording the status leaves final process ownership to the - // embedding host while preserving failure information. process.exitCode = code; log(`DSH launcher did not provide appExit; recorded process.exitCode=${code}`); } @@ -64,13 +56,7 @@ export async function apply(ctx) { onEof: (error) => requestHostExit(ctx, error ? 1 : 0, log) }); - ctx.provide(SERVICE_KEY, Object.freeze({ - mode: 'stdio', - close: transport.close - })); - - // Cordis owns lifetime. Mount completes immediately; stdin EOF closes the - // adapter and asks the official launcher for bounded composition shutdown. + ctx.provide(SERVICE_KEY, Object.freeze({ mode: 'stdio', close: transport.close })); return transport.close; } diff --git a/src/dsh/stdio-transport.mjs b/src/dsh/stdio-transport.mjs index 6e7d7dcc..7d22e95b 100644 --- a/src/dsh/stdio-transport.mjs +++ b/src/dsh/stdio-transport.mjs @@ -24,10 +24,8 @@ function internalError(message, error) { /** * Start a single-client Codex app-server transport directly on process stdio. - * - * The transport owns framing only. The adapter continues to talk exclusively - * to the already-mounted DSH Context supplied by the hosting composition; it - * never imports, boots or disposes another Harness runtime. + * The adapter talks only to the already-mounted DSH Context supplied by the + * hosting composition; this module never boots or disposes a Harness runtime. */ export function startDshxStdioTransport({ ctx, @@ -52,21 +50,16 @@ export function startDshxStdioTransport({ } const transportFault = (message) => { - try { - errorOutput?.write?.(`[dshx] ${message}\n`); - } catch { - // Diagnostics must never make the protocol transport less reliable. - } + try { errorOutput?.write?.(`[dshx] ${message}\n`); } catch {} }; let closing = false; let readClosed = false; + let eofTriggered = false; let closePromise; const pending = new Set(); const send = (message) => { - // stdin may already be at EOF while the final request is still being - // handled; keep stdout writable until all pending responses drain. if (output.destroyed === true || output.writableEnded === true) { throw new Error('DSHX stdio app-server output is not writable'); } @@ -83,14 +76,7 @@ export function startDshxStdioTransport({ } }; - const adapter = new Adapter({ - ctx, - cwd, - home, - version, - send, - diagnostics - }); + const adapter = new Adapter({ ctx, cwd, home, version, send, diagnostics }); const lines = createInterface({ input, crlfDelay: Infinity, terminal: false }); const handleLine = (line) => { @@ -103,13 +89,9 @@ export function startDshxStdioTransport({ safeSend(parseError(error)); return; } - try { const handled = await adapter.handle(message); if (!handled) return; - // Preserve the existing adapter contract: the JSON-RPC response must - // reach the client before any afterResponse side effect is allowed to - // emit follow-up notifications. if (!safeSend(handled.response)) return; await handled.afterResponse?.(); } catch (error) { @@ -120,20 +102,17 @@ export function startDshxStdioTransport({ pending.add(task); void task.finally(() => pending.delete(task)); }; - lines.on('line', handleLine); + let handleNaturalEof; const close = () => { if (closePromise) return closePromise; closing = true; + input.off?.('end', handleNaturalEof); closePromise = (async () => { if (!readClosed) { readClosed = true; - try { - lines.close(); - } catch { - // Already closed by EOF. - } + try { lines.close(); } catch {} } if (pending.size > 0) await Promise.allSettled([...pending]); await adapter.close?.(); @@ -141,24 +120,40 @@ export function startDshxStdioTransport({ return closePromise; }; - lines.once('close', () => { - const naturalEof = !closing; + handleNaturalEof = () => { + if (eofTriggered || closing) return; + eofTriggered = true; readClosed = true; - if (!naturalEof) return; + diagnostics('stdio input EOF; draining presentation requests'); void close().then( - () => Promise.resolve(onEof()).catch((error) => transportFault(`stdio EOF callback failed: ${error instanceof Error ? error.message : String(error)}`)), - (error) => { + async () => { + diagnostics('stdio presentation drained; requesting host exit'); + try { + await onEof(); + } catch (error) { + transportFault(`stdio EOF callback failed: ${error instanceof Error ? error.message : String(error)}`); + } + }, + async (error) => { transportFault(`stdio shutdown failed: ${error instanceof Error ? error.message : String(error)}`); - void Promise.resolve(onEof(error)).catch((callbackError) => transportFault(`stdio EOF callback failed: ${callbackError instanceof Error ? callbackError.message : String(callbackError)}`)); + try { + await onEof(error); + } catch (callbackError) { + transportFault(`stdio EOF callback failed: ${callbackError instanceof Error ? callbackError.message : String(callbackError)}`); + } } ); - }); + }; - return Object.freeze({ - mode: 'stdio', - close, - send + // The underlying stream's `end` is the authoritative EOF fact. readline's + // `close` remains a fallback for Readable implementations that close the + // interface without first surfacing `end`. + input.once('end', handleNaturalEof); + lines.once('close', () => { + if (!closing) handleNaturalEof(); }); + + return Object.freeze({ mode: 'stdio', close, send }); } export const internals = { parseError, internalError }; From 8a885e374ed1c9534227b5db6dae243025ca4491 Mon Sep 17 00:00:00 2001 From: code-new-bie <403466121@qq.com> Date: Thu, 27 Aug 2026 13:47:17 +0800 Subject: [PATCH 28/60] test(lifecycle): let official profile boot settle before EOF --- scripts/runtime-smoke.mjs | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/scripts/runtime-smoke.mjs b/scripts/runtime-smoke.mjs index 0ecceb93..c2a8b9dc 100644 --- a/scripts/runtime-smoke.mjs +++ b/scripts/runtime-smoke.mjs @@ -11,6 +11,13 @@ const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..'); const PACKAGE = JSON.parse(fs.readFileSync(path.join(ROOT, 'package.json'), 'utf8')); const BOOT_TIMEOUT_MS = Number(process.env.DSHX_SMOKE_BOOT_TIMEOUT_MS ?? 90_000); const EXIT_TIMEOUT_MS = Number(process.env.DSHX_SMOKE_EXIT_TIMEOUT_MS ?? 15_000); +// `initialize` proves the loader tree has mounted, but rc.8's official +// `runProfile()` still finishes its launcher-owned user-patch watcher setup +// immediately afterwards. That phase has intentionally no public plugin seam. +// Give the host one short bounded turn to settle before testing normal EOF; +// tearing the root down inside that private setup window exercises a launcher +// startup race, not the steady-state app-server lifecycle DSHX owns. +const HOST_SETTLE_GRACE_MS = Number(process.env.DSHX_SMOKE_HOST_SETTLE_GRACE_MS ?? 250); const ensured = ensureProfileInstalled({ packageRoot: ROOT, @@ -33,6 +40,7 @@ await new Promise((resolve, reject) => { let stderr = ''; let settled = false; let timer; + let settleTimer; const arm = (timeoutMs, label) => { clearTimeout(timer); timer = setTimeout(() => finish(new Error(`official DSH stdio ${label} exceeded ${timeoutMs}ms${stderr ? `:\n${stderr}` : ''}`)), timeoutMs); @@ -41,6 +49,7 @@ await new Promise((resolve, reject) => { if (settled) return; settled = true; clearTimeout(timer); + clearTimeout(settleTimer); lines.close(); if (error) { try { child.kill('SIGTERM'); } catch {} @@ -63,8 +72,12 @@ await new Promise((resolve, reject) => { initialized = true; process.stdout.write(`official DSH composition mounted: ${message.result?.userAgent ?? 'dshx'}\n`); child.stdin.write(`${JSON.stringify({ method: 'initialized', params: {} })}\n`); - child.stdin.end(); - arm(EXIT_TIMEOUT_MS, 'EOF/appExit shutdown'); + settleTimer = setTimeout(() => { + if (settled || child.stdin.destroyed) return; + process.stdout.write('official DSH profile boot settled; closing app-server stdin\n'); + child.stdin.end(); + arm(EXIT_TIMEOUT_MS, 'EOF/appExit shutdown'); + }, HOST_SETTLE_GRACE_MS); }); child.on('exit', (code, signal) => { if (!initialized) { From facdef073578235adfbfea88a237550bf6f16169 Mon Sep 17 00:00:00 2001 From: code-new-bie <403466121@qq.com> Date: Thu, 27 Aug 2026 13:52:01 +0800 Subject: [PATCH 29/60] build(codex): surface patch context failures --- scripts/materialize-codex.sh | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/scripts/materialize-codex.sh b/scripts/materialize-codex.sh index 3a1cde68..3f563740 100644 --- a/scripts/materialize-codex.sh +++ b/scripts/materialize-codex.sh @@ -24,8 +24,10 @@ for patch in "$ROOT"/upstream/patches/codex/*.patch; do # The maintained thin-fork patches are intentionally hand-readable and may # have stale hunk line counts after upstream rebases. Recount from the hunk # bodies while still requiring every context line to match the pinned Codex. - git -C "$DEST" apply --recount --check "$patch" - git -C "$DEST" apply --recount "$patch" + # Keep verbose diagnostics enabled: when an upstream sync drifts, CI should + # print the exact context Git searched for rather than only a line number. + git -C "$DEST" apply --verbose --recount --check "$patch" + git -C "$DEST" apply --verbose --recount "$patch" done printf '%s\n' "Materialized Codex $PIN at $DEST" From 16d0b581fa600076f39df7031ed3a5fc316762d0 Mon Sep 17 00:00:00 2001 From: code-new-bie <403466121@qq.com> Date: Thu, 27 Aug 2026 13:54:52 +0800 Subject: [PATCH 30/60] build(codex): accept strict compact patch hunks --- scripts/materialize-codex.sh | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/scripts/materialize-codex.sh b/scripts/materialize-codex.sh index 3f563740..086310c5 100644 --- a/scripts/materialize-codex.sh +++ b/scripts/materialize-codex.sh @@ -21,13 +21,14 @@ git -C "$DEST" clean -ffd >/dev/null for patch in "$ROOT"/upstream/patches/codex/*.patch; do [[ -e "$patch" ]] || continue - # The maintained thin-fork patches are intentionally hand-readable and may - # have stale hunk line counts after upstream rebases. Recount from the hunk - # bodies while still requiring every context line to match the pinned Codex. - # Keep verbose diagnostics enabled: when an upstream sync drifts, CI should - # print the exact context Git searched for rather than only a line number. - git -C "$DEST" apply --verbose --recount --check "$patch" - git -C "$DEST" apply --verbose --recount "$patch" + # The maintained thin-fork patches are intentionally compact and may carry + # fewer context lines than git-apply's traditional unified-diff minimum, as + # well as stale hunk line counts after upstream rebases. --unidiff-zero only + # permits that compact shape; every context line that is present must still + # match exactly. --recount derives counts from the hunk body, and --check + # fails closed before any patch mutates the pinned tree. + git -C "$DEST" apply --verbose --unidiff-zero --recount --check "$patch" + git -C "$DEST" apply --verbose --unidiff-zero --recount "$patch" done printf '%s\n' "Materialized Codex $PIN at $DEST" From c890965f0a31a549953b52119af9e8b60dec786a Mon Sep 17 00:00:00 2001 From: code-new-bie <403466121@qq.com> Date: Thu, 27 Aug 2026 13:55:18 +0800 Subject: [PATCH 31/60] build(codex): align Windows compact patch application --- scripts/materialize-codex.ps1 | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/scripts/materialize-codex.ps1 b/scripts/materialize-codex.ps1 index 2add41fb..f48df68d 100644 --- a/scripts/materialize-codex.ps1 +++ b/scripts/materialize-codex.ps1 @@ -21,10 +21,12 @@ git -C $Dest clean -ffd | Out-Null $Patches = Get-ChildItem (Join-Path $Root 'upstream\patches\codex\*.patch') -ErrorAction SilentlyContinue | Sort-Object Name foreach ($Patch in $Patches) { - # Recount stale hand-maintained hunk line counts, but still require every - # context line to match the pinned Codex commit before applying the patch. - git -C $Dest apply --recount --check $Patch.FullName - git -C $Dest apply --recount $Patch.FullName + # Match the Unix materializer exactly: compact hand-maintained hunks may + # carry fewer context lines than traditional unified diffs, while every + # context line present must still match the pinned source. Validate the + # whole patch before mutating the checkout. + git -C $Dest apply --verbose --unidiff-zero --recount --check $Patch.FullName + git -C $Dest apply --verbose --unidiff-zero --recount $Patch.FullName } Write-Host "Materialized Codex $Pin at $Dest" From 0517fc2743e27c31a054c73e14eb5087da12fe3f Mon Sep 17 00:00:00 2001 From: code-new-bie <403466121@qq.com> Date: Thu, 27 Aug 2026 16:28:24 +0800 Subject: [PATCH 32/60] fix(tui): complete stdio backend integration --- scripts/verify-bundle-install.mjs | 11 +- scripts/verify-tui-invariants.mjs | 17 ++- test/dshx-upstream-patch-policy.test.mjs | 21 ++++ .../0011-dshx-stdio-mode-detection.patch | 114 ++++++++++++++++++ 4 files changed, 158 insertions(+), 5 deletions(-) mode change 100644 => 100755 scripts/verify-bundle-install.mjs create mode 100644 upstream/patches/codex/0011-dshx-stdio-mode-detection.patch diff --git a/scripts/verify-bundle-install.mjs b/scripts/verify-bundle-install.mjs old mode 100644 new mode 100755 index 809afa33..007e35ce --- a/scripts/verify-bundle-install.mjs +++ b/scripts/verify-bundle-install.mjs @@ -16,6 +16,7 @@ const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..'); const PACKAGE = JSON.parse(fs.readFileSync(path.join(ROOT, 'package.json'), 'utf8')); const NAME = PACKAGE.name; const PROFILE = 'tui'; +const HOST_SETTLE_GRACE_MS = Number(process.env.DSHX_BUNDLE_HOST_SETTLE_GRACE_MS ?? 250); function fail(message) { console.error(`\n[verify-bundle] FAIL: ${message}`); @@ -42,10 +43,12 @@ async function probeStdioSurface({ dsh, cwd, env, profile = PROFILE, timeoutMs = let stderr = ''; let initialized; let settled = false; + let settleTimer; const finish = (error, result) => { if (settled) return; settled = true; clearTimeout(timer); + clearTimeout(settleTimer); lines.close(); if (error) { try { child.kill('SIGTERM'); } catch {} @@ -69,7 +72,13 @@ async function probeStdioSurface({ dsh, cwd, env, profile = PROFILE, timeoutMs = } initialized = message.result; child.stdin.write(`${JSON.stringify({ method: 'initialized', params: {} })}\n`); - child.stdin.end(); + // initialize proves the bundle rows are mounted. rc.8's official + // runProfile() then completes launcher-owned patch-watcher setup, which + // intentionally has no plugin-facing settle service. Exercise steady- + // state EOF only after that bounded host-only startup window. + settleTimer = setTimeout(() => { + if (!settled && !child.stdin.destroyed) child.stdin.end(); + }, HOST_SETTLE_GRACE_MS); }); child.on('exit', (code, signal) => { if (!initialized) { diff --git a/scripts/verify-tui-invariants.mjs b/scripts/verify-tui-invariants.mjs index 180ca4b3..92c7af81 100644 --- a/scripts/verify-tui-invariants.mjs +++ b/scripts/verify-tui-invariants.mjs @@ -19,6 +19,8 @@ const session = '.upstream/codex/codex-rs/tui/src/app_server_session.rs'; const slash = '.upstream/codex/codex-rs/tui/src/slash_command.rs'; const startup = '.upstream/codex/codex-rs/tui/src/app/startup.rs'; const event = '.upstream/codex/codex-rs/tui/src/app/event_dispatch.rs'; +const approval = '.upstream/codex/codex-rs/tui/src/bottom_pane/approval_overlay.rs'; +const permissions = '.upstream/codex/codex-rs/tui/src/chatwidget/permission_popups.rs'; for (const needle of [ 'DSHX_APP_SERVER_CMD is required', @@ -43,14 +45,21 @@ const legacyBridge = '.upstream/codex/codex-rs/stdio-to-uds/src/dshx_ipc_bridge. if (existsSync(legacyBridge)) throw new Error('legacy dshx-ipc-bridge must not be materialized'); if (existsSync('src/dsh/local-server.mjs')) throw new Error('legacy Node socket host must not ship'); +for (const path of [approval, permissions, lib]) { + requireText(path, 'fn dshx_backend'); + requireText(path, 'DSHX_APP_SERVER_CMD'); + forbidText(path, 'DSHX_APP_SERVER_ENDPOINT', 'legacy socket-mode DSHX detection'); +} requireText('.upstream/codex/codex-rs/tui/src/history_cell/session.rs', 'DeepSeek Harness'); -requireText('.upstream/codex/codex-rs/tui/src/bottom_pane/approval_overlay.rs', 'fn dshx_backend'); -requireText('.upstream/codex/codex-rs/tui/src/chatwidget/permission_popups.rs', 'fn dshx_backend'); -requireText(lib, 'fn dshx_backend'); requireText(lib, '!dshx_backend()'); requireText(startup, '!crate::dshx_backend()'); requireText(event, '!crate::dshx_backend()'); -requireText(session, 'ThreadParamsMode::Remote'); +requireText(session, 'if crate::dshx_backend()'); +forbidText( + session, + 'dshx_backend() && matches!(thread_params_mode, ThreadParamsMode::Remote)', + 'DSHX thread ownership must not depend on remote-workspace classification' +); requireText(app, 'dshx'); requireText(slash, 'if crate::dshx_backend()'); requireText(slash, 'DeepSeek Harness'); diff --git a/test/dshx-upstream-patch-policy.test.mjs b/test/dshx-upstream-patch-policy.test.mjs index 2abe9bb8..cd75a8f5 100644 --- a/test/dshx-upstream-patch-policy.test.mjs +++ b/test/dshx-upstream-patch-policy.test.mjs @@ -3,6 +3,7 @@ import fs from 'node:fs'; import test from 'node:test'; const slashPatch = fs.readFileSync('upstream/patches/codex/0009-dshx-slash-capabilities.patch', 'utf8'); +const stdioModePatch = fs.readFileSync('upstream/patches/codex/0011-dshx-stdio-mode-detection.patch', 'utf8'); function hiddenCapabilityBlock() { const start = slashPatch.indexOf('+ if crate::dshx_backend()'); @@ -33,3 +34,23 @@ test('Codex-only runtime owners stay hidden from DSHX', () => { ); } }); + +test('DSHX mode detection follows the stdio child command, never the removed socket endpoint', () => { + const oldNeedle = '- std::env::var_os("DSHX_APP_SERVER_ENDPOINT").is_some()'; + const newNeedle = '+ std::env::var_os("DSHX_APP_SERVER_CMD").is_some()'; + assert.equal(stdioModePatch.split(oldNeedle).length - 1, 3, 'all three legacy mode detectors must be replaced'); + assert.equal(stdioModePatch.split(newNeedle).length - 1, 3, 'all three DSHX mode detectors must follow the stdio command env'); +}); + +test('DSH thread ownership is independent from Codex remote-workspace classification', () => { + assert.equal( + stdioModePatch.split('- if crate::dshx_backend() && matches!(thread_params_mode, ThreadParamsMode::Remote) {').length - 1, + 3, + 'start/resume/fork must all remove the legacy Remote-mode gate' + ); + assert.equal( + stdioModePatch.split('+ if crate::dshx_backend() {').length - 1, + 3, + 'start/resume/fork must all remain DSH-owned while StdioChild is a LocalDaemon' + ); +}); diff --git a/upstream/patches/codex/0011-dshx-stdio-mode-detection.patch b/upstream/patches/codex/0011-dshx-stdio-mode-detection.patch new file mode 100644 index 00000000..ab205b2b --- /dev/null +++ b/upstream/patches/codex/0011-dshx-stdio-mode-detection.patch @@ -0,0 +1,114 @@ +diff --git a/codex-rs/app-server-client/src/stdio.rs b/codex-rs/app-server-client/src/stdio.rs +--- a/codex-rs/app-server-client/src/stdio.rs ++++ b/codex-rs/app-server-client/src/stdio.rs +@@ -320,8 +320,10 @@ impl StdioAppServerRequestHandle { + pub async fn request(&self, request: ClientRequest) -> IoResult { +- let request = jsonrpc_request_from_client_request(request); ++ self.request_json_rpc(jsonrpc_request_from_client_request(request)).await ++ } ++ pub async fn request_json_rpc(&self, request: JSONRPCRequest) -> IoResult { + let (response_tx, response_rx) = oneshot::channel(); + self.command_tx.send(StdioClientCommand::Request { request: Box::new(request), response_tx }).await + .map_err(|_| IoError::new(ErrorKind::BrokenPipe, "stdio app-server worker is closed"))?; + response_rx.await.map_err(|_| IoError::new(ErrorKind::BrokenPipe, "stdio request response channel is closed"))? + } +diff --git a/codex-rs/tui/src/app_server_session/fs.rs b/codex-rs/tui/src/app_server_session/fs.rs +--- a/codex-rs/tui/src/app_server_session/fs.rs ++++ b/codex-rs/tui/src/app_server_session/fs.rs +@@ -128,6 +128,22 @@ impl AppServerSession { + })?) + .wrap_err_with(|| format!("{method} returned invalid data")) + } ++ AppServerRequestHandle::Stdio(handle) => { ++ let response = handle ++ .request_json_rpc(JSONRPCRequest { ++ id: request_id, ++ method: method.to_string(), ++ params: Some(remote_params()), ++ trace: None, ++ }) ++ .await ++ .wrap_err_with(|| format!("{method} failed in TUI"))?; ++ serde_json::from_value(response.map_err(|source| { ++ color_eyre::eyre::eyre!("{method} failed in TUI: {}", source.message) ++ })?) ++ .wrap_err_with(|| format!("{method} returned invalid data")) ++ } + AppServerRequestHandle::InProcess(_) => { + let path = AbsolutePathBuf::from_absolute_path_checked(path.as_str()) + .wrap_err_with(|| format!("invalid local app-server fs path {path}"))?; +diff --git a/codex-rs/tui/src/status/remote_connection.rs b/codex-rs/tui/src/status/remote_connection.rs +--- a/codex-rs/tui/src/status/remote_connection.rs ++++ b/codex-rs/tui/src/status/remote_connection.rs +@@ -25,6 +25,7 @@ pub(crate) fn remote_connection_status_value( + RemoteAppServerEndpoint::UnixSocket { socket_path } => { + format!("unix://{}", socket_path.display()) + } ++ RemoteAppServerEndpoint::StdioChild { .. } => return None, + }; + let version = server_version + .map(|version| format!("v{version}")) +diff --git a/codex-rs/tui/src/bottom_pane/approval_overlay.rs b/codex-rs/tui/src/bottom_pane/approval_overlay.rs +--- a/codex-rs/tui/src/bottom_pane/approval_overlay.rs ++++ b/codex-rs/tui/src/bottom_pane/approval_overlay.rs +@@ -787,7 +787,7 @@ struct ApprovalOption { + } + + fn dshx_backend() -> bool { +- std::env::var_os("DSHX_APP_SERVER_ENDPOINT").is_some() ++ std::env::var_os("DSHX_APP_SERVER_CMD").is_some() + } + + fn command_decision_to_review_decision( +diff --git a/codex-rs/tui/src/chatwidget/permission_popups.rs b/codex-rs/tui/src/chatwidget/permission_popups.rs +--- a/codex-rs/tui/src/chatwidget/permission_popups.rs ++++ b/codex-rs/tui/src/chatwidget/permission_popups.rs +@@ -10,7 +10,7 @@ use codex_protocol::openai_models::MODEL_SPECIALTY_CYBER; + + fn dshx_backend() -> bool { +- std::env::var_os("DSHX_APP_SERVER_ENDPOINT").is_some() ++ std::env::var_os("DSHX_APP_SERVER_CMD").is_some() + } + + impl ChatWidget { +diff --git a/codex-rs/tui/src/lib.rs b/codex-rs/tui/src/lib.rs +--- a/codex-rs/tui/src/lib.rs ++++ b/codex-rs/tui/src/lib.rs +@@ -237,7 +237,7 @@ const INTERACTIVE_OTEL_SHUTDOWN_TIMEOUT: Duration = Duration::from_millis(/*mill + + fn dshx_backend() -> bool { +- std::env::var_os("DSHX_APP_SERVER_ENDPOINT").is_some() ++ std::env::var_os("DSHX_APP_SERVER_CMD").is_some() + } + + #[cfg(unix)] +diff --git a/codex-rs/tui/src/app_server_session.rs b/codex-rs/tui/src/app_server_session.rs +--- a/codex-rs/tui/src/app_server_session.rs ++++ b/codex-rs/tui/src/app_server_session.rs +@@ -1664,7 +1664,7 @@ fn thread_start_params_from_config( + remote_cwd_override: Option<&std::path::Path>, + session_start_source: Option, + ) -> ThreadStartParams { +- if crate::dshx_backend() && matches!(thread_params_mode, ThreadParamsMode::Remote) { ++ if crate::dshx_backend() { + return ThreadStartParams { + cwd: thread_cwd_from_config(config, thread_params_mode, remote_cwd_override), + ephemeral: Some(config.ephemeral), +@@ -1713,7 +1713,7 @@ fn thread_resume_params_from_config( + remote_cwd_override: Option<&std::path::Path>, + model_settings: ResumeModelSettings, + ) -> ThreadResumeParams { +- if crate::dshx_backend() && matches!(thread_params_mode, ThreadParamsMode::Remote) { ++ if crate::dshx_backend() { + return ThreadResumeParams { + thread_id: thread_id.to_string(), + ..ThreadResumeParams::default() +@@ -1778,7 +1778,7 @@ fn thread_fork_params_from_config( + thread_params_mode: ThreadParamsMode, + remote_cwd_override: Option<&std::path::Path>, + ) -> ThreadForkParams { +- if crate::dshx_backend() && matches!(thread_params_mode, ThreadParamsMode::Remote) { ++ if crate::dshx_backend() { + return ThreadForkParams { + thread_id: thread_id.to_string(), + ..ThreadForkParams::default() From f193b5e9ec3d30ad8cbb96ddfec6431a9b5c3eeb Mon Sep 17 00:00:00 2001 From: code-new-bie <403466121@qq.com> Date: Thu, 27 Aug 2026 18:14:27 +0800 Subject: [PATCH 33/60] fix(plugin): accept base-only tui composition --- scripts/verify-bundle-install.mjs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/scripts/verify-bundle-install.mjs b/scripts/verify-bundle-install.mjs index 007e35ce..ef6f30ed 100755 --- a/scripts/verify-bundle-install.mjs +++ b/scripts/verify-bundle-install.mjs @@ -117,8 +117,13 @@ function assertComposition(dumpText) { for (const id of ['dshx-startup', 'dshx-presentation']) { if (!byId.has(id)) throw new Error(`composed tree is missing '${id}'`); } - if (byId.get('headless-runner')?.disabled !== true) { - throw new Error('competing headless-runner must be disabled by the DSHX bundle patch'); + // A fresh custom `tui` profile is base-only in official DSH, so the + // headless bundle (and therefore headless-runner) is normally absent. + // If a user deliberately composes headless into the same profile, the + // DSHX layer defensively disables that competing presentation runner. + const headlessRunner = byId.get('headless-runner'); + if (headlessRunner !== undefined && headlessRunner.disabled !== true) { + throw new Error('competing headless-runner must be absent or disabled by the DSHX bundle patch'); } } finally { fs.rmSync(temp, { force: true }); From ca669b381737aff24b2ebda8198417eefa1a8382 Mon Sep 17 00:00:00 2001 From: code-new-bie <403466121@qq.com> Date: Thu, 27 Aug 2026 18:14:48 +0800 Subject: [PATCH 34/60] refactor(plugin): make DSH services host-only peers --- package.json | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/package.json b/package.json index 0c11317c..33041bfe 100644 --- a/package.json +++ b/package.json @@ -45,17 +45,16 @@ "dev": "node ./bin/dshx.mjs" }, "dependencies": { - "@deepseek-ai/dsh-cmdline": "0.1.0-rc.8", "@deepseek-ai/schemastery": "3.18.1" }, "peerDependencies": { "@deepseek-ai/dsh": ">=0.1.0-rc.8", - "@deepseek-ai/dsh-agent": "0.1.0-rc.8", - "@deepseek-ai/dsh-app-boot": "0.1.0-rc.8", - "@deepseek-ai/dsh-host-apiproxy": "0.1.0-rc.8", - "@deepseek-ai/dsh-launch-environment": "0.1.0-rc.8", - "@deepseek-ai/dsh-llm": "0.1.0-rc.8", - "@deepseek-ai/dsh-session": "0.1.0-rc.8" + "@deepseek-ai/dsh-agent": ">=0.1.0-rc.8", + "@deepseek-ai/dsh-app-boot": ">=0.1.0-rc.8", + "@deepseek-ai/dsh-host-apiproxy": ">=0.1.0-rc.8", + "@deepseek-ai/dsh-launch-environment": ">=0.1.0-rc.8", + "@deepseek-ai/dsh-llm": ">=0.1.0-rc.8", + "@deepseek-ai/dsh-session": ">=0.1.0-rc.8" }, "devDependencies": { "@deepseek-ai/dsh": "0.1.0-rc.8", From 1527e9a459a6b4ddcd7fc61d1d47524d83d32ccc Mon Sep 17 00:00:00 2001 From: code-new-bie <403466121@qq.com> Date: Thu, 27 Aug 2026 18:15:14 +0800 Subject: [PATCH 35/60] test(ownership): forbid all production DSH packages --- scripts/verify-ownership-boundary.mjs | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/scripts/verify-ownership-boundary.mjs b/scripts/verify-ownership-boundary.mjs index 4c90985e..ddead309 100644 --- a/scripts/verify-ownership-boundary.mjs +++ b/scripts/verify-ownership-boundary.mjs @@ -23,13 +23,15 @@ if (!manifest.exports?.['./presentation'] || !manifest.exports?.['./startup']) { throw new Error('package exports must expose the two Cordis surface rows'); } -// Stateful DSH runtime packages are host peers; only leaf helper libraries may -// be real dependencies in the profile package. -const runtimePeers = Object.keys(manifest.peerDependencies ?? {}).filter((name) => name.startsWith('@deepseek-ai/dsh')); +// Every DSH package belongs to the user's official installation. DSHX may +// depend on non-DSH leaf helpers, but it must never install a second Harness +// package into the profile. Service definitions are host peers and resolve +// through DSH's installation-owned profile fallback. +const runtimePeers = Object.keys(manifest.peerDependencies ?? {}).filter((name) => name === '@deepseek-ai/dsh' || name.startsWith('@deepseek-ai/dsh-')); if (runtimePeers.length === 0) throw new Error('DSH runtime packages must be peerDependencies'); -for (const name of runtimePeers) { - if (manifest.dependencies?.[name] !== undefined) { - throw new Error(`${name} must not be a production dependency (single-instance rule)`); +for (const name of Object.keys(manifest.dependencies ?? {})) { + if (name === '@deepseek-ai/dsh' || name.startsWith('@deepseek-ai/dsh-')) { + throw new Error(`${name} must not be a production dependency (single-runtime rule)`); } } From 7ee2ae8a3a124adb619683182f2dd871af2200bd Mon Sep 17 00:00:00 2001 From: code-new-bie <403466121@qq.com> Date: Thu, 27 Aug 2026 18:15:56 +0800 Subject: [PATCH 36/60] build(release): stage only current production dependency root --- scripts/package-platform.mjs | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/scripts/package-platform.mjs b/scripts/package-platform.mjs index b067c1e0..41621578 100644 --- a/scripts/package-platform.mjs +++ b/scripts/package-platform.mjs @@ -27,7 +27,12 @@ if (!fs.existsSync(tuiSource)) { throw new Error(`Missing built TUI at ${tuiSource}; build the pinned Codex TUI first`); } -assertDependencyMap('dependencies', sourceLockRoot.dependencies, rootPackage.dependencies); +// The lock may retain unreachable historical production nodes until the next +// reviewed freeze. Every dependency still shipped by the current manifest must +// nevertheless have the exact frozen root spec. The staged shrinkwrap below +// rewrites its root dependency map to the current manifest, so retired extras +// cannot become publishable dependencies. +assertDependencySubset('dependencies', sourceLockRoot.dependencies, rootPackage.dependencies); assertDependencyMap('devDependencies', sourceLockRoot.devDependencies, rootPackage.devDependencies); const releaseRoot = path.join(root, '.release'); @@ -115,8 +120,8 @@ for (const file of walkJs(stage)) { } // Derive the publishable shrinkwrap from the source lock; do not resolve a new -// graph during packaging. Dev nodes may remain recorded but are unreachable -// because the staged root exposes production dependencies only. +// graph during packaging. Dev nodes and historical nodes may remain recorded +// but are unreachable because the staged root exposes production dependencies only. const shrinkwrap = structuredClone(sourceLock); shrinkwrap.name = packageJson.name; shrinkwrap.version = packageJson.version; @@ -186,6 +191,14 @@ const metadata = { fs.writeFileSync(`${targetTarball}.json`, `${JSON.stringify(metadata, null, 2)}\n`); process.stdout.write(`${targetTarball}\n`); +function assertDependencySubset(label, actual = {}, expected = {}) { + for (const [name, spec] of Object.entries(expected)) { + if (actual[name] !== spec) { + throw new Error(`Frozen package-lock.json ${label}.${name} does not match package.json: expected ${spec}, got ${actual[name] ?? ''}`); + } + } +} + function assertDependencyMap(label, actual = {}, expected = {}) { const actualEntries = Object.entries(actual).sort(([a], [b]) => a.localeCompare(b)); const expectedEntries = Object.entries(expected).sort(([a], [b]) => a.localeCompare(b)); From 60d62664d3995911dcbf15fe06e3dc014ef0d0f9 Mon Sep 17 00:00:00 2001 From: code-new-bie <403466121@qq.com> Date: Thu, 27 Aug 2026 18:16:18 +0800 Subject: [PATCH 37/60] ci(rc): verify official bundle activation cross-platform --- .github/workflows/rc-platform.yml | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/.github/workflows/rc-platform.yml b/.github/workflows/rc-platform.yml index 221e6689..e63499cd 100644 --- a/.github/workflows/rc-platform.yml +++ b/.github/workflows/rc-platform.yml @@ -37,6 +37,8 @@ jobs: run: npm ci --include=optional --ignore-scripts=false - name: Verify DSH release closure run: node scripts/verify-dsh-closure.mjs + - name: Enable pnpm for official profile machinery + run: corepack enable pnpm - name: Verify official DSH stdio lifecycle run: node scripts/runtime-smoke.mjs - name: Build pinned Codex TUI @@ -46,6 +48,8 @@ jobs: run: ./scripts/build-codex-tui.ps1 - name: Verify thin-fork and stdio invariants run: node scripts/verify-tui-invariants.mjs + - name: Verify bundle install and stdio activation + run: node scripts/verify-bundle-install.mjs - name: Exercise real TUI through Windows ConPTY + CJK text run: node test/tui_smoke_windows.mjs @@ -74,6 +78,8 @@ jobs: run: npm ci --include=optional --ignore-scripts=false - name: Verify DSH release closure run: node scripts/verify-dsh-closure.mjs + - name: Enable pnpm for official profile machinery + run: corepack enable pnpm - name: Verify official DSH stdio lifecycle run: node scripts/runtime-smoke.mjs - name: Build pinned Codex TUI @@ -83,6 +89,8 @@ jobs: run: bash scripts/build-codex-tui.sh - name: Verify thin-fork and stdio invariants run: node scripts/verify-tui-invariants.mjs + - name: Verify bundle install and stdio activation + run: node scripts/verify-bundle-install.mjs - name: Exercise real TUI through macOS PTY + CJK + resize shell: bash run: | @@ -91,3 +99,20 @@ jobs: python3 -m venv "$VENV" "$VENV/bin/python" -m pip install --disable-pip-version-check pexpect "$VENV/bin/python" test/tui_smoke.py + + summary: + if: always() && (github.event_name == 'workflow_dispatch' || startsWith(github.head_ref, 'release/')) + name: RC platform summary + needs: [windows, macos] + runs-on: ubuntu-latest + steps: + - name: Require all platform gates + env: + WINDOWS_RESULT: ${{ needs.windows.result }} + MACOS_RESULT: ${{ needs.macos.result }} + shell: bash + run: | + set -euo pipefail + [[ "$WINDOWS_RESULT" == success ]] || { echo "Windows RC gate: $WINDOWS_RESULT" >&2; exit 1; } + [[ "$MACOS_RESULT" == success ]] || { echo "macOS RC gate: $MACOS_RESULT" >&2; exit 1; } + echo 'Windows and macOS RC platform gates passed.' From 21784a5953065905ae168f7e5b5d6e541118efb6 Mon Sep 17 00:00:00 2001 From: code-new-bie <403466121@qq.com> Date: Thu, 27 Aug 2026 18:16:49 +0800 Subject: [PATCH 38/60] ci(release): settle official profile before lifecycle gates --- .github/workflows/release.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index be5d5d5c..216ebe6e 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -76,6 +76,8 @@ jobs: node scripts/verify-dsh-closure.mjs npm test node scripts/verify-ownership-boundary.mjs + - name: Enable pnpm for official profile machinery + run: corepack enable pnpm - name: Verify official DSH stdio lifecycle run: node scripts/runtime-smoke.mjs - name: Build pinned TUI (Unix) @@ -102,8 +104,6 @@ jobs: run: node test/tui_smoke_windows.mjs - name: Build installable platform tarball run: node scripts/package-platform.mjs - - name: Enable pnpm for official plugin machinery - run: corepack enable pnpm - name: Verify release bundle install and stdio activation env: DSHX_REQUIRE_RELEASE: '1' From d7c41ed8d02ea78e45425188362202b05e4b6a17 Mon Sep 17 00:00:00 2001 From: code-new-bie <403466121@qq.com> Date: Thu, 27 Aug 2026 18:22:07 +0800 Subject: [PATCH 39/60] fix(release): keep DSH host peers advisory --- .github/workflows/release.yml | 10 +++++++++- package.json | 9 +++++++++ scripts/package-platform.mjs | 2 ++ scripts/verify-ownership-boundary.mjs | 12 ++++++++++-- 4 files changed, 30 insertions(+), 3 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 216ebe6e..9ad8399d 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -76,7 +76,7 @@ jobs: node scripts/verify-dsh-closure.mjs npm test node scripts/verify-ownership-boundary.mjs - - name: Enable pnpm for official profile machinery + - name: Enable pnpm for official plugin machinery run: corepack enable pnpm - name: Verify official DSH stdio lifecycle run: node scripts/runtime-smoke.mjs @@ -116,7 +116,12 @@ jobs: TGZ="$(find dist/release -maxdepth 1 -name 'dshx-*.tgz' -print -quit)" PREFIX="$RUNNER_TEMP/dshx-release-smoke" npm install --global --prefix "$PREFIX" --include=optional --ignore-scripts=false "$TGZ" + if npm ls --global --prefix "$PREFIX" @deepseek-ai/dsh --depth=0 >/dev/null 2>&1; then + echo 'clean DSHX install unexpectedly materialized a second @deepseek-ai/dsh runtime' >&2 + exit 1 + fi "$PREFIX/bin/dshx" --version | grep -F "$DSHX_VERSION" + export DSHX_DSH_BIN="$PWD/node_modules/@deepseek-ai/dsh/lib/bin.js" "$PREFIX/bin/dshx" doctor - name: Clean install smoke (Windows) if: runner.os == 'Windows' @@ -126,8 +131,11 @@ jobs: if (-not $tgz) { throw 'platform tarball missing' } $prefix = Join-Path $env:RUNNER_TEMP 'dshx-release-smoke' npm install --global --prefix $prefix --include=optional --ignore-scripts=false $tgz.FullName + & npm ls --global --prefix $prefix '@deepseek-ai/dsh' --depth=0 *> $null + if ($LASTEXITCODE -eq 0) { throw 'clean DSHX install unexpectedly materialized a second @deepseek-ai/dsh runtime' } $version = & (Join-Path $prefix 'dshx.cmd') --version if (-not ($version -match [regex]::Escape($env:DSHX_VERSION))) { throw "wrong dshx version: $version" } + $env:DSHX_DSH_BIN = (Resolve-Path 'node_modules\@deepseek-ai\dsh\lib\bin.js').Path & (Join-Path $prefix 'dshx.cmd') doctor - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: diff --git a/package.json b/package.json index 33041bfe..c961185b 100644 --- a/package.json +++ b/package.json @@ -56,6 +56,15 @@ "@deepseek-ai/dsh-llm": ">=0.1.0-rc.8", "@deepseek-ai/dsh-session": ">=0.1.0-rc.8" }, + "peerDependenciesMeta": { + "@deepseek-ai/dsh": { "optional": true }, + "@deepseek-ai/dsh-agent": { "optional": true }, + "@deepseek-ai/dsh-app-boot": { "optional": true }, + "@deepseek-ai/dsh-host-apiproxy": { "optional": true }, + "@deepseek-ai/dsh-launch-environment": { "optional": true }, + "@deepseek-ai/dsh-llm": { "optional": true }, + "@deepseek-ai/dsh-session": { "optional": true } + }, "devDependencies": { "@deepseek-ai/dsh": "0.1.0-rc.8", "@deepseek-ai/dsh-agent": "0.1.0-rc.8", diff --git a/scripts/package-platform.mjs b/scripts/package-platform.mjs index 41621578..4ae11c40 100644 --- a/scripts/package-platform.mjs +++ b/scripts/package-platform.mjs @@ -88,6 +88,7 @@ const packageJson = { exports: rootPackage.exports, dsh: rootPackage.dsh, peerDependencies: rootPackage.peerDependencies, + peerDependenciesMeta: rootPackage.peerDependenciesMeta, dependencies: rootPackage.dependencies, repository: { type: 'git', url: 'https://github.com/code-new-bie/dsh-codex.git' }, files: [ @@ -135,6 +136,7 @@ shrinkwrapRoot.engines = packageJson.engines; shrinkwrapRoot.bin = packageJson.bin; shrinkwrapRoot.dependencies = packageJson.dependencies; shrinkwrapRoot.peerDependencies = packageJson.peerDependencies ?? {}; +shrinkwrapRoot.peerDependenciesMeta = packageJson.peerDependenciesMeta ?? {}; delete shrinkwrapRoot.devDependencies; const shrinkwrapPath = path.join(stage, 'npm-shrinkwrap.json'); fs.writeFileSync(shrinkwrapPath, `${JSON.stringify(shrinkwrap, null, 2)}\n`); diff --git a/scripts/verify-ownership-boundary.mjs b/scripts/verify-ownership-boundary.mjs index ddead309..0af87373 100644 --- a/scripts/verify-ownership-boundary.mjs +++ b/scripts/verify-ownership-boundary.mjs @@ -25,8 +25,8 @@ if (!manifest.exports?.['./presentation'] || !manifest.exports?.['./startup']) { // Every DSH package belongs to the user's official installation. DSHX may // depend on non-DSH leaf helpers, but it must never install a second Harness -// package into the profile. Service definitions are host peers and resolve -// through DSH's installation-owned profile fallback. +// package into the profile. Service definitions are optional advisory host +// peers and resolve through DSH's installation-owned profile fallback. const runtimePeers = Object.keys(manifest.peerDependencies ?? {}).filter((name) => name === '@deepseek-ai/dsh' || name.startsWith('@deepseek-ai/dsh-')); if (runtimePeers.length === 0) throw new Error('DSH runtime packages must be peerDependencies'); for (const name of Object.keys(manifest.dependencies ?? {})) { @@ -34,6 +34,14 @@ for (const name of Object.keys(manifest.dependencies ?? {})) { throw new Error(`${name} must not be a production dependency (single-runtime rule)`); } } +for (const name of runtimePeers) { + if (manifest.peerDependencies[name] !== '>=0.1.0-rc.8') { + throw new Error(`${name} must use the host compatibility floor >=0.1.0-rc.8`); + } + if (manifest.peerDependenciesMeta?.[name]?.optional !== true) { + throw new Error(`${name} must be an optional advisory peer so npm cannot auto-install a second Harness runtime`); + } +} // There is exactly one runtime owner: the official dsh launcher/profile. for (const retired of ['src/dsh/runtime-boot.mjs', 'src/dsh/local-server.mjs']) { From eafb3ca615d8457ac9f12d2ad9ed5168ce1a1149 Mon Sep 17 00:00:00 2001 From: code-new-bie <403466121@qq.com> Date: Thu, 27 Aug 2026 20:16:36 +0800 Subject: [PATCH 40/60] refactor(plugin): make dshx the native tui profile entry --- bin/dshx.mjs | 204 +++--------------- cordis.patch.yml | 19 +- src/dsh/presentation-plugin.mjs | 140 ++++++++++-- src/dsh/profile-bootstrap.mjs | 116 ++++++---- src/dsh/startup-plugin.mjs | 28 +-- test/dshx-presentation-plugin.test.mjs | 134 ++++++++---- test/dshx-profile-bootstrap.test.mjs | 105 +++++---- .../0012-dshx-inherited-profile-pipe.patch | 194 +++++++++++++++++ 8 files changed, 588 insertions(+), 352 deletions(-) create mode 100644 upstream/patches/codex/0012-dshx-inherited-profile-pipe.patch diff --git a/bin/dshx.mjs b/bin/dshx.mjs index 88f4fae8..7bad781e 100755 --- a/bin/dshx.mjs +++ b/bin/dshx.mjs @@ -1,43 +1,19 @@ #!/usr/bin/env node -// DSHX launcher: presentation-only bootstrap over the user's own official DSH -// installation. The pinned Codex TUI owns the terminal; it spawns DSH as a -// local stdio app-server child through DSHX_APP_SERVER_CMD. +// DSHX is the UX alias for the standard DSH TUI profile. It may ensure the +// bundle is installed, but the official `dsh --profile tui` process remains +// the application host and owns the Loader tree, runtime services and exit. import fs from 'node:fs'; -import os from 'node:os'; import path from 'node:path'; import process from 'node:process'; -import { spawn, spawnSync } from 'node:child_process'; -import { createInterface } from 'node:readline'; +import { spawnSync } from 'node:child_process'; import { fileURLToPath } from 'node:url'; -import { parseCliInvocation } from '../src/cli/arguments.mjs'; import { isSupportedNodeVersion } from '../src/cli/runtime.mjs'; import { ensureProfileInstalled, resolveDshInvocation } from '../src/dsh/profile-bootstrap.mjs'; const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..'); const PACKAGE = JSON.parse(fs.readFileSync(path.join(ROOT, 'package.json'), 'utf8')); -const VERSION = PACKAGE.version; const DEFAULT_PROFILE = 'tui'; -function usage() { - return `DSHX ${VERSION}\n\nUsage:\n dshx Start DSHX in the current project\n dshx Start with an initial prompt\n dshx resume Open the DSH session picker\n dshx resume --last Resume the most recent DSH session\n dshx resume Resume a specific DSH session\n dshx doctor Check the TUI and official DSH stdio composition\n dshx --version Print version\n dshx --help Show this help\n\nEnvironment:\n DSHX_TUI_BIN Override the packaged DSHX TUI binary (development only)\n DSHX_TUI_HOME Override DSHX presentation-only Codex home\n DSHX_DSH_BIN Override the official dsh JavaScript entrypoint\n DSHX_PROFILE Override the DSH profile (default: ${DEFAULT_PROFILE})\n DSHX_DEBUG=1 Print DSHX adapter diagnostics\n\nPlugin usage:\n The surface is a standard DSH profile bundle managed by the official CLI:\n dsh plugin --profile ${DEFAULT_PROFILE} add ${PACKAGE.name}\n\nProduct boundary:\n DSHX owns the launcher, a thin Codex TUI fork and a presentation adapter.\n DeepSeek Harness remains authoritative for Agent/Session/Tool/Approval state.\n No Harness runtime is bundled or booted by DSHX itself.\n`; -} - -function commandDetail(command, result) { - if (result.status === 0) return (result.stdout || result.stderr).trim(); - if (result.error) return `${command} failed: ${result.error.message}`; - return `${command} is not runnable${result.stderr ? `: ${result.stderr.trim()}` : ''}`; -} - -function tuiBinary() { - if (process.env.DSHX_TUI_BIN) return process.env.DSHX_TUI_BIN; - const name = process.platform === 'win32' ? 'dshx-tui.exe' : 'dshx-tui'; - return path.join(ROOT, 'dist', 'bin', name); -} - -function tuiHome() { - return path.resolve(process.env.DSHX_TUI_HOME || path.join(os.homedir(), '.dshx', 'codex-tui')); -} - function selectedProfile() { const value = process.env.DSHX_PROFILE || DEFAULT_PROFILE; if (!value.trim()) throw new Error('DSH profile name must be non-empty'); @@ -48,166 +24,46 @@ export function bootstrapSurfaceProfile() { return ensureProfileInstalled({ packageRoot: ROOT, name: PACKAGE.name, - version: VERSION, + version: PACKAGE.version, profile: selectedProfile() }); } -function presentationHomeCheck() { - const home = tuiHome(); - try { - fs.mkdirSync(home, { recursive: true, mode: 0o700 }); - if (!fs.statSync(home).isDirectory()) throw new Error('path exists but is not a directory'); - fs.accessSync(home, fs.constants.R_OK | fs.constants.W_OK); - return { ok: true, detail: home }; - } catch (error) { - return { ok: false, detail: `${home}: ${error instanceof Error ? error.message : String(error)}` }; - } -} - -/** Probe the real installed profile through the same stdio protocol used by the TUI. */ -function backendActivationProbe(dsh, profile, timeoutMs = 90_000) { - return new Promise((resolve) => { - const child = spawn(dsh.command, [...dsh.args, '--profile', profile, '--dshx-app-server'], { - cwd: process.cwd(), - env: process.env, - stdio: ['pipe', 'pipe', 'pipe'], - windowsHide: true - }); - const lines = createInterface({ input: child.stdout, crlfDelay: Infinity, terminal: false }); - let stderr = ''; - let settled = false; - const finish = (ok, detail) => { - if (settled) return; - settled = true; - clearTimeout(timer); - lines.close(); - try { child.stdin.end(); } catch {} - try { child.kill('SIGTERM'); } catch {} - resolve({ ok, detail }); - }; - const timer = setTimeout(() => finish(false, `no stdio activation within ${timeoutMs}ms`), timeoutMs); - child.stderr.on('data', (chunk) => { stderr = `${stderr}${chunk.toString('utf8')}`.slice(-8192); }); - lines.on('line', (line) => { - let message; - try { message = JSON.parse(line); } catch { return; } - if (message?.id === 'dshx-doctor' && message?.result) { - finish(true, `stdio surface active (${message.result.userAgent ?? 'DSH'})`); - } else if (message?.id === 'dshx-doctor' && message?.error) { - finish(false, message.error.message || 'initialize rejected'); - } - }); - child.on('error', (error) => finish(false, error.message)); - child.on('exit', (code) => { - if (!settled) finish(false, `official CLI exited before initialize (code ${code ?? '?'})${stderr.trim() ? `: ${stderr.trim().split('\n').slice(-3).join(' | ')}` : ''}`); - }); - child.stdin.write(`${JSON.stringify({ - id: 'dshx-doctor', - method: 'initialize', - params: { clientInfo: { name: 'dshx-doctor', version: VERSION } } - })}\n`); - }); -} - -async function doctor() { - const executable = tuiBinary(); - const tuiCheck = fs.existsSync(executable) - ? spawnSync(executable, ['--version'], { encoding: 'utf8' }) - : { status: 127, stdout: '', stderr: '', error: null }; - const homeCheck = presentationHomeCheck(); - - let profileDetail = ''; - let profileOk = true; - let dsh; - let profile; - try { - const ensured = bootstrapSurfaceProfile(); - profile = ensured.profile; - profileDetail = `profile '${profile}' (${ensured.action})`; - dsh = resolveDshInvocation(ROOT); - } catch (error) { - profileOk = false; - profileDetail = error instanceof Error ? error.message : String(error); - } - - let harness = { ok: false, detail: 'skipped: surface profile unavailable' }; - if (profileOk) harness = await backendActivationProbe(dsh, profile); - - const rows = [ - ['Node', `${process.version} (required: ${PACKAGE.engines.node})`, isSupportedNodeVersion(process.versions.node)], - ['Pinned Codex TUI', tuiCheck.status === 0 ? commandDetail(executable, tuiCheck) : commandDetail(executable, tuiCheck), tuiCheck.status === 0], - ['Surface profile', profileDetail, profileOk], - ['DeepSeek Harness stdio surface', harness.detail, harness.ok], - ['Presentation home', homeCheck.detail, homeCheck.ok] - ]; - for (const [name, detail, ok] of rows) process.stdout.write(`${ok ? '✓' : '✗'} ${name}: ${detail}\n`); - if (rows.some((row) => !row[2])) { - process.stderr.write( - process.platform === 'win32' - ? 'For a source checkout, build the pinned TUI with `.\\scripts\\build-codex-tui.ps1`.\n' - : 'For a source checkout, build the pinned TUI with `./scripts/build-codex-tui.sh`.\n' - ); - process.exitCode = 1; - } -} - -async function run() { - let invocation; - try { - invocation = parseCliInvocation(process.argv.slice(2)); - } catch (error) { - process.stderr.write(`dshx: ${error.message}\n`); - process.exitCode = 2; - return; - } - - if (invocation.kind === 'help') return void process.stdout.write(usage()); - if (invocation.kind === 'version') return void process.stdout.write(`${VERSION}\n`); - if (invocation.kind === 'doctor') return void await doctor(); - +export function run(argv = process.argv.slice(2)) { if (!isSupportedNodeVersion(process.versions.node)) { process.stderr.write(`dshx: unsupported Node ${process.version}; required ${PACKAGE.engines.node}\n`); - process.exitCode = 1; - return; - } - - const executable = tuiBinary(); - if (!fs.existsSync(executable)) { - process.stderr.write(`dshx: packaged TUI binary not found (${executable}); run \`dshx doctor\`\n`); - process.exitCode = 127; - return; + return 1; } let profile; try { profile = bootstrapSurfaceProfile().profile; } catch (error) { - process.stderr.write(`dshx: ${error instanceof Error ? error.message : error}\n`); - process.exitCode = 1; - return; + process.stderr.write(`dshx: ${error instanceof Error ? error.message : String(error)}\n`); + return 1; } const dsh = resolveDshInvocation(ROOT); - const backendCommand = [dsh.command, ...dsh.args, '--profile', profile, '--dshx-app-server']; - const child = spawn(executable, invocation.tuiArgs ?? [], { - cwd: process.cwd(), - env: { - ...process.env, - CODEX_HOME: tuiHome(), - DSHX_APP_SERVER_CMD: JSON.stringify(backendCommand), - ...(invocation.resumeEnv ?? {}) - }, - stdio: 'inherit', - windowsHide: false - }); - child.on('error', (error) => { - process.stderr.write(`dshx: failed to start pinned TUI: ${error.message}\n`); - process.exitCode = 127; - }); - child.on('exit', (code, signal) => { - if (signal && process.env.DSHX_DEBUG === '1') process.stderr.write(`[dshx] TUI exited via ${signal}\n`); - process.exitCode = code ?? (signal ? 1 : 0); - }); + const result = spawnSync( + dsh.command, + [...dsh.args, '--profile', profile, ...argv], + { + cwd: process.cwd(), + env: process.env, + stdio: 'inherit', + shell: false, + windowsHide: false + } + ); + if (result.error) { + process.stderr.write(`dshx: failed to start official DSH profile: ${result.error.message}\n`); + return result.error.code === 'ENOENT' ? 127 : 1; + } + if (result.signal) { + if (process.env.DSHX_DEBUG === '1') process.stderr.write(`[dshx] dsh --profile ${profile} exited via ${result.signal}\n`); + return 1; + } + return result.status ?? 1; } -await run(); +process.exitCode = run(); diff --git a/cordis.patch.yml b/cordis.patch.yml index 50ecf87c..069ca20c 100644 --- a/cordis.patch.yml +++ b/cordis.patch.yml @@ -1,17 +1,8 @@ -# The DSHX presentation bundle rides on the profile's official DSH base. -# The package manifest declares `dsh.bundle.patch`; the loader applies this -# patch in `dsh.profile.bundles` order and owns row lifecycle. -# -# Only competing headless presentation rows are disabled. Runtime capability -# rows remain entirely host-owned and user-authoritative. -# -# The launcher hands the private `--dshx-app-server` sentinel through the -# official cmdlineArgs service. dshx-startup publishes that launch fact and -# dshx-presentation binds NDJSON stdio directly to the already-mounted Context. -- id: headless-startup - disabled: true -- id: headless-runner - disabled: true +# DSHX is a standard presentation bundle over the profile's official DSH base. +# `dsh --profile tui` is the application entry point. The startup row receives +# the launcher's immutable cmdlineArgs snapshot; the presentation runner waits +# for the Loader tree to settle, launches the pinned native TUI, and binds its +# inherited fd 3 protocol pipe directly to the live DSH Context. - insert: - id: dshx-startup diff --git a/src/dsh/presentation-plugin.mjs b/src/dsh/presentation-plugin.mjs index 906fbe96..3f230068 100644 --- a/src/dsh/presentation-plugin.mjs +++ b/src/dsh/presentation-plugin.mjs @@ -1,18 +1,28 @@ +import fs from 'node:fs'; +import path from 'node:path'; import process from 'node:process'; +import { spawn } from 'node:child_process'; +import { fileURLToPath } from 'node:url'; import z from '@deepseek-ai/schemastery'; import { startDshxStdioTransport } from './stdio-transport.mjs'; /** - * dshx-presentation — presentation framing over the live DSH composition. - * No Harness runtime or network/socket host is created by this row. + * dshx-presentation — native TUI runner over the live DSH composition. + * + * The official `dsh --profile tui` process is the parent/runtime owner. This + * row launches only the pinned presentation binary. Terminal fds 0/1/2 are + * inherited by the TUI; fd 3 is a private duplex NDJSON pipe bound directly to + * the already-mounted DSH Context. */ + +const PACKAGE_ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../..'); +const PROTOCOL_FD = 3; + export const name = 'dshx-presentation'; export const inject = ['dshxStartup']; export const Config = z.object({}); export const SERVICE_KEY = 'dshxPresentation'; -export const internals = { startStdio: startDshxStdioTransport }; - function appExit(ctx) { if (typeof ctx?.get === 'function') { const value = ctx.get('appExit'); @@ -32,32 +42,118 @@ function requestHostExit(ctx, code, log) { log(`DSH launcher did not provide appExit; recorded process.exitCode=${code}`); } -export async function apply(ctx) { - if (!ctx || typeof ctx.provide !== 'function') { - throw new Error('dshx-presentation requires a Cordis Context with provide()'); +export function resolveTuiBinary(environment = process.env, platform = process.platform) { + if (environment.DSHX_TUI_BIN) return path.resolve(environment.DSHX_TUI_BIN); + return path.join(PACKAGE_ROOT, 'dist', 'bin', platform === 'win32' ? 'dshx-tui.exe' : 'dshx-tui'); +} + +function protocolStdioMode(platform = process.platform) { + return platform === 'win32' ? 'overlapped' : 'pipe'; +} + +export const internals = { + spawnTui: spawn, + startTransport: startDshxStdioTransport +}; + +export function apply(ctx) { + if (!ctx || typeof ctx.provide !== 'function' || typeof ctx.get !== 'function') { + throw new Error('dshx-presentation requires a live Cordis Context'); } const launch = ctx.dshxStartup; - if (!launch || typeof launch.home !== 'string') { - throw new Error('dshx-presentation requires the dshxStartup service (mount dshx-startup first)'); - } - if (launch.appServer !== true) { - throw new Error('dshx-presentation is a stdio app-server surface; launch it through `dshx`'); + if (!launch || typeof launch.home !== 'string' || !Array.isArray(launch.tuiArgs)) { + throw new Error('dshx-presentation requires the dshxStartup service'); } const log = launch.debug === true ? (message) => process.stderr.write(`[dshx] ${message}\n`) : () => {}; - const transport = internals.startStdio({ - ctx, - cwd: launch.cwd, - home: launch.home, - version: launch.version, - diagnostics: log, - onEof: (error) => requestHostExit(ctx, error ? 1 : 0, log) - }); + const state = { + child: undefined, + transport: undefined, + closing: false, + finished: false + }; - ctx.provide(SERVICE_KEY, Object.freeze({ mode: 'stdio', close: transport.close })); - return transport.close; + const close = async () => { + if (state.closing) return; + state.closing = true; + try { await state.transport?.close?.(); } catch {} + const child = state.child; + if (child && child.exitCode == null && child.signalCode == null) { + try { child.kill('SIGTERM'); } catch {} + } + }; + + const finish = async (code, detail) => { + if (state.finished) return; + state.finished = true; + try { await state.transport?.close?.(); } catch {} + if (state.closing) return; + if (detail) log(detail); + requestHostExit(ctx, code, log); + }; + + const launchTui = async () => { + const loader = ctx.get('loader'); + await loader?.await?.(); + if (state.closing) return; + + fs.mkdirSync(launch.home, { recursive: true, mode: 0o700 }); + const executable = resolveTuiBinary(process.env); + if (!fs.existsSync(executable)) { + throw new Error(`packaged DSHX TUI binary not found: ${executable}`); + } + + const child = internals.spawnTui(executable, launch.tuiArgs, { + cwd: launch.cwd, + env: { + ...process.env, + CODEX_HOME: launch.home, + DSHX_APP_SERVER_FD: String(PROTOCOL_FD) + }, + stdio: ['inherit', 'inherit', 'inherit', protocolStdioMode()], + windowsHide: false + }); + state.child = child; + + const protocol = child.stdio?.[PROTOCOL_FD]; + if (!protocol || typeof protocol.on !== 'function' || typeof protocol.write !== 'function') { + try { child.kill('SIGTERM'); } catch {} + throw new Error(`native TUI did not expose inherited protocol fd ${PROTOCOL_FD}`); + } + + state.transport = internals.startTransport({ + ctx, + cwd: launch.cwd, + home: launch.home, + version: launch.version, + input: protocol, + output: protocol, + diagnostics: log, + onEof: (error) => { + if (error && !state.closing) { + log(`protocol pipe closed with error: ${error instanceof Error ? error.message : String(error)}`); + try { child.kill('SIGTERM'); } catch {} + } + } + }); + + child.once('error', (error) => { + void finish(1, `native TUI spawn failed: ${error.message}`); + }); + child.once('exit', (code, signal) => { + const exitCode = typeof code === 'number' ? code : (signal ? 1 : 0); + void finish(exitCode, signal ? `native TUI exited via ${signal}` : undefined); + }); + }; + + ctx.provide(SERVICE_KEY, Object.freeze({ mode: 'inherited-pipe', fd: PROTOCOL_FD, close })); + void launchTui().catch((error) => { + void finish(1, `failed to launch native TUI: ${error instanceof Error ? error.stack ?? error.message : String(error)}`); + }); + return close; } export const plugin = { name, inject, Config, apply }; +export const constants = { PACKAGE_ROOT, PROTOCOL_FD }; diff --git a/src/dsh/profile-bootstrap.mjs b/src/dsh/profile-bootstrap.mjs index b22ee208..1c5060dc 100644 --- a/src/dsh/profile-bootstrap.mjs +++ b/src/dsh/profile-bootstrap.mjs @@ -6,16 +6,13 @@ import { spawnSync } from 'node:child_process'; import { createRequire } from 'node:module'; /** - * Shared bootstrap over the official DSH plugin machinery. + * Shared bootstrap over the official DSH profile/plugin machinery. * - * The surface ships as a standard profile bundle; every entry point (the - * zero-argument CLI, the smoke scripts, CI) ensures the selected profile - * carries this exact package version by running the official - * `dsh plugin --profile

add ` command, which owns profile - * initialization, pnpm installation and bundles reconciliation. + * DSHX is a standard profile bundle. The UX launcher only ensures that the + * selected profile carries this exact bundle version; the official `dsh` + * process remains the application host and owns composition/lifecycle. */ -/** Resolve the DSH home directory exactly like the official launcher. */ export function dshHomeDir(environment = process.env) { return environment.DSH_HOME || path.join(os.homedir(), '.dsh'); } @@ -24,59 +21,89 @@ export function profileManifestPath(profileName, environment = process.env) { return path.join(dshHomeDir(environment), 'profiles', profileName, 'package.json'); } -/** - * How to invoke the official dsh CLI. Host fidelity first: a `dsh` on the - * user's PATH IS their installed DeepSeek Harness (same build that powers - * their other surfaces and wrote their state files), so it always wins. - * Only when none exists do we fall back to the dependency-local CLI from - * npm ci — fresh machines and CI. - */ -function isExecutable(candidate) { +function isExecutable(candidate, platform = process.platform) { try { + if (!fs.existsSync(candidate)) return false; + if (platform === 'win32') return true; fs.accessSync(candidate, fs.constants.X_OK); - return fs.existsSync(candidate); + return true; } catch { return false; } } -export function resolveDshInvocation(fromDirectory = process.cwd(), environment = process.env) { +function dependencyCliFrom(directory) { + try { + const anchor = createRequire(path.join(directory, 'package.json')).resolve('@deepseek-ai/dsh/package.json'); + const cli = path.join(path.dirname(anchor), 'lib', 'bin.js'); + return fs.existsSync(cli) ? cli : undefined; + } catch { + return undefined; + } +} + +/** + * Resolve the user's real DSH launcher. PATH wins. On Windows npm exposes a + * `dsh.cmd` shim; Rust/native children cannot execute batch files directly, so + * resolve that shim back to the same installation's JS bin and invoke it with + * the current Node executable. No shell command string is constructed. + */ +export function resolveDshInvocation( + fromDirectory = process.cwd(), + environment = process.env, + platform = process.platform +) { if (environment.DSHX_DSH_BIN) { return { command: process.execPath, args: [environment.DSHX_DSH_BIN] }; } - const extensions = process.platform === 'win32' ? ['dsh.cmd', 'dsh.exe', 'dsh'] : ['dsh']; + + const names = platform === 'win32' ? ['dsh.cmd', 'dsh.exe', 'dsh'] : ['dsh']; for (const directory of (environment.PATH || '').split(path.delimiter)) { if (!directory) continue; - for (const name of extensions) { + for (const name of names) { const candidate = path.join(directory, name); - if (isExecutable(candidate)) return { command: candidate, args: [] }; + if (!isExecutable(candidate, platform)) continue; + if (platform === 'win32' && name.toLowerCase().endsWith('.cmd')) { + const cli = dependencyCliFrom(directory); + if (!cli) { + throw new Error(`found ${candidate} but could not resolve the matching @deepseek-ai/dsh/lib/bin.js`); + } + return { command: process.execPath, args: [cli] }; + } + return { command: candidate, args: [] }; } } + + const localCli = dependencyCliFrom(fromDirectory); + if (localCli) return { command: process.execPath, args: [localCli] }; + return { command: 'dsh', args: [] }; +} + +/** Resolve the package version actually visible from one profile dependency tree. */ +export function installedProfilePackageVersion(profileName, packageName, environment = process.env) { + const manifestPath = profileManifestPath(profileName, environment); try { - const anchor = createRequire(path.join(fromDirectory, 'package.json')).resolve( - '@deepseek-ai/dsh/package.json' - ); - const cli = path.join(path.dirname(anchor), 'lib', 'bin.js'); - if (fs.existsSync(cli)) return { command: process.execPath, args: [cli] }; + const packageJsonPath = createRequire(manifestPath).resolve(`${packageName}/package.json`); + const installed = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8')); + return typeof installed.version === 'string' ? installed.version : undefined; } catch { - // Not installed locally; fall through to bare PATH lookup. + return undefined; } - return { command: 'dsh', args: [] }; } -/** A profile satisfies bootstrap when it pins this exact version as a bundle layer. */ -export function profileSatisfied(manifest, { name, version }) { +/** + * Profile satisfaction is about installed state, not the dependency spec text: + * pnpm may record local/global installs as `link:`/`file:` while resolving the + * exact package version requested by the launcher. + */ +export function profileSatisfied(manifest, { name, version }, installedVersion = undefined) { if (!manifest || typeof manifest !== 'object') return false; const bundles = manifest.dsh?.profile?.bundles ?? []; const dependencies = manifest.dependencies ?? {}; - return dependencies[name] === version && bundles.includes(name); + const resolvedVersion = installedVersion ?? (dependencies[name] === version ? version : undefined); + return dependencies[name] !== undefined && bundles.includes(name) && resolvedVersion === version; } -/** - * Ensure `profileName` exists and carries `{name}@{version}` from - * `packageRoot` as an activated bundle layer. Idempotent: satisfied profiles - * are left untouched, honoring DSHX_SKIP_PROFILE_BOOTSTRAP=1 for offline runs. - */ export function ensureProfileInstalled({ packageRoot, name, @@ -87,28 +114,23 @@ export function ensureProfileInstalled({ } = {}) { let satisfied = false; try { - satisfied = profileSatisfied(JSON.parse(fs.readFileSync(profileManifestPath(profile, environment), 'utf8')), { - name, - version - }); + const manifest = JSON.parse(fs.readFileSync(profileManifestPath(profile, environment), 'utf8')); + const installedVersion = installedProfilePackageVersion(profile, name, environment); + satisfied = profileSatisfied(manifest, { name, version }, installedVersion); } catch { - // Missing or unreadable manifest: the official command initializes it. + // Missing/unreadable profile: the official plugin command initializes it. } if (satisfied) return { profile, action: 'already-installed' }; - if (environment.DSHX_SKIP_PROFILE_BOOTSTRAP === '1') { - return { profile, action: 'skipped' }; - } + if (environment.DSHX_SKIP_PROFILE_BOOTSTRAP === '1') return { profile, action: 'skipped' }; const { command, args } = resolveDshInvocation(packageRoot, environment); const result = spawnSyncImpl( command, [...args, 'plugin', '--profile', profile, 'add', packageRoot], - { stdio: 'inherit', shell: process.platform === 'win32' } + { stdio: 'inherit', shell: false } ); if (result.error?.code === 'ENOENT') { - throw new Error( - "official 'dsh' CLI not found (looked up DSHX_DSH_BIN, @deepseek-ai/dsh dependency and PATH); install DeepSeek Harness to manage the DSHX surface profile" - ); + throw new Error("official 'dsh' CLI not found; install DeepSeek Harness to manage the DSHX profile"); } if (result.status !== 0) { throw new Error(`failed to install ${name} into profile '${profile}' via dsh plugin add (exit ${result.status ?? '?'})`); diff --git a/src/dsh/startup-plugin.mjs b/src/dsh/startup-plugin.mjs index 1bd4df3d..1c49af4e 100644 --- a/src/dsh/startup-plugin.mjs +++ b/src/dsh/startup-plugin.mjs @@ -1,18 +1,18 @@ -import fs from 'node:fs'; import os from 'node:os'; import path from 'node:path'; +import fs from 'node:fs'; import { fileURLToPath } from 'node:url'; import z from '@deepseek-ai/schemastery'; /** - * dshx-startup — resolve the private app-server launch handshake supplied by - * the official DSH launcher. The host owns argv and publishes the immutable - * inner arguments through cmdlineArgs; this row only recognizes DSHX's private - * stdio sentinel and publishes the presentation launch descriptor. + * dshx-startup — ordinary app-argument provider for the `tui` profile. + * + * The official DSH launcher owns argv and exposes the immutable inner arguments + * through `ctx.cmdlineArgs`. DSHX does not need a private app-server sentinel: + * `dsh --profile tui ` is itself the surface invocation. */ const PACKAGE_ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../..'); -const APP_SERVER_ARG = '--dshx-app-server'; let cachedVersion; export const name = 'dshx-startup'; @@ -24,33 +24,25 @@ export function resolveVersion() { return cachedVersion; } -export function isStdioAppServerInvocation(cmdlineArgs = []) { - return Array.from(cmdlineArgs, String).includes(APP_SERVER_ARG); -} - export function resolveLaunchDescriptor(environment = process.env, cmdlineArgs = []) { - return { + return Object.freeze({ cwd: process.cwd(), home: path.resolve(environment.DSHX_TUI_HOME || path.join(os.homedir(), '.dshx', 'codex-tui')), version: resolveVersion(), debug: environment.DSHX_DEBUG === '1', - appServer: isStdioAppServerInvocation(cmdlineArgs) - }; + tuiArgs: Object.freeze(Array.from(cmdlineArgs, String)) + }); } export function apply(ctx) { const cmdlineArgs = ctx.cmdlineArgs?.get?.() ?? []; - const launch = resolveLaunchDescriptor(process.env, cmdlineArgs); - fs.mkdirSync(launch.home, { recursive: true, mode: 0o700 }); - ctx.provide('dshxStartup', launch); + ctx.provide('dshxStartup', resolveLaunchDescriptor(process.env, cmdlineArgs)); } export const plugin = { name, inject, Config, apply }; export const internals = { - APP_SERVER_ARG, PACKAGE_ROOT, - isStdioAppServerInvocation, resolveLaunchDescriptor, resolveVersion }; diff --git a/test/dshx-presentation-plugin.test.mjs b/test/dshx-presentation-plugin.test.mjs index 1831c1c1..4ea65dc5 100644 --- a/test/dshx-presentation-plugin.test.mjs +++ b/test/dshx-presentation-plugin.test.mjs @@ -1,4 +1,6 @@ import assert from 'node:assert/strict'; +import { EventEmitter } from 'node:events'; +import { PassThrough } from 'node:stream'; import { readFileSync } from 'node:fs'; import test from 'node:test'; import { fileURLToPath } from 'node:url'; @@ -8,14 +10,14 @@ import { Config, plugin, internals, - SERVICE_KEY + SERVICE_KEY, + constants } from '../src/dsh/presentation-plugin.mjs'; import { name as startupName, inject as startupInject, Config as startupConfig, - plugin as startupPlugin, - internals as startupInternals + plugin as startupPlugin } from '../src/dsh/startup-plugin.mjs'; const LAUNCH = { @@ -23,20 +25,37 @@ const LAUNCH = { home: '/home/test/.dshx/codex-tui', version: 'test', debug: true, - appServer: true + tuiArgs: ['resume', '--last'] }; +function tick() { return new Promise((resolve) => setImmediate(resolve)); } + +function fakeChild() { + const child = new EventEmitter(); + child.stdio = [null, null, null, new PassThrough()]; + child.exitCode = null; + child.signalCode = null; + child.killed = false; + child.kill = () => { child.killed = true; return true; }; + return child; +} + function fakeContext(launch = LAUNCH, onExit = () => {}) { const provided = new Map(); + let loaderAwaited = 0; const ctx = { dshxStartup: launch, provide: (key, value) => provided.set(key, value), - get: (key) => key === 'appExit' ? onExit : undefined + get: (key) => { + if (key === 'appExit') return onExit; + if (key === 'loader') return { await: async () => { loaderAwaited += 1; } }; + return undefined; + } }; - return { ctx, provided }; + return { ctx, provided, loaderAwaited: () => loaderAwaited }; } -test('both rows expose named Cordis plugin contracts', () => { +test('startup and presentation expose ordinary Cordis plugin contracts', () => { assert.equal(startupName, 'dshx-startup'); assert.deepEqual(startupInject, ['cmdlineArgs']); assert.equal(typeof startupConfig, 'function'); @@ -57,10 +76,10 @@ test('both rows expose named Cordis plugin contracts', () => { } }); -test('startup consumes the official cmdlineArgs service and selects stdio mode', () => { +test('startup publishes the raw official profile arguments for the native TUI', () => { const provided = new Map(); const ctx = { - cmdlineArgs: { get: () => ['--dshx-app-server'] }, + cmdlineArgs: { get: () => ['resume', '--last'] }, provide: (key, value) => provided.set(key, value) }; const previous = process.env.DSHX_TUI_HOME; @@ -69,54 +88,89 @@ test('startup consumes the official cmdlineArgs service and selects stdio mode', startupPlugin.apply(ctx); const launch = provided.get('dshxStartup'); assert.equal(launch.home, '/tmp/dshx-launch-home'); - assert.equal(launch.appServer, true); - assert.equal(launch.version, JSON.parse(readFileSync(new URL('../package.json', import.meta.url), 'utf8')).version); - assert.equal(startupInternals.isStdioAppServerInvocation(['--other']), false); + assert.deepEqual(launch.tuiArgs, ['resume', '--last']); + assert.equal('appServer' in launch, false); assert.equal('bridgeCommand' in launch, false); - assert.equal('tuiCommand' in launch, false); + assert.equal(launch.version, JSON.parse(readFileSync(new URL('../package.json', import.meta.url), 'utf8')).version); } finally { if (previous === undefined) delete process.env.DSHX_TUI_HOME; else process.env.DSHX_TUI_HOME = previous; } }); -test('presentation binds stdio directly to the live DSH Context and exits through appExit', async () => { +test('presentation waits for Loader settlement, launches TUI with inherited fd3, and exits through appExit', async () => { const exits = []; - const { ctx, provided } = fakeContext(LAUNCH, (code) => exits.push(code)); - const started = []; - let closed = 0; - const original = internals.startStdio; - internals.startStdio = (options) => { - started.push(options); - return { mode: 'stdio', close: async () => { closed += 1; } }; + const { ctx, provided, loaderAwaited } = fakeContext(LAUNCH, (code) => exits.push(code)); + const child = fakeChild(); + const spawned = []; + const transports = []; + const originalSpawn = internals.spawnTui; + const originalTransport = internals.startTransport; + const previousTui = process.env.DSHX_TUI_BIN; + process.env.DSHX_TUI_BIN = fileURLToPath(new URL('../package.json', import.meta.url)); + internals.spawnTui = (command, args, options) => { + spawned.push({ command, args, options }); + return child; + }; + internals.startTransport = (options) => { + transports.push(options); + return { mode: 'stdio', close: async () => {} }; }; try { - const dispose = await plugin.apply(ctx, {}); - assert.equal(started.length, 1); - assert.equal(started[0].ctx, ctx, 'the row must use the already-mounted composition'); - assert.equal(started[0].home, LAUNCH.home); - assert.equal(typeof started[0].onEof, 'function'); + const dispose = plugin.apply(ctx, {}); + assert.equal(typeof dispose, 'function'); + assert.equal(spawned.length, 0, 'apply must return before loader.await() settles'); + await tick(); + assert.equal(loaderAwaited(), 1); + assert.equal(spawned.length, 1); + assert.deepEqual(spawned[0].args, LAUNCH.tuiArgs); + assert.deepEqual(spawned[0].options.stdio.slice(0, 3), ['inherit', 'inherit', 'inherit']); + assert.equal(spawned[0].options.env.DSHX_APP_SERVER_FD, String(constants.PROTOCOL_FD)); + assert.equal(transports.length, 1); + assert.equal(transports[0].ctx, ctx, 'protocol adapter must use the live profile Context'); + assert.equal(transports[0].input, child.stdio[3]); + assert.equal(transports[0].output, child.stdio[3]); const service = provided.get(SERVICE_KEY); - assert.equal(service.mode, 'stdio'); - assert.equal(service.url, undefined); - assert.equal(typeof service.close, 'function'); + assert.equal(service.mode, 'inherited-pipe'); + assert.equal(service.fd, 3); + assert.deepEqual(exits, []); - started[0].onEof(); + child.exitCode = 0; + child.emit('exit', 0, null); + await tick(); assert.deepEqual(exits, [0]); await dispose(); - assert.equal(closed, 1); } finally { - internals.startStdio = original; + internals.spawnTui = originalSpawn; + internals.startTransport = originalTransport; + if (previousTui === undefined) delete process.env.DSHX_TUI_BIN; + else process.env.DSHX_TUI_BIN = previousTui; } }); -test('presentation rejects accidental non-app-server profile launches', async () => { - const { ctx } = fakeContext({ ...LAUNCH, appServer: false }); - await assert.rejects(() => plugin.apply(ctx, {}), /launch it through `dshx`/); -}); - -test('presentation refuses contexts without the Cordis seams', async () => { - await assert.rejects(() => plugin.apply({}, {}), /requires a Cordis Context with provide/); - await assert.rejects(() => plugin.apply({ provide: () => {} }, {}), /requires the dshxStartup service/); +test('disposal terminates a still-running TUI without requesting another host exit', async () => { + const exits = []; + const { ctx } = fakeContext(LAUNCH, (code) => exits.push(code)); + const child = fakeChild(); + const originalSpawn = internals.spawnTui; + const originalTransport = internals.startTransport; + const previousTui = process.env.DSHX_TUI_BIN; + process.env.DSHX_TUI_BIN = fileURLToPath(new URL('../package.json', import.meta.url)); + internals.spawnTui = () => child; + internals.startTransport = () => ({ close: async () => {} }); + try { + const dispose = plugin.apply(ctx, {}); + await tick(); + await dispose(); + assert.equal(child.killed, true); + child.emit('exit', 0, null); + await tick(); + assert.deepEqual(exits, []); + } finally { + internals.spawnTui = originalSpawn; + internals.startTransport = originalTransport; + if (previousTui === undefined) delete process.env.DSHX_TUI_BIN; + else process.env.DSHX_TUI_BIN = previousTui; + } }); diff --git a/test/dshx-profile-bootstrap.test.mjs b/test/dshx-profile-bootstrap.test.mjs index 7e54dbc5..bcaa958a 100644 --- a/test/dshx-profile-bootstrap.test.mjs +++ b/test/dshx-profile-bootstrap.test.mjs @@ -2,12 +2,15 @@ import assert from 'node:assert/strict'; import fs from 'node:fs'; import os from 'node:os'; import path from 'node:path'; +import process from 'node:process'; import test from 'node:test'; import { dshHomeDir, profileManifestPath, profileSatisfied, - ensureProfileInstalled + installedProfilePackageVersion, + ensureProfileInstalled, + resolveDshInvocation } from '../src/dsh/profile-bootstrap.mjs'; function temporaryHome(run) { @@ -21,78 +24,106 @@ function temporaryHome(run) { const SELF = { name: '@code-new-bie/dshx-tui', version: '9.9.9-test' }; +function profileDir(home) { + return path.join(home, 'profiles', 'tui'); +} + function writeManifest(home, manifest) { - const dir = path.join(home, 'profiles', 'tui'); + const dir = profileDir(home); fs.mkdirSync(dir, { recursive: true }); fs.writeFileSync(path.join(dir, 'package.json'), JSON.stringify(manifest, null, 2)); } +function writeInstalledPackage(home, version = SELF.version) { + const dir = path.join(profileDir(home), 'node_modules', '@code-new-bie', 'dshx-tui'); + fs.mkdirSync(dir, { recursive: true }); + fs.writeFileSync(path.join(dir, 'package.json'), JSON.stringify({ + name: SELF.name, + version, + exports: { './package.json': './package.json' } + }, null, 2)); +} + test('home and manifest paths honor DSH_HOME exactly like the official launcher', () => { assert.equal(dshHomeDir({}), path.join(os.homedir(), '.dsh')); assert.equal(dshHomeDir({ DSH_HOME: '/tmp/h' }), '/tmp/h'); assert.equal(profileManifestPath('tui', { DSH_HOME: '/tmp/h' }), path.join('/tmp/h', 'profiles', 'tui', 'package.json')); }); -test('profile satisfaction needs the exact version AND bundle-layer membership', () => { - const ok = { dependencies: { [SELF.name]: SELF.version }, dsh: { profile: { bundles: ['@deepseek-ai/dsh-base', SELF.name] } } }; - const wrongVersion = { ...ok, dependencies: { [SELF.name]: '0.0.1' } }; - const missingLayer = { dependencies: { [SELF.name]: SELF.version }, dsh: { profile: { bundles: ['@deepseek-ai/dsh-base'] } } }; - assert.equal(profileSatisfied(ok, SELF), true); - assert.equal(profileSatisfied(wrongVersion, SELF), false); - assert.equal(profileSatisfied(missingLayer, SELF), false); - assert.equal(profileSatisfied(undefined, SELF), false); +test('profile satisfaction uses actual resolved version rather than pnpm link/file spec text', () => { + const linked = { + dependencies: { [SELF.name]: 'link:/opt/dshx' }, + dsh: { profile: { bundles: ['@deepseek-ai/dsh-base', SELF.name] } } + }; + assert.equal(profileSatisfied(linked, SELF, SELF.version), true); + assert.equal(profileSatisfied(linked, SELF, '0.0.1'), false); + assert.equal(profileSatisfied({ ...linked, dependencies: {} }, SELF, SELF.version), false); + assert.equal(profileSatisfied({ ...linked, dsh: { profile: { bundles: ['@deepseek-ai/dsh-base'] } } }, SELF, SELF.version), false); + assert.equal(profileSatisfied(undefined, SELF, SELF.version), false); }); -test('bootstrap installs through the official command when the profile is missing', () => { +test('installed package version resolves from the profile dependency tree', () => { + temporaryHome((home) => { + writeManifest(home, { + name: 'dsh-profile-tui', + private: true, + dependencies: { [SELF.name]: 'link:/opt/dshx' }, + dsh: { profile: { bundles: ['@deepseek-ai/dsh-base', SELF.name] } } + }); + assert.equal(installedProfilePackageVersion('tui', SELF.name, { DSH_HOME: home }), undefined); + writeInstalledPackage(home); + assert.equal(installedProfilePackageVersion('tui', SELF.name, { DSH_HOME: home }), SELF.version); + }); +}); + +test('bootstrap installs through the official plugin command when the profile is missing', () => { temporaryHome((home) => { const calls = []; const result = ensureProfileInstalled({ packageRoot: '/repo', ...SELF, environment: { DSH_HOME: home }, - spawnSyncImpl: (command, args) => { - calls.push([command, args]); + spawnSyncImpl: (command, args, options) => { + calls.push([command, args, options]); return { status: 0 }; } }); assert.equal(result.action, 'installed'); - const forwarded = calls[0][1]; - assert.equal(forwarded[0], 'plugin'); - assert.deepEqual(forwarded.slice(1, 4), ['--profile', 'tui', 'add']); - assert.equal(forwarded.at(-1), '/repo'); + assert.equal(calls[0][1][0], 'plugin'); + assert.deepEqual(calls[0][1].slice(1, 4), ['--profile', 'tui', 'add']); + assert.equal(calls[0][1].at(-1), '/repo'); + assert.equal(calls[0][2].shell, false); }); }); -test('bootstrap is idempotent for satisfied profiles and honors the skip switch', () => { +test('bootstrap is idempotent for linked profiles with the exact installed package', () => { temporaryHome((home) => { writeManifest(home, { name: 'dsh-profile-tui', private: true, - dependencies: { [SELF.name]: SELF.version }, + dependencies: { [SELF.name]: 'link:/opt/dshx' }, dsh: { profile: { bundles: ['@deepseek-ai/dsh-base', SELF.name] } } }); + writeInstalledPackage(home); const spawn = () => ({ status: 1 }); assert.equal( ensureProfileInstalled({ packageRoot: '/repo', ...SELF, environment: { DSH_HOME: home }, spawnSyncImpl: spawn }).action, 'already-installed' ); - // The skip switch only short-circuits profiles that still need work. - fs.writeFileSync( - path.join(home, 'profiles', 'tui', 'package.json'), - JSON.stringify({ - name: 'dsh-profile-tui', - private: true, - dependencies: { [SELF.name]: '0.0.1' }, - dsh: { profile: { bundles: ['@deepseek-ai/dsh-base'] } } - }) - ); - assert.equal( - ensureProfileInstalled({ - packageRoot: '/repo', ...SELF, - environment: { DSH_HOME: home, DSHX_SKIP_PROFILE_BOOTSTRAP: '1' }, - spawnSyncImpl: spawn - }).action, - 'skipped' - ); + }); +}); + +test('Windows npm dsh.cmd shim resolves back to the same installation JS bin without a shell', () => { + temporaryHome((home) => { + const prefix = path.join(home, 'npm'); + const packageDir = path.join(prefix, 'node_modules', '@deepseek-ai', 'dsh'); + const cli = path.join(packageDir, 'lib', 'bin.js'); + fs.mkdirSync(path.dirname(cli), { recursive: true }); + fs.writeFileSync(path.join(prefix, 'dsh.cmd'), '@echo off\r\n'); + fs.writeFileSync(path.join(packageDir, 'package.json'), JSON.stringify({ name: '@deepseek-ai/dsh', exports: { './package.json': './package.json' } })); + fs.writeFileSync(cli, ''); + const resolved = resolveDshInvocation(home, { PATH: prefix }, 'win32'); + assert.equal(resolved.command, process.execPath); + assert.deepEqual(resolved.args, [cli]); }); }); diff --git a/upstream/patches/codex/0012-dshx-inherited-profile-pipe.patch b/upstream/patches/codex/0012-dshx-inherited-profile-pipe.patch new file mode 100644 index 00000000..84bd8339 --- /dev/null +++ b/upstream/patches/codex/0012-dshx-inherited-profile-pipe.patch @@ -0,0 +1,194 @@ +diff --git a/codex-rs/app-server-client/Cargo.toml b/codex-rs/app-server-client/Cargo.toml +--- a/codex-rs/app-server-client/Cargo.toml ++++ b/codex-rs/app-server-client/Cargo.toml +@@ + serde = { workspace = true } + serde_json = { workspace = true } +-tokio = { workspace = true, features = ["sync", "time", "rt", "io-util", "process"] } ++libc = { workspace = true } ++tokio = { workspace = true, features = ["sync", "time", "rt", "io-util", "process", "fs"] } + tokio-tungstenite = { workspace = true } +diff --git a/codex-rs/app-server-client/src/stdio.rs b/codex-rs/app-server-client/src/stdio.rs +--- a/codex-rs/app-server-client/src/stdio.rs ++++ b/codex-rs/app-server-client/src/stdio.rs +@@ + use std::io::Error as IoError; + use std::io::ErrorKind; + use std::io::Result as IoResult; +-use std::process::Stdio; ++use std::fs::File as StdFile; ++use std::pin::Pin; ++#[cfg(unix)] ++use std::os::fd::FromRawFd; ++#[cfg(windows)] ++use std::os::windows::io::FromRawHandle; +@@ ++use tokio::fs::File as TokioFile; + use tokio::io::AsyncBufReadExt; ++use tokio::io::AsyncRead; ++use tokio::io::AsyncWrite; + use tokio::io::AsyncWriteExt; + use tokio::io::BufReader; +-use tokio::process::ChildStdin; +-use tokio::process::Command; +@@ + const INITIALIZE_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(30); ++ ++type BoxReader = Pin>; ++type BoxWriter = Pin>; +@@ + pub struct StdioAppServerConnectArgs { +- pub command: Vec, ++ pub fd: i32, +@@ + impl StdioAppServerClient { + pub async fn connect(args: StdioAppServerConnectArgs) -> IoResult { +- let executable = args.command.first().filter(|value| !value.is_empty()).ok_or_else(|| { +- IoError::new(ErrorKind::InvalidInput, "stdio app-server command must not be empty") +- })?; +- let mut command = Command::new(executable); +- command +- .args(&args.command[1..]) +- .stdin(Stdio::piped()) +- .stdout(Stdio::piped()) +- .stderr(Stdio::inherit()) +- .kill_on_drop(true); +- let mut child = command.spawn().map_err(|err| { +- IoError::new( +- err.kind(), +- format!("failed to spawn stdio app server `{executable}`: {err}"), +- ) +- })?; +- let mut stdin = child.stdin.take().ok_or_else(|| { +- IoError::new(ErrorKind::BrokenPipe, "stdio app-server stdin was not piped") +- })?; +- let stdout = child.stdout.take().ok_or_else(|| { +- IoError::new(ErrorKind::BrokenPipe, "stdio app-server stdout was not piped") +- })?; ++ if args.fd < 3 { ++ return Err(IoError::new(ErrorKind::InvalidInput, "DSHX protocol fd must be >= 3")); ++ } ++ let stream = inherited_protocol_file(args.fd)?; ++ let reader = stream.try_clone()?; ++ let mut stdin: BoxWriter = Box::pin(TokioFile::from_std(stream)); ++ let stdout: BoxReader = Box::pin(TokioFile::from_std(reader)); + let mut lines = BufReader::new(stdout).lines(); +- let endpoint = format!("stdio://{}", executable); ++ let endpoint = format!("fd://{}", args.fd); +@@ + StdioClientCommand::Shutdown { response_tx } => { +- let mut result = stdin.shutdown().await; +- if result.is_ok() { +- result = match timeout(SHUTDOWN_TIMEOUT, child.wait()).await { +- Ok(Ok(_status)) => Ok(()), +- Ok(Err(err)) => Err(err), +- Err(_) => { +- let _ = child.kill().await; +- Err(IoError::new( +- ErrorKind::TimedOut, +- format!("timed out shutting down stdio app server `{endpoint}`"), +- )) +- } +- }; +- } ++ let result = stdin.shutdown().await; + clean_shutdown = result.is_ok(); + let _ = response_tx.send(result); + break; +@@ + if !clean_shutdown { + let _ = stdin.shutdown().await; +- if child.try_wait().ok().flatten().is_none() { +- let _ = child.kill().await; +- } + } +@@ + async fn initialize_stdio_connection( +- stdin: &mut ChildStdin, +- lines: &mut tokio::io::Lines>, ++ stdin: &mut BoxWriter, ++ lines: &mut tokio::io::Lines>, +@@ +-async fn write_jsonrpc_line(stdin: &mut ChildStdin, message: JSONRPCMessage, endpoint: &str) -> IoResult<()> { ++async fn write_jsonrpc_line(stdin: &mut BoxWriter, message: JSONRPCMessage, endpoint: &str) -> IoResult<()> { +@@ + fn deliver_event(event_tx: &mpsc::UnboundedSender, event: AppServerEvent) -> IoResult<()> { + event_tx.send(event).map_err(|_| IoError::new(ErrorKind::BrokenPipe, "stdio app-server event consumer is closed")) + } ++ ++#[cfg(unix)] ++fn inherited_protocol_file(fd: i32) -> IoResult { ++ // fd ownership is intentionally transferred to the app-server client; the ++ // TUI is the only consumer of the inherited DSHX protocol descriptor. ++ Ok(unsafe { StdFile::from_raw_fd(fd) }) ++} ++ ++#[cfg(windows)] ++fn inherited_protocol_file(fd: i32) -> IoResult { ++ let handle = unsafe { libc::_get_osfhandle(fd) }; ++ if handle == -1 { ++ return Err(IoError::last_os_error()); ++ } ++ Ok(unsafe { StdFile::from_raw_handle(handle as std::os::windows::io::RawHandle) }) ++} +diff --git a/codex-rs/tui/src/main.rs b/codex-rs/tui/src/main.rs +--- a/codex-rs/tui/src/main.rs ++++ b/codex-rs/tui/src/main.rs +@@ +- let dshx_command_json = std::env::var("DSHX_APP_SERVER_CMD").map_err(|_| { +- anyhow::anyhow!( +- "DSHX_APP_SERVER_CMD is required; DSHX never falls back to the Codex agent runtime" +- ) +- })?; +- let dshx_command: Vec = serde_json::from_str(&dshx_command_json) +- .map_err(|err| anyhow::anyhow!("invalid DSHX_APP_SERVER_CMD JSON: {err}"))?; +- if dshx_command.is_empty() || dshx_command[0].is_empty() { +- anyhow::bail!("DSHX_APP_SERVER_CMD must contain a non-empty executable argv[0]"); +- } ++ let dshx_fd: i32 = std::env::var("DSHX_APP_SERVER_FD") ++ .map_err(|_| anyhow::anyhow!("DSHX_APP_SERVER_FD is required; DSHX never falls back to the Codex agent runtime"))? ++ .parse() ++ .map_err(|err| anyhow::anyhow!("invalid DSHX_APP_SERVER_FD: {err}"))?; ++ if dshx_fd < 3 { ++ anyhow::bail!("DSHX_APP_SERVER_FD must be an inherited descriptor >= 3"); ++ } + let dshx_endpoint = RemoteAppServerEndpoint::StdioChild { +- command: dshx_command, ++ command: vec![format!("fd:{dshx_fd}")], + }; +diff --git a/codex-rs/tui/src/lib.rs b/codex-rs/tui/src/lib.rs +--- a/codex-rs/tui/src/lib.rs ++++ b/codex-rs/tui/src/lib.rs +@@ + fn dshx_backend() -> bool { +- std::env::var_os("DSHX_APP_SERVER_CMD").is_some() ++ std::env::var_os("DSHX_APP_SERVER_FD").is_some() + } +@@ + RemoteAppServerEndpoint::StdioChild { command } => { ++ let fd = command ++ .first() ++ .and_then(|value| value.strip_prefix("fd:")) ++ .and_then(|value| value.parse::().ok()) ++ .ok_or_else(|| color_eyre::eyre::eyre!("invalid inherited DSHX protocol fd endpoint"))?; + let app_server = StdioAppServerClient::connect(StdioAppServerConnectArgs { +- command, ++ fd, + client_name, + client_version, +diff --git a/codex-rs/tui/src/bottom_pane/approval_overlay.rs b/codex-rs/tui/src/bottom_pane/approval_overlay.rs +--- a/codex-rs/tui/src/bottom_pane/approval_overlay.rs ++++ b/codex-rs/tui/src/bottom_pane/approval_overlay.rs +@@ + fn dshx_backend() -> bool { +- std::env::var_os("DSHX_APP_SERVER_CMD").is_some() ++ std::env::var_os("DSHX_APP_SERVER_FD").is_some() + } +diff --git a/codex-rs/tui/src/chatwidget/permission_popups.rs b/codex-rs/tui/src/chatwidget/permission_popups.rs +--- a/codex-rs/tui/src/chatwidget/permission_popups.rs ++++ b/codex-rs/tui/src/chatwidget/permission_popups.rs +@@ + fn dshx_backend() -> bool { +- std::env::var_os("DSHX_APP_SERVER_CMD").is_some() ++ std::env::var_os("DSHX_APP_SERVER_FD").is_some() + } From 178d22b139437eed084a1c250c535c4245b257c8 Mon Sep 17 00:00:00 2001 From: code-new-bie <403466121@qq.com> Date: Thu, 27 Aug 2026 20:27:39 +0800 Subject: [PATCH 41/60] test(plugin): verify profile-owned fd3 surface lifecycle --- scripts/fd3-smoke-client.mjs | 52 ++++++++ scripts/runtime-smoke.mjs | 84 +++++------- scripts/verify-bundle-install.mjs | 92 ++++--------- scripts/verify-tui-invariants.mjs | 30 +++-- src/dsh/presentation-plugin.mjs | 9 +- test/dshx-presentation-plugin.test.mjs | 16 +-- test/dshx-upstream-patch-policy.test.mjs | 39 +++--- .../0012-dshx-inherited-profile-pipe.patch | 122 +++++++++--------- 8 files changed, 218 insertions(+), 226 deletions(-) create mode 100755 scripts/fd3-smoke-client.mjs mode change 100644 => 100755 scripts/runtime-smoke.mjs diff --git a/scripts/fd3-smoke-client.mjs b/scripts/fd3-smoke-client.mjs new file mode 100755 index 00000000..7221b0a3 --- /dev/null +++ b/scripts/fd3-smoke-client.mjs @@ -0,0 +1,52 @@ +#!/usr/bin/env node +import fs from 'node:fs'; +import process from 'node:process'; +import { createInterface } from 'node:readline'; + +const FD = Number(process.env.DSHX_APP_SERVER_FD ?? '3'); +const TIMEOUT_MS = Number(process.env.DSHX_FD3_TIMEOUT_MS ?? 30_000); +const SETTLE_MS = Number(process.env.DSHX_FD3_SETTLE_MS ?? 300); + +if (!Number.isInteger(FD) || FD < 3) { + process.stderr.write(`[fd3-smoke] invalid DSHX_APP_SERVER_FD=${JSON.stringify(process.env.DSHX_APP_SERVER_FD)}\n`); + process.exit(2); +} + +const input = fs.createReadStream(null, { fd: FD, autoClose: false, encoding: 'utf8' }); +const lines = createInterface({ input, crlfDelay: Infinity, terminal: false }); +let settled = false; +const timer = setTimeout(() => finish(3, 'timed out waiting for initialize'), TIMEOUT_MS); + +function write(message) { + fs.writeSync(FD, `${JSON.stringify(message)}\n`, null, 'utf8'); +} + +function finish(code, detail) { + if (settled) return; + settled = true; + clearTimeout(timer); + try { lines.close(); } catch {} + if (detail) process.stderr.write(`[fd3-smoke] ${detail}\n`); + setTimeout(() => process.exit(code), code === 0 ? SETTLE_MS : 0); +} + +lines.on('line', (line) => { + let message; + try { message = JSON.parse(line); } catch { return; } + if (message?.id !== 'fd3-smoke') return; + if (message.error) { + finish(4, `initialize rejected: ${message.error.message || JSON.stringify(message.error)}`); + return; + } + write({ method: 'initialized', params: {} }); + process.stdout.write(`DSHX_FD3_SMOKE ${JSON.stringify({ userAgent: message.result?.userAgent ?? null })}\n`); + finish(0); +}); + +input.on('error', (error) => finish(5, `protocol read failed: ${error.message}`)); + +write({ + id: 'fd3-smoke', + method: 'initialize', + params: { clientInfo: { name: 'dshx-fd3-smoke', version: '1' } } +}); diff --git a/scripts/runtime-smoke.mjs b/scripts/runtime-smoke.mjs old mode 100644 new mode 100755 index c2a8b9dc..d734471a --- a/scripts/runtime-smoke.mjs +++ b/scripts/runtime-smoke.mjs @@ -3,21 +3,13 @@ import fs from 'node:fs'; import path from 'node:path'; import process from 'node:process'; import { spawn } from 'node:child_process'; -import { createInterface } from 'node:readline'; import { fileURLToPath } from 'node:url'; import { ensureProfileInstalled, resolveDshInvocation } from '../src/dsh/profile-bootstrap.mjs'; const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..'); const PACKAGE = JSON.parse(fs.readFileSync(path.join(ROOT, 'package.json'), 'utf8')); +const CLIENT = path.join(ROOT, 'scripts', 'fd3-smoke-client.mjs'); const BOOT_TIMEOUT_MS = Number(process.env.DSHX_SMOKE_BOOT_TIMEOUT_MS ?? 90_000); -const EXIT_TIMEOUT_MS = Number(process.env.DSHX_SMOKE_EXIT_TIMEOUT_MS ?? 15_000); -// `initialize` proves the loader tree has mounted, but rc.8's official -// `runProfile()` still finishes its launcher-owned user-patch watcher setup -// immediately afterwards. That phase has intentionally no public plugin seam. -// Give the host one short bounded turn to settle before testing normal EOF; -// tearing the root down inside that private setup window exercises a launcher -// startup race, not the steady-state app-server lifecycle DSHX owns. -const HOST_SETTLE_GRACE_MS = Number(process.env.DSHX_SMOKE_HOST_SETTLE_GRACE_MS ?? 250); const ensured = ensureProfileInstalled({ packageRoot: ROOT, @@ -29,69 +21,51 @@ process.stdout.write(`surface profile '${ensured.profile}' ${ensured.action}\n`) const dsh = resolveDshInvocation(ROOT); await new Promise((resolve, reject) => { - const child = spawn(dsh.command, [...dsh.args, '--profile', ensured.profile, '--dshx-app-server'], { + const child = spawn(dsh.command, [...dsh.args, '--profile', ensured.profile, CLIENT], { cwd: process.cwd(), - env: { ...process.env, DSHX_DEBUG: '1' }, - stdio: ['pipe', 'pipe', 'pipe'], + env: { + ...process.env, + DSHX_DEBUG: '1', + DSHX_TUI_BIN: process.execPath + }, + stdio: ['ignore', 'pipe', 'pipe'], windowsHide: true }); - const lines = createInterface({ input: child.stdout, crlfDelay: Infinity, terminal: false }); - let initialized = false; + let stdout = ''; let stderr = ''; let settled = false; - let timer; - let settleTimer; - const arm = (timeoutMs, label) => { - clearTimeout(timer); - timer = setTimeout(() => finish(new Error(`official DSH stdio ${label} exceeded ${timeoutMs}ms${stderr ? `:\n${stderr}` : ''}`)), timeoutMs); - }; + const timer = setTimeout(() => finish(new Error( + `official DSH TUI profile exceeded ${BOOT_TIMEOUT_MS}ms${stderr ? `:\n${stderr}` : ''}` + )), BOOT_TIMEOUT_MS); const finish = (error) => { if (settled) return; settled = true; clearTimeout(timer); - clearTimeout(settleTimer); - lines.close(); if (error) { try { child.kill('SIGTERM'); } catch {} reject(error); - } else { - resolve(); - } + } else resolve(); }; - arm(BOOT_TIMEOUT_MS, 'boot'); + child.stdout.on('data', (chunk) => { stdout += chunk.toString('utf8'); }); child.stderr.on('data', (chunk) => { stderr = `${stderr}${chunk.toString('utf8')}`.slice(-16384); }); child.on('error', finish); - lines.on('line', (line) => { - let message; - try { message = JSON.parse(line); } catch { return; } - if (message?.id !== 'runtime-smoke') return; - if (message.error) { - finish(new Error(`initialize rejected: ${message.error.message || JSON.stringify(message.error)}`)); + child.on('exit', (code, signal) => { + if (code !== 0) { + finish(new Error(`official DSH TUI profile failed (code ${code ?? '?'} signal ${signal ?? '-'})${stderr ? `:\n${stderr}` : ''}`)); return; } - initialized = true; - process.stdout.write(`official DSH composition mounted: ${message.result?.userAgent ?? 'dshx'}\n`); - child.stdin.write(`${JSON.stringify({ method: 'initialized', params: {} })}\n`); - settleTimer = setTimeout(() => { - if (settled || child.stdin.destroyed) return; - process.stdout.write('official DSH profile boot settled; closing app-server stdin\n'); - child.stdin.end(); - arm(EXIT_TIMEOUT_MS, 'EOF/appExit shutdown'); - }, HOST_SETTLE_GRACE_MS); - }); - child.on('exit', (code, signal) => { - if (!initialized) { - finish(new Error(`official DSH exited before initialize (${signal ?? code ?? 'unknown'})${stderr ? `:\n${stderr}` : ''}`)); - } else if (code !== 0) { - finish(new Error(`official DSH EOF disposal failed (code ${code ?? '?'} signal ${signal ?? '-'})${stderr ? `:\n${stderr}` : ''}`)); - } else { - process.stdout.write('official DSH composition disposed through appExit\n'); - finish(); + const marker = stdout.split(/\r?\n/).find((line) => line.startsWith('DSHX_FD3_SMOKE ')); + if (!marker) { + finish(new Error(`native presentation child never completed fd3 initialize${stderr ? `:\n${stderr}` : ''}`)); + return; + } + const payload = JSON.parse(marker.slice('DSHX_FD3_SMOKE '.length)); + if (!String(payload.userAgent ?? '').startsWith('dshx/')) { + finish(new Error(`unexpected initialize identity: ${JSON.stringify(payload)}`)); + return; } + process.stdout.write(`official DSH composition mounted and served native child: ${payload.userAgent}\n`); + process.stdout.write('native child exit disposed official DSH composition through appExit\n'); + finish(); }); - child.stdin.write(`${JSON.stringify({ - id: 'runtime-smoke', - method: 'initialize', - params: { clientInfo: { name: 'dshx-runtime-smoke', version: PACKAGE.version } } - })}\n`); }); diff --git a/scripts/verify-bundle-install.mjs b/scripts/verify-bundle-install.mjs index ef6f30ed..5bc2b86b 100755 --- a/scripts/verify-bundle-install.mjs +++ b/scripts/verify-bundle-install.mjs @@ -1,14 +1,10 @@ #!/usr/bin/env node -/** - * End-to-end DSH bundle compliance proof using only official host machinery: - * npm pack -> dsh plugin add -> dsh --dump-config -> stdio initialize/EOF. - */ +/** End-to-end standard DSH bundle proof for the profile-owned TUI surface. */ import fs from 'node:fs'; import os from 'node:os'; import path from 'node:path'; import process from 'node:process'; import { spawn, spawnSync } from 'node:child_process'; -import { createInterface } from 'node:readline'; import { fileURLToPath } from 'node:url'; import { resolveDshInvocation } from '../src/dsh/profile-bootstrap.mjs'; @@ -16,7 +12,7 @@ const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..'); const PACKAGE = JSON.parse(fs.readFileSync(path.join(ROOT, 'package.json'), 'utf8')); const NAME = PACKAGE.name; const PROFILE = 'tui'; -const HOST_SETTLE_GRACE_MS = Number(process.env.DSHX_BUNDLE_HOST_SETTLE_GRACE_MS ?? 250); +const CLIENT = path.join(ROOT, 'scripts', 'fd3-smoke-client.mjs'); function fail(message) { console.error(`\n[verify-bundle] FAIL: ${message}`); @@ -31,71 +27,44 @@ function run(command, args, { cwd = ROOT, env = process.env, check = true } = {} return result; } -async function probeStdioSurface({ dsh, cwd, env, profile = PROFILE, timeoutMs = 90_000 }) { +async function probeProfileSurface({ dsh, cwd, env, profile = PROFILE, timeoutMs = 90_000 }) { return await new Promise((resolve, reject) => { - const child = spawn(dsh.command, [...dsh.args, '--profile', profile, '--dshx-app-server'], { + const child = spawn(dsh.command, [...dsh.args, '--profile', profile, CLIENT], { cwd, - env, - stdio: ['pipe', 'pipe', 'pipe'], + env: { ...env, DSHX_TUI_BIN: process.execPath }, + stdio: ['ignore', 'pipe', 'pipe'], windowsHide: true }); - const lines = createInterface({ input: child.stdout, crlfDelay: Infinity, terminal: false }); + let stdout = ''; let stderr = ''; - let initialized; let settled = false; - let settleTimer; const finish = (error, result) => { if (settled) return; settled = true; clearTimeout(timer); - clearTimeout(settleTimer); - lines.close(); if (error) { try { child.kill('SIGTERM'); } catch {} reject(error); - } else { - resolve(result); - } + } else resolve(result); }; - const timer = setTimeout(() => { - finish(new Error(`stdio surface timed out after ${timeoutMs}ms${stderr ? `:\n${stderr}` : ''}`)); - }, timeoutMs); + const timer = setTimeout(() => finish(new Error( + `profile-owned TUI surface timed out after ${timeoutMs}ms${stderr ? `:\n${stderr}` : ''}` + )), timeoutMs); + child.stdout.on('data', (chunk) => { stdout += chunk.toString('utf8'); }); child.stderr.on('data', (chunk) => { stderr = `${stderr}${chunk.toString('utf8')}`.slice(-16384); }); child.on('error', (error) => finish(error)); - lines.on('line', (line) => { - let message; - try { message = JSON.parse(line); } catch { return; } - if (message?.id !== 'verify-bundle') return; - if (message.error) { - finish(new Error(`stdio initialize rejected: ${message.error.message || JSON.stringify(message.error)}`)); - return; - } - initialized = message.result; - child.stdin.write(`${JSON.stringify({ method: 'initialized', params: {} })}\n`); - // initialize proves the bundle rows are mounted. rc.8's official - // runProfile() then completes launcher-owned patch-watcher setup, which - // intentionally has no plugin-facing settle service. Exercise steady- - // state EOF only after that bounded host-only startup window. - settleTimer = setTimeout(() => { - if (!settled && !child.stdin.destroyed) child.stdin.end(); - }, HOST_SETTLE_GRACE_MS); - }); child.on('exit', (code, signal) => { - if (!initialized) { - finish(new Error(`stdio surface exited before initialize (${signal ?? code ?? 'unknown'})${stderr ? `:\n${stderr}` : ''}`)); + if (code !== 0) { + finish(new Error(`profile-owned TUI failed (code ${code ?? '?'} signal ${signal ?? '-'})${stderr ? `:\n${stderr}` : ''}`)); return; } - if (code !== 0) { - finish(new Error(`stdio surface did not honor bounded EOF exit (code ${code ?? '?'} signal ${signal ?? '-'})${stderr ? `:\n${stderr}` : ''}`)); + const marker = stdout.split(/\r?\n/).find((line) => line.startsWith('DSHX_FD3_SMOKE ')); + if (!marker) { + finish(new Error(`presentation child never completed fd3 initialize${stderr ? `:\n${stderr}` : ''}`)); return; } - finish(null, initialized); + finish(null, JSON.parse(marker.slice('DSHX_FD3_SMOKE '.length))); }); - child.stdin.write(`${JSON.stringify({ - id: 'verify-bundle', - method: 'initialize', - params: { clientInfo: { name: 'dshx-bundle-verifier', version: PACKAGE.version } } - })}\n`); }); } @@ -113,17 +82,9 @@ function assertComposition(dumpText) { for (const value of Object.values(node)) walk(value); }; walk(tree); - const byId = new Map(rows.map((row) => [row.id, row])); + const ids = new Set(rows.map((row) => row.id)); for (const id of ['dshx-startup', 'dshx-presentation']) { - if (!byId.has(id)) throw new Error(`composed tree is missing '${id}'`); - } - // A fresh custom `tui` profile is base-only in official DSH, so the - // headless bundle (and therefore headless-runner) is normally absent. - // If a user deliberately composes headless into the same profile, the - // DSHX layer defensively disables that competing presentation runner. - const headlessRunner = byId.get('headless-runner'); - if (headlessRunner !== undefined && headlessRunner.disabled !== true) { - throw new Error('competing headless-runner must be absent or disabled by the DSHX bundle patch'); + if (!ids.has(id)) throw new Error(`composed tree is missing '${id}'`); } } finally { fs.rmSync(temp, { force: true }); @@ -132,16 +93,9 @@ function assertComposition(dumpText) { } function assertSingleRuntime(home) { - const ownLeafLibs = new Set( - Object.keys(PACKAGE.dependencies ?? {}) - .filter((name) => name.startsWith('@deepseek-ai/dsh')) - .map((name) => name.slice('@deepseek-ai/'.length)) - ); const profileModules = path.join(home, 'profiles', PROFILE, 'node_modules', '@deepseek-ai'); const shadowed = fs.existsSync(profileModules) - ? fs.readdirSync(profileModules) - .filter((entry) => /^dsh(-|$)/.test(entry)) - .filter((entry) => !ownLeafLibs.has(entry)) + ? fs.readdirSync(profileModules).filter((entry) => /^dsh(-|$)/.test(entry)) : []; if (shadowed.length > 0) { throw new Error(`profile shadows stateful DSH runtime packages: ${shadowed.join(', ')}`); @@ -176,12 +130,12 @@ async function verifyInstall(specifier, label) { const dump = run(dsh.command, [...dsh.args, '--profile', PROFILE, '--dump-config'], { cwd: work, env }); await assertComposition(dump.stdout); - const initialized = await probeStdioSurface({ dsh, cwd: work, env }); + const initialized = await probeProfileSurface({ dsh, cwd: work, env }); if (!String(initialized?.userAgent ?? '').startsWith('dshx/')) { throw new Error(`unexpected initialize identity: ${JSON.stringify(initialized)}`); } assertSingleRuntime(home); - console.log(`[verify-bundle] ${label} ok: official profile -> stdio -> ${initialized.userAgent}`); + console.log(`[verify-bundle] ${label} ok: official profile -> presentation child fd3 -> ${initialized.userAgent}`); } finally { fs.rmSync(work, { recursive: true, force: true }); } diff --git a/scripts/verify-tui-invariants.mjs b/scripts/verify-tui-invariants.mjs index 92c7af81..fcb33ba2 100644 --- a/scripts/verify-tui-invariants.mjs +++ b/scripts/verify-tui-invariants.mjs @@ -23,22 +23,24 @@ const approval = '.upstream/codex/codex-rs/tui/src/bottom_pane/approval_overlay. const permissions = '.upstream/codex/codex-rs/tui/src/chatwidget/permission_popups.rs'; for (const needle of [ - 'DSHX_APP_SERVER_CMD is required', - 'RemoteAppServerEndpoint::StdioChild', + 'DSHX_APP_SERVER_FD is required', + 'RemoteAppServerEndpoint::InheritedPipe', 'Some(dshx_endpoint)', 'DSHX_RESUME_MODE', ]) requireText(main, needle); -forbidText(main, 'DSHX_APP_SERVER_ENDPOINT', 'legacy socket endpoint transport'); -forbidText(main, 'DSHX_APP_SERVER_TOKEN', 'legacy bearer-token transport'); +for (const legacy of ['DSHX_APP_SERVER_CMD', 'DSHX_APP_SERVER_ENDPOINT', 'DSHX_APP_SERVER_TOKEN']) { + forbidText(main, legacy, `legacy backend transport ${legacy}`); +} for (const needle of [ 'pub struct StdioAppServerClient', - 'Command::new(executable)', + 'inherited_protocol_file', 'JSONRPCMessage', 'stdin.shutdown()', ]) requireText(stdio, needle); +forbidText(stdio, 'Command::new(', 'TUI must not spawn a DSH backend'); requireText(client, 'Stdio(StdioAppServerClient)'); -requireText(lib, 'Some(endpoint @ RemoteAppServerEndpoint::StdioChild'); +requireText(lib, 'Some(endpoint @ RemoteAppServerEndpoint::InheritedPipe'); requireText(lib, 'AppServerTarget::LocalDaemon { endpoint }'); const legacyBridge = '.upstream/codex/codex-rs/stdio-to-uds/src/dshx_ipc_bridge.rs'; @@ -47,7 +49,8 @@ if (existsSync('src/dsh/local-server.mjs')) throw new Error('legacy Node socket for (const path of [approval, permissions, lib]) { requireText(path, 'fn dshx_backend'); - requireText(path, 'DSHX_APP_SERVER_CMD'); + requireText(path, 'DSHX_APP_SERVER_FD'); + forbidText(path, 'DSHX_APP_SERVER_CMD', 'child-backend DSHX detection'); forbidText(path, 'DSHX_APP_SERVER_ENDPOINT', 'legacy socket-mode DSHX detection'); } requireText('.upstream/codex/codex-rs/tui/src/history_cell/session.rs', 'DeepSeek Harness'); @@ -72,6 +75,17 @@ if (slashText.slice(hiddenStart, hiddenEnd).includes('SlashCommand::Diff')) { throw new Error('/diff must remain visible in DSHX'); } +const launcher = read('bin/dshx.mjs'); +requireText('bin/dshx.mjs', "'--profile', profile"); +forbidText('bin/dshx.mjs', 'DSHX_APP_SERVER_CMD', 'launcher must not create a backend child command'); +forbidText('bin/dshx.mjs', 'DSHX_APP_SERVER_FD', 'only the profile-owned presentation runner may publish the protocol fd'); + +const presentation = read('src/dsh/presentation-plugin.mjs'); +if (!presentation.includes("stdio: ['inherit', 'inherit', 'inherit', 'pipe']")) { + throw new Error('presentation runner must preserve terminal fds 0/1/2 and reserve fd3 for the protocol pipe'); +} +requireText('src/dsh/presentation-plugin.mjs', 'DSHX_APP_SERVER_FD'); + const pkg = JSON.parse(read('package.json')); if (pkg.dependencies?.ws) throw new Error('ws must not be a production dependency'); -console.log('DSHX pinned TUI stdio invariants verified'); +console.log('DSHX pinned TUI profile-owned fd3 invariants verified'); diff --git a/src/dsh/presentation-plugin.mjs b/src/dsh/presentation-plugin.mjs index 3f230068..2eead961 100644 --- a/src/dsh/presentation-plugin.mjs +++ b/src/dsh/presentation-plugin.mjs @@ -47,10 +47,6 @@ export function resolveTuiBinary(environment = process.env, platform = process.p return path.join(PACKAGE_ROOT, 'dist', 'bin', platform === 'win32' ? 'dshx-tui.exe' : 'dshx-tui'); } -function protocolStdioMode(platform = process.platform) { - return platform === 'win32' ? 'overlapped' : 'pipe'; -} - export const internals = { spawnTui: spawn, startTransport: startDshxStdioTransport @@ -112,7 +108,10 @@ export function apply(ctx) { CODEX_HOME: launch.home, DSHX_APP_SERVER_FD: String(PROTOCOL_FD) }, - stdio: ['inherit', 'inherit', 'inherit', protocolStdioMode()], + // fd 3 is an anonymous duplex pipe. Keep it synchronous on Windows too: + // the Rust client wraps the inherited handle in tokio::fs::File, whose + // blocking adapter works uniformly without FILE_FLAG_OVERLAPPED. + stdio: ['inherit', 'inherit', 'inherit', 'pipe'], windowsHide: false }); state.child = child; diff --git a/test/dshx-presentation-plugin.test.mjs b/test/dshx-presentation-plugin.test.mjs index 4ea65dc5..bad45e23 100644 --- a/test/dshx-presentation-plugin.test.mjs +++ b/test/dshx-presentation-plugin.test.mjs @@ -2,6 +2,8 @@ import assert from 'node:assert/strict'; import { EventEmitter } from 'node:events'; import { PassThrough } from 'node:stream'; import { readFileSync } from 'node:fs'; +import os from 'node:os'; +import path from 'node:path'; import test from 'node:test'; import { fileURLToPath } from 'node:url'; import { @@ -22,7 +24,7 @@ import { const LAUNCH = { cwd: '/workspace', - home: '/home/test/.dshx/codex-tui', + home: path.join(os.tmpdir(), `dshx-presentation-test-${process.pid}`), version: 'test', debug: true, tuiArgs: ['resume', '--last'] @@ -83,11 +85,11 @@ test('startup publishes the raw official profile arguments for the native TUI', provide: (key, value) => provided.set(key, value) }; const previous = process.env.DSHX_TUI_HOME; - process.env.DSHX_TUI_HOME = '/tmp/dshx-launch-home'; + process.env.DSHX_TUI_HOME = path.join(os.tmpdir(), 'dshx-launch-home'); try { startupPlugin.apply(ctx); const launch = provided.get('dshxStartup'); - assert.equal(launch.home, '/tmp/dshx-launch-home'); + assert.equal(launch.home, path.join(os.tmpdir(), 'dshx-launch-home')); assert.deepEqual(launch.tuiArgs, ['resume', '--last']); assert.equal('appServer' in launch, false); assert.equal('bridgeCommand' in launch, false); @@ -119,23 +121,21 @@ test('presentation waits for Loader settlement, launches TUI with inherited fd3, try { const dispose = plugin.apply(ctx, {}); assert.equal(typeof dispose, 'function'); - assert.equal(spawned.length, 0, 'apply must return before loader.await() settles'); + assert.equal(spawned.length, 0); await tick(); assert.equal(loaderAwaited(), 1); assert.equal(spawned.length, 1); assert.deepEqual(spawned[0].args, LAUNCH.tuiArgs); - assert.deepEqual(spawned[0].options.stdio.slice(0, 3), ['inherit', 'inherit', 'inherit']); + assert.deepEqual(spawned[0].options.stdio, ['inherit', 'inherit', 'inherit', 'pipe']); assert.equal(spawned[0].options.env.DSHX_APP_SERVER_FD, String(constants.PROTOCOL_FD)); assert.equal(transports.length, 1); - assert.equal(transports[0].ctx, ctx, 'protocol adapter must use the live profile Context'); + assert.equal(transports[0].ctx, ctx); assert.equal(transports[0].input, child.stdio[3]); assert.equal(transports[0].output, child.stdio[3]); const service = provided.get(SERVICE_KEY); assert.equal(service.mode, 'inherited-pipe'); assert.equal(service.fd, 3); - assert.deepEqual(exits, []); - child.exitCode = 0; child.emit('exit', 0, null); await tick(); diff --git a/test/dshx-upstream-patch-policy.test.mjs b/test/dshx-upstream-patch-policy.test.mjs index cd75a8f5..920192ba 100644 --- a/test/dshx-upstream-patch-policy.test.mjs +++ b/test/dshx-upstream-patch-policy.test.mjs @@ -4,6 +4,7 @@ import test from 'node:test'; const slashPatch = fs.readFileSync('upstream/patches/codex/0009-dshx-slash-capabilities.patch', 'utf8'); const stdioModePatch = fs.readFileSync('upstream/patches/codex/0011-dshx-stdio-mode-detection.patch', 'utf8'); +const inheritedPipePatch = fs.readFileSync('upstream/patches/codex/0012-dshx-inherited-profile-pipe.patch', 'utf8'); function hiddenCapabilityBlock() { const start = slashPatch.indexOf('+ if crate::dshx_backend()'); @@ -16,41 +17,35 @@ function hiddenCapabilityBlock() { test('DSH-backed daily commands remain visible in the Codex thin fork', () => { const hidden = hiddenCapabilityBlock(); for (const command of ['Diff', 'Fork', 'Compact', 'Agents']) { - assert.equal( - hidden.includes(`SlashCommand::${command}`), - false, - `/${command.toLowerCase()} is DSH-backed and must not be hidden` - ); + assert.equal(hidden.includes(`SlashCommand::${command}`), false); } }); test('Codex-only runtime owners stay hidden from DSHX', () => { const hidden = hiddenCapabilityBlock(); for (const command of ['AutoReview', 'Mcp', 'Plugins', 'Logout', 'MultiAgents']) { - assert.equal( - hidden.includes(`SlashCommand::${command}`), - true, - `/${command.toLowerCase()} must stay hidden until an equivalent DSH public seam is faithfully projected` - ); + assert.equal(hidden.includes(`SlashCommand::${command}`), true); } }); -test('DSHX mode detection follows the stdio child command, never the removed socket endpoint', () => { - const oldNeedle = '- std::env::var_os("DSHX_APP_SERVER_ENDPOINT").is_some()'; - const newNeedle = '+ std::env::var_os("DSHX_APP_SERVER_CMD").is_some()'; - assert.equal(stdioModePatch.split(oldNeedle).length - 1, 3, 'all three legacy mode detectors must be replaced'); - assert.equal(stdioModePatch.split(newNeedle).length - 1, 3, 'all three DSHX mode detectors must follow the stdio command env'); +test('final DSHX mode detection follows the inherited profile fd, never a backend command or socket endpoint', () => { + assert.equal(inheritedPipePatch.split('- std::env::var_os("DSHX_APP_SERVER_CMD").is_some()').length - 1, 3); + assert.equal(inheritedPipePatch.split('+ std::env::var_os("DSHX_APP_SERVER_FD").is_some()').length - 1, 3); + assert.match(inheritedPipePatch, /DSHX_APP_SERVER_FD is required/); + assert.doesNotMatch(inheritedPipePatch, /\+.*DSHX_APP_SERVER_ENDPOINT/); }); test('DSH thread ownership is independent from Codex remote-workspace classification', () => { assert.equal( stdioModePatch.split('- if crate::dshx_backend() && matches!(thread_params_mode, ThreadParamsMode::Remote) {').length - 1, - 3, - 'start/resume/fork must all remove the legacy Remote-mode gate' - ); - assert.equal( - stdioModePatch.split('+ if crate::dshx_backend() {').length - 1, - 3, - 'start/resume/fork must all remain DSH-owned while StdioChild is a LocalDaemon' + 3 ); + assert.equal(stdioModePatch.split('+ if crate::dshx_backend() {').length - 1, 3); +}); + +test('the final transport patch removes TUI-owned backend spawning', () => { + assert.match(inheritedPipePatch, /RemoteAppServerEndpoint::InheritedPipe/); + assert.match(inheritedPipePatch, /inherited_protocol_file/); + assert.match(inheritedPipePatch, /- let mut command = Command::new\(executable\);/); + assert.doesNotMatch(inheritedPipePatch, /\+.*Command::new\(executable\)/); }); diff --git a/upstream/patches/codex/0012-dshx-inherited-profile-pipe.patch b/upstream/patches/codex/0012-dshx-inherited-profile-pipe.patch index 84bd8339..c8356460 100644 --- a/upstream/patches/codex/0012-dshx-inherited-profile-pipe.patch +++ b/upstream/patches/codex/0012-dshx-inherited-profile-pipe.patch @@ -1,48 +1,55 @@ diff --git a/codex-rs/app-server-client/Cargo.toml b/codex-rs/app-server-client/Cargo.toml --- a/codex-rs/app-server-client/Cargo.toml +++ b/codex-rs/app-server-client/Cargo.toml -@@ - serde = { workspace = true } +@@ -1,1 +1,2 @@ serde_json = { workspace = true } --tokio = { workspace = true, features = ["sync", "time", "rt", "io-util", "process"] } +libc = { workspace = true } -+tokio = { workspace = true, features = ["sync", "time", "rt", "io-util", "process", "fs"] } - tokio-tungstenite = { workspace = true } +@@ -1,1 +1,1 @@ +-tokio = { workspace = true, features = ["sync", "time", "rt", "io-util", "process"] } ++tokio = { workspace = true, features = ["sync", "time", "rt", "io-util", "fs"] } +diff --git a/codex-rs/app-server-client/src/remote.rs b/codex-rs/app-server-client/src/remote.rs +--- a/codex-rs/app-server-client/src/remote.rs ++++ b/codex-rs/app-server-client/src/remote.rs +@@ -1,3 +1,3 @@ +- StdioChild { +- command: Vec, ++ InheritedPipe { ++ fd: i32, + }, +@@ -1,1 +1,1 @@ +- RemoteAppServerEndpoint::StdioChild { .. } => Err(IoError::new( ++ RemoteAppServerEndpoint::InheritedPipe { .. } => Err(IoError::new( diff --git a/codex-rs/app-server-client/src/stdio.rs b/codex-rs/app-server-client/src/stdio.rs --- a/codex-rs/app-server-client/src/stdio.rs +++ b/codex-rs/app-server-client/src/stdio.rs -@@ - use std::io::Error as IoError; - use std::io::ErrorKind; - use std::io::Result as IoResult; +@@ -1,1 +1,8 @@ -use std::process::Stdio; +use std::fs::File as StdFile; +use std::pin::Pin; +#[cfg(unix)] -+use std::os::fd::FromRawFd; ++use std::os::fd::BorrowedFd; +#[cfg(windows)] -+use std::os::windows::io::FromRawHandle; -@@ -+use tokio::fs::File as TokioFile; ++use std::os::windows::io::BorrowedHandle; ++#[cfg(windows)] ++use std::os::windows::io::RawHandle; +@@ -1,1 +1,4 @@ use tokio::io::AsyncBufReadExt; ++use tokio::fs::File as TokioFile; +use tokio::io::AsyncRead; +use tokio::io::AsyncWrite; - use tokio::io::AsyncWriteExt; - use tokio::io::BufReader; +@@ -1,1 +0,0 @@ -use tokio::process::ChildStdin; +@@ -1,1 +0,0 @@ -use tokio::process::Command; -@@ +@@ -1,1 +1,4 @@ const INITIALIZE_TIMEOUT: std::time::Duration = std::time::Duration::from_secs(30); + +type BoxReader = Pin>; +type BoxWriter = Pin>; -@@ - pub struct StdioAppServerConnectArgs { +@@ -1,1 +1,1 @@ - pub command: Vec, + pub fd: i32, -@@ - impl StdioAppServerClient { - pub async fn connect(args: StdioAppServerConnectArgs) -> IoResult { +@@ -1,31 +1,14 @@ - let executable = args.command.first().filter(|value| !value.is_empty()).ok_or_else(|| { - IoError::new(ErrorKind::InvalidInput, "stdio app-server command must not be empty") - })?; @@ -75,7 +82,7 @@ diff --git a/codex-rs/app-server-client/src/stdio.rs b/codex-rs/app-server-clien let mut lines = BufReader::new(stdout).lines(); - let endpoint = format!("stdio://{}", executable); + let endpoint = format!("fd://{}", args.fd); -@@ +@@ -1,17 +1,2 @@ StdioClientCommand::Shutdown { response_tx } => { - let mut result = stdin.shutdown().await; - if result.is_ok() { @@ -93,48 +100,45 @@ diff --git a/codex-rs/app-server-client/src/stdio.rs b/codex-rs/app-server-clien - } + let result = stdin.shutdown().await; clean_shutdown = result.is_ok(); - let _ = response_tx.send(result); - break; -@@ +@@ -1,5 +1,2 @@ if !clean_shutdown { let _ = stdin.shutdown().await; - if child.try_wait().ok().flatten().is_none() { - let _ = child.kill().await; - } } -@@ - async fn initialize_stdio_connection( +@@ -1,2 +1,2 @@ - stdin: &mut ChildStdin, - lines: &mut tokio::io::Lines>, + stdin: &mut BoxWriter, + lines: &mut tokio::io::Lines>, -@@ +@@ -1,1 +1,1 @@ -async fn write_jsonrpc_line(stdin: &mut ChildStdin, message: JSONRPCMessage, endpoint: &str) -> IoResult<()> { +async fn write_jsonrpc_line(stdin: &mut BoxWriter, message: JSONRPCMessage, endpoint: &str) -> IoResult<()> { -@@ +@@ -1,3 +1,24 @@ fn deliver_event(event_tx: &mpsc::UnboundedSender, event: AppServerEvent) -> IoResult<()> { event_tx.send(event).map_err(|_| IoError::new(ErrorKind::BrokenPipe, "stdio app-server event consumer is closed")) } + +#[cfg(unix)] +fn inherited_protocol_file(fd: i32) -> IoResult { -+ // fd ownership is intentionally transferred to the app-server client; the -+ // TUI is the only consumer of the inherited DSHX protocol descriptor. -+ Ok(unsafe { StdFile::from_raw_fd(fd) }) ++ let borrowed = unsafe { BorrowedFd::borrow_raw(fd) }; ++ Ok(StdFile::from(borrowed.try_clone_to_owned()?)) +} + +#[cfg(windows)] +fn inherited_protocol_file(fd: i32) -> IoResult { -+ let handle = unsafe { libc::_get_osfhandle(fd) }; ++ let handle = unsafe { libc::get_osfhandle(fd) }; + if handle == -1 { + return Err(IoError::last_os_error()); + } -+ Ok(unsafe { StdFile::from_raw_handle(handle as std::os::windows::io::RawHandle) }) ++ let borrowed = unsafe { BorrowedHandle::borrow_raw(handle as RawHandle) }; ++ Ok(StdFile::from(borrowed.try_clone_to_owned()?)) +} diff --git a/codex-rs/tui/src/main.rs b/codex-rs/tui/src/main.rs --- a/codex-rs/tui/src/main.rs +++ b/codex-rs/tui/src/main.rs -@@ +@@ -1,14 +1,10 @@ - let dshx_command_json = std::env::var("DSHX_APP_SERVER_CMD").map_err(|_| { - anyhow::anyhow!( - "DSHX_APP_SERVER_CMD is required; DSHX never falls back to the Codex agent runtime" @@ -144,51 +148,51 @@ diff --git a/codex-rs/tui/src/main.rs b/codex-rs/tui/src/main.rs - .map_err(|err| anyhow::anyhow!("invalid DSHX_APP_SERVER_CMD JSON: {err}"))?; - if dshx_command.is_empty() || dshx_command[0].is_empty() { - anyhow::bail!("DSHX_APP_SERVER_CMD must contain a non-empty executable argv[0]"); -- } + let dshx_fd: i32 = std::env::var("DSHX_APP_SERVER_FD") + .map_err(|_| anyhow::anyhow!("DSHX_APP_SERVER_FD is required; DSHX never falls back to the Codex agent runtime"))? + .parse() + .map_err(|err| anyhow::anyhow!("invalid DSHX_APP_SERVER_FD: {err}"))?; + if dshx_fd < 3 { + anyhow::bail!("DSHX_APP_SERVER_FD must be an inherited descriptor >= 3"); -+ } - let dshx_endpoint = RemoteAppServerEndpoint::StdioChild { + } +- let dshx_endpoint = RemoteAppServerEndpoint::StdioChild { - command: dshx_command, -+ command: vec![format!("fd:{dshx_fd}")], ++ let dshx_endpoint = RemoteAppServerEndpoint::InheritedPipe { ++ fd: dshx_fd, }; diff --git a/codex-rs/tui/src/lib.rs b/codex-rs/tui/src/lib.rs --- a/codex-rs/tui/src/lib.rs +++ b/codex-rs/tui/src/lib.rs -@@ - fn dshx_backend() -> bool { -- std::env::var_os("DSHX_APP_SERVER_CMD").is_some() -+ std::env::var_os("DSHX_APP_SERVER_FD").is_some() - } -@@ - RemoteAppServerEndpoint::StdioChild { command } => { -+ let fd = command -+ .first() -+ .and_then(|value| value.strip_prefix("fd:")) -+ .and_then(|value| value.parse::().ok()) -+ .ok_or_else(|| color_eyre::eyre::eyre!("invalid inherited DSHX protocol fd endpoint"))?; +@@ -1,1 +1,1 @@ +- RemoteAppServerEndpoint::StdioChild { .. } => false, ++ RemoteAppServerEndpoint::InheritedPipe { .. } => false, +@@ -1,3 +1,3 @@ +- RemoteAppServerEndpoint::StdioChild { command } => { ++ RemoteAppServerEndpoint::InheritedPipe { fd } => { let app_server = StdioAppServerClient::connect(StdioAppServerConnectArgs { - command, + fd, - client_name, - client_version, +@@ -1,1 +1,1 @@ +- Some(endpoint @ RemoteAppServerEndpoint::StdioChild { .. }) => { ++ Some(endpoint @ RemoteAppServerEndpoint::InheritedPipe { .. }) => { +@@ -1,1 +1,1 @@ +- std::env::var_os("DSHX_APP_SERVER_CMD").is_some() ++ std::env::var_os("DSHX_APP_SERVER_FD").is_some() +diff --git a/codex-rs/tui/src/status/remote_connection.rs b/codex-rs/tui/src/status/remote_connection.rs +--- a/codex-rs/tui/src/status/remote_connection.rs ++++ b/codex-rs/tui/src/status/remote_connection.rs +@@ -1,1 +1,1 @@ +- RemoteAppServerEndpoint::StdioChild { .. } => return None, ++ RemoteAppServerEndpoint::InheritedPipe { .. } => return None, diff --git a/codex-rs/tui/src/bottom_pane/approval_overlay.rs b/codex-rs/tui/src/bottom_pane/approval_overlay.rs --- a/codex-rs/tui/src/bottom_pane/approval_overlay.rs +++ b/codex-rs/tui/src/bottom_pane/approval_overlay.rs -@@ - fn dshx_backend() -> bool { +@@ -1,1 +1,1 @@ - std::env::var_os("DSHX_APP_SERVER_CMD").is_some() + std::env::var_os("DSHX_APP_SERVER_FD").is_some() - } diff --git a/codex-rs/tui/src/chatwidget/permission_popups.rs b/codex-rs/tui/src/chatwidget/permission_popups.rs --- a/codex-rs/tui/src/chatwidget/permission_popups.rs +++ b/codex-rs/tui/src/chatwidget/permission_popups.rs -@@ - fn dshx_backend() -> bool { +@@ -1,1 +1,1 @@ - std::env::var_os("DSHX_APP_SERVER_CMD").is_some() + std::env::var_os("DSHX_APP_SERVER_FD").is_some() - } From c7c9de4687452b3f8ad25688fbe49d85cd33d058 Mon Sep 17 00:00:00 2001 From: code-new-bie <403466121@qq.com> Date: Thu, 27 Aug 2026 21:03:55 +0800 Subject: [PATCH 42/60] test(plugin): enforce profile-owned TUI runtime --- scripts/verify-ownership-boundary.mjs | 53 ++++++++++++++++++--------- 1 file changed, 36 insertions(+), 17 deletions(-) diff --git a/scripts/verify-ownership-boundary.mjs b/scripts/verify-ownership-boundary.mjs index 0af87373..ced9dc68 100644 --- a/scripts/verify-ownership-boundary.mjs +++ b/scripts/verify-ownership-boundary.mjs @@ -10,11 +10,15 @@ function forbidText(path, pattern, label = String(pattern)) { if (hit) throw new Error(`${path} violates ownership invariant: ${label}`); } -// Bundle/profile ownership: activation is declared, never mounted by DSHX. -requireText('cordis.patch.yml', 'id: headless-startup'); -requireText('cordis.patch.yml', 'id: headless-runner'); +// Standard DSH bundle ownership: this layer inserts only its own surface rows. +requireText('cordis.patch.yml', 'id: dshx-startup'); +requireText('cordis.patch.yml', 'id: dshx-presentation'); requireText('cordis.patch.yml', "name: '@code-new-bie/dshx-tui/startup'"); requireText('cordis.patch.yml', "name: '@code-new-bie/dshx-tui/presentation'"); +requireText('cordis.patch.yml', 'inject: [dshxStartup]'); +forbidText('cordis.patch.yml', 'headless-startup', 'depending on another surface startup row'); +forbidText('cordis.patch.yml', 'headless-runner', 'depending on another surface runner'); + const manifest = JSON.parse(read('package.json')); if (manifest.dsh?.bundle?.patch !== './cordis.patch.yml') { throw new Error('package.json must declare dsh.bundle.patch -> ./cordis.patch.yml'); @@ -27,7 +31,9 @@ if (!manifest.exports?.['./presentation'] || !manifest.exports?.['./startup']) { // depend on non-DSH leaf helpers, but it must never install a second Harness // package into the profile. Service definitions are optional advisory host // peers and resolve through DSH's installation-owned profile fallback. -const runtimePeers = Object.keys(manifest.peerDependencies ?? {}).filter((name) => name === '@deepseek-ai/dsh' || name.startsWith('@deepseek-ai/dsh-')); +const runtimePeers = Object.keys(manifest.peerDependencies ?? {}).filter( + (name) => name === '@deepseek-ai/dsh' || name.startsWith('@deepseek-ai/dsh-') +); if (runtimePeers.length === 0) throw new Error('DSH runtime packages must be peerDependencies'); for (const name of Object.keys(manifest.dependencies ?? {})) { if (name === '@deepseek-ai/dsh' || name.startsWith('@deepseek-ai/dsh-')) { @@ -43,34 +49,47 @@ for (const name of runtimePeers) { } } -// There is exactly one runtime owner: the official dsh launcher/profile. +// There is exactly one runtime owner: the user's official dsh launcher/profile. for (const retired of ['src/dsh/runtime-boot.mjs', 'src/dsh/local-server.mjs']) { if (existsSync(retired)) throw new Error(`${retired} must stay deleted; DSHX cannot own a runtime/socket host`); } requireText('src/dsh/profile-bootstrap.mjs', "'plugin', '--profile'"); requireText('src/dsh/profile-bootstrap.mjs', 'resolveDshInvocation'); -requireText('bin/dshx.mjs', 'DSHX_APP_SERVER_CMD'); -requireText('bin/dshx.mjs', "'--dshx-app-server'"); +requireText('bin/dshx.mjs', "'--profile', profile, ...argv"); +requireText('bin/dshx.mjs', "stdio: 'inherit'"); +requireText('bin/dshx.mjs', 'shell: false'); forbidText('bin/dshx.mjs', /(?:from\s+|import\s+\(\s*|require\()\s*["']@deepseek-ai\//, 'importing Harness runtime builds'); -forbidText('bin/dshx.mjs', 'DSHX_APP_SERVER_ENDPOINT', 'socket endpoint launch path'); -forbidText('bin/dshx.mjs', 'DSHX_IPC_BRIDGE_BIN', 'bridge launch path'); +for (const retired of ['DSHX_APP_SERVER_CMD', '--dshx-app-server', 'DSHX_APP_SERVER_ENDPOINT', 'DSHX_IPC_BRIDGE_BIN']) { + forbidText('bin/dshx.mjs', retired, `retired nested-backend launch seam ${retired}`); +} -// Cordis rows consume launcher facts and bind only NDJSON stdio to the live ctx. +// Surface rows follow the official startup-provider -> presentation-runner pattern. requireText('src/dsh/startup-plugin.mjs', "inject = ['cmdlineArgs']"); -requireText('src/dsh/startup-plugin.mjs', '--dshx-app-server'); requireText('src/dsh/startup-plugin.mjs', "provide('dshxStartup'"); +requireText('src/dsh/startup-plugin.mjs', 'tuiArgs:'); +forbidText('src/dsh/startup-plugin.mjs', '--dshx-app-server', 'private backend sentinel'); + +requireText('src/dsh/presentation-plugin.mjs', "inject = ['dshxStartup']"); +requireText('src/dsh/presentation-plugin.mjs', 'internals.spawnTui'); +requireText('src/dsh/presentation-plugin.mjs', "stdio: ['inherit', 'inherit', 'inherit', 'pipe']"); +requireText('src/dsh/presentation-plugin.mjs', 'DSHX_APP_SERVER_FD'); requireText('src/dsh/presentation-plugin.mjs', 'startDshxStdioTransport'); requireText('src/dsh/presentation-plugin.mjs', 'ctx.provide(SERVICE_KEY'); -requireText('src/dsh/presentation-plugin.mjs', "inject = ['dshxStartup']"); -forbidText('src/dsh/presentation-plugin.mjs', 'spawn('); +requireText('src/dsh/presentation-plugin.mjs', 'requestHostExit(ctx'); forbidText('src/dsh/presentation-plugin.mjs', 'runtime-boot'); +forbidText('src/dsh/presentation-plugin.mjs', 'resolveDshInvocation', 'presentation runner starting another DSH'); + requireText('src/dsh/stdio-transport.mjs', 'already-mounted DSH Context'); forbidText('src/dsh/stdio-transport.mjs', /WebSocket|unix:\/\//, 'network/socket framing'); -// The thin fork must spawn a local stdio backend and must not materialize the -// historical Rust UDS bridge. -requireText('upstream/patches/codex/0001-dshx-force-ui-backend.patch', 'DSHX_APP_SERVER_CMD'); -requireText('upstream/patches/codex/0010-dshx-stdio-backend.patch', 'StdioAppServerClient'); +// The final thin-fork layer consumes only the inherited profile pipe. Earlier +// migration patches may mention StdioChild/DSHX_APP_SERVER_CMD as removed text; +// 0012 must replace that intermediate topology in the materialized result. +const inheritedPatch = 'upstream/patches/codex/0012-dshx-inherited-profile-pipe.patch'; +requireText(inheritedPatch, 'InheritedPipe'); +requireText(inheritedPatch, 'DSHX_APP_SERVER_FD'); +requireText(inheritedPatch, '-use tokio::process::Command;'); +requireText(inheritedPatch, '- let mut command = Command::new(executable);'); for (const file of readdirSync('upstream/patches/codex')) { if (!file.endsWith('.patch')) continue; forbidText(`upstream/patches/codex/${file}`, 'dshx-ipc-bridge', 'legacy Rust bridge'); From 5d9beffb43e00b1f1eebe6245720a0246ec9fbba Mon Sep 17 00:00:00 2001 From: code-new-bie <403466121@qq.com> Date: Thu, 27 Aug 2026 21:12:01 +0800 Subject: [PATCH 43/60] fix(plugin): align TUI Loader settlement with CLI surfaces --- cordis.patch.yml | 6 ++++++ src/dsh/presentation-plugin.mjs | 4 ++++ 2 files changed, 10 insertions(+) diff --git a/cordis.patch.yml b/cordis.patch.yml index 069ca20c..3a5b9cf4 100644 --- a/cordis.patch.yml +++ b/cordis.patch.yml @@ -4,6 +4,12 @@ # for the Loader tree to settle, launches the pinned native TUI, and binds its # inherited fd 3 protocol pipe directly to the live DSH Context. +# Match the official headless CLI-surface pattern: the shared module HMR row is +# not part of the interactive runner. The profile launcher's watch fallback +# remains responsible for user patch layers during the process lifetime. +- id: hmr + disabled: true + - insert: - id: dshx-startup name: '@code-new-bie/dshx-tui/startup' diff --git a/src/dsh/presentation-plugin.mjs b/src/dsh/presentation-plugin.mjs index 2eead961..3c03ba9d 100644 --- a/src/dsh/presentation-plugin.mjs +++ b/src/dsh/presentation-plugin.mjs @@ -92,7 +92,9 @@ export function apply(ctx) { const launchTui = async () => { const loader = ctx.get('loader'); + log('waiting for official DSH Loader settlement'); await loader?.await?.(); + log('official DSH Loader settled; launching native TUI'); if (state.closing) return; fs.mkdirSync(launch.home, { recursive: true, mode: 0o700 }); @@ -115,6 +117,7 @@ export function apply(ctx) { windowsHide: false }); state.child = child; + log(`native TUI child spawned with protocol fd ${PROTOCOL_FD}`); const protocol = child.stdio?.[PROTOCOL_FD]; if (!protocol || typeof protocol.on !== 'function' || typeof protocol.write !== 'function') { @@ -137,6 +140,7 @@ export function apply(ctx) { } } }); + log('fd3 presentation transport bound to live DSH Context'); child.once('error', (error) => { void finish(1, `native TUI spawn failed: ${error.message}`); From 1af0c5d61a62a6a3ad090251fb5964405c4df776 Mon Sep 17 00:00:00 2001 From: code-new-bie <403466121@qq.com> Date: Fri, 28 Aug 2026 08:25:10 +0800 Subject: [PATCH 44/60] fix(plugin): use directional inherited protocol pipes --- scripts/profile-pipe-smoke-client.mjs | 54 ++++++++++++++++++++++++ scripts/runtime-smoke.mjs | 8 ++-- scripts/verify-ownership-boundary.mjs | 14 ++++--- src/dsh/presentation-plugin.mjs | 58 +++++++++++++++++--------- test/dshx-presentation-plugin.test.mjs | 21 ++++++---- 5 files changed, 119 insertions(+), 36 deletions(-) create mode 100755 scripts/profile-pipe-smoke-client.mjs diff --git a/scripts/profile-pipe-smoke-client.mjs b/scripts/profile-pipe-smoke-client.mjs new file mode 100755 index 00000000..0df737d3 --- /dev/null +++ b/scripts/profile-pipe-smoke-client.mjs @@ -0,0 +1,54 @@ +#!/usr/bin/env node +import fs from 'node:fs'; +import process from 'node:process'; +import { createInterface } from 'node:readline'; + +const inputFd = Number(process.env.DSHX_APP_SERVER_INPUT_FD ?? '0'); +const outputFd = Number(process.env.DSHX_APP_SERVER_OUTPUT_FD ?? '4'); +if (!Number.isInteger(inputFd) || inputFd < 0 || !Number.isInteger(outputFd) || outputFd < 0) { + throw new Error('DSHX profile-pipe smoke requires valid protocol input/output fds'); +} + +const input = fs.createReadStream(null, { fd: inputFd, autoClose: false }); +const lines = createInterface({ input, crlfDelay: Infinity, terminal: false }); +let settled = false; +const timeout = setTimeout(() => { + if (settled) return; + settled = true; + process.stderr.write('[fd-smoke] initialize timed out\n'); + process.exitCode = 1; + lines.close(); +}, Number(process.env.DSHX_FD_SMOKE_TIMEOUT_MS ?? 30_000)); + +function send(message) { + fs.writeSync(outputFd, `${JSON.stringify(message)}\n`); +} + +lines.on('line', (line) => { + let message; + try { message = JSON.parse(line); } catch { return; } + if (message?.id !== 'profile-pipe-smoke' || settled) return; + settled = true; + clearTimeout(timeout); + if (message.error) { + process.stderr.write(`[fd-smoke] initialize rejected: ${message.error.message ?? JSON.stringify(message.error)}\n`); + process.exitCode = 1; + lines.close(); + return; + } + send({ method: 'initialized', params: {} }); + process.stdout.write(`DSHX_PROFILE_PIPE_SMOKE ${JSON.stringify({ userAgent: message.result?.userAgent ?? null })}\n`); + // `initialize` proves the Loader tree is already settled. Give rc.8's + // launcher-owned post-boot watcher setup one bounded turn before child exit, + // matching the steady-state lifecycle exercised by the real native TUI. + setTimeout(() => { + lines.close(); + process.exitCode = 0; + }, Number(process.env.DSHX_FD_SETTLE_MS ?? 300)); +}); + +send({ + id: 'profile-pipe-smoke', + method: 'initialize', + params: { clientInfo: { name: 'dshx-profile-pipe-smoke', version: '1' } } +}); diff --git a/scripts/runtime-smoke.mjs b/scripts/runtime-smoke.mjs index d734471a..38c83470 100755 --- a/scripts/runtime-smoke.mjs +++ b/scripts/runtime-smoke.mjs @@ -8,7 +8,7 @@ import { ensureProfileInstalled, resolveDshInvocation } from '../src/dsh/profile const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..'); const PACKAGE = JSON.parse(fs.readFileSync(path.join(ROOT, 'package.json'), 'utf8')); -const CLIENT = path.join(ROOT, 'scripts', 'fd3-smoke-client.mjs'); +const CLIENT = path.join(ROOT, 'scripts', 'profile-pipe-smoke-client.mjs'); const BOOT_TIMEOUT_MS = Number(process.env.DSHX_SMOKE_BOOT_TIMEOUT_MS ?? 90_000); const ensured = ensureProfileInstalled({ @@ -54,12 +54,12 @@ await new Promise((resolve, reject) => { finish(new Error(`official DSH TUI profile failed (code ${code ?? '?'} signal ${signal ?? '-'})${stderr ? `:\n${stderr}` : ''}`)); return; } - const marker = stdout.split(/\r?\n/).find((line) => line.startsWith('DSHX_FD3_SMOKE ')); + const marker = stdout.split(/\r?\n/).find((line) => line.startsWith('DSHX_PROFILE_PIPE_SMOKE ')); if (!marker) { - finish(new Error(`native presentation child never completed fd3 initialize${stderr ? `:\n${stderr}` : ''}`)); + finish(new Error(`native presentation child never completed directional-pipe initialize${stderr ? `:\n${stderr}` : ''}`)); return; } - const payload = JSON.parse(marker.slice('DSHX_FD3_SMOKE '.length)); + const payload = JSON.parse(marker.slice('DSHX_PROFILE_PIPE_SMOKE '.length)); if (!String(payload.userAgent ?? '').startsWith('dshx/')) { finish(new Error(`unexpected initialize identity: ${JSON.stringify(payload)}`)); return; diff --git a/scripts/verify-ownership-boundary.mjs b/scripts/verify-ownership-boundary.mjs index ced9dc68..d2d34bc3 100644 --- a/scripts/verify-ownership-boundary.mjs +++ b/scripts/verify-ownership-boundary.mjs @@ -11,6 +11,8 @@ function forbidText(path, pattern, label = String(pattern)) { } // Standard DSH bundle ownership: this layer inserts only its own surface rows. +requireText('cordis.patch.yml', 'id: hmr'); +requireText('cordis.patch.yml', 'disabled: true'); requireText('cordis.patch.yml', 'id: dshx-startup'); requireText('cordis.patch.yml', 'id: dshx-presentation'); requireText('cordis.patch.yml', "name: '@code-new-bie/dshx-tui/startup'"); @@ -71,8 +73,10 @@ forbidText('src/dsh/startup-plugin.mjs', '--dshx-app-server', 'private backend s requireText('src/dsh/presentation-plugin.mjs', "inject = ['dshxStartup']"); requireText('src/dsh/presentation-plugin.mjs', 'internals.spawnTui'); -requireText('src/dsh/presentation-plugin.mjs', "stdio: ['inherit', 'inherit', 'inherit', 'pipe']"); -requireText('src/dsh/presentation-plugin.mjs', 'DSHX_APP_SERVER_FD'); +requireText('src/dsh/presentation-plugin.mjs', "stdio: ['pipe', 'inherit', 'inherit', 0, 'pipe']"); +requireText('src/dsh/presentation-plugin.mjs', 'DSHX_APP_SERVER_INPUT_FD'); +requireText('src/dsh/presentation-plugin.mjs', 'DSHX_TERMINAL_INPUT_FD'); +requireText('src/dsh/presentation-plugin.mjs', 'DSHX_APP_SERVER_OUTPUT_FD'); requireText('src/dsh/presentation-plugin.mjs', 'startDshxStdioTransport'); requireText('src/dsh/presentation-plugin.mjs', 'ctx.provide(SERVICE_KEY'); requireText('src/dsh/presentation-plugin.mjs', 'requestHostExit(ctx'); @@ -82,9 +86,9 @@ forbidText('src/dsh/presentation-plugin.mjs', 'resolveDshInvocation', 'presentat requireText('src/dsh/stdio-transport.mjs', 'already-mounted DSH Context'); forbidText('src/dsh/stdio-transport.mjs', /WebSocket|unix:\/\//, 'network/socket framing'); -// The final thin-fork layer consumes only the inherited profile pipe. Earlier -// migration patches may mention StdioChild/DSHX_APP_SERVER_CMD as removed text; -// 0012 must replace that intermediate topology in the materialized result. +// Rust is still in the inherited-pipe migration layer until the Core profile +// lifecycle proves the final directional Node pipe topology. The next thin-fork +// patch must remove backend spawning; no bridge/socket path may return. const inheritedPatch = 'upstream/patches/codex/0012-dshx-inherited-profile-pipe.patch'; requireText(inheritedPatch, 'InheritedPipe'); requireText(inheritedPatch, 'DSHX_APP_SERVER_FD'); diff --git a/src/dsh/presentation-plugin.mjs b/src/dsh/presentation-plugin.mjs index 3c03ba9d..d6fe6bb7 100644 --- a/src/dsh/presentation-plugin.mjs +++ b/src/dsh/presentation-plugin.mjs @@ -10,13 +10,19 @@ import { startDshxStdioTransport } from './stdio-transport.mjs'; * dshx-presentation — native TUI runner over the live DSH composition. * * The official `dsh --profile tui` process is the parent/runtime owner. This - * row launches only the pinned presentation binary. Terminal fds 0/1/2 are - * inherited by the TUI; fd 3 is a private duplex NDJSON pipe bound directly to - * the already-mounted DSH Context. + * row launches only the pinned presentation binary. Terminal output stays on + * fds 1/2. Node only guarantees child fd 0 as parent->child for a spawned + * stdio pipe, so protocol input temporarily occupies child fd 0; the parent's + * terminal stdin is also inherited as fd 3 and the Rust entrypoint restores it + * to fd 0 before Codex initializes the terminal. Child fd 4 carries protocol + * output back to this row. No listener, socket address, bridge, or second DSH + * runtime exists in this topology. */ const PACKAGE_ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../..'); -const PROTOCOL_FD = 3; +const PROTOCOL_INPUT_FD = 0; +const TERMINAL_INPUT_FD = 3; +const PROTOCOL_OUTPUT_FD = 4; export const name = 'dshx-presentation'; export const inject = ['dshxStartup']; @@ -108,21 +114,29 @@ export function apply(ctx) { env: { ...process.env, CODEX_HOME: launch.home, - DSHX_APP_SERVER_FD: String(PROTOCOL_FD) + DSHX_APP_SERVER_INPUT_FD: String(PROTOCOL_INPUT_FD), + DSHX_TERMINAL_INPUT_FD: String(TERMINAL_INPUT_FD), + DSHX_APP_SERVER_OUTPUT_FD: String(PROTOCOL_OUTPUT_FD) }, - // fd 3 is an anonymous duplex pipe. Keep it synchronous on Windows too: - // the Rust client wraps the inherited handle in tokio::fs::File, whose - // blocking adapter works uniformly without FILE_FLAG_OVERLAPPED. - stdio: ['inherit', 'inherit', 'inherit', 'pipe'], + // Node's spawn contract makes fd 0 child-readable and fd > 0 + // child-writable for stdio:'pipe'. Keep the terminal's original stdin as + // child fd 3; the Rust entrypoint duplicates protocol fd 0, restores fd 3 + // onto stdin, then uses fd 4 for protocol output. + stdio: ['pipe', 'inherit', 'inherit', 0, 'pipe'], windowsHide: false }); state.child = child; - log(`native TUI child spawned with protocol fd ${PROTOCOL_FD}`); + log(`native TUI child spawned with protocol input fd ${PROTOCOL_INPUT_FD}, terminal input fd ${TERMINAL_INPUT_FD}, protocol output fd ${PROTOCOL_OUTPUT_FD}`); - const protocol = child.stdio?.[PROTOCOL_FD]; - if (!protocol || typeof protocol.on !== 'function' || typeof protocol.write !== 'function') { + const protocolInput = child.stdin; + const protocolOutput = child.stdio?.[PROTOCOL_OUTPUT_FD]; + if (!protocolInput || typeof protocolInput.write !== 'function') { try { child.kill('SIGTERM'); } catch {} - throw new Error(`native TUI did not expose inherited protocol fd ${PROTOCOL_FD}`); + throw new Error('native TUI did not expose parent-writable protocol input'); + } + if (!protocolOutput || typeof protocolOutput.on !== 'function') { + try { child.kill('SIGTERM'); } catch {} + throw new Error(`native TUI did not expose protocol output fd ${PROTOCOL_OUTPUT_FD}`); } state.transport = internals.startTransport({ @@ -130,17 +144,17 @@ export function apply(ctx) { cwd: launch.cwd, home: launch.home, version: launch.version, - input: protocol, - output: protocol, + input: protocolOutput, + output: protocolInput, diagnostics: log, onEof: (error) => { if (error && !state.closing) { - log(`protocol pipe closed with error: ${error instanceof Error ? error.message : String(error)}`); + log(`protocol output pipe closed with error: ${error instanceof Error ? error.message : String(error)}`); try { child.kill('SIGTERM'); } catch {} } } }); - log('fd3 presentation transport bound to live DSH Context'); + log('directional presentation pipes bound to live DSH Context'); child.once('error', (error) => { void finish(1, `native TUI spawn failed: ${error.message}`); @@ -151,7 +165,13 @@ export function apply(ctx) { }); }; - ctx.provide(SERVICE_KEY, Object.freeze({ mode: 'inherited-pipe', fd: PROTOCOL_FD, close })); + ctx.provide(SERVICE_KEY, Object.freeze({ + mode: 'inherited-pipes', + inputFd: PROTOCOL_INPUT_FD, + terminalInputFd: TERMINAL_INPUT_FD, + outputFd: PROTOCOL_OUTPUT_FD, + close + })); void launchTui().catch((error) => { void finish(1, `failed to launch native TUI: ${error instanceof Error ? error.stack ?? error.message : String(error)}`); }); @@ -159,4 +179,4 @@ export function apply(ctx) { } export const plugin = { name, inject, Config, apply }; -export const constants = { PACKAGE_ROOT, PROTOCOL_FD }; +export const constants = { PACKAGE_ROOT, PROTOCOL_INPUT_FD, TERMINAL_INPUT_FD, PROTOCOL_OUTPUT_FD }; diff --git a/test/dshx-presentation-plugin.test.mjs b/test/dshx-presentation-plugin.test.mjs index bad45e23..f6054ebf 100644 --- a/test/dshx-presentation-plugin.test.mjs +++ b/test/dshx-presentation-plugin.test.mjs @@ -34,7 +34,8 @@ function tick() { return new Promise((resolve) => setImmediate(resolve)); } function fakeChild() { const child = new EventEmitter(); - child.stdio = [null, null, null, new PassThrough()]; + child.stdin = new PassThrough(); + child.stdio = [child.stdin, null, null, null, new PassThrough()]; child.exitCode = null; child.signalCode = null; child.killed = false; @@ -100,7 +101,7 @@ test('startup publishes the raw official profile arguments for the native TUI', } }); -test('presentation waits for Loader settlement, launches TUI with inherited fd3, and exits through appExit', async () => { +test('presentation waits for Loader settlement, launches TUI with directional inherited pipes, and exits through appExit', async () => { const exits = []; const { ctx, provided, loaderAwaited } = fakeContext(LAUNCH, (code) => exits.push(code)); const child = fakeChild(); @@ -126,16 +127,20 @@ test('presentation waits for Loader settlement, launches TUI with inherited fd3, assert.equal(loaderAwaited(), 1); assert.equal(spawned.length, 1); assert.deepEqual(spawned[0].args, LAUNCH.tuiArgs); - assert.deepEqual(spawned[0].options.stdio, ['inherit', 'inherit', 'inherit', 'pipe']); - assert.equal(spawned[0].options.env.DSHX_APP_SERVER_FD, String(constants.PROTOCOL_FD)); + assert.deepEqual(spawned[0].options.stdio, ['pipe', 'inherit', 'inherit', 0, 'pipe']); + assert.equal(spawned[0].options.env.DSHX_APP_SERVER_INPUT_FD, String(constants.PROTOCOL_INPUT_FD)); + assert.equal(spawned[0].options.env.DSHX_TERMINAL_INPUT_FD, String(constants.TERMINAL_INPUT_FD)); + assert.equal(spawned[0].options.env.DSHX_APP_SERVER_OUTPUT_FD, String(constants.PROTOCOL_OUTPUT_FD)); assert.equal(transports.length, 1); assert.equal(transports[0].ctx, ctx); - assert.equal(transports[0].input, child.stdio[3]); - assert.equal(transports[0].output, child.stdio[3]); + assert.equal(transports[0].input, child.stdio[4]); + assert.equal(transports[0].output, child.stdin); const service = provided.get(SERVICE_KEY); - assert.equal(service.mode, 'inherited-pipe'); - assert.equal(service.fd, 3); + assert.equal(service.mode, 'inherited-pipes'); + assert.equal(service.inputFd, 0); + assert.equal(service.terminalInputFd, 3); + assert.equal(service.outputFd, 4); child.exitCode = 0; child.emit('exit', 0, null); await tick(); From 6202b327a2581ef51eab87f0774cd11452b78de2 Mon Sep 17 00:00:00 2001 From: code-new-bie <403466121@qq.com> Date: Fri, 28 Aug 2026 08:27:32 +0800 Subject: [PATCH 45/60] test(plugin): read spawned protocol input through libuv --- scripts/profile-pipe-smoke-client.mjs | 37 +++++++++++++++++---------- 1 file changed, 24 insertions(+), 13 deletions(-) diff --git a/scripts/profile-pipe-smoke-client.mjs b/scripts/profile-pipe-smoke-client.mjs index 0df737d3..655145fb 100755 --- a/scripts/profile-pipe-smoke-client.mjs +++ b/scripts/profile-pipe-smoke-client.mjs @@ -9,31 +9,37 @@ if (!Number.isInteger(inputFd) || inputFd < 0 || !Number.isInteger(outputFd) || throw new Error('DSHX profile-pipe smoke requires valid protocol input/output fds'); } -const input = fs.createReadStream(null, { fd: inputFd, autoClose: false }); +// `child_process.spawn(..., { stdio: ['pipe', ...] })` gives fd 0 to the +// child as a libuv-managed nonblocking pipe on Unix. `fs.createReadStream()` +// performs ordinary fs reads and can surface EAGAIN immediately; process.stdin +// is the supported stream wrapper for this descriptor and waits correctly. +const input = inputFd === 0 + ? process.stdin + : fs.createReadStream(null, { fd: inputFd, autoClose: false }); +input.setEncoding('utf8'); const lines = createInterface({ input, crlfDelay: Infinity, terminal: false }); let settled = false; -const timeout = setTimeout(() => { +const timeout = setTimeout(() => finish(1, 'initialize timed out'), Number(process.env.DSHX_FD_SMOKE_TIMEOUT_MS ?? 30_000)); + +function finish(code, detail) { if (settled) return; settled = true; - process.stderr.write('[fd-smoke] initialize timed out\n'); - process.exitCode = 1; - lines.close(); -}, Number(process.env.DSHX_FD_SMOKE_TIMEOUT_MS ?? 30_000)); + clearTimeout(timeout); + if (detail) process.stderr.write(`[fd-smoke] ${detail}\n`); + try { lines.close(); } catch {} + process.exitCode = code; +} function send(message) { - fs.writeSync(outputFd, `${JSON.stringify(message)}\n`); + fs.writeSync(outputFd, `${JSON.stringify(message)}\n`, null, 'utf8'); } lines.on('line', (line) => { let message; try { message = JSON.parse(line); } catch { return; } if (message?.id !== 'profile-pipe-smoke' || settled) return; - settled = true; - clearTimeout(timeout); if (message.error) { - process.stderr.write(`[fd-smoke] initialize rejected: ${message.error.message ?? JSON.stringify(message.error)}\n`); - process.exitCode = 1; - lines.close(); + finish(1, `initialize rejected: ${message.error.message ?? JSON.stringify(message.error)}`); return; } send({ method: 'initialized', params: {} }); @@ -41,12 +47,17 @@ lines.on('line', (line) => { // `initialize` proves the Loader tree is already settled. Give rc.8's // launcher-owned post-boot watcher setup one bounded turn before child exit, // matching the steady-state lifecycle exercised by the real native TUI. + settled = true; + clearTimeout(timeout); setTimeout(() => { - lines.close(); + try { lines.close(); } catch {} process.exitCode = 0; }, Number(process.env.DSHX_FD_SETTLE_MS ?? 300)); }); +lines.on('error', (error) => finish(1, `protocol readline failed: ${error.message}`)); +input.on?.('error', (error) => finish(1, `protocol input failed: ${error.message}`)); + send({ id: 'profile-pipe-smoke', method: 'initialize', From 8b56ace8220bdc57febe57f2e68ed137db3eb480 Mon Sep 17 00:00:00 2001 From: code-new-bie <403466121@qq.com> Date: Fri, 28 Aug 2026 08:35:55 +0800 Subject: [PATCH 46/60] fix(tui): remap profile-owned protocol pipes --- scripts/fd3-smoke-client.mjs | 52 ------ scripts/verify-ownership-boundary.mjs | 32 ++-- scripts/verify-tui-invariants.mjs | 44 +++-- test/dshx-upstream-patch-policy.test.mjs | 17 +- .../0012-dshx-inherited-profile-pipe.patch | 173 ++++++++++++++---- 5 files changed, 188 insertions(+), 130 deletions(-) delete mode 100755 scripts/fd3-smoke-client.mjs diff --git a/scripts/fd3-smoke-client.mjs b/scripts/fd3-smoke-client.mjs deleted file mode 100755 index 7221b0a3..00000000 --- a/scripts/fd3-smoke-client.mjs +++ /dev/null @@ -1,52 +0,0 @@ -#!/usr/bin/env node -import fs from 'node:fs'; -import process from 'node:process'; -import { createInterface } from 'node:readline'; - -const FD = Number(process.env.DSHX_APP_SERVER_FD ?? '3'); -const TIMEOUT_MS = Number(process.env.DSHX_FD3_TIMEOUT_MS ?? 30_000); -const SETTLE_MS = Number(process.env.DSHX_FD3_SETTLE_MS ?? 300); - -if (!Number.isInteger(FD) || FD < 3) { - process.stderr.write(`[fd3-smoke] invalid DSHX_APP_SERVER_FD=${JSON.stringify(process.env.DSHX_APP_SERVER_FD)}\n`); - process.exit(2); -} - -const input = fs.createReadStream(null, { fd: FD, autoClose: false, encoding: 'utf8' }); -const lines = createInterface({ input, crlfDelay: Infinity, terminal: false }); -let settled = false; -const timer = setTimeout(() => finish(3, 'timed out waiting for initialize'), TIMEOUT_MS); - -function write(message) { - fs.writeSync(FD, `${JSON.stringify(message)}\n`, null, 'utf8'); -} - -function finish(code, detail) { - if (settled) return; - settled = true; - clearTimeout(timer); - try { lines.close(); } catch {} - if (detail) process.stderr.write(`[fd3-smoke] ${detail}\n`); - setTimeout(() => process.exit(code), code === 0 ? SETTLE_MS : 0); -} - -lines.on('line', (line) => { - let message; - try { message = JSON.parse(line); } catch { return; } - if (message?.id !== 'fd3-smoke') return; - if (message.error) { - finish(4, `initialize rejected: ${message.error.message || JSON.stringify(message.error)}`); - return; - } - write({ method: 'initialized', params: {} }); - process.stdout.write(`DSHX_FD3_SMOKE ${JSON.stringify({ userAgent: message.result?.userAgent ?? null })}\n`); - finish(0); -}); - -input.on('error', (error) => finish(5, `protocol read failed: ${error.message}`)); - -write({ - id: 'fd3-smoke', - method: 'initialize', - params: { clientInfo: { name: 'dshx-fd3-smoke', version: '1' } } -}); diff --git a/scripts/verify-ownership-boundary.mjs b/scripts/verify-ownership-boundary.mjs index d2d34bc3..3b4146f9 100644 --- a/scripts/verify-ownership-boundary.mjs +++ b/scripts/verify-ownership-boundary.mjs @@ -31,8 +31,7 @@ if (!manifest.exports?.['./presentation'] || !manifest.exports?.['./startup']) { // Every DSH package belongs to the user's official installation. DSHX may // depend on non-DSH leaf helpers, but it must never install a second Harness -// package into the profile. Service definitions are optional advisory host -// peers and resolve through DSH's installation-owned profile fallback. +// package into the profile. const runtimePeers = Object.keys(manifest.peerDependencies ?? {}).filter( (name) => name === '@deepseek-ai/dsh' || name.startsWith('@deepseek-ai/dsh-') ); @@ -61,9 +60,10 @@ requireText('bin/dshx.mjs', "'--profile', profile, ...argv"); requireText('bin/dshx.mjs', "stdio: 'inherit'"); requireText('bin/dshx.mjs', 'shell: false'); forbidText('bin/dshx.mjs', /(?:from\s+|import\s+\(\s*|require\()\s*["']@deepseek-ai\//, 'importing Harness runtime builds'); -for (const retired of ['DSHX_APP_SERVER_CMD', '--dshx-app-server', 'DSHX_APP_SERVER_ENDPOINT', 'DSHX_IPC_BRIDGE_BIN']) { - forbidText('bin/dshx.mjs', retired, `retired nested-backend launch seam ${retired}`); -} +for (const retired of [ + 'DSHX_APP_SERVER_CMD', '--dshx-app-server', 'DSHX_APP_SERVER_ENDPOINT', 'DSHX_IPC_BRIDGE_BIN', + 'DSHX_APP_SERVER_FD', 'DSHX_APP_SERVER_INPUT_FD', 'DSHX_APP_SERVER_OUTPUT_FD', 'DSHX_TERMINAL_INPUT_FD' +]) forbidText('bin/dshx.mjs', retired, `launcher owning transport/runtime seam ${retired}`); // Surface rows follow the official startup-provider -> presentation-runner pattern. requireText('src/dsh/startup-plugin.mjs', "inject = ['cmdlineArgs']"); @@ -74,9 +74,9 @@ forbidText('src/dsh/startup-plugin.mjs', '--dshx-app-server', 'private backend s requireText('src/dsh/presentation-plugin.mjs', "inject = ['dshxStartup']"); requireText('src/dsh/presentation-plugin.mjs', 'internals.spawnTui'); requireText('src/dsh/presentation-plugin.mjs', "stdio: ['pipe', 'inherit', 'inherit', 0, 'pipe']"); -requireText('src/dsh/presentation-plugin.mjs', 'DSHX_APP_SERVER_INPUT_FD'); -requireText('src/dsh/presentation-plugin.mjs', 'DSHX_TERMINAL_INPUT_FD'); -requireText('src/dsh/presentation-plugin.mjs', 'DSHX_APP_SERVER_OUTPUT_FD'); +for (const name of ['DSHX_APP_SERVER_INPUT_FD', 'DSHX_TERMINAL_INPUT_FD', 'DSHX_APP_SERVER_OUTPUT_FD']) { + requireText('src/dsh/presentation-plugin.mjs', name); +} requireText('src/dsh/presentation-plugin.mjs', 'startDshxStdioTransport'); requireText('src/dsh/presentation-plugin.mjs', 'ctx.provide(SERVICE_KEY'); requireText('src/dsh/presentation-plugin.mjs', 'requestHostExit(ctx'); @@ -86,14 +86,15 @@ forbidText('src/dsh/presentation-plugin.mjs', 'resolveDshInvocation', 'presentat requireText('src/dsh/stdio-transport.mjs', 'already-mounted DSH Context'); forbidText('src/dsh/stdio-transport.mjs', /WebSocket|unix:\/\//, 'network/socket framing'); -// Rust is still in the inherited-pipe migration layer until the Core profile -// lifecycle proves the final directional Node pipe topology. The next thin-fork -// patch must remove backend spawning; no bridge/socket path may return. +// The final thin fork consumes only profile-owned directional inherited pipes. const inheritedPatch = 'upstream/patches/codex/0012-dshx-inherited-profile-pipe.patch'; -requireText(inheritedPatch, 'InheritedPipe'); -requireText(inheritedPatch, 'DSHX_APP_SERVER_FD'); -requireText(inheritedPatch, '-use tokio::process::Command;'); +for (const needle of [ + 'InheritedPipes', 'DSHX_APP_SERVER_INPUT_FD', 'DSHX_TERMINAL_INPUT_FD', + 'DSHX_APP_SERVER_OUTPUT_FD', 'dshx_prepare_stdio', 'O_NONBLOCK', 'SetStdHandle' +]) requireText(inheritedPatch, needle); requireText(inheritedPatch, '- let mut command = Command::new(executable);'); +forbidText(inheritedPatch, /^\+libc = \{ workspace = true \}$/m, 'lockfile-changing app-server-client libc dependency'); +forbidText(inheritedPatch, /^\+.*DSHX_APP_SERVER_FD(?!_)/m, 'retired single-fd transport'); for (const file of readdirSync('upstream/patches/codex')) { if (!file.endsWith('.patch')) continue; forbidText(`upstream/patches/codex/${file}`, 'dshx-ipc-bridge', 'legacy Rust bridge'); @@ -101,8 +102,7 @@ for (const file of readdirSync('upstream/patches/codex')) { forbidText('scripts/build-codex-tui.sh', 'dshx-ipc-bridge'); forbidText('scripts/build-codex-tui.ps1', 'dshx-ipc-bridge'); -// Domain capabilities delegate to DSH public services rather than local OS or -// shadow runtime state. +// Domain capabilities delegate to DSH public services rather than local OS or shadow runtime state. for (const path of ['src/dsh/user-shell.mjs', 'src/dsh/workspace-command.mjs']) { forbidText(path, /execFile|execSync|spawn\(/, 'local process execution'); requireText(path, 'tools.execute'); diff --git a/scripts/verify-tui-invariants.mjs b/scripts/verify-tui-invariants.mjs index fcb33ba2..9df0c931 100644 --- a/scripts/verify-tui-invariants.mjs +++ b/scripts/verify-tui-invariants.mjs @@ -2,12 +2,10 @@ import { existsSync, readFileSync } from 'node:fs'; function read(path) { return readFileSync(path, 'utf8'); } function requireText(path, needle) { - const text = read(path); - if (!text.includes(needle)) throw new Error(`${path} is missing required invariant: ${needle}`); + if (!read(path).includes(needle)) throw new Error(`${path} is missing required invariant: ${needle}`); } function forbidText(path, needle, label = needle) { - const text = read(path); - if (text.includes(needle)) throw new Error(`${path} violates TUI invariant: ${label}`); + if (read(path).includes(needle)) throw new Error(`${path} violates TUI invariant: ${label}`); } const main = '.upstream/codex/codex-rs/tui/src/main.rs'; @@ -23,24 +21,31 @@ const approval = '.upstream/codex/codex-rs/tui/src/bottom_pane/approval_overlay. const permissions = '.upstream/codex/codex-rs/tui/src/chatwidget/permission_popups.rs'; for (const needle of [ - 'DSHX_APP_SERVER_FD is required', - 'RemoteAppServerEndpoint::InheritedPipe', + 'DSHX_APP_SERVER_INPUT_FD', + 'DSHX_TERMINAL_INPUT_FD', + 'DSHX_APP_SERVER_OUTPUT_FD', + 'RemoteAppServerEndpoint::InheritedPipes', + 'dshx_prepare_stdio', 'Some(dshx_endpoint)', 'DSHX_RESUME_MODE', ]) requireText(main, needle); -for (const legacy of ['DSHX_APP_SERVER_CMD', 'DSHX_APP_SERVER_ENDPOINT', 'DSHX_APP_SERVER_TOKEN']) { +for (const legacy of ['DSHX_APP_SERVER_CMD', 'DSHX_APP_SERVER_ENDPOINT', 'DSHX_APP_SERVER_TOKEN', 'DSHX_APP_SERVER_FD']) { forbidText(main, legacy, `legacy backend transport ${legacy}`); } +if (process.platform !== 'win32') requireText(main, 'O_NONBLOCK'); +requireText(main, 'SetStdHandle'); for (const needle of [ 'pub struct StdioAppServerClient', + 'input_fd: i32', + 'output_fd: i32', 'inherited_protocol_file', 'JSONRPCMessage', 'stdin.shutdown()', ]) requireText(stdio, needle); forbidText(stdio, 'Command::new(', 'TUI must not spawn a DSH backend'); requireText(client, 'Stdio(StdioAppServerClient)'); -requireText(lib, 'Some(endpoint @ RemoteAppServerEndpoint::InheritedPipe'); +requireText(lib, 'Some(endpoint @ RemoteAppServerEndpoint::InheritedPipes'); requireText(lib, 'AppServerTarget::LocalDaemon { endpoint }'); const legacyBridge = '.upstream/codex/codex-rs/stdio-to-uds/src/dshx_ipc_bridge.rs'; @@ -49,9 +54,10 @@ if (existsSync('src/dsh/local-server.mjs')) throw new Error('legacy Node socket for (const path of [approval, permissions, lib]) { requireText(path, 'fn dshx_backend'); - requireText(path, 'DSHX_APP_SERVER_FD'); - forbidText(path, 'DSHX_APP_SERVER_CMD', 'child-backend DSHX detection'); - forbidText(path, 'DSHX_APP_SERVER_ENDPOINT', 'legacy socket-mode DSHX detection'); + requireText(path, 'DSHX_APP_SERVER_INPUT_FD'); + for (const legacy of ['DSHX_APP_SERVER_CMD', 'DSHX_APP_SERVER_ENDPOINT', 'DSHX_APP_SERVER_FD']) { + forbidText(path, legacy, `legacy DSHX mode detection ${legacy}`); + } } requireText('.upstream/codex/codex-rs/tui/src/history_cell/session.rs', 'DeepSeek Harness'); requireText(lib, '!dshx_backend()'); @@ -75,17 +81,17 @@ if (slashText.slice(hiddenStart, hiddenEnd).includes('SlashCommand::Diff')) { throw new Error('/diff must remain visible in DSHX'); } -const launcher = read('bin/dshx.mjs'); requireText('bin/dshx.mjs', "'--profile', profile"); -forbidText('bin/dshx.mjs', 'DSHX_APP_SERVER_CMD', 'launcher must not create a backend child command'); -forbidText('bin/dshx.mjs', 'DSHX_APP_SERVER_FD', 'only the profile-owned presentation runner may publish the protocol fd'); +for (const legacy of [ + 'DSHX_APP_SERVER_CMD', 'DSHX_APP_SERVER_FD', 'DSHX_APP_SERVER_INPUT_FD', + 'DSHX_APP_SERVER_OUTPUT_FD', 'DSHX_TERMINAL_INPUT_FD', 'DSHX_APP_SERVER_ENDPOINT' +]) forbidText('bin/dshx.mjs', legacy, `only the profile-owned presentation row may publish transport fact ${legacy}`); -const presentation = read('src/dsh/presentation-plugin.mjs'); -if (!presentation.includes("stdio: ['inherit', 'inherit', 'inherit', 'pipe']")) { - throw new Error('presentation runner must preserve terminal fds 0/1/2 and reserve fd3 for the protocol pipe'); +requireText('src/dsh/presentation-plugin.mjs', "stdio: ['pipe', 'inherit', 'inherit', 0, 'pipe']"); +for (const needle of ['DSHX_APP_SERVER_INPUT_FD', 'DSHX_TERMINAL_INPUT_FD', 'DSHX_APP_SERVER_OUTPUT_FD']) { + requireText('src/dsh/presentation-plugin.mjs', needle); } -requireText('src/dsh/presentation-plugin.mjs', 'DSHX_APP_SERVER_FD'); const pkg = JSON.parse(read('package.json')); if (pkg.dependencies?.ws) throw new Error('ws must not be a production dependency'); -console.log('DSHX pinned TUI profile-owned fd3 invariants verified'); +console.log('DSHX pinned TUI profile-owned directional pipe invariants verified'); diff --git a/test/dshx-upstream-patch-policy.test.mjs b/test/dshx-upstream-patch-policy.test.mjs index 920192ba..4ff0b20b 100644 --- a/test/dshx-upstream-patch-policy.test.mjs +++ b/test/dshx-upstream-patch-policy.test.mjs @@ -28,11 +28,14 @@ test('Codex-only runtime owners stay hidden from DSHX', () => { } }); -test('final DSHX mode detection follows the inherited profile fd, never a backend command or socket endpoint', () => { +test('final DSHX mode detection follows the inherited profile pipes, never a backend command or socket endpoint', () => { assert.equal(inheritedPipePatch.split('- std::env::var_os("DSHX_APP_SERVER_CMD").is_some()').length - 1, 3); - assert.equal(inheritedPipePatch.split('+ std::env::var_os("DSHX_APP_SERVER_FD").is_some()').length - 1, 3); - assert.match(inheritedPipePatch, /DSHX_APP_SERVER_FD is required/); + assert.equal(inheritedPipePatch.split('+ std::env::var_os("DSHX_APP_SERVER_INPUT_FD").is_some()').length - 1, 3); + for (const name of ['DSHX_APP_SERVER_INPUT_FD', 'DSHX_TERMINAL_INPUT_FD', 'DSHX_APP_SERVER_OUTPUT_FD']) { + assert.match(inheritedPipePatch, new RegExp(name)); + } assert.doesNotMatch(inheritedPipePatch, /\+.*DSHX_APP_SERVER_ENDPOINT/); + assert.doesNotMatch(inheritedPipePatch, /\+.*DSHX_APP_SERVER_FD(?!_)/); }); test('DSH thread ownership is independent from Codex remote-workspace classification', () => { @@ -43,9 +46,13 @@ test('DSH thread ownership is independent from Codex remote-workspace classifica assert.equal(stdioModePatch.split('+ if crate::dshx_backend() {').length - 1, 3); }); -test('the final transport patch removes TUI-owned backend spawning', () => { - assert.match(inheritedPipePatch, /RemoteAppServerEndpoint::InheritedPipe/); +test('the final transport patch removes TUI-owned backend spawning and restores terminal stdin', () => { + assert.match(inheritedPipePatch, /RemoteAppServerEndpoint::InheritedPipes/); assert.match(inheritedPipePatch, /inherited_protocol_file/); + assert.match(inheritedPipePatch, /dshx_prepare_stdio/); + assert.match(inheritedPipePatch, /O_NONBLOCK/); + assert.match(inheritedPipePatch, /SetStdHandle/); assert.match(inheritedPipePatch, /- let mut command = Command::new\(executable\);/); assert.doesNotMatch(inheritedPipePatch, /\+.*Command::new\(executable\)/); + assert.doesNotMatch(inheritedPipePatch, /^\+libc = \{ workspace = true \}$/m, 'app-server-client must not add a lockfile-changing libc dependency'); }); diff --git a/upstream/patches/codex/0012-dshx-inherited-profile-pipe.patch b/upstream/patches/codex/0012-dshx-inherited-profile-pipe.patch index c8356460..f003f254 100644 --- a/upstream/patches/codex/0012-dshx-inherited-profile-pipe.patch +++ b/upstream/patches/codex/0012-dshx-inherited-profile-pipe.patch @@ -1,24 +1,22 @@ diff --git a/codex-rs/app-server-client/Cargo.toml b/codex-rs/app-server-client/Cargo.toml --- a/codex-rs/app-server-client/Cargo.toml +++ b/codex-rs/app-server-client/Cargo.toml -@@ -1,1 +1,2 @@ - serde_json = { workspace = true } -+libc = { workspace = true } @@ -1,1 +1,1 @@ -tokio = { workspace = true, features = ["sync", "time", "rt", "io-util", "process"] } +tokio = { workspace = true, features = ["sync", "time", "rt", "io-util", "fs"] } diff --git a/codex-rs/app-server-client/src/remote.rs b/codex-rs/app-server-client/src/remote.rs --- a/codex-rs/app-server-client/src/remote.rs +++ b/codex-rs/app-server-client/src/remote.rs -@@ -1,3 +1,3 @@ +@@ -1,3 +1,4 @@ - StdioChild { - command: Vec, -+ InheritedPipe { -+ fd: i32, ++ InheritedPipes { ++ input_fd: i32, ++ output_fd: i32, }, @@ -1,1 +1,1 @@ - RemoteAppServerEndpoint::StdioChild { .. } => Err(IoError::new( -+ RemoteAppServerEndpoint::InheritedPipe { .. } => Err(IoError::new( ++ RemoteAppServerEndpoint::InheritedPipes { .. } => Err(IoError::new( diff --git a/codex-rs/app-server-client/src/stdio.rs b/codex-rs/app-server-client/src/stdio.rs --- a/codex-rs/app-server-client/src/stdio.rs +++ b/codex-rs/app-server-client/src/stdio.rs @@ -32,6 +30,8 @@ diff --git a/codex-rs/app-server-client/src/stdio.rs b/codex-rs/app-server-clien +use std::os::windows::io::BorrowedHandle; +#[cfg(windows)] +use std::os::windows::io::RawHandle; +@@ -1,1 +0,0 @@ +-use crate::SHUTDOWN_TIMEOUT; @@ -1,1 +1,4 @@ use tokio::io::AsyncBufReadExt; +use tokio::fs::File as TokioFile; @@ -46,10 +46,11 @@ diff --git a/codex-rs/app-server-client/src/stdio.rs b/codex-rs/app-server-clien + +type BoxReader = Pin>; +type BoxWriter = Pin>; -@@ -1,1 +1,1 @@ +@@ -1,1 +2,2 @@ - pub command: Vec, -+ pub fd: i32, -@@ -1,31 +1,14 @@ ++ pub input_fd: i32, ++ pub output_fd: i32, +@@ -1,31 +1,20 @@ - let executable = args.command.first().filter(|value| !value.is_empty()).ok_or_else(|| { - IoError::new(ErrorKind::InvalidInput, "stdio app-server command must not be empty") - })?; @@ -72,16 +73,19 @@ diff --git a/codex-rs/app-server-client/src/stdio.rs b/codex-rs/app-server-clien - let stdout = child.stdout.take().ok_or_else(|| { - IoError::new(ErrorKind::BrokenPipe, "stdio app-server stdout was not piped") - })?; -+ if args.fd < 3 { -+ return Err(IoError::new(ErrorKind::InvalidInput, "DSHX protocol fd must be >= 3")); ++ if args.input_fd < 0 || args.output_fd < 0 || args.input_fd == args.output_fd { ++ return Err(IoError::new( ++ ErrorKind::InvalidInput, ++ "DSHX protocol input/output descriptors must be distinct non-negative fds", ++ )); + } -+ let stream = inherited_protocol_file(args.fd)?; -+ let reader = stream.try_clone()?; -+ let mut stdin: BoxWriter = Box::pin(TokioFile::from_std(stream)); -+ let stdout: BoxReader = Box::pin(TokioFile::from_std(reader)); ++ let stdout_file = inherited_protocol_file(args.input_fd)?; ++ let stdin_file = inherited_protocol_file(args.output_fd)?; ++ let mut stdin: BoxWriter = Box::pin(TokioFile::from_std(stdin_file)); ++ let stdout: BoxReader = Box::pin(TokioFile::from_std(stdout_file)); let mut lines = BufReader::new(stdout).lines(); - let endpoint = format!("stdio://{}", executable); -+ let endpoint = format!("fd://{}", args.fd); ++ let endpoint = format!("fds://{}/{}", args.input_fd, args.output_fd); @@ -1,17 +1,2 @@ StdioClientCommand::Shutdown { response_tx } => { - let mut result = stdin.shutdown().await; @@ -115,7 +119,7 @@ diff --git a/codex-rs/app-server-client/src/stdio.rs b/codex-rs/app-server-clien @@ -1,1 +1,1 @@ -async fn write_jsonrpc_line(stdin: &mut ChildStdin, message: JSONRPCMessage, endpoint: &str) -> IoResult<()> { +async fn write_jsonrpc_line(stdin: &mut BoxWriter, message: JSONRPCMessage, endpoint: &str) -> IoResult<()> { -@@ -1,3 +1,24 @@ +@@ -1,3 +1,29 @@ fn deliver_event(event_tx: &mpsc::UnboundedSender, event: AppServerEvent) -> IoResult<()> { event_tx.send(event).map_err(|_| IoError::new(ErrorKind::BrokenPipe, "stdio app-server event consumer is closed")) } @@ -127,8 +131,13 @@ diff --git a/codex-rs/app-server-client/src/stdio.rs b/codex-rs/app-server-clien +} + +#[cfg(windows)] ++unsafe extern "C" { ++ fn _get_osfhandle(fd: i32) -> isize; ++} ++ ++#[cfg(windows)] +fn inherited_protocol_file(fd: i32) -> IoResult { -+ let handle = unsafe { libc::get_osfhandle(fd) }; ++ let handle = unsafe { _get_osfhandle(fd) }; + if handle == -1 { + return Err(IoError::last_os_error()); + } @@ -138,7 +147,94 @@ diff --git a/codex-rs/app-server-client/src/stdio.rs b/codex-rs/app-server-clien diff --git a/codex-rs/tui/src/main.rs b/codex-rs/tui/src/main.rs --- a/codex-rs/tui/src/main.rs +++ b/codex-rs/tui/src/main.rs -@@ -1,14 +1,10 @@ +@@ -1,1 +1,87 @@ +-fn main() -> anyhow::Result<()> { ++#[cfg(unix)] ++fn dshx_make_blocking(fd: i32) -> anyhow::Result<()> { ++ let flags = unsafe { libc::fcntl(fd, libc::F_GETFL) }; ++ if flags == -1 { ++ return Err(anyhow::anyhow!("failed to read DSHX pipe flags for fd {fd}: {}", std::io::Error::last_os_error())); ++ } ++ if flags & libc::O_NONBLOCK != 0 { ++ let result = unsafe { libc::fcntl(fd, libc::F_SETFL, flags & !libc::O_NONBLOCK) }; ++ if result == -1 { ++ return Err(anyhow::anyhow!("failed to clear O_NONBLOCK for DSHX fd {fd}: {}", std::io::Error::last_os_error())); ++ } ++ } ++ Ok(()) ++} ++ ++fn dshx_env_fd(name: &str) -> anyhow::Result { ++ std::env::var(name) ++ .map_err(|_| anyhow::anyhow!("{name} is required; DSHX never falls back to the Codex agent runtime"))? ++ .parse() ++ .map_err(|err| anyhow::anyhow!("invalid {name}: {err}")) ++} ++ ++#[cfg(unix)] ++fn dshx_prepare_stdio(input_fd: i32, terminal_fd: i32, output_fd: i32) -> anyhow::Result<(i32, i32)> { ++ if input_fd != libc::STDIN_FILENO { ++ anyhow::bail!("DSHX_APP_SERVER_INPUT_FD must be child stdin (fd 0)"); ++ } ++ if terminal_fd < 3 || output_fd < 3 || terminal_fd == output_fd { ++ anyhow::bail!("DSHX terminal/protocol output fds must be distinct inherited descriptors >= 3"); ++ } ++ let saved_input = unsafe { libc::dup(input_fd) }; ++ if saved_input < 0 { ++ return Err(anyhow::anyhow!("failed to preserve DSHX protocol input: {}", std::io::Error::last_os_error())); ++ } ++ if unsafe { libc::dup2(terminal_fd, libc::STDIN_FILENO) } < 0 { ++ unsafe { libc::close(saved_input) }; ++ return Err(anyhow::anyhow!("failed to restore terminal stdin: {}", std::io::Error::last_os_error())); ++ } ++ dshx_make_blocking(saved_input)?; ++ dshx_make_blocking(output_fd)?; ++ Ok((saved_input, output_fd)) ++} ++ ++#[cfg(windows)] ++unsafe extern "C" { ++ fn _dup(fd: i32) -> i32; ++ fn _dup2(source: i32, target: i32) -> i32; ++ fn _close(fd: i32) -> i32; ++ fn _get_osfhandle(fd: i32) -> isize; ++} ++ ++#[cfg(windows)] ++fn dshx_prepare_stdio(input_fd: i32, terminal_fd: i32, output_fd: i32) -> anyhow::Result<(i32, i32)> { ++ if input_fd != 0 { ++ anyhow::bail!("DSHX_APP_SERVER_INPUT_FD must be child stdin (fd 0)"); ++ } ++ if terminal_fd < 3 || output_fd < 3 || terminal_fd == output_fd { ++ anyhow::bail!("DSHX terminal/protocol output fds must be distinct inherited descriptors >= 3"); ++ } ++ let terminal_handle = unsafe { _get_osfhandle(terminal_fd) }; ++ if terminal_handle == -1 { ++ return Err(anyhow::anyhow!("failed to resolve inherited terminal stdin: {}", std::io::Error::last_os_error())); ++ } ++ let saved_input = unsafe { _dup(input_fd) }; ++ if saved_input < 0 { ++ return Err(anyhow::anyhow!("failed to preserve DSHX protocol input: {}", std::io::Error::last_os_error())); ++ } ++ if unsafe { _dup2(terminal_fd, 0) } != 0 { ++ unsafe { _close(saved_input) }; ++ return Err(anyhow::anyhow!("failed to restore CRT terminal stdin: {}", std::io::Error::last_os_error())); ++ } ++ let restored = unsafe { ++ windows_sys::Win32::System::Console::SetStdHandle( ++ windows_sys::Win32::System::Console::STD_INPUT_HANDLE, ++ terminal_handle as _, ++ ) ++ }; ++ if restored == 0 { ++ unsafe { _close(saved_input) }; ++ return Err(anyhow::anyhow!("failed to restore Win32 terminal stdin: {}", std::io::Error::last_os_error())); ++ } ++ Ok((saved_input, output_fd)) ++} ++ ++fn main() -> anyhow::Result<()> { +@@ -1,14 +1,11 @@ - let dshx_command_json = std::env::var("DSHX_APP_SERVER_CMD").map_err(|_| { - anyhow::anyhow!( - "DSHX_APP_SERVER_CMD is required; DSHX never falls back to the Codex agent runtime" @@ -148,51 +244,52 @@ diff --git a/codex-rs/tui/src/main.rs b/codex-rs/tui/src/main.rs - .map_err(|err| anyhow::anyhow!("invalid DSHX_APP_SERVER_CMD JSON: {err}"))?; - if dshx_command.is_empty() || dshx_command[0].is_empty() { - anyhow::bail!("DSHX_APP_SERVER_CMD must contain a non-empty executable argv[0]"); -+ let dshx_fd: i32 = std::env::var("DSHX_APP_SERVER_FD") -+ .map_err(|_| anyhow::anyhow!("DSHX_APP_SERVER_FD is required; DSHX never falls back to the Codex agent runtime"))? -+ .parse() -+ .map_err(|err| anyhow::anyhow!("invalid DSHX_APP_SERVER_FD: {err}"))?; -+ if dshx_fd < 3 { -+ anyhow::bail!("DSHX_APP_SERVER_FD must be an inherited descriptor >= 3"); - } +- } - let dshx_endpoint = RemoteAppServerEndpoint::StdioChild { - command: dshx_command, -+ let dshx_endpoint = RemoteAppServerEndpoint::InheritedPipe { -+ fd: dshx_fd, ++ let dshx_input_fd = dshx_env_fd("DSHX_APP_SERVER_INPUT_FD")?; ++ let dshx_terminal_fd = dshx_env_fd("DSHX_TERMINAL_INPUT_FD")?; ++ let dshx_output_fd = dshx_env_fd("DSHX_APP_SERVER_OUTPUT_FD")?; ++ let (dshx_input_fd, dshx_output_fd) = ++ dshx_prepare_stdio(dshx_input_fd, dshx_terminal_fd, dshx_output_fd)?; ++ let dshx_endpoint = RemoteAppServerEndpoint::InheritedPipes { ++ input_fd: dshx_input_fd, ++ output_fd: dshx_output_fd, }; diff --git a/codex-rs/tui/src/lib.rs b/codex-rs/tui/src/lib.rs --- a/codex-rs/tui/src/lib.rs +++ b/codex-rs/tui/src/lib.rs @@ -1,1 +1,1 @@ - RemoteAppServerEndpoint::StdioChild { .. } => false, -+ RemoteAppServerEndpoint::InheritedPipe { .. } => false, -@@ -1,3 +1,3 @@ ++ RemoteAppServerEndpoint::InheritedPipes { .. } => false, +@@ -1,3 +1,4 @@ - RemoteAppServerEndpoint::StdioChild { command } => { -+ RemoteAppServerEndpoint::InheritedPipe { fd } => { ++ RemoteAppServerEndpoint::InheritedPipes { input_fd, output_fd } => { let app_server = StdioAppServerClient::connect(StdioAppServerConnectArgs { - command, -+ fd, ++ input_fd, ++ output_fd, @@ -1,1 +1,1 @@ - Some(endpoint @ RemoteAppServerEndpoint::StdioChild { .. }) => { -+ Some(endpoint @ RemoteAppServerEndpoint::InheritedPipe { .. }) => { ++ Some(endpoint @ RemoteAppServerEndpoint::InheritedPipes { .. }) => { @@ -1,1 +1,1 @@ - std::env::var_os("DSHX_APP_SERVER_CMD").is_some() -+ std::env::var_os("DSHX_APP_SERVER_FD").is_some() ++ std::env::var_os("DSHX_APP_SERVER_INPUT_FD").is_some() diff --git a/codex-rs/tui/src/status/remote_connection.rs b/codex-rs/tui/src/status/remote_connection.rs --- a/codex-rs/tui/src/status/remote_connection.rs +++ b/codex-rs/tui/src/status/remote_connection.rs @@ -1,1 +1,1 @@ - RemoteAppServerEndpoint::StdioChild { .. } => return None, -+ RemoteAppServerEndpoint::InheritedPipe { .. } => return None, ++ RemoteAppServerEndpoint::InheritedPipes { .. } => return None, diff --git a/codex-rs/tui/src/bottom_pane/approval_overlay.rs b/codex-rs/tui/src/bottom_pane/approval_overlay.rs --- a/codex-rs/tui/src/bottom_pane/approval_overlay.rs +++ b/codex-rs/tui/src/bottom_pane/approval_overlay.rs @@ -1,1 +1,1 @@ - std::env::var_os("DSHX_APP_SERVER_CMD").is_some() -+ std::env::var_os("DSHX_APP_SERVER_FD").is_some() ++ std::env::var_os("DSHX_APP_SERVER_INPUT_FD").is_some() diff --git a/codex-rs/tui/src/chatwidget/permission_popups.rs b/codex-rs/tui/src/chatwidget/permission_popups.rs --- a/codex-rs/tui/src/chatwidget/permission_popups.rs +++ b/codex-rs/tui/src/chatwidget/permission_popups.rs @@ -1,1 +1,1 @@ - std::env::var_os("DSHX_APP_SERVER_CMD").is_some() -+ std::env::var_os("DSHX_APP_SERVER_FD").is_some() ++ std::env::var_os("DSHX_APP_SERVER_INPUT_FD").is_some() From c33e3bf8b8581d21420261874c229f9d311efb7a Mon Sep 17 00:00:00 2001 From: code-new-bie <403466121@qq.com> Date: Fri, 28 Aug 2026 09:16:20 +0800 Subject: [PATCH 47/60] fix(tui): retain bounded stdio shutdown timeout --- .../patches/codex/0013-dshx-stdio-shutdown-timeout.patch | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 upstream/patches/codex/0013-dshx-stdio-shutdown-timeout.patch diff --git a/upstream/patches/codex/0013-dshx-stdio-shutdown-timeout.patch b/upstream/patches/codex/0013-dshx-stdio-shutdown-timeout.patch new file mode 100644 index 00000000..cc92b00d --- /dev/null +++ b/upstream/patches/codex/0013-dshx-stdio-shutdown-timeout.patch @@ -0,0 +1,9 @@ +diff --git a/codex-rs/app-server-client/src/stdio.rs b/codex-rs/app-server-client/src/stdio.rs +--- a/codex-rs/app-server-client/src/stdio.rs ++++ b/codex-rs/app-server-client/src/stdio.rs +@@ -1,1 +1,1 @@ +- && let Ok(Ok(result)) = timeout(SHUTDOWN_TIMEOUT, response_rx).await ++ && let Ok(Ok(result)) = timeout(crate::SHUTDOWN_TIMEOUT, response_rx).await +@@ -1,1 +1,1 @@ +- if timeout(SHUTDOWN_TIMEOUT, &mut worker_handle).await.is_err() { ++ if timeout(crate::SHUTDOWN_TIMEOUT, &mut worker_handle).await.is_err() { From 7b50d203244c6eb15aed2fec7c0161593556709a Mon Sep 17 00:00:00 2001 From: code-new-bie <403466121@qq.com> Date: Fri, 28 Aug 2026 09:20:06 +0800 Subject: [PATCH 48/60] refactor(plugin): retire socket transport surfaces --- .github/workflows/release.yml | 20 ++-- README.md | 175 ++++++++++++------------------ SECURITY.md | 79 ++++++++------ bin/dshx-stub-local.mjs | 70 ------------ devtools/dshx-stub-server.mjs | 21 ---- devtools/stub-server.mjs | 127 ---------------------- devtools/tui-stub-parent.mjs | 117 ++++++++++++++++++++ docs/ARCHITECTURE.md | 172 ++++++++++++++--------------- docs/DSH-CAPABILITY-MATRIX.md | 123 +++++++++------------ docs/RELEASE-READINESS.md | 119 ++++++++++---------- docs/ROADMAP.md | 128 +++++++++------------- docs/RUNTIME-INTEGRATION.md | 156 +++++++++++--------------- docs/UX-PARITY.md | 104 ++++++++---------- package.json | 2 +- scripts/package-platform.mjs | 18 +-- scripts/verify-bundle-install.mjs | 16 +-- scripts/windows-rc-acceptance.ps1 | 12 +- test/tui_smoke.py | 11 +- test/tui_smoke_windows.mjs | 6 +- 19 files changed, 616 insertions(+), 860 deletions(-) delete mode 100644 bin/dshx-stub-local.mjs delete mode 100644 devtools/dshx-stub-server.mjs delete mode 100644 devtools/stub-server.mjs create mode 100644 devtools/tui-stub-parent.mjs diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 9ad8399d..67236565 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -70,7 +70,7 @@ jobs: if: runner.os == 'Windows' shell: pwsh run: Add-Content -Path $env:GITHUB_ENV -Value "DSHX_VERSION=$($env:GITHUB_REF_NAME.TrimStart('v'))" - - name: Test presentation adapter from frozen graph + - name: Test standard DSH presentation bundle from frozen graph run: | npm ci --include=optional --ignore-scripts=false node scripts/verify-dsh-closure.mjs @@ -78,7 +78,7 @@ jobs: node scripts/verify-ownership-boundary.mjs - name: Enable pnpm for official plugin machinery run: corepack enable pnpm - - name: Verify official DSH stdio lifecycle + - name: Verify official DSH profile lifecycle run: node scripts/runtime-smoke.mjs - name: Build pinned TUI (Unix) if: runner.os != 'Windows' @@ -88,9 +88,9 @@ jobs: if: runner.os == 'Windows' shell: pwsh run: ./scripts/build-codex-tui.ps1 - - name: Verify stdio thin-fork invariants + - name: Verify profile-owned directional-pipe thin-fork invariants run: node scripts/verify-tui-invariants.mjs - - name: Real pinned TUI stdio PTY + CJK + resize smoke + - name: Real pinned TUI PTY + CJK + resize smoke if: runner.os != 'Windows' shell: bash run: | @@ -99,12 +99,12 @@ jobs: python3 -m venv "$VENV" "$VENV/bin/python" -m pip install --disable-pip-version-check pexpect "$VENV/bin/python" test/tui_smoke.py - - name: Real pinned TUI Windows ConPTY + CJK stdio smoke + - name: Real pinned TUI Windows ConPTY + CJK smoke if: runner.os == 'Windows' run: node test/tui_smoke_windows.mjs - name: Build installable platform tarball run: node scripts/package-platform.mjs - - name: Verify release bundle install and stdio activation + - name: Verify release bundle install and profile activation env: DSHX_REQUIRE_RELEASE: '1' run: node scripts/verify-bundle-install.mjs @@ -120,9 +120,8 @@ jobs: echo 'clean DSHX install unexpectedly materialized a second @deepseek-ai/dsh runtime' >&2 exit 1 fi - "$PREFIX/bin/dshx" --version | grep -F "$DSHX_VERSION" export DSHX_DSH_BIN="$PWD/node_modules/@deepseek-ai/dsh/lib/bin.js" - "$PREFIX/bin/dshx" doctor + "$PREFIX/bin/dshx" --version | grep -F "$DSHX_VERSION" - name: Clean install smoke (Windows) if: runner.os == 'Windows' shell: pwsh @@ -133,10 +132,9 @@ jobs: npm install --global --prefix $prefix --include=optional --ignore-scripts=false $tgz.FullName & npm ls --global --prefix $prefix '@deepseek-ai/dsh' --depth=0 *> $null if ($LASTEXITCODE -eq 0) { throw 'clean DSHX install unexpectedly materialized a second @deepseek-ai/dsh runtime' } + $env:DSHX_DSH_BIN = (Resolve-Path 'node_modules\@deepseek-ai\dsh\lib\bin.js').Path $version = & (Join-Path $prefix 'dshx.cmd') --version if (-not ($version -match [regex]::Escape($env:DSHX_VERSION))) { throw "wrong dshx version: $version" } - $env:DSHX_DSH_BIN = (Resolve-Path 'node_modules\@deepseek-ai\dsh\lib\bin.js').Path - & (Join-Path $prefix 'dshx.cmd') doctor - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: dshx-${{ matrix.label }} @@ -175,7 +173,7 @@ jobs: baseline = {key: records[0][1].get(key) for key in keys} if baseline['version'] != expected_version: raise SystemExit(f"artifact version mismatch: expected {expected_version}, got {baseline['version']}") - if baseline['transport'] != 'local-stdio-child': + if baseline['transport'] != 'profile-directional-pipes': raise SystemExit(f"unexpected transport provenance: {baseline['transport']}") if baseline['dependencyGraph'] != 'source-package-lock': raise SystemExit(f"unexpected dependency graph provenance: {baseline['dependencyGraph']}") diff --git a/README.md b/README.md index e4bf19e2..c08580af 100644 --- a/README.md +++ b/README.md @@ -1,174 +1,137 @@ # DSHX (`dsh-codex`) -DSHX is a terminal frontend for **official DeepSeek Harness** that reuses a pinned Codex TUI thin fork instead of reimplementing a look-alike terminal UI. +DSHX is a standard **DeepSeek Harness TUI bundle** that reuses a pinned Codex TUI thin fork for terminal rendering and interaction. Agent behavior remains owned by the user's installed DeepSeek Harness. ## Product contract -From a code project, the normal user entry point is: +Normal use is simply: ```bash +cd /path/to/project dshx ``` -No separate Codex installation, remote-mode command, bridge command, DSH WebUI, or manual profile plumbing is part of the production UX. +The interaction target is the pinned Codex CLI/TUI: composer, slash commands, model and permission pickers, approvals, ask-user flows, tool/shell cells, diffs, plan/reasoning presentation, steering, Ctrl+C interrupt, resume, status/footer, scrolling, resize and mouse behavior. Windows Terminal and CJK/IME are release gates. -The interaction target is the pinned Codex CLI/TUI: welcome screen, composer, slash commands, model and permission pickers, approvals, ask-user flows, tool/shell cells, diffs, plan/reasoning presentation, steering, Ctrl+C interrupt, resume, status/footer, scrolling, resize and mouse behavior. Windows Terminal and CJK/IME are first-class release gates. +DSHX does **not** ship a Codex agent runtime, a second DSH runtime, a WebUI dependency, a local server, a WebSocket/UDS bridge, or a user-facing remote-mode command. -## Plugin usage +## Standard DSH plugin delivery -DSHX ships as a standard DSH profile bundle: the package manifest declares -`dsh.bundle.patch`, so the official machinery installs, layers, hot-reloads -and withdraws it like any other composition row set. +The package declares `dsh.bundle.patch`, so DSH installs and composes it through the official plugin/profile machinery: ```bash -# Install into any profile (tarball from a release, or this checkout): dsh plugin --profile tui add ./code-new-bie-dshx-tui-.tgz +dsh --profile tui -# Withdraw it again; the surface disappears on the next profile start: dsh plugin --profile tui remove @code-new-bie/dshx-tui ``` -The zero-argument `dshx` launcher is a thin bootstrap over the same command: -it ensures the selected profile carries this exact package version, boots the -official composition, and spawns the pinned TUI against the endpoint that the -loader-mounted surface rows publish. - -## Ownership boundary - -We maintain only: +`dshx` is only a convenience bootstrap. It ensures the selected profile contains this package and then starts the user's official `dsh --profile ` launcher. The DSH process owns the Loader tree, runtime services and process-exit lifecycle. -- the Codex TUI thin fork and upstream sync patches; -- TUI behavior and UX parity; -- the `dshx` launcher, local presentation transport and packaging; -- the thinnest practical projection from DSH **public APIs/events** into the TUI protocol. - -We do **not** maintain, fork or recreate DeepSeek Harness capabilities. DSH owns the agent loop, sessions, model routing, tools, sandbox, approval policy, skills, subagents, plugins, jobs/workflows and persistence. - -If DSH does not expose a capability, DSHX waits for upstream or explicitly hides/degrades the corresponding UI. It does not implement a replacement runtime. +## Runtime topology ```text -pinned Codex TUI thin fork ← DSHX presentation - │ - │ WebSocket framing over private local UDS - ▼ -dshx-ipc-bridge ← tiny transport bridge; no runtime state - │ - │ JSONL over child stdio - ▼ -DSHX presentation adapter ← translation only - │ -════════════════ ownership boundary ════════════════ - │ official DSH public APIs/events - ▼ -Official DeepSeek Harness ← Agent / Session / tools / policy / persistence +dshx + │ thin profile bootstrap + ▼ +user-installed dsh --profile tui ← sole runtime owner + │ + ├─ dshx-startup Cordis row + └─ dshx-presentation Cordis row + │ + │ launches presentation child only + ▼ + pinned Codex TUI thin fork + ⇅ anonymous directional child-process pipes + TUI-protocol projection + ⇅ official DSH public APIs/events + Agent / Session / tools / policy / persistence ``` -There is **no TCP listener in the production launch path**. The bridge reuses Codex's own cross-platform `codex_uds` implementation so the Rust TUI and Node DSH composition can stay in separate processes without unsafe FFI. - -## Current integration status +The production transport has no listener and no address. The DSH parent starts the native TUI with three inherited descriptor facts: -`release/1.0-rc` is the sole production release-candidate integration branch, reviewed directly against `main` in Draft PR #11. Older M0/M1/thin-launcher/transport PRs are historical workstreams rather than release dependencies. +- child fd `0`: protocol input, DSH → TUI; +- child fd `3`: preserved terminal stdin; +- child fd `4`: protocol output, TUI → DSH. -The selected production transport is the small local-IPC bridge above. The alternative experiment that added a larger direct-stdio transport implementation inside the Codex client is intentionally excluded from the 1.0 line to keep the maintained upstream diff smaller. +The thin fork saves protocol fd 0, restores the terminal handle onto ordinary stdin before crossterm starts, and connects its app-server-compatible client to the two protocol descriptors. This keeps the upstream TUI in charge of terminal I/O while the already-mounted DSH Context stays in charge of runtime behavior. -The candidate implementation includes: +## Ownership boundary -- zero-argument `dshx` launch and `dshx resume` flows; -- official DSH runtime composition and exact supported DSH rc.8 release-closure checks; -- DSH-backed session/history, model, permissions, approvals, ask-user, tools/shell/diffs, plan/reasoning, steering/interrupt, rename, fork/compaction, skills and subagent presentation boundaries; -- pinned Codex TUI build plus packaged cross-platform local IPC bridge; -- an executable visible-slash-command contract so every runtime-owned command left visible is either DSH-backed or the build fails; -- release artifacts for Linux x64, Windows x64, macOS arm64 and macOS x64; -- clean-install `dshx doctor`, including a real local UDS + WebSocket-framing ping/pong data-plane self-check; -- Linux/macOS real-TUI PTY smoke and Windows real-TUI ConPTY + Chinese-text smoke through the production local-IPC topology; -- fail-closed ownership/security tests that keep DSH authoritative. +DSHX owns only: -A commit is not called 1.0-ready merely because these paths exist. The exact release candidate must pass the repository CI/release gates and the side-by-side Windows Terminal/CJK/IME acceptance pass described in `docs/RELEASE-READINESS.md` and `docs/UX-PARITY.md`. +- the pinned Codex TUI thin fork and its narrow patch queue; +- UX parity and branding; +- the standard DSH startup/presentation rows; +- the anonymous presentation transport; +- the thinnest practical projection from DSH public APIs/events into the TUI protocol. -## Install a release artifact +DeepSeek Harness owns: -Production users should install the **platform-specific tarball generated by a published DSHX release**, not build the pinned Codex workspace themselves. +- Agent creation, continuation and cancellation; +- Session identity, history and persistence; +- model selection, routing and credentials; +- tools and shell execution; +- sandbox and approval policy; +- user questions; +- skills, subagents, plugins and jobs/workflows. -1. Download the tarball for your platform from the chosen GitHub release and verify its SHA-256 against that release's `SHA256SUMS`. -2. Install the downloaded artifact globally with npm: +If DSH does not expose a capability that the Codex UI expects, DSHX hides it, degrades it explicitly, or fails closed. It does not create a replacement runtime. -```bash -npm install --global ./dshx---.tgz -``` +The Codex protocol dialect is confined to `src/tui-protocol/`. Modules under `src/dsh/` use DSH vocabulary and public services. -3. Verify the installed product, then enter any code project and start it: +## Host compatibility -```bash -dshx --version -dshx doctor -cd /path/to/project -dshx -``` +Production does not pin the user's DSH installation to one exact release. DSH packages are optional advisory peers with a compatibility floor; the profile resolves services from the host installation. Development and CI freeze one tested DSH closure so regressions are reproducible without shipping that closure as a second runtime. -Windows PowerShell uses the same npm install command. For a 1.0 release-candidate acceptance run, use `scripts/windows-rc-acceptance.ps1` so the tarball checksum, isolated install, `dshx --version` and `dshx doctor` are verified before the real Windows Terminal/IME comparison. +## Build and verification -The release tarball already contains the matching native `dshx-tui` and `dshx-ipc-bridge` binaries. A separate Codex install, DSH WebUI process, bridge command or remote-mode setup is not part of installation. - -## Build from source - -Source builds are for contributors and DSHX development. The pinned DSH runtime supports Node.js `^22.19.0 || >=24.0.0`; DSHX 1.0 standardizes dependency freezing, CI and release builds on **Node.js 24 LTS / npm 11**. Rust/Cargo, Git and the platform toolchain required by the pinned Codex workspace are also required for native TUI builds. - -The release dependency graph is frozen outside CI so GitHub Actions never mutates the candidate branch. On a trusted Node 24 LTS machine with npm-registry access, generate and verify the lock with: - -```bash -npm run freeze:deps -``` - -Review and commit the generated `package-lock.json`. Do not hand-edit or fabricate it. After the graph has been frozen, all contributor/CI installs use: +Source builds require Node.js supported by DSH (`^22.19.0 || >=24.0.0`), Rust/Cargo, Git and the pinned Codex platform toolchain. CI/release dependency freezing uses Node 24 LTS / npm 11. ```bash npm ci +npm test +node scripts/verify-ownership-boundary.mjs +node scripts/runtime-smoke.mjs ``` -Linux/macOS: +Build the pinned native TUI: ```bash +# Linux/macOS ./scripts/build-codex-tui.sh -npm link -dshx doctor -dshx -``` -Windows PowerShell: - -```powershell -.\scripts\build-codex-tui.ps1 -npm link -dshx doctor -dshx +# Windows PowerShell +./scripts/build-codex-tui.ps1 ``` -`dshx doctor` checks the DSH-compatible Node runtime, the packaged TUI, the local IPC data plane, the `tui` surface profile (bootstrapped idempotently through the official plugin command), the official DSH composition with the loader-activated surface rows, and the isolated DSHX presentation home/IPC path. - -For the full plugin-delivery proof — pack → official install into a throwaway profile → composed-tree assertions → loader activation with a live transport — run: +Then verify the materialized thin fork and standard bundle delivery: ```bash +node scripts/verify-tui-invariants.mjs npm run verify:bundle ``` +`verify:bundle` performs pack → official `dsh plugin --profile tui add` into an isolated DSH home → composed-tree assertions → live directional-pipe initialize → single-runtime assertions. + +Linux/macOS PTY and Windows ConPTY tests use a deterministic **test parent** that owns the protocol stub and starts the native TUI with the same directional-pipe topology as production. The TUI never starts that stub itself. + ## Release model -GitHub Actions is an automation surface rather than the authority for repository correctness. Ordinary PR/main CI is deliberately lean: one Node 24 core job followed by one Linux TUI job. `release/**` adds real Windows ConPTY and macOS PTY/CJK/resize gates. Only `v*` tags run the full platform packaging, clean-install, provenance, checksum and publication matrix. +Ordinary CI runs the Node/DSH core gate followed by a Linux native-TUI gate. Release-candidate validation additionally runs macOS PTY and Windows ConPTY/CJK gates. Release tags build platform-specific tarballs, clean-install them, verify standard plugin activation and publish checksums/provenance. -The release workflow builds platform-specific installable tarballs from the frozen npm graph, builds the pinned TUI and IPC bridge, clean-installs each artifact, runs `dshx doctor`, exercises Linux/macOS PTY and Windows ConPTY real-TUI gates, verifies cross-platform provenance, and publishes SHA-256 checksums for both tarballs and provenance sidecars. Release candidates containing `-` in the tag are published as prereleases. +A release artifact contains the DSHX Cordis rows/projection code and one matching `dshx-tui` native binary. It does not contain a bridge executable or a private DSH runtime. -The publishable `npm-shrinkwrap.json` inside each artifact is derived from the reviewed source `package-lock.json`; packaging does not resolve a second dependency graph. Release sidecars record the source-lock SHA-256 plus the pinned Codex and DSH commits. +Manual Windows Terminal acceptance remains required for real IME composition/cancel behavior and side-by-side visual parity; automated ConPTY can validate Chinese text and resize but cannot fully emulate an IME. -## Design references +See: - `docs/ARCHITECTURE.md` - `docs/RUNTIME-INTEGRATION.md` - `docs/DSH-CAPABILITY-MATRIX.md` -- `docs/ROADMAP.md` - `docs/UX-PARITY.md` - `docs/RELEASE-READINESS.md` -- `SECURITY.md` ## License -Apache-2.0 for project-owned code. Synchronized upstream code keeps its applicable upstream notices and license requirements. +Apache-2.0 for project-owned code. Synchronized upstream code retains its applicable upstream notices and license requirements. diff --git a/SECURITY.md b/SECURITY.md index 7024e2ad..22fea5cc 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -2,59 +2,66 @@ ## Scope -Security-sensitive areas include command execution, filesystem mutation, sandbox policy, approval translation, credential/model configuration, session persistence and local presentation transports. +Security-sensitive areas include command execution, filesystem mutation, sandbox/approval translation, credential/model configuration, session persistence and the local presentation transport. ## Core invariant -The TUI is presentation. DeepSeek Harness owns policy enforcement. The adapter must never silently turn a denied or approval-required DSH operation into an allowed operation. +The TUI is presentation. **DeepSeek Harness owns policy enforcement.** DSHX must never turn a denied, approval-required or unavailable DSH operation into an allowed local operation. -When a DSH permission concept cannot be represented faithfully by the current Codex UI/protocol, fail closed and surface the incompatibility to the user. +When a DSH permission/capability cannot be represented faithfully by the pinned Codex UI/protocol, DSHX fails closed or hides that surface. + +## Runtime ownership + +Production has one Harness runtime: the user's installed `dsh --profile tui` process. DSHX packages must not install or boot a second DSH runtime. The presentation adapter operates inside the already-mounted Context and delegates stateful behavior to public DSH services. + +The TUI child must never spawn a DSH/backend child or fall back to Codex Agent/runtime ownership. ## Production transport -DSHX does not expose its production presentation protocol on a TCP listener. The product topology is: +The production protocol is never exposed on a listening endpoint: ```text -pinned Codex TUI - ↕ WebSocket framing over private local Unix-domain socket -packaged dshx-ipc-bridge - ↕ JSONL over child stdio -DSHX presentation adapter - ↕ official public APIs/events -DeepSeek Harness +official DSH parent + ⇅ anonymous directional child-process pipes +pinned Codex TUI child ``` -The pinned TUI explicitly rejects TCP WebSocket endpoints in DSHX mode. +Child descriptors are arranged so protocol bytes and terminal input stay separate: protocol input arrives on child fd0, original terminal stdin is preserved as fd3 and restored before terminal initialization, and protocol output leaves on fd4. + +Consequences: -On Unix, the rendezvous directory is a fresh random directory below the system temporary directory and both DSHX and pinned `codex_uds` enforce owner-only `0700` directory permissions. +- no TCP/WebSocket listener; +- no Unix-domain socket; +- no rendezvous path or bearer token; +- no IPC bridge executable; +- no reconnect/attach surface; +- transport lifetime is bounded by the parent/child process relationship. -On Windows, pinned `codex_uds` cannot apply Unix permission bits, so DSHX deliberately does **not** trust an arbitrary/shared `%TEMP%` as the rendezvous root. The random socket directory is created below the current user's DSHX presentation home (`~/.dshx/codex-tui/i/` by default), inheriting the user's profile ACL. A custom `DSHX_TUI_HOME` is rejected if it resolves outside the current Windows user profile, including a different drive or a shared temporary directory, so the development override cannot weaken the production ACL boundary. The Windows suffix is deliberately short, and DSHX rejects an AF_UNIX pathname at or above the fixed 108-byte `sun_path` capacity before launching the bridge; the error instructs the user to select a shorter `DSHX_TUI_HOME` under the user profile. Path length is measured in UTF-8 bytes so non-ASCII profile paths fail predictably rather than at bind time. +On Unix the native thin fork clears inherited nonblocking flags before file-backed protocol reads/writes. On Windows it restores both CRT stdin and the Win32 standard input handle before crossterm uses the console. -Startup is transactional. Socket-directory creation/path validation, official DSH boot, bridge readiness, and presentation-Adapter construction are one startup transaction. If any stage fails, DSHX closes readline state, terminates the bridge with bounded escalation, disposes the official DSH runtime when one exists, and removes the private rendezvous directory. Cleanup failures are diagnostic-only during failed startup: they must never replace the original startup error reported to the user. +## Failure and shutdown behavior -Normal shutdown is also one idempotent transaction. Concurrent `close()` callers await the same cleanup promise; adapter shutdown, bridge termination, DSH disposal and rendezvous removal each still run after an earlier cleanup failure. The first failure remains the reported root cause and later cleanup failures are diagnostic-only. Rendezvous cleanup therefore does not depend on successful adapter or DSH disposal. +- Loader composition must settle before the native TUI is started. +- A missing packaged TUI or missing protocol descriptor is a startup failure, not a fallback to Codex core. +- Protocol parse/dispatch failures stay on the protocol/error channels and cannot contaminate terminal protocol output. +- TUI exit requests official DSH `appExit`; the DSH launcher/root Fiber remains teardown authority. +- Presentation disposal closes the adapter and terminates a still-running child without inventing another runtime lifecycle. -The isolated DSHX presentation home is never the user's ordinary `CODEX_HOME`. +## Capability boundary + +Regression coverage must ensure: + +- approval cancellation/rejection is fail-closed; +- shell/filesystem execution goes through DSH tools and sandbox policy; +- Ctrl+C/interrupt delegates to DSH Agent/subagent authority; +- resume preserves DSH-owned session/model state; +- DSH credentials/profile documents are not rewritten by DSHX; +- malformed/unknown protocol messages cannot gain capability; +- no production network listener/bridge/local-server path reappears; +- no production DSH dependency or private composition reappears; +- the TUI cannot start a backend runtime child; +- unsupported Codex runtime commands remain hidden or explicit failures. ## Reporting Please report security issues privately to the repository owner rather than opening a public issue with exploit details. - -## Release requirements - -A production release must include regression coverage for: - -- approval cancellation and rejection; -- shell/filesystem permission escalation; -- interrupted turns; -- session resume without privilege drift; -- model/provider configuration preservation; -- user profile/home DSH patch files remaining unmodified by DSHX; -- malformed/unknown protocol events; -- private local-IPC path creation and Windows AF_UNIX UTF-8 path limits; -- custom Windows presentation homes being rejected outside the current user profile ACL boundary; -- transactional startup rollback for socket creation, DSH boot, bridge readiness and Adapter-construction failures; -- startup cleanup failures preserving the original failure as the reported root cause; -- concurrent/idempotent shutdown and first-error preservation across adapter/bridge/DSH/rendezvous cleanup failures; -- no production TCP listener or Codex-core fallback; -- transport disconnect/reconnect behavior where applicable. diff --git a/bin/dshx-stub-local.mjs b/bin/dshx-stub-local.mjs deleted file mode 100644 index 6af6a2bb..00000000 --- a/bin/dshx-stub-local.mjs +++ /dev/null @@ -1,70 +0,0 @@ -#!/usr/bin/env node -import fs from 'node:fs'; -import { startDshxStdioTransport } from '../src/dsh/stdio-transport.mjs'; -import { ProtocolStub, normalizeDispatchResult } from '../devtools/protocol-poc.mjs'; - -const delayMs = Number(process.env.DSHX_STUB_EVENT_DELAY_MS || 18); -const traceFile = process.env.DSHX_STUB_TRACE_FILE; -const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms)); - -function trace(record) { - if (!traceFile) return; - fs.appendFileSync(traceFile, `${JSON.stringify({ at: Date.now(), ...record })}\n`, 'utf8'); -} - -class LocalStubAdapter { - constructor({ send, cwd }) { - this.send = send; - this.stub = new ProtocolStub({ cwd }); - } - - async handle(message) { - if (message?.id === undefined) { - trace({ direction: 'in', kind: 'notification', method: message?.method ?? null }); - return null; - } - trace({ direction: 'in', kind: 'request', id: message.id, method: message?.method ?? null }); - const { response, events } = normalizeDispatchResult(this.stub, message); - return { - response, - afterResponse: async () => { - trace({ - direction: 'out', - kind: response?.error ? 'error' : 'response', - id: response?.id ?? null, - method: message?.method ?? null, - error: response?.error?.message ?? null - }); - for (const event of events) { - const threadId = event?.params?.threadId ?? event?.params?.thread?.id; - const turnId = event?.params?.turnId ?? event?.params?.turn?.id; - const belongsToActiveTurn = typeof threadId === 'string' - && typeof turnId === 'string' - && event.method !== 'turn/completed'; - if (belongsToActiveTurn && !this.stub.isTurnActive(threadId, turnId)) { - trace({ direction: 'drop', method: event.method, threadId, turnId, reason: 'inactive-before-delay' }); - break; - } - if (delayMs > 0) await sleep(delayMs); - if (belongsToActiveTurn && !this.stub.isTurnActive(threadId, turnId)) { - trace({ direction: 'drop', method: event.method, threadId, turnId, reason: 'inactive-after-delay' }); - break; - } - this.send(event); - trace({ direction: 'out', kind: 'notification', method: event.method, threadId: threadId ?? null, turnId: turnId ?? null }); - if (event.method === 'turn/completed' && typeof threadId === 'string' && typeof turnId === 'string') { - this.stub.completeTurn(threadId, turnId); - } - } - } - }; - } - - async close() {} -} - -startDshxStdioTransport({ - ctx: { get: () => undefined }, - Adapter: LocalStubAdapter, - diagnostics: (message) => process.stderr.write(`[dshx-stdio-stub] ${message}\n`) -}); diff --git a/devtools/dshx-stub-server.mjs b/devtools/dshx-stub-server.mjs deleted file mode 100644 index 1870e9f1..00000000 --- a/devtools/dshx-stub-server.mjs +++ /dev/null @@ -1,21 +0,0 @@ -#!/usr/bin/env node -import { startProtocolStubServer } from './stub-server.mjs'; - -const token = process.env.DSHX_STUB_TOKEN || undefined; -const server = await startProtocolStubServer({ - token, - log: (message) => process.stderr.write(`[dshx-stub] ${message}\n`) -}); - -process.stdout.write(`${server.url}\n`); - -async function shutdown() { - try { - await server.close(); - } finally { - process.exit(0); - } -} - -process.on('SIGINT', shutdown); -process.on('SIGTERM', shutdown); diff --git a/devtools/stub-server.mjs b/devtools/stub-server.mjs deleted file mode 100644 index 20231389..00000000 --- a/devtools/stub-server.mjs +++ /dev/null @@ -1,127 +0,0 @@ -import crypto from 'node:crypto'; -import { WebSocketServer } from 'ws'; -import { ProtocolStub, normalizeDispatchResult } from './protocol-poc.mjs'; - -const DEFAULT_HOST = '127.0.0.1'; -const DEFAULT_EVENT_DELAY_MS = 18; - -function sleep(ms) { - return new Promise((resolve) => setTimeout(resolve, ms)); -} - -function sendJson(socket, message) { - if (socket.readyState === 1) socket.send(JSON.stringify(message)); -} - -function tokenMatches(header, token) { - if (!token) return true; - const left = Buffer.from(typeof header === 'string' ? header : '', 'utf8'); - const right = Buffer.from(`Bearer ${token}`, 'utf8'); - return left.length === right.length && crypto.timingSafeEqual(left, right); -} - -async function sendEvents(socket, events, delayMs, stub) { - for (const event of events) { - const threadId = event?.params?.threadId; - const turnId = event?.params?.turnId ?? event?.params?.turn?.id; - const belongsToActiveTurn = - typeof threadId === 'string' && - typeof turnId === 'string' && - event.method !== 'turn/completed'; - - if (belongsToActiveTurn && !stub.isTurnActive(threadId, turnId)) break; - if (delayMs > 0) await sleep(delayMs); - if (belongsToActiveTurn && !stub.isTurnActive(threadId, turnId)) break; - - sendJson(socket, event); - if ( - event.method === 'turn/completed' && - typeof threadId === 'string' && - typeof turnId === 'string' - ) { - stub.completeTurn(threadId, turnId); - } - } -} - -export async function startProtocolStubServer({ - host = DEFAULT_HOST, - port = 0, - cwd = process.cwd(), - eventDelayMs = DEFAULT_EVENT_DELAY_MS, - token, - log = () => {} -} = {}) { - const stub = new ProtocolStub({ cwd }); - const server = new WebSocketServer({ - host, - port, - verifyClient: token - ? (info, done) => done(tokenMatches(info.req.headers.authorization, token), 401, 'Unauthorized') - : undefined - }); - - server.on('connection', (socket, request) => { - log(`client connected from ${request.socket.remoteAddress ?? 'unknown'}`); - - socket.on('message', (raw) => { - let message; - try { - message = JSON.parse(raw.toString('utf8')); - } catch (error) { - sendJson(socket, { - id: null, - error: { - code: -32700, - message: `Parse error: ${error instanceof Error ? error.message : error}` - } - }); - return; - } - - // Notifications intentionally have no id and receive no response. - if (message?.id === undefined) { - log(`notification ${message?.method ?? ''}`); - return; - } - - log(`request ${message.method} id=${String(message.id)}`); - const { response, events } = normalizeDispatchResult(stub, message); - sendJson(socket, response); - if (events.length > 0) void sendEvents(socket, events, eventDelayMs, stub); - }); - - socket.on('error', (error) => log(`socket error: ${error.message}`)); - }); - - await new Promise((resolve, reject) => { - if (server.address()) return resolve(); - server.once('listening', resolve); - server.once('error', reject); - }); - - const address = server.address(); - if (!address || typeof address === 'string') { - throw new Error('Protocol stub server did not bind a TCP address'); - } - - let closePromise; - const close = () => { - if (closePromise) return closePromise; - closePromise = new Promise((resolve, reject) => { - // WebSocketServer.close() waits for connected clients. Stub shutdown owns - // those test/dev clients so callers cannot deadlock by closing the server first. - for (const client of server.clients) client.terminate(); - server.close((error) => (error ? reject(error) : resolve())); - }); - return closePromise; - }; - - return { - host, - port: address.port, - url: `ws://${host}:${address.port}`, - token, - close - }; -} diff --git a/devtools/tui-stub-parent.mjs b/devtools/tui-stub-parent.mjs new file mode 100644 index 00000000..d6b246db --- /dev/null +++ b/devtools/tui-stub-parent.mjs @@ -0,0 +1,117 @@ +#!/usr/bin/env node +/** Deterministic presentation-only parent for PTY/ConPTY tests. + * + * This intentionally mirrors the production process ownership: the parent owns + * the protocol adapter and launches only the native TUI child. Child fd0 is the + * parent->TUI protocol pipe, fd3 preserves the terminal input handle, and fd4 is + * the TUI->parent protocol pipe. No listener, socket, bridge, or backend child is + * created by the TUI. + */ +import fs from 'node:fs'; +import path from 'node:path'; +import process from 'node:process'; +import { spawn } from 'node:child_process'; +import { fileURLToPath } from 'node:url'; +import { startDshxStdioTransport } from '../src/dsh/stdio-transport.mjs'; +import { ProtocolStub, normalizeDispatchResult } from './protocol-poc.mjs'; + +const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..'); +const delayMs = Number(process.env.DSHX_STUB_EVENT_DELAY_MS || 18); +const traceFile = process.env.DSHX_STUB_TRACE_FILE; +const binary = process.env.DSHX_TUI_BIN || path.join(ROOT, 'dist', 'bin', process.platform === 'win32' ? 'dshx-tui.exe' : 'dshx-tui'); +const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms)); + +function trace(record) { + if (!traceFile) return; + fs.appendFileSync(traceFile, `${JSON.stringify({ at: Date.now(), ...record })}\n`, 'utf8'); +} + +class LocalStubAdapter { + constructor({ send, cwd }) { + this.send = send; + this.stub = new ProtocolStub({ cwd }); + } + + async handle(message) { + if (message?.id === undefined) { + trace({ direction: 'in', kind: 'notification', method: message?.method ?? null }); + return null; + } + trace({ direction: 'in', kind: 'request', id: message.id, method: message?.method ?? null }); + const { response, events } = normalizeDispatchResult(this.stub, message); + return { + response, + afterResponse: async () => { + trace({ + direction: 'out', + kind: response?.error ? 'error' : 'response', + id: response?.id ?? null, + method: message?.method ?? null, + error: response?.error?.message ?? null + }); + for (const event of events) { + const threadId = event?.params?.threadId ?? event?.params?.thread?.id; + const turnId = event?.params?.turnId ?? event?.params?.turn?.id; + const belongsToActiveTurn = typeof threadId === 'string' + && typeof turnId === 'string' + && event.method !== 'turn/completed'; + if (belongsToActiveTurn && !this.stub.isTurnActive(threadId, turnId)) break; + if (delayMs > 0) await sleep(delayMs); + if (belongsToActiveTurn && !this.stub.isTurnActive(threadId, turnId)) break; + this.send(event); + trace({ direction: 'out', kind: 'notification', method: event.method, threadId: threadId ?? null, turnId: turnId ?? null }); + if (event.method === 'turn/completed' && typeof threadId === 'string' && typeof turnId === 'string') { + this.stub.completeTurn(threadId, turnId); + } + } + } + }; + } + + async close() {} +} + +if (!fs.existsSync(binary)) throw new Error(`DSHX TUI binary not found: ${binary}`); +const child = spawn(binary, process.argv.slice(2), { + cwd: process.cwd(), + env: { + ...process.env, + DSHX_APP_SERVER_INPUT_FD: '0', + DSHX_TERMINAL_INPUT_FD: '3', + DSHX_APP_SERVER_OUTPUT_FD: '4' + }, + stdio: ['pipe', 'inherit', 'inherit', 0, 'pipe'], + windowsHide: false +}); +const protocolOutput = child.stdio?.[4]; +if (!child.stdin || !protocolOutput) throw new Error('directional TUI protocol pipes were not created'); + +const transport = startDshxStdioTransport({ + ctx: { get: () => undefined }, + Adapter: LocalStubAdapter, + cwd: process.cwd(), + input: protocolOutput, + output: child.stdin, + diagnostics: (message) => process.env.DSHX_DEBUG === '1' && process.stderr.write(`[dshx-stub-parent] ${message}\n`) +}); + +let closing = false; +async function close() { + if (closing) return; + closing = true; + try { await transport.close(); } catch {} + if (child.exitCode == null && child.signalCode == null) { + try { child.kill('SIGTERM'); } catch {} + } +} + +child.once('error', (error) => { + process.stderr.write(`[dshx-stub-parent] native TUI spawn failed: ${error.message}\n`); + process.exitCode = 1; +}); +child.once('exit', (code, signal) => { + void transport.close().finally(() => { + process.exitCode = typeof code === 'number' ? code : (signal ? 1 : 0); + }); +}); +process.once('SIGTERM', () => { void close(); }); diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md index dcdf5a25..ddc4810a 100644 --- a/docs/ARCHITECTURE.md +++ b/docs/ARCHITECTURE.md @@ -2,120 +2,112 @@ ## Objective -DSHX is a terminal frontend for official DeepSeek Harness. Its purpose is to preserve the pinned Codex terminal interaction model while projecting DSH public runtime state into that UI. +DSHX is a standard terminal presentation bundle for **official DeepSeek Harness**. It preserves the pinned Codex TUI interaction model while projecting DSH public runtime state into that UI. -It is **not** a fork of DeepSeek Harness and must not grow into an agent framework. +It is not a DeepSeek Harness fork and must not grow into an agent framework. -## Normative ownership boundary +## Ownership | Concern | Owner | |---|---| -| Terminal layout / composer / keyboard / overlays | DSHX / Codex TUI thin fork | -| UX parity and branding | DSHX | -| `dshx` launcher / packaging | DSHX | -| Public API/event → TUI protocol projection | DSHX thin adapter | -| Session persistence | DeepSeek Harness upstream | -| Agent loop | DeepSeek Harness upstream | -| Model routing | DeepSeek Harness upstream | -| Tool registry and execution | DeepSeek Harness upstream | -| Sandbox and approval policy | DeepSeek Harness upstream | -| Skills / subagents / plugins / jobs | DeepSeek Harness upstream | +| Terminal layout, composer, keyboard, overlays | pinned Codex TUI / DSHX thin fork | +| UX parity and DSHX branding | DSHX | +| Standard bundle rows and `dshx` convenience launcher | DSHX | +| DSH public API/event → TUI protocol projection | DSHX | +| Agent loop and control | DeepSeek Harness | +| Sessions and persistence | DeepSeek Harness | +| Models, providers and credentials | DeepSeek Harness | +| Tools and shell execution | DeepSeek Harness | +| Sandbox and approvals | DeepSeek Harness | +| Skills, subagents, plugins and jobs | DeepSeek Harness | -The adapter may translate and cache disposable presentation state. It must never become a second source of truth for session history, policy, model configuration, tools or agent state. +The adapter may keep disposable presentation correlation state. It must never become a second source of truth for history, policy, model configuration, tools or Agent state. -If a DSH capability is unavailable or cannot be represented safely, DSHX must disable, hide or explicitly mark the corresponding UI unsupported. It must **not** implement the missing runtime capability. - -## Target topology +## Process topology ```text -┌─────────────────────────────────────┐ -│ Codex TUI thin fork │ project-owned presentation -│ │ -│ welcome / composer / cells / diff │ -│ slash commands / pickers / footer │ -└──────────────────┬──────────────────┘ - │ - app-server-compatible view - │ -┌──────────────────▼──────────────────┐ -│ dsh-codex thin adapter │ project-owned translation -│ │ -│ Thread ↔ Session id/projection │ -│ Turn ↔ DSH turn lifecycle │ -│ Item ↔ exposed DSH events │ -└──────────────────┬──────────────────┘ -═══════════════════╪════════════════════ ownership boundary - │ official public APIs/events -┌──────────────────▼──────────────────┐ -│ DeepSeek Harness │ upstream-owned runtime -│ │ -│ agents / sessions / llm / tools │ -│ sandbox / approvals / skills / ... │ -└─────────────────────────────────────┘ +dshx + │ ensure bundle in profile + ▼ +user-installed dsh --profile tui + │ sole DSH runtime / Loader owner + ├─ dshx-startup + └─ dshx-presentation + │ spawn native TUI only + ▼ + pinned Codex TUI + ⇅ directional anonymous child pipes + src/tui-protocol + ⇅ + DSH public services/events ``` -## Protocol mapping - -Mappings are UI projections, not replacement implementations. The Codex -dialect is confined to `src/tui-protocol/` (wire-format dictionary plus the -app-server method router); domain modules under `src/dsh/` speak DSH -vocabulary only, and the ownership guard enforces that placement. +There is no production TCP listener, WebSocket server, Unix-domain socket, IPC bridge or second DSH process. -| Codex concept | DSH source | -|---|---| -| Thread | DSH Session identity and exposed metadata | -| `thread/start` | official DSH Session/Agent creation API | -| `thread/resume` | official DSH Session inspection/resume API | -| `thread/list` | official DSH session catalog | -| Turn | official DSH user-interaction lifecycle | -| agent-message delta | exposed DSH agent/model streaming event | -| command execution item | exposed DSH tool/shell event | -| file-change item | exposed DSH filesystem/editor event | -| approval request | official DSH approval request | -| user-input request | official DSH ask-user request | -| plan update | exposed DSH plan/todo state | -| turn interrupt | official DSH cancellation/control API | - -Where no official mapping exists, the adapter reports unsupported instead of synthesizing a shadow capability. +## Directional pipe contract -## Session invariants +Node's child-process pipes are directional, not a generic duplex fd. The presentation runner therefore launches the TUI with: -1. DSH session IDs and persisted events are authoritative. -2. DSHX does not keep a parallel conversation database. -3. Resume obtains model/provider/reasoning state from DSH through supported interfaces; the TUI does not invent replacements. -4. TUI caches are disposable and reconstructable. -5. DSHX never changes permission semantics to make a Codex widget easier to reuse. +```js +stdio: ['pipe', 'inherit', 'inherit', 0, 'pipe'] +``` -## Codex upstream strategy +The child sees: -The TUI is pinned to a known `openai/codex` commit. Upstream changes are integrated as explicit sync commits. Project-specific changes should live behind narrow extension points so rendering/input code remains close to upstream. +| fd | Meaning | +|---:|---| +| 0 | protocol input, DSH parent → TUI | +| 1 | terminal stdout | +| 2 | terminal stderr | +| 3 | original terminal stdin | +| 4 | protocol output, TUI → DSH parent | -Desired long-term diff: +Before terminal initialization, the thin fork duplicates protocol fd 0, restores fd 3 onto ordinary stdin, and then gives the saved protocol input plus fd 4 to the app-server-compatible client. On Unix it clears inherited `O_NONBLOCK` on protocol descriptors before wrapping them as file-backed Tokio I/O; on Windows it restores both CRT stdin and the Win32 standard input handle. -```text -Codex TUI upstream 95%+ unchanged -DSH UI adapter project-owned and thin -Branding minimal patch -DSH-specific UI isolated extension points only -``` +The protocol bytes are newline-delimited JSON. Transport code carries no runtime state and has no network address. -## Runtime transport +## Standard plugin composition -M0 may use Codex remote/app-server WebSocket mode strictly as a development protocol harness. It is not an accepted production dependency. +`package.json` declares: -Production `dshx` must hide transport/runtime orchestration from the user and use a local supported integration path (for example in-process, stdio or a production-grade local socket) consistent with the pinned TUI architecture. +```json +{"dsh":{"bundle":{"patch":"./cordis.patch.yml"}}} +``` -## Launcher contract +The patch adds only DSHX-owned startup/presentation rows. `dshx-startup` consumes the official `cmdlineArgs` service and publishes immutable presentation launch facts. `dshx-presentation` consumes that service, waits for Loader settlement, starts the native TUI and binds its pipes directly to the live Context. -Production 1.0 must support: +The user's `dsh --profile tui` process remains the application host. `dshx` may install the bundle idempotently through `dsh plugin --profile tui add`, but it does not mount a private composition. -```bash -cd -dshx -``` +## Protocol boundary -The user must not need to invoke `codex --remote`, a bridge script, package-manager commands or DSH profile plumbing for normal startup. +Codex wire vocabulary is confined to `src/tui-protocol/` and protocol plumbing. Domain modules under `src/dsh/` speak DSH concepts and public services. -## Security model +Typical projections include: -The TUI renders approval decisions; DSH enforces them. Translation must never silently upgrade privileges. If the current Codex UI/protocol cannot faithfully represent a DSH permission request, DSHX fails closed and surfaces an explicit incompatibility. +| TUI concept | DSH authority | +|---|---| +| Thread | Session identity/metadata | +| thread start/resume/list | Agent + Session public services | +| Turn | DSH turn lifecycle | +| assistant/reasoning deltas | DSH Session events | +| command/file cells | DSH tool/result events | +| approvals | DSH approval service | +| ask-user | DSH user-question service | +| plan | DSH plan/todo state | +| interrupt/steer | DSH Agent/subagent control | + +Where no faithful mapping exists, DSHX reports unsupported or hides the surface rather than synthesizing a shadow capability. + +## Session and security invariants + +1. DSH session ids and persisted events are authoritative. +2. DSHX has no parallel conversation database. +3. Resume restores DSH-owned model/session state. +4. Presentation caches are disposable. +5. DSHX never weakens sandbox or approval semantics for UI compatibility. +6. Missing required DSH services fail closed. +7. The TUI child never starts a backend/runtime child of its own. + +## Upstream strategy + +The TUI is pinned to a known `openai/codex` commit. Project divergence is maintained as an ordered, build-tested patch queue. Rendering/input code should remain as close to upstream as practical; DSH-specific behavior belongs at the protocol and narrow startup seams. diff --git a/docs/DSH-CAPABILITY-MATRIX.md b/docs/DSH-CAPABILITY-MATRIX.md index 280a15d5..72bbbd7f 100644 --- a/docs/DSH-CAPABILITY-MATRIX.md +++ b/docs/DSH-CAPABILITY-MATRIX.md @@ -1,81 +1,62 @@ # DSH public capability matrix -This document is a guardrail for the DSHX adapter. Every Codex-facing behavior must map to an **official DeepSeek Harness public API/event**. If no suitable public capability exists at the supported DSH release, DSHX marks the surface unsupported or degrades the presentation; it does not implement a replacement runtime. +Every Codex-facing runtime behavior must map to an **official DeepSeek Harness public API/event**. If no faithful public capability exists in the host, DSHX hides/degrades the UI or fails closed; it does not implement a replacement runtime. -Supported DSH package line: `0.1.0-rc.8`. -Pinned DSH source reference: `141eb6fef83422698aef7a981029e843e8161534`. +The current CI-tested closure is DSH `0.1.0-rc.8` at the repository's pinned DSH source reference. Production is host-version agnostic above the declared compatibility floor and resolves services from the user's installation. -## Core interaction mapping +## Core mapping -| Codex/TUI need | Official DSH source | DSHX responsibility | Status | +| Codex/TUI need | DSH authority | DSHX responsibility | Status | |---|---|---|---| -| Start a conversation | `ctx.agents.create(...)` | Project result into `thread/start` / Thread UI | Implemented + tested | -| Resume a conversation | `ctx.agents.resume({ resumeSessionId })` | Project resumed Session into Thread/resume UI | Implemented + tested | -| Live agent lookup | `ctx.agents.get(id)`, `list()`, `roots()` | Presentation/navigation only | Implemented + tested | -| User follow-up | `Agent.followup(message)` | Convert composer input to official DSH user content | Implemented + tested | -| Steering while running | `Agent.steer(message)` | Forward active-turn steering from composer | Implemented + tested | -| Cancel / Ctrl+C | `Agent.cancel(cause, options?)` | Map TUI interrupt intent; never invent policy | Implemented + tested | -| Wait for quiescence | `Agent.whenIdle()` | Drive UI busy/idle convergence | Implemented + tested | -| Agent/subagent status | `agent/status`, `agent/created`, `agent/disposed` | Render thread active/idle/not-loaded state | Implemented + tested | -| Durable transcript source | `Session` append-only event log | Project only; never create a second transcript DB | Implemented + guarded | -| Session event feed | `session/event` | Translate exposed event vocabulary to TUI items | Implemented + tested | -| User message | `user/message` | Render transcript/input history | Implemented + tested | -| Token/chunk streaming | `assistant/chunk` | Convert visible/reasoning chunks to Codex deltas | Implemented + tested | -| Final assistant message | `assistant/message` | Finalize message/reasoning items | Implemented + tested | -| Tool invocation/result | `tool/call`, `tool/result` | Render matching Codex tool/shell/file/diff cells; never execute locally | Implemented + tested | -| File contextual diff | producing tool result/meta | Present diff/card only | Implemented where DSH emits faithful metadata | -| Plan / todo | `todo/write`, `planMode` | Project plan list/mode into Codex presentation | Implemented + tested | -| Provider/model catalog | `ctx.llm.listProviders()`, `listModels()`, `resolveModelInfo()` | Populate `/model` using public registry | Implemented + tested | -| Model/reasoning validation | `ctx.llm.resolveCallConfig()` + official model-selection service | Validate/apply picker changes through DSH | Implemented + tested | -| Persisted route metadata | `request/header` | Restore model/reasoning presentation on resume | Implemented + tested | -| Context/token usage | `request/context` + persisted session usage | Feed footer/usage projection when exposed | Implemented + tested | -| Session listing/inspection | `ctx.sessionPersistence.list()`, `inspect()` | Resume picker/history hydration | Implemented + tested | -| Session persistence/crash repair | `ctx.sessionPersistence` implementations | **None** — DSH owns durability and repair | Upstream-owned | -| Paginated history | persisted Session events | Convert immutable events into Codex turn/item pages | Implemented + tested | -| Permission preset list/current | `ctx.permissionPresets` | Populate Codex-style permissions selector | Implemented + tested | -| Permission preset switch | `ctx.permissionPresets.set(...)` | Delegate selected value; do not write policy events ourselves | Implemented + tested | -| Effective sandbox/approval state | DSH sandbox/approval services | Present DSH enforcement without inventing Codex semantics | Implemented + tested | -| Interactive approval request | scoped `approval/request` waterfall | Present only faithful one-shot decisions; fail closed otherwise | Implemented + tested | -| Ask user | `ctx.userQuestions.registerProvider(...)` | Present Codex request-user-input overlay and return DSH answer | Implemented for faithful single-select/free-text cases | -| Skills discovery | official DSH skills registry/provider surface | Adapt current registry snapshot to `skills/list` | Implemented + tested | -| Session fork | Host API `sessions.fork` | Select DSH event boundary and delegate durable fork | Implemented + ownership guarded | -| Manual compaction | official DSH `/compact` command | Invoke through DSH command service; render compaction events | Implemented + ownership guarded | -| Shell execution | official DSH `tools.execute` with owning Agent | Map Codex shell request/result to DSH tool execution | Implemented + ownership guarded | -| Workspace diff command | official DSH `tools.execute` with owning Agent | Use DSH execution, then present result | Implemented + ownership guarded | -| Subagent lifecycle | official `subagents` service + agent lifecycle events | Present child threads/status; delegate interrupt authority | Implemented + fail-closed authority tests | - -## Permission semantic notes - -DSH sandbox mode governs the semantics exposed by DSH; DSHX must not invent network/process guarantees that are absent from that public contract. Where Codex's legacy sandbox shape is broader than DSH's vocabulary, DSHX presents an external sandbox plus the actual DSH permission preset rather than falsely claiming Codex-native enforcement. - -DSH approval outcomes are closed and fail-closed. Only an explicit DSH grant is projected as approval. Codex's session-wide approval actions are hidden when no faithful DSH equivalent exists. Unknown plugin-tool approvals are not guessed into shell/file semantics; unclaimed requests remain unavailable/denied according to DSH policy. - -## Session durability and restart semantics - -DSHX keeps no durable transcript. Resume calls `ctx.agents.resume(...)`, history is read from DSH persistence, and the latest persisted `request/header` wins over the current machine default when restoring model/reasoning presentation. DSHX does not repair, replay or rewrite Session state after a crash. - -## Known deliberate capability gaps - -These are not shadow-implemented: - -- **DSH multi-select user questions:** the pinned Codex request-user-input presentation does not provide a faithful multi-select contract in the current adapter, so DSHX rejects that request instead of silently changing its semantics. -- **Codex-specific review/apps/plugins/hooks/memory/personality surfaces:** hidden where the supported DSH release has no faithful public equivalent wired into DSHX. -- **Jobs/workflows UI:** DSH may own these capabilities, but a stable terminal presentation contract has not yet been adopted; this is a presentation-only future surface. -- **Ephemeral Codex fork / goal-continuation semantics:** not mapped onto durable DSH Session forks. -- **Codex service-tier and reasoning-summary/personality thread settings:** rejected because there is no equivalent public DSH setting to project. - -A visible Codex command is kept only when its semantics are backed by DSH or are purely local TUI presentation. Unsupported runtime-owned commands are hidden rather than routed to Codex core. - -## Capability fallback rule +| Start conversation | `ctx.agents.create(...)` | project result into Thread UI | implemented/tested | +| Resume | `ctx.agents.resume(...)` | hydrate Codex Thread from DSH Session | implemented/tested | +| Session list/history | DSH persistence/query services | resume picker/history pages | implemented/tested | +| Follow-up | `Agent.followup(...)` | convert composer input | implemented/tested | +| Steering | `Agent.steer(...)` | forward active-turn steering | implemented/tested | +| Interrupt | Agent/subagent control | map Ctrl+C without inventing authority | implemented/tested | +| Agent status | DSH Agent lifecycle events | active/idle/not-loaded projection | implemented/tested | +| Transcript | DSH Session event log | presentation projection only | implemented/guarded | +| Assistant/reasoning stream | DSH Session events | Codex item/delta projection | implemented/tested | +| Tool execution/result | DSH ToolRuntime/events | shell/tool/file/diff presentation; never local execution | implemented/tested | +| Plan/todo | DSH plan/todo state | Codex plan projection | implemented/tested | +| Model catalog | DSH LLM registry | model picker | implemented/tested | +| Model validation/selection | DSH model-selection/resolution services | validate/apply picker changes | implemented/tested | +| Persisted route state | DSH request header | restore model/reasoning presentation | implemented/tested | +| Token/context usage | DSH request/session usage | footer projection where exposed | implemented/tested | +| Permission presets | DSH permission service | picker/list/switch projection | implemented/tested | +| Effective sandbox/approval | DSH policy services | present policy without weakening it | implemented/tested | +| Approval request | DSH approval waterfall | faithful one-shot UI only | implemented/fail-closed | +| Ask user | DSH user-question provider | Codex input overlay where semantics match | partial, explicit gaps | +| Skills | DSH skills registry | `skills/list` projection | implemented/tested | +| Fork | DSH Host/session fork API | translate presentation anchor and delegate | implemented/guarded | +| Compaction | official DSH command plane | invoke/render only | implemented/guarded | +| Shell/workspace command | DSH `tools.execute` with owning Agent | present request/result | implemented/guarded | +| Subagents | DSH subagent service + lifecycle events | child thread/status/interrupt presentation | implemented/tested | + +## Semantic rules + +- DSH sandbox/approval vocabulary is authoritative; DSHX does not claim stronger Codex-native enforcement than DSH exposes. +- Only explicit DSH grants are shown as approval. Unsupported session-wide grants remain unavailable. +- Unknown plugin-tool approvals are not guessed into shell/file semantics. +- Resume uses persisted DSH Session/request state; DSHX keeps no durable transcript or repair logic. +- Visible Codex commands are either presentation-local or backed by DSH. Unsupported runtime-owned commands are hidden instead of routed to Codex core. + +## Deliberate gaps + +- DSH multi-select user questions where the pinned Codex UI cannot represent the semantics faithfully. +- Codex-specific review/apps/plugins/hooks/memory/personality surfaces without a DSH public equivalent. +- Jobs/workflows terminal UI until a stable presentation contract is selected. +- Codex-only ephemeral fork/goal-continuation semantics that do not match durable DSH Session forks. +- Codex service-tier/reasoning-summary/personality settings without DSH equivalents. + +## Fallback rule For every UI feature: -1. Detect whether the supported DSH composition exposes a faithful public capability. -2. If yes, adapt it narrowly into the Codex TUI surface. -3. If semantics are only partially representable, show an explicit reduced/unsupported state. -4. If representing it would weaken permissions, authority or durability semantics, fail closed. -5. Never solve a missing upstream capability by adding a shadow runtime to `dsh-codex`. - -## Release evidence +1. detect a faithful DSH public capability; +2. adapt it narrowly when present; +3. show an explicit reduced/unsupported state when only partial presentation is possible; +4. fail closed if translation would weaken authority, permissions or durability; +5. never add a shadow runtime to compensate for a missing upstream seam. -This matrix describes implementation/ownership, not release-candidate pass status. The exact candidate must still satisfy `docs/RELEASE-READINESS.md`, including CI, packaged local-IPC checks and manual Windows Terminal/CJK/IME parity acceptance. +This matrix describes implementation ownership. Release evidence is tracked separately in `RELEASE-READINESS.md`, including standard bundle activation, directional-pipe native UI gates and manual Windows Terminal/CJK/IME parity. diff --git a/docs/RELEASE-READINESS.md b/docs/RELEASE-READINESS.md index 7a38a4bc..8da4ab66 100644 --- a/docs/RELEASE-READINESS.md +++ b/docs/RELEASE-READINESS.md @@ -1,64 +1,69 @@ # 1.0 release readiness -This file defines the evidence required before a DSHX release candidate may be promoted to 1.0. It intentionally distinguishes **implemented checks** from **checks that have actually passed on a release candidate**. +This document defines the evidence required before a DSHX release candidate can be promoted. A check is green only when it passes for the **exact candidate SHA/artifact**; the existence of a test is not evidence by itself. -## Rule +## Required architecture -No item becomes green because code for the check exists. A release candidate is green only when the corresponding repository gate or CI job has passed for the exact candidate commit/tag and the result is recorded. GitHub Actions is an automation surface, not the authority for release correctness: runner-independent repository scripts are preferred wherever a check does not intrinsically require a hosted platform. +A candidate is invalid regardless of test results if any of these are false: -The pinned DSH `0.1.0-rc.8` line requires Node `^22.19.0 || >=24.0.0`. DSHX 1.0 standardizes dependency freezing, CI and release artifact generation on **Node 24 LTS / npm 11** so all release evidence uses one supported toolchain. +- the package is a standard DSH bundle (`dsh.bundle.patch`); +- the user's installed `dsh --profile tui` process is the sole DSH runtime/Loader owner; +- the presentation row starts only the pinned native TUI child; +- TUI protocol I/O uses anonymous directional child-process pipes; +- no production TCP/WebSocket/UDS listener, bridge executable or Node local server exists; +- the TUI does not spawn a DSH/backend child; +- DSH owns Agent, Session, models, tools, sandbox, approvals, skills, subagents and persistence; +- Codex dialect code remains confined to the TUI protocol boundary; +- production installation does not materialize a second DSH runtime or hard-block an untested host version. ## Automation tiers -- **PR / main CI:** two Ubuntu jobs only. `Core / Node 24` runs first; `Linux TUI / pinned Codex / local IPC` runs only after Core passes. -- **RC platform gate:** `release/**` PR heads targeting `main` (or manual dispatch) run real Windows ConPTY and macOS PTY/CJK/resize validation with explicit exact-head checkout verification. -- **Release tag:** `v*` runs the full platform packaging, clean-install, provenance, checksum and publication matrix. -- **Dependency freeze:** never writes a branch from CI. Run `npm run freeze:deps` in a trusted Node 24 LTS / npm 11 environment with npm-registry access, review the generated `package-lock.json`, then commit it. CI consumes it with `npm ci`. +- **PR/main CI:** Node 24 core gate, then Linux native TUI/build/bundle/PTY gate. +- **RC platform gate:** release-head PRs or explicit dispatch run Windows ConPTY and macOS PTY/CJK/resize against an exact SHA. +- **Release tag:** `v*` builds platform tarballs, verifies standard bundle activation, clean-installs artifacts, runs native UI gates and publishes provenance/checksums. +- **Dependency freeze:** generated outside CI with Node 24/npm 11, reviewed and committed; CI consumes it with `npm ci`. ## Automated gates -| Gate | Evidence implemented in repository | Required result for 1.0 | +| Gate | Evidence | Required | |---|---|---| -| Zero-argument launch | `bin/dshx.mjs`, clean-install smoke | pass on supported release artifacts | -| Supported Node runtime | package engine matches pinned DSH (`^22.19.0 || >=24.0.0`); release/freeze baseline Node 24 LTS | pass | -| Official DSH composition | `scripts/runtime-smoke.mjs` | pass on exact candidate | -| Frozen source dependency graph | checked-in `package-lock.json`; `npm run freeze:deps` resolves it with install scripts disabled under Node 24/npm 11 | lock present, reviewed and no manifest drift | -| Exact DSH dependency closure | `scripts/verify-dsh-closure.mjs`, source lock and release shrinkwrap | pass | -| DSH ownership boundary | adapter/unit tests + `scripts/verify-ownership-boundary.mjs` | pass | -| Approval/permission fail-closed | approval/permission/subagent authority tests | pass | -| Session resume/durability projection | DSH `agents.resume`, persistence projection and resume tests; persisted model/header wins over machine default | pass | -| Local production transport | no production TCP listener; pinned TUI rejects TCP WebSocket endpoint | pass | -| Cross-platform local IPC data plane | `dshx-ipc-bridge --check` performs real private UDS + WebSocket-framing ping/pong | pass on Linux/Windows/macOS | -| Visible slash-command contract | `scripts/verify-slash-contract.mjs` classifies every pinned Codex command and asserts DSH-backed methods for every runtime-owned command left visible in DSHX | pass | -| Real pinned TUI / Linux + macOS | PTY smoke drives pinned TUI through local IPC, resizes the terminal, and roundtrips a CJK prompt | pass on both Unix release platforms | -| Real pinned TUI / Windows | ConPTY smoke drives pinned TUI through the same local-IPC topology, resizes the terminal, and roundtrips a Chinese prompt | pass | -| Automated CJK/resize sanity | Linux/macOS PTY + Windows ConPTY verify UTF-8 input/echo survives a live resize without process/session loss | pass | -| CI action supply chain | every external `uses:` ref is a current GitHub Action release pinned to a full immutable commit SHA; `test/ci-actions-pins.test.mjs` rejects mutable refs | pass | -| Packaging | platform tarball + static local-import closure check + publishable shrinkwrap derived from the frozen source graph | pass | -| Clean installation | install generated tarball then `dshx --version` + `dshx doctor` | pass on every release platform | -| Release provenance | platform sidecar records Codex pin, DSH pin and SHA-256 of the frozen source `package-lock.json` | present and consistent across artifacts | -| Release artifacts | Linux x64, Windows x64, macOS arm64, macOS x64 | all built | -| Integrity | release `SHA256SUMS` covers tarballs and provenance sidecars | published | -| Codex thin-fork invariants | patch application/build + `scripts/verify-tui-invariants.mjs` | pass | - -## Manual UX acceptance gate - -Automation can exercise PTY/ConPTY resize and Chinese text, but it cannot establish real **IME composition-state behavior**, mouse behavior, or visual parity. For the exact 1.0 release candidate, perform a side-by-side run against the pinned Codex TUI using the same Windows Terminal dimensions/theme and record pass/fail for: - -- Windows Terminal startup, visual reflow after resize, scroll and mouse behavior; -- Chinese IME composition/commit/cancel in the multiline composer; -- wide CJK glyph alignment in transcript/tool/diff cells; -- slash completion and help keyboard behavior; +| Frozen dependency graph | checked-in `package-lock.json` | no manifest drift | +| Tested DSH closure | `scripts/verify-dsh-closure.mjs` | pass | +| Ownership boundary | unit tests + `scripts/verify-ownership-boundary.mjs` | pass | +| Official profile lifecycle | `scripts/runtime-smoke.mjs` | Loader settle → directional initialize → child exit → `appExit` | +| Standard bundle delivery | `scripts/verify-bundle-install.mjs` | pack/add/dump/activate/single-runtime pass | +| Thin-fork materialization/build | build scripts + `scripts/verify-tui-invariants.mjs` | pass with pinned Codex and `cargo --locked` | +| No backend child | thin-fork guard | TUI contains no DSH/backend `Command::new` path | +| No socket/bridge production path | ownership/package guards | pass | +| Visible slash-command contract | `scripts/verify-slash-contract.mjs` | pass | +| Session/model/tool/approval delegation | unit/contract suite | pass/fail-closed | +| Linux native TUI | PTY deterministic directional-pipe test | startup, CJK prompt, resize pass | +| macOS native TUI | RC PTY test | startup, CJK prompt, resize pass | +| Windows native TUI | RC ConPTY test | startup, Chinese prompt, resize pass | +| Packaging | `scripts/package-platform.mjs` | TUI-only platform tarball, local-import closure, frozen shrinkwrap | +| Clean install | release workflow | no second `@deepseek-ai/dsh`; installed launcher/version works | +| Provenance | release sidecar | same source-lock SHA, Codex pin, DSH tested pin, transport contract | +| Integrity | `SHA256SUMS` | covers tarballs and sidecars | +| GitHub Actions pins | `test/ci-actions-pins.test.mjs` | immutable action SHAs | + +## Manual Windows Terminal / IME gate + +ConPTY can validate Unicode text and resize, but cannot prove real IME composition behavior or visual parity. For the exact Windows RC artifact, compare against the pinned Codex TUI in the same Windows Terminal dimensions/theme and record: + +- startup/reflow/scroll/mouse behavior; +- Chinese IME compose/commit/cancel in the multiline composer; +- wide CJK alignment in transcript/tool/diff cells; +- slash completion/help; - model and permission pickers; - approval and ask-user overlays; -- shell/tool streaming and collapse behavior; +- tool/shell streaming and collapse behavior; - unified diff review; -- plan/reasoning cells when DSH exposes them; -- steering and Ctrl+C interrupt during an active turn; -- resume picker and restored session/model state; +- plan/reasoning presentation when DSH exposes it; +- steering and Ctrl+C during an active DSH turn; +- resume and restored DSH session/model state; - status/footer rendering. -Before starting the manual comparison, verify and install the **exact generated Windows artifact** with: +Prepare the exact artifact with: ```powershell ./scripts/windows-rc-acceptance.ps1 ` @@ -66,23 +71,15 @@ Before starting the manual comparison, verify and install the **exact generated -ExpectedSha256 ``` -The harness verifies the artifact hash, performs an isolated global-prefix install, runs `dshx --version` and `dshx doctor`, and prints the exact installed `dshx.cmd` path to use for the Windows Terminal/IME session. Do not substitute a source checkout after this setup. - -Any difference is either fixed, documented as a deliberate product difference in `docs/UX-PARITY.md`, or blocks 1.0. +The helper verifies the artifact checksum, performs an isolated install and prints the exact launcher path to use for the manual session. Do not substitute a source checkout after this point. ## Promotion procedure -1. In a trusted Node 24 LTS / npm 11 environment with npm-registry access, run `npm run freeze:deps`; review and commit the generated `package-lock.json`, then freeze the candidate commit on `release/1.0-rc`. Codex/DSH pins must not change during validation. -2. Require the exact candidate to pass the lean `CI` workflow (`Core / Node 24` then `Linux TUI`) and the `RC Platform Gate` (Windows ConPTY + macOS PTY). Equivalent runner-independent repository gates may be used for diagnosis, but platform acceptance must execute on the named platform. -3. Create a prerelease tag (for example `v1.0.0-rc.N`) and require every release-matrix build/clean-install/TUI gate to pass. The RC tag must point at the current `release/1.0-rc` head. -4. Confirm each release sidecar identifies the same frozen source-lock SHA-256 and expected Codex/DSH pins. -5. Run `scripts/windows-rc-acceptance.ps1` against the generated Windows release artifact and its published SHA-256, then use the printed installed launcher for the manual Windows Terminal/CJK/IME side-by-side acceptance run. -6. Resolve every failed gate without weakening a DSH ownership or security boundary. -7. Re-run affected automated and manual gates after fixes. -8. Merge PR #11 only after all RC gates are green; stable `v1.0.0` must point at the current `main` head and the release ledger issues #12–#15 must be closed. - -## Current integration note - -`release/1.0-rc` is the sole release-candidate integration branch. It is based on the production local-IPC implementation from `agent/production-ipc`; the alternative direct-stdio Codex-client experiment is intentionally excluded because it requires a much larger upstream TUI/client patch and would increase DSHX maintenance ownership. - -Older stacked draft PRs remain historical engineering workstreams only. They are not release evidence. The exact `release/1.0-rc` head and its eventual `v1.0.0-rc.N` tag are the only commits whose automated/manual evidence may be used to promote 1.0. +1. Freeze/review the Node dependency graph and pin the Codex/DSH tested sources. +2. Require the exact SHA to pass Core + Linux native CI. +3. Run the exact same SHA through Windows and macOS RC platform gates. +4. Build a prerelease tag and require every release-matrix build, bundle activation, clean-install and native UI gate to pass. +5. Confirm all sidecars agree on source lock, Codex pin, DSH tested pin and transport identifier. +6. Perform the Windows Terminal/IME side-by-side gate on the generated Windows artifact. +7. Fix failures without weakening DSH ownership/security boundaries; repeat affected gates on a new exact SHA. +8. Promote only when no automated or manual blocker remains. diff --git a/docs/ROADMAP.md b/docs/ROADMAP.md index 51919370..b2a495a8 100644 --- a/docs/ROADMAP.md +++ b/docs/ROADMAP.md @@ -1,101 +1,75 @@ # Roadmap -All milestones obey one ownership rule: **DSHX maintains the TUI, launcher, transport and thin public-API adapter only. DeepSeek Harness capabilities remain upstream-owned.** +All milestones obey one rule: **DSHX owns presentation; DeepSeek Harness owns runtime capabilities.** A feature is complete only when it is delivered through official DSH services rather than copied into DSHX. -Milestone status describes implementation progress. A 1.0 release requires the independent evidence in `RELEASE-READINESS.md`. +## M0 — Protocol/TUI proof — complete -## Milestone 0 — Codex TUI protocol proof — complete +- pinned Codex TUI can run without Codex Agent ownership; +- deterministic protocol fixtures cover bootstrap/thread/turn/streaming/interrupt; +- Codex protocol vocabulary is isolated at the TUI boundary. -Goal: prove that the pinned Codex TUI can be driven without Codex's agent runtime. +Historical WebSocket/remote experiments are not production architecture. -Delivered: +## M1 — DSH public-API daily loop — complete at contract level -- pinned Codex and DSH upstream references; -- deterministic app-server-compatible development stub; -- bootstrap/thread/turn/streaming/interrupt protocol proof; -- zero-argument development launcher; -- thin-fork patches proving the Codex TUI can run with DSHX as its backend. +Implemented through DSH-owned services/events: -The historical TCP/WebSocket path is retained only as a development fixture and is excluded from the production package. +- start/resume/list/history; +- response and reasoning streaming; +- model selection; +- tool/shell/file/diff presentation; +- approvals and user questions; +- steering and Ctrl+C; +- token/context/footer projection where exposed; +- skills, fork, compaction and subagent presentation boundaries; +- fail-closed behavior for unsupported semantics. -## Milestone 1 — Official DSH public-API adapter / daily coding loop — implementation complete, RC evidence pending +Release evidence remains governed by `RELEASE-READINESS.md`. -Delivered through official DSH public APIs/events: +## M2 — Standard plugin/runtime ownership — complete at architecture level -- session start/resume/list/history projection; -- response + reasoning streaming; -- specialized shell/tool/file/diff presentation where DSH exposes faithful semantics; -- approval and ask-user presentation with DSH policy authoritative; -- steering and Ctrl+C interrupt; -- model/provider/reasoning picker backed by official DSH registry/resolution; -- context/token/footer projection where DSH exposes the data; -- skills discovery; -- fork, compaction and subagent boundaries delegated to DSH-owned services; -- fail-closed ownership tests preventing local execution/runtime duplication. +- package declares `dsh.bundle.patch`; +- official `dsh plugin --profile tui add/remove` owns installation/reconciliation; +- `dsh --profile tui` is the sole runtime and Loader owner; +- `dshx-startup` + `dshx-presentation` are ordinary Cordis rows; +- `dshx` is a thin bootstrap over the user's DSH launcher; +- no private DSH composition or production DSH dependency is shipped. -Exit gate: the exact release candidate must pass the automated daily-loop/PTY gates and real dogfooding; implementation alone does not declare the milestone release-green. +## M3 — Native transport simplification — implementation complete; platform evidence required -## Milestone 2 — Codex UX parity — thin-fork parity implemented; manual terminal acceptance pending +Final topology: -Implemented/inherited from the pinned Codex TUI: +```text +official DSH parent + └─ pinned native TUI child + ⇅ anonymous directional process pipes +``` -- welcome screen, composer and slash-command interaction; -- model and permission pickers; -- resume picker using DSH session data; -- approval and ask-user overlays; -- tool/shell/diff/plan/reasoning cells; -- steering/interrupt behavior; -- Codex-native scroll, mouse and resize behavior; -- status/footer rendering where DSH exposes data. +The production bridge, UDS/WebSocket carrier, local server and TUI-owned backend child are retired. The thin fork restores terminal stdin before crossterm initialization and uses separate inherited descriptors for protocol input/output. -Unsupported Codex runtime semantics are explicitly hidden/rejected rather than silently emulated. See `DSH-CAPABILITY-MATRIX.md`. +Exit evidence: -Exit gate still pending: side-by-side Windows Terminal + Chinese IME/CJK acceptance against the pinned Codex TUI using the exact generated release-candidate artifact. +- Linux `cargo --locked` + PTY/CJK/resize; +- macOS PTY/CJK/resize; +- Windows ConPTY/CJK plus correct CRT/Win32 stdin restoration; +- standard-bundle live initialize and teardown. -## Milestone 3 — Additional DSH capability surfaces (presentation only) — partial +## M4 — Codex UX parity — automated coverage implemented; manual IME gate required -Implemented where official seams are stable: +The pinned TUI supplies the upstream composer, slash interactions, pickers, overlays, cells, scroll/mouse/resize and footer behavior. DSHX only hides or adapts runtime semantics that DSH cannot faithfully provide. -- Skills discovery/UI feed. -- Subagent thread/status presentation and DSH-owned interruption authority. +The final 1.0 blocker here is a side-by-side Windows Terminal run with the exact generated artifact, including Chinese IME compose/commit/cancel and wide-glyph alignment. -Future presentation-only candidates: +## M5 — Packaging/release closure — in progress until exact-SHA gates are green -- Jobs/workflows UI. -- Plugin diagnostics/configuration UI where DSH exposes a stable product-facing seam. -- Additional DSH-specific commands that do not disturb Codex-compatible commands. +A final candidate must prove: -This milestone is not a blocker for the core 1.0 daily coding loop unless a listed capability is required by the final product acceptance matrix. +- TUI-only native artifact; no bridge executable; +- no second DSH runtime in a clean installation; +- official plugin activation/removal; +- Core + Linux native CI green on exact SHA; +- Windows + macOS RC platform gates green on that same SHA; +- release matrix/provenance/checksums green; +- manual Windows Terminal/IME parity recorded. -## Milestone 4 — Production packaging and 1.0 gate — implementation complete, external validation pending - -Implemented: - -- `dshx` zero-argument startup with no manual bridge/profile/remote command; -- pinned Codex TUI included in platform release artifacts; -- packaged cross-platform `dshx-ipc-bridge` using Codex `codex_uds`; -- production Unix-socket transport with no TCP listener / bearer-token loopback dependency; -- real local-IPC data-plane self-check in `dshx doctor`; -- exact supported DSH release closure and compatibility gates; -- DSH-owned session durability/resume projection tests; -- approval/permission/subagent fail-closed tests; -- Linux x64, Windows x64, macOS arm64 and macOS x64 release jobs; -- clean-install artifact smoke and SHA-256 checksums; -- Linux real pinned-TUI PTY smoke in CI **and tagged release workflow**; -- Codex/DSH pin + patch-queue sync model; -- explicit RC promotion checklist in `RELEASE-READINESS.md`. - -## Milestone 5 — Standard profile-bundle delivery — implementation complete, real-session acceptance pending - -The surface ships as a regular DSH profile bundle instead of a bespoke launcher runtime: - -- the package manifest declares `dsh.bundle.patch`; official `dsh plugin --profile

add/remove` installs, layers, reconciles and withdraws the surface; -- loader-mounted rows (`dshx-startup`, `dshx-presentation`) own launch parameters, transport and endpoint publication; lifecycle authority is the Cordis root Fiber; -- `bin/dshx` is a thin bootstrap over the same official command (idempotent, version-pinned), and bare `dsh --profile tui` serves the endpoint passively with a visible listening hint; -- the Codex dialect is confined to `src/tui-protocol/`, enforced structurally by the ownership guard; -- per-platform release tarballs embed the pinned TUI + bridge and activate with zero environment overrides; -- verification: `npm run verify:bundle` proves dev-flow and release-flavor delivery end to end (reconcile, composed-tree assertions, activation, single-instance rule); CI gates it in the Linux TUI job. - -Exit gate: one real interactive dogfooding session plus the Windows Terminal/CJK/IME acceptance already required for 1.0. - -1.0 may ship only when the exact candidate has green CI/release evidence and the manual Windows Terminal/CJK/IME UX acceptance is recorded as passing. +Additional DSH-specific UI surfaces (jobs/workflows, plugin diagnostics, future commands) are post-1.0 presentation work unless the acceptance matrix promotes them to blockers. diff --git a/docs/RUNTIME-INTEGRATION.md b/docs/RUNTIME-INTEGRATION.md index ab87e8a9..501e86a5 100644 --- a/docs/RUNTIME-INTEGRATION.md +++ b/docs/RUNTIME-INTEGRATION.md @@ -2,124 +2,96 @@ ## Decision -DSHX reuses the same architectural seam that official DeepSeek Harness uses for its headless product: a direct Cordis/core entry point over the official DSH composition, without requiring the WebUI/browser runtime for normal terminal use. +DSHX is a **DSH profile surface**, not an application that embeds or launches a private Harness runtime. The user's installed `dsh --profile tui` process owns the Cordis Loader tree and all runtime services. DSHX contributes a startup row, a presentation row, protocol projection code and the pinned native TUI. -The TUI remains project-owned. DeepSeek Harness remains upstream-owned. +The tested development closure is DSH `0.1.0-rc.8`, but production compatibility is host-driven. Runtime peer declarations use a compatibility floor and remain optional advisory peers so installing DSHX cannot materialize a second Harness runtime into the profile. -Tested official DSH line for the current release branch: `0.1.0-rc.8`. The -plugin is host-version agnostic at runtime — it composes inside whatever -DeepSeek Harness installation hosts the profile, and an untested line only -produces a one-shot startup warning (never a block). -Pinned DSH source reference: `141eb6fef83422698aef7a981029e843e8161534`. +## Lifecycle -The official runtime owns Agent creation/resume, Session persistence, model selection/routing, tools, approvals, permission policy, skills, subagents and every other capability surface. DSHX generalizes only the **presentation lifetime** from a headless/one-shot consumer into an interactive terminal frontend. +1. `dshx` resolves the user's DSH launcher and idempotently ensures this package is installed into the selected profile through `dsh plugin --profile

add `. +2. `dshx` starts `dsh --profile

...` with the user's arguments unchanged. +3. The Loader composes `dshx-startup` and `dshx-presentation` from `cordis.patch.yml`. +4. `dshx-startup` reads official `cmdlineArgs` and publishes presentation facts (`cwd`, presentation home, package version, TUI args). +5. `dshx-presentation` waits for Loader settlement and starts the packaged native TUI as its child. +6. The presentation row binds anonymous directional child pipes directly to the live DSH Context through `startDshxStdioTransport`. +7. The TUI speaks the pinned Codex app-server-compatible JSONL dialect across those pipes; the adapter translates to DSH public services/events. +8. TUI exit requests official `appExit`, so the DSH launcher disposes the root composition and remains the sole teardown authority. -## Production topology +## Descriptor contract + +The DSH parent uses Node's supported directional stdio semantics: ```text -┌──────────────────────────────────────────┐ -│ dshx Node launcher │ -│ - boots official DSH composition │ -│ - mounts dshx-presentation plugin row │ -│ - owns child-process lifetime only │ -└────────────────────┬─────────────────────┘ - │ - │ DSH public APIs/events - ▼ -┌──────────────────────────────────────────┐ -│ DSHX presentation adapter │ -│ - Codex protocol projection only │ -│ - mounted as the dshx-presentation │ -│ Cordis plugin (name/inject/Config/ │ -│ apply), disposed by the root Fiber │ -└────────────────────┬─────────────────────┘ - │ JSONL / child stdio - ▼ -┌──────────────────────────────────────────┐ -│ dshx-ipc-bridge │ -│ - pinned Codex workspace binary │ -│ - no agent/session/runtime state │ -└────────────────────┬─────────────────────┘ - │ WebSocket framing over - │ private local UDS only - ▼ -┌──────────────────────────────────────────┐ -│ pinned Codex TUI thin fork │ -│ presentation/input only │ -└──────────────────────────────────────────┘ +child fd0 protocol input DSH → TUI +child fd1 terminal stdout +child fd2 terminal stderr +child fd3 preserved terminal stdin +child fd4 protocol output TUI → DSH ``` -The bridge exists because the TUI is Rust and the official DSH composition is Node/TypeScript. It reuses Codex's own cross-platform `codex_uds` implementation rather than introducing unsafe FFI or a second runtime. - -## Why WebSocket framing is still present - -The pinned Codex app-server client speaks WebSocket frames for its remote transport abstraction, including its Unix-socket endpoint. DSHX keeps that framing but changes the production carrier: +Spawn configuration: -- **forbidden in production:** `ws://127.0.0.1:*`, TCP listeners, bearer-token loopback transport, user-facing Codex remote mode; -- **production:** a private `unix://.../app.sock` endpoint implemented by `codex_uds`, with the bridge relaying JSON messages to Node over child stdio. - -Therefore production does not depend on Codex's experimental TCP WebSocket remote mode, while the TUI can continue using the upstream protocol machinery with a minimal thin-fork patch. +```js +stdio: ['pipe', 'inherit', 'inherit', 0, 'pipe'] +``` -## Launcher lifecycle +The native thin fork performs descriptor remapping before crossterm initializes: -`dshx` performs the following sequence: +- duplicate fd 0 to preserve protocol input; +- restore fd 3 onto ordinary stdin; +- on Unix, clear inherited `O_NONBLOCK` from the saved input and fd 4 before Tokio file I/O; +- on Windows, restore both CRT fd 0 and `STD_INPUT_HANDLE`; +- create `RemoteAppServerEndpoint::InheritedPipes { input_fd, output_fd }`. -1. Bootstrap the surface profile through the official plugin machinery: `dsh plugin --profile

add ` (idempotent — a profile already pinning this exact package version as a bundle layer is left untouched). The package manifest declares `dsh.bundle.patch`, so the loader picks the surface up as a real bundle layer. -2. Boot the official DSH composition for that profile; the loader mounts the rows declared by the shipped `cordis.patch.yml` (`dshx-startup`, `dshx-presentation`) and locks the competing headless presentation rows. -3. The startup row publishes launch parameters (presentation home, packaged binaries, version) as the `dshxStartup` service; the presentation row injects it, starts the local transport, and publishes the endpoint as the `dshxPresentation` service. -4. Spawn `dshx-ipc-bridge`, wait for its readiness control message, and expose the resulting `unix://` endpoint to the TUI. -5. Spawn the pinned Codex TUI with `DSHX_APP_SERVER_ENDPOINT` set to that local endpoint and an isolated presentation-only `CODEX_HOME`. -6. Relay app-server JSON between the TUI and the DSH presentation adapter while DSH remains authoritative for all runtime state. -7. On TUI exit or process shutdown, dispose the official Context: its root Fiber unwinds the presentation plugin (closing the transport and removing the temporary socket directory) — the Fiber is the sole teardown authority. +The app-server client reads from the saved input descriptor and writes to fd 4. It does not spawn a backend process. -Ctrl+C is intentionally not intercepted by the Node launcher because it is an in-TUI interaction used to interrupt/steer the active DSH turn. Process `SIGTERM` is propagated for lifecycle shutdown. +## No transport service -## What the adapter may do +The production transport deliberately has no address and no listening service. DSHX does not use: -- Create/resume Agents through official DSH services. -- Forward follow-up, steering and cancellation to official Agent/subagent control APIs. -- Subscribe to public Agent/Session events. -- Read official session persistence/list/inspection surfaces. -- Project DSH events into Codex Thread/Turn/Item UI events. -- Keep disposable UI correlation state such as `DSH turn number → current Codex turn id`. -- Translate a user decision from an upstream Codex picker into the corresponding official DSH approval/question API call without weakening it. +- TCP/WebSocket remote mode; +- Unix-domain sockets; +- local socket rendezvous directories; +- bearer-token loopback auth; +- a Rust/Node bridge executable; +- a Node local-server process. -## What the adapter must not do +The process relationship itself provides the local trust/lifetime boundary. -- Implement an agent loop. -- Call model providers directly instead of DSH. -- Execute tools or shell commands outside DSH. -- Store a second durable transcript or session database. -- Repair/replay sessions with DSHX-owned persistence logic. -- Decide sandbox/approval policy. -- Reimplement compaction, fork, skills, subagents, jobs or plugins. -- Persist an independent model choice when DSH already owns selection. +## Adapter authority -The test suite contains ownership guards for these boundaries. Missing official services are compatibility failures, not invitations to add shadow implementations. +The adapter may: -## Development-only transport +- create/resume Agents through official DSH services; +- forward follow-up, steering, interrupt and subagent control; +- subscribe to Agent/Session events; +- read official persistence/session-query surfaces; +- project those facts into Codex Thread/Turn/Item UI shapes; +- keep disposable correlation state needed only for presentation; +- translate approval/question UI responses to the matching DSH service. -The historical deterministic protocol PoC (`devtools/protocol-poc.mjs`) and TCP/WebSocket stub (`devtools/stub-server.mjs`) remain useful test fixtures for protocol work, but they live outside the production `src/` tree and are not copied into the installable production package. The `ws` dependency is development-only. +It must not: -The real TUI smoke test uses `bin/dshx-stub-local.mjs`, which drives the deterministic fixture through the same packaged local-IPC bridge as production. +- implement an Agent loop; +- call model providers directly; +- execute tools/shell commands outside DSH; +- store a second durable transcript; +- reimplement session repair, compaction, fork, skills, subagents, jobs or plugins; +- decide sandbox/approval policy; +- persist independent model/runtime state when DSH owns it. -## Diagnostics +Missing required public services are compatibility errors, not extension points for shadow implementations. -`dshx doctor` validates: +## Development and test topology -- supported Node runtime; -- packaged pinned Codex TUI; -- packaged `dshx-ipc-bridge`; -- a real UDS + WebSocket `ping → pong` self-test using Codex's cross-platform UDS implementation; -- official DSH bundle composition; -- isolated DSHX presentation home. +Protocol unit tests can instantiate deterministic adapters in-process. Real TUI PTY/ConPTY tests use `devtools/tui-stub-parent.mjs`: the **test parent** owns a deterministic protocol stub and launches the TUI with the same descriptor layout as production. This validates terminal stdin restoration, native directional-pipe transport, CJK input and resize without requiring provider credentials or network calls. -A successful bridge self-test proves the local transport data plane on the current OS; it is stronger than merely checking that the binary exists. +Separately, `scripts/runtime-smoke.mjs` and `scripts/verify-bundle-install.mjs` exercise the real official DSH profile and prove that Loader settlement, initialize, appExit and single-runtime ownership work through the same parent-owned pipe contract. -## Compatibility and upstream sync +## Compatibility -DSH and Codex are both moving upstreams. The repository pins source/package versions and keeps the Codex divergence as an ordered patch queue. Compatibility is defined by public capabilities actually exposed by the supported DSH line. +DSH and Codex are moving upstreams. The repository pins a tested source/package closure for reproducible CI and keeps Codex divergence as an ordered patch queue, but production resolves the actual DSH services from the host installation. -If a DSH update removes a required public seam, that version is unsupported until DSHX can adapt through another official seam or DSH restores one. DSHX must not preserve compatibility by copying DSH internals. +If an upstream DSH release removes a required public seam, DSHX adapts through another public seam or reports an incompatibility. It does not preserve compatibility by copying DSH internals. -If a Codex update breaks a patch or app-server shape, the pin is advanced only after the patch queue, protocol tests, PTY smoke, packaging checks and UX parity gate are revalidated. +A Codex pin is advanced only when the patch queue materializes cleanly and the core, native build, bundle, PTY/ConPTY, platform and UX-parity gates pass again. diff --git a/docs/UX-PARITY.md b/docs/UX-PARITY.md index d8d39a00..d4afca7a 100644 --- a/docs/UX-PARITY.md +++ b/docs/UX-PARITY.md @@ -1,76 +1,60 @@ # Codex UX parity matrix -The target is **behavioral parity with the pinned Codex TUI**, not a screenshot-inspired imitation. DSHX therefore keeps upstream Codex widgets/input handling wherever possible and changes only backend ownership, product data/branding, and unsupported-capability visibility. - -Status below means implementation/evidence coverage, not that the final release candidate has passed manual acceptance. - -## Acceptance matrix - -| Surface | Target | Current implementation evidence | -|---|---|---| -| Welcome screen | same structure, DSH branding/data only | Codex TUI thin fork + branding patch; PTY smoke asserts DSH surface | -| Composer | same multiline/editing behavior | inherited unchanged from pinned Codex TUI | -| Slash completion | same interaction pattern | inherited Codex UI; backend-incompatible commands hidden by narrow capability patch | -| Help/shortcuts | same keyboard model where applicable | inherited from pinned Codex TUI | -| Model picker | same presentation; data from DSH | official DSH model/provider directory + settings tests | -| Permission picker | same presentation; policy from DSH | DSH permission preset projection + backend-aware Codex picker patch | -| Tool cells | same renderer classes where mappings exist | DSH tool presentation specialization + tests | -| Shell cells | same streaming/collapse behavior | Codex shell renderer driven by DSH-owned tool execution/events | -| File diffs | same review rendering | Codex diff renderer driven by DSH tool metadata/workspace command path | -| Approval | same one-shot interaction where semantics match | DSH approval provider + fail-closed backend-aware overlay patch | -| Ask user | same picker/freeform experience where semantics match | `ctx.userQuestions` provider → Codex request-user-input overlay; multi-select remains explicit unsupported gap | -| Plan | same presentation mapped from DSH plan state | `todo/write` + DSH plan mode projection/tests | -| Reasoning | same cell behavior where DSH exposes it | DSH reasoning chunks/messages → Codex reasoning item/delta | -| Steering | same active-turn input semantics | Codex active composer → `Agent.steer(...)` through DSH controller | -| Interrupt | same Ctrl+C expectation | launcher preserves Ctrl+C for TUI; TUI interrupt delegates to DSH Agent/subagent authority | -| Resume | same picker behavior; sessions from DSH | Codex resume UI + DSH persistence list/inspect/resume/history hydration | -| Status/footer | same structure; DSH metrics/data | persisted/current model + token/context projections where exposed | -| Scroll/mouse | same behavior | inherited from pinned Codex TUI | -| Resize | no corruption or state loss | inherited from pinned Codex TUI; manual RC verification required | -| Windows Terminal | first-class release gate | native Windows build/package + real local-IPC doctor; visual/input acceptance still manual | -| CJK/IME | first-class release gate | Codex input code is inherited; exact RC artifact still requires manual Chinese IME acceptance | - -## Backend command visibility - -A Codex slash command is visible only when either: - -1. it is a presentation/local-TUI operation, or -2. DSHX has a faithful mapping to an official DSH public capability. - -Codex runtime-owned surfaces such as unsupported app/plugin/hook/memory/personality/review modes are hidden rather than falling through to Codex core. `/diff` remains visible because its execution path is DSH-owned. Skills remain visible because `skills/list` is backed by the official DSH registry surface. +The target is **behavioral parity with the pinned Codex TUI**, not a screenshot-inspired imitation. DSHX keeps upstream Codex widgets/input handling wherever practical and changes backend ownership, DSH data/branding, and unsupported-capability visibility. + +| Surface | Target / evidence | +|---|---| +| Welcome | upstream structure, DSH branding/version/model data | +| Composer | inherited multiline/editing behavior | +| Slash completion/help | inherited interaction; unsupported runtime-owned commands hidden | +| Model picker | Codex presentation backed by DSH model registry/resolution | +| Permission picker | Codex presentation backed by DSH permission presets/policy | +| Tool/shell/file/diff cells | Codex renderers fed from DSH-owned tool/session events | +| Approval | one-shot Codex overlay only where DSH semantics match; fail closed otherwise | +| Ask user | DSH user-question service projected into Codex UI; unsupported semantics explicit | +| Plan/reasoning | projected from DSH-exposed plan/reasoning events | +| Steering/interrupt | delegated to DSH Agent/subagent authority | +| Resume | Codex UI backed by DSH persistence/session state | +| Status/footer | DSH-owned model/token/context data where exposed | +| Scroll/mouse/resize | inherited Codex behavior; native PTY/ConPTY regression gates | +| Windows/CJK/IME | automated ConPTY Unicode/resize plus manual Windows Terminal IME gate | + +## Capability visibility + +A Codex command is visible only when it is either a presentation-local operation or has a faithful mapping to an official DSH public capability. Unsupported Codex runtime owners are hidden rather than routed to Codex core. + +`/diff`, fork/compact/agents and skills remain visible only where their execution/data path is DSH-owned. `scripts/verify-slash-contract.mjs` makes this classification executable. ## Allowed deliberate differences -- Product branding. -- Model/provider names and DSH-owned configuration vocabulary. -- Backend-specific capabilities that have no Codex equivalent. -- Explicit unsupported messages when semantic translation would be unsafe or misleading. -- Hidden Codex runtime commands when the supported DSH line has no faithful public equivalent. -- DSH multi-select user questions until the pinned Codex UI can represent them without semantic loss. +- DSHX branding and DSH model/provider vocabulary; +- DSH-specific capabilities with no Codex equivalent; +- explicit unsupported messages where semantic translation would be unsafe; +- hidden Codex runtime commands without a faithful DSH equivalent. ## Not acceptable -- Reimplementing a Codex widget merely because it looks simple. -- Maintaining a separate durable session history for UI convenience. -- Downgrading an approval or subagent authority requirement during protocol translation. -- Silent model changes on resume. -- Routing a hidden/unsupported command back into Codex's agent runtime. -- Replacing the inherited Codex composer with a generic readline prompt. -- Calling automated transport tests proof of Windows Terminal/CJK/IME parity. +- replacing upstream widgets with look-alikes unnecessarily; +- keeping a second durable session history; +- weakening approvals/sandbox/subagent authority in translation; +- silent model changes on resume; +- falling back to Codex Agent/runtime for hidden commands; +- replacing the composer with generic readline-style input; +- treating protocol/PTY automation as proof of real IME composition behavior. ## Automated parity protection -The repository protects the parts that can be automated: +- pinned Codex patch materialization and `cargo --locked` build; +- thin-fork invariants proving the TUI does not spawn a backend runtime; +- real native TUI startup through parent-owned directional pipes; +- Linux/macOS PTY and Windows ConPTY CJK/resize tests; +- DSH adapter protocol/unit tests and fail-closed ownership tests; +- standard DSH bundle activation and single-runtime checks. -- pinned Codex patch application/build; -- source invariants keeping DSHX on the external backend path; -- DSH adapter protocol/unit tests; -- ownership/fail-closed tests; -- real pinned-TUI PTY lifecycle smoke over production local IPC; -- native platform package + `dshx doctor`, including a real local-IPC data-plane self-test. +The PTY/ConPTY fixture is presentation-only: `devtools/tui-stub-parent.mjs` owns a deterministic protocol stub and launches the TUI with the same descriptor topology as production. The TUI never launches its own stub/backend. ## Manual release comparison -For every 1.0 release candidate, install the **generated release artifact** and compare it side by side with the pinned upstream Codex version using the same Windows Terminal dimensions/theme. At minimum verify composer editing, Chinese IME composition/commit/cancel, wide-glyph alignment, slash completion, pickers, overlays, tool/shell/diff cells, reasoning/plan, steering/Ctrl+C, resume, scroll/mouse, resize and footer rendering. +For every 1.0 RC, install the exact generated Windows artifact and compare it side-by-side with the pinned upstream Codex TUI under the same Windows Terminal dimensions/theme. Verify composer editing, Chinese IME composition/commit/cancel, wide-glyph alignment, slash completion, pickers, overlays, tool/shell/diff cells, reasoning/plan, steering/Ctrl+C, resume, scroll/mouse, resize and footer rendering. -Differences are either fixed, documented above as deliberate, or block release. The promotion procedure lives in `RELEASE-READINESS.md`. +Differences are fixed, explicitly documented as deliberate, or block release. See `RELEASE-READINESS.md`. diff --git a/package.json b/package.json index c961185b..d4eeb8c3 100644 --- a/package.json +++ b/package.json @@ -41,7 +41,7 @@ "freeze:deps": "node scripts/freeze-deps.mjs", "verify:release-deps": "node scripts/verify-dsh-closure.mjs . package-lock.json", "verify:bundle": "node scripts/verify-bundle-install.mjs", - "stub": "node ./devtools/dshx-stub-server.mjs", + "stub": "node ./devtools/tui-stub-parent.mjs", "dev": "node ./bin/dshx.mjs" }, "dependencies": { diff --git a/scripts/package-platform.mjs b/scripts/package-platform.mjs index 4ae11c40..8919b2aa 100644 --- a/scripts/package-platform.mjs +++ b/scripts/package-platform.mjs @@ -27,11 +27,6 @@ if (!fs.existsSync(tuiSource)) { throw new Error(`Missing built TUI at ${tuiSource}; build the pinned Codex TUI first`); } -// The lock may retain unreachable historical production nodes until the next -// reviewed freeze. Every dependency still shipped by the current manifest must -// nevertheless have the exact frozen root spec. The staged shrinkwrap below -// rewrites its root dependency map to the current manifest, so retired extras -// cannot become publishable dependencies. assertDependencySubset('dependencies', sourceLockRoot.dependencies, rootPackage.dependencies); assertDependencyMap('devDependencies', sourceLockRoot.devDependencies, rootPackage.devDependencies); @@ -50,9 +45,8 @@ function copy(relative) { fs.cpSync(from, to, { recursive: true }); } -// Ship the presentation closure only. The user's installed DSH owns every -// stateful runtime service; DSHX contributes Cordis rows, protocol projection -// code and the pinned TUI binary. There is no socket/bridge executable. +// Ship only the presentation closure. DSH remains host-owned and no bridge, +// local server or private Harness runtime is included in the artifact. copy('bin/dshx.mjs'); copy('src/cli'); copy('src/dsh'); @@ -108,7 +102,6 @@ const packageJson = { }; fs.writeFileSync(path.join(stage, 'package.json'), `${JSON.stringify(packageJson, null, 2)}\n`); -// Every relative production import must resolve from the staged package. const localImportPattern = /(?:from\s+|import\s*(?:\(\s*)?)["'](\.{1,2}\/[^"']+)["']/g; for (const file of walkJs(stage)) { const source = fs.readFileSync(file, 'utf8'); @@ -120,9 +113,8 @@ for (const file of walkJs(stage)) { } } -// Derive the publishable shrinkwrap from the source lock; do not resolve a new -// graph during packaging. Dev nodes and historical nodes may remain recorded -// but are unreachable because the staged root exposes production dependencies only. +// Derive the publishable shrinkwrap from the reviewed source lock. Historical +// unreachable records may remain, but the staged root exposes production deps only. const shrinkwrap = structuredClone(sourceLock); shrinkwrap.name = packageJson.name; shrinkwrap.version = packageJson.version; @@ -185,7 +177,7 @@ const metadata = { dshHostRange: rootPackage.peerDependencies?.['@deepseek-ai/dsh'] ?? null, codexCommit: fs.readFileSync(path.join(root, 'upstream', 'CODEX_COMMIT'), 'utf8').trim(), dshCommit: fs.readFileSync(path.join(root, 'upstream', 'DSH_COMMIT'), 'utf8').trim(), - transport: 'local-stdio-child', + transport: 'profile-directional-pipes', dependencyGraph: 'source-package-lock', sourceLockSha256, tarball: path.basename(targetTarball) diff --git a/scripts/verify-bundle-install.mjs b/scripts/verify-bundle-install.mjs index 5bc2b86b..dacb199c 100755 --- a/scripts/verify-bundle-install.mjs +++ b/scripts/verify-bundle-install.mjs @@ -12,7 +12,7 @@ const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..'); const PACKAGE = JSON.parse(fs.readFileSync(path.join(ROOT, 'package.json'), 'utf8')); const NAME = PACKAGE.name; const PROFILE = 'tui'; -const CLIENT = path.join(ROOT, 'scripts', 'fd3-smoke-client.mjs'); +const CLIENT = path.join(ROOT, 'scripts', 'profile-pipe-smoke-client.mjs'); function fail(message) { console.error(`\n[verify-bundle] FAIL: ${message}`); @@ -31,7 +31,7 @@ async function probeProfileSurface({ dsh, cwd, env, profile = PROFILE, timeoutMs return await new Promise((resolve, reject) => { const child = spawn(dsh.command, [...dsh.args, '--profile', profile, CLIENT], { cwd, - env: { ...env, DSHX_TUI_BIN: process.execPath }, + env: { ...env, DSHX_TUI_BIN: process.execPath, DSHX_DEBUG: '1' }, stdio: ['ignore', 'pipe', 'pipe'], windowsHide: true }); @@ -58,12 +58,12 @@ async function probeProfileSurface({ dsh, cwd, env, profile = PROFILE, timeoutMs finish(new Error(`profile-owned TUI failed (code ${code ?? '?'} signal ${signal ?? '-'})${stderr ? `:\n${stderr}` : ''}`)); return; } - const marker = stdout.split(/\r?\n/).find((line) => line.startsWith('DSHX_FD3_SMOKE ')); + const marker = stdout.split(/\r?\n/).find((line) => line.startsWith('DSHX_PROFILE_PIPE_SMOKE ')); if (!marker) { - finish(new Error(`presentation child never completed fd3 initialize${stderr ? `:\n${stderr}` : ''}`)); + finish(new Error(`presentation child never completed directional-pipe initialize${stderr ? `:\n${stderr}` : ''}`)); return; } - finish(null, JSON.parse(marker.slice('DSHX_FD3_SMOKE '.length))); + finish(null, JSON.parse(marker.slice('DSHX_PROFILE_PIPE_SMOKE '.length))); }); }); } @@ -116,7 +116,9 @@ async function verifyInstall(specifier, label) { }; for (const key of [ 'DSHX_APP_SERVER_CMD', 'DSHX_APP_SERVER_ENDPOINT', 'DSHX_APP_SERVER_TOKEN', - 'DSHX_IPC_BRIDGE_BIN', 'DSHX_ATTACH', 'DSHX_HEADLESS', 'DSHX_TUI_ARGS' + 'DSHX_IPC_BRIDGE_BIN', 'DSHX_APP_SERVER_FD', 'DSHX_APP_SERVER_INPUT_FD', + 'DSHX_APP_SERVER_OUTPUT_FD', 'DSHX_TERMINAL_INPUT_FD', 'DSHX_ATTACH', + 'DSHX_HEADLESS', 'DSHX_TUI_ARGS' ]) delete env[key]; try { @@ -135,7 +137,7 @@ async function verifyInstall(specifier, label) { throw new Error(`unexpected initialize identity: ${JSON.stringify(initialized)}`); } assertSingleRuntime(home); - console.log(`[verify-bundle] ${label} ok: official profile -> presentation child fd3 -> ${initialized.userAgent}`); + console.log(`[verify-bundle] ${label} ok: official profile -> presentation child directional pipes -> ${initialized.userAgent}`); } finally { fs.rmSync(work, { recursive: true, force: true }); } diff --git a/scripts/windows-rc-acceptance.ps1 b/scripts/windows-rc-acceptance.ps1 index c76ceaad..8bd2fed0 100644 --- a/scripts/windows-rc-acceptance.ps1 +++ b/scripts/windows-rc-acceptance.ps1 @@ -37,14 +37,12 @@ if (-not (Test-Path -LiteralPath $dshx)) { throw "installed dshx launcher not found: $dshx" } +# This is a thin DSH profile launcher; it intentionally has no private +# `doctor` control plane. `--version` crosses the same official DSH profile and +# native TUI startup path while terminating before an interactive session. $version = (& $dshx --version | Out-String).Trim() if ($LASTEXITCODE -ne 0 -or [string]::IsNullOrWhiteSpace($version)) { - throw 'installed dshx --version failed' -} - -& $dshx doctor -if ($LASTEXITCODE -ne 0) { - throw 'installed dshx doctor failed' + throw 'installed dshx --version failed; verify that official DeepSeek Harness is installed and resolvable' } Write-Host '' @@ -54,7 +52,7 @@ Write-Host "SHA-256: $actual" Write-Host "Version: $version" Write-Host "Launcher: $dshx" Write-Host '' -Write-Host 'Use this exact launcher for issue #12. In the project directory, run:' +Write-Host 'Use this exact launcher in the project directory for Windows Terminal/IME acceptance:' Write-Host " & '$dshx'" Write-Host '' Write-Host 'Do not replace the generated artifact with a source checkout during IME/visual acceptance.' diff --git a/test/tui_smoke.py b/test/tui_smoke.py index b7d2fba9..30fbc8b1 100644 --- a/test/tui_smoke.py +++ b/test/tui_smoke.py @@ -57,16 +57,13 @@ def expect_rendered_tokens(child, tokens): env.update({ "TERM": "xterm-256color", "CODEX_HOME": codex_home, + "DSHX_TUI_BIN": str(binary), "DSHX_STUB_TRACE_FILE": str(trace_path), - "DSHX_APP_SERVER_CMD": json.dumps([ - os.environ.get("NODE", "node"), - str(ROOT / "bin" / "dshx-stub-local.mjs"), - ]), - # pexpect is a PTY transport rather than a full terminal emulator. "CODEX_TUI_DISABLE_KEYBOARD_ENHANCEMENT": "1", }) child = pexpect.spawn( - str(binary), + env.get("NODE", "node"), + [str(ROOT / "devtools" / "tui-stub-parent.mjs")], cwd=str(ROOT), env=env, encoding="utf-8", @@ -100,7 +97,7 @@ def expect_rendered_tokens(child, tokens): transcript.append(child.before or "") trace = trace_path.read_text(encoding="utf-8") if trace_path.exists() else "" raise AssertionError( - "Pinned DSHX TUI stdio/CJK/resize smoke failed.\n" + "Pinned DSHX TUI directional-stdio/CJK/resize smoke failed.\n" f"Protocol trace:\n{trace}\n" "Transcript:\n" + "".join(transcript) ) diff --git a/test/tui_smoke_windows.mjs b/test/tui_smoke_windows.mjs index 390075da..b84ac182 100644 --- a/test/tui_smoke_windows.mjs +++ b/test/tui_smoke_windows.mjs @@ -88,7 +88,7 @@ const traceFile = path.join(os.tmpdir(), `dshx-conpty-trace-${process.pid}-${Dat let term; let dataDisposable; try { - term = pty.spawn(binary, [], { + term = pty.spawn(process.execPath, [path.join(ROOT, 'devtools', 'tui-stub-parent.mjs')], { name: 'xterm-256color', cols: 120, rows: 32, @@ -96,8 +96,8 @@ try { env: stringEnv({ TERM: 'xterm-256color', CODEX_HOME: codexHome, + DSHX_TUI_BIN: binary, DSHX_STUB_TRACE_FILE: traceFile, - DSHX_APP_SERVER_CMD: JSON.stringify([process.execPath, path.join(ROOT, 'bin', 'dshx-stub-local.mjs')]), CODEX_TUI_DISABLE_KEYBOARD_ENHANCEMENT: '1' }) }); @@ -122,7 +122,7 @@ try { term.write('\r'); await waitForOutput(state, 'DSHX protocol stub received:'); await waitForOutput(state, prompt); - process.stdout.write('Windows ConPTY DSHX stdio + CJK + resize smoke passed\n'); + process.stdout.write('Windows ConPTY DSHX directional stdio + CJK + resize smoke passed\n'); } finally { dataDisposable?.dispose?.(); try { term?.kill(); } catch {} From f152272a5520f2655c2d99a7ab12e97642acac5b Mon Sep 17 00:00:00 2001 From: code-new-bie <403466121@qq.com> Date: Fri, 28 Aug 2026 09:25:08 +0800 Subject: [PATCH 49/60] test(plugin): retire network wire fixture --- .github/workflows/ci.yml | 4 +- scripts/verify-ownership-boundary.mjs | 9 +- test/wire.test.mjs | 151 ++++++-------------------- 3 files changed, 45 insertions(+), 119 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 520921fc..cd1683b7 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -49,11 +49,11 @@ jobs: run: corepack enable pnpm - name: Boot and dispose official DeepSeek Harness composition run: node scripts/runtime-smoke.mjs - - name: Syntax check shipped JavaScript + - name: Syntax check shipped and development JavaScript shell: bash run: | set -euo pipefail - while IFS= read -r file; do node --check "$file"; done < <(find src bin scripts -type f -name '*.mjs' -print | sort) + while IFS= read -r file; do node --check "$file"; done < <(find src bin scripts devtools test -type f \( -name '*.mjs' -o -name '*.js' \) -print | sort) - name: Syntax check PTY smoke run: python3 -m py_compile test/tui_smoke.py diff --git a/scripts/verify-ownership-boundary.mjs b/scripts/verify-ownership-boundary.mjs index 3b4146f9..fe69a4bd 100644 --- a/scripts/verify-ownership-boundary.mjs +++ b/scripts/verify-ownership-boundary.mjs @@ -28,6 +28,7 @@ if (manifest.dsh?.bundle?.patch !== './cordis.patch.yml') { if (!manifest.exports?.['./presentation'] || !manifest.exports?.['./startup']) { throw new Error('package exports must expose the two Cordis surface rows'); } +if (manifest.dependencies?.ws) throw new Error('ws must never be a production dependency'); // Every DSH package belongs to the user's official installation. DSHX may // depend on non-DSH leaf helpers, but it must never install a second Harness @@ -51,7 +52,13 @@ for (const name of runtimePeers) { } // There is exactly one runtime owner: the user's official dsh launcher/profile. -for (const retired of ['src/dsh/runtime-boot.mjs', 'src/dsh/local-server.mjs']) { +for (const retired of [ + 'src/dsh/runtime-boot.mjs', + 'src/dsh/local-server.mjs', + 'bin/dshx-stub-local.mjs', + 'devtools/dshx-stub-server.mjs', + 'devtools/stub-server.mjs' +]) { if (existsSync(retired)) throw new Error(`${retired} must stay deleted; DSHX cannot own a runtime/socket host`); } requireText('src/dsh/profile-bootstrap.mjs', "'plugin', '--profile'"); diff --git a/test/wire.test.mjs b/test/wire.test.mjs index 40d2e52f..0ff57fbe 100644 --- a/test/wire.test.mjs +++ b/test/wire.test.mjs @@ -1,148 +1,67 @@ import assert from 'node:assert/strict'; import test from 'node:test'; -import { WebSocket } from 'ws'; -import { startProtocolStubServer } from '../devtools/stub-server.mjs'; +import { ProtocolStub, normalizeDispatchResult } from '../devtools/protocol-poc.mjs'; -function openSocket(url) { - return new Promise((resolve, reject) => { - const socket = new WebSocket(url); - socket.once('open', () => resolve(socket)); - socket.once('error', reject); - }); +function dispatch(stub, message) { + return normalizeDispatchResult(stub, message); } -function createInbox(socket) { - const queued = []; - const waiters = []; - - socket.on('message', (raw) => { - const message = JSON.parse(raw.toString('utf8')); - const waiter = waiters.shift(); - if (waiter) waiter.resolve(message); - else queued.push(message); - }); - - socket.on('error', (error) => { - for (const waiter of waiters.splice(0)) waiter.reject(error); - }); - - return { - async next(timeoutMs = 2000) { - if (queued.length > 0) return queued.shift(); - let timer; - try { - return await new Promise((resolve, reject) => { - const waiter = { resolve, reject }; - waiters.push(waiter); - timer = setTimeout(() => { - const index = waiters.indexOf(waiter); - if (index !== -1) waiters.splice(index, 1); - reject(new Error(`Timed out waiting for WebSocket message after ${timeoutMs}ms`)); - }, timeoutMs); - }); - } finally { - clearTimeout(timer); - } - }, - - async until(predicate, timeoutMs = 3000) { - const deadline = Date.now() + timeoutMs; - const seen = []; - while (Date.now() < deadline) { - const message = await this.next(Math.max(1, deadline - Date.now())); - seen.push(message); - if (predicate(message)) return { message, seen }; - } - throw new Error('Timed out waiting for matching WebSocket message'); - } - }; +function request(stub, id, method, params = {}) { + const { response, events } = dispatch(stub, { id, method, params }); + assert.equal(response?.id, id, `${method} must preserve the request id`); + return { response, events }; } -function send(socket, message) { - socket.send(JSON.stringify(message)); -} +test('wire contract: Codex-style initialize → thread → streamed turn lifecycle', () => { + const stub = new ProtocolStub({ cwd: process.cwd() }); -function closeSocket(socket) { - return new Promise((resolve) => { - if (socket.readyState === WebSocket.CLOSED) return resolve(); - socket.once('close', resolve); - socket.close(); + const initialized = request(stub, 'initialize', 'initialize', { + clientInfo: { name: 'codex-tui', version: 'wire-test' } }); -} + assert.equal(initialized.response.result.platformFamily.length > 0, true); + assert.equal(Object.hasOwn(initialized.response, 'jsonrpc'), false); + assert.match(initialized.response.result.userAgent, /^dshx\//); -test('wire: Codex-style initialize → thread → streamed turn lifecycle', async (t) => { - const server = await startProtocolStubServer({ eventDelayMs: 2 }); - const socket = await openSocket(server.url); - t.after(async () => { - await closeSocket(socket); - await server.close(); - }); - const inbox = createInbox(socket); - - send(socket, { - id: 'initialize', - method: 'initialize', - params: { clientInfo: { name: 'codex-tui', version: 'wire-test' } } - }); - const initialize = await inbox.next(); - assert.equal(initialize.id, 'initialize'); - assert.equal(initialize.result.platformFamily.length > 0, true); - assert.equal(Object.hasOwn(initialize, 'jsonrpc'), false); - - // Codex sends this after a successful initialize response. It is a notification, - // so the server must accept it without replying. - send(socket, { method: 'initialized' }); + // Codex sends this notification after initialize. The protocol fixture must + // accept it without synthesizing a response or a transport-level side effect. + const notification = dispatch(stub, { method: 'initialized' }); + assert.equal(notification.response ?? null, null); + assert.deepEqual(notification.events, []); for (const [id, method, expected] of [ [1, 'account/read', (result) => result.requiresOpenaiAuth === false], [2, 'model/list', (result) => result.data?.[0]?.model === 'dshx-stub'], [3, 'configRequirements/read', (result) => result.requirements === null] ]) { - send(socket, { id, method, params: {} }); - const response = await inbox.until((message) => message.id === id); - assert.equal(expected(response.message.result), true, `${method} returned unexpected result`); + const { response } = request(stub, id, method); + assert.equal(expected(response.result), true, `${method} returned unexpected result`); } - send(socket, { id: 4, method: 'thread/start', params: {} }); - const threadStart = await inbox.until((message) => message.id === 4); - const threadId = threadStart.message.result.thread.id; + const started = request(stub, 4, 'thread/start'); + const threadId = started.response.result.thread.id; assert.equal(typeof threadId, 'string'); - - const threadStarted = await inbox.until( - (message) => message.method === 'thread/started' && message.params?.thread?.id === threadId + const threadStarted = started.events.find( + (event) => event.method === 'thread/started' && event.params?.thread?.id === threadId ); - assert.equal(threadStarted.message.params.thread.modelProvider, 'dsh'); + assert.ok(threadStarted, 'thread/start must emit thread/started'); + assert.equal(threadStarted.params.thread.modelProvider, 'dsh'); - send(socket, { - id: 5, - method: 'turn/start', - params: { - threadId, - input: [{ type: 'text', text: 'wire hello', text_elements: [] }] - } + const accepted = request(stub, 5, 'turn/start', { + threadId, + input: [{ type: 'text', text: 'wire hello', text_elements: [] }] }); + const turnId = accepted.response.result.turn.id; + assert.equal(accepted.response.result.turn.status, 'inProgress'); - const turnResponse = await inbox.until((message) => message.id === 5); - const turnId = turnResponse.message.result.turn.id; - assert.equal(turnResponse.message.result.turn.status, 'inProgress'); - - const events = []; - while (true) { - const message = await inbox.next(); - if (message.method) events.push(message); - if ( - message.method === 'turn/completed' && - message.params?.threadId === threadId && - message.params?.turn?.id === turnId - ) break; - } - + const events = accepted.events; const methods = events.map((event) => event.method); assert.equal(methods[0], 'turn/started'); assert.equal(methods[1], 'item/started'); assert.ok(methods.includes('item/agentMessage/delta')); assert.equal(methods.at(-2), 'item/completed'); assert.equal(methods.at(-1), 'turn/completed'); + assert.equal(events.at(-1)?.params?.threadId, threadId); + assert.equal(events.at(-1)?.params?.turn?.id, turnId); const deltas = events .filter((event) => event.method === 'item/agentMessage/delta') From 7765a1293af320353ed8d657c5e2fdc6e415e2b9 Mon Sep 17 00:00:00 2001 From: code-new-bie <403466121@qq.com> Date: Fri, 28 Aug 2026 09:26:43 +0800 Subject: [PATCH 50/60] test(protocol): decouple wire fixture identity --- test/wire.test.mjs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/wire.test.mjs b/test/wire.test.mjs index 0ff57fbe..b1632551 100644 --- a/test/wire.test.mjs +++ b/test/wire.test.mjs @@ -20,7 +20,8 @@ test('wire contract: Codex-style initialize → thread → streamed turn lifecyc }); assert.equal(initialized.response.result.platformFamily.length > 0, true); assert.equal(Object.hasOwn(initialized.response, 'jsonrpc'), false); - assert.match(initialized.response.result.userAgent, /^dshx\//); + assert.equal(typeof initialized.response.result.userAgent, 'string'); + assert.notEqual(initialized.response.result.userAgent.length, 0); // Codex sends this notification after initialize. The protocol fixture must // accept it without synthesizing a response or a transport-level side effect. From fe58be476343891bd98f9120b1242c905761e196 Mon Sep 17 00:00:00 2001 From: code-new-bie <403466121@qq.com> Date: Fri, 28 Aug 2026 09:27:48 +0800 Subject: [PATCH 51/60] test(protocol): keep wire fixture request-only --- test/wire.test.mjs | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/test/wire.test.mjs b/test/wire.test.mjs index b1632551..17275cd8 100644 --- a/test/wire.test.mjs +++ b/test/wire.test.mjs @@ -2,12 +2,8 @@ import assert from 'node:assert/strict'; import test from 'node:test'; import { ProtocolStub, normalizeDispatchResult } from '../devtools/protocol-poc.mjs'; -function dispatch(stub, message) { - return normalizeDispatchResult(stub, message); -} - function request(stub, id, method, params = {}) { - const { response, events } = dispatch(stub, { id, method, params }); + const { response, events } = normalizeDispatchResult(stub, { id, method, params }); assert.equal(response?.id, id, `${method} must preserve the request id`); return { response, events }; } @@ -23,12 +19,6 @@ test('wire contract: Codex-style initialize → thread → streamed turn lifecyc assert.equal(typeof initialized.response.result.userAgent, 'string'); assert.notEqual(initialized.response.result.userAgent.length, 0); - // Codex sends this notification after initialize. The protocol fixture must - // accept it without synthesizing a response or a transport-level side effect. - const notification = dispatch(stub, { method: 'initialized' }); - assert.equal(notification.response ?? null, null); - assert.deepEqual(notification.events, []); - for (const [id, method, expected] of [ [1, 'account/read', (result) => result.requiresOpenaiAuth === false], [2, 'model/list', (result) => result.data?.[0]?.model === 'dshx-stub'], From f3fe513af84b5d38c253029378ea535dd28b051b Mon Sep 17 00:00:00 2001 From: code-new-bie <403466121@qq.com> Date: Fri, 28 Aug 2026 09:37:43 +0800 Subject: [PATCH 52/60] refactor(plugin): finish profile-owned surface cleanup --- bin/dshx.mjs | 8 +++++ package.json | 3 +- scripts/package-platform.mjs | 14 +++----- scripts/verify-ownership-boundary.mjs | 21 +++++------ src/cli/arguments.mjs | 29 --------------- src/cli/runtime.mjs | 7 ---- test/cli-arguments.test.mjs | 52 --------------------------- test/cli-launcher.test.mjs | 19 ++++++++++ test/cli-runtime.test.mjs | 8 ----- 9 files changed, 42 insertions(+), 119 deletions(-) delete mode 100644 src/cli/arguments.mjs delete mode 100644 test/cli-arguments.test.mjs create mode 100644 test/cli-launcher.test.mjs diff --git a/bin/dshx.mjs b/bin/dshx.mjs index 7bad781e..266d6812 100755 --- a/bin/dshx.mjs +++ b/bin/dshx.mjs @@ -30,6 +30,14 @@ export function bootstrapSurfaceProfile() { } export function run(argv = process.argv.slice(2)) { + // `--version` is a DSH launcher-owned flag when it appears after `--profile`, + // so the UX alias must answer this one metadata query before delegating. All + // real app arguments remain owned by the mounted TUI profile. + if (argv.length === 1 && (argv[0] === '--version' || argv[0] === '-V')) { + process.stdout.write(`${PACKAGE.version}\n`); + return 0; + } + if (!isSupportedNodeVersion(process.versions.node)) { process.stderr.write(`dshx: unsupported Node ${process.version}; required ${PACKAGE.engines.node}\n`); return 1; diff --git a/package.json b/package.json index d4eeb8c3..04d0de8d 100644 --- a/package.json +++ b/package.json @@ -72,7 +72,6 @@ "@deepseek-ai/dsh-host-apiproxy": "0.1.0-rc.8", "@deepseek-ai/dsh-launch-environment": "0.1.0-rc.8", "@deepseek-ai/dsh-llm": "0.1.0-rc.8", - "@deepseek-ai/dsh-session": "0.1.0-rc.8", - "ws": "^8.18.0" + "@deepseek-ai/dsh-session": "0.1.0-rc.8" } } diff --git a/scripts/package-platform.mjs b/scripts/package-platform.mjs index 8919b2aa..c862db53 100644 --- a/scripts/package-platform.mjs +++ b/scripts/package-platform.mjs @@ -27,8 +27,12 @@ if (!fs.existsSync(tuiSource)) { throw new Error(`Missing built TUI at ${tuiSource}; build the pinned Codex TUI first`); } +// A reviewed lock can retain unreachable historical root records until the next +// trusted freeze. Every dependency that the current manifest can install must +// still have the exact frozen spec; extras are deliberately ignored here and +// are removed from the staged publishable root below. assertDependencySubset('dependencies', sourceLockRoot.dependencies, rootPackage.dependencies); -assertDependencyMap('devDependencies', sourceLockRoot.devDependencies, rootPackage.devDependencies); +assertDependencySubset('devDependencies', sourceLockRoot.devDependencies, rootPackage.devDependencies); const releaseRoot = path.join(root, '.release'); const stage = path.join(releaseRoot, `dshx-${platform}-${arch}`); @@ -193,14 +197,6 @@ function assertDependencySubset(label, actual = {}, expected = {}) { } } -function assertDependencyMap(label, actual = {}, expected = {}) { - const actualEntries = Object.entries(actual).sort(([a], [b]) => a.localeCompare(b)); - const expectedEntries = Object.entries(expected).sort(([a], [b]) => a.localeCompare(b)); - if (JSON.stringify(actualEntries) !== JSON.stringify(expectedEntries)) { - throw new Error(`Frozen package-lock.json ${label} does not match package.json`); - } -} - function* walkJs(directory) { for (const entry of fs.readdirSync(directory, { withFileTypes: true })) { if (entry.name === 'node_modules' || entry.name === 'dist' || entry.name === 'upstream') continue; diff --git a/scripts/verify-ownership-boundary.mjs b/scripts/verify-ownership-boundary.mjs index fe69a4bd..b53a1e82 100644 --- a/scripts/verify-ownership-boundary.mjs +++ b/scripts/verify-ownership-boundary.mjs @@ -10,7 +10,6 @@ function forbidText(path, pattern, label = String(pattern)) { if (hit) throw new Error(`${path} violates ownership invariant: ${label}`); } -// Standard DSH bundle ownership: this layer inserts only its own surface rows. requireText('cordis.patch.yml', 'id: hmr'); requireText('cordis.patch.yml', 'disabled: true'); requireText('cordis.patch.yml', 'id: dshx-startup'); @@ -28,11 +27,10 @@ if (manifest.dsh?.bundle?.patch !== './cordis.patch.yml') { if (!manifest.exports?.['./presentation'] || !manifest.exports?.['./startup']) { throw new Error('package exports must expose the two Cordis surface rows'); } -if (manifest.dependencies?.ws) throw new Error('ws must never be a production dependency'); +if (manifest.dependencies?.ws || manifest.devDependencies?.ws) { + throw new Error('ws must not be a direct DSHX dependency; production transport is directional stdio'); +} -// Every DSH package belongs to the user's official installation. DSHX may -// depend on non-DSH leaf helpers, but it must never install a second Harness -// package into the profile. const runtimePeers = Object.keys(manifest.peerDependencies ?? {}).filter( (name) => name === '@deepseek-ai/dsh' || name.startsWith('@deepseek-ai/dsh-') ); @@ -51,28 +49,30 @@ for (const name of runtimePeers) { } } -// There is exactly one runtime owner: the user's official dsh launcher/profile. for (const retired of [ 'src/dsh/runtime-boot.mjs', 'src/dsh/local-server.mjs', 'bin/dshx-stub-local.mjs', 'devtools/dshx-stub-server.mjs', - 'devtools/stub-server.mjs' + 'devtools/stub-server.mjs', + 'src/cli/arguments.mjs' ]) { - if (existsSync(retired)) throw new Error(`${retired} must stay deleted; DSHX cannot own a runtime/socket host`); + if (existsSync(retired)) throw new Error(`${retired} must stay deleted; DSHX cannot own a runtime/socket/control plane`); } requireText('src/dsh/profile-bootstrap.mjs', "'plugin', '--profile'"); requireText('src/dsh/profile-bootstrap.mjs', 'resolveDshInvocation'); requireText('bin/dshx.mjs', "'--profile', profile, ...argv"); requireText('bin/dshx.mjs', "stdio: 'inherit'"); requireText('bin/dshx.mjs', 'shell: false'); +requireText('bin/dshx.mjs', "argv.length === 1 && (argv[0] === '--version' || argv[0] === '-V')"); +requireText('bin/dshx.mjs', 'process.stdout.write(`${PACKAGE.version}\\n`)'); +forbidText('bin/dshx.mjs', 'doctor', 'bespoke launcher doctor control plane'); forbidText('bin/dshx.mjs', /(?:from\s+|import\s+\(\s*|require\()\s*["']@deepseek-ai\//, 'importing Harness runtime builds'); for (const retired of [ 'DSHX_APP_SERVER_CMD', '--dshx-app-server', 'DSHX_APP_SERVER_ENDPOINT', 'DSHX_IPC_BRIDGE_BIN', 'DSHX_APP_SERVER_FD', 'DSHX_APP_SERVER_INPUT_FD', 'DSHX_APP_SERVER_OUTPUT_FD', 'DSHX_TERMINAL_INPUT_FD' ]) forbidText('bin/dshx.mjs', retired, `launcher owning transport/runtime seam ${retired}`); -// Surface rows follow the official startup-provider -> presentation-runner pattern. requireText('src/dsh/startup-plugin.mjs', "inject = ['cmdlineArgs']"); requireText('src/dsh/startup-plugin.mjs', "provide('dshxStartup'"); requireText('src/dsh/startup-plugin.mjs', 'tuiArgs:'); @@ -93,7 +93,6 @@ forbidText('src/dsh/presentation-plugin.mjs', 'resolveDshInvocation', 'presentat requireText('src/dsh/stdio-transport.mjs', 'already-mounted DSH Context'); forbidText('src/dsh/stdio-transport.mjs', /WebSocket|unix:\/\//, 'network/socket framing'); -// The final thin fork consumes only profile-owned directional inherited pipes. const inheritedPatch = 'upstream/patches/codex/0012-dshx-inherited-profile-pipe.patch'; for (const needle of [ 'InheritedPipes', 'DSHX_APP_SERVER_INPUT_FD', 'DSHX_TERMINAL_INPUT_FD', @@ -109,7 +108,6 @@ for (const file of readdirSync('upstream/patches/codex')) { forbidText('scripts/build-codex-tui.sh', 'dshx-ipc-bridge'); forbidText('scripts/build-codex-tui.ps1', 'dshx-ipc-bridge'); -// Domain capabilities delegate to DSH public services rather than local OS or shadow runtime state. for (const path of ['src/dsh/user-shell.mjs', 'src/dsh/workspace-command.mjs']) { forbidText(path, /execFile|execSync|spawn\(/, 'local process execution'); requireText(path, 'tools.execute'); @@ -127,7 +125,6 @@ forbidText('src/tui-protocol/adapter.mjs', /seedLength|dshForkSeed/, 'shadow for requireText('src/tui-protocol/adapter.mjs', 'subagents.interrupt'); forbidText('src/dsh/agent-driver.mjs', 'fork(sourceAgent'); -// Codex is only a presentation dialect. for (const required of ['src/tui-protocol/shapes.mjs', 'src/tui-protocol/adapter.mjs']) { if (!existsSync(required)) throw new Error(`missing protocol projection module: ${required}`); } diff --git a/src/cli/arguments.mjs b/src/cli/arguments.mjs deleted file mode 100644 index 811ae5d0..00000000 --- a/src/cli/arguments.mjs +++ /dev/null @@ -1,29 +0,0 @@ -export function parseLaunchArgs(args) { - if (args[0] !== 'resume') return { tuiArgs: args, resumeEnv: {} }; - const rest = args.slice(1); - if (rest.length === 0) return { tuiArgs: [], resumeEnv: { DSHX_RESUME_MODE: 'picker' } }; - if (rest.length === 1 && rest[0] === '--last') { - return { tuiArgs: [], resumeEnv: { DSHX_RESUME_MODE: 'last' } }; - } - if (rest.length === 1 && !rest[0].startsWith('-')) { - return { - tuiArgs: [], - resumeEnv: { DSHX_RESUME_MODE: 'id', DSHX_RESUME_SESSION_ID: rest[0] } - }; - } - throw new Error('Usage: dshx resume [--last|]'); -} - -export function parseCliInvocation(args) { - if (args.length === 1 && (args[0] === '--help' || args[0] === '-h')) { - return { kind: 'help' }; - } - if (args.length === 1 && (args[0] === '--version' || args[0] === '-V')) { - return { kind: 'version' }; - } - if (args[0] === 'doctor') { - if (args.length !== 1) throw new Error('Usage: dshx doctor'); - return { kind: 'doctor' }; - } - return { kind: 'launch', ...parseLaunchArgs(args) }; -} diff --git a/src/cli/runtime.mjs b/src/cli/runtime.mjs index e590597f..05619107 100644 --- a/src/cli/runtime.mjs +++ b/src/cli/runtime.mjs @@ -1,12 +1,5 @@ export const DSHX_NODE_ENGINE = '^22.19.0 || >=24.0.0'; export const DSHX_RELEASE_NODE_MAJOR = 24; -// `dshx doctor` deliberately boots the full official DSH composition, including -// profile watchers. A fresh Windows install can incur one-time module/native -// initialization that exceeds 20s even though subsequent and normal product -// startup are healthy. Keep the diagnostic bounded, but allow realistic cold -// starts on supported desktop hardware. -export const DSHX_DOCTOR_BOOT_TIMEOUT_MS = 60_000; -export const DSHX_DOCTOR_DISPOSE_TIMEOUT_MS = 10_000; export function isSupportedNodeVersion(version) { const match = /^(\d+)\.(\d+)\.(\d+)/.exec(String(version ?? '')); diff --git a/test/cli-arguments.test.mjs b/test/cli-arguments.test.mjs deleted file mode 100644 index facbb6fe..00000000 --- a/test/cli-arguments.test.mjs +++ /dev/null @@ -1,52 +0,0 @@ -import assert from 'node:assert/strict'; -import test from 'node:test'; -import { parseCliInvocation, parseLaunchArgs } from '../src/cli/arguments.mjs'; - -test('top-level help and version are recognized only as the sole argument', () => { - assert.deepEqual(parseCliInvocation(['--help']), { kind: 'help' }); - assert.deepEqual(parseCliInvocation(['-h']), { kind: 'help' }); - assert.deepEqual(parseCliInvocation(['--version']), { kind: 'version' }); - assert.deepEqual(parseCliInvocation(['-V']), { kind: 'version' }); - - assert.deepEqual(parseCliInvocation(['explain', '--version', 'behavior']), { - kind: 'launch', - tuiArgs: ['explain', '--version', 'behavior'], - resumeEnv: {} - }); - assert.deepEqual(parseCliInvocation(['explain', '--help', 'output']), { - kind: 'launch', - tuiArgs: ['explain', '--help', 'output'], - resumeEnv: {} - }); -}); - -test('doctor is an exact top-level command and rejects trailing arguments', () => { - assert.deepEqual(parseCliInvocation(['doctor']), { kind: 'doctor' }); - assert.throws(() => parseCliInvocation(['doctor', 'extra']), /Usage: dshx doctor/); -}); - -test('zero-argument launch and ordinary prompts pass through unchanged', () => { - assert.deepEqual(parseCliInvocation([]), { kind: 'launch', tuiArgs: [], resumeEnv: {} }); - assert.deepEqual(parseCliInvocation(['hello', 'world']), { - kind: 'launch', - tuiArgs: ['hello', 'world'], - resumeEnv: {} - }); -}); - -test('resume modes remain explicit and reject ambiguous option combinations', () => { - assert.deepEqual(parseLaunchArgs(['resume']), { - tuiArgs: [], - resumeEnv: { DSHX_RESUME_MODE: 'picker' } - }); - assert.deepEqual(parseLaunchArgs(['resume', '--last']), { - tuiArgs: [], - resumeEnv: { DSHX_RESUME_MODE: 'last' } - }); - assert.deepEqual(parseLaunchArgs(['resume', 'session-123']), { - tuiArgs: [], - resumeEnv: { DSHX_RESUME_MODE: 'id', DSHX_RESUME_SESSION_ID: 'session-123' } - }); - assert.throws(() => parseLaunchArgs(['resume', '--unknown']), /Usage: dshx resume/); - assert.throws(() => parseLaunchArgs(['resume', 'a', 'b']), /Usage: dshx resume/); -}); diff --git a/test/cli-launcher.test.mjs b/test/cli-launcher.test.mjs new file mode 100644 index 00000000..5f77f0f0 --- /dev/null +++ b/test/cli-launcher.test.mjs @@ -0,0 +1,19 @@ +import assert from 'node:assert/strict'; +import fs from 'node:fs'; +import { spawnSync } from 'node:child_process'; +import test from 'node:test'; + +const pkg = JSON.parse(fs.readFileSync('package.json', 'utf8')); + +test('dshx --version reports DSHX metadata without bootstrapping or invoking DSH', () => { + for (const flag of ['--version', '-V']) { + const result = spawnSync(process.execPath, ['bin/dshx.mjs', flag], { + cwd: process.cwd(), + env: { ...process.env, DSHX_DSH_BIN: '/definitely/not/a/dsh/binary' }, + encoding: 'utf8' + }); + assert.equal(result.status, 0, result.stderr); + assert.equal(result.stdout.trim(), pkg.version); + assert.equal(result.stderr, ''); + } +}); diff --git a/test/cli-runtime.test.mjs b/test/cli-runtime.test.mjs index b522767d..b045f60d 100644 --- a/test/cli-runtime.test.mjs +++ b/test/cli-runtime.test.mjs @@ -1,8 +1,6 @@ import assert from 'node:assert/strict'; import test from 'node:test'; import { - DSHX_DOCTOR_BOOT_TIMEOUT_MS, - DSHX_DOCTOR_DISPOSE_TIMEOUT_MS, DSHX_NODE_ENGINE, DSHX_RELEASE_NODE_MAJOR, assertReleaseNodeVersion, @@ -27,9 +25,3 @@ test('release/freeze work is intentionally standardized on Node 24 LTS', () => { assert.throws(() => assertReleaseNodeVersion('22.23.0'), /requires Node 24\.x/); assert.throws(() => assertReleaseNodeVersion('26.3.0'), /requires Node 24\.x/); }); - -test('doctor permits realistic first-run DSH cold starts while remaining bounded', () => { - assert.equal(DSHX_DOCTOR_BOOT_TIMEOUT_MS, 60_000); - assert.equal(DSHX_DOCTOR_DISPOSE_TIMEOUT_MS, 10_000); - assert.ok(DSHX_DOCTOR_BOOT_TIMEOUT_MS > 20_000); -}); From a8b3babf3cb90813659ebbbfa10c74439f884be9 Mon Sep 17 00:00:00 2001 From: code-new-bie <403466121@qq.com> Date: Fri, 28 Aug 2026 11:53:35 +0800 Subject: [PATCH 53/60] test(tui): enforce complete slash capability contract --- scripts/verify-tui-invariants.mjs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/scripts/verify-tui-invariants.mjs b/scripts/verify-tui-invariants.mjs index 9df0c931..6949cb41 100644 --- a/scripts/verify-tui-invariants.mjs +++ b/scripts/verify-tui-invariants.mjs @@ -94,4 +94,11 @@ for (const needle of ['DSHX_APP_SERVER_INPUT_FD', 'DSHX_TERMINAL_INPUT_FD', 'DSH const pkg = JSON.parse(read('package.json')); if (pkg.dependencies?.ws) throw new Error('ws must not be a production dependency'); + +// Every native build gate also verifies the complete pinned slash-command +// classification. This script requires the materialized Codex tree, so keeping +// it behind the thin-fork build makes the release-readiness requirement real on +// Linux, Windows, macOS and tagged release matrices without duplicating workflow steps. +await import('./verify-slash-contract.mjs'); + console.log('DSHX pinned TUI profile-owned directional pipe invariants verified'); From 693af43753eb89fe64020b0fbb7073fadd10cb75 Mon Sep 17 00:00:00 2001 From: code-new-bie <403466121@qq.com> Date: Fri, 28 Aug 2026 12:09:15 +0800 Subject: [PATCH 54/60] chore(deps): synchronize frozen manifest contract --- package-lock.json | 62 ++++++++++++++++++++++++++-------- package.json | 2 +- scripts/freeze-deps.mjs | 1 + scripts/lock-root-contract.mjs | 37 ++++++++++++++++++++ scripts/verify-dsh-closure.mjs | 13 +++++++ scripts/verify-lock-root.mjs | 15 ++++++++ test/lock-root.test.mjs | 30 ++++++++++++++++ 7 files changed, 144 insertions(+), 16 deletions(-) create mode 100644 scripts/lock-root-contract.mjs mode change 100644 => 100755 scripts/verify-dsh-closure.mjs create mode 100755 scripts/verify-lock-root.mjs create mode 100644 test/lock-root.test.mjs diff --git a/package-lock.json b/package-lock.json index 3230e417..6353979d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,7 +8,6 @@ "name": "@code-new-bie/dshx-tui", "version": "0.0.0-m1", "dependencies": { - "@deepseek-ai/dsh-cmdline": "0.1.0-rc.8", "@deepseek-ai/schemastery": "3.18.1" }, "bin": { @@ -21,20 +20,42 @@ "@deepseek-ai/dsh-host-apiproxy": "0.1.0-rc.8", "@deepseek-ai/dsh-launch-environment": "0.1.0-rc.8", "@deepseek-ai/dsh-llm": "0.1.0-rc.8", - "@deepseek-ai/dsh-session": "0.1.0-rc.8", - "ws": "^8.18.0" + "@deepseek-ai/dsh-session": "0.1.0-rc.8" }, "engines": { "node": "^22.19.0 || >=24.0.0" }, "peerDependencies": { - "@deepseek-ai/dsh": "0.1.0-rc.8", - "@deepseek-ai/dsh-agent": "0.1.0-rc.8", - "@deepseek-ai/dsh-app-boot": "0.1.0-rc.8", - "@deepseek-ai/dsh-host-apiproxy": "0.1.0-rc.8", - "@deepseek-ai/dsh-launch-environment": "0.1.0-rc.8", - "@deepseek-ai/dsh-llm": "0.1.0-rc.8", - "@deepseek-ai/dsh-session": "0.1.0-rc.8" + "@deepseek-ai/dsh": ">=0.1.0-rc.8", + "@deepseek-ai/dsh-agent": ">=0.1.0-rc.8", + "@deepseek-ai/dsh-app-boot": ">=0.1.0-rc.8", + "@deepseek-ai/dsh-host-apiproxy": ">=0.1.0-rc.8", + "@deepseek-ai/dsh-launch-environment": ">=0.1.0-rc.8", + "@deepseek-ai/dsh-llm": ">=0.1.0-rc.8", + "@deepseek-ai/dsh-session": ">=0.1.0-rc.8" + }, + "peerDependenciesMeta": { + "@deepseek-ai/dsh": { + "optional": true + }, + "@deepseek-ai/dsh-agent": { + "optional": true + }, + "@deepseek-ai/dsh-app-boot": { + "optional": true + }, + "@deepseek-ai/dsh-host-apiproxy": { + "optional": true + }, + "@deepseek-ai/dsh-launch-environment": { + "optional": true + }, + "@deepseek-ai/dsh-llm": { + "optional": true + }, + "@deepseek-ai/dsh-session": { + "optional": true + } } }, "node_modules/@anthropic-ai/sdk": { @@ -556,6 +577,7 @@ "version": "4.0.1", "resolved": "https://registry.npmmirror.com/@deepseek-ai/cordis/-/cordis-4.0.1.tgz", "integrity": "sha512-YBdskTU2Po1kru3GgcUWUbkTsPMA9LkSQDAY8rBkFJeajdgcQad3QPJZE26JyK99Xb6HaASvoXg2DSUTeN/0Nw==", + "dev": true, "license": "MIT", "dependencies": { "@deepseek-ai/cosmokit": "^1.8.2", @@ -611,7 +633,7 @@ "version": "1.0.6", "resolved": "https://registry.npmmirror.com/@deepseek-ai/cordis-plugin-include/-/cordis-plugin-include-1.0.6.tgz", "integrity": "sha512-i1VXrZCbv6tk/iUgedCNjrxxArbWT3IvRZGB5sdqJ3ectnihivXXQbRZ8JJ73DSmAPvlMGmrbtjFAfm10yvXRg==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "@deepseek-ai/cosmokit": "^1.8.2", @@ -626,6 +648,7 @@ "version": "1.0.2", "resolved": "https://registry.npmmirror.com/@deepseek-ai/cordis-plugin-loader/-/cordis-plugin-loader-1.0.2.tgz", "integrity": "sha512-RIW9hoVyhYDWdCI9BsvtZccPde1ECLC4OAxupwowGTak78vwVTVdb3HezTSOK1Y1/Ax3Ru0LA1pYOB04CnTxIQ==", + "dev": true, "license": "MIT", "dependencies": { "@deepseek-ai/cosmokit": "^1.8.2" @@ -1852,6 +1875,7 @@ "version": "0.1.0-rc.8", "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-cmdline/-/dsh-cmdline-0.1.0-rc.8.tgz", "integrity": "sha512-xsnNFm2XpMD9wpBBLq80x8yXTi664DHywkLwxgAhDsWyp9tB2aSWaWVKxugPWSWwrB3F4nfloWqaeUfgXRFtBQ==", + "dev": true, "license": "MIT", "peerDependencies": { "@deepseek-ai/cordis": "^4.0.1", @@ -2396,6 +2420,7 @@ "version": "0.1.0-rc.8", "resolved": "https://registry.npmmirror.com/@deepseek-ai/dsh-invariants/-/dsh-invariants-0.1.0-rc.8.tgz", "integrity": "sha512-u0lYqyxOYwfsVnbsfGXZos5vFvA4cqFnBEW3/ezgljNwkYwzeUP/Y5wjPnQjP+ZzBn3CnVeIF6s2N2Vk3iA5mQ==", + "dev": true, "license": "MIT", "peer": true, "dependencies": { @@ -5978,7 +6003,7 @@ "version": "2.0.1", "resolved": "https://registry.npmmirror.com/argparse/-/argparse-2.0.1.tgz", "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "devOptional": true, + "dev": true, "license": "Python-2.0" }, "node_modules/base64-js": { @@ -6991,7 +7016,7 @@ "version": "4.3.1", "resolved": "https://registry.npmmirror.com/js-yaml/-/js-yaml-4.3.1.tgz", "integrity": "sha512-CY6crGq313MX8GkwvB7tzgp99vjQxY1++5y10/BKN/GUfHqWaOGQMNZkBvqSzsZKWk/ijwHlWzzkLulsGHhjWQ==", - "devOptional": true, + "dev": true, "funding": [ { "type": "github", @@ -7212,7 +7237,7 @@ "version": "0.1.5", "resolved": "https://registry.npmmirror.com/node-addon-native-custom-loader/-/node-addon-native-custom-loader-0.1.5.tgz", "integrity": "sha512-rL0XXRytayIChYf1xaG9/1NzGBRTyFkQTIpn+MDz/hpr0PZw1a9PZIoH9HlYfagNawhXU+jfN650EvoSIvR7Vw==", - "devOptional": true, + "dev": true, "license": "MIT", "engines": { "node": ">=20" @@ -7222,7 +7247,7 @@ "version": "0.1.5", "resolved": "https://registry.npmmirror.com/node-addon-require-builtin/-/node-addon-require-builtin-0.1.5.tgz", "integrity": "sha512-isaquiStlp7qdFpaffy+2ssJPUR/kLPRE5gqfeWbb0Ahph9H7O3BOFwThqkVaTrxfpnjrQauxlOEgvzD+snhUg==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "node-addon-native-custom-loader": "0.1.5" @@ -7247,6 +7272,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -7266,6 +7292,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -7285,6 +7312,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -7304,6 +7332,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -7323,6 +7352,7 @@ "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -7342,6 +7372,7 @@ "cpu": [ "ia32" ], + "dev": true, "license": "MIT", "optional": true, "os": [ @@ -7361,6 +7392,7 @@ "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ diff --git a/package.json b/package.json index 04d0de8d..b5d3576f 100644 --- a/package.json +++ b/package.json @@ -39,7 +39,7 @@ "test:protocol": "node --test --test-force-exit test/protocol.test.mjs test/wire.test.mjs", "test:dsh": "node --test --test-force-exit \"test/dsh-*.test.mjs\"", "freeze:deps": "node scripts/freeze-deps.mjs", - "verify:release-deps": "node scripts/verify-dsh-closure.mjs . package-lock.json", + "verify:release-deps": "node scripts/verify-lock-root.mjs && node scripts/verify-dsh-closure.mjs . package-lock.json", "verify:bundle": "node scripts/verify-bundle-install.mjs", "stub": "node ./devtools/tui-stub-parent.mjs", "dev": "node ./bin/dshx.mjs" diff --git a/scripts/freeze-deps.mjs b/scripts/freeze-deps.mjs index b386ccc6..da51e7c2 100644 --- a/scripts/freeze-deps.mjs +++ b/scripts/freeze-deps.mjs @@ -53,6 +53,7 @@ const [installCommand, installArgs] = npmInvocation([ ]); run(installCommand, installArgs); +run(process.execPath, ['scripts/verify-lock-root.mjs']); run(process.execPath, [ 'scripts/verify-dsh-closure.mjs', '.', diff --git a/scripts/lock-root-contract.mjs b/scripts/lock-root-contract.mjs new file mode 100644 index 00000000..d030592b --- /dev/null +++ b/scripts/lock-root-contract.mjs @@ -0,0 +1,37 @@ +import assert from 'node:assert/strict'; + +export function normalizeBin(bin = {}) { + return Object.fromEntries( + Object.entries(bin).map(([name, target]) => [name, String(target).replace(/^\.\//, '')]) + ); +} + +export function assertLockRootMatchesManifest(manifest, lock, label = 'package-lock.json') { + const root = lock?.packages?.['']; + assert.ok(root, `${label} has no root package record`); + assert.equal(lock.name, manifest.name, `${label} top-level name drift`); + assert.equal(lock.version, manifest.version, `${label} top-level version drift`); + assert.equal(root.name, manifest.name, `${label} root name drift`); + assert.equal(root.version, manifest.version, `${label} root version drift`); + + for (const field of [ + 'dependencies', + 'devDependencies', + 'peerDependencies', + 'peerDependenciesMeta', + 'engines', + ]) { + assert.deepStrictEqual( + root[field] ?? {}, + manifest[field] ?? {}, + `${label} root ${field} drift` + ); + } + + assert.deepStrictEqual( + normalizeBin(root.bin), + normalizeBin(manifest.bin), + `${label} root bin drift` + ); + return root; +} diff --git a/scripts/verify-dsh-closure.mjs b/scripts/verify-dsh-closure.mjs old mode 100644 new mode 100755 index 3e167988..cabe34e4 --- a/scripts/verify-dsh-closure.mjs +++ b/scripts/verify-dsh-closure.mjs @@ -2,6 +2,7 @@ import fs from 'node:fs'; import path from 'node:path'; import process from 'node:process'; +import { assertLockRootMatchesManifest } from './lock-root-contract.mjs'; const root = path.resolve(process.argv[2] ?? process.cwd()); const packagePath = path.join(root, 'package.json'); @@ -39,6 +40,18 @@ if (hostSpec !== expected && !hostSpec.includes(expected)) { } const lock = JSON.parse(fs.readFileSync(lockPath, 'utf8')); +// Source package-lock files are also the reviewed manifest freeze contract. +// npm-shrinkwrap files produced for platform artifacts intentionally have a +// different staged root (no devDependencies, platform os/cpu), so they keep +// using the DSH closure check below rather than this source-root assertion. +if ( + path.basename(lockPath) === 'package-lock.json' && + typeof pkg.name === 'string' && + typeof pkg.version === 'string' +) { + assertLockRootMatchesManifest(pkg, lock, path.relative(root, lockPath) || 'package-lock.json'); +} + const packages = lock.packages ?? {}; const mismatches = []; let count = 0; diff --git a/scripts/verify-lock-root.mjs b/scripts/verify-lock-root.mjs new file mode 100755 index 00000000..cf93192b --- /dev/null +++ b/scripts/verify-lock-root.mjs @@ -0,0 +1,15 @@ +#!/usr/bin/env node +import fs from 'node:fs'; +import path from 'node:path'; +import process from 'node:process'; +import { fileURLToPath } from 'node:url'; +import { assertLockRootMatchesManifest } from './lock-root-contract.mjs'; + +const scriptRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..'); +const root = process.argv[2] ? path.resolve(process.argv[2]) : scriptRoot; +const lockPath = process.argv[3] ? path.resolve(process.argv[3]) : path.join(root, 'package-lock.json'); +const manifest = JSON.parse(fs.readFileSync(path.join(root, 'package.json'), 'utf8')); +const lock = JSON.parse(fs.readFileSync(lockPath, 'utf8')); + +assertLockRootMatchesManifest(manifest, lock, path.relative(root, lockPath) || 'package-lock.json'); +console.log('Frozen package-lock root matches package.json'); diff --git a/test/lock-root.test.mjs b/test/lock-root.test.mjs new file mode 100644 index 00000000..67fe09e1 --- /dev/null +++ b/test/lock-root.test.mjs @@ -0,0 +1,30 @@ +import assert from 'node:assert/strict'; +import fs from 'node:fs'; +import test from 'node:test'; +import { assertLockRootMatchesManifest } from '../scripts/lock-root-contract.mjs'; + +const manifest = JSON.parse(fs.readFileSync('package.json', 'utf8')); +const lock = JSON.parse(fs.readFileSync('package-lock.json', 'utf8')); + +test('frozen package-lock root exactly matches the current manifest contract', () => { + assert.doesNotThrow(() => assertLockRootMatchesManifest(manifest, lock)); +}); + +test('lock contract rejects stale direct dependencies and host peer ranges', () => { + const staleDependency = structuredClone(lock); + staleDependency.packages[''].devDependencies = { + ...staleDependency.packages[''].devDependencies, + ws: '^8.18.0', + }; + assert.throws( + () => assertLockRootMatchesManifest(manifest, staleDependency), + /root devDependencies drift/ + ); + + const stalePeer = structuredClone(lock); + stalePeer.packages[''].peerDependencies['@deepseek-ai/dsh'] = '0.1.0-rc.8'; + assert.throws( + () => assertLockRootMatchesManifest(manifest, stalePeer), + /root peerDependencies drift/ + ); +}); From dc206c1795b7c3fecf5090307dba47300f1a1979 Mon Sep 17 00:00:00 2001 From: code-new-bie <403466121@qq.com> Date: Fri, 28 Aug 2026 14:03:47 +0800 Subject: [PATCH 55/60] build(release): fail closed on manifest lock drift --- scripts/package-platform.mjs | 22 ++++++---------------- 1 file changed, 6 insertions(+), 16 deletions(-) diff --git a/scripts/package-platform.mjs b/scripts/package-platform.mjs index c862db53..e475dbd6 100644 --- a/scripts/package-platform.mjs +++ b/scripts/package-platform.mjs @@ -5,6 +5,7 @@ import process from 'node:process'; import { createHash } from 'node:crypto'; import { execFileSync } from 'node:child_process'; import { fileURLToPath } from 'node:url'; +import { assertLockRootMatchesManifest } from './lock-root-contract.mjs'; const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..'); const rootPackage = JSON.parse(fs.readFileSync(path.join(root, 'package.json'), 'utf8')); @@ -27,12 +28,9 @@ if (!fs.existsSync(tuiSource)) { throw new Error(`Missing built TUI at ${tuiSource}; build the pinned Codex TUI first`); } -// A reviewed lock can retain unreachable historical root records until the next -// trusted freeze. Every dependency that the current manifest can install must -// still have the exact frozen spec; extras are deliberately ignored here and -// are removed from the staged publishable root below. -assertDependencySubset('dependencies', sourceLockRoot.dependencies, rootPackage.dependencies); -assertDependencySubset('devDependencies', sourceLockRoot.devDependencies, rootPackage.devDependencies); +// Packaging is itself a release boundary, so it must reject any source +// manifest/lock drift even when callers bypass the normal CI preflight. +assertLockRootMatchesManifest(rootPackage, sourceLock, 'package-lock.json'); const releaseRoot = path.join(root, '.release'); const stage = path.join(releaseRoot, `dshx-${platform}-${arch}`); @@ -117,8 +115,8 @@ for (const file of walkJs(stage)) { } } -// Derive the publishable shrinkwrap from the reviewed source lock. Historical -// unreachable records may remain, but the staged root exposes production deps only. +// Derive the publishable shrinkwrap from the exact reviewed source lock. The +// staged root intentionally removes devDependencies and adds platform metadata. const shrinkwrap = structuredClone(sourceLock); shrinkwrap.name = packageJson.name; shrinkwrap.version = packageJson.version; @@ -189,14 +187,6 @@ const metadata = { fs.writeFileSync(`${targetTarball}.json`, `${JSON.stringify(metadata, null, 2)}\n`); process.stdout.write(`${targetTarball}\n`); -function assertDependencySubset(label, actual = {}, expected = {}) { - for (const [name, spec] of Object.entries(expected)) { - if (actual[name] !== spec) { - throw new Error(`Frozen package-lock.json ${label}.${name} does not match package.json: expected ${spec}, got ${actual[name] ?? ''}`); - } - } -} - function* walkJs(directory) { for (const entry of fs.readdirSync(directory, { withFileTypes: true })) { if (entry.name === 'node_modules' || entry.name === 'dist' || entry.name === 'upstream') continue; From 44f89910800cc684a68f0b03f26590af9a271fe4 Mon Sep 17 00:00:00 2001 From: code-new-bie <403466121@qq.com> Date: Fri, 28 Aug 2026 14:18:46 +0800 Subject: [PATCH 56/60] fix(ci): run npm shell-free in Windows bundle verification --- scripts/verify-bundle-install.mjs | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) mode change 100755 => 100644 scripts/verify-bundle-install.mjs diff --git a/scripts/verify-bundle-install.mjs b/scripts/verify-bundle-install.mjs old mode 100755 new mode 100644 index dacb199c..017954bc --- a/scripts/verify-bundle-install.mjs +++ b/scripts/verify-bundle-install.mjs @@ -21,12 +21,26 @@ function fail(message) { function run(command, args, { cwd = ROOT, env = process.env, check = true } = {}) { const result = spawnSync(command, args, { cwd, env, encoding: 'utf8' }); + if (result.error) throw result.error; if (check && result.status !== 0) { throw new Error(`${command} ${args.join(' ')} failed (exit ${result.status}):\n${result.stderr || result.stdout}`); } return result; } +function npmInvocation(args) { + if (process.platform !== 'win32') return ['npm', args]; + const candidates = [ + process.env.npm_execpath, + path.join(path.dirname(process.execPath), 'node_modules', 'npm', 'bin', 'npm-cli.js') + ].filter(Boolean); + const npmCli = candidates.find((candidate) => fs.existsSync(candidate)); + if (!npmCli) { + throw new Error(`Unable to locate npm CLI for shell-free Windows execution; checked: ${candidates.join(', ')}`); + } + return [process.execPath, [npmCli, ...args]]; +} + async function probeProfileSurface({ dsh, cwd, env, profile = PROFILE, timeoutMs = 90_000 }) { return await new Promise((resolve, reject) => { const child = spawn(dsh.command, [...dsh.args, '--profile', profile, CLIENT], { @@ -146,7 +160,14 @@ async function verifyInstall(specifier, label) { try { const packDir = fs.mkdtempSync(path.join(os.tmpdir(), 'dshx-source-pack-')); try { - const packed = run('npm', ['pack', '--pack-destination', packDir, '--loglevel', 'error']); + const [npmCommand, npmArgs] = npmInvocation([ + 'pack', + '--pack-destination', + packDir, + '--loglevel', + 'error' + ]); + const packed = run(npmCommand, npmArgs); const name = packed.stdout.trim().split('\n').pop()?.trim(); if (!name?.endsWith('.tgz')) throw new Error(`npm pack returned no tarball: ${packed.stdout}`); await verifyInstall(path.join(packDir, name), 'source bundle'); From 87007de34ffece955b0f90e296f03c45ec848e96 Mon Sep 17 00:00:00 2001 From: code-new-bie <403466121@qq.com> Date: Fri, 28 Aug 2026 15:11:47 +0800 Subject: [PATCH 57/60] fix(release): bind staged DSH closure to source baseline --- scripts/package-platform.mjs | 20 +++++++++++---- scripts/verify-dsh-closure.mjs | 47 +++++++++++++++++++++++++++++----- 2 files changed, 56 insertions(+), 11 deletions(-) mode change 100644 => 100755 scripts/package-platform.mjs diff --git a/scripts/package-platform.mjs b/scripts/package-platform.mjs old mode 100644 new mode 100755 index e475dbd6..f6cc5c94 --- a/scripts/package-platform.mjs +++ b/scripts/package-platform.mjs @@ -19,6 +19,15 @@ const sourceLock = JSON.parse(sourceLockBytes.toString('utf8')); const sourceLockRoot = sourceLock.packages?.['']; if (!sourceLockRoot) throw new Error('Frozen package-lock.json has no root package record'); +const exactDshVersion = /^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?$/; +const testedDshVersion = rootPackage.devDependencies?.['@deepseek-ai/dsh'] + ?? Object.entries(rootPackage.peerDependencies ?? {}) + .find(([name, value]) => name.startsWith('@deepseek-ai/dsh-') && exactDshVersion.test(String(value)))?.[1] + ?? rootPackage.dependencies?.['@deepseek-ai/dsh']; +if (typeof testedDshVersion !== 'string' || !exactDshVersion.test(testedDshVersion)) { + throw new Error(`Unable to derive one exact tested DSH release from the source manifest: ${JSON.stringify(testedDshVersion)}`); +} + const version = process.env.DSHX_VERSION || rootPackage.version; const platform = process.platform; const arch = process.arch; @@ -135,10 +144,15 @@ delete shrinkwrapRoot.devDependencies; const shrinkwrapPath = path.join(stage, 'npm-shrinkwrap.json'); fs.writeFileSync(shrinkwrapPath, `${JSON.stringify(shrinkwrap, null, 2)}\n`); +// The stage intentionally has no source-only devDependency from which to infer +// the tested release. Bind its closure check to the exact baseline already +// derived from the reviewed source manifest instead of weakening the check. execFileSync(process.execPath, [ path.join(root, 'scripts', 'verify-dsh-closure.mjs'), stage, - shrinkwrapPath + shrinkwrapPath, + '--expected', + testedDshVersion ], { cwd: root, stdio: 'inherit' }); const packArgs = ['pack', stage, '--pack-destination', out, '--json']; @@ -166,10 +180,6 @@ if (path.resolve(sourceTarball) !== path.resolve(targetTarball)) { fs.renameSync(sourceTarball, targetTarball); } -const testedDshVersion = rootPackage.devDependencies?.['@deepseek-ai/dsh'] - ?? Object.entries(rootPackage.peerDependencies ?? {}) - .find(([name, value]) => name.startsWith('@deepseek-ai/dsh-') && /^\d/.test(String(value)))?.[1] - ?? rootPackage.peerDependencies?.['@deepseek-ai/dsh']; const metadata = { version, platform, diff --git a/scripts/verify-dsh-closure.mjs b/scripts/verify-dsh-closure.mjs index cabe34e4..20ee3f58 100755 --- a/scripts/verify-dsh-closure.mjs +++ b/scripts/verify-dsh-closure.mjs @@ -4,10 +4,29 @@ import path from 'node:path'; import process from 'node:process'; import { assertLockRootMatchesManifest } from './lock-root-contract.mjs'; -const root = path.resolve(process.argv[2] ?? process.cwd()); +const cliArgs = process.argv.slice(2); +const positional = []; +let expectedOverride = null; +for (let index = 0; index < cliArgs.length; index += 1) { + const arg = cliArgs[index]; + if (arg === '--expected') { + const value = cliArgs[index + 1]; + if (!value || value.startsWith('--')) throw new Error('--expected requires an exact DSH version'); + expectedOverride = value; + index += 1; + continue; + } + if (arg.startsWith('--')) throw new Error(`Unknown option: ${arg}`); + positional.push(arg); +} +if (positional.length > 2) { + throw new Error('Usage: verify-dsh-closure.mjs [root] [lockfile] [--expected ]'); +} + +const root = path.resolve(positional[0] ?? process.cwd()); const packagePath = path.join(root, 'package.json'); -const lockPath = process.argv[3] - ? path.resolve(process.argv[3]) +const lockPath = positional[1] + ? path.resolve(positional[1]) : path.join(root, fs.existsSync(path.join(root, 'npm-shrinkwrap.json')) ? 'npm-shrinkwrap.json' : 'package-lock.json'); if (!fs.existsSync(packagePath)) throw new Error(`Missing package.json at ${packagePath}`); @@ -19,6 +38,8 @@ const exactVersion = /^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?$/; // Host compatibility and test reproducibility are separate contracts. The // host-facing @deepseek-ai/dsh peer may be a range, while the source/test graph // pins one exact DSH release line for every stateful package in the lockfile. +// Platform stages intentionally omit source-only devDependencies, so the +// packager may pass the already-validated source baseline via --expected. const hostSpec = pkg.dependencies?.['@deepseek-ai/dsh'] ?? pkg.peerDependencies?.['@deepseek-ai/dsh']; if (typeof hostSpec !== 'string') { throw new Error('DSHX requires an @deepseek-ai/dsh dependency or peerDependency host contract'); @@ -31,10 +52,24 @@ const exactCandidates = [ .map(([, value]) => value) ].filter((value) => typeof value === 'string' && exactVersion.test(value)); const uniqueCandidates = [...new Set(exactCandidates)]; -if (uniqueCandidates.length !== 1) { - throw new Error(`DSHX requires one exact tested DSH release baseline; found ${JSON.stringify(uniqueCandidates)}`); + +let expected = expectedOverride; +if (expected != null) { + if (!exactVersion.test(expected)) { + throw new Error(`--expected must be one exact DSH release version, got ${JSON.stringify(expected)}`); + } + if (uniqueCandidates.length > 1 || (uniqueCandidates.length === 1 && uniqueCandidates[0] !== expected)) { + throw new Error( + `DSHX manifest baseline conflicts with explicit tested DSH release ${expected}; found ${JSON.stringify(uniqueCandidates)}` + ); + } +} else { + if (uniqueCandidates.length !== 1) { + throw new Error(`DSHX requires one exact tested DSH release baseline; found ${JSON.stringify(uniqueCandidates)}`); + } + [expected] = uniqueCandidates; } -const expected = uniqueCandidates[0]; + if (hostSpec !== expected && !hostSpec.includes(expected)) { throw new Error(`@deepseek-ai/dsh host range ${hostSpec} does not include tested baseline ${expected}`); } From 1f66125248bb8ab1c23c9c440f2eb99ae45cf4ae Mon Sep 17 00:00:00 2001 From: code-new-bie <403466121@qq.com> Date: Fri, 28 Aug 2026 15:24:04 +0800 Subject: [PATCH 58/60] test(platform): canonicalize profile bootstrap path assertion --- test/dshx-profile-bootstrap.test.mjs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/dshx-profile-bootstrap.test.mjs b/test/dshx-profile-bootstrap.test.mjs index bcaa958a..68fde19f 100644 --- a/test/dshx-profile-bootstrap.test.mjs +++ b/test/dshx-profile-bootstrap.test.mjs @@ -124,6 +124,7 @@ test('Windows npm dsh.cmd shim resolves back to the same installation JS bin wit fs.writeFileSync(cli, ''); const resolved = resolveDshInvocation(home, { PATH: prefix }, 'win32'); assert.equal(resolved.command, process.execPath); - assert.deepEqual(resolved.args, [cli]); + assert.equal(resolved.args.length, 1); + assert.equal(fs.realpathSync(resolved.args[0]), fs.realpathSync(cli)); }); }); From a7430794ff993cebacbe49bae110348297898a19 Mon Sep 17 00:00:00 2001 From: code-new-bie <403466121@qq.com> Date: Fri, 28 Aug 2026 17:36:34 +0800 Subject: [PATCH 59/60] docs(architecture): align directional-pipe comments --- cordis.patch.yml | 4 +++- src/dsh/stdio-transport.mjs | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/cordis.patch.yml b/cordis.patch.yml index 3a5b9cf4..9907ef8e 100644 --- a/cordis.patch.yml +++ b/cordis.patch.yml @@ -2,7 +2,9 @@ # `dsh --profile tui` is the application entry point. The startup row receives # the launcher's immutable cmdlineArgs snapshot; the presentation runner waits # for the Loader tree to settle, launches the pinned native TUI, and binds its -# inherited fd 3 protocol pipe directly to the live DSH Context. +# anonymous directional protocol pipes directly to the live DSH Context. Child +# fd 0 is protocol input, fd 3 preserves terminal stdin, and fd 4 is protocol +# output. # Match the official headless CLI-surface pattern: the shared module HMR row is # not part of the interactive runner. The profile launcher's watch fallback diff --git a/src/dsh/stdio-transport.mjs b/src/dsh/stdio-transport.mjs index 7d22e95b..ada89b19 100644 --- a/src/dsh/stdio-transport.mjs +++ b/src/dsh/stdio-transport.mjs @@ -23,7 +23,9 @@ function internalError(message, error) { } /** - * Start a single-client Codex app-server transport directly on process stdio. + * Start a single-client Codex app-server transport over supplied readable and + * writable streams. Production supplies the presentation child's directional + * protocol pipes; process stdio remains only the default for direct/test use. * The adapter talks only to the already-mounted DSH Context supplied by the * hosting composition; this module never boots or disposes a Harness runtime. */ From 3729f2a6e5dc6422a21875e86c64ebac3fb95297 Mon Sep 17 00:00:00 2001 From: code-new-bie <403466121@qq.com> Date: Fri, 28 Aug 2026 23:23:58 +0800 Subject: [PATCH 60/60] build(release): keep frozen lock bytes cross-platform stable --- .gitattributes | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .gitattributes diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 00000000..56d13ba4 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,3 @@ +# Release provenance hashes the reviewed lockfile bytes. Keep that identity +# stable across Windows, macOS, and Linux checkouts. +package-lock.json text eol=lf