From f248dc37732062cdb4c2f23b9b2c8f0c403a9a74 Mon Sep 17 00:00:00 2001 From: Turtle Date: Tue, 4 Aug 2026 11:38:42 +0800 Subject: [PATCH 1/5] docs: remove line numbers from subsystem catalog links --- docs/subsystems/approval.i18n.yaml | 4 +-- docs/subsystems/approval.md | 4 +-- docs/subsystems/approval.zh.md | 4 +-- docs/subsystems/bash.i18n.yaml | 4 +-- docs/subsystems/bash.md | 4 +-- docs/subsystems/bash.zh.md | 4 +-- docs/subsystems/client-modules.i18n.yaml | 4 +-- docs/subsystems/client-modules.md | 2 +- docs/subsystems/client-modules.zh.md | 2 +- docs/subsystems/code-runtime.i18n.yaml | 4 +-- docs/subsystems/code-runtime.md | 2 +- docs/subsystems/code-runtime.zh.md | 2 +- docs/subsystems/commands.i18n.yaml | 4 +-- docs/subsystems/commands.md | 4 +-- docs/subsystems/commands.zh.md | 4 +-- docs/subsystems/compaction.i18n.yaml | 4 +-- docs/subsystems/compaction.md | 4 +-- docs/subsystems/compaction.zh.md | 4 +-- docs/subsystems/core.i18n.yaml | 4 +-- docs/subsystems/core.md | 32 ++++++++--------- docs/subsystems/core.zh.md | 32 ++++++++--------- docs/subsystems/credentials.i18n.yaml | 4 +-- docs/subsystems/credentials.md | 4 +-- docs/subsystems/credentials.zh.md | 4 +-- docs/subsystems/filesystem.i18n.yaml | 4 +-- docs/subsystems/filesystem.md | 8 ++--- docs/subsystems/filesystem.zh.md | 8 ++--- docs/subsystems/goal.i18n.yaml | 4 +-- docs/subsystems/goal.md | 4 +-- docs/subsystems/goal.zh.md | 4 +-- docs/subsystems/http-server.i18n.yaml | 4 +-- docs/subsystems/http-server.md | 2 +- docs/subsystems/http-server.zh.md | 2 +- docs/subsystems/invariants.i18n.yaml | 4 +-- docs/subsystems/invariants.md | 2 +- docs/subsystems/invariants.zh.md | 2 +- docs/subsystems/llm-streaming.i18n.yaml | 4 +-- docs/subsystems/llm-streaming.md | 6 ++-- docs/subsystems/llm-streaming.zh.md | 6 ++-- docs/subsystems/permission.i18n.yaml | 4 +-- docs/subsystems/permission.md | 2 +- docs/subsystems/permission.zh.md | 2 +- docs/subsystems/persistence.i18n.yaml | 4 +-- docs/subsystems/persistence.md | 2 +- docs/subsystems/persistence.zh.md | 2 +- docs/subsystems/plan.i18n.yaml | 4 +-- docs/subsystems/plan.md | 2 +- docs/subsystems/plan.zh.md | 2 +- docs/subsystems/pty.i18n.yaml | 4 +-- docs/subsystems/pty.md | 2 +- docs/subsystems/pty.zh.md | 2 +- docs/subsystems/sandbox.i18n.yaml | 4 +-- docs/subsystems/sandbox.md | 4 +-- docs/subsystems/sandbox.zh.md | 4 +-- docs/subsystems/session-projection.i18n.yaml | 4 +-- docs/subsystems/session-projection.md | 4 +-- docs/subsystems/session-projection.zh.md | 4 +-- docs/subsystems/session-query.i18n.yaml | 4 +-- docs/subsystems/session-query.md | 2 +- docs/subsystems/session-query.zh.md | 2 +- docs/subsystems/session-reference.i18n.yaml | 4 +-- docs/subsystems/session-reference.md | 2 +- docs/subsystems/session-reference.zh.md | 2 +- docs/subsystems/session-title.i18n.yaml | 4 +-- docs/subsystems/session-title.md | 2 +- docs/subsystems/session-title.zh.md | 2 +- docs/subsystems/session.i18n.yaml | 4 +-- docs/subsystems/session.md | 10 +++--- docs/subsystems/session.zh.md | 10 +++--- docs/subsystems/settings.i18n.yaml | 4 +-- docs/subsystems/settings.md | 6 ++-- docs/subsystems/settings.zh.md | 6 ++-- docs/subsystems/skills.i18n.yaml | 4 +-- docs/subsystems/skills.md | 4 +-- docs/subsystems/skills.zh.md | 4 +-- docs/subsystems/spill.i18n.yaml | 4 +-- docs/subsystems/spill.md | 2 +- docs/subsystems/spill.zh.md | 2 +- docs/subsystems/storage.i18n.yaml | 4 +-- docs/subsystems/storage.md | 6 ++-- docs/subsystems/storage.zh.md | 6 ++-- docs/subsystems/subagent.i18n.yaml | 4 +-- docs/subsystems/subagent.md | 10 +++--- docs/subsystems/subagent.zh.md | 10 +++--- docs/subsystems/subprocess.i18n.yaml | 4 +-- docs/subsystems/subprocess.md | 4 +-- docs/subsystems/subprocess.zh.md | 4 +-- docs/subsystems/system-prompt.i18n.yaml | 4 +-- docs/subsystems/system-prompt.md | 6 ++-- docs/subsystems/system-prompt.zh.md | 6 ++-- docs/subsystems/tasks.i18n.yaml | 4 +-- docs/subsystems/tasks.md | 2 +- docs/subsystems/tasks.zh.md | 2 +- docs/subsystems/telemetry.i18n.yaml | 4 +-- docs/subsystems/telemetry.md | 4 +-- docs/subsystems/telemetry.zh.md | 4 +-- docs/subsystems/token-meter.i18n.yaml | 4 +-- docs/subsystems/token-meter.md | 2 +- docs/subsystems/token-meter.zh.md | 2 +- docs/subsystems/tools.i18n.yaml | 4 +-- docs/subsystems/tools.md | 14 ++++---- docs/subsystems/tools.zh.md | 14 ++++---- docs/subsystems/typert.i18n.yaml | 4 +-- docs/subsystems/typert.md | 4 +-- docs/subsystems/typert.zh.md | 4 +-- docs/subsystems/user-interaction.i18n.yaml | 4 +-- docs/subsystems/user-interaction.md | 2 +- docs/subsystems/user-interaction.zh.md | 2 +- docs/subsystems/web.i18n.yaml | 4 +-- docs/subsystems/web.md | 2 +- docs/subsystems/web.zh.md | 2 +- docs/subsystems/workflow.i18n.yaml | 4 +-- docs/subsystems/workflow.md | 14 ++++---- docs/subsystems/workflow.zh.md | 14 ++++---- docs/subsystems/workspace.i18n.yaml | 4 +-- docs/subsystems/workspace.md | 4 +-- docs/subsystems/workspace.zh.md | 4 +-- .../typert/generator/src/cordis-catalog.ts | 10 ++++-- .../generator/tests/cordis-catalog.spec.ts | 34 +++++++++++++++++++ 119 files changed, 316 insertions(+), 276 deletions(-) diff --git a/docs/subsystems/approval.i18n.yaml b/docs/subsystems/approval.i18n.yaml index 088b30ff32..7c24a8f465 100644 --- a/docs/subsystems/approval.i18n.yaml +++ b/docs/subsystems/approval.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write docs/subsystems/approval.md -approval.md: 660ced6d75886bbea41985fd1f357bf92e8a7838 -approval.zh.md: 56975914098978af99580694ca19f20a02ed4022 +approval.md: 6a722c7dcdb78927a23b544f097c60ef412857c3 +approval.zh.md: 673d2f704766e5d2b1c6c28dceedc03d54a98052 diff --git a/docs/subsystems/approval.md b/docs/subsystems/approval.md index 660ced6d75..6a722c7dcd 100644 --- a/docs/subsystems/approval.md +++ b/docs/subsystems/approval.md @@ -141,7 +141,7 @@ overrideOf(session: Session): ApprovalPolicy | undefined Types: [Agent](core.md) · [Session](session.md) -Source: [`packages/interaction/user-approval/src/index.ts:192`](../../packages/interaction/user-approval/src/index.ts) +Source: [`packages/interaction/user-approval/src/index.ts`](../../packages/interaction/user-approval/src/index.ts) @@ -166,5 +166,5 @@ Ask composed answerers for one decision. Return an outcome to claim the request Types: [Scoped](scope.md) -Source: [`packages/interaction/user-approval/src/index.ts:30`](../../packages/interaction/user-approval/src/index.ts) +Source: [`packages/interaction/user-approval/src/index.ts`](../../packages/interaction/user-approval/src/index.ts) diff --git a/docs/subsystems/approval.zh.md b/docs/subsystems/approval.zh.md index 5697591409..673d2f7047 100644 --- a/docs/subsystems/approval.zh.md +++ b/docs/subsystems/approval.zh.md @@ -141,7 +141,7 @@ overrideOf(session: Session): ApprovalPolicy | undefined Types: [Agent](core.md) · [Session](session.md) -Source: [`packages/interaction/user-approval/src/index.ts:192`](../../packages/interaction/user-approval/src/index.ts) +Source: [`packages/interaction/user-approval/src/index.ts`](../../packages/interaction/user-approval/src/index.ts) @@ -166,5 +166,5 @@ Ask composed answerers for one decision. Return an outcome to claim the request Types: [Scoped](scope.md) -Source: [`packages/interaction/user-approval/src/index.ts:30`](../../packages/interaction/user-approval/src/index.ts) +Source: [`packages/interaction/user-approval/src/index.ts`](../../packages/interaction/user-approval/src/index.ts) diff --git a/docs/subsystems/bash.i18n.yaml b/docs/subsystems/bash.i18n.yaml index dbfc52bf6e..02b4147beb 100644 --- a/docs/subsystems/bash.i18n.yaml +++ b/docs/subsystems/bash.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write docs/subsystems/bash.md -bash.md: d2797c1e3ff73fe8ecb5a053ed4a1d13b13298dd -bash.zh.md: b38a4f332978e94d2945f5fa49b38e8d7df8c9ca +bash.md: d66cbbccff97c2aab22cc0c415afeabeb3741684 +bash.zh.md: 6f016f8cf9024921bf46ebe3fd2de7451aef4998 diff --git a/docs/subsystems/bash.md b/docs/subsystems/bash.md index d2797c1e3f..d66cbbccff 100644 --- a/docs/subsystems/bash.md +++ b/docs/subsystems/bash.md @@ -266,7 +266,7 @@ abstract run(spec: BashExecSpec): Promise abstract start(spec: BashExecSpec): BashProcess ``` -Source: [`packages/bash/bash/src/index.ts:53`](../../packages/bash/bash/src/index.ts) +Source: [`packages/bash/bash/src/index.ts`](../../packages/bash/bash/src/index.ts) @@ -299,5 +299,5 @@ list(): BashEnvVariableInfo[] Types: [DshEnvironment](subprocess.md) · [ToolExecution](tools.md) -Source: [`packages/bash/bash-env/src/index.ts:89`](../../packages/bash/bash-env/src/index.ts) +Source: [`packages/bash/bash-env/src/index.ts`](../../packages/bash/bash-env/src/index.ts) diff --git a/docs/subsystems/bash.zh.md b/docs/subsystems/bash.zh.md index b38a4f3329..6f016f8cf9 100644 --- a/docs/subsystems/bash.zh.md +++ b/docs/subsystems/bash.zh.md @@ -266,7 +266,7 @@ abstract run(spec: BashExecSpec): Promise abstract start(spec: BashExecSpec): BashProcess ``` -Source: [`packages/bash/bash/src/index.ts:53`](../../packages/bash/bash/src/index.ts) +Source: [`packages/bash/bash/src/index.ts`](../../packages/bash/bash/src/index.ts) @@ -299,5 +299,5 @@ list(): BashEnvVariableInfo[] Types: [DshEnvironment](subprocess.md) · [ToolExecution](tools.md) -Source: [`packages/bash/bash-env/src/index.ts:89`](../../packages/bash/bash-env/src/index.ts) +Source: [`packages/bash/bash-env/src/index.ts`](../../packages/bash/bash-env/src/index.ts) diff --git a/docs/subsystems/client-modules.i18n.yaml b/docs/subsystems/client-modules.i18n.yaml index 8c320d18e6..6239d4724c 100644 --- a/docs/subsystems/client-modules.i18n.yaml +++ b/docs/subsystems/client-modules.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write docs/subsystems/client-modules.md -client-modules.md: 808fa62b2e5a4351b1dc98bbe4f3d2af63c9dd2b -client-modules.zh.md: dcab60bea7c54770cc5e6032afb39d6dd189d037 +client-modules.md: ccf18d4f217bc4795ea73490a9d009f6292f6c8b +client-modules.zh.md: 4ee3c7461e9378f6f6a1aaac3d839e15eeb4109a diff --git a/docs/subsystems/client-modules.md b/docs/subsystems/client-modules.md index 808fa62b2e..ccf18d4f21 100644 --- a/docs/subsystems/client-modules.md +++ b/docs/subsystems/client-modules.md @@ -114,5 +114,5 @@ onRebuilt(listener: (id: string, rev: string) => void): () => void onGraphChanged(listener: () => void): () => void ``` -Source: [`packages/client/modules/src/index.ts:184`](../../packages/client/modules/src/index.ts) +Source: [`packages/client/modules/src/index.ts`](../../packages/client/modules/src/index.ts) diff --git a/docs/subsystems/client-modules.zh.md b/docs/subsystems/client-modules.zh.md index dcab60bea7..4ee3c7461e 100644 --- a/docs/subsystems/client-modules.zh.md +++ b/docs/subsystems/client-modules.zh.md @@ -114,5 +114,5 @@ onRebuilt(listener: (id: string, rev: string) => void): () => void onGraphChanged(listener: () => void): () => void ``` -Source: [`packages/client/modules/src/index.ts:184`](../../packages/client/modules/src/index.ts) +Source: [`packages/client/modules/src/index.ts`](../../packages/client/modules/src/index.ts) diff --git a/docs/subsystems/code-runtime.i18n.yaml b/docs/subsystems/code-runtime.i18n.yaml index 47783d5f77..2ac82dad56 100644 --- a/docs/subsystems/code-runtime.i18n.yaml +++ b/docs/subsystems/code-runtime.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write docs/subsystems/code-runtime.md -code-runtime.md: 6d3fa7fa72891897155cb9c611c7aa472629de4f -code-runtime.zh.md: 47516c7d21c24399498a05410ab9a46b61736fb4 +code-runtime.md: a82d79cf231e664caa84f4967dfca0551782ae20 +code-runtime.zh.md: 62f47d14133f13dc0016a8db6b1c8077f7a557f1 diff --git a/docs/subsystems/code-runtime.md b/docs/subsystems/code-runtime.md index 6d3fa7fa72..a82d79cf23 100644 --- a/docs/subsystems/code-runtime.md +++ b/docs/subsystems/code-runtime.md @@ -187,5 +187,5 @@ Registers one `ctx.codeRuntime` implementation. Program, budget, abort, and subs abstract run(request: CodeRunRequest): Promise ``` -Source: [`packages/code-runtime/code-runtime/src/index.ts:102`](../../packages/code-runtime/code-runtime/src/index.ts) +Source: [`packages/code-runtime/code-runtime/src/index.ts`](../../packages/code-runtime/code-runtime/src/index.ts) diff --git a/docs/subsystems/code-runtime.zh.md b/docs/subsystems/code-runtime.zh.md index 47516c7d21..62f47d1413 100644 --- a/docs/subsystems/code-runtime.zh.md +++ b/docs/subsystems/code-runtime.zh.md @@ -187,5 +187,5 @@ Registers one `ctx.codeRuntime` implementation. Program, budget, abort, and subs abstract run(request: CodeRunRequest): Promise ``` -Source: [`packages/code-runtime/code-runtime/src/index.ts:102`](../../packages/code-runtime/code-runtime/src/index.ts) +Source: [`packages/code-runtime/code-runtime/src/index.ts`](../../packages/code-runtime/code-runtime/src/index.ts) diff --git a/docs/subsystems/commands.i18n.yaml b/docs/subsystems/commands.i18n.yaml index 32c5f15c15..f19e2e690d 100644 --- a/docs/subsystems/commands.i18n.yaml +++ b/docs/subsystems/commands.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write docs/subsystems/commands.md -commands.md: 5e280d659c2a74b3d8ba20f362922e9eb4e0b84c -commands.zh.md: 24f099d1926f7dba45122bdc53c23a4274e3f507 +commands.md: 7bbe7320886c0ec2346491d2dfe9fa2686a6be80 +commands.zh.md: 06d4e15ffb21908163b07de8152024e624737db0 diff --git a/docs/subsystems/commands.md b/docs/subsystems/commands.md index 5e280d659c..7bbe732088 100644 --- a/docs/subsystems/commands.md +++ b/docs/subsystems/commands.md @@ -161,7 +161,7 @@ async execute( agent: Agent, line: string, signal: AbortSignal, ): Promise @@ -183,5 +183,5 @@ A command was registered or unregistered. This is an unfiltered registry notific 'commands/change'(): void ``` -Source: [`packages/interaction/commands/src/index.ts:134`](../../packages/interaction/commands/src/index.ts) +Source: [`packages/interaction/commands/src/index.ts`](../../packages/interaction/commands/src/index.ts) diff --git a/docs/subsystems/commands.zh.md b/docs/subsystems/commands.zh.md index 24f099d192..06d4e15ffb 100644 --- a/docs/subsystems/commands.zh.md +++ b/docs/subsystems/commands.zh.md @@ -161,7 +161,7 @@ async execute( agent: Agent, line: string, signal: AbortSignal, ): Promise @@ -183,5 +183,5 @@ A command was registered or unregistered. This is an unfiltered registry notific 'commands/change'(): void ``` -Source: [`packages/interaction/commands/src/index.ts:134`](../../packages/interaction/commands/src/index.ts) +Source: [`packages/interaction/commands/src/index.ts`](../../packages/interaction/commands/src/index.ts) diff --git a/docs/subsystems/compaction.i18n.yaml b/docs/subsystems/compaction.i18n.yaml index d2fe7303fc..ae26b315db 100644 --- a/docs/subsystems/compaction.i18n.yaml +++ b/docs/subsystems/compaction.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write docs/subsystems/compaction.md -compaction.md: fdff28ac2ec83966a03050ba8d54fe0ee26c4fc6 -compaction.zh.md: e4227320d9829cac695dc4ba0c5779086f77194b +compaction.md: ffdb39fb4a8a304a9fe97afa6d182b15f0d108d3 +compaction.zh.md: b4d85583f30769afa738119eba13606fa2bd1415 diff --git a/docs/subsystems/compaction.md b/docs/subsystems/compaction.md index fdff28ac2e..ffdb39fb4a 100644 --- a/docs/subsystems/compaction.md +++ b/docs/subsystems/compaction.md @@ -192,7 +192,7 @@ abstract compactRegion( start: number, end: number, agent: CompactAgentContext, Types: [CommandId](commands.md) -Source: [`packages/compact/compact/src/index.ts:96`](../../packages/compact/compact/src/index.ts) +Source: [`packages/compact/compact/src/index.ts`](../../packages/compact/compact/src/index.ts) @@ -234,5 +234,5 @@ pruneSession(session: Session): PruneResult Types: [ContentBlock](llm-streaming.md) · [Session](session.md) -Source: [`packages/compact/compact-tool-result-prune/src/index.ts:44`](../../packages/compact/compact-tool-result-prune/src/index.ts) +Source: [`packages/compact/compact-tool-result-prune/src/index.ts`](../../packages/compact/compact-tool-result-prune/src/index.ts) diff --git a/docs/subsystems/compaction.zh.md b/docs/subsystems/compaction.zh.md index e4227320d9..b4d85583f3 100644 --- a/docs/subsystems/compaction.zh.md +++ b/docs/subsystems/compaction.zh.md @@ -192,7 +192,7 @@ abstract compactRegion( start: number, end: number, agent: CompactAgentContext, Types: [CommandId](commands.md) -Source: [`packages/compact/compact/src/index.ts:96`](../../packages/compact/compact/src/index.ts) +Source: [`packages/compact/compact/src/index.ts`](../../packages/compact/compact/src/index.ts) @@ -234,5 +234,5 @@ pruneSession(session: Session): PruneResult Types: [ContentBlock](llm-streaming.md) · [Session](session.md) -Source: [`packages/compact/compact-tool-result-prune/src/index.ts:44`](../../packages/compact/compact-tool-result-prune/src/index.ts) +Source: [`packages/compact/compact-tool-result-prune/src/index.ts`](../../packages/compact/compact-tool-result-prune/src/index.ts) diff --git a/docs/subsystems/core.i18n.yaml b/docs/subsystems/core.i18n.yaml index 70ceac3b11..577a6e0f8f 100644 --- a/docs/subsystems/core.i18n.yaml +++ b/docs/subsystems/core.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write docs/subsystems/core.md -core.md: 27c4359e360223d336cd94695bb45a79f0fd370c -core.zh.md: 4e7519665b6d9efb8075546d93325debd961905d +core.md: 468f92623c4a1368b02da30a39a8e35f8b13b5fa +core.zh.md: db940e68a876b70fc5a2f639db981ed5def53357 diff --git a/docs/subsystems/core.md b/docs/subsystems/core.md index 27c4359e36..468f92623c 100644 --- a/docs/subsystems/core.md +++ b/docs/subsystems/core.md @@ -336,7 +336,7 @@ currentSelection(): ModelSelection async saveSelection(next: ModelSelection): Promise ``` -Source: [`packages/core/agent-default-model/src/index.ts:64`](../../packages/core/agent-default-model/src/index.ts) +Source: [`packages/core/agent-default-model/src/index.ts`](../../packages/core/agent-default-model/src/index.ts) @@ -375,7 +375,7 @@ async resume(ownerCtx: Context, options: ResumeAgentOptions): Promise @@ -547,7 +547,7 @@ list(): Agent[] roots(): Agent[] ``` -Source: [`packages/core/agent/src/index.ts:254`](../../packages/core/agent/src/index.ts) +Source: [`packages/core/agent/src/index.ts`](../../packages/core/agent/src/index.ts) @@ -575,7 +575,7 @@ A fully configured agent and live session were published. Setup is composition-o Types: [Scoped](scope.md) -Source: [`packages/core/agent/src/runtime-types.ts:159`](../../packages/core/agent/src/runtime-types.ts) +Source: [`packages/core/agent/src/runtime-types.ts`](../../packages/core/agent/src/runtime-types.ts) @@ -597,7 +597,7 @@ An agent left the registry; AgentLoop emits this after driver quiescence and sco Types: [Scoped](scope.md) -Source: [`packages/core/agent/src/runtime-types.ts:168`](../../packages/core/agent/src/runtime-types.ts) +Source: [`packages/core/agent/src/runtime-types.ts`](../../packages/core/agent/src/runtime-types.ts) @@ -621,7 +621,7 @@ A step or turn errored. The machine reports a failure here even when the error h Types: [Scoped](scope.md) -Source: [`packages/core/agent/src/runtime-types.ts:290`](../../packages/core/agent/src/runtime-types.ts) +Source: [`packages/core/agent/src/runtime-types.ts`](../../packages/core/agent/src/runtime-types.ts) @@ -645,7 +645,7 @@ One message left the inbox inside its open turn. If the proposed step is rejecte Types: [Scoped](scope.md) · [UserMessage](session.md) -Source: [`packages/core/agent/src/runtime-types.ts:197`](../../packages/core/agent/src/runtime-types.ts) +Source: [`packages/core/agent/src/runtime-types.ts`](../../packages/core/agent/src/runtime-types.ts) @@ -666,7 +666,7 @@ One message was discarded from the live inbox. Types: [Scoped](scope.md) · [UserMessage](session.md) -Source: [`packages/core/agent/src/runtime-types.ts:205`](../../packages/core/agent/src/runtime-types.ts) +Source: [`packages/core/agent/src/runtime-types.ts`](../../packages/core/agent/src/runtime-types.ts) @@ -687,7 +687,7 @@ One message entered the live inbox. Types: [Scoped](scope.md) · [UserMessage](session.md) -Source: [`packages/core/agent/src/runtime-types.ts:186`](../../packages/core/agent/src/runtime-types.ts) +Source: [`packages/core/agent/src/runtime-types.ts`](../../packages/core/agent/src/runtime-types.ts) @@ -712,7 +712,7 @@ Reject a proposed step or replace the messages that enter it. Calling `next()` p Types: [Scoped](scope.md) · [UserMessage](session.md) -Source: [`packages/core/agent/src/runtime-types.ts:231`](../../packages/core/agent/src/runtime-types.ts) +Source: [`packages/core/agent/src/runtime-types.ts`](../../packages/core/agent/src/runtime-types.ts) @@ -738,7 +738,7 @@ Replace the frozen call configuration. `await next()` yields the config the mach Types: [LlmCallConfig](llm-streaming.md) · [Scoped](scope.md) -Source: [`packages/core/agent/src/runtime-types.ts:244`](../../packages/core/agent/src/runtime-types.ts) +Source: [`packages/core/agent/src/runtime-types.ts`](../../packages/core/agent/src/runtime-types.ts) @@ -767,7 +767,7 @@ Handle one failed model-request attempt before the loop retries or closes its st Types: [LlmFailure](llm-streaming.md) · [ResolvedRetryPolicy](llm-streaming.md) · [Scoped](scope.md) -Source: [`packages/core/agent/src/runtime-types.ts:260`](../../packages/core/agent/src/runtime-types.ts) +Source: [`packages/core/agent/src/runtime-types.ts`](../../packages/core/agent/src/runtime-types.ts) @@ -791,7 +791,7 @@ The session lifecycle began, once before the first turn. Use `agent.inject()` to Types: [Scoped](scope.md) -Source: [`packages/core/agent/src/runtime-types.ts:217`](../../packages/core/agent/src/runtime-types.ts) +Source: [`packages/core/agent/src/runtime-types.ts`](../../packages/core/agent/src/runtime-types.ts) @@ -814,7 +814,7 @@ Agent status changed (`idle` ⇄ `running`). A waking delivery enters `running` Types: [Scoped](scope.md) -Source: [`packages/core/agent/src/runtime-types.ts:178`](../../packages/core/agent/src/runtime-types.ts) +Source: [`packages/core/agent/src/runtime-types.ts`](../../packages/core/agent/src/runtime-types.ts) @@ -845,7 +845,7 @@ The turn is about to close: the model owes no response (no live tool calls, no f Types: [Scoped](scope.md) -Source: [`packages/core/agent/src/runtime-types.ts:278`](../../packages/core/agent/src/runtime-types.ts) +Source: [`packages/core/agent/src/runtime-types.ts`](../../packages/core/agent/src/runtime-types.ts) @@ -870,5 +870,5 @@ A declarative agent entry failed before it could publish a live agent. Consumers 'agent-loop/config-start-failed'(payload: { sessionId: SessionId; error: unknown }): void ``` -Source: [`packages/core/agent-loop/src/index.ts:182`](../../packages/core/agent-loop/src/index.ts) +Source: [`packages/core/agent-loop/src/index.ts`](../../packages/core/agent-loop/src/index.ts) diff --git a/docs/subsystems/core.zh.md b/docs/subsystems/core.zh.md index 4e7519665b..db940e68a8 100644 --- a/docs/subsystems/core.zh.md +++ b/docs/subsystems/core.zh.md @@ -344,7 +344,7 @@ currentSelection(): ModelSelection async saveSelection(next: ModelSelection): Promise ``` -Source: [`packages/core/agent-default-model/src/index.ts:64`](../../packages/core/agent-default-model/src/index.ts) +Source: [`packages/core/agent-default-model/src/index.ts`](../../packages/core/agent-default-model/src/index.ts) @@ -383,7 +383,7 @@ async resume(ownerCtx: Context, options: ResumeAgentOptions): Promise @@ -555,7 +555,7 @@ list(): Agent[] roots(): Agent[] ``` -Source: [`packages/core/agent/src/index.ts:254`](../../packages/core/agent/src/index.ts) +Source: [`packages/core/agent/src/index.ts`](../../packages/core/agent/src/index.ts) @@ -583,7 +583,7 @@ A fully configured agent and live session were published. Setup is composition-o Types: [Scoped](scope.md) -Source: [`packages/core/agent/src/runtime-types.ts:159`](../../packages/core/agent/src/runtime-types.ts) +Source: [`packages/core/agent/src/runtime-types.ts`](../../packages/core/agent/src/runtime-types.ts) @@ -605,7 +605,7 @@ An agent left the registry; AgentLoop emits this after driver quiescence and sco Types: [Scoped](scope.md) -Source: [`packages/core/agent/src/runtime-types.ts:168`](../../packages/core/agent/src/runtime-types.ts) +Source: [`packages/core/agent/src/runtime-types.ts`](../../packages/core/agent/src/runtime-types.ts) @@ -629,7 +629,7 @@ A step or turn errored. The machine reports a failure here even when the error h Types: [Scoped](scope.md) -Source: [`packages/core/agent/src/runtime-types.ts:290`](../../packages/core/agent/src/runtime-types.ts) +Source: [`packages/core/agent/src/runtime-types.ts`](../../packages/core/agent/src/runtime-types.ts) @@ -653,7 +653,7 @@ One message left the inbox inside its open turn. If the proposed step is rejecte Types: [Scoped](scope.md) · [UserMessage](session.md) -Source: [`packages/core/agent/src/runtime-types.ts:197`](../../packages/core/agent/src/runtime-types.ts) +Source: [`packages/core/agent/src/runtime-types.ts`](../../packages/core/agent/src/runtime-types.ts) @@ -674,7 +674,7 @@ One message was discarded from the live inbox. Types: [Scoped](scope.md) · [UserMessage](session.md) -Source: [`packages/core/agent/src/runtime-types.ts:205`](../../packages/core/agent/src/runtime-types.ts) +Source: [`packages/core/agent/src/runtime-types.ts`](../../packages/core/agent/src/runtime-types.ts) @@ -695,7 +695,7 @@ One message entered the live inbox. Types: [Scoped](scope.md) · [UserMessage](session.md) -Source: [`packages/core/agent/src/runtime-types.ts:186`](../../packages/core/agent/src/runtime-types.ts) +Source: [`packages/core/agent/src/runtime-types.ts`](../../packages/core/agent/src/runtime-types.ts) @@ -720,7 +720,7 @@ Reject a proposed step or replace the messages that enter it. Calling `next()` p Types: [Scoped](scope.md) · [UserMessage](session.md) -Source: [`packages/core/agent/src/runtime-types.ts:231`](../../packages/core/agent/src/runtime-types.ts) +Source: [`packages/core/agent/src/runtime-types.ts`](../../packages/core/agent/src/runtime-types.ts) @@ -746,7 +746,7 @@ Replace the frozen call configuration. `await next()` yields the config the mach Types: [LlmCallConfig](llm-streaming.md) · [Scoped](scope.md) -Source: [`packages/core/agent/src/runtime-types.ts:244`](../../packages/core/agent/src/runtime-types.ts) +Source: [`packages/core/agent/src/runtime-types.ts`](../../packages/core/agent/src/runtime-types.ts) @@ -775,7 +775,7 @@ Handle one failed model-request attempt before the loop retries or closes its st Types: [LlmFailure](llm-streaming.md) · [ResolvedRetryPolicy](llm-streaming.md) · [Scoped](scope.md) -Source: [`packages/core/agent/src/runtime-types.ts:260`](../../packages/core/agent/src/runtime-types.ts) +Source: [`packages/core/agent/src/runtime-types.ts`](../../packages/core/agent/src/runtime-types.ts) @@ -799,7 +799,7 @@ The session lifecycle began, once before the first turn. Use `agent.inject()` to Types: [Scoped](scope.md) -Source: [`packages/core/agent/src/runtime-types.ts:217`](../../packages/core/agent/src/runtime-types.ts) +Source: [`packages/core/agent/src/runtime-types.ts`](../../packages/core/agent/src/runtime-types.ts) @@ -822,7 +822,7 @@ Agent status changed (`idle` ⇄ `running`). A waking delivery enters `running` Types: [Scoped](scope.md) -Source: [`packages/core/agent/src/runtime-types.ts:178`](../../packages/core/agent/src/runtime-types.ts) +Source: [`packages/core/agent/src/runtime-types.ts`](../../packages/core/agent/src/runtime-types.ts) @@ -853,7 +853,7 @@ The turn is about to close: the model owes no response (no live tool calls, no f Types: [Scoped](scope.md) -Source: [`packages/core/agent/src/runtime-types.ts:278`](../../packages/core/agent/src/runtime-types.ts) +Source: [`packages/core/agent/src/runtime-types.ts`](../../packages/core/agent/src/runtime-types.ts) @@ -878,5 +878,5 @@ A declarative agent entry failed before it could publish a live agent. Consumers 'agent-loop/config-start-failed'(payload: { sessionId: SessionId; error: unknown }): void ``` -Source: [`packages/core/agent-loop/src/index.ts:182`](../../packages/core/agent-loop/src/index.ts) +Source: [`packages/core/agent-loop/src/index.ts`](../../packages/core/agent-loop/src/index.ts) diff --git a/docs/subsystems/credentials.i18n.yaml b/docs/subsystems/credentials.i18n.yaml index 7e9e057c75..e73e4d77db 100644 --- a/docs/subsystems/credentials.i18n.yaml +++ b/docs/subsystems/credentials.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write docs/subsystems/credentials.md -credentials.md: 0bc2224ac039addc795d3806e8c85004f2bb84a7 -credentials.zh.md: f236b0b2daef85784308f10dbcfc67db84c42234 +credentials.md: a7a93718bfb942bec51ee0d63e5aac6771a57f87 +credentials.zh.md: 3450ba82da1c749ea4b13e699e7ccba4e108626a diff --git a/docs/subsystems/credentials.md b/docs/subsystems/credentials.md index 0bc2224ac0..a7a93718bf 100644 --- a/docs/subsystems/credentials.md +++ b/docs/subsystems/credentials.md @@ -101,7 +101,7 @@ abstract set(ref: CredentialRef, value: string): Promise abstract unset(ref: CredentialRef): Promise ``` -Source: [`packages/credentials/credentials/src/index.ts:77`](../../packages/credentials/credentials/src/index.ts) +Source: [`packages/credentials/credentials/src/index.ts`](../../packages/credentials/credentials/src/index.ts) @@ -129,5 +129,5 @@ Committed change to a provider-managed credential source: a `set`, an `unset`, o 'credentials/updated'(ref: CredentialRef): void ``` -Source: [`packages/credentials/credentials/src/index.ts:67`](../../packages/credentials/credentials/src/index.ts) +Source: [`packages/credentials/credentials/src/index.ts`](../../packages/credentials/credentials/src/index.ts) diff --git a/docs/subsystems/credentials.zh.md b/docs/subsystems/credentials.zh.md index f236b0b2da..3450ba82da 100644 --- a/docs/subsystems/credentials.zh.md +++ b/docs/subsystems/credentials.zh.md @@ -101,7 +101,7 @@ abstract set(ref: CredentialRef, value: string): Promise abstract unset(ref: CredentialRef): Promise ``` -Source: [`packages/credentials/credentials/src/index.ts:77`](../../packages/credentials/credentials/src/index.ts) +Source: [`packages/credentials/credentials/src/index.ts`](../../packages/credentials/credentials/src/index.ts) @@ -129,5 +129,5 @@ Committed change to a provider-managed credential source: a `set`, an `unset`, o 'credentials/updated'(ref: CredentialRef): void ``` -Source: [`packages/credentials/credentials/src/index.ts:67`](../../packages/credentials/credentials/src/index.ts) +Source: [`packages/credentials/credentials/src/index.ts`](../../packages/credentials/credentials/src/index.ts) diff --git a/docs/subsystems/filesystem.i18n.yaml b/docs/subsystems/filesystem.i18n.yaml index fac61bde63..ca09a3aa3f 100644 --- a/docs/subsystems/filesystem.i18n.yaml +++ b/docs/subsystems/filesystem.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write docs/subsystems/filesystem.md -filesystem.md: e0edad514b0c4d9108b18cc0b472600b29024c51 -filesystem.zh.md: 81c2d87b6a96740c7a99449a27c16331f5a0645a +filesystem.md: 850ad8ccc43c7fcb93006c7d0ed10c26e77f1763 +filesystem.zh.md: e0a2d4b6277ca6f9e766a7101ffbd1a5f82b4f6d diff --git a/docs/subsystems/filesystem.md b/docs/subsystems/filesystem.md index e0edad514b..850ad8ccc4 100644 --- a/docs/subsystems/filesystem.md +++ b/docs/subsystems/filesystem.md @@ -413,7 +413,7 @@ abstract editText( target: FsTarget, edit: FsEditRequest, expected?: { version: Types: [SandboxExecutionPolicy](sandbox.md) -Source: [`packages/fs/fs/src/index.ts:86`](../../packages/fs/fs/src/index.ts) +Source: [`packages/fs/fs/src/index.ts`](../../packages/fs/fs/src/index.ts) @@ -436,7 +436,7 @@ Single-slot decision for the next FileSystem.editText. Calling `next()` yields a 'fs/edit-intent'(target: FsTarget, actor: object | undefined, next: () => { version: FsVersion } | undefined | Promise<{ version: FsVersion } | undefined>): Promise<{ version: FsVersion } | undefined> ``` -Source: [`packages/fs/fs/src/index.ts:66`](../../packages/fs/fs/src/index.ts) +Source: [`packages/fs/fs/src/index.ts`](../../packages/fs/fs/src/index.ts) @@ -457,7 +457,7 @@ Record an authoritative positive or negative observation. Listeners must be sync 'fs/observed'(target: FsTarget, observation: FsObservation, actor: object | undefined): void ``` -Source: [`packages/fs/fs/src/index.ts:76`](../../packages/fs/fs/src/index.ts) +Source: [`packages/fs/fs/src/index.ts`](../../packages/fs/fs/src/index.ts) @@ -477,5 +477,5 @@ Single-slot decision for the next FileSystem.writeText. Calling `next()` yields 'fs/write-intent'(target: FsTarget, actor: object | undefined, next: () => FsWriteIntent | undefined | Promise): Promise ``` -Source: [`packages/fs/fs/src/index.ts:58`](../../packages/fs/fs/src/index.ts) +Source: [`packages/fs/fs/src/index.ts`](../../packages/fs/fs/src/index.ts) diff --git a/docs/subsystems/filesystem.zh.md b/docs/subsystems/filesystem.zh.md index 81c2d87b6a..e0a2d4b627 100644 --- a/docs/subsystems/filesystem.zh.md +++ b/docs/subsystems/filesystem.zh.md @@ -413,7 +413,7 @@ abstract editText( target: FsTarget, edit: FsEditRequest, expected?: { version: Types: [SandboxExecutionPolicy](sandbox.md) -Source: [`packages/fs/fs/src/index.ts:86`](../../packages/fs/fs/src/index.ts) +Source: [`packages/fs/fs/src/index.ts`](../../packages/fs/fs/src/index.ts) @@ -436,7 +436,7 @@ Single-slot decision for the next FileSystem.editText. Calling `next()` yields a 'fs/edit-intent'(target: FsTarget, actor: object | undefined, next: () => { version: FsVersion } | undefined | Promise<{ version: FsVersion } | undefined>): Promise<{ version: FsVersion } | undefined> ``` -Source: [`packages/fs/fs/src/index.ts:66`](../../packages/fs/fs/src/index.ts) +Source: [`packages/fs/fs/src/index.ts`](../../packages/fs/fs/src/index.ts) @@ -457,7 +457,7 @@ Record an authoritative positive or negative observation. Listeners must be sync 'fs/observed'(target: FsTarget, observation: FsObservation, actor: object | undefined): void ``` -Source: [`packages/fs/fs/src/index.ts:76`](../../packages/fs/fs/src/index.ts) +Source: [`packages/fs/fs/src/index.ts`](../../packages/fs/fs/src/index.ts) @@ -477,5 +477,5 @@ Single-slot decision for the next FileSystem.writeText. Calling `next()` yields 'fs/write-intent'(target: FsTarget, actor: object | undefined, next: () => FsWriteIntent | undefined | Promise): Promise ``` -Source: [`packages/fs/fs/src/index.ts:58`](../../packages/fs/fs/src/index.ts) +Source: [`packages/fs/fs/src/index.ts`](../../packages/fs/fs/src/index.ts) diff --git a/docs/subsystems/goal.i18n.yaml b/docs/subsystems/goal.i18n.yaml index cdd932726e..e8ddb0489b 100644 --- a/docs/subsystems/goal.i18n.yaml +++ b/docs/subsystems/goal.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write docs/subsystems/goal.md -goal.md: 6f54a5261cb44c3fda389e37cb689a00061ab241 -goal.zh.md: ea5a0fe7923648aead5e6f54ab31162a7abdb954 +goal.md: 7cddef581d15e6c8a635c62a42d413d4c17aafa9 +goal.zh.md: fbd251ed5cb97529250afc70c6e80ba4808d7b04 diff --git a/docs/subsystems/goal.md b/docs/subsystems/goal.md index 6f54a5261c..7cddef581d 100644 --- a/docs/subsystems/goal.md +++ b/docs/subsystems/goal.md @@ -247,7 +247,7 @@ block(agent: Agent, ref: GoalRef, reason: GoalBlockReason): GoalView Types: [Agent](core.md) -Source: [`packages/goal/goal/src/index.ts:183`](../../packages/goal/goal/src/index.ts) +Source: [`packages/goal/goal/src/index.ts`](../../packages/goal/goal/src/index.ts) @@ -273,5 +273,5 @@ Goal mutation accepted by one live agent. The matching `goal/change` session eve Types: [Agent](core.md) · [Scoped](scope.md) -Source: [`packages/goal/goal/src/domain.ts:114`](../../packages/goal/goal/src/domain.ts) +Source: [`packages/goal/goal/src/domain.ts`](../../packages/goal/goal/src/domain.ts) diff --git a/docs/subsystems/goal.zh.md b/docs/subsystems/goal.zh.md index ea5a0fe792..fbd251ed5c 100644 --- a/docs/subsystems/goal.zh.md +++ b/docs/subsystems/goal.zh.md @@ -247,7 +247,7 @@ block(agent: Agent, ref: GoalRef, reason: GoalBlockReason): GoalView Types: [Agent](core.md) -Source: [`packages/goal/goal/src/index.ts:183`](../../packages/goal/goal/src/index.ts) +Source: [`packages/goal/goal/src/index.ts`](../../packages/goal/goal/src/index.ts) @@ -273,5 +273,5 @@ Goal mutation accepted by one live agent. The matching `goal/change` session eve Types: [Agent](core.md) · [Scoped](scope.md) -Source: [`packages/goal/goal/src/domain.ts:114`](../../packages/goal/goal/src/domain.ts) +Source: [`packages/goal/goal/src/domain.ts`](../../packages/goal/goal/src/domain.ts) diff --git a/docs/subsystems/http-server.i18n.yaml b/docs/subsystems/http-server.i18n.yaml index 6f61102676..5c03d2668d 100644 --- a/docs/subsystems/http-server.i18n.yaml +++ b/docs/subsystems/http-server.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write docs/subsystems/http-server.md -http-server.md: b9795fe98b432b6ef5f7d01a4d3e115c809fe642 -http-server.zh.md: 8d55c48ae2882bd471ca4e64e011c7d79c4ebb40 +http-server.md: c6164be82e3b3bb85ec2239f49b0baebe7189f91 +http-server.zh.md: 726c72faa543116d38f518b56c70aefdfa19864f diff --git a/docs/subsystems/http-server.md b/docs/subsystems/http-server.md index b9795fe98b..c6164be82e 100644 --- a/docs/subsystems/http-server.md +++ b/docs/subsystems/http-server.md @@ -104,5 +104,5 @@ tapIndex(transform: (html: string) => string): () => void applyIndexTaps(html: string): string ``` -Source: [`packages/host/webserver/src/index.ts:60`](../../packages/host/webserver/src/index.ts) +Source: [`packages/host/webserver/src/index.ts`](../../packages/host/webserver/src/index.ts) diff --git a/docs/subsystems/http-server.zh.md b/docs/subsystems/http-server.zh.md index 8d55c48ae2..726c72faa5 100644 --- a/docs/subsystems/http-server.zh.md +++ b/docs/subsystems/http-server.zh.md @@ -104,5 +104,5 @@ tapIndex(transform: (html: string) => string): () => void applyIndexTaps(html: string): string ``` -Source: [`packages/host/webserver/src/index.ts:60`](../../packages/host/webserver/src/index.ts) +Source: [`packages/host/webserver/src/index.ts`](../../packages/host/webserver/src/index.ts) diff --git a/docs/subsystems/invariants.i18n.yaml b/docs/subsystems/invariants.i18n.yaml index 2ff4b67060..c19f608a3b 100644 --- a/docs/subsystems/invariants.i18n.yaml +++ b/docs/subsystems/invariants.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write docs/subsystems/invariants.md -invariants.md: ccf81f0252dd2db4eec666df6fab8c7d6a830f25 -invariants.zh.md: 046aa4a56d48fa0386fba3a51d850ab21ce5145d +invariants.md: 1fcd17292655446ee8480e290d6a4cc5f13306ea +invariants.zh.md: e705e99273fcd43fec10d17f9f886bcb3e8c8ca5 diff --git a/docs/subsystems/invariants.md b/docs/subsystems/invariants.md index ccf81f0252..1fcd172926 100644 --- a/docs/subsystems/invariants.md +++ b/docs/subsystems/invariants.md @@ -84,5 +84,5 @@ Package-owned invariant registry with global and regex-based selection. register(packageName: string, installer: InvariantInstaller): () => void ``` -Source: [`packages/support/invariants/src/index.ts:94`](../../packages/support/invariants/src/index.ts) +Source: [`packages/support/invariants/src/index.ts`](../../packages/support/invariants/src/index.ts) diff --git a/docs/subsystems/invariants.zh.md b/docs/subsystems/invariants.zh.md index 046aa4a56d..e705e99273 100644 --- a/docs/subsystems/invariants.zh.md +++ b/docs/subsystems/invariants.zh.md @@ -84,5 +84,5 @@ Package-owned invariant registry with global and regex-based selection. register(packageName: string, installer: InvariantInstaller): () => void ``` -Source: [`packages/support/invariants/src/index.ts:94`](../../packages/support/invariants/src/index.ts) +Source: [`packages/support/invariants/src/index.ts`](../../packages/support/invariants/src/index.ts) diff --git a/docs/subsystems/llm-streaming.i18n.yaml b/docs/subsystems/llm-streaming.i18n.yaml index 86ec4e3c3f..49942dab93 100644 --- a/docs/subsystems/llm-streaming.i18n.yaml +++ b/docs/subsystems/llm-streaming.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write docs/subsystems/llm-streaming.md -llm-streaming.md: 4d450c19ec2bbfacabcefc83466e67c8a6c82bd6 -llm-streaming.zh.md: 777c44eaff2b1ee6e5939e04e580d6ad34b1ad1a +llm-streaming.md: d7e0ef6ddc2e98a79d8c923ed19860dc02cfd575 +llm-streaming.zh.md: 580fd06ba616f08906516196063e8f6553396f0b diff --git a/docs/subsystems/llm-streaming.md b/docs/subsystems/llm-streaming.md index 4d450c19ec..d7e0ef6ddc 100644 --- a/docs/subsystems/llm-streaming.md +++ b/docs/subsystems/llm-streaming.md @@ -830,7 +830,7 @@ async prepareCall(config: LlmCallConfig, signal?: AbortSignal): Promise ``` -Source: [`packages/llm/llm/src/index.ts:292`](../../packages/llm/llm/src/index.ts) +Source: [`packages/llm/llm/src/index.ts`](../../packages/llm/llm/src/index.ts) @@ -855,7 +855,7 @@ The provider topology changed: an adapter registered or unregistered routes, or 'llm/adapters-updated'(): void ``` -Source: [`packages/llm/llm/src/index.ts:73`](../../packages/llm/llm/src/index.ts) +Source: [`packages/llm/llm/src/index.ts`](../../packages/llm/llm/src/index.ts) @@ -879,5 +879,5 @@ Waterfall around every streaming model call (retry, replay, routing). Bound to t 'llm/stream'(this: LlmService, options: GenerateOptions, next: () => AsyncIterable): AsyncIterable ``` -Source: [`packages/llm/llm/src/index.ts:62`](../../packages/llm/llm/src/index.ts) +Source: [`packages/llm/llm/src/index.ts`](../../packages/llm/llm/src/index.ts) diff --git a/docs/subsystems/llm-streaming.zh.md b/docs/subsystems/llm-streaming.zh.md index 777c44eaff..580fd06ba6 100644 --- a/docs/subsystems/llm-streaming.zh.md +++ b/docs/subsystems/llm-streaming.zh.md @@ -838,7 +838,7 @@ async prepareCall(config: LlmCallConfig, signal?: AbortSignal): Promise ``` -Source: [`packages/llm/llm/src/index.ts:292`](../../packages/llm/llm/src/index.ts) +Source: [`packages/llm/llm/src/index.ts`](../../packages/llm/llm/src/index.ts) @@ -863,7 +863,7 @@ The provider topology changed: an adapter registered or unregistered routes, or 'llm/adapters-updated'(): void ``` -Source: [`packages/llm/llm/src/index.ts:73`](../../packages/llm/llm/src/index.ts) +Source: [`packages/llm/llm/src/index.ts`](../../packages/llm/llm/src/index.ts) @@ -887,5 +887,5 @@ Waterfall around every streaming model call (retry, replay, routing). Bound to t 'llm/stream'(this: LlmService, options: GenerateOptions, next: () => AsyncIterable): AsyncIterable ``` -Source: [`packages/llm/llm/src/index.ts:62`](../../packages/llm/llm/src/index.ts) +Source: [`packages/llm/llm/src/index.ts`](../../packages/llm/llm/src/index.ts) diff --git a/docs/subsystems/permission.i18n.yaml b/docs/subsystems/permission.i18n.yaml index 3f9c9b533c..3644c5dbec 100644 --- a/docs/subsystems/permission.i18n.yaml +++ b/docs/subsystems/permission.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write docs/subsystems/permission.md -permission.md: 6f9a37dbb784ccbaea74056519992e40f9c07c6d -permission.zh.md: 8eda50fae09a67c41003d7a914fb139c4132a900 +permission.md: 0b9c155adb777059b53c9378f8d07fffaff65ab8 +permission.zh.md: b804804ca1d56a6e9f27bc1fa6bbdcda6a93420f diff --git a/docs/subsystems/permission.md b/docs/subsystems/permission.md index 6f9a37dbb7..0b9c155adb 100644 --- a/docs/subsystems/permission.md +++ b/docs/subsystems/permission.md @@ -127,5 +127,5 @@ set(session: Session, name: string): void Types: [Session](session.md) · [SessionEvent](session.md) -Source: [`packages/interaction/permission/src/index.ts:159`](../../packages/interaction/permission/src/index.ts) +Source: [`packages/interaction/permission/src/index.ts`](../../packages/interaction/permission/src/index.ts) diff --git a/docs/subsystems/permission.zh.md b/docs/subsystems/permission.zh.md index 8eda50fae0..b804804ca1 100644 --- a/docs/subsystems/permission.zh.md +++ b/docs/subsystems/permission.zh.md @@ -127,5 +127,5 @@ set(session: Session, name: string): void Types: [Session](session.md) · [SessionEvent](session.md) -Source: [`packages/interaction/permission/src/index.ts:159`](../../packages/interaction/permission/src/index.ts) +Source: [`packages/interaction/permission/src/index.ts`](../../packages/interaction/permission/src/index.ts) diff --git a/docs/subsystems/persistence.i18n.yaml b/docs/subsystems/persistence.i18n.yaml index f198d0a25e..56de498b2f 100644 --- a/docs/subsystems/persistence.i18n.yaml +++ b/docs/subsystems/persistence.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write docs/subsystems/persistence.md -persistence.md: 640e2c0122b01ae869d20c1805742abad782c95b -persistence.zh.md: 7e28d6d1f63a78741840fb74194d3249696423ae +persistence.md: 4c1c5f7ef706e97bf2248c20831accd92e2ff55d +persistence.zh.md: d1fdef31f164a3a3c2c78804bfc6156fdf3fcd92 diff --git a/docs/subsystems/persistence.md b/docs/subsystems/persistence.md index 640e2c0122..4c1c5f7ef7 100644 --- a/docs/subsystems/persistence.md +++ b/docs/subsystems/persistence.md @@ -334,5 +334,5 @@ abstract listSnapshots(signal?: AbortSignal): Promise diff --git a/docs/subsystems/persistence.zh.md b/docs/subsystems/persistence.zh.md index 7e28d6d1f6..d1fdef31f1 100644 --- a/docs/subsystems/persistence.zh.md +++ b/docs/subsystems/persistence.zh.md @@ -334,5 +334,5 @@ abstract listSnapshots(signal?: AbortSignal): Promise diff --git a/docs/subsystems/plan.i18n.yaml b/docs/subsystems/plan.i18n.yaml index 2286bad3fd..2873cc7431 100644 --- a/docs/subsystems/plan.i18n.yaml +++ b/docs/subsystems/plan.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write docs/subsystems/plan.md -plan.md: 29a2473c440b654422c4c563820efa72847a820a -plan.zh.md: bcb327719102b90c1c7009d78cee0fa930cdc7a8 +plan.md: 2f5c74a281131c292fba890869a707ecc628e8ed +plan.zh.md: 3351544758a712ac0f3a0585fc771b0057ecd98e diff --git a/docs/subsystems/plan.md b/docs/subsystems/plan.md index 29a2473c44..2f5c74a281 100644 --- a/docs/subsystems/plan.md +++ b/docs/subsystems/plan.md @@ -82,5 +82,5 @@ set(agent: Agent, active: boolean): 'committed' | 'queued' | 'cancelled' | 'noop Types: [Agent](core.md) -Source: [`packages/plan/plan-mode/src/index.ts:183`](../../packages/plan/plan-mode/src/index.ts) +Source: [`packages/plan/plan-mode/src/index.ts`](../../packages/plan/plan-mode/src/index.ts) diff --git a/docs/subsystems/plan.zh.md b/docs/subsystems/plan.zh.md index bcb3277191..3351544758 100644 --- a/docs/subsystems/plan.zh.md +++ b/docs/subsystems/plan.zh.md @@ -82,5 +82,5 @@ set(agent: Agent, active: boolean): 'committed' | 'queued' | 'cancelled' | 'noop Types: [Agent](core.md) -Source: [`packages/plan/plan-mode/src/index.ts:183`](../../packages/plan/plan-mode/src/index.ts) +Source: [`packages/plan/plan-mode/src/index.ts`](../../packages/plan/plan-mode/src/index.ts) diff --git a/docs/subsystems/pty.i18n.yaml b/docs/subsystems/pty.i18n.yaml index 76b4500aea..90fe856de7 100644 --- a/docs/subsystems/pty.i18n.yaml +++ b/docs/subsystems/pty.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write docs/subsystems/pty.md -pty.md: 45b157c73926d85d5fc2bb037d3954da7bf75063 -pty.zh.md: 4409ef0b0504780b0b5564a34b61d4f1b2c02775 +pty.md: a7e93bd46a5fea824bbbb7d5aa38c3cd257cc5ce +pty.zh.md: b783a08496f1ee28c1cdbf7e1aa7ba03b3bee392 diff --git a/docs/subsystems/pty.md b/docs/subsystems/pty.md index 45b157c739..a7e93bd46a 100644 --- a/docs/subsystems/pty.md +++ b/docs/subsystems/pty.md @@ -180,5 +180,5 @@ list(owner: Agent): PtySessionSnapshot[] Types: [Agent](core.md) -Source: [`packages/pty/pty/src/index.ts:105`](../../packages/pty/pty/src/index.ts) +Source: [`packages/pty/pty/src/index.ts`](../../packages/pty/pty/src/index.ts) diff --git a/docs/subsystems/pty.zh.md b/docs/subsystems/pty.zh.md index 4409ef0b05..b783a08496 100644 --- a/docs/subsystems/pty.zh.md +++ b/docs/subsystems/pty.zh.md @@ -180,5 +180,5 @@ list(owner: Agent): PtySessionSnapshot[] Types: [Agent](core.md) -Source: [`packages/pty/pty/src/index.ts:105`](../../packages/pty/pty/src/index.ts) +Source: [`packages/pty/pty/src/index.ts`](../../packages/pty/pty/src/index.ts) diff --git a/docs/subsystems/sandbox.i18n.yaml b/docs/subsystems/sandbox.i18n.yaml index a6f8fd2609..1e04bca9a0 100644 --- a/docs/subsystems/sandbox.i18n.yaml +++ b/docs/subsystems/sandbox.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write docs/subsystems/sandbox.md -sandbox.md: dd960b3021dcdc87cfd36fd439cbec0a810dd736 -sandbox.zh.md: 23644bb43a131a0e3c8595187a6fc11e74682d9e +sandbox.md: 0973984b52f246e3fd982183439c64f0cf5e6c99 +sandbox.zh.md: e8bfb53c52e691b1c5027d687bc8e4a3d735c018 diff --git a/docs/subsystems/sandbox.md b/docs/subsystems/sandbox.md index dd960b3021..0973984b52 100644 --- a/docs/subsystems/sandbox.md +++ b/docs/subsystems/sandbox.md @@ -176,7 +176,7 @@ Abstract process-sandbox service. confine must return enforcing argv or fail clo abstract confine(argv: readonly string[], policy: SandboxPolicy): ConfinedArgv ``` -Source: [`packages/sandbox/sandbox/src/index.ts:148`](../../packages/sandbox/sandbox/src/index.ts) +Source: [`packages/sandbox/sandbox/src/index.ts`](../../packages/sandbox/sandbox/src/index.ts) @@ -206,5 +206,5 @@ overrideOf(session: Session): SandboxMode | undefined Types: [Session](session.md) -Source: [`packages/sandbox/sandbox-policy/src/index.ts:91`](../../packages/sandbox/sandbox-policy/src/index.ts) +Source: [`packages/sandbox/sandbox-policy/src/index.ts`](../../packages/sandbox/sandbox-policy/src/index.ts) diff --git a/docs/subsystems/sandbox.zh.md b/docs/subsystems/sandbox.zh.md index 23644bb43a..e8bfb53c52 100644 --- a/docs/subsystems/sandbox.zh.md +++ b/docs/subsystems/sandbox.zh.md @@ -176,7 +176,7 @@ Abstract process-sandbox service. confine must return enforcing argv or fail clo abstract confine(argv: readonly string[], policy: SandboxPolicy): ConfinedArgv ``` -Source: [`packages/sandbox/sandbox/src/index.ts:148`](../../packages/sandbox/sandbox/src/index.ts) +Source: [`packages/sandbox/sandbox/src/index.ts`](../../packages/sandbox/sandbox/src/index.ts) @@ -206,5 +206,5 @@ overrideOf(session: Session): SandboxMode | undefined Types: [Session](session.md) -Source: [`packages/sandbox/sandbox-policy/src/index.ts:91`](../../packages/sandbox/sandbox-policy/src/index.ts) +Source: [`packages/sandbox/sandbox-policy/src/index.ts`](../../packages/sandbox/sandbox-policy/src/index.ts) diff --git a/docs/subsystems/session-projection.i18n.yaml b/docs/subsystems/session-projection.i18n.yaml index 823ed61107..fa23022abb 100644 --- a/docs/subsystems/session-projection.i18n.yaml +++ b/docs/subsystems/session-projection.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write docs/subsystems/session-projection.md -session-projection.md: d91a3faa50dc092d89aa2c7d5ce1e6118df7ebd6 -session-projection.zh.md: 7dac3db8470a2941b711db6a30fced8dbe7c7a8d +session-projection.md: a9851a016713a1e2019354a9b1fc26f018321f45 +session-projection.zh.md: a1c9fa61d7108fc545aa7ee513d8516c10b79179 diff --git a/docs/subsystems/session-projection.md b/docs/subsystems/session-projection.md index d91a3faa50..a9851a0167 100644 --- a/docs/subsystems/session-projection.md +++ b/docs/subsystems/session-projection.md @@ -148,7 +148,7 @@ async coldSnapshot(id: SessionId, signal?: AbortSignal): Promise @@ -258,5 +258,5 @@ restore(checkpoint: ProjectionCheckpoint, events: readonly SessionEvent[], baseS Types: [Session](session.md) · [SessionEvent](session.md) -Source: [`packages/session/session-projection/src/index.ts:156`](../../packages/session/session-projection/src/index.ts) +Source: [`packages/session/session-projection/src/index.ts`](../../packages/session/session-projection/src/index.ts) diff --git a/docs/subsystems/session-projection.zh.md b/docs/subsystems/session-projection.zh.md index 7dac3db847..a1c9fa61d7 100644 --- a/docs/subsystems/session-projection.zh.md +++ b/docs/subsystems/session-projection.zh.md @@ -148,7 +148,7 @@ async coldSnapshot(id: SessionId, signal?: AbortSignal): Promise @@ -258,5 +258,5 @@ restore(checkpoint: ProjectionCheckpoint, events: readonly SessionEvent[], baseS Types: [Session](session.md) · [SessionEvent](session.md) -Source: [`packages/session/session-projection/src/index.ts:156`](../../packages/session/session-projection/src/index.ts) +Source: [`packages/session/session-projection/src/index.ts`](../../packages/session/session-projection/src/index.ts) diff --git a/docs/subsystems/session-query.i18n.yaml b/docs/subsystems/session-query.i18n.yaml index 4ba7a3392b..aabf674f67 100644 --- a/docs/subsystems/session-query.i18n.yaml +++ b/docs/subsystems/session-query.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write docs/subsystems/session-query.md -session-query.md: 3b6d99af58ffb7c3e7b58cc4a3e9143732382861 -session-query.zh.md: c23e9ad53ef6a3e4a8e50a892824068f33e4e15b +session-query.md: 2c9791aa7bfcb74f38a7554f619b7f0a1e2376d3 +session-query.zh.md: 3b968f1de674c1308484c24290496e78e688ddd9 diff --git a/docs/subsystems/session-query.md b/docs/subsystems/session-query.md index 3b6d99af58..2c9791aa7b 100644 --- a/docs/subsystems/session-query.md +++ b/docs/subsystems/session-query.md @@ -490,5 +490,5 @@ async readEvent(request: SessionEventReadRequest, signal?: AbortSignal): Promise Types: [SessionId](core.md) · [SessionTitleSnapshot](session-title.md) -Source: [`packages/session-query/session-query/src/index.ts:81`](../../packages/session-query/session-query/src/index.ts) +Source: [`packages/session-query/session-query/src/index.ts`](../../packages/session-query/session-query/src/index.ts) diff --git a/docs/subsystems/session-query.zh.md b/docs/subsystems/session-query.zh.md index c23e9ad53e..3b968f1de6 100644 --- a/docs/subsystems/session-query.zh.md +++ b/docs/subsystems/session-query.zh.md @@ -490,5 +490,5 @@ async readEvent(request: SessionEventReadRequest, signal?: AbortSignal): Promise Types: [SessionId](core.md) · [SessionTitleSnapshot](session-title.md) -Source: [`packages/session-query/session-query/src/index.ts:81`](../../packages/session-query/session-query/src/index.ts) +Source: [`packages/session-query/session-query/src/index.ts`](../../packages/session-query/session-query/src/index.ts) diff --git a/docs/subsystems/session-reference.i18n.yaml b/docs/subsystems/session-reference.i18n.yaml index a73c858289..f400e35b10 100644 --- a/docs/subsystems/session-reference.i18n.yaml +++ b/docs/subsystems/session-reference.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write docs/subsystems/session-reference.md -session-reference.md: f539a59b8d26182aff9746b6d6a39a86ba15cb45 -session-reference.zh.md: 1035614141936af1f94bdabe35b3104be319a762 +session-reference.md: 4dc3ef117fe2f04dd3f64c80cfc9547f984bd0b5 +session-reference.zh.md: c0c1f7830fa93c472f30aeb7742fd2008d01c297 diff --git a/docs/subsystems/session-reference.md b/docs/subsystems/session-reference.md index f539a59b8d..4dc3ef117f 100644 --- a/docs/subsystems/session-reference.md +++ b/docs/subsystems/session-reference.md @@ -104,5 +104,5 @@ async prepare( agent: Agent, content: ContentBlock[], references: SessionReferen Types: [Agent](core.md) · [ContentBlock](llm-streaming.md) -Source: [`packages/context/session-reference/src/index.ts:70`](../../packages/context/session-reference/src/index.ts) +Source: [`packages/context/session-reference/src/index.ts`](../../packages/context/session-reference/src/index.ts) diff --git a/docs/subsystems/session-reference.zh.md b/docs/subsystems/session-reference.zh.md index 1035614141..c0c1f7830f 100644 --- a/docs/subsystems/session-reference.zh.md +++ b/docs/subsystems/session-reference.zh.md @@ -104,5 +104,5 @@ async prepare( agent: Agent, content: ContentBlock[], references: SessionReferen Types: [Agent](core.md) · [ContentBlock](llm-streaming.md) -Source: [`packages/context/session-reference/src/index.ts:70`](../../packages/context/session-reference/src/index.ts) +Source: [`packages/context/session-reference/src/index.ts`](../../packages/context/session-reference/src/index.ts) diff --git a/docs/subsystems/session-title.i18n.yaml b/docs/subsystems/session-title.i18n.yaml index 29804cae7e..c6a771b927 100644 --- a/docs/subsystems/session-title.i18n.yaml +++ b/docs/subsystems/session-title.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write docs/subsystems/session-title.md -session-title.md: 339177b03a03b7d82375f7a293934cb164e9f266 -session-title.zh.md: b1353025a4f621e9a3117c0406ad304c35828a49 +session-title.md: 05edbb380d76aaadd9f4798bea52f13b366f2b0b +session-title.zh.md: 5396f86b71abc47ba7fdc647e9fd3a98e5d2ff25 diff --git a/docs/subsystems/session-title.md b/docs/subsystems/session-title.md index 339177b03a..05edbb380d 100644 --- a/docs/subsystems/session-title.md +++ b/docs/subsystems/session-title.md @@ -200,5 +200,5 @@ register(provider: SessionTitleProvider): () => Promise Types: [Session](session.md) -Source: [`packages/session/session-title/src/index.ts:261`](../../packages/session/session-title/src/index.ts) +Source: [`packages/session/session-title/src/index.ts`](../../packages/session/session-title/src/index.ts) diff --git a/docs/subsystems/session-title.zh.md b/docs/subsystems/session-title.zh.md index b1353025a4..5396f86b71 100644 --- a/docs/subsystems/session-title.zh.md +++ b/docs/subsystems/session-title.zh.md @@ -200,5 +200,5 @@ register(provider: SessionTitleProvider): () => Promise Types: [Session](session.md) -Source: [`packages/session/session-title/src/index.ts:261`](../../packages/session/session-title/src/index.ts) +Source: [`packages/session/session-title/src/index.ts`](../../packages/session/session-title/src/index.ts) diff --git a/docs/subsystems/session.i18n.yaml b/docs/subsystems/session.i18n.yaml index 3b9f9ce01d..bb15a107e5 100644 --- a/docs/subsystems/session.i18n.yaml +++ b/docs/subsystems/session.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write docs/subsystems/session.md -session.md: f5b9e63e2320885cc41b30a09398dd341700152d -session.zh.md: 985e0a448d1cf860ccbb0f2885d855ad6830af9f +session.md: cb9530db52adb679d1a6cf1926e681475592bba8 +session.zh.md: d2ed317129c137e13c008a719cff4dc2df7e0678 diff --git a/docs/subsystems/session.md b/docs/subsystems/session.md index f5b9e63e23..cb9530db52 100644 --- a/docs/subsystems/session.md +++ b/docs/subsystems/session.md @@ -733,7 +733,7 @@ fork(source: SessionForkSource, boundary?: number, childSessionId?: SessionId): Types: [CreateSessionOptions](persistence.md) · [PrepareSessionOptions](persistence.md) · [SessionId](core.md) -Source: [`packages/core/session/src/index.ts:807`](../../packages/core/session/src/index.ts) +Source: [`packages/core/session/src/index.ts`](../../packages/core/session/src/index.ts) @@ -762,7 +762,7 @@ Creation announcement during session publication. A synchronous throw vetoes and Types: [Scoped](scope.md) -Source: [`packages/core/session/src/index.ts:74`](../../packages/core/session/src/index.ts) +Source: [`packages/core/session/src/index.ts`](../../packages/core/session/src/index.ts) @@ -785,7 +785,7 @@ Emitted once when an announced session leaves the store, including publication r Types: [Scoped](scope.md) -Source: [`packages/core/session/src/index.ts:84`](../../packages/core/session/src/index.ts) +Source: [`packages/core/session/src/index.ts`](../../packages/core/session/src/index.ts) @@ -810,7 +810,7 @@ Post-commit, fire-and-forget append feed. The listener snapshot resolves before Types: [Scoped](scope.md) -Source: [`packages/core/session/src/index.ts:96`](../../packages/core/session/src/index.ts) +Source: [`packages/core/session/src/index.ts`](../../packages/core/session/src/index.ts) @@ -832,5 +832,5 @@ Awaited parallel durability checkpoint: every listener runs and the caller await Types: [Scoped](scope.md) -Source: [`packages/core/session/src/index.ts:105`](../../packages/core/session/src/index.ts) +Source: [`packages/core/session/src/index.ts`](../../packages/core/session/src/index.ts) diff --git a/docs/subsystems/session.zh.md b/docs/subsystems/session.zh.md index 985e0a448d..d2ed317129 100644 --- a/docs/subsystems/session.zh.md +++ b/docs/subsystems/session.zh.md @@ -737,7 +737,7 @@ fork(source: SessionForkSource, boundary?: number, childSessionId?: SessionId): Types: [CreateSessionOptions](persistence.md) · [PrepareSessionOptions](persistence.md) · [SessionId](core.md) -Source: [`packages/core/session/src/index.ts:807`](../../packages/core/session/src/index.ts) +Source: [`packages/core/session/src/index.ts`](../../packages/core/session/src/index.ts) @@ -766,7 +766,7 @@ Creation announcement during session publication. A synchronous throw vetoes and Types: [Scoped](scope.md) -Source: [`packages/core/session/src/index.ts:74`](../../packages/core/session/src/index.ts) +Source: [`packages/core/session/src/index.ts`](../../packages/core/session/src/index.ts) @@ -789,7 +789,7 @@ Emitted once when an announced session leaves the store, including publication r Types: [Scoped](scope.md) -Source: [`packages/core/session/src/index.ts:84`](../../packages/core/session/src/index.ts) +Source: [`packages/core/session/src/index.ts`](../../packages/core/session/src/index.ts) @@ -814,7 +814,7 @@ Post-commit, fire-and-forget append feed. The listener snapshot resolves before Types: [Scoped](scope.md) -Source: [`packages/core/session/src/index.ts:96`](../../packages/core/session/src/index.ts) +Source: [`packages/core/session/src/index.ts`](../../packages/core/session/src/index.ts) @@ -836,5 +836,5 @@ Awaited parallel durability checkpoint: every listener runs and the caller await Types: [Scoped](scope.md) -Source: [`packages/core/session/src/index.ts:105`](../../packages/core/session/src/index.ts) +Source: [`packages/core/session/src/index.ts`](../../packages/core/session/src/index.ts) diff --git a/docs/subsystems/settings.i18n.yaml b/docs/subsystems/settings.i18n.yaml index a257e0e33e..c7bf36c066 100644 --- a/docs/subsystems/settings.i18n.yaml +++ b/docs/subsystems/settings.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write docs/subsystems/settings.md -settings.md: 9256bf9436d2e77093fc8c6a3728b62fc4e8d67f -settings.zh.md: 720eb9c2718c1fa14a148cced806c224634dba69 +settings.md: 25c56946016c5d108743e2af1f4785ec63501c80 +settings.zh.md: 697f87e7c27f0613042bb05b835de7bd9e56acf6 diff --git a/docs/subsystems/settings.md b/docs/subsystems/settings.md index 9256bf9436..25c5694601 100644 --- a/docs/subsystems/settings.md +++ b/docs/subsystems/settings.md @@ -252,7 +252,7 @@ async replace(ns: SettingsNamespace, section: object, expectedRevision?: number) async mutate(ns: SettingsNamespace, ops: readonly SettingsPathOp[], expectedRevision?: number): Promise ``` -Source: [`packages/settings/settings/src/index.ts:387`](../../packages/settings/settings/src/index.ts) +Source: [`packages/settings/settings/src/index.ts`](../../packages/settings/settings/src/index.ts) @@ -279,7 +279,7 @@ One registered namespace's RAW user section changed, whether or not the resolved 'settings/document-updated'(ns: SettingsNamespace, revision: number): void ``` -Source: [`packages/settings/settings/src/index.ts:170`](../../packages/settings/settings/src/index.ts) +Source: [`packages/settings/settings/src/index.ts`](../../packages/settings/settings/src/index.ts) @@ -306,5 +306,5 @@ Committed change to one registered namespace's resolved value. Emitted after the 'settings/updated'(ns: SettingsNamespace, next: unknown, prev: unknown, source: SettingsUpdateSource): void ``` -Source: [`packages/settings/settings/src/index.ts:157`](../../packages/settings/settings/src/index.ts) +Source: [`packages/settings/settings/src/index.ts`](../../packages/settings/settings/src/index.ts) diff --git a/docs/subsystems/settings.zh.md b/docs/subsystems/settings.zh.md index 720eb9c271..697f87e7c2 100644 --- a/docs/subsystems/settings.zh.md +++ b/docs/subsystems/settings.zh.md @@ -252,7 +252,7 @@ async replace(ns: SettingsNamespace, section: object, expectedRevision?: number) async mutate(ns: SettingsNamespace, ops: readonly SettingsPathOp[], expectedRevision?: number): Promise ``` -Source: [`packages/settings/settings/src/index.ts:387`](../../packages/settings/settings/src/index.ts) +Source: [`packages/settings/settings/src/index.ts`](../../packages/settings/settings/src/index.ts) @@ -279,7 +279,7 @@ One registered namespace's RAW user section changed, whether or not the resolved 'settings/document-updated'(ns: SettingsNamespace, revision: number): void ``` -Source: [`packages/settings/settings/src/index.ts:170`](../../packages/settings/settings/src/index.ts) +Source: [`packages/settings/settings/src/index.ts`](../../packages/settings/settings/src/index.ts) @@ -306,5 +306,5 @@ Committed change to one registered namespace's resolved value. Emitted after the 'settings/updated'(ns: SettingsNamespace, next: unknown, prev: unknown, source: SettingsUpdateSource): void ``` -Source: [`packages/settings/settings/src/index.ts:157`](../../packages/settings/settings/src/index.ts) +Source: [`packages/settings/settings/src/index.ts`](../../packages/settings/settings/src/index.ts) diff --git a/docs/subsystems/skills.i18n.yaml b/docs/subsystems/skills.i18n.yaml index a169374140..c86747102f 100644 --- a/docs/subsystems/skills.i18n.yaml +++ b/docs/subsystems/skills.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write docs/subsystems/skills.md -skills.md: 696f759179203230bf748c8a4be2cee333acd9a3 -skills.zh.md: d2244e86f0ceaf77c1eab02508dc3f07df727dbb +skills.md: 010b2e3ea1ef96d8509761973bf7223f20659eb1 +skills.zh.md: f48ab74b4f85aafcbdc07814e4cafb2fed2832dd diff --git a/docs/subsystems/skills.md b/docs/subsystems/skills.md index 696f759179..010b2e3ea1 100644 --- a/docs/subsystems/skills.md +++ b/docs/subsystems/skills.md @@ -283,7 +283,7 @@ async snapshot(options: SkillLookupOptions = {}): Promise async get(name: string, options: SkillLookupOptions = {}): Promise ``` -Source: [`packages/skill/skill/src/index.ts:305`](../../packages/skill/skill/src/index.ts) +Source: [`packages/skill/skill/src/index.ts`](../../packages/skill/skill/src/index.ts) @@ -306,5 +306,5 @@ A skill provider, runtime contribution, or provider-backed catalog may have chan 'skills/change'(): void ``` -Source: [`packages/skill/skill/src/index.ts:284`](../../packages/skill/skill/src/index.ts) +Source: [`packages/skill/skill/src/index.ts`](../../packages/skill/skill/src/index.ts) diff --git a/docs/subsystems/skills.zh.md b/docs/subsystems/skills.zh.md index d2244e86f0..f48ab74b4f 100644 --- a/docs/subsystems/skills.zh.md +++ b/docs/subsystems/skills.zh.md @@ -283,7 +283,7 @@ async snapshot(options: SkillLookupOptions = {}): Promise async get(name: string, options: SkillLookupOptions = {}): Promise ``` -Source: [`packages/skill/skill/src/index.ts:305`](../../packages/skill/skill/src/index.ts) +Source: [`packages/skill/skill/src/index.ts`](../../packages/skill/skill/src/index.ts) @@ -306,5 +306,5 @@ A skill provider, runtime contribution, or provider-backed catalog may have chan 'skills/change'(): void ``` -Source: [`packages/skill/skill/src/index.ts:284`](../../packages/skill/skill/src/index.ts) +Source: [`packages/skill/skill/src/index.ts`](../../packages/skill/skill/src/index.ts) diff --git a/docs/subsystems/spill.i18n.yaml b/docs/subsystems/spill.i18n.yaml index da210bd7d2..56104d33d5 100644 --- a/docs/subsystems/spill.i18n.yaml +++ b/docs/subsystems/spill.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write docs/subsystems/spill.md -spill.md: bc323f8d2591e93a56e938c245274ef6be86085f -spill.zh.md: f81d5e5de3633561a5a090a14c39b43268b8c63f +spill.md: 51b7c167150c614d33db970c516ca603a04b2782 +spill.zh.md: 338af03316c9c03903bf0342c4d863fff7728f73 diff --git a/docs/subsystems/spill.md b/docs/subsystems/spill.md index bc323f8d25..51b7c16715 100644 --- a/docs/subsystems/spill.md +++ b/docs/subsystems/spill.md @@ -113,5 +113,5 @@ Semantics every implementation must honor: abstract saveText(input: SaveTextSpill): Promise ``` -Source: [`packages/spill/spill/src/index.ts:45`](../../packages/spill/spill/src/index.ts) +Source: [`packages/spill/spill/src/index.ts`](../../packages/spill/spill/src/index.ts) diff --git a/docs/subsystems/spill.zh.md b/docs/subsystems/spill.zh.md index f81d5e5de3..338af03316 100644 --- a/docs/subsystems/spill.zh.md +++ b/docs/subsystems/spill.zh.md @@ -113,5 +113,5 @@ Semantics every implementation must honor: abstract saveText(input: SaveTextSpill): Promise ``` -Source: [`packages/spill/spill/src/index.ts:45`](../../packages/spill/spill/src/index.ts) +Source: [`packages/spill/spill/src/index.ts`](../../packages/spill/spill/src/index.ts) diff --git a/docs/subsystems/storage.i18n.yaml b/docs/subsystems/storage.i18n.yaml index 9b3d8a19d6..ca283d72ab 100644 --- a/docs/subsystems/storage.i18n.yaml +++ b/docs/subsystems/storage.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write docs/subsystems/storage.md -storage.md: 3234fdf9587dc2853b4f9ec4205d230aae4b633a -storage.zh.md: fb13ec96099f2173478aecf1b91799237755414c +storage.md: 6947c23fedc4adab3364196c9b3c30618e96921e +storage.zh.md: b2c43d0f6ad319ec0f85320bed2d38d9507cfdc5 diff --git a/docs/subsystems/storage.md b/docs/subsystems/storage.md index 3234fdf958..6947c23fed 100644 --- a/docs/subsystems/storage.md +++ b/docs/subsystems/storage.md @@ -156,7 +156,7 @@ mount(form: K, facility: StorageForms[K]): () => v form(form: K): StorageForms[K] ``` -Source: [`packages/storage/storage/src/index.ts:47`](../../packages/storage/storage/src/index.ts) +Source: [`packages/storage/storage/src/index.ts`](../../packages/storage/storage/src/index.ts) @@ -201,7 +201,7 @@ get(name: string): DomainImpl | undefined async closeAll(): Promise ``` -Source: [`packages/storage/storage-domain/src/index.ts:69`](../../packages/storage/storage-domain/src/index.ts) +Source: [`packages/storage/storage-domain/src/index.ts`](../../packages/storage/storage-domain/src/index.ts) @@ -225,5 +225,5 @@ A domain record or the global singleton changed, emitted once per write strictly 'domain/changed'(change: DomainChanged): void ``` -Source: [`packages/storage/storage-domain/src/events.ts:46`](../../packages/storage/storage-domain/src/events.ts) +Source: [`packages/storage/storage-domain/src/events.ts`](../../packages/storage/storage-domain/src/events.ts) diff --git a/docs/subsystems/storage.zh.md b/docs/subsystems/storage.zh.md index fb13ec9609..b2c43d0f6a 100644 --- a/docs/subsystems/storage.zh.md +++ b/docs/subsystems/storage.zh.md @@ -156,7 +156,7 @@ mount(form: K, facility: StorageForms[K]): () => v form(form: K): StorageForms[K] ``` -Source: [`packages/storage/storage/src/index.ts:47`](../../packages/storage/storage/src/index.ts) +Source: [`packages/storage/storage/src/index.ts`](../../packages/storage/storage/src/index.ts) @@ -201,7 +201,7 @@ get(name: string): DomainImpl | undefined async closeAll(): Promise ``` -Source: [`packages/storage/storage-domain/src/index.ts:69`](../../packages/storage/storage-domain/src/index.ts) +Source: [`packages/storage/storage-domain/src/index.ts`](../../packages/storage/storage-domain/src/index.ts) @@ -225,5 +225,5 @@ A domain record or the global singleton changed, emitted once per write strictly 'domain/changed'(change: DomainChanged): void ``` -Source: [`packages/storage/storage-domain/src/events.ts:46`](../../packages/storage/storage-domain/src/events.ts) +Source: [`packages/storage/storage-domain/src/events.ts`](../../packages/storage/storage-domain/src/events.ts) diff --git a/docs/subsystems/subagent.i18n.yaml b/docs/subsystems/subagent.i18n.yaml index e98438900d..d1691920e9 100644 --- a/docs/subsystems/subagent.i18n.yaml +++ b/docs/subsystems/subagent.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write docs/subsystems/subagent.md -subagent.md: 99c54e0696c9c3585c50285ecb69b14c90d83c11 -subagent.zh.md: c5a79247a81f5174662f2b5d1ed2d3c20cf6c672 +subagent.md: 89df677c991a52ba88f2811e014b9b1131f7385d +subagent.zh.md: 99a11df9cc842969a6fd8a30f6d6887d98a2e79f diff --git a/docs/subsystems/subagent.md b/docs/subsystems/subagent.md index 99c54e0696..89df677c99 100644 --- a/docs/subsystems/subagent.md +++ b/docs/subsystems/subagent.md @@ -613,7 +613,7 @@ async start(name: string, request: SubagentStartRequest): Promise Types: [Agent](core.md) · [ContentBlock](llm-streaming.md) · [MessageId](llm-streaming.md) · [SessionId](core.md) -Source: [`packages/subagent/subagent/src/index.ts:167`](../../packages/subagent/subagent/src/index.ts) +Source: [`packages/subagent/subagent/src/index.ts`](../../packages/subagent/subagent/src/index.ts) @@ -639,7 +639,7 @@ A published child settled. Scope-filtered dispatch uses the same delegating pare Types: [Scoped](scope.md) -Source: [`packages/subagent/subagent/src/index.ts:162`](../../packages/subagent/subagent/src/index.ts) +Source: [`packages/subagent/subagent/src/index.ts`](../../packages/subagent/subagent/src/index.ts) @@ -656,7 +656,7 @@ A provider became resolvable in the registry. 'subagent/provider-added'(provider: SubagentProvider): void ``` -Source: [`packages/subagent/subagent/src/index.ts:136`](../../packages/subagent/subagent/src/index.ts) +Source: [`packages/subagent/subagent/src/index.ts`](../../packages/subagent/subagent/src/index.ts) @@ -673,7 +673,7 @@ A provider left the registry. Accepted runs remain holder-owned. 'subagent/provider-removed'(name: string): void ``` -Source: [`packages/subagent/subagent/src/index.ts:142`](../../packages/subagent/subagent/src/index.ts) +Source: [`packages/subagent/subagent/src/index.ts`](../../packages/subagent/subagent/src/index.ts) @@ -697,5 +697,5 @@ A provider established a published child. For in-process providers, `ctx.agents. Types: [Scoped](scope.md) -Source: [`packages/subagent/subagent/src/index.ts:153`](../../packages/subagent/subagent/src/index.ts) +Source: [`packages/subagent/subagent/src/index.ts`](../../packages/subagent/subagent/src/index.ts) diff --git a/docs/subsystems/subagent.zh.md b/docs/subsystems/subagent.zh.md index c5a79247a8..99a11df9cc 100644 --- a/docs/subsystems/subagent.zh.md +++ b/docs/subsystems/subagent.zh.md @@ -615,7 +615,7 @@ async start(name: string, request: SubagentStartRequest): Promise Types: [Agent](core.md) · [ContentBlock](llm-streaming.md) · [MessageId](llm-streaming.md) · [SessionId](core.md) -Source: [`packages/subagent/subagent/src/index.ts:167`](../../packages/subagent/subagent/src/index.ts) +Source: [`packages/subagent/subagent/src/index.ts`](../../packages/subagent/subagent/src/index.ts) @@ -641,7 +641,7 @@ A published child settled. Scope-filtered dispatch uses the same delegating pare Types: [Scoped](scope.md) -Source: [`packages/subagent/subagent/src/index.ts:162`](../../packages/subagent/subagent/src/index.ts) +Source: [`packages/subagent/subagent/src/index.ts`](../../packages/subagent/subagent/src/index.ts) @@ -658,7 +658,7 @@ A provider became resolvable in the registry. 'subagent/provider-added'(provider: SubagentProvider): void ``` -Source: [`packages/subagent/subagent/src/index.ts:136`](../../packages/subagent/subagent/src/index.ts) +Source: [`packages/subagent/subagent/src/index.ts`](../../packages/subagent/subagent/src/index.ts) @@ -675,7 +675,7 @@ A provider left the registry. Accepted runs remain holder-owned. 'subagent/provider-removed'(name: string): void ``` -Source: [`packages/subagent/subagent/src/index.ts:142`](../../packages/subagent/subagent/src/index.ts) +Source: [`packages/subagent/subagent/src/index.ts`](../../packages/subagent/subagent/src/index.ts) @@ -699,5 +699,5 @@ A provider established a published child. For in-process providers, `ctx.agents. Types: [Scoped](scope.md) -Source: [`packages/subagent/subagent/src/index.ts:153`](../../packages/subagent/subagent/src/index.ts) +Source: [`packages/subagent/subagent/src/index.ts`](../../packages/subagent/subagent/src/index.ts) diff --git a/docs/subsystems/subprocess.i18n.yaml b/docs/subsystems/subprocess.i18n.yaml index 26064089c2..25daa209e9 100644 --- a/docs/subsystems/subprocess.i18n.yaml +++ b/docs/subsystems/subprocess.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write docs/subsystems/subprocess.md -subprocess.md: 4fb20e1b440b8fc10540fa2adbd00ae63fd7e221 -subprocess.zh.md: a41f14aa550c4780b5661b546880d932d513b817 +subprocess.md: e7adb0fbcc1565b6ba17e8af6c70fc43d06faf20 +subprocess.zh.md: dd9ec8e8a9749c2d782683ecf34c4249acbc3e3d diff --git a/docs/subsystems/subprocess.md b/docs/subsystems/subprocess.md index 4fb20e1b44..e7adb0fbcc 100644 --- a/docs/subsystems/subprocess.md +++ b/docs/subsystems/subprocess.md @@ -271,7 +271,7 @@ Creates one lazily consumable E2B SDK handle and deletes the sandbox at timeout async getSandbox(): Promise ``` -Source: [`packages/e2b/e2b/src/index.ts:74`](../../packages/e2b/e2b/src/index.ts) +Source: [`packages/e2b/e2b/src/index.ts`](../../packages/e2b/e2b/src/index.ts) @@ -320,5 +320,5 @@ abstract spawn(spec: SubprocessSpawnSpec): SubprocessHandle abstract spawnTerminal(spec: SubprocessTerminalSpawnSpec): Promise ``` -Source: [`packages/subprocess/subprocess/src/index.ts:102`](../../packages/subprocess/subprocess/src/index.ts) +Source: [`packages/subprocess/subprocess/src/index.ts`](../../packages/subprocess/subprocess/src/index.ts) diff --git a/docs/subsystems/subprocess.zh.md b/docs/subsystems/subprocess.zh.md index a41f14aa55..dd9ec8e8a9 100644 --- a/docs/subsystems/subprocess.zh.md +++ b/docs/subsystems/subprocess.zh.md @@ -271,7 +271,7 @@ Creates one lazily consumable E2B SDK handle and deletes the sandbox at timeout async getSandbox(): Promise ``` -Source: [`packages/e2b/e2b/src/index.ts:74`](../../packages/e2b/e2b/src/index.ts) +Source: [`packages/e2b/e2b/src/index.ts`](../../packages/e2b/e2b/src/index.ts) @@ -320,5 +320,5 @@ abstract spawn(spec: SubprocessSpawnSpec): SubprocessHandle abstract spawnTerminal(spec: SubprocessTerminalSpawnSpec): Promise ``` -Source: [`packages/subprocess/subprocess/src/index.ts:102`](../../packages/subprocess/subprocess/src/index.ts) +Source: [`packages/subprocess/subprocess/src/index.ts`](../../packages/subprocess/subprocess/src/index.ts) diff --git a/docs/subsystems/system-prompt.i18n.yaml b/docs/subsystems/system-prompt.i18n.yaml index a7a5e5a6d0..e3a5dd5bec 100644 --- a/docs/subsystems/system-prompt.i18n.yaml +++ b/docs/subsystems/system-prompt.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write docs/subsystems/system-prompt.md -system-prompt.md: 94ce40f8bf98dd4efe3514879c2527c2a7bd3b21 -system-prompt.zh.md: c46ee6e2b70c6603500bd9061ed09b805ed61630 +system-prompt.md: a6267c5e081662f19a083b78e9dec5a99f335075 +system-prompt.zh.md: 88b26796769f028e826c769a60b71c8275bef0c7 diff --git a/docs/subsystems/system-prompt.md b/docs/subsystems/system-prompt.md index 94ce40f8bf..a6267c5e08 100644 --- a/docs/subsystems/system-prompt.md +++ b/docs/subsystems/system-prompt.md @@ -139,7 +139,7 @@ variable(name: string, provider: (context: AssembleContext) => string | undefine async assemble(context: AssembleContext = {}): Promise ``` -Source: [`packages/core/system-prompt/src/index.ts:314`](../../packages/core/system-prompt/src/index.ts) +Source: [`packages/core/system-prompt/src/index.ts`](../../packages/core/system-prompt/src/index.ts) @@ -167,7 +167,7 @@ Expert waterfall over the assembled sections, contexts, tools, and variables. Sc Types: [Scoped](scope.md) -Source: [`packages/core/system-prompt/src/index.ts:29`](../../packages/core/system-prompt/src/index.ts) +Source: [`packages/core/system-prompt/src/index.ts`](../../packages/core/system-prompt/src/index.ts) @@ -184,5 +184,5 @@ Emitted when any prompt provider changes. This registry notification is unfilter 'system-prompt/change'(): void ``` -Source: [`packages/core/system-prompt/src/index.ts:35`](../../packages/core/system-prompt/src/index.ts) +Source: [`packages/core/system-prompt/src/index.ts`](../../packages/core/system-prompt/src/index.ts) diff --git a/docs/subsystems/system-prompt.zh.md b/docs/subsystems/system-prompt.zh.md index c46ee6e2b7..88b2679676 100644 --- a/docs/subsystems/system-prompt.zh.md +++ b/docs/subsystems/system-prompt.zh.md @@ -139,7 +139,7 @@ variable(name: string, provider: (context: AssembleContext) => string | undefine async assemble(context: AssembleContext = {}): Promise ``` -Source: [`packages/core/system-prompt/src/index.ts:314`](../../packages/core/system-prompt/src/index.ts) +Source: [`packages/core/system-prompt/src/index.ts`](../../packages/core/system-prompt/src/index.ts) @@ -167,7 +167,7 @@ Expert waterfall over the assembled sections, contexts, tools, and variables. Sc Types: [Scoped](scope.md) -Source: [`packages/core/system-prompt/src/index.ts:29`](../../packages/core/system-prompt/src/index.ts) +Source: [`packages/core/system-prompt/src/index.ts`](../../packages/core/system-prompt/src/index.ts) @@ -184,5 +184,5 @@ Emitted when any prompt provider changes. This registry notification is unfilter 'system-prompt/change'(): void ``` -Source: [`packages/core/system-prompt/src/index.ts:35`](../../packages/core/system-prompt/src/index.ts) +Source: [`packages/core/system-prompt/src/index.ts`](../../packages/core/system-prompt/src/index.ts) diff --git a/docs/subsystems/tasks.i18n.yaml b/docs/subsystems/tasks.i18n.yaml index c229d0a5c0..24e8422287 100644 --- a/docs/subsystems/tasks.i18n.yaml +++ b/docs/subsystems/tasks.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write docs/subsystems/tasks.md -tasks.md: d3e92891a6736a85519b97775ebe7aa6f12a5ae2 -tasks.zh.md: fe54d7a6482743a8f2ef31b143edb25afe0a478b +tasks.md: 3e008cdcbec79054b84a04b10b41df88efaa540c +tasks.zh.md: 51d8ce0171534071ea01270df51f519711c5cc70 diff --git a/docs/subsystems/tasks.md b/docs/subsystems/tasks.md index d3e92891a6..3e008cdcbe 100644 --- a/docs/subsystems/tasks.md +++ b/docs/subsystems/tasks.md @@ -256,5 +256,5 @@ abstract attachSurface(name: string): () => void Types: [Agent](core.md) -Source: [`packages/tasks/tasks/src/index.ts:50`](../../packages/tasks/tasks/src/index.ts) +Source: [`packages/tasks/tasks/src/index.ts`](../../packages/tasks/tasks/src/index.ts) diff --git a/docs/subsystems/tasks.zh.md b/docs/subsystems/tasks.zh.md index fe54d7a648..51d8ce0171 100644 --- a/docs/subsystems/tasks.zh.md +++ b/docs/subsystems/tasks.zh.md @@ -256,5 +256,5 @@ abstract attachSurface(name: string): () => void Types: [Agent](core.md) -Source: [`packages/tasks/tasks/src/index.ts:50`](../../packages/tasks/tasks/src/index.ts) +Source: [`packages/tasks/tasks/src/index.ts`](../../packages/tasks/tasks/src/index.ts) diff --git a/docs/subsystems/telemetry.i18n.yaml b/docs/subsystems/telemetry.i18n.yaml index c994c46baa..f50ba4311f 100644 --- a/docs/subsystems/telemetry.i18n.yaml +++ b/docs/subsystems/telemetry.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write docs/subsystems/telemetry.md -telemetry.md: 93869f2344eeedfee344735191af842fef188886 -telemetry.zh.md: 50642f1ed917ea52ee152e333f70753c12fba583 +telemetry.md: d548d4354e83f6c4d13d4f747339f4943c7f067b +telemetry.zh.md: 167cfb956cdc9e707007bde53e982ec015a946c8 diff --git a/docs/subsystems/telemetry.md b/docs/subsystems/telemetry.md index 93869f2344..d548d4354e 100644 --- a/docs/subsystems/telemetry.md +++ b/docs/subsystems/telemetry.md @@ -142,7 +142,7 @@ flush?(): void abstract shutdown(): Promise ``` -Source: [`packages/session/session-telemetry/src/index.ts:140`](../../packages/session/session-telemetry/src/index.ts) +Source: [`packages/session/session-telemetry/src/index.ts`](../../packages/session/session-telemetry/src/index.ts) @@ -176,5 +176,5 @@ Transform one outbound record before it reaches the backend. This waterfall is t 'telemetry/record'(record: TelemetryRecord, next: () => TelemetryRecord): TelemetryRecord ``` -Source: [`packages/session/session-telemetry/src/index.ts:43`](../../packages/session/session-telemetry/src/index.ts) +Source: [`packages/session/session-telemetry/src/index.ts`](../../packages/session/session-telemetry/src/index.ts) diff --git a/docs/subsystems/telemetry.zh.md b/docs/subsystems/telemetry.zh.md index 50642f1ed9..167cfb956c 100644 --- a/docs/subsystems/telemetry.zh.md +++ b/docs/subsystems/telemetry.zh.md @@ -142,7 +142,7 @@ flush?(): void abstract shutdown(): Promise ``` -Source: [`packages/session/session-telemetry/src/index.ts:140`](../../packages/session/session-telemetry/src/index.ts) +Source: [`packages/session/session-telemetry/src/index.ts`](../../packages/session/session-telemetry/src/index.ts) @@ -176,5 +176,5 @@ Transform one outbound record before it reaches the backend. This waterfall is t 'telemetry/record'(record: TelemetryRecord, next: () => TelemetryRecord): TelemetryRecord ``` -Source: [`packages/session/session-telemetry/src/index.ts:43`](../../packages/session/session-telemetry/src/index.ts) +Source: [`packages/session/session-telemetry/src/index.ts`](../../packages/session/session-telemetry/src/index.ts) diff --git a/docs/subsystems/token-meter.i18n.yaml b/docs/subsystems/token-meter.i18n.yaml index 17bbb937cc..375c53e4af 100644 --- a/docs/subsystems/token-meter.i18n.yaml +++ b/docs/subsystems/token-meter.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write docs/subsystems/token-meter.md -token-meter.md: 8a01980191bf29b1fbc0f8b1d0b33d1fb149319c -token-meter.zh.md: 7411ce26cb75697607a706469d7923d46ff3f421 +token-meter.md: 3eff5798788703053fe2b5e6623afc65653af8a3 +token-meter.zh.md: f76d451520a8f6fb97ecf5b5ded22f459af3b471 diff --git a/docs/subsystems/token-meter.md b/docs/subsystems/token-meter.md index 8a01980191..3eff579878 100644 --- a/docs/subsystems/token-meter.md +++ b/docs/subsystems/token-meter.md @@ -86,5 +86,5 @@ estimateMessage(message: Message): number Types: [EpochHeader](session.md) · [Message](llm-streaming.md) · [Session](session.md) -Source: [`packages/llm/token-meter/src/index.ts:74`](../../packages/llm/token-meter/src/index.ts) +Source: [`packages/llm/token-meter/src/index.ts`](../../packages/llm/token-meter/src/index.ts) diff --git a/docs/subsystems/token-meter.zh.md b/docs/subsystems/token-meter.zh.md index 7411ce26cb..f76d451520 100644 --- a/docs/subsystems/token-meter.zh.md +++ b/docs/subsystems/token-meter.zh.md @@ -86,5 +86,5 @@ estimateMessage(message: Message): number Types: [EpochHeader](session.md) · [Message](llm-streaming.md) · [Session](session.md) -Source: [`packages/llm/token-meter/src/index.ts:74`](../../packages/llm/token-meter/src/index.ts) +Source: [`packages/llm/token-meter/src/index.ts`](../../packages/llm/token-meter/src/index.ts) diff --git a/docs/subsystems/tools.i18n.yaml b/docs/subsystems/tools.i18n.yaml index 1384b3888b..6be79a2f66 100644 --- a/docs/subsystems/tools.i18n.yaml +++ b/docs/subsystems/tools.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write docs/subsystems/tools.md -tools.md: 83389f39c3188fc251504ed5786249ff1921acae -tools.zh.md: 45cb85b3f2940f84b46bc58406bc8255cbe08be7 +tools.md: bae35a2d2c5b9857fd646a0ee873d468818ebc08 +tools.zh.md: c14a35d62683eb26c7403234740d32c33ed68a6c diff --git a/docs/subsystems/tools.md b/docs/subsystems/tools.md index 83389f39c3..bae35a2d2c 100644 --- a/docs/subsystems/tools.md +++ b/docs/subsystems/tools.md @@ -554,7 +554,7 @@ async execute(exec: ToolExecutionInput): Promise Types: [ScopeKey](scope.md) -Source: [`packages/core/tools/src/index.ts:747`](../../packages/core/tools/src/index.ts) +Source: [`packages/core/tools/src/index.ts`](../../packages/core/tools/src/index.ts) @@ -579,7 +579,7 @@ A tool was registered or unregistered, or a scoped restriction changed (the avai 'tools/change'(): void ``` -Source: [`packages/core/tools/src/index.ts:192`](../../packages/core/tools/src/index.ts) +Source: [`packages/core/tools/src/index.ts`](../../packages/core/tools/src/index.ts) @@ -605,7 +605,7 @@ Shape the DURABLE LOG COPY of one `run_code` sub-dispatch outcome before the bri Types: [ContentBlock](llm-streaming.md) · [Scoped](scope.md) -Source: [`packages/core/tools/src/index.ts:174`](../../packages/core/tools/src/index.ts) +Source: [`packages/core/tools/src/index.ts`](../../packages/core/tools/src/index.ts) @@ -629,7 +629,7 @@ Around-dispatch waterfall for timeout, retry, or metrics. `next()` returns a nor Types: [Scoped](scope.md) -Source: [`packages/core/tools/src/index.ts:149`](../../packages/core/tools/src/index.ts) +Source: [`packages/core/tools/src/index.ts`](../../packages/core/tools/src/index.ts) @@ -654,7 +654,7 @@ Accept, replace, enrich, or block a normalized dispatch result. `next()` accepts Types: [Scoped](scope.md) -Source: [`packages/core/tools/src/index.ts:161`](../../packages/core/tools/src/index.ts) +Source: [`packages/core/tools/src/index.ts`](../../packages/core/tools/src/index.ts) @@ -677,7 +677,7 @@ Allow, deny, or ask before dispatch. `next()` delegates to allow; missing approv Types: [Scoped](scope.md) -Source: [`packages/core/tools/src/index.ts:138`](../../packages/core/tools/src/index.ts) +Source: [`packages/core/tools/src/index.ts`](../../packages/core/tools/src/index.ts) @@ -698,5 +698,5 @@ Observe the frozen, lossless-JSON final outcome. Listener failures are contained Types: [Scoped](scope.md) -Source: [`packages/core/tools/src/index.ts:182`](../../packages/core/tools/src/index.ts) +Source: [`packages/core/tools/src/index.ts`](../../packages/core/tools/src/index.ts) diff --git a/docs/subsystems/tools.zh.md b/docs/subsystems/tools.zh.md index 45cb85b3f2..c14a35d626 100644 --- a/docs/subsystems/tools.zh.md +++ b/docs/subsystems/tools.zh.md @@ -554,7 +554,7 @@ async execute(exec: ToolExecutionInput): Promise Types: [ScopeKey](scope.md) -Source: [`packages/core/tools/src/index.ts:747`](../../packages/core/tools/src/index.ts) +Source: [`packages/core/tools/src/index.ts`](../../packages/core/tools/src/index.ts) @@ -579,7 +579,7 @@ A tool was registered or unregistered, or a scoped restriction changed (the avai 'tools/change'(): void ``` -Source: [`packages/core/tools/src/index.ts:192`](../../packages/core/tools/src/index.ts) +Source: [`packages/core/tools/src/index.ts`](../../packages/core/tools/src/index.ts) @@ -605,7 +605,7 @@ Shape the DURABLE LOG COPY of one `run_code` sub-dispatch outcome before the bri Types: [ContentBlock](llm-streaming.md) · [Scoped](scope.md) -Source: [`packages/core/tools/src/index.ts:174`](../../packages/core/tools/src/index.ts) +Source: [`packages/core/tools/src/index.ts`](../../packages/core/tools/src/index.ts) @@ -629,7 +629,7 @@ Around-dispatch waterfall for timeout, retry, or metrics. `next()` returns a nor Types: [Scoped](scope.md) -Source: [`packages/core/tools/src/index.ts:149`](../../packages/core/tools/src/index.ts) +Source: [`packages/core/tools/src/index.ts`](../../packages/core/tools/src/index.ts) @@ -654,7 +654,7 @@ Accept, replace, enrich, or block a normalized dispatch result. `next()` accepts Types: [Scoped](scope.md) -Source: [`packages/core/tools/src/index.ts:161`](../../packages/core/tools/src/index.ts) +Source: [`packages/core/tools/src/index.ts`](../../packages/core/tools/src/index.ts) @@ -677,7 +677,7 @@ Allow, deny, or ask before dispatch. `next()` delegates to allow; missing approv Types: [Scoped](scope.md) -Source: [`packages/core/tools/src/index.ts:138`](../../packages/core/tools/src/index.ts) +Source: [`packages/core/tools/src/index.ts`](../../packages/core/tools/src/index.ts) @@ -698,5 +698,5 @@ Observe the frozen, lossless-JSON final outcome. Listener failures are contained Types: [Scoped](scope.md) -Source: [`packages/core/tools/src/index.ts:182`](../../packages/core/tools/src/index.ts) +Source: [`packages/core/tools/src/index.ts`](../../packages/core/tools/src/index.ts) diff --git a/docs/subsystems/typert.i18n.yaml b/docs/subsystems/typert.i18n.yaml index d58e6036ab..a60ced9485 100644 --- a/docs/subsystems/typert.i18n.yaml +++ b/docs/subsystems/typert.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write docs/subsystems/typert.md -typert.md: 8ce52837ceee8e9c8c4a61de28f972912faa2cf0 -typert.zh.md: a025716dad9a9279a45530a0a9109a13a2c34b0c +typert.md: 9ea963e9a28f0b5e186b00de75e4103baaf3501d +typert.zh.md: 781641ae9f63e85cf9518717244d685bdfa64331 diff --git a/docs/subsystems/typert.md b/docs/subsystems/typert.md index 8ce52837ce..9ea963e9a2 100644 --- a/docs/subsystems/typert.md +++ b/docs/subsystems/typert.md @@ -274,7 +274,7 @@ toJSONSchema(key: string, params?: z.core.ToJSONSchemaParams): z.core.JSONSchema Types: [TypertContribution](invariants.md) · [TypertFace](invariants.md) · [TypertPackageFilter](invariants.md) · [TypertPackageRecord](invariants.md) · [TypertSchemaFilter](invariants.md) · [TypertSchemaRecord](invariants.md) -Source: [`packages/typert/registry/src/service.ts:446`](../../packages/typert/registry/src/service.ts) +Source: [`packages/typert/registry/src/service.ts`](../../packages/typert/registry/src/service.ts) @@ -292,5 +292,5 @@ Resolve strict generated definitions or conservative SRC markers against current async invoke(request: InvokeRemoteRequest): Promise ``` -Source: [`packages/api/gateway/src/index.ts:78`](../../packages/api/gateway/src/index.ts) +Source: [`packages/api/gateway/src/index.ts`](../../packages/api/gateway/src/index.ts) diff --git a/docs/subsystems/typert.zh.md b/docs/subsystems/typert.zh.md index a025716dad..781641ae9f 100644 --- a/docs/subsystems/typert.zh.md +++ b/docs/subsystems/typert.zh.md @@ -274,7 +274,7 @@ toJSONSchema(key: string, params?: z.core.ToJSONSchemaParams): z.core.JSONSchema Types: [TypertContribution](invariants.md) · [TypertFace](invariants.md) · [TypertPackageFilter](invariants.md) · [TypertPackageRecord](invariants.md) · [TypertSchemaFilter](invariants.md) · [TypertSchemaRecord](invariants.md) -Source: [`packages/typert/registry/src/service.ts:446`](../../packages/typert/registry/src/service.ts) +Source: [`packages/typert/registry/src/service.ts`](../../packages/typert/registry/src/service.ts) @@ -292,5 +292,5 @@ Resolve strict generated definitions or conservative SRC markers against current async invoke(request: InvokeRemoteRequest): Promise ``` -Source: [`packages/api/gateway/src/index.ts:78`](../../packages/api/gateway/src/index.ts) +Source: [`packages/api/gateway/src/index.ts`](../../packages/api/gateway/src/index.ts) diff --git a/docs/subsystems/user-interaction.i18n.yaml b/docs/subsystems/user-interaction.i18n.yaml index 296bc8b766..f538f623ef 100644 --- a/docs/subsystems/user-interaction.i18n.yaml +++ b/docs/subsystems/user-interaction.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write docs/subsystems/user-interaction.md -user-interaction.md: a19155ae06af0133ae468c004b2e3b66f1de3fb8 -user-interaction.zh.md: c7aa9cafc9865191cda4089ad2beb214a33b00ef +user-interaction.md: 5860fbf2d7c7cab404b2586a91e69f17787b4f76 +user-interaction.zh.md: 7a1908184a1c3a27fa7db9395d341ded07ea1c93 diff --git a/docs/subsystems/user-interaction.md b/docs/subsystems/user-interaction.md index a19155ae06..5860fbf2d7 100644 --- a/docs/subsystems/user-interaction.md +++ b/docs/subsystems/user-interaction.md @@ -174,5 +174,5 @@ registerProvider(provider: UserInteractionProvider): () => void async ask(request: AskUserQuestionRequest): Promise ``` -Source: [`packages/interaction/user-interaction/src/index.ts:51`](../../packages/interaction/user-interaction/src/index.ts) +Source: [`packages/interaction/user-interaction/src/index.ts`](../../packages/interaction/user-interaction/src/index.ts) diff --git a/docs/subsystems/user-interaction.zh.md b/docs/subsystems/user-interaction.zh.md index c7aa9cafc9..7a1908184a 100644 --- a/docs/subsystems/user-interaction.zh.md +++ b/docs/subsystems/user-interaction.zh.md @@ -174,5 +174,5 @@ registerProvider(provider: UserInteractionProvider): () => void async ask(request: AskUserQuestionRequest): Promise ``` -Source: [`packages/interaction/user-interaction/src/index.ts:51`](../../packages/interaction/user-interaction/src/index.ts) +Source: [`packages/interaction/user-interaction/src/index.ts`](../../packages/interaction/user-interaction/src/index.ts) diff --git a/docs/subsystems/web.i18n.yaml b/docs/subsystems/web.i18n.yaml index 8a11d774e6..9e9b98c697 100644 --- a/docs/subsystems/web.i18n.yaml +++ b/docs/subsystems/web.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write docs/subsystems/web.md -web.md: 2a7cc499b42dd8b45ce6783a35a2fadd8df1183d -web.zh.md: 6857f2a06a7d90702b6626409b4d8db914b3c465 +web.md: 43b9d378a1d81063111c9df4174ba16e3f49ad9f +web.zh.md: 80dee03e0037cd2515ab49ba0a425312f2d87813 diff --git a/docs/subsystems/web.md b/docs/subsystems/web.md index 2a7cc499b4..43b9d378a1 100644 --- a/docs/subsystems/web.md +++ b/docs/subsystems/web.md @@ -195,5 +195,5 @@ async search(request: WebSearchRequest, signal?: AbortSignal): Promise ``` -Source: [`packages/web/web/src/index.ts:74`](../../packages/web/web/src/index.ts) +Source: [`packages/web/web/src/index.ts`](../../packages/web/web/src/index.ts) diff --git a/docs/subsystems/web.zh.md b/docs/subsystems/web.zh.md index 6857f2a06a..80dee03e00 100644 --- a/docs/subsystems/web.zh.md +++ b/docs/subsystems/web.zh.md @@ -195,5 +195,5 @@ async search(request: WebSearchRequest, signal?: AbortSignal): Promise ``` -Source: [`packages/web/web/src/index.ts:74`](../../packages/web/web/src/index.ts) +Source: [`packages/web/web/src/index.ts`](../../packages/web/web/src/index.ts) diff --git a/docs/subsystems/workflow.i18n.yaml b/docs/subsystems/workflow.i18n.yaml index f1ddf20d11..7e69a5497a 100644 --- a/docs/subsystems/workflow.i18n.yaml +++ b/docs/subsystems/workflow.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write docs/subsystems/workflow.md -workflow.md: 4c552b31435963d4133a31f2e98f8a913305c1f8 -workflow.zh.md: 53ef84134b00e323bd5331ff30b18012124b5241 +workflow.md: 5e8b4a8d8fb73a7ef404305a27e297df824c7dd9 +workflow.zh.md: 14d4a443d8ba26ffa2c16064eed86b7b1bbf32d9 diff --git a/docs/subsystems/workflow.md b/docs/subsystems/workflow.md index 4c552b3143..5e8b4a8d8f 100644 --- a/docs/subsystems/workflow.md +++ b/docs/subsystems/workflow.md @@ -155,7 +155,7 @@ Workflow Service Definition contract. Invalid requests throw before publication; abstract start(request: WorkflowStartRequest): WorkflowRun ``` -Source: [`packages/workflow/workflow/src/index.ts:159`](../../packages/workflow/workflow/src/index.ts) +Source: [`packages/workflow/workflow/src/index.ts`](../../packages/workflow/workflow/src/index.ts) @@ -181,7 +181,7 @@ One `agent()` call settled (clean result, child failure, or run cancellation). P 'workflow/agent-end'(info: WorkflowRunInfo, agent: WorkflowAgentEndInfo): void ``` -Source: [`packages/workflow/workflow/src/index.ts:81`](../../packages/workflow/workflow/src/index.ts) +Source: [`packages/workflow/workflow/src/index.ts`](../../packages/workflow/workflow/src/index.ts) @@ -202,7 +202,7 @@ One `agent()` call established a published child run. Paired with Events['workfl 'workflow/agent-start'(info: WorkflowRunInfo, agent: WorkflowAgentInfo): void ``` -Source: [`packages/workflow/workflow/src/index.ts:70`](../../packages/workflow/workflow/src/index.ts) +Source: [`packages/workflow/workflow/src/index.ts`](../../packages/workflow/workflow/src/index.ts) @@ -223,7 +223,7 @@ A workflow run settled (any stop reason). Fired when WorkflowRun.result resolves 'workflow/end'(info: WorkflowRunInfo, result: WorkflowResultInfo): void ``` -Source: [`packages/workflow/workflow/src/index.ts:91`](../../packages/workflow/workflow/src/index.ts) +Source: [`packages/workflow/workflow/src/index.ts`](../../packages/workflow/workflow/src/index.ts) @@ -241,7 +241,7 @@ The script emitted a narration line (a `log(message)` call). 'workflow/log'(info: WorkflowRunInfo, message: string): void ``` -Source: [`packages/workflow/workflow/src/index.ts:60`](../../packages/workflow/workflow/src/index.ts) +Source: [`packages/workflow/workflow/src/index.ts`](../../packages/workflow/workflow/src/index.ts) @@ -260,7 +260,7 @@ The script entered a phase (a `phase(title)` call) — progress grouping for obs 'workflow/phase'(info: WorkflowRunInfo, title: string): void ``` -Source: [`packages/workflow/workflow/src/index.ts:53`](../../packages/workflow/workflow/src/index.ts) +Source: [`packages/workflow/workflow/src/index.ts`](../../packages/workflow/workflow/src/index.ts) @@ -278,5 +278,5 @@ A workflow run started — the script's meta block validated, the body about to 'workflow/start'(info: WorkflowRunInfo): void ``` -Source: [`packages/workflow/workflow/src/index.ts:45`](../../packages/workflow/workflow/src/index.ts) +Source: [`packages/workflow/workflow/src/index.ts`](../../packages/workflow/workflow/src/index.ts) diff --git a/docs/subsystems/workflow.zh.md b/docs/subsystems/workflow.zh.md index 53ef84134b..14d4a443d8 100644 --- a/docs/subsystems/workflow.zh.md +++ b/docs/subsystems/workflow.zh.md @@ -155,7 +155,7 @@ Workflow Service Definition contract. Invalid requests throw before publication; abstract start(request: WorkflowStartRequest): WorkflowRun ``` -Source: [`packages/workflow/workflow/src/index.ts:159`](../../packages/workflow/workflow/src/index.ts) +Source: [`packages/workflow/workflow/src/index.ts`](../../packages/workflow/workflow/src/index.ts) @@ -181,7 +181,7 @@ One `agent()` call settled (clean result, child failure, or run cancellation). P 'workflow/agent-end'(info: WorkflowRunInfo, agent: WorkflowAgentEndInfo): void ``` -Source: [`packages/workflow/workflow/src/index.ts:81`](../../packages/workflow/workflow/src/index.ts) +Source: [`packages/workflow/workflow/src/index.ts`](../../packages/workflow/workflow/src/index.ts) @@ -202,7 +202,7 @@ One `agent()` call established a published child run. Paired with Events['workfl 'workflow/agent-start'(info: WorkflowRunInfo, agent: WorkflowAgentInfo): void ``` -Source: [`packages/workflow/workflow/src/index.ts:70`](../../packages/workflow/workflow/src/index.ts) +Source: [`packages/workflow/workflow/src/index.ts`](../../packages/workflow/workflow/src/index.ts) @@ -223,7 +223,7 @@ A workflow run settled (any stop reason). Fired when WorkflowRun.result resolves 'workflow/end'(info: WorkflowRunInfo, result: WorkflowResultInfo): void ``` -Source: [`packages/workflow/workflow/src/index.ts:91`](../../packages/workflow/workflow/src/index.ts) +Source: [`packages/workflow/workflow/src/index.ts`](../../packages/workflow/workflow/src/index.ts) @@ -241,7 +241,7 @@ The script emitted a narration line (a `log(message)` call). 'workflow/log'(info: WorkflowRunInfo, message: string): void ``` -Source: [`packages/workflow/workflow/src/index.ts:60`](../../packages/workflow/workflow/src/index.ts) +Source: [`packages/workflow/workflow/src/index.ts`](../../packages/workflow/workflow/src/index.ts) @@ -260,7 +260,7 @@ The script entered a phase (a `phase(title)` call) — progress grouping for obs 'workflow/phase'(info: WorkflowRunInfo, title: string): void ``` -Source: [`packages/workflow/workflow/src/index.ts:53`](../../packages/workflow/workflow/src/index.ts) +Source: [`packages/workflow/workflow/src/index.ts`](../../packages/workflow/workflow/src/index.ts) @@ -278,5 +278,5 @@ A workflow run started — the script's meta block validated, the body about to 'workflow/start'(info: WorkflowRunInfo): void ``` -Source: [`packages/workflow/workflow/src/index.ts:45`](../../packages/workflow/workflow/src/index.ts) +Source: [`packages/workflow/workflow/src/index.ts`](../../packages/workflow/workflow/src/index.ts) diff --git a/docs/subsystems/workspace.i18n.yaml b/docs/subsystems/workspace.i18n.yaml index b2c2248876..72fec29277 100644 --- a/docs/subsystems/workspace.i18n.yaml +++ b/docs/subsystems/workspace.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write docs/subsystems/workspace.md -workspace.md: ca088a2091a7f47a3d52992fec13fae44061a608 -workspace.zh.md: e414c759a043f934e1a8b5d89c7a3b6101bbb6f4 +workspace.md: b23e38be71e902da60794f1287bad1f9f18558a3 +workspace.zh.md: 8843ff5ef1968e3a140d4fc382c46deb7a8807ee diff --git a/docs/subsystems/workspace.md b/docs/subsystems/workspace.md index ca088a2091..b23e38be71 100644 --- a/docs/subsystems/workspace.md +++ b/docs/subsystems/workspace.md @@ -147,7 +147,7 @@ Abstract directory-picking service. Subclass, implement `capability()`, and load abstract capability(): DirectoryPickerCapability ``` -Source: [`packages/host/directory-picker/src/index.ts:131`](../../packages/host/directory-picker/src/index.ts) +Source: [`packages/host/directory-picker/src/index.ts`](../../packages/host/directory-picker/src/index.ts) @@ -215,5 +215,5 @@ async resolveByPath(path: string): Promise Types: [SessionId](core.md) -Source: [`packages/workspace/workspace/src/index.ts:81`](../../packages/workspace/workspace/src/index.ts) +Source: [`packages/workspace/workspace/src/index.ts`](../../packages/workspace/workspace/src/index.ts) diff --git a/docs/subsystems/workspace.zh.md b/docs/subsystems/workspace.zh.md index e414c759a0..8843ff5ef1 100644 --- a/docs/subsystems/workspace.zh.md +++ b/docs/subsystems/workspace.zh.md @@ -147,7 +147,7 @@ Abstract directory-picking service. Subclass, implement `capability()`, and load abstract capability(): DirectoryPickerCapability ``` -Source: [`packages/host/directory-picker/src/index.ts:131`](../../packages/host/directory-picker/src/index.ts) +Source: [`packages/host/directory-picker/src/index.ts`](../../packages/host/directory-picker/src/index.ts) @@ -215,5 +215,5 @@ async resolveByPath(path: string): Promise Types: [SessionId](core.md) -Source: [`packages/workspace/workspace/src/index.ts:81`](../../packages/workspace/workspace/src/index.ts) +Source: [`packages/workspace/workspace/src/index.ts`](../../packages/workspace/workspace/src/index.ts) diff --git a/packages/typert/generator/src/cordis-catalog.ts b/packages/typert/generator/src/cordis-catalog.ts index 1950c255cb..8f8520d22b 100644 --- a/packages/typert/generator/src/cordis-catalog.ts +++ b/packages/typert/generator/src/cordis-catalog.ts @@ -734,6 +734,12 @@ function anchorFor(headingText: string): string[] { return [``, ''] } +/** Render a subsystem `file:line` source pointer as a file-only link. */ +function sourceLink(source: string): string { + const file = source.split(':')[0] + return `[\`${file}\`](../../${file})` +} + /** Render one harness event entry onto its owning page, nested under its scope heading. */ function renderEvent(e: EventEntry, onPage: string, linkedTypePages: Readonly>): string[] { const out = [...anchorFor(`${e.name} — ${e.mode}`), `#### \`${e.name}\` — ${e.mode}`, ''] @@ -741,7 +747,7 @@ function renderEvent(e: EventEntry, onPage: string, linkedTypePages: Readonly method.signature).join('\n'), onPage, linkedTypePages) if (links) out.push(links, '') } - out.push(`Source: [\`${s.source}\`](../../${s.source.split(':')[0]})`, '') + out.push(`Source: ${sourceLink(s.source)}`, '') return out } diff --git a/packages/typert/generator/tests/cordis-catalog.spec.ts b/packages/typert/generator/tests/cordis-catalog.spec.ts index 9474c15145..28fa27bbe8 100644 --- a/packages/typert/generator/tests/cordis-catalog.spec.ts +++ b/packages/typert/generator/tests/cordis-catalog.spec.ts @@ -5,12 +5,46 @@ import { projectCordisCatalog, renderInheritedPage, renderPageRegion, + type CordisCatalogPolicy, } from '../src/cordis-catalog.ts' import { CORDIS_CATALOG_POLICY, EVENT_SCOPE_PAGE, REGION_BEGIN, REGION_END, SERVICE_PAGE } from '../../../../scripts/gen-cordis-catalog.ts' const workspaceRoot = resolve(import.meta.dirname, '../../../..') +const SOURCE_LINK_POLICY: CordisCatalogPolicy = { + linkedTypePages: {}, + foundationTypeNames: new Set(), + typeLinkExemptions: {}, + inheritedEvents: [{ name: 'ready', summary: 'Ready.', source: 'vendor/cordis/src/events.ts:9' }], + inheritedServices: [{ name: 'ctx.root', summary: 'Root.', source: 'vendor/cordis/src/context.ts:12' }], +} + describe('Typert-backed Cordis catalog', () => { + it('omits subsystem source lines while preserving inherited Cordis source lines', () => { + const page = renderPageRegion('fixture.md', [{ + key: 'fixture', + type: 'Fixture', + abstract: false, + doc: 'Fixture.', + methods: [], + source: 'packages/fixture/service.ts:24', + }], [{ + name: 'fixture/ready', + scope: 'fixture', + signature: "'fixture/ready'(): void", + jsDoc: '/** Ready. */', + mode: 'emit', + doc: 'Ready.', + source: 'packages/fixture/events.ts:42', + }], SOURCE_LINK_POLICY) + const inherited = renderInheritedPage(SOURCE_LINK_POLICY) + + expect(page).toContain('Source: [`packages/fixture/events.ts`](../../packages/fixture/events.ts)') + expect(page).toContain('Source: [`packages/fixture/service.ts`](../../packages/fixture/service.ts)') + expect(inherited).toContain('([`vendor/cordis/src/events.ts:9`](../../vendor/cordis/src/events.ts))') + expect(inherited).toContain('([`vendor/cordis/src/context.ts:12`](../../vendor/cordis/src/context.ts))') + }) + it('reproduces every committed catalog artifact byte for byte', { timeout: 480_000 }, () => { const { projector, model } = projectCordisCatalog(workspaceRoot, CORDIS_CATALOG_POLICY) const expected = (path: string): string => readFileSync(join(workspaceRoot, path), 'utf8') From 92723cafeb5547fd303e6c5fca9836dc783d0ceb Mon Sep 17 00:00:00 2001 From: lsdsjy <1356263+lsdsjy@users.noreply.github.com> Date: Thu, 20 Aug 2026 15:07:39 +0800 Subject: [PATCH 2/5] fix(frontend-static): return 404 for missing paths --- ...6-08-20-explicit-web-index-paths.i18n.yaml | 6 +++ .../2026-08-20-explicit-web-index-paths.md | 27 ++++++++++ .../2026-08-20-explicit-web-index-paths.zh.md | 27 ++++++++++ docs/subsystems/client-modules.i18n.yaml | 4 +- docs/subsystems/client-modules.md | 2 +- docs/subsystems/client-modules.zh.md | 2 +- docs/subsystems/web-server.i18n.yaml | 4 +- docs/subsystems/web-server.md | 4 +- docs/subsystems/web-server.zh.md | 4 +- .../host/frontend-static/README.i18n.yaml | 4 +- packages/host/frontend-static/README.md | 3 +- packages/host/frontend-static/README.zh.md | 3 +- packages/host/frontend-static/package.json | 2 +- packages/host/frontend-static/src/index.ts | 31 +++++++----- .../tests/frontend-static.spec.ts | 49 +++++++++++++++---- 15 files changed, 137 insertions(+), 35 deletions(-) create mode 100644 .agents/notes/implemented/bug-fix/2026-08-20-explicit-web-index-paths.i18n.yaml create mode 100644 .agents/notes/implemented/bug-fix/2026-08-20-explicit-web-index-paths.md create mode 100644 .agents/notes/implemented/bug-fix/2026-08-20-explicit-web-index-paths.zh.md diff --git a/.agents/notes/implemented/bug-fix/2026-08-20-explicit-web-index-paths.i18n.yaml b/.agents/notes/implemented/bug-fix/2026-08-20-explicit-web-index-paths.i18n.yaml new file mode 100644 index 0000000000..0efe5d0ca3 --- /dev/null +++ b/.agents/notes/implemented/bug-fix/2026-08-20-explicit-web-index-paths.i18n.yaml @@ -0,0 +1,6 @@ +# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each +# side as of the last confirmed-consistent state. Both languages carry equal authority; +# after editing either side, bring the other along and re-record with: +# pnpm run verify-translation-pairing --write .agents/notes/implemented/bug-fix/2026-08-20-explicit-web-index-paths.md +2026-08-20-explicit-web-index-paths.md: 6ff08c3c2a18ffd79ef7a048f563a91e41a504da +2026-08-20-explicit-web-index-paths.zh.md: 7b419b9f4c8b4b0de20660b3f70d12e67ab264ff diff --git a/.agents/notes/implemented/bug-fix/2026-08-20-explicit-web-index-paths.md b/.agents/notes/implemented/bug-fix/2026-08-20-explicit-web-index-paths.md new file mode 100644 index 0000000000..6ff08c3c2a --- /dev/null +++ b/.agents/notes/implemented/bug-fix/2026-08-20-explicit-web-index-paths.md @@ -0,0 +1,27 @@ +# Agent Note: Explicit Web index paths and 404 static misses + +Status: implemented + +English | [中文](2026-08-20-explicit-web-index-paths.zh.md) + +## Problem + +An unconditional SPA fallback makes every unmatched GET or HEAD request look successful. A broken ordinary link and a missing JavaScript, stylesheet, source map, or manifest then receive the HTML shell with status 200, so browsers, caches, and monitoring cannot distinguish a valid page entry from an absent resource. + +## Decision + +`dsh-host-frontend-static` renders `index.html` only when the normalized target is the dist root or the configured index path. The current Web client has no History API pathname routes; query strings do not change pathname matching, and URL fragments never reach the server. Existing files are served normally, while `ENOENT`, `EISDIR`, and `ENOTDIR` reads produce an empty 404 response with no content type. Other filesystem failures are rethrown to the webserver's request-failure handling instead of being mislabeled as absence. + +GET and HEAD use the same status and content type for index entries, files, and misses. Named routes still match before the fallback, traversal outside the dist root remains 403, and non-GET/HEAD requests reaching the fallback remain 405. + +## Alternatives considered + +**Infer page routes from the absence of a file extension.** A file extension does not declare a client route: this would still turn unknown ordinary paths into successful pages, reject any future dotted client route, and mishandle extensionless static files when they are absent. + +**Use an `Accept: text/html` request header as the fallback rule.** The header expresses representation preference, not whether the pathname is a declared client route. Browser fetches, bots, and monitors may request HTML for an invalid path, so the same false-success behavior remains. + +**Add a configurable pathname allowlist now.** No current client route consumes such configuration. A future History API router can add an explicit server rule or configuration field together with the route that requires it, without preserving a speculative public option today. + +## Consequences + +Broken links and missing assets have distinct HTTP state that caches and monitoring can observe, and an asset loader cannot execute the HTML shell as JavaScript. A future pathname-based client route returns 404 until its server entry rule and real-composition coverage land in the same change. The frontend-static real Loader test pins GET/HEAD parity for index entries, existing assets, ordinary misses, and resource misses; it also covers API-like paths, traversal, malformed targets, unsupported methods, and fallback disposal. diff --git a/.agents/notes/implemented/bug-fix/2026-08-20-explicit-web-index-paths.zh.md b/.agents/notes/implemented/bug-fix/2026-08-20-explicit-web-index-paths.zh.md new file mode 100644 index 0000000000..7b419b9f4c --- /dev/null +++ b/.agents/notes/implemented/bug-fix/2026-08-20-explicit-web-index-paths.zh.md @@ -0,0 +1,27 @@ +# Agent Note: 显式 Web index 路径与静态资源未命中的 404 + +Status: implemented + +[English](2026-08-20-explicit-web-index-paths.md) | 中文 + +## 问题 + +无条件 SPA 回退会让每个未匹配的 GET 或 HEAD 请求看起来都成功。失效的普通链接,以及缺失的 JavaScript、样式表、source map 或 manifest,都会收到状态码为 200 的 HTML 外壳,导致浏览器、缓存与监控无法区分有效页面入口和缺失资源。 + +## 决策 + +`dsh-host-frontend-static` 只在规范化目标为 dist 根目录或配置的 index 路径时渲染 `index.html`。当前 Web 客户端没有 History API pathname 路由;查询字符串不会改变 pathname 匹配,URL 片段也不会到达服务器。现有文件照常提供,而 `ENOENT`、`EISDIR` 和 `ENOTDIR` 读取产生不带内容类型的空 404 响应。其他文件系统失败会重新抛给 webserver 的请求失败处理,不会被错误标记为缺失。 + +GET 与 HEAD 对 index 入口、文件和未命中项使用相同的状态码与内容类型。具名路由仍先于回退匹配,越出 dist 根目录的遍历仍返回 403,到达回退的非 GET/HEAD 请求仍返回 405。 + +## 曾考虑的替代方案 + +**根据路径没有文件扩展名来推断页面路由。** 文件扩展名不会声明客户端路由:这种做法仍会把未知普通路径变成成功页面,会拒绝未来任何带点号的客户端路由,也会在缺少无扩展名静态文件时错误处理该请求。 + +**把 `Accept: text/html` 请求头作为回退规则。** 该请求头表达的是内容表示偏好,而不是 pathname 是否为已声明的客户端路由。浏览器 fetch、机器人和监控都可能为无效路径请求 HTML,因此仍会产生同样的假成功行为。 + +**立即添加可配置的 pathname 允许列表。** 当前没有客户端路由消费这项配置。未来的 History API 路由可以在引入所需路由时,同时添加显式服务器规则或配置字段,无需现在保留推测性的公开选项。 + +## 后果 + +失效链接与缺失资源具有可供缓存和监控观察的独立 HTTP 状态,资源加载器也不会把 HTML 外壳当作 JavaScript 执行。未来基于 pathname 的客户端路由会保持 404,直到同一项变更同时加入服务器入口规则与真实组合测试。frontend-static 的真实 Loader 测试固定了 index 入口、现有资源、普通未命中和资源未命中的 GET/HEAD 状态一致性,并覆盖类似 API 的路径、路径遍历、畸形目标、不支持的方法和回退释放。 diff --git a/docs/subsystems/client-modules.i18n.yaml b/docs/subsystems/client-modules.i18n.yaml index 1020af937b..9e4e1a9dd7 100644 --- a/docs/subsystems/client-modules.i18n.yaml +++ b/docs/subsystems/client-modules.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write docs/subsystems/client-modules.md -client-modules.md: 7003454792f4ffed1776d1ab3b1df8e811caca49 -client-modules.zh.md: ae5a6aab0391453540a772472250a693be72710f +client-modules.md: ae767c6a098cb1b7188c06e61efd2798eb93ff66 +client-modules.zh.md: 710453e3e10c298ed8c2b87bbab6e8e9eb154a87 diff --git a/docs/subsystems/client-modules.md b/docs/subsystems/client-modules.md index 7003454792..ae767c6a09 100644 --- a/docs/subsystems/client-modules.md +++ b/docs/subsystems/client-modules.md @@ -62,7 +62,7 @@ Package metadata — including the negative "not a client package" verdict — i ## The bundle route and index injection -`GET`/`HEAD /plugins//client.js` serves the registered bundle from disk with `no-cache` (the rev query, not HTTP caching, anchors consistency); other methods are 405. An unknown id — or a registered row whose bundle is unreadable because it has not been built yet — answers a loud 404 rather than letting the carrier's SPA fallback ship HTML as JavaScript. The injection rows carry the current graph on every index render, so a reload always boots against the live composition. +`GET`/`HEAD /plugins//client.js` serves the registered bundle from disk with `no-cache` (the rev query, not HTTP caching, anchors consistency); other methods are 405. An unknown id — or a registered row whose bundle is unreadable because it has not been built yet — answers a loud 404, so no unreadable bundle appears as a successful JavaScript response. The injection rows carry the current graph on every index render, so a reload always boots against the live composition. ## The service diff --git a/docs/subsystems/client-modules.zh.md b/docs/subsystems/client-modules.zh.md index ae5a6aab03..710453e3e1 100644 --- a/docs/subsystems/client-modules.zh.md +++ b/docs/subsystems/client-modules.zh.md @@ -62,7 +62,7 @@ interface WebBootGraph { ## bundle 路由与 index 注入 -`GET`/`HEAD /plugins//client.js` 以 `no-cache` 从磁盘提供已注册的 bundle(锚定一致性的是 rev 查询参数,而非 HTTP 缓存);其他方法返回 405。未知 id——或已注册、但 bundle 因尚未构建而不可读的行——回应一个大声的 404,而不是让载体的 SPA 回退把 HTML 当作 JavaScript 发出。注入行在每次 index 渲染时携带当前图,因此刷新页面总是针对实时组合启动。 +`GET`/`HEAD /plugins//client.js` 以 `no-cache` 从磁盘提供已注册的 bundle(锚定一致性的是 rev 查询参数,而非 HTTP 缓存);其他方法返回 405。未知 id——或已注册、但 bundle 因尚未构建而不可读的行——回应一个大声的 404,因此不可读 bundle 不会表现为成功的 JavaScript 响应。注入行在每次 index 渲染时携带当前图,因此刷新页面总是针对实时组合启动。 ## 服务 diff --git a/docs/subsystems/web-server.i18n.yaml b/docs/subsystems/web-server.i18n.yaml index 37263bb0c4..2c23ed2e72 100644 --- a/docs/subsystems/web-server.i18n.yaml +++ b/docs/subsystems/web-server.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write docs/subsystems/web-server.md -web-server.md: c60047c2ffb45b7316e994bd3a606f4b82a872dc -web-server.zh.md: 29a46280c603bca89fa7f552b9813ccffb0f6bcc +web-server.md: 439b8ceafc363c7fa1cfa91997f39b4aa97a3397 +web-server.zh.md: 1aeb747230affcdc581c094c520cb6ceab459df4 diff --git a/docs/subsystems/web-server.md b/docs/subsystems/web-server.md index c60047c2ff..439b8ceafc 100644 --- a/docs/subsystems/web-server.md +++ b/docs/subsystems/web-server.md @@ -24,7 +24,7 @@ interface WebRoute { } ``` -Match order is fixed: exact table first, then longest matching prefix, then the registered fallback. Registration order carries no request-facing semantics — named routes are composed to be disjoint, and the fallback seat answers anything no named route claims; one owner only, a second registration throws. The shipped Web composition claims the seat with [`dsh-host-frontend-static`](../../packages/host/frontend-static/src/index.ts), the SPA dist server with locked semantics: non-GET/HEAD is 405, traversal outside the dist root is 403, any miss falls back to `index.html` with HTTP 200 (SPA routing), and unknown extensions ship as octet-stream. +Match order is fixed: exact table first, then longest matching prefix, then the registered fallback. Registration order carries no request-facing semantics — named routes are composed to be disjoint, and the fallback seat answers anything no named route claims; one owner only, a second registration throws. The shipped Web composition claims the seat with [`dsh-host-frontend-static`](../../packages/host/frontend-static/src/index.ts), the SPA dist server with locked semantics: non-GET/HEAD is 405, traversal outside the dist root is 403, the dist root and configured index path render `index.html`, missing paths are empty 404 responses, and unknown extensions ship as octet-stream. ## Config @@ -42,7 +42,7 @@ interface Config { ## The service -`WebServer` (`ctx.webServer`) listens immediately on activation; a listen failure (EADDRINUSE…) rejects initialization, and the boot process reports the failed fiber. `register(route)` adds one named route and returns its disposer; a duplicate `(kind, path)` throws because route patterns are a composition-level contract and a collision is a misconfiguration. `collectIndexInjections()` gathers structured `IndexInjection` rows over one `webserver/index-inject` emit, and `renderIndex(html)` renders them into every index response — `/` and each SPA fallback — before applying the raw `tapIndex(transform)` escape-hatch transforms in registration order; [dsh-client-modules](../../packages/client/modules) answers the event with the boot manifest rows. `port` reads the listening port, including the port assigned by the OS when `config.port` is 0. +`WebServer` (`ctx.webServer`) listens immediately on activation; a listen failure (EADDRINUSE…) rejects initialization, and the boot process reports the failed fiber. `register(route)` adds one named route and returns its disposer; a duplicate `(kind, path)` throws because route patterns are a composition-level contract and a collision is a misconfiguration. `collectIndexInjections()` gathers structured `IndexInjection` rows over one `webserver/index-inject` emit, and `renderIndex(html)` renders them into the root and configured index responses before applying the raw `tapIndex(transform)` escape-hatch transforms in registration order; [dsh-client-modules](../../packages/client/modules) answers the event with the boot manifest rows. `port` reads the listening port, including the port assigned by the OS when `config.port` is 0. A request whose handling throws (a malformed %-escape hitting `decodeURIComponent`, a client dropping mid-body) is logged as a warning and answered 400 — or the socket destroyed when headers are already out — never a process exit. Disposal pairs `close()` with `closeAllConnections()` because a handler may hold its response open (SSE) and such connections never end on their own; without the force-close, teardown would hang. The package never prints: the URL line belongs to the shell. Per-package operational detail, including the dev-mode bundle watch pipeline, stays in the [README](../../packages/host/webserver/README.md). diff --git a/docs/subsystems/web-server.zh.md b/docs/subsystems/web-server.zh.md index 29a46280c6..1aeb747230 100644 --- a/docs/subsystems/web-server.zh.md +++ b/docs/subsystems/web-server.zh.md @@ -24,7 +24,7 @@ interface WebRoute { } ``` -匹配顺序固定:先查 exact 表,再取最长匹配前缀,最后落到已注册的回退。注册顺序不携带任何面向请求的语义:具名路由在组合上互不相交,任何未被具名路由认领的请求都由回退席位应答;席位只有一个所有者,第二次注册会抛出异常。发布的 Web 组合用 [`dsh-host-frontend-static`](../../packages/host/frontend-static/src/index.ts) 认领席位,即遵循固定语义的 SPA dist 服务器:非 GET/HEAD 返回 405,越出 dist 根目录的遍历返回 403,任何未命中都以 HTTP 200 回退到 `index.html`(SPA 路由),未知扩展名按 octet-stream 发送。 +匹配顺序固定:先查 exact 表,再取最长匹配前缀,最后落到已注册的回退。注册顺序不携带任何面向请求的语义:具名路由在组合上互不相交,任何未被具名路由认领的请求都由回退席位应答;席位只有一个所有者,第二次注册会抛出异常。发布的 Web 组合用 [`dsh-host-frontend-static`](../../packages/host/frontend-static/src/index.ts) 认领席位,即遵循固定语义的 SPA dist 服务器:非 GET/HEAD 返回 405,越出 dist 根目录的遍历返回 403,dist 根目录和配置的 index 路径渲染 `index.html`,缺失路径返回空的 404,未知扩展名按 octet-stream 发送。 ## 配置 @@ -42,7 +42,7 @@ interface Config { ## 服务 -`WebServer`(`ctx.webServer`)在激活时立即监听;监听失败(EADDRINUSE 等)会使初始化被拒绝,启动进程会报告失败的 fiber。`register(route)` 添加一条具名路由并返回其 disposer;重复的 `(kind, path)` 抛出异常,因为路由模式是组合层约定,冲突即配置错误。`collectIndexInjections()` 经一次 `webserver/index-inject` emit 收集结构化 `IndexInjection` 行,`renderIndex(html)` 把它们渲染进每个 index 响应(`/` 和每次 SPA 回退),随后再按注册顺序应用原始的 `tapIndex(transform)` 逃生口转换;[dsh-client-modules](../../packages/client/modules) 以启动 manifest(元数据清单)行回应该事件。`port` 读取监听端口,包括 `config.port` 为 0 时操作系统分配的端口。 +`WebServer`(`ctx.webServer`)在激活时立即监听;监听失败(EADDRINUSE 等)会使初始化被拒绝,启动进程会报告失败的 fiber。`register(route)` 添加一条具名路由并返回其 disposer;重复的 `(kind, path)` 抛出异常,因为路由模式是组合层约定,冲突即配置错误。`collectIndexInjections()` 经一次 `webserver/index-inject` emit 收集结构化 `IndexInjection` 行,`renderIndex(html)` 把它们渲染进根路径和配置的 index 响应,随后再按注册顺序应用原始的 `tapIndex(transform)` 逃生口转换;[dsh-client-modules](../../packages/client/modules) 以启动 manifest(元数据清单)行回应该事件。`port` 读取监听端口,包括 `config.port` 为 0 时操作系统分配的端口。 处理过程中抛出异常的请求(畸形的 % 转义撞上 `decodeURIComponent`、客户端在请求体中途断开)会记录为警告并应答 400(响应头已发出时则销毁 socket),绝不导致进程退出。dispose(资源释放)把 `close()` 与 `closeAllConnections()` 配对使用,因为处理器可能像 SSE(Server-Sent Events)那样保持响应打开,而这类连接永远不会自行结束;没有强制关闭,拆卸就会挂起。该包从不打印输出:URL 行归 shell 所有。逐包运维细节(含开发模式的 bundle 监视流水线)留在 [README](../../packages/host/webserver/README.zh.md) 中。 diff --git a/packages/host/frontend-static/README.i18n.yaml b/packages/host/frontend-static/README.i18n.yaml index 22b23d33bf..3115d93aa3 100644 --- a/packages/host/frontend-static/README.i18n.yaml +++ b/packages/host/frontend-static/README.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write packages/host/frontend-static/README.md -README.md: fb9ab0c9fea6fdaffdc08ecb63b17ffff9ff1e16 -README.zh.md: 53955c1f43f9404d3a0f58117649c4b79e2cf692 +README.md: d0c99a57230d7accc93a654f21c002762e2d2df3 +README.zh.md: a1fe98be24a639d75b3b5561c837b8f977954f7d diff --git a/packages/host/frontend-static/README.md b/packages/host/frontend-static/README.md index fb9ab0c9fe..d0c99a5723 100644 --- a/packages/host/frontend-static/README.md +++ b/packages/host/frontend-static/README.md @@ -2,7 +2,7 @@ English | [中文](README.zh.md) -SPA dist server for the Web shell: a function plugin (config `{distIndex}`) that claims the [webserver](../webserver/README.md)'s single fallback seat and serves the built frontend directory with the shell's locked semantics — traversal outside the dist root is 403, any miss falls back to `index.html` with HTTP 200 (SPA routing), unknown extensions ship as `application/octet-stream`, and non-GET/HEAD without a matching named route is 405. Every index response is rendered through the webserver's `renderIndex` — structured injection rows first, then the raw index taps — which is how the boot manifest reaches the page. `distIndex` is an assembly fact of the composing application: [`dsh-web-app`](../../bundle/web-app/README.md) resolves it through the frontend package's exports and mounts this plugin; a deployment never hardcodes it. +SPA dist server for the Web shell: a function plugin (config `{distIndex}`) that claims the [webserver](../webserver/README.md)'s single fallback seat and serves the built frontend directory with explicit index entry points. The dist root and configured index path render `index.html` with HTTP 200; an absent file or any other undeclared pathname returns an empty 404, traversal outside the dist root returns 403, unknown extensions ship as `application/octet-stream`, and non-GET/HEAD without a matching named route returns 405. Every index response is rendered through the webserver's `renderIndex` — structured injection rows first, then the raw index taps — which is how the boot manifest reaches the page. `distIndex` is an assembly fact of the composing application: [`dsh-web-app`](../../bundle/web-app/README.md) resolves it through the frontend package's exports and mounts this plugin; a deployment never hardcodes it. The fallback seat is single-owner (a second claim throws) and effect-scoped: disposing the plugin's fiber releases the seat, after which the unclaimed webserver answers 404. @@ -17,3 +17,4 @@ None; this package neither assembles nor sends a provider request. ## Known Limitations and Deferred Work - **The starter MIME table is minimal** — it covers the Vite-emitted asset set plus the shipped PWA manifest; other extensions fall back to `application/octet-stream` until an asset class actually ships. +- **Pathname routing is explicit** — the current client enters through the root or configured index path and has no History API pathname routes. Adding one requires an explicit server rule and real-composition coverage rather than a broad fallback for every miss. diff --git a/packages/host/frontend-static/README.zh.md b/packages/host/frontend-static/README.zh.md index 53955c1f43..a1fe98be24 100644 --- a/packages/host/frontend-static/README.zh.md +++ b/packages/host/frontend-static/README.zh.md @@ -2,7 +2,7 @@ [English](README.md) | 中文 -Web 壳的 SPA dist 服务器:一个函数插件(配置为 `{distIndex}`),占据 [webserver](../webserver/README.zh.md) 的唯一回退席位,并按壳层锁定的语义服务已构建的前端目录——越出 dist 根目录的遍历返回 403,任何未命中项都以 HTTP 200 回退到 `index.html`(SPA 路由),未知扩展名按 `application/octet-stream` 提供,GET/HEAD 之外的方法在没有匹配的具名路由时返回 405。每个 index 响应都经 webserver 的 `renderIndex` 渲染——先结构化注入行、后原始 index 转换器——启动 manifest(元数据清单)就是经这条路径送达页面的。`distIndex` 是组合应用的组装事实:[`dsh-web-app`](../../bundle/web-app/README.zh.md) 通过前端包的 exports 解析它并挂载本插件;部署绝不硬编码它。 +Web 壳的 SPA dist 服务器:一个函数插件(配置为 `{distIndex}`),占据 [webserver](../webserver/README.zh.md) 的唯一回退席位,并通过显式 index 入口服务已构建的前端目录。dist 根目录和配置的 index 路径以 HTTP 200 渲染 `index.html`;缺失文件或其他未声明的 pathname 返回空的 404,越出 dist 根目录的遍历返回 403,未知扩展名按 `application/octet-stream` 提供,GET/HEAD 之外的方法在没有匹配的具名路由时返回 405。每个 index 响应都经 webserver 的 `renderIndex` 渲染——先结构化注入行、后原始 index 转换器——启动 manifest(元数据清单)就是经这条路径送达页面的。`distIndex` 是组合应用的组装事实:[`dsh-web-app`](../../bundle/web-app/README.zh.md) 通过前端包的 exports 解析它并挂载本插件;部署绝不硬编码它。 回退席位只有单一所有者(第二次占据会抛错),并受 effect 作用域约束:dispose(资源释放)插件的 fiber 会释放席位,此后无人占据的 webserver 回答 404。 @@ -17,3 +17,4 @@ Web 壳的 SPA dist 服务器:一个函数插件(配置为 `{distIndex}`) ## 已知限制与延期工作 - **初始 MIME 表很精简**:它覆盖 Vite 输出的资产集合及实际交付的 PWA manifest;其他扩展名在相应资产类别实际发布前都会回退到 `application/octet-stream`。 +- **pathname 路由是显式的**:当前客户端只从根路径或配置的 index 路径进入,没有 History API pathname 路由。添加这类路由时必须同时添加显式服务器规则和真实组合测试,不得为每个未命中项启用宽泛回退。 diff --git a/packages/host/frontend-static/package.json b/packages/host/frontend-static/package.json index 07b44df96b..c938a923de 100644 --- a/packages/host/frontend-static/package.json +++ b/packages/host/frontend-static/package.json @@ -1,6 +1,6 @@ { "name": "@deepseek-ai/dsh-host-frontend-static", - "description": "SPA dist server for the Web shell: owns the webserver fallback seat, serving the built frontend with index-tap injection, traversal rejection, and SPA index fallback", + "description": "SPA dist server for the Web shell: owns the webserver fallback seat, serving explicit index entries and static assets with traversal rejection and 404 misses", "version": "0.1.0-rc.8", "publishConfig": { "access": "public" diff --git a/packages/host/frontend-static/src/index.ts b/packages/host/frontend-static/src/index.ts index ad516f1c79..935a9dfebc 100644 --- a/packages/host/frontend-static/src/index.ts +++ b/packages/host/frontend-static/src/index.ts @@ -1,11 +1,11 @@ /** * @deepseek-ai/dsh-host-frontend-static — SPA dist server over the webserver - * fallback seat: serves the built frontend directory with the semantics the - * Web shell locked at step1 — traversal outside the dist root is 403, any - * miss falls back to index.html with HTTP 200 (SPA routing), unknown - * extensions ship as octet-stream, non-GET/HEAD is 405. Every index response - * runs through the webserver's index render (structured injection rows, then - * raw taps). The dist location is workspace knowledge of the composing + * fallback seat: serves the built frontend directory with explicit index + * entry points. The dist root and configured index path render index.html; + * missing paths return 404, traversal outside the dist root is 403, unknown + * extensions ship as octet-stream, and non-GET/HEAD is 405. Every index + * response runs through the webserver's index render (structured injection + * rows, then raw taps). The dist location is workspace knowledge of the composing * application, so `distIndex` is typically supplied through a `!!js` * expression, never hardcoded by a deployment. * @module @deepseek-ai/dsh-host-frontend-static @@ -44,14 +44,20 @@ const MIME: Record = { '.webmanifest': 'application/manifest+json', } +const STATIC_MISS_CODES: ReadonlySet = new Set([ + 'ENOENT', + 'EISDIR', + 'ENOTDIR', +]) + /** * Serve one GET/HEAD static request from the dist root. * @param pathname - decoded URL pathname of the request. * @param res - the node:http response to write. * @param distRoot - absolute dist root directory (resolved by the caller). * @param distIndex - absolute path of index.html inside distRoot. - * @param renderIndex - produces the index.html body (injection rendering) for - * `/` and every SPA fallback. + * @param renderIndex - produces the index.html body (structured injection rendering) for + * the dist root and configured index path. */ export async function serveStatic( pathname: string, res: ServerResponse, distRoot: string, distIndex: string, @@ -79,9 +85,12 @@ export async function serveStatic( const body = await readFile(target) res.writeHead(200, { 'content-type': MIME[extname(target)] ?? 'application/octet-stream' }) res.end(body) - } catch { - // Miss (ENOENT/EISDIR) falls back to index.html with 200 (SPA routing). - await serveIndex() + } catch (error) { + // Only absent or non-file targets are 404; other filesystem failures reach + // the webserver's request-failure handling. + if (!STATIC_MISS_CODES.has((error as NodeJS.ErrnoException).code)) throw error + res.writeHead(404) + res.end() } } diff --git a/packages/host/frontend-static/tests/frontend-static.spec.ts b/packages/host/frontend-static/tests/frontend-static.spec.ts index 1b9fc9c65c..627a800d64 100644 --- a/packages/host/frontend-static/tests/frontend-static.spec.ts +++ b/packages/host/frontend-static/tests/frontend-static.spec.ts @@ -1,9 +1,9 @@ /** * REAL-composition coverage: a test-only cordis.yml booted through the * vendored Loader mounts the webserver and frontend-static rows, and every - * assertion observes the served HTTP surface — asset serving, MIME fallback, - * SPA index fallback with index taps, traversal rejection, 405 on non-GET/ - * HEAD, and seat release on fiber disposal (HMR safety). + * assertion observes the served HTTP surface — asset serving, explicit index + * entry points with index taps, 404 misses, traversal rejection, 405 on non- + * GET/HEAD, and seat release on fiber disposal (HMR safety). */ import { mkdir, mkdtemp, rm, writeFile } from 'node:fs/promises' @@ -37,6 +37,7 @@ async function loadComposition(): Promise { await writeFile(join(dist, 'app.js'), 'export {}') await writeFile(join(dist, 'blob.bin'), 'BLOB') await writeFile(join(dist, 'manifest.webmanifest'), '{}') + await mkdir(join(dist, 'empty')) const configPath = join(root, 'cordis.yml') await writeFile(configPath, [ "- name: '@deepseek-ai/dsh-host-webserver'", @@ -84,7 +85,7 @@ async function request(port: number, path: string, init?: RequestInit): Promise< } describe('real Loader composition', () => { - it('serves the dist with SPA fallback, taps, traversal rejection, and method gating', { timeout: 60_000 }, async () => { + it('serves explicit index entries and files while preserving HTTP error semantics', { timeout: 60_000 }, async () => { const loaded = await loadComposition() const unloaded = [...loaded.loader.entries()] .filter(entry => entry.fiber === undefined && !entry.disabled) @@ -100,27 +101,57 @@ describe('real Loader composition', () => { type: 'application/manifest+json', body: '{}', }) + expect(await request(port, '/app.js', { method: 'HEAD' })).toEqual({ + status: 200, + type: 'text/javascript; charset=utf-8', + body: '', + }) await writeFile(join(root!, 'dist', 'app.js'), 'export const rebuilt = true') expect(await request(port, '/app.js')).toMatchObject({ status: 200, body: 'export const rebuilt = true' }) // Unknown extension ships as octet-stream. expect(await request(port, '/blob.bin')).toMatchObject({ status: 200, type: 'application/octet-stream', body: 'BLOB' }) - // `/`, the index path, and any miss all render index.html (SPA routing) - // through the registered index taps. + // Only the root and index path render index.html through registered taps. const untap = server.tapIndex(html => html.replace('', '')) - for (const path of ['/', '/index.html', '/no/such/route']) { + for (const path of ['/', '/index.html', '/?fixture']) { const got = await request(port, path) expect(got.status).toBe(200) + expect(got.type).toBe('text/html; charset=utf-8') expect(got.body).toContain('__T__') expect(got.body).toContain('shell') } + expect(await request(port, '/', { method: 'HEAD' })).toEqual({ + status: 200, + type: 'text/html; charset=utf-8', + body: '', + }) untap() expect((await request(port, '/')).body).not.toContain('__T__') - // Traversal outside the dist root is 403; non-GET/HEAD is 405. + // Ordinary unknown paths and static-resource misses are empty 404s for + // both GET and HEAD; neither class can be mistaken for the HTML shell. + const ordinaryMisses = ['/no/such/route', '/api/no/such/route', '/empty', '/app.js/child'] + const assetMisses = [ + '/missing.js', + '/missing.css', + '/missing.mjs', + '/missing.js.map', + '/missing.webmanifest', + '/missing.manifest', + ] + for (const path of [...ordinaryMisses, ...assetMisses]) { + const get = await request(port, path) + const head = await request(port, path, { method: 'HEAD' }) + expect(get).toEqual({ status: 404, type: null, body: '' }) + expect(head).toEqual(get) + } + + // Traversal outside the dist root is 403, non-GET/HEAD is 405, and a + // malformed filesystem target still reaches the webserver's 400 guard. expect((await request(port, '/..%2f..%2fetc%2fpasswd')).status).toBe(403) - expect((await request(port, '/nowhere', { method: 'POST' })).status).toBe(405) + expect((await request(port, '/app.js', { method: 'POST' })).status).toBe(405) + expect((await request(port, '/bad%00path')).status).toBe(400) // HMR safety: disposing the frontend row releases the fallback seat (the // unclaimed webserver answers 404) and the seat is claimable again. From 600f3a3110135454a14228d1380420d258722194 Mon Sep 17 00:00:00 2001 From: lsdsjy <1356263+lsdsjy@users.noreply.github.com> Date: Thu, 20 Aug 2026 15:38:45 +0800 Subject: [PATCH 3/5] fix(frontend-static): return 404 for a missing index --- docs/subsystems/web-server.i18n.yaml | 4 +- docs/subsystems/web-server.md | 4 +- docs/subsystems/web-server.zh.md | 4 +- .../host/frontend-static/README.i18n.yaml | 4 +- packages/host/frontend-static/README.md | 2 +- packages/host/frontend-static/README.zh.md | 2 +- packages/host/frontend-static/src/index.ts | 46 ++++++++++--------- .../tests/frontend-static.spec.ts | 10 ++++ 8 files changed, 44 insertions(+), 32 deletions(-) diff --git a/docs/subsystems/web-server.i18n.yaml b/docs/subsystems/web-server.i18n.yaml index 2c23ed2e72..9434d236d4 100644 --- a/docs/subsystems/web-server.i18n.yaml +++ b/docs/subsystems/web-server.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write docs/subsystems/web-server.md -web-server.md: 439b8ceafc363c7fa1cfa91997f39b4aa97a3397 -web-server.zh.md: 1aeb747230affcdc581c094c520cb6ceab459df4 +web-server.md: c23a48cd57aeb2127107c0487cb46c9202d11605 +web-server.zh.md: 4097e26ce826067a92de7ba3ec65f790dd6ad1dd diff --git a/docs/subsystems/web-server.md b/docs/subsystems/web-server.md index 439b8ceafc..c23a48cd57 100644 --- a/docs/subsystems/web-server.md +++ b/docs/subsystems/web-server.md @@ -24,7 +24,7 @@ interface WebRoute { } ``` -Match order is fixed: exact table first, then longest matching prefix, then the registered fallback. Registration order carries no request-facing semantics — named routes are composed to be disjoint, and the fallback seat answers anything no named route claims; one owner only, a second registration throws. The shipped Web composition claims the seat with [`dsh-host-frontend-static`](../../packages/host/frontend-static/src/index.ts), the SPA dist server with locked semantics: non-GET/HEAD is 405, traversal outside the dist root is 403, the dist root and configured index path render `index.html`, missing paths are empty 404 responses, and unknown extensions ship as octet-stream. +Match order is fixed: exact table first, then longest matching prefix, then the registered fallback. Registration order carries no request-facing semantics — named routes are composed to be disjoint, and the fallback seat answers anything no named route claims; one owner only, a second registration throws. The shipped Web composition claims the seat with [`dsh-host-frontend-static`](../../packages/host/frontend-static/src/index.ts), the SPA dist server with locked semantics: non-GET/HEAD is 405, traversal outside the dist root is 403, a readable index renders at the dist root and configured index path, existing files are served directly, absent or non-file targets are empty 404 responses, and unknown extensions ship as octet-stream. ## Config @@ -42,7 +42,7 @@ interface Config { ## The service -`WebServer` (`ctx.webServer`) listens immediately on activation; a listen failure (EADDRINUSE…) rejects initialization, and the boot process reports the failed fiber. `register(route)` adds one named route and returns its disposer; a duplicate `(kind, path)` throws because route patterns are a composition-level contract and a collision is a misconfiguration. `collectIndexInjections()` gathers structured `IndexInjection` rows over one `webserver/index-inject` emit, and `renderIndex(html)` renders them into the root and configured index responses before applying the raw `tapIndex(transform)` escape-hatch transforms in registration order; [dsh-client-modules](../../packages/client/modules) answers the event with the boot manifest rows. `port` reads the listening port, including the port assigned by the OS when `config.port` is 0. +`WebServer` (`ctx.webServer`) listens immediately on activation; a listen failure (EADDRINUSE…) rejects initialization, and the boot process reports the failed fiber. `register(route)` adds one named route and returns its disposer; a duplicate `(kind, path)` throws because route patterns are a composition-level contract and a collision is a misconfiguration. `collectIndexInjections()` gathers structured `IndexInjection` rows over one `webserver/index-inject` emit, and `renderIndex(html)` renders them into successful root and configured index responses before applying the raw `tapIndex(transform)` escape-hatch transforms in registration order; [dsh-client-modules](../../packages/client/modules) answers the event with the boot manifest rows. `port` reads the listening port, including the port assigned by the OS when `config.port` is 0. A request whose handling throws (a malformed %-escape hitting `decodeURIComponent`, a client dropping mid-body) is logged as a warning and answered 400 — or the socket destroyed when headers are already out — never a process exit. Disposal pairs `close()` with `closeAllConnections()` because a handler may hold its response open (SSE) and such connections never end on their own; without the force-close, teardown would hang. The package never prints: the URL line belongs to the shell. Per-package operational detail, including the dev-mode bundle watch pipeline, stays in the [README](../../packages/host/webserver/README.md). diff --git a/docs/subsystems/web-server.zh.md b/docs/subsystems/web-server.zh.md index 1aeb747230..4097e26ce8 100644 --- a/docs/subsystems/web-server.zh.md +++ b/docs/subsystems/web-server.zh.md @@ -24,7 +24,7 @@ interface WebRoute { } ``` -匹配顺序固定:先查 exact 表,再取最长匹配前缀,最后落到已注册的回退。注册顺序不携带任何面向请求的语义:具名路由在组合上互不相交,任何未被具名路由认领的请求都由回退席位应答;席位只有一个所有者,第二次注册会抛出异常。发布的 Web 组合用 [`dsh-host-frontend-static`](../../packages/host/frontend-static/src/index.ts) 认领席位,即遵循固定语义的 SPA dist 服务器:非 GET/HEAD 返回 405,越出 dist 根目录的遍历返回 403,dist 根目录和配置的 index 路径渲染 `index.html`,缺失路径返回空的 404,未知扩展名按 octet-stream 发送。 +匹配顺序固定:先查 exact 表,再取最长匹配前缀,最后落到已注册的回退。注册顺序不携带任何面向请求的语义:具名路由在组合上互不相交,任何未被具名路由认领的请求都由回退席位应答;席位只有一个所有者,第二次注册会抛出异常。发布的 Web 组合用 [`dsh-host-frontend-static`](../../packages/host/frontend-static/src/index.ts) 认领席位,即遵循固定语义的 SPA dist 服务器:非 GET/HEAD 返回 405,越出 dist 根目录的遍历返回 403,可读的 index 在 dist 根目录和配置的 index 路径渲染,现有文件直接提供,缺失或不是文件的目标返回空的 404,未知扩展名按 octet-stream 发送。 ## 配置 @@ -42,7 +42,7 @@ interface Config { ## 服务 -`WebServer`(`ctx.webServer`)在激活时立即监听;监听失败(EADDRINUSE 等)会使初始化被拒绝,启动进程会报告失败的 fiber。`register(route)` 添加一条具名路由并返回其 disposer;重复的 `(kind, path)` 抛出异常,因为路由模式是组合层约定,冲突即配置错误。`collectIndexInjections()` 经一次 `webserver/index-inject` emit 收集结构化 `IndexInjection` 行,`renderIndex(html)` 把它们渲染进根路径和配置的 index 响应,随后再按注册顺序应用原始的 `tapIndex(transform)` 逃生口转换;[dsh-client-modules](../../packages/client/modules) 以启动 manifest(元数据清单)行回应该事件。`port` 读取监听端口,包括 `config.port` 为 0 时操作系统分配的端口。 +`WebServer`(`ctx.webServer`)在激活时立即监听;监听失败(EADDRINUSE 等)会使初始化被拒绝,启动进程会报告失败的 fiber。`register(route)` 添加一条具名路由并返回其 disposer;重复的 `(kind, path)` 抛出异常,因为路由模式是组合层约定,冲突即配置错误。`collectIndexInjections()` 经一次 `webserver/index-inject` emit 收集结构化 `IndexInjection` 行,`renderIndex(html)` 把它们渲染进成功的根路径和配置 index 响应,随后再按注册顺序应用原始的 `tapIndex(transform)` 逃生口转换;[dsh-client-modules](../../packages/client/modules) 以启动 manifest(元数据清单)行回应该事件。`port` 读取监听端口,包括 `config.port` 为 0 时操作系统分配的端口。 处理过程中抛出异常的请求(畸形的 % 转义撞上 `decodeURIComponent`、客户端在请求体中途断开)会记录为警告并应答 400(响应头已发出时则销毁 socket),绝不导致进程退出。dispose(资源释放)把 `close()` 与 `closeAllConnections()` 配对使用,因为处理器可能像 SSE(Server-Sent Events)那样保持响应打开,而这类连接永远不会自行结束;没有强制关闭,拆卸就会挂起。该包从不打印输出:URL 行归 shell 所有。逐包运维细节(含开发模式的 bundle 监视流水线)留在 [README](../../packages/host/webserver/README.zh.md) 中。 diff --git a/packages/host/frontend-static/README.i18n.yaml b/packages/host/frontend-static/README.i18n.yaml index 3115d93aa3..771455e06a 100644 --- a/packages/host/frontend-static/README.i18n.yaml +++ b/packages/host/frontend-static/README.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write packages/host/frontend-static/README.md -README.md: d0c99a57230d7accc93a654f21c002762e2d2df3 -README.zh.md: a1fe98be24a639d75b3b5561c837b8f977954f7d +README.md: e4f3765a0471566dfb2f6780b1072d3e79788dc5 +README.zh.md: 7672478480f07b760634fef0c8640fcbdc0e6e7e diff --git a/packages/host/frontend-static/README.md b/packages/host/frontend-static/README.md index d0c99a5723..e4f3765a04 100644 --- a/packages/host/frontend-static/README.md +++ b/packages/host/frontend-static/README.md @@ -2,7 +2,7 @@ English | [中文](README.zh.md) -SPA dist server for the Web shell: a function plugin (config `{distIndex}`) that claims the [webserver](../webserver/README.md)'s single fallback seat and serves the built frontend directory with explicit index entry points. The dist root and configured index path render `index.html` with HTTP 200; an absent file or any other undeclared pathname returns an empty 404, traversal outside the dist root returns 403, unknown extensions ship as `application/octet-stream`, and non-GET/HEAD without a matching named route returns 405. Every index response is rendered through the webserver's `renderIndex` — structured injection rows first, then the raw index taps — which is how the boot manifest reaches the page. `distIndex` is an assembly fact of the composing application: [`dsh-web-app`](../../bundle/web-app/README.md) resolves it through the frontend package's exports and mounts this plugin; a deployment never hardcodes it. +SPA dist server for the Web shell: a function plugin (config `{distIndex}`) that claims the [webserver](../webserver/README.md)'s single fallback seat and serves the built frontend directory with explicit index entry points. While `distIndex` is readable, the dist root and configured index path render `index.html` with HTTP 200; other existing files are served directly. An absent or non-file target inside the dist root, including a missing configured index, returns an empty 404; traversal outside the dist root returns 403, unknown extensions ship as `application/octet-stream`, and non-GET/HEAD without a matching named route returns 405. Every successful index response is rendered through the webserver's `renderIndex` — structured injection rows first, then the raw index taps — which is how the boot manifest reaches the page. `distIndex` is an assembly fact of the composing application: [`dsh-web-app`](../../bundle/web-app/README.md) resolves it through the frontend package's exports and mounts this plugin; a deployment never hardcodes it. The fallback seat is single-owner (a second claim throws) and effect-scoped: disposing the plugin's fiber releases the seat, after which the unclaimed webserver answers 404. diff --git a/packages/host/frontend-static/README.zh.md b/packages/host/frontend-static/README.zh.md index a1fe98be24..7672478480 100644 --- a/packages/host/frontend-static/README.zh.md +++ b/packages/host/frontend-static/README.zh.md @@ -2,7 +2,7 @@ [English](README.md) | 中文 -Web 壳的 SPA dist 服务器:一个函数插件(配置为 `{distIndex}`),占据 [webserver](../webserver/README.zh.md) 的唯一回退席位,并通过显式 index 入口服务已构建的前端目录。dist 根目录和配置的 index 路径以 HTTP 200 渲染 `index.html`;缺失文件或其他未声明的 pathname 返回空的 404,越出 dist 根目录的遍历返回 403,未知扩展名按 `application/octet-stream` 提供,GET/HEAD 之外的方法在没有匹配的具名路由时返回 405。每个 index 响应都经 webserver 的 `renderIndex` 渲染——先结构化注入行、后原始 index 转换器——启动 manifest(元数据清单)就是经这条路径送达页面的。`distIndex` 是组合应用的组装事实:[`dsh-web-app`](../../bundle/web-app/README.zh.md) 通过前端包的 exports 解析它并挂载本插件;部署绝不硬编码它。 +Web 壳的 SPA dist 服务器:一个函数插件(配置为 `{distIndex}`),占据 [webserver](../webserver/README.zh.md) 的唯一回退席位,并通过显式 index 入口服务已构建的前端目录。`distIndex` 可读时,dist 根目录和配置的 index 路径以 HTTP 200 渲染 `index.html`;其他现有文件直接提供。dist 根目录内缺失或不是文件的目标——包括缺失的配置 index——返回空的 404;越出 dist 根目录的遍历返回 403,未知扩展名按 `application/octet-stream` 提供,GET/HEAD 之外的方法在没有匹配的具名路由时返回 405。每个成功的 index 响应都经 webserver 的 `renderIndex` 渲染——先结构化注入行、后原始 index 转换器——启动 manifest(元数据清单)就是经这条路径送达页面的。`distIndex` 是组合应用的组装事实:[`dsh-web-app`](../../bundle/web-app/README.zh.md) 通过前端包的 exports 解析它并挂载本插件;部署绝不硬编码它。 回退席位只有单一所有者(第二次占据会抛错),并受 effect 作用域约束:dispose(资源释放)插件的 fiber 会释放席位,此后无人占据的 webserver 回答 404。 diff --git a/packages/host/frontend-static/src/index.ts b/packages/host/frontend-static/src/index.ts index 935a9dfebc..1afd319906 100644 --- a/packages/host/frontend-static/src/index.ts +++ b/packages/host/frontend-static/src/index.ts @@ -1,13 +1,13 @@ /** * @deepseek-ai/dsh-host-frontend-static — SPA dist server over the webserver * fallback seat: serves the built frontend directory with explicit index - * entry points. The dist root and configured index path render index.html; - * missing paths return 404, traversal outside the dist root is 403, unknown - * extensions ship as octet-stream, and non-GET/HEAD is 405. Every index - * response runs through the webserver's index render (structured injection - * rows, then raw taps). The dist location is workspace knowledge of the composing - * application, so `distIndex` is typically supplied through a `!!js` - * expression, never hardcoded by a deployment. + * entry points. A readable index renders at the dist root and configured index + * path; missing paths return 404, traversal outside the dist root is 403, + * unknown extensions ship as octet-stream, and non-GET/HEAD is 405. Every + * index response runs through the webserver's index render (structured + * injection rows, then raw taps). The dist location is workspace knowledge of + * the composing application, so `distIndex` is typically supplied through a + * `!!js` expression, never hardcoded by a deployment. * @module @deepseek-ai/dsh-host-frontend-static */ @@ -34,8 +34,10 @@ export const Config: z = z.object({ distIndex: z.string().required(), }) +const HTML_MIME = 'text/html; charset=utf-8' + const MIME: Record = { - '.html': 'text/html; charset=utf-8', + '.html': HTML_MIME, '.js': 'text/javascript; charset=utf-8', '.css': 'text/css; charset=utf-8', '.svg': 'image/svg+xml', @@ -56,8 +58,8 @@ const STATIC_MISS_CODES: ReadonlySet = new Set([ * @param res - the node:http response to write. * @param distRoot - absolute dist root directory (resolved by the caller). * @param distIndex - absolute path of index.html inside distRoot. - * @param renderIndex - produces the index.html body (structured injection rendering) for - * the dist root and configured index path. + * @param renderIndex - produces the index.html body (structured injection + * rendering) for the dist root and configured index path. */ export async function serveStatic( pathname: string, res: ServerResponse, distRoot: string, distIndex: string, @@ -72,26 +74,26 @@ export async function serveStatic( res.end() return } - const serveIndex = async (): Promise => { - const body = await renderIndex() - res.writeHead(200, { 'content-type': MIME['.html'] }) - res.end(body) - } - if (target === distRoot || target === distIndex) { - await serveIndex() - return - } + let body: string | Buffer + let type: string try { - const body = await readFile(target) - res.writeHead(200, { 'content-type': MIME[extname(target)] ?? 'application/octet-stream' }) - res.end(body) + if (target === distRoot || target === distIndex) { + body = await renderIndex() + type = HTML_MIME + } else { + body = await readFile(target) + type = MIME[extname(target)] ?? 'application/octet-stream' + } } catch (error) { // Only absent or non-file targets are 404; other filesystem failures reach // the webserver's request-failure handling. if (!STATIC_MISS_CODES.has((error as NodeJS.ErrnoException).code)) throw error res.writeHead(404) res.end() + return } + res.writeHead(200, { 'content-type': type }) + res.end(body) } /** diff --git a/packages/host/frontend-static/tests/frontend-static.spec.ts b/packages/host/frontend-static/tests/frontend-static.spec.ts index 627a800d64..fda9dcbc3e 100644 --- a/packages/host/frontend-static/tests/frontend-static.spec.ts +++ b/packages/host/frontend-static/tests/frontend-static.spec.ts @@ -129,6 +129,16 @@ describe('real Loader composition', () => { untap() expect((await request(port, '/')).body).not.toContain('__T__') + // A missing configured index follows the same empty-404 contract for both + // of its public entry paths and for both supported methods. + await rm(join(root!, 'dist', 'index.html')) + for (const path of ['/', '/index.html']) { + const get = await request(port, path) + const head = await request(port, path, { method: 'HEAD' }) + expect(get).toEqual({ status: 404, type: null, body: '' }) + expect(head).toEqual(get) + } + // Ordinary unknown paths and static-resource misses are empty 404s for // both GET and HEAD; neither class can be mistaken for the HTML shell. const ordinaryMisses = ['/no/such/route', '/api/no/such/route', '/empty', '/app.js/child'] From de572dd9102a938b7f0f82de935118a604bafa0b Mon Sep 17 00:00:00 2001 From: "yx.zhang" Date: Thu, 20 Aug 2026 16:01:57 +0800 Subject: [PATCH 4/5] feat(web): refine subagent header switcher --- ...07-27-web-subagent-conversations.i18n.yaml | 4 +- .../2026-07-27-web-subagent-conversations.md | 10 +- ...026-07-27-web-subagent-conversations.zh.md | 10 +- apps/web/tests/agent-preset-selection.e2e.ts | 4 +- .../agent-preset-selection/header.expected.md | 7 +- .../subagent-conversation/nested.expected.md | 4 +- .../subagent-conversation/ui.expected.md | 8 +- .../offline-composer.expected.md | 2 +- apps/web/tests/subagent-conversation.e2e.ts | 33 +- .../client/ui-conversation/README.i18n.yaml | 4 +- packages/client/ui-conversation/README.md | 4 +- packages/client/ui-conversation/README.zh.md | 4 +- .../ui-conversation/src/client/apply.ts | 1 + .../src/client/contract/slots.ts | 28 +- .../ui-conversation/src/client/index.ts | 3 +- .../skeleton/ConversationRoot.module.css | 5 + .../client/skeleton/ConversationSession.tsx | 38 ++- .../tests/chat-apply.client.spec.tsx | 2 + .../tests/skeleton.client.spec.tsx | 50 ++- packages/client/ui-subagent/README.i18n.yaml | 4 +- packages/client/ui-subagent/README.md | 4 +- packages/client/ui-subagent/README.zh.md | 4 +- packages/client/ui-subagent/package.json | 4 +- ...e.css => SubagentHeaderLineage.module.css} | 73 +++- ...ogAction.tsx => SubagentHeaderLineage.tsx} | 316 +++++++++++++++--- .../client/ui-subagent/src/client/index.ts | 14 +- .../client/ui-subagent/src/client/locales.ts | 2 + .../tests/browser-plugin.client.spec.ts | 10 +- .../tests/conversation-ui.client.spec.tsx | 304 ++++++++++++++--- .../src/client/slot-catalog.ts | 76 +++-- pnpm-lock.yaml | 6 + 31 files changed, 837 insertions(+), 201 deletions(-) rename packages/client/ui-subagent/src/client/{SubagentCatalogAction.module.css => SubagentHeaderLineage.module.css} (81%) rename packages/client/ui-subagent/src/client/{SubagentCatalogAction.tsx => SubagentHeaderLineage.tsx} (67%) diff --git a/.agents/notes/implemented/feature/2026-07-27-web-subagent-conversations.i18n.yaml b/.agents/notes/implemented/feature/2026-07-27-web-subagent-conversations.i18n.yaml index b9e7f4546a..b4b4b68309 100644 --- a/.agents/notes/implemented/feature/2026-07-27-web-subagent-conversations.i18n.yaml +++ b/.agents/notes/implemented/feature/2026-07-27-web-subagent-conversations.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write .agents/notes/implemented/feature/2026-07-27-web-subagent-conversations.md -2026-07-27-web-subagent-conversations.md: d20e55429d04d4308ae26d001575e664058c7dea -2026-07-27-web-subagent-conversations.zh.md: 057dccb2543b47c5347ee3c5cc71a9be36b4ea7e +2026-07-27-web-subagent-conversations.md: 592a0ef2bbf050cf86617facfd56adcd6377b63e +2026-07-27-web-subagent-conversations.zh.md: 07c852a9492e10bf454916462bdb474d7c66a1ec diff --git a/.agents/notes/implemented/feature/2026-07-27-web-subagent-conversations.md b/.agents/notes/implemented/feature/2026-07-27-web-subagent-conversations.md index d20e55429d..592a0ef2bb 100644 --- a/.agents/notes/implemented/feature/2026-07-27-web-subagent-conversations.md +++ b/.agents/notes/implemented/feature/2026-07-27-web-subagent-conversations.md @@ -14,7 +14,7 @@ The UI must also preserve the membership, modes, and diagnostics of the [durable ## Decision -The Web product exposes the selected session's direct session-backed subagents from a header action. Users can lazily expand descendant catalogs and open either mode in the existing conversation region. A one-shot child is permanently read-only. A continuable child accepts human follow-ups only while its exact direct-parent Agent is live; otherwise its persisted transcript remains readable with a recovery explanation. +The Web product exposes the selected session's direct session-backed subagents from the current-title lineage region in the header. Users can lazily expand descendant catalogs and open either mode in the existing conversation region. A one-shot child is permanently read-only. A continuable child accepts human follow-ups only while its exact direct-parent Agent is live; otherwise its persisted transcript remains readable with a recovery explanation. Every opened child carries a catalog-derived address `{ parentSessionId, childSessionId, mode }`. The mode-bearing address, not lineage or the coarse origin marker, selects dedicated history and prompt transports. History reads the persisted session without activation. A continuable prompt calls `ctx.subagents.followup()` and succeeds at inbox acceptance with `{ messageId }`; it does not steer an open turn, expose an Activation, wait for completion, or return an outcome. @@ -37,13 +37,13 @@ The Figma [subagent list](https://www.figma.com/design/jRBBK7zBgcszdVWQ0Fh5J8/Ha ## Product contract -The header action is absent only when a complete empty direct-catalog response agrees with the session-summary projection that no subagent descendants are known. Its trigger counts every known session-summary descendant reached through an uninterrupted `origin: 'subagent'` lineage, stops at ordinary forks, and shows ongoing activity when any counted descendant is running. Because ordinary sidebar rows hide subagent-origin sessions, the Workspace browser indexes the same uninterrupted lineage onto each visible ordinary row: any running descendant supplies its blue activity indicator and exact count in hover and assistive text without describing an idle parent as running. An ordinary fork starts a separate aggregation subtree. Pending interaction outranks parent running; either remains primary while descendant activity becomes a second hover and assistive status. With neither present, descendant activity outranks an unviewed completion reminder, which returns after the last running descendant stops. Every healthy direct-catalog row carries a read-time `hasChildren` hint derived only from direct lineage headers with durable `origin: 'subagent'`; normal healthy and diagnostic subagent candidates carry that marker, while ordinary forks do not. This lookahead reads no descendant event log, and the descriptor-backed catalog loaded after disclosure remains authoritative. When summaries establish descendants before that catalog exists or after a stale empty response, the action stays visible and exposes only disabled loading rows until opening it refreshes the catalog; summary-only rows never grant navigation. The UI omits disclosure for a known leaf before interaction; the hint does not promise that the child will remain a leaf. While an expanded direct catalog is loading, known lineage reserves one disabled loading row per direct descendant without recursively fetching descendant catalogs. The tree then presents continuable and one-shot rows, falling back to the session id when an optional one-shot label is absent. Corrupt, unsupported, and unavailable candidates remain visible as disabled diagnostic rows. +The descendant-count control is absent only when a complete empty direct-catalog response agrees with the session-summary projection that no subagent descendants are known. On an ordinary session, a slash separates the current title from that count control. Every subagent breadcrumb combines its compact 12px title with a fixed double chevron: the current breadcrumb uses primary color and weight 500, while ancestors use tertiary color and weight 400. Hovering a combined control for 150ms opens its direct-parent catalog, with a short crossing grace for the portaled menu; ArrowDown remains the keyboard entry path. Clicking an ancestor cancels pending hover, closes an open catalog, and only navigates upward. Each direct-parent catalog enables sibling switching and bolds its selected row; its label overrides the session-summary title, and a missing ancestor catalog refreshes automatically. Only the current subagent appends its own descendant-count control. Long titles truncate before the fixed chevron. The count trigger counts every known session-summary descendant reached through an uninterrupted `origin: 'subagent'` lineage, stops at ordinary forks, and shows ongoing activity when any counted descendant is running. Because ordinary sidebar rows hide subagent-origin sessions, the Workspace browser indexes the same uninterrupted lineage onto each visible ordinary row: any running descendant supplies its blue activity indicator and exact count in hover and assistive text without describing an idle parent as running. An ordinary fork starts a separate aggregation subtree. Pending interaction outranks parent running; either remains primary while descendant activity becomes a second hover and assistive status. With neither present, descendant activity outranks an unviewed completion reminder, which returns after the last running descendant stops. Every healthy direct-catalog row carries a read-time `hasChildren` hint derived only from direct lineage headers with durable `origin: 'subagent'`; normal healthy and diagnostic subagent candidates carry that marker, while ordinary forks do not. This lookahead reads no descendant event log, and the descriptor-backed catalog loaded after disclosure remains authoritative. When summaries establish descendants before that catalog exists or after a stale empty response, the action stays visible and exposes only disabled loading rows until opening it refreshes the catalog; summary-only rows never grant navigation. The UI omits disclosure for a known leaf before interaction; the hint does not promise that the child will remain a leaf. While an expanded direct catalog is loading, known lineage reserves one disabled loading row per direct descendant without recursively fetching descendant catalogs. The tree then presents continuable and one-shot rows, falling back to the session id when an optional one-shot label is absent. Corrupt, unsupported, and unavailable candidates remain visible as disabled diagnostic rows. `running` means the exact child Agent driver is draining work at the Host sampling boundary; `inactive` means that driver is idle or absent. The UI does not translate either value into success, failure, cancellation, completeness, or resumability. `subagent.list` supplies the current driver-status baseline, `host/session-status` updates known activity in place, request-local replay prevents an older in-flight list response from overwriting a newer transition, and `host/session-removed` returns a known row to `inactive`; reconnect reads a fresh baseline. A `host/session-added` frame for a direct subagent immediately flips any loaded parent row to `hasChildren: true`, and that positive hint survives an older in-flight catalog response; membership, labels, mode, diagnostics, and the authoritative snapshot still require a debounced `subagent.list` refresh while the affected branch is open. A prompt response remains delivery-time authority. Healthy rows reuse the standard session projections retained in the list mirror. The token figure sums the four disjoint `tokenUsage` buckets across the durable log. `subagentTiming` resets at every descriptor so an inherited fork seed cannot enter the child's total, accumulates completed `turn/start` → `turn/end` spans, and carries same-cut `active.since` and `active.through` bounds for an open turn. Existing session events advance `active.through` while that turn remains open; the menu adds no separate timer or log read and advances its local clock only while a known descendant is running. Below one day it formats whole seconds; longer visual values retain at most two adjacent units, using approximate 30-day months and 365-day years, while hover and accessible naming preserve the exact day/hour/minute/second duration. An inactive row bounds an interrupted open turn with `active.through`, so a stale projection never borrows newer session metadata and reopening the menu never restarts completed work. Neither metric implies a durable outcome. -Selecting a row records its exact address before opening the resident client `Session`. History pagination, event folding, tool render intents, titles, and live mux reconciliation reuse the ordinary conversation machinery. Breadcrumbs use catalog labels, follow parent links only through `origin: 'subagent'` rows, include the first ordinary owner, and keep ordinary forks single-level. Forking an addressed subagent creates an ordinary fork with direct source lineage and attaches it to the nearest workspace-owning ancestor. The catalog is an ARIA tree with lazy ArrowRight/ArrowLeft disclosure, linear ArrowUp/ArrowDown navigation, Home/End, Escape, and focus restoration. +Selecting a row records its exact address before opening the resident client `Session`. History pagination, event folding, tool render intents, titles, and live mux reconciliation reuse the ordinary conversation machinery. Breadcrumbs follow parent links only through `origin: 'subagent'` rows, include the first ordinary owner, and keep ordinary forks single-level. Each subagent breadcrumb gets its direct-parent sibling catalog and uses that catalog's label when available. Forking an addressed subagent creates an ordinary fork with direct source lineage and attaches it to the nearest workspace-owning ancestor. The catalog is an ARIA tree with lazy ArrowRight/ArrowLeft disclosure, linear ArrowUp/ArrowDown navigation, Home/End, Escape, and focus restoration. A one-shot row always replaces the composer with copy explaining that the execution record is read-only. A continuable row does so only while `parentAvailable` is false and the child is not running; a running parent-offline child keeps the ordinary composer with its input and Send action disabled so independent Stop stays reachable, and the read-only takeover returns once it stops. With a live parent, Enter and Send admit another FIFO turn even while the child runs, while independent Stop routes through `subagent.interrupt` ([interrupt contract](2026-08-06-continuable-subagent-interrupt.md)). Prompt failures retain the draft through the ordinary error behavior. @@ -69,7 +69,7 @@ The adapter stays in `dsh-host-apiproxy`; `dsh-host-webserver` remains a carrier The React-free runtime owns catalogs, single-flight refreshes, retained addresses, availability hints, transport selection, and a reference-stable map of each list row's current projection values. Re-selecting a known child retains its address so navigation cannot silently switch to ordinary session APIs. A missing intermediate breadcrumb address can be recovered from an already-loaded ancestor catalog, but it is not retained for transport and creates no scope until the user selects that breadcrumb. Restored navigation persists the full mode-bearing address. -Catalogs ride the standard `useSessions` snapshot. Component-local state owns menu visibility, expanded branches, and focus. `ui-conversation` declares the generic header-action list slot and dispatches the current conversation snapshot through its composer chain; it contains no subagent-specific takeover flag. `@deepseek-ai/dsh-client-ui-subagent` registers the catalog action and elects a reason-specific read-only composer from ordinary owner props. Components receive derived props and callbacks, never `ctx`. +Catalogs ride the standard `useSessions` snapshot. Component-local state owns menu visibility, expanded branches, focus, and hover timers. `ui-conversation` declares a lineage slot for every subagent breadcrumb, passing its session id, ordinary title fallback, and an upward-navigation callback for ancestors; it contains no catalog-specific condition. `@deepseek-ai/dsh-client-ui-subagent` occupies each lineage slot with direct-parent catalog navigation and elects a reason-specific read-only composer from ordinary owner props. Components receive derived props and callbacks, never `ctx`. Every in-process subagent child stamps `SessionHeader.origin: 'subagent'` before publication. Session list summaries and incremental Host frames project it so grouped and flat sidebars omit duplicate child rows while preserving ordinary forks. The same existing `host/session-added` frame marks a loaded direct parent row expandable without introducing a catalog event stream. Descriptor mode and catalog verification remain the authority for navigation, continuation, and authorization. @@ -104,7 +104,7 @@ The shipped Web composition mounts SQLite session query beside JSONL persistence - Host protocol tests pin schemas including required boolean expandability, id echoing, mode verification, non-activating history, exact-parent enforcement, FIFO admission receipts, cancellation, and sanitized failure mapping. - Generic Host tests pin attached and cold history and forks without Agent publication, cold projection folding, descriptor/origin/runtime-owner denial, explicit-id adoption denial, and the direct queue-control fence. - Client object tests pin retained and restored addresses, one-shot read-only and cancel rejection, history routing, continuable prompt and interrupt routing, suppression of Agent-bound model controls, live activity flips including in-flight response replay and detach fallback, subagent-parent expandability flips, and membership refresh. -- jsdom tests pin the aggregate descendant count and activity, sidebar propagation across nested lineage and ordinary-fork boundaries, row-status precedence, token totals, second-precision running and frozen inactive durations, adaptive long-duration units with exact accessible text, the summary-backed root action across absent and stale-empty catalogs, known loading-row shape, mixed-mode rows, pre-click leaf disclosure, diagnostics, lazy descendant disclosure, direct-parent addresses, keyboard behavior, and both read-only reasons. +- jsdom tests pin the ordinary-title separator, per-level combined subagent-title switchers, 12px nested titles, current and ancestor styling, selected-row weight, catalog-label precedence, hover delay, upward-click suppression, truncation with a retained chevron, the aggregate descendant count and activity, sidebar propagation across nested lineage and ordinary-fork boundaries, row-status precedence, token totals, second-precision running and frozen inactive durations, adaptive long-duration units with exact accessible text, the summary-backed root action across absent and stale-empty catalogs, known loading-row shape, mixed-mode rows, pre-click leaf disclosure, diagnostics, lazy descendant disclosure, direct-parent addresses, keyboard behavior, and both read-only reasons. - The keyless assembled Web snapshot contains an inactive continuable child with durable usage, an inactive one-shot sibling with a deterministic long duration, and a persisted grandchild; it pins the three-descendant trigger across a stale empty catalog response, usage and timing rows, adaptive long-duration presentation, and the aggregate running transition, expands without activation, opens persisted history, admits a human FIFO follow-up, reconciles child mux events, and proves one-shot history remains read-only. A separate assembled scenario holds a real child Agent turn at the LLM seam while it pins the aggregate running state in both the header and visible idle owner row, then cancels the turn during teardown. - Navigation tests pin subagent-only breadcrumbs, workspace placement for forks created from subagents, and `origin: 'subagent'` sidebar filtering without hiding ordinary forks. diff --git a/.agents/notes/implemented/feature/2026-07-27-web-subagent-conversations.zh.md b/.agents/notes/implemented/feature/2026-07-27-web-subagent-conversations.zh.md index 057dccb254..07c852a949 100644 --- a/.agents/notes/implemented/feature/2026-07-27-web-subagent-conversations.zh.md +++ b/.agents/notes/implemented/feature/2026-07-27-web-subagent-conversations.zh.md @@ -14,7 +14,7 @@ UI 还必须保留[持久化目录](../../implemented/feature/2026-07-22-durable ## 决策 -Web 产品通过页头操作公开选中会话中由会话支撑的直接 subagent。用户可以懒加载展开后代目录,并在现有对话区域中打开任一 mode。one-shot child 永久只读。可继续 child 只有在其确切直接 parent agent 存活时才接受用户后续消息;否则,其持久化 transcript 仍然可读,并附带恢复说明。 +Web 产品通过页头的当前 title 谱系区域公开选中会话中由会话支撑的直接 subagent。用户可以懒加载展开后代目录,并在现有对话区域中打开任一 mode。one-shot child 永久只读。可继续 child 只有在其确切直接 parent agent 存活时才接受用户后续消息;否则,其持久化 transcript 仍然可读,并附带恢复说明。 每个打开的 child 都携带目录派生地址 `{ parentSessionId, childSessionId, mode }`。选择专用历史与提示词传输的是包含 mode 的地址,而不是谱系或粗粒度 origin 标记。历史操作会从持久化存储读取会话,而不触发激活。可继续提示词操作会调用 `ctx.subagents.followup()`,并在 inbox 接受消息时以 `{ messageId }` 成功返回;它不会对进行中的轮次执行 steering(中途引导)、公开 Activation、等待完成或返回结果。 @@ -37,13 +37,13 @@ Figma 中的 [subagent 列表](https://www.figma.com/design/jRBBK7zBgcszdVWQ0Fh5 ## 产品约定 -只有当完整的直接目录空响应与会话摘要投影相符,二者均表明没有已知的 subagent 后代时,才不显示页头操作。其触发器会统计经不间断的 `origin: 'subagent'` 谱系可达的每个已知会话摘要后代,在普通 fork 处停止,并在任一计入统计的后代处于 `running` 时显示活动仍在进行。由于普通侧边栏行会隐藏 origin 为 subagent 的会话,Workspace 浏览器会在每个可见的普通行上索引同一条不间断谱系:任何运行中的后代都会让该行显示蓝色活动指示器,并在悬停与无障碍文本中给出确切数量,同时不会把空闲 parent 描述为正在运行。普通 fork 会开启单独的聚合子树。待处理交互优先于 parent 的运行中状态;二者无论哪一项存在都会保持为主要状态,而后代活动则成为悬停与无障碍状态中的第二项。两者均不存在时,后代活动优先于未查看的完成提醒;最后一个运行中的后代停止后,该提醒会恢复。每个健康的直接目录行都携带读取时的 `hasChildren` 提示,该值只根据持久化 `origin: 'subagent'` 的直接谱系 header 派生;正常的健康与 diagnostic subagent 候选都会携带该标记,而普通 fork 不会。该预查不读取任何后代事件日志,展开后仍以描述符支撑的目录为权威依据。当摘要在该目录尚不存在时或在一次陈旧的空响应后确认已有后代时,该操作会保持可见,并且在打开它以刷新目录之前仅显示禁用的加载行;仅由摘要支撑的行绝不会提供导航能力。UI 会在交互前就省略已知叶子节点的展开控件;该提示不承诺 child 会一直是叶子。已展开的直接目录加载期间,已知谱系会为每个直接后代预留一行禁用的加载行,而不会递归获取后代目录。随后树会呈现可继续与 one-shot 行;one-shot 的可选 label 缺失时,回退到其会话 id。损坏、不受支持或不可用的候选仍以禁用的 diagnostic 行显示。 +只有当完整的直接目录空响应与会话摘要投影相符,二者均表明没有已知的 subagent 后代时,才不显示后代数量控件。普通会话会用斜杠分隔当前 title 和该数量控件。每一级 subagent 面包屑都将紧凑的 12px title 与固定显示的双向箭头组合成一个控件:当前面包屑使用主标签颜色和 500 字重,祖先则使用三级标签颜色和 400 字重。悬停组合控件 150ms 后会打开其直接 parent 目录;浮层菜单具有短暂的跨越宽限时间,ArrowDown 保留为键盘入口。点击祖先会取消待触发的悬停、关闭已打开的目录,并且只向上导航。每个直接 parent 目录都可切换 sibling,并会加粗其选中行;目录 label 优先于会话摘要 title,缺失的祖先目录会自动刷新。只有当前 subagent 会追加自己的后代数量控件。过长的 title 会在固定箭头之前截断。数量触发器会统计经不间断的 `origin: 'subagent'` 谱系可达的每个已知会话摘要后代,在普通 fork 处停止,并在任一计入统计的后代处于 `running` 时显示活动仍在进行。由于普通侧边栏行会隐藏 origin 为 subagent 的会话,Workspace 浏览器会在每个可见的普通行上索引同一条不间断谱系:任何运行中的后代都会让该行显示蓝色活动指示器,并在悬停与无障碍文本中给出确切数量,同时不会把空闲 parent 描述为正在运行。普通 fork 会开启单独的聚合子树。待处理交互优先于 parent 的运行中状态;二者无论哪一项存在都会保持为主要状态,而后代活动则成为悬停与无障碍状态中的第二项。两者均不存在时,后代活动优先于未查看的完成提醒;最后一个运行中的后代停止后,该提醒会恢复。每个健康的直接目录行都携带读取时的 `hasChildren` 提示,该值只根据持久化 `origin: 'subagent'` 的直接谱系 header 派生;正常的健康与 diagnostic subagent 候选都会携带该标记,而普通 fork 不会。该预查不读取任何后代事件日志,展开后仍以描述符支撑的目录为权威依据。当摘要在该目录尚不存在时或在一次陈旧的空响应后确认已有后代时,该操作会保持可见,并且在打开它以刷新目录之前仅显示禁用的加载行;仅由摘要支撑的行绝不会提供导航能力。UI 会在交互前就省略已知叶子节点的展开控件;该提示不承诺 child 会一直是叶子。已展开的直接目录加载期间,已知谱系会为每个直接后代预留一行禁用的加载行,而不会递归获取后代目录。随后树会呈现可继续与 one-shot 行;one-shot 的可选 label 缺失时,回退到其会话 id。损坏、不受支持或不可用的候选仍以禁用的 diagnostic 行显示。 `running` 表示在 Host 采样边界,确切 child Agent driver 正在处理工作;`inactive` 表示该 driver 空闲或不存在。UI 不会把任一值解释为成功、失败、取消、完成状态或可恢复性。`subagent.list` 提供当前 driver 状态基线,`host/session-status` 会就地更新已知活动状态,请求内回放会阻止更早发起但尚未完成的列表响应覆盖较新的状态转换,`host/session-removed` 则会使已知行恢复为 `inactive`;重连时会读取新的基线。直接 subagent 的 `host/session-added` 帧会立即把任何已加载的 parent 行翻转为 `hasChildren: true`,并使这项正向提示不被更早发起但尚未完成的目录响应覆盖;受影响分支打开期间,成员、label、mode、diagnostic 与权威快照仍需要通过去抖动的 `subagent.list` 刷新来更新。消息投递时仍以提示词响应为权威依据。 健康行会复用列表镜像中保留的标准会话投影。token 用量数值会汇总持久化日志中四个互不重叠的 `tokenUsage` 桶。`subagentTiming` 会在每个描述符处重置,使继承的 fork 种子不会计入 child 总量;它会累加已完成的 `turn/start` → `turn/end` 时段,并携带未结束轮次同一切面的 `active.since` 和 `active.through` 边界。该轮次保持未结束期间,现有会话事件会推进 `active.through`;菜单不会增加单独的计时器或日志读取,且仅在有已知后代处于运行状态时才推进其本地时钟。不足一天时,菜单会以整秒格式化时间;达到一天后的视觉值最多保留两个相邻单位,其中月份按近似 30 天计算,年份按近似 365 天计算,而悬停信息与无障碍名称会保留精确的天/小时/分钟/秒耗时。对 inactive 行,菜单以 `active.through` 为被中断未结束轮次的上界,因此陈旧投影绝不会借用更新的会话元数据,且重新打开菜单绝不会让已完成工作重新计时。这两项指标都不蕴含持久化结果语义。 -选择一行后,系统会先记录其确切地址,再打开常驻客户端 `Session`。历史分页、事件 fold、工具渲染意图、title 与实时 mux 归并都会复用普通对话机制。面包屑导航使用目录 label,只会沿 `origin: 'subagent'` 行的父链接逐级回溯,包含第一个普通 owner,并让普通 fork 保持单层。从已寻址 subagent 创建 fork 时,会生成具有直接源谱系的普通 fork,并将其附加到最近拥有 Workspace 的祖先。目录是一棵 ARIA 树,支持懒加载式 ArrowRight/ArrowLeft 展开与折叠、线性 ArrowUp/ArrowDown 导航、Home/End、Escape 以及焦点恢复。 +选择一行后,系统会先记录其确切地址,再打开常驻客户端 `Session`。历史分页、事件 fold、工具渲染意图、title 与实时 mux 归并都会复用普通对话机制。面包屑导航只会沿 `origin: 'subagent'` 行的父链接逐级回溯,包含第一个普通 owner,并让普通 fork 保持单层。每一级 subagent 面包屑都会获得其直接 parent 的 sibling 目录,并在目录可用时采用其中的 label。从已寻址 subagent 创建 fork 时,会生成具有直接源谱系的普通 fork,并将其附加到最近拥有 Workspace 的祖先。目录是一棵 ARIA 树,支持懒加载式 ArrowRight/ArrowLeft 展开与折叠、线性 ArrowUp/ArrowDown 导航、Home/End、Escape 以及焦点恢复。 one-shot 行始终会用文案替代输入框,说明执行记录为只读。可继续行仅在 `parentAvailable` 为 false 且 child 未在运行时如此;parent 离线但仍在运行的 child 保留普通输入框,并禁用其输入区和 Send 操作,让独立的 Stop 保持可达,停止后只读替代恢复。parent 在线时,即使 child 正在运行,Enter 和 Send 也会准入另一个 FIFO 轮次,而独立的 Stop 经由 `subagent.interrupt` 路由([中断约定](2026-08-06-continuable-subagent-interrupt.zh.md))。提示词失败会通过普通错误行为保留草稿。 @@ -69,7 +69,7 @@ one-shot 行始终会用文案替代输入框,说明执行记录为只读。 不依赖 React 的运行时负责目录、单次并发刷新、保留的地址、可用性提示、传输选择,以及每个列表行当前投影值的引用稳定映射。再次选择已知 child 时会保留其地址,避免导航静默切换到普通会话 API。缺失的中间面包屑地址可以从已加载的祖先目录恢复,但在用户选择该面包屑之前不会保留为传输地址,也不会创建 scope。恢复的导航会持久化包含 mode 的完整地址。 -目录通过标准 `useSessions` 快照传递。组件局部状态负责菜单可见性、已展开分支与焦点。`ui-conversation` 声明通用页头操作列表 slot,并通过其 composer 链分发当前对话快照;其中没有 subagent 专用的接管标记。`@deepseek-ai/dsh-client-ui-subagent` 注册目录操作,并根据普通 owner props 选择按原因区分的只读编辑器。组件只接收派生 props 与回调,绝不接收 `ctx`。 +目录通过标准 `useSessions` 快照传递。组件局部状态负责菜单可见性、已展开分支、焦点与悬停计时器。`ui-conversation` 为每一级 subagent 面包屑声明谱系 slot,传入该级会话 id、普通 title 回退,并为祖先传入向上导航回调;其中没有目录专用条件。`@deepseek-ai/dsh-client-ui-subagent` 以直接 parent 目录导航占用每个谱系 slot,并根据普通 owner props 选择按原因区分的只读编辑器。组件只接收派生 props 与回调,绝不接收 `ctx`。 每个进程内 subagent child 都会在发布前写入 `SessionHeader.origin: 'subagent'`。会话列表摘要与增量 Host 帧会投影该字段,使分组和扁平侧边栏省略重复的 child 行,同时保留普通 fork。同一条现有的 `host/session-added` 帧还会把已加载的直接 parent 行标记为可展开,而无需引入目录事件流。描述符 mode 与目录校验仍然是导航、继续执行和授权的权威依据。 @@ -104,7 +104,7 @@ one-shot 行始终会用文案替代输入框,说明执行记录为只读。 - 宿主协议测试固定 schema(包括必需的布尔可展开性)、id 回显、mode 校验、非激活式历史、确切 parent 强制要求、FIFO 准入回执、取消与脱敏后的失败映射。 - 通用 Host 测试固定在不发布 Agent 的情况下读取已附加与冷态历史及执行 fork、冷态投影归并、按描述符/origin/运行时 owner 拒绝、拒绝显式 id 接纳,以及直接队列控制栅栏。 - 客户端对象测试固定已保留与已恢复的地址、one-shot 只读与取消拒绝、历史路由、可继续提示词与中断路由、屏蔽绑定到 agent 的模型控件、实时活动状态翻转(包括在途响应回放与 detach 回退)、subagent parent 可展开性翻转与成员刷新。 -- jsdom 测试固定后代聚合计数与活动状态、侧边栏活动在嵌套谱系中的传播与普通 fork 边界、行状态优先级、token 用量总计、精确到秒的运行中耗时与冻结后 inactive 耗时、采用自适应单位的长耗时及其精确无障碍文本、目录缺失或为陈旧空目录时由摘要支撑的根操作、已知加载行的形态、混合 mode 行、点击前的叶子展开控件、diagnostic、后代懒加载展开、直接 parent 地址、键盘行为与两种只读原因。 +- jsdom 测试固定普通 title 分隔符、逐级合并的 subagent title 切换热区、嵌套 title 的 12px 字号、当前与祖先样式、选中行字重、目录 label 优先级、悬停延迟、向上点击抑制、保留箭头的截断、后代聚合计数与活动状态、侧边栏活动在嵌套谱系中的传播与普通 fork 边界、行状态优先级、token 用量总计、精确到秒的运行中耗时与冻结后 inactive 耗时、采用自适应单位的长耗时及其精确无障碍文本、目录缺失或为陈旧空目录时由摘要支撑的根操作、已知加载行的形态、混合 mode 行、点击前的叶子展开控件、diagnostic、后代懒加载展开、直接 parent 地址、键盘行为与两种只读原因。 - 无密钥的组装 Web 快照包含一个具有持久化 token 用量的 inactive 可继续 child、一个具有确定性长耗时的 inactive one-shot sibling 和一个持久化 grandchild;它会固定触发器在一次陈旧的空目录响应后仍显示三个后代,并固定 token 用量与计时行、自适应长耗时呈现及聚合 `running` 状态转换,在不激活的情况下展开、打开持久化历史、准入一条用户 FIFO 后续消息、归并 child mux 事件,并证明 one-shot 历史仍然只读。另一个独立的组装场景会在 LLM seam 处保持一个真实的 child Agent 轮次进行中,同时固定页头和可见空闲 owner 行中的聚合运行状态,随后在 teardown 期间取消该轮次。 - 导航测试固定仅含 subagent 的面包屑导航、从 subagent 创建 fork 时的 Workspace 归属,以及 `origin: 'subagent'` 侧边栏过滤,同时不隐藏普通 fork。 diff --git a/apps/web/tests/agent-preset-selection.e2e.ts b/apps/web/tests/agent-preset-selection.e2e.ts index 7a512c9b90..3d7c10abbc 100644 --- a/apps/web/tests/agent-preset-selection.e2e.ts +++ b/apps/web/tests/agent-preset-selection.e2e.ts @@ -282,8 +282,8 @@ describe('web e2e: agent-preset selection', () => { await compareOrRefreshGolden(HEADER_EXPECTED, snapshot, MODE) expect(snapshot).toContain('Minimal mode') expect(snapshot).toContain('button "1 subagent"') - expect(snapshot.indexOf('Minimal mode')).toBeLessThan(snapshot.indexOf('button "1 subagent"')) - expect(snapshot.indexOf('button "1 subagent"')).toBeLessThan(snapshot.indexOf('button "Session log"')) + expect(snapshot.indexOf('button "1 subagent"')).toBeLessThan(snapshot.indexOf('Minimal mode')) + expect(snapshot.indexOf('Minimal mode')).toBeLessThan(snapshot.indexOf('button "Session log"')) // Static chrome, not a control: the header can only report a composition // the host would refuse to change. expect(snapshot).not.toContain('button "Minimal mode"') diff --git a/apps/web/tests/snapshots/agent-preset-selection/header.expected.md b/apps/web/tests/snapshots/agent-preset-selection/header.expected.md index 612edbc213..9a9f380833 100644 --- a/apps/web/tests/snapshots/agent-preset-selection/header.expected.md +++ b/apps/web/tests/snapshots/agent-preset-selection/header.expected.md @@ -1,10 +1,11 @@ - navigation "Session hierarchy": - button "Seeded turn" [disabled] + - text: / + - button "1 subagent": + - text: 1 subagent + - img - img - text: Minimal mode -- button "1 subagent": - - text: 1 subagent - - img - button "Session log": - text: Session log - img diff --git a/apps/web/tests/snapshots/subagent-conversation/nested.expected.md b/apps/web/tests/snapshots/subagent-conversation/nested.expected.md index 0b0c96e887..e5d8498557 100644 --- a/apps/web/tests/snapshots/subagent-conversation/nested.expected.md +++ b/apps/web/tests/snapshots/subagent-conversation/nested.expected.md @@ -2,9 +2,9 @@ - navigation "Session hierarchy": - button "Ask a research subagent to" - text: / - - button "event-sourcing researcher" + - 'button "Switch subagent: event-sourcing researcher"': event-sourcing researcher - text: / - - button "example editor" [disabled] + - 'button "Switch subagent: example editor"': example editor - button "Session log": - text: Session log - img diff --git a/apps/web/tests/snapshots/subagent-conversation/ui.expected.md b/apps/web/tests/snapshots/subagent-conversation/ui.expected.md index 55a424f2a7..dc26ca3e97 100644 --- a/apps/web/tests/snapshots/subagent-conversation/ui.expected.md +++ b/apps/web/tests/snapshots/subagent-conversation/ui.expected.md @@ -2,12 +2,12 @@ - navigation "Session hierarchy": - button "Ask a research subagent to" - text: / - - button "event-sourcing researcher" [disabled] + - 'button "Switch subagent: event-sourcing researcher"': event-sourcing researcher + - button "1 subagent": + - text: 1 subagent + - img - img - text: Standard mode - - button "1 subagent": - - text: 1 subagent - - img - button "Session log": - text: Session log - img diff --git a/apps/web/tests/snapshots/subagent-interrupt/offline-composer.expected.md b/apps/web/tests/snapshots/subagent-interrupt/offline-composer.expected.md index f4ca5e1b3d..378ebea7d0 100644 --- a/apps/web/tests/snapshots/subagent-interrupt/offline-composer.expected.md +++ b/apps/web/tests/snapshots/subagent-interrupt/offline-composer.expected.md @@ -2,7 +2,7 @@ - navigation "Session hierarchy": - button "Ask a research subagent to" - text: / - - button "event-sourcing researcher" [disabled] + - 'button "Switch subagent: event-sourcing researcher"': event-sourcing researcher - img - text: Standard mode - button "Session log": diff --git a/apps/web/tests/subagent-conversation.e2e.ts b/apps/web/tests/subagent-conversation.e2e.ts index 4b8ecb55e6..eb5b364628 100644 --- a/apps/web/tests/subagent-conversation.e2e.ts +++ b/apps/web/tests/subagent-conversation.e2e.ts @@ -226,7 +226,7 @@ describe('web e2e: persisted subagent conversation and human continuation', () = await page.waitForSelector('[class*="frame"]', { timeout: 30_000 }) const catalogButton = page.getByRole('button', { name: /subagents/ }) await catalogButton.waitFor({ timeout: 15_000 }) - await catalogButton.click() + await catalogButton.hover() const catalogTree = page.getByRole('tree', { name: 'Subagent sessions' }) await catalogTree.getByRole('treeitem').nth(1).waitFor({ timeout: 15_000 }) await catalogTree.press('Escape') @@ -280,7 +280,7 @@ describe('web e2e: persisted subagent conversation and human continuation', () = await page.getByRole('button', { name: '3 subagents' }).waitFor({ timeout: 15_000 }) acknowledgeReloadConnectionLoss(tripwire, warningStart) - await page.getByRole('button', { name: '3 subagents' }).click() + await page.getByRole('button', { name: '3 subagents' }).hover() await expect.poll(() => trailingRequested, { timeout: 15_000 }).toBe(true) const tree = page.getByRole('tree', { name: 'Subagent sessions' }) await tree.getByRole('treeitem', { name: 'Loading subagents' }).first().waitFor() @@ -301,7 +301,13 @@ describe('web e2e: persisted subagent conversation and human continuation', () = it('expands a persisted grandchild progressively without activating either level', async () => { onTestFailed(() => saveFailureShot(page, 'web-e2e-subagent-tree')) - await page.getByRole('button', { name: '3 subagents' }).click() + await page.getByRole('button', { name: '3 subagents' }).hover() + const catalogTree = page.getByRole('tree', { name: 'Subagent sessions' }) + expect(await catalogTree.evaluate((element) => { + const rect = element.getBoundingClientRect() + const hit = document.elementFromPoint(rect.left + 8, rect.top + 8) + return hit !== null && element.contains(hit) + })).toBe(true) expect(await page.getByRole('button', { name: `Expand ${ONE_SHOT_LABEL} descendants`, }).count()).toBe(0) @@ -327,7 +333,7 @@ describe('web e2e: persisted subagent conversation and human continuation', () = it('opens the completed child from persistence without activating it', async () => { onTestFailed(() => saveFailureShot(page, 'web-e2e-subagent-open')) - await page.getByRole('button', { name: '3 subagents' }).click() + await page.getByRole('button', { name: '3 subagents' }).hover() await page.getByRole('treeitem', { name: new RegExp(LABEL) }).click() await expect.poll( () => page.getByText(INITIAL_PROMPT, { exact: true }).count(), @@ -337,7 +343,7 @@ describe('web e2e: persisted subagent conversation and human continuation', () = throw new Error(`viewing the child activated it; API calls: ${apiCalls.join(', ')}`) } const hierarchy = page.getByRole('navigation', { name: 'Session hierarchy' }) - await hierarchy.getByRole('button', { name: LABEL, disabled: true }).waitFor() + await hierarchy.getByRole('button', { name: `Switch subagent: ${LABEL}` }).waitFor() const sidebar = await captureStableAria( page, '[role="tree"][aria-label="Sessions"]', @@ -383,11 +389,12 @@ describe('web e2e: persisted subagent conversation and human continuation', () = it('opens an unavailable persisted grandchild after recording the available child', async () => { onTestFailed(() => saveFailureShot(page, 'web-e2e-subagent-grandchild')) - await page.getByRole('button', { name: '1 subagent' }).click() + await page.getByRole('button', { name: '1 subagent' }).hover() const tree = page.getByRole('tree', { name: 'Subagent sessions' }) - const nestedRow = tree.getByRole('treeitem', { name: new RegExp(NESTED_LABEL) }) - expect(await nestedRow.locator(':scope > *').count()).toBe(1) - const clickArea = nestedRow.locator(':scope > *') + const nestedRow = tree.locator('[role="treeitem"]').filter({ hasText: NESTED_LABEL }) + await nestedRow.waitFor({ timeout: 15_000 }) + const clickArea = nestedRow.locator(':scope > div') + expect(await clickArea.count()).toBe(1) const [treeBox, clickAreaBox] = await Promise.all([ tree.boundingBox(), clickArea.boundingBox(), @@ -429,7 +436,7 @@ describe('web e2e: persisted subagent conversation and human continuation', () = .getByRole('treeitem') .last() await parentSession.click() - await page.getByRole('button', { name: '3 subagents' }).click() + await page.getByRole('button', { name: '3 subagents' }).hover() await page.getByRole('treeitem', { name: new RegExp(ONE_SHOT_LABEL) }).click() await page.getByText('One-shot tasks do not accept follow-ups; review the full execution record here.').waitFor() expect(scaffold.ctx.agents.get(oneShotId)).toBeUndefined() @@ -440,7 +447,7 @@ describe('web e2e: persisted subagent conversation and human continuation', () = await page.getByRole('tree', { name: 'Sessions' }) .getByRole('treeitem', { name: /Ask a research subagent to/ }) .click() - await page.getByRole('button', { name: '3 subagents' }).click() + await page.getByRole('button', { name: '3 subagents' }).hover() await page.getByRole('treeitem', { name: new RegExp(LABEL) }).click() await page.getByRole('textbox', { name: 'Message the agent' }).waitFor() const forkResponse = page.waitForResponse(response => @@ -466,7 +473,7 @@ describe('web e2e: persisted subagent conversation and human continuation', () = onTestFailed(() => saveFailureShot(page, 'web-e2e-subagent-post-fork-followup')) const sessions = page.getByRole('tree', { name: 'Sessions' }) await sessions.getByRole('treeitem', { name: /Ask a research subagent to/ }).click() - await page.getByRole('button', { name: '3 subagents' }).click() + await page.getByRole('button', { name: '3 subagents' }).hover() await page.getByRole('treeitem', { name: new RegExp(LABEL) }).click() await page.locator('textarea:enabled').first().waitFor() expect(scaffold.ctx.agents.get(childId)).toBeUndefined() @@ -483,7 +490,7 @@ describe('web e2e: persisted subagent conversation and human continuation', () = await expect.poll(() => scaffold.ctx.agents.get(forkId)).not.toBeUndefined() await sessions.getByRole('treeitem', { name: /Ask a research subagent to/ }).click() - await page.getByRole('button', { name: '3 subagents' }).click() + await page.getByRole('button', { name: '3 subagents' }).hover() await page.getByRole('treeitem', { name: new RegExp(LABEL) }).click() const input = page.locator('textarea:enabled').first() await input.waitFor() diff --git a/packages/client/ui-conversation/README.i18n.yaml b/packages/client/ui-conversation/README.i18n.yaml index b087acd7ce..60409a8da5 100644 --- a/packages/client/ui-conversation/README.i18n.yaml +++ b/packages/client/ui-conversation/README.i18n.yaml @@ -2,5 +2,5 @@ # side as of the last confirmed-consistent state. Both languages carry equal authority; # after editing either side, bring the other along and re-record with: # pnpm run verify-translation-pairing --write packages/client/ui-conversation/README.md -README.md: a90d1d9dd8156fc1063dc7358374f8b1715deb1a -README.zh.md: a2d514af398f8a023f21b3308477bb6236bf6786 +README.md: 2e295ddfdbfffc83b08af5cababda83d1672e6e2 +README.zh.md: 76395003e4858fa41c3329301039aed31633ecad diff --git a/packages/client/ui-conversation/README.md b/packages/client/ui-conversation/README.md index a90d1d9dd8..2e295ddfdb 100644 --- a/packages/client/ui-conversation/README.md +++ b/packages/client/ui-conversation/README.md @@ -6,7 +6,7 @@ Conversation domain: skeleton (header/tabs/composer/empty state), chat view (gro Compaction renders as one collapsed row at the checkpoint's flow position without replacing the transcript above it. Automatic compaction uses the context-compacted title. Every completed marker with a loaded `compaction/summary` event shows the replaced-item and estimated-token counts and discloses the summary on click. Manual `/compact` starts as a running `compact` row; on successful settlement its explicit summary-event reference folds that command into the checkpoint row under the same React key. A completed checkpoint keeps the context-compaction icon at rest and replaces it with the collapsed or expanded disclosure only on hover or keyboard focus. Input rejection, no compactable history, cancellation, and failure retain the generic command row and its handler-authored text. Pairing never depends on adjacency because durable context may be injected while compaction is running. The framed checkpoint payload is model-facing and never renders; when the cited `compaction/summary` event is outside the loaded window, the checkpoint remains visible but non-expandable. -The resident conversation shell survives no-session and session transitions. Without a current session it locks message actions and presents the whole dashed composer card as a trigger for the root-scoped `conversation.hero.workspace` Workspace picker; the textarea remains read-only and keyboard-accessible. The Hero's leading mark is the independent root-scoped `conversation.hero.brand.mark` slot, with the fish mark as its fallback. Selecting a Workspace connects or reuses its Host-owned blank session and opens that session without replacing the shell. The root always owns the same scrollport and Hero/composer subtree; separate strict-session header and body outlets fill their regions when the first Session arrives, so the Workspace picker, scroll body, composer seat, and textarea retain their React and DOM identity. Blank sessions render the same composer body as active sessions, while the InputHub carries drafts across Workspace switches and mirrors them into the session store. In the active phase the session header shows only the current session title and view tabs as ordinary column chrome; fork lineage remains session data and is not projected into the header. Beneath it the scrollport (`data-conversation-scroll`) holds the flowing views and the sticky composer stack (stats dock + input docks + bar). That scrollport reserves its scrollbar gutter unconditionally, and a view opting into a composer overlay leaves it a scroll container, so the input card keeps one horizontal position whether or not the transcript scrolls and whichever view tab is shown ([decision](../../../.agents/notes/implemented/bug-fix/2026-08-04-composer-tab-gutter-reservation.md)). Wheel over the textarea chains: the capped draft scrolls locally until its edge, then forwards to that host. Safari alone receives a pre-paint recovery when a native edit shortens the draft and leaves stale soft-wrap overflow; draft growth, programmatic updates, and other browsers never read layout for that recovery ([decision](../../../.agents/notes/implemented/bug-fix/2026-08-13-safari-textarea-soft-wrap-reflow.md)). +The resident conversation shell survives no-session and session transitions. Without a current session it locks message actions and presents the whole dashed composer card as a trigger for the root-scoped `conversation.hero.workspace` Workspace picker; the textarea remains read-only and keyboard-accessible. The Hero's leading mark is the independent root-scoped `conversation.hero.brand.mark` slot, with the fish mark as its fallback. Selecting a Workspace connects or reuses its Host-owned blank session and opens that session without replacing the shell. The root always owns the same scrollport and Hero/composer subtree; separate strict-session header and body outlets fill their regions when the first Session arrives, so the Workspace picker, scroll body, composer seat, and textarea retain their React and DOM identity. Blank sessions render the same composer body as active sessions, while the InputHub carries drafts across Workspace switches and mirrors them into the session store. In the active phase the session header shows the current session title, optional lineage controls, and view tabs as ordinary column chrome; ordinary fork lineage remains session data and is not projected into the header. Beneath it the scrollport (`data-conversation-scroll`) holds the flowing views and the sticky composer stack (stats dock + input docks + bar). That scrollport reserves its scrollbar gutter unconditionally, and a view opting into a composer overlay leaves it a scroll container, so the input card keeps one horizontal position whether or not the transcript scrolls and whichever view tab is shown ([decision](../../../.agents/notes/implemented/bug-fix/2026-08-04-composer-tab-gutter-reservation.md)). Wheel over the textarea chains: the capped draft scrolls locally until its edge, then forwards to that host. Safari alone receives a pre-paint recovery when a native edit shortens the draft and leaves stale soft-wrap overflow; draft growth, programmatic updates, and other browsers never read layout for that recovery ([decision](../../../.agents/notes/implemented/bug-fix/2026-08-13-safari-textarea-soft-wrap-reflow.md)). Another plugin can make one session's composer inert through `ctx.conversation.blocks`: it sets a block carrying its own localized reason, and the bar renders the same disabled textarea with that reason as the placeholder — the no-workspace posture, reused. The push direction is the constraint, not a preference: the plugins that know a session cannot send (ui-model-selection, when no adapter serves its route) already depend on this package, so this package cannot read them. The model seat is the one control a block leaves live — every block this contract has is cleared by choosing a model, so locking it too would leave the composer asking for the only thing it prevents. A block is an affordance only; the Host refuses a prompt it cannot route regardless of what any client disables. The no-workspace state wins when both hold, because picking a workspace is the earlier prerequisite. @@ -16,7 +16,7 @@ Chat business rows are independent registry contributions rather than a closed b Approvals take over the composer through the chain this package declares: `ApprovalPanel` registers as a selector-routed `'conversation.composer'` entry (the ui-user-questions pattern) and occupies the composer in place of the InputBar while an approval wait is pending (amber strip, justification headline, paired command line from the running call's args, one-shot refuse/allow). The `PendingApproval` domain face in `contract/slots.ts` owns the wire encoding — the `ApprovalResponsePayload` value with the audit correlation — over the runtime's `PendingWait` carrier; the broadcast `approval/resolved` frame settles the wait and restores the composer. The runtime manager projects every approval or question wait through `SessionSummary.pendingInteraction`, including sessions never instantiated; `ui-workspace` owns its sidebar presentation. Pending waits leave the message flow entirely: questions (ui-user-questions) and approvals (ApprovalPanel) both answer through the composer takeover, so no display-only placeholder card remains. The composer's bottom-row Access seat mounts `PermissionSelect`, fed by the host-computed `permissions` projection through the standard-kit `useProjection` (key absence hides the chip); the chip opens a Menu-primitive dropdown whose built-in preset ids render as localized product labels only when the host keeps their canonical names, while explicit host labels remain unchanged and unknown kebab-case names render in title case. Safe preset picks submit `/permission ` immediately through the bar's injected `command` callback, while `danger-full-access` first opens an in-page Modal risk confirmation. The enabling action stays disabled until the user checks the acknowledgement; cancel, Escape, close, and mask click submit nothing. -The session header renders the session-scoped `'conversation.session.header.actions'` list beside the title and the independent `'conversation.session.header.utilities'` list at the right edge. Session context and lineage controls remain in `actions`; optional Session utilities cannot reorder or move them. The composer chain currency includes the current conversation `session`; ui-subagent selects one-shot or parent-unavailable addressed sessions for reason-specific read-only copy, while the ordinary InputBar keeps every addressed child Send-only because the continuation service exposes no public per-Activation cancellation operation and `session.cancel` would bypass its ownership. +The session header renders each subagent breadcrumb title through the optional session-scoped `'conversation.session.header.lineage'` seat, followed by the `'conversation.session.header.actions'` list and the independent `'conversation.session.header.utilities'` list at the right edge. Each lineage owner identifies its breadcrumb session and supplies the ordinary title as fallback; an ancestor also supplies its upward-navigation callback. Removing the occupant restores every title without affecting header actions, and optional Session utilities cannot reorder or move either group. The composer chain currency includes the current conversation `session`; ui-subagent selects one-shot or parent-unavailable addressed sessions for reason-specific read-only copy, while the ordinary InputBar keeps every addressed child Send-only because the continuation service exposes no public per-Activation cancellation operation and `session.cancel` would bypass its ownership. Logged non-user messages render as a default-collapsed disclosure whose header names the role the runtime projected for the message — `上下文注入` for an injection, `跨会话召回` for a recalled session — followed by the producer name that projection read out of the durable source, so a reader distinguishes a skill catalog from a workspace instruction file or a recalled session without expanding. A direct message that cites another session precedes its recall row in durable order. The Chat snapshot associates exact labels only from that immediately following sourced recall, preserving multi-word titles without carrying one recall's labels onto a later direct message. Recall uses a chat-bubble glyph while other context keeps the document glyph; a source that names no producer shows the role alone. Composer and user-bubble references use the same inline language: a chat-bubble, file, or folder glyph plus business-color text, without a nested capsule. Like claimed slash commands, composer references keep their complete display text in the transparent textarea and use the aligned backdrop for color and the leading domain glyph; native text metrics own width, wrapping, selection, and caret placement. The occurrence range remains structured for serialization and boundary deletion, while an edit inside it converts the remaining characters to ordinary text. The session draft mirror stores each occurrence's clipboard projection, so a remount without the occurrence table restores canonical parseable reference text instead of a display-only label. The shared `DisclosureRow` primitive gives this context surface the same compact geometry as other flow rows while retaining context semantics: the expanded body follows its content height up to a 141px scrolling cap and synthesizes no tool state or summary ([historical disclosure decision](../../../.agents/notes/archived/feature/2026-07-30-web-context-injection-disclosure.md), [producer-label decision](../../../.agents/notes/implemented/feature/2026-08-04-web-context-source-and-steer-marks.md)). That body follows the form the producer declared on its durable source: `instructions` names the reconciled files above their text, `catalog` lists the entries the source recorded instead of the model-facing prose, and every other value — absent, unknown to this version, or carrying no usable fields — renders the opaque body, which shows the model-facing text with its real line breaks and the remaining source fields. The opaque body is the documented default, not a leftover: a resumed, forked, or foreign log must render whether or not its producer is mounted here. A durable or pending steering bubble shares the user bubble's presentation unadorned; its mid-turn position in the flow is the only steering signal the transcript shows. diff --git a/packages/client/ui-conversation/README.zh.md b/packages/client/ui-conversation/README.zh.md index a2d514af39..76395003e4 100644 --- a/packages/client/ui-conversation/README.zh.md +++ b/packages/client/ui-conversation/README.zh.md @@ -6,7 +6,7 @@ 压缩(compaction)在检查点自身的消息流位置渲染为一行折叠标记,不替换其上方的 transcript(文本记录)。自动压缩使用「上下文已压缩」标题。每个已加载对应 `compaction/summary` 事件的完成标记都会显示被替换条目数量和估算 token 数量,并可点击展开摘要。手动 `/compact` 开始时显示为运行中的 `compact` 行;成功结算后,其显式摘要事件引用会在保持同一 React key 的前提下把该命令折叠进检查点行。完成的检查点静止时保留上下文压缩(context compaction)图标,仅在悬停或键盘聚焦时将其替换为收起/展开指示图标。输入被拒绝、没有可压缩历史、取消和失败时仍使用通用命令行及处理器撰写的文本。配对绝不依赖相邻关系,因为压缩运行期间可能注入持久上下文。面向模型的带框检查点载荷绝不渲染;被引用的 `compaction/summary` 事件位于已加载窗口之外时,检查点仍然可见但不可展开。 -常驻会话壳会跨无会话与会话状态切换而保留。没有当前会话时,它会锁定消息操作,并让整张虚线编辑器卡片成为根作用域 `conversation.hero.workspace` Workspace picker 的入口;textarea 保持只读且支持键盘操作。Hero 前方的标记是独立的根作用域 `conversation.hero.brand.mark` slot,未被占用时回退到鱼形标记。选择 Workspace 会连接或复用由 Host 拥有的空白会话,并在不替换会话壳的情况下打开该会话。根组件始终拥有同一个滚动容器与 Hero/编辑器子树;首个会话到达时,彼此独立的严格会话页头和主体 outlet 只填入各自区域,因此 Workspace picker、滚动主体、编辑器 seat 与 textarea 都保留原有 React 和 DOM identity。空白会话与活跃会话渲染相同的输入区主体;InputHub 则在 Workspace 切换间携带草稿,并将草稿镜像到会话 store。活跃阶段,会话标题栏作为普通列 chrome,仅显示当前会话标题和视图标签;fork 谱系仍保留为会话数据,不投影到标题栏。其下滚动容器(`data-conversation-scroll`)承载流动排版的各视图与 sticky 编辑器栈(统计 dock+输入区 dock+输入栏)。该滚动容器无条件预留自己的滚动条槽,选用编辑器 overlay 的视图也仍把它保留为滚动容器,因此无论对话记录是否滚动、无论展示哪个视图标签,输入卡片都保持同一个横向位置([决策](../../../.agents/notes/implemented/bug-fix/2026-08-04-composer-tab-gutter-reservation.zh.md))。textarea 上的滚轮会链式处理:限高草稿先在本地滚动,到达边缘后再转交给该宿主。只有 Safari 会在原生编辑缩短草稿并留下陈旧软换行溢出时执行绘制前恢复;草稿增长、程序化更新与其他浏览器都不会为这项恢复读取布局([决策](../../../.agents/notes/implemented/bug-fix/2026-08-13-safari-textarea-soft-wrap-reflow.zh.md))。 +常驻会话壳会跨无会话与会话状态切换而保留。没有当前会话时,它会锁定消息操作,并让整张虚线编辑器卡片成为根作用域 `conversation.hero.workspace` Workspace picker 的入口;textarea 保持只读且支持键盘操作。Hero 前方的标记是独立的根作用域 `conversation.hero.brand.mark` slot,未被占用时回退到鱼形标记。选择 Workspace 会连接或复用由 Host 拥有的空白会话,并在不替换会话壳的情况下打开该会话。根组件始终拥有同一个滚动容器与 Hero/编辑器子树;首个会话到达时,彼此独立的严格会话页头和主体 outlet 只填入各自区域,因此 Workspace picker、滚动主体、编辑器 seat 与 textarea 都保留原有 React 和 DOM identity。空白会话与活跃会话渲染相同的输入区主体;InputHub 则在 Workspace 切换间携带草稿,并将草稿镜像到会话 store。活跃阶段,会话标题栏作为普通列 chrome,显示当前会话 title、可选谱系控件和视图标签;普通 fork 谱系仍保留为会话数据,不投影到标题栏。其下滚动容器(`data-conversation-scroll`)承载流动排版的各视图与 sticky 编辑器栈(统计 dock+输入区 dock+输入栏)。该滚动容器无条件预留自己的滚动条槽,选用编辑器 overlay 的视图也仍把它保留为滚动容器,因此无论对话记录是否滚动、无论展示哪个视图标签,输入卡片都保持同一个横向位置([决策](../../../.agents/notes/implemented/bug-fix/2026-08-04-composer-tab-gutter-reservation.zh.md))。textarea 上的滚轮会链式处理:限高草稿先在本地滚动,到达边缘后再转交给该宿主。只有 Safari 会在原生编辑缩短草稿并留下陈旧软换行溢出时执行绘制前恢复;草稿增长、程序化更新与其他浏览器都不会为这项恢复读取布局([决策](../../../.agents/notes/implemented/bug-fix/2026-08-13-safari-textarea-soft-wrap-reflow.zh.md))。 别的插件可以经 `ctx.conversation.blocks` 让某个会话的编辑器变为惰性:它设置一个携带自己本地化理由的 block,输入栏就渲染同一个禁用的 textarea,并把该理由作为 placeholder——复用无 Workspace 时的那套姿态。推送方向是约束而非偏好:知道某会话发不出消息的插件(ui-model-selection,在没有适配器服务其路由时)本就依赖本包,因此本包读不到它们。模型 seat 是 block 唯一保留可用的控件——这份约定里的每个 block 都靠选模型来解除,把它一起锁上会让编辑器索要它自己拦下的那件事。block 只是提示性设计;无论客户端禁用了什么,宿主都会拒绝一个它无法路由的提示词。两者同时成立时以无 Workspace 姿态为准,因为选 Workspace 是更靠前的前提。 @@ -14,7 +14,7 @@ Chat 业务行是彼此独立的注册表贡献,不是封闭的内建联合。Client 插件通过 declaration merging 增加类型化 `ChatNodeDataMap` key,在 `ctx.conversationEvents` 上注册 `ConversationNodeDefinition`,再向 `conversation.chat.node` 注册匹配的 keyed renderer;它无须修改会话 fold 或中央 renderer switch。稳定事件 id、append/prepend 回放、Location data 与 renderer 约束见 [Conversation Node 实操手册](../../../docs/cookbook/adding-a-conversation-node.zh.md)。 -会话页头会在标题旁渲染会话作用域的 `'conversation.session.header.actions'` 列表,并在最右侧渲染独立的 `'conversation.session.header.utilities'` 列表。会话上下文和谱系控件保留在 `actions` 中;可选的会话工具不会改变它们的顺序或位置。编辑器链的 currency 包含当前对话 `session`;ui-subagent 会选取 one-shot 或 parent 不可用的已寻址会话,并按原因显示只读文案,而普通 InputBar 会让所有已寻址 child 仅保留 Send,因为继续执行服务不公开逐 Activation 取消操作,`session.cancel` 也会绕过其所有权。 +会话页头通过可选的会话作用域 `'conversation.session.header.lineage'` seat 渲染每一级 subagent 面包屑 title,随后依次渲染 `'conversation.session.header.actions'` 列表和最右侧独立的 `'conversation.session.header.utilities'` 列表。每个谱系 owner 都会标识其面包屑会话,并提供普通 title 作为回退;祖先还会提供向上导航的回调。移除 occupant 会恢复每个 title,且不影响页头操作;可选的会话工具不会改变这两个区域的顺序或位置。编辑器链的 currency 包含当前对话 `session`;ui-subagent 会选取 one-shot 或 parent 不可用的已寻址会话,并按原因显示只读文案,而普通 InputBar 会让所有已寻址 child 仅保留 Send,因为继续执行服务不公开逐 Activation 取消操作,`session.cancel` 也会绕过其所有权。 已记录的非用户消息渲染为默认折叠的展开项,标题栏先给出运行时为该消息投影出的角色——注入为 `上下文注入`,召回为 `跨会话召回`——其后是该投影从持久来源读出的生产者名称,因此读者无需展开即可区分 skill(技能)目录、工作区指令文件与被召回的会话。引用其他会话的直接消息在持久顺序中位于其召回行之前。Chat 快照只从紧随其后的带来源召回中关联准确标签,因此既能保留多词标题,也不会把一条召回的标签带到后续直接消息上。召回使用聊天气泡图标,其他上下文保留文档图标;来源未提供生产者名称时只显示角色。输入框与用户气泡中的引用使用同一种行内语言:聊天气泡、文件或文件夹图标加业务色文字,不嵌套胶囊容器。与已认领的 slash command 相同,输入框引用会把完整展示文本保留在透明 textarea 中,再用对齐的 backdrop 提供颜色和开头的领域图标;宽度、换行、选择区与光标位置均由原生文本度量决定。occurrence 范围仍为序列化与边界整段删除保留结构身份,在范围内部编辑则会把剩余字符转为普通文本。会话草稿镜像会存储每个 occurrence 的剪贴板投影,因此在 occurrence 表缺失的情况下重新挂载时,会恢复可解析的规范引用文本,而不是仅供显示的标签。共享的 `DisclosureRow` 原子组件让该上下文界面与消息流中的其他紧凑行保持相同几何,同时保留上下文语义:展开内容区的高度会随内容自适应,最大为 141px,超出后滚动,且不会合成工具状态或摘要([历史展开项决策](../../../.agents/notes/archived/feature/2026-07-30-web-context-injection-disclosure.md)、[生产者标签决策](../../../.agents/notes/implemented/feature/2026-08-04-web-context-source-and-steer-marks.zh.md))。该内容区按生产方在持久来源上声明的形态渲染:`instructions` 在正文之上列出它对账过的文件,`catalog` 列出来源记录的条目而非面向模型的正文,其余取值——未声明、本版本不认识、或字段不可用——一律渲染 opaque 内容区,即按真实换行展示面向模型的文本,并把剩余来源字段列出。opaque 不是兜底剩余物而是有文档的默认:恢复的、fork 的、外部写入的日志,无论其生产方是否挂载在此处,都必须渲染得出来。持久或待处理的 steering(中途引导)气泡沿用用户气泡的呈现,不加任何装饰;transcript 中唯一的 steering 信号是它出现在轮次中途的位置。 diff --git a/packages/client/ui-conversation/src/client/apply.ts b/packages/client/ui-conversation/src/client/apply.ts index 294009a09b..7920104d68 100644 --- a/packages/client/ui-conversation/src/client/apply.ts +++ b/packages/client/ui-conversation/src/client/apply.ts @@ -259,6 +259,7 @@ export function apply(ctx: Context): void { name: 'conversation.session.header', locale: NS, children: { + 'conversation.session.header.lineage': { kind: 'single', scope: 'session' }, 'conversation.session.header.actions': { kind: 'list', scope: 'session' }, 'conversation.session.header.utilities': { kind: 'list', scope: 'session' }, }, diff --git a/packages/client/ui-conversation/src/client/contract/slots.ts b/packages/client/ui-conversation/src/client/contract/slots.ts index 4ea0c79402..832e48b890 100644 --- a/packages/client/ui-conversation/src/client/contract/slots.ts +++ b/packages/client/ui-conversation/src/client/contract/slots.ts @@ -77,6 +77,16 @@ declare module '@deepseek-ai/dsh-client-ui-slots' { * takes every action entry down with it. */ 'conversation.session.header': { kind: 'single'; scope: 'session' } + /** + * One breadcrumb title and its lineage controls. The owner supplies the + * ordinary title as both slot currency and render fallback; an occupant + * may replace it with one combined navigation control. + */ + 'conversation.session.header.lineage': { + kind: 'single' + scope: 'session' + owner: ConversationHeaderLineageOwnerProps + } /** * One button in the session header's action row — the additive way to put * a per-session control beside the title without replacing the header. @@ -305,6 +315,18 @@ export interface ConversationSessionOwnerProps { /** Header actions derive their state from the standard session/global kit. */ export interface ConversationHeaderActionOwnerProps {} +/** Breadcrumb-title content handed to the optional lineage renderer. */ +export interface ConversationHeaderLineageOwnerProps { + /** Session represented by this breadcrumb title. */ + lineageSessionId: SessionId + /** Ordinary breadcrumb-title node retained when no lineage renderer is installed. */ + title: ReactNode + /** Display title available to a renderer that combines the title with a control. */ + displayTitle: string + /** Navigate to an ancestor title when its combined control is clicked. */ + openTitle?: () => void +} + /** * The input-region slot currency: dock/left/right entries read * the conversation snapshot and the live input state as owner props (both @@ -640,7 +662,11 @@ export type ConversationSessionSlotProps = /** Full strict-session header props: shared store, tabs/actions render shares, navigation, and locale. */ export type ConversationSessionHeaderSlotProps = PropsRuntime<'conversation.session.header'> - & PropsRenderSlots<'conversation.session.header.actions' | 'conversation.session.header.utilities'> + & PropsRenderSlots< + 'conversation.session.header.lineage' + | 'conversation.session.header.actions' + | 'conversation.session.header.utilities' + > & PropsStore & ConversationSessionHeaderInjected & PropsLocale<'conversation'> diff --git a/packages/client/ui-conversation/src/client/index.ts b/packages/client/ui-conversation/src/client/index.ts index 814734411b..78732229b0 100644 --- a/packages/client/ui-conversation/src/client/index.ts +++ b/packages/client/ui-conversation/src/client/index.ts @@ -31,7 +31,8 @@ export type { ChatFileMentions, ChatNodeOwnerProps, ChatNodeViewProps, ChatStore, ChatViewInjected, ChatViewSlotProps, CommandRowOwnerProps, CommandRowProps, ComposerBarInjected, ComposerAttachment, ComposerAttachmentsOwnerProps, ComposerAttachmentsProps, ComposerChainProps, ConversationInjected, - ConversationSessionHeaderInjected, ConversationSessionInjected, ConversationSlotProps, ConvViewOwnerProps, + ConversationHeaderLineageOwnerProps, ConversationSessionHeaderInjected, ConversationSessionInjected, + ConversationSlotProps, ConvViewOwnerProps, ConvViewProps, DetailsInjected, DetailsSlotProps, DetailsToolOwnerProps, EmptyWorkspaceOwnerProps, HeroBrandMarkOwnerProps, MessageImagesOwnerProps, MessageImagesProps, RenderMessageImages, TurnTailOwnerProps, UseChatNodeTurnData, } from './contract/slots.ts' diff --git a/packages/client/ui-conversation/src/client/skeleton/ConversationRoot.module.css b/packages/client/ui-conversation/src/client/skeleton/ConversationRoot.module.css index 6146d42810..265a0bd802 100644 --- a/packages/client/ui-conversation/src/client/skeleton/ConversationRoot.module.css +++ b/packages/client/ui-conversation/src/client/skeleton/ConversationRoot.module.css @@ -103,6 +103,11 @@ cursor: pointer; } +.crumbSubagent { + font-size: 12px; + line-height: 18px; +} + .crumb:hover:not(:disabled) { background: var(--dsw-alias-interactive-bg-hover); } diff --git a/packages/client/ui-conversation/src/client/skeleton/ConversationSession.tsx b/packages/client/ui-conversation/src/client/skeleton/ConversationSession.tsx index d576aa175d..ca5e22c4dc 100644 --- a/packages/client/ui-conversation/src/client/skeleton/ConversationSession.tsx +++ b/packages/client/ui-conversation/src/client/skeleton/ConversationSession.tsx @@ -18,6 +18,7 @@ export type ConversationSessionHeaderProps = ConversationSessionHeaderSlotProps interface Breadcrumb { readonly id: SessionId readonly displayTitle: string + readonly subagent: boolean } const DEFAULT_VIEW_ID = 'chat' @@ -38,7 +39,11 @@ function deriveAncestry(list: SessionListState, id: SessionId): readonly Breadcr seen.add(cursor) const summary: SessionSummary | undefined = list.byId[cursor] if (summary === undefined) break - chain.unshift({ id: summary.id, displayTitle: summary.displayTitle }) + chain.unshift({ + id: summary.id, + displayTitle: summary.displayTitle, + subagent: summary.origin === 'subagent', + }) if (summary.origin !== 'subagent') break cursor = summary.parentId } @@ -83,17 +88,32 @@ export function ConversationSessionHeader({