@ai-agent-forge/agent-forge 0.88.5 → 0.88.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (202) hide show
  1. package/CHANGELOG.md +36 -0
  2. package/bundled-plugins/agent-loop-policy/agent-forge.json +1 -1
  3. package/bundled-plugins/agent-loop-policy/plugin.json +1 -1
  4. package/bundled-plugins/alignment/agent-forge.json +19 -0
  5. package/bundled-plugins/alignment/dist/baseline.d.ts +12 -0
  6. package/bundled-plugins/alignment/dist/baseline.d.ts.map +1 -0
  7. package/bundled-plugins/alignment/dist/baseline.js +68 -0
  8. package/bundled-plugins/alignment/dist/baseline.js.map +1 -0
  9. package/bundled-plugins/alignment/dist/engine.d.ts +102 -0
  10. package/bundled-plugins/alignment/dist/engine.d.ts.map +1 -0
  11. package/bundled-plugins/alignment/dist/engine.js +654 -0
  12. package/bundled-plugins/alignment/dist/engine.js.map +1 -0
  13. package/bundled-plugins/alignment/dist/entry.d.ts +14 -0
  14. package/bundled-plugins/alignment/dist/entry.d.ts.map +1 -0
  15. package/bundled-plugins/alignment/dist/entry.js +23 -0
  16. package/bundled-plugins/alignment/dist/entry.js.map +1 -0
  17. package/bundled-plugins/alignment/dist/export.d.ts +15 -0
  18. package/bundled-plugins/alignment/dist/export.d.ts.map +1 -0
  19. package/bundled-plugins/alignment/dist/export.js +122 -0
  20. package/bundled-plugins/alignment/dist/export.js.map +1 -0
  21. package/bundled-plugins/alignment/dist/http-server.d.ts +33 -0
  22. package/bundled-plugins/alignment/dist/http-server.d.ts.map +1 -0
  23. package/bundled-plugins/alignment/dist/http-server.js +119 -0
  24. package/bundled-plugins/alignment/dist/http-server.js.map +1 -0
  25. package/bundled-plugins/alignment/dist/index.d.ts +24 -0
  26. package/bundled-plugins/alignment/dist/index.d.ts.map +1 -0
  27. package/bundled-plugins/alignment/dist/index.js +719 -0
  28. package/bundled-plugins/alignment/dist/index.js.map +1 -0
  29. package/bundled-plugins/alignment/dist/page.d.ts +15 -0
  30. package/bundled-plugins/alignment/dist/page.d.ts.map +1 -0
  31. package/bundled-plugins/alignment/dist/page.js +857 -0
  32. package/bundled-plugins/alignment/dist/page.js.map +1 -0
  33. package/bundled-plugins/alignment/dist/render.d.ts +40 -0
  34. package/bundled-plugins/alignment/dist/render.d.ts.map +1 -0
  35. package/bundled-plugins/alignment/dist/render.js +194 -0
  36. package/bundled-plugins/alignment/dist/render.js.map +1 -0
  37. package/bundled-plugins/alignment/dist/types.d.ts +217 -0
  38. package/bundled-plugins/alignment/dist/types.d.ts.map +1 -0
  39. package/bundled-plugins/alignment/dist/types.js +30 -0
  40. package/bundled-plugins/alignment/dist/types.js.map +1 -0
  41. package/bundled-plugins/alignment/plugin.json +12 -0
  42. package/bundled-plugins/browser-playwright/MANUAL.md +60 -0
  43. package/bundled-plugins/browser-playwright/agent-forge.json +25 -0
  44. package/bundled-plugins/browser-playwright/dist/capability.d.ts +25 -0
  45. package/bundled-plugins/browser-playwright/dist/capability.d.ts.map +1 -0
  46. package/bundled-plugins/browser-playwright/dist/capability.js +612 -0
  47. package/bundled-plugins/browser-playwright/dist/capability.js.map +1 -0
  48. package/bundled-plugins/browser-playwright/dist/entry.d.ts +13 -0
  49. package/bundled-plugins/browser-playwright/dist/entry.d.ts.map +1 -0
  50. package/bundled-plugins/browser-playwright/dist/entry.js +14 -0
  51. package/bundled-plugins/browser-playwright/dist/entry.js.map +1 -0
  52. package/bundled-plugins/browser-playwright/dist/index.d.ts +7 -0
  53. package/bundled-plugins/browser-playwright/dist/index.d.ts.map +1 -0
  54. package/bundled-plugins/browser-playwright/dist/index.js +5 -0
  55. package/bundled-plugins/browser-playwright/dist/index.js.map +1 -0
  56. package/bundled-plugins/browser-playwright/dist/operations.d.ts +69 -0
  57. package/bundled-plugins/browser-playwright/dist/operations.d.ts.map +1 -0
  58. package/bundled-plugins/browser-playwright/dist/operations.js +149 -0
  59. package/bundled-plugins/browser-playwright/dist/operations.js.map +1 -0
  60. package/bundled-plugins/browser-playwright/dist/playwright-driver.d.ts +275 -0
  61. package/bundled-plugins/browser-playwright/dist/playwright-driver.d.ts.map +1 -0
  62. package/bundled-plugins/browser-playwright/dist/playwright-driver.js +953 -0
  63. package/bundled-plugins/browser-playwright/dist/playwright-driver.js.map +1 -0
  64. package/bundled-plugins/browser-playwright/dist/setup.d.ts +88 -0
  65. package/bundled-plugins/browser-playwright/dist/setup.d.ts.map +1 -0
  66. package/bundled-plugins/browser-playwright/dist/setup.js +252 -0
  67. package/bundled-plugins/browser-playwright/dist/setup.js.map +1 -0
  68. package/bundled-plugins/browser-playwright/dist/types.d.ts +270 -0
  69. package/bundled-plugins/browser-playwright/dist/types.d.ts.map +1 -0
  70. package/bundled-plugins/browser-playwright/dist/types.js +2 -0
  71. package/bundled-plugins/browser-playwright/dist/types.js.map +1 -0
  72. package/bundled-plugins/browser-playwright/plugin.json +20 -0
  73. package/bundled-plugins/coding-tools/agent-forge.json +1 -1
  74. package/bundled-plugins/coding-tools/dist/bash.d.ts +2 -7
  75. package/bundled-plugins/coding-tools/dist/bash.d.ts.map +1 -1
  76. package/bundled-plugins/coding-tools/dist/bash.js +2 -34
  77. package/bundled-plugins/coding-tools/dist/bash.js.map +1 -1
  78. package/bundled-plugins/coding-tools/dist/read.d.ts +2 -0
  79. package/bundled-plugins/coding-tools/dist/read.d.ts.map +1 -1
  80. package/bundled-plugins/coding-tools/dist/read.js +11 -0
  81. package/bundled-plugins/coding-tools/dist/read.js.map +1 -1
  82. package/bundled-plugins/coding-tools/plugin.json +1 -1
  83. package/bundled-plugins/compaction-policy/agent-forge.json +1 -1
  84. package/bundled-plugins/compaction-policy/plugin.json +1 -1
  85. package/bundled-plugins/mcp-http/dist/mcp-http.d.ts.map +1 -1
  86. package/bundled-plugins/mcp-http/dist/mcp-http.js +84 -31
  87. package/bundled-plugins/mcp-http/dist/mcp-http.js.map +1 -1
  88. package/bundled-plugins/overflow-policy/agent-forge.json +1 -1
  89. package/bundled-plugins/overflow-policy/plugin.json +1 -1
  90. package/bundled-plugins/provider-failover/agent-forge.json +1 -1
  91. package/bundled-plugins/provider-failover/plugin.json +1 -1
  92. package/bundled-plugins/retry-policy/agent-forge.json +1 -1
  93. package/bundled-plugins/retry-policy/plugin.json +1 -1
  94. package/dist/bundle/.build-manifest.json +60 -58
  95. package/dist/bundle/chunks/{anthropic-messages-3FJHRAJL.js → anthropic-messages-NL4Y6WPB.js} +1 -1
  96. package/dist/bundle/chunks/{azure-openai-responses-GCL47IDS.js → azure-openai-responses-CPXC42HO.js} +1 -1
  97. package/dist/bundle/chunks/bedrock-converse-stream.js +1 -1
  98. package/dist/bundle/chunks/chunk-5LRQFZFE.js +2 -0
  99. package/dist/bundle/chunks/{chunk-HTEVUY7F.js → chunk-7HSJPQKN.js} +1 -1
  100. package/dist/bundle/chunks/{chunk-AC2FIS4G.js → chunk-EDO7Q6XR.js} +1 -1
  101. package/dist/bundle/chunks/{chunk-755VNWIF.js → chunk-ISLHFRER.js} +6 -6
  102. package/dist/bundle/chunks/{chunk-HV64ASMT.js → chunk-K3S6GTL7.js} +1 -1
  103. package/dist/bundle/chunks/{chunk-HEL6TAWE.js → chunk-L2SXIPI5.js} +37 -36
  104. package/dist/bundle/chunks/{chunk-V3ACW7VD.js → chunk-WJSKB3FC.js} +1 -1
  105. package/dist/bundle/chunks/{chunk-32YDZI4J.js → chunk-ZS5JEI76.js} +1 -1
  106. package/dist/bundle/chunks/{google-generative-ai-6BMXWA44.js → google-generative-ai-UMZ53EFA.js} +1 -1
  107. package/dist/bundle/chunks/{google-vertex-6H7NLRTK.js → google-vertex-ZNR5NS6H.js} +1 -1
  108. package/dist/bundle/chunks/image-resize-worker.js +1 -1
  109. package/dist/bundle/chunks/{mistral-conversations-IXUHSFSJ.js → mistral-conversations-IT66WUNN.js} +1 -1
  110. package/dist/bundle/chunks/{openai-codex-responses-YHUAEVCM.js → openai-codex-responses-FOVCVG6I.js} +1 -1
  111. package/dist/bundle/chunks/{openai-completions-ULQCFC72.js → openai-completions-FLQ7CBOL.js} +1 -1
  112. package/dist/bundle/chunks/{openai-responses-NLLAJDPS.js → openai-responses-ABGYHS2T.js} +1 -1
  113. package/dist/bundle/chunks/{pi-messages-EJTI2EJ3.js → pi-messages-6K5W6LUN.js} +1 -1
  114. package/dist/bundle/chunks/{virtual-modules-TQWEGNNZ.js → virtual-modules-2QGILFV7.js} +1 -1
  115. package/dist/bundle/cli.js +1 -1
  116. package/dist/bundle/client.js +1 -1
  117. package/dist/bundle/index.js +1 -1
  118. package/dist/bundle/rpc-entry.js +1 -1
  119. package/dist/client/remote-session.d.ts.map +1 -1
  120. package/dist/client/remote-session.js +65 -6
  121. package/dist/client/remote-session.js.map +1 -1
  122. package/dist/core/agent-session-store.d.ts.map +1 -1
  123. package/dist/core/agent-session-store.js +20 -3
  124. package/dist/core/agent-session-store.js.map +1 -1
  125. package/dist/core/extensions/agent-composition.d.ts.map +1 -1
  126. package/dist/core/extensions/agent-composition.js +20 -1
  127. package/dist/core/extensions/agent-composition.js.map +1 -1
  128. package/dist/core/i18n/locales/zh-cn/core-errors.d.ts.map +1 -1
  129. package/dist/core/i18n/locales/zh-cn/core-errors.js +1 -0
  130. package/dist/core/i18n/locales/zh-cn/core-errors.js.map +1 -1
  131. package/dist/core/i18n/locales/zh-cn/interactive-mode.d.ts.map +1 -1
  132. package/dist/core/i18n/locales/zh-cn/interactive-mode.js +10 -3
  133. package/dist/core/i18n/locales/zh-cn/interactive-mode.js.map +1 -1
  134. package/dist/core/keybindings.d.ts +35 -0
  135. package/dist/core/keybindings.d.ts.map +1 -1
  136. package/dist/core/keybindings.js +34 -0
  137. package/dist/core/keybindings.js.map +1 -1
  138. package/dist/core/sdk.d.ts.map +1 -1
  139. package/dist/core/sdk.js +62 -15
  140. package/dist/core/sdk.js.map +1 -1
  141. package/dist/core/session-manager.d.ts.map +1 -1
  142. package/dist/core/session-manager.js +11 -3
  143. package/dist/core/session-manager.js.map +1 -1
  144. package/dist/core/system-prompt.d.ts.map +1 -1
  145. package/dist/core/system-prompt.js +2 -2
  146. package/dist/core/system-prompt.js.map +1 -1
  147. package/dist/core/tools/capability-mount.d.ts.map +1 -1
  148. package/dist/core/tools/capability-mount.js +4 -21
  149. package/dist/core/tools/capability-mount.js.map +1 -1
  150. package/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
  151. package/dist/modes/interactive/components/assistant-message.js +2 -2
  152. package/dist/modes/interactive/components/assistant-message.js.map +1 -1
  153. package/dist/modes/interactive/components/bash-execution.d.ts +2 -0
  154. package/dist/modes/interactive/components/bash-execution.d.ts.map +1 -1
  155. package/dist/modes/interactive/components/bash-execution.js +25 -0
  156. package/dist/modes/interactive/components/bash-execution.js.map +1 -1
  157. package/dist/modes/interactive/components/changelog-pager.d.ts +53 -0
  158. package/dist/modes/interactive/components/changelog-pager.d.ts.map +1 -0
  159. package/dist/modes/interactive/components/changelog-pager.js +239 -0
  160. package/dist/modes/interactive/components/changelog-pager.js.map +1 -0
  161. package/dist/modes/interactive/components/tool-execution.d.ts +6 -0
  162. package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  163. package/dist/modes/interactive/components/tool-execution.js +12 -0
  164. package/dist/modes/interactive/components/tool-execution.js.map +1 -1
  165. package/dist/modes/interactive/components/tool-run-group.d.ts +41 -11
  166. package/dist/modes/interactive/components/tool-run-group.d.ts.map +1 -1
  167. package/dist/modes/interactive/components/tool-run-group.js +126 -14
  168. package/dist/modes/interactive/components/tool-run-group.js.map +1 -1
  169. package/dist/modes/interactive/interactive-commands.d.ts.map +1 -1
  170. package/dist/modes/interactive/interactive-commands.js +23 -13
  171. package/dist/modes/interactive/interactive-commands.js.map +1 -1
  172. package/dist/modes/interactive/interactive-events.d.ts +14 -4
  173. package/dist/modes/interactive/interactive-events.d.ts.map +1 -1
  174. package/dist/modes/interactive/interactive-events.js +94 -12
  175. package/dist/modes/interactive/interactive-events.js.map +1 -1
  176. package/dist/modes/interactive/interactive-mode.d.ts +6 -1
  177. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  178. package/dist/modes/interactive/interactive-mode.js +21 -5
  179. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  180. package/dist/plugins/ecosystem/node-local-package-source.d.ts +2 -1
  181. package/dist/plugins/ecosystem/node-local-package-source.d.ts.map +1 -1
  182. package/dist/plugins/ecosystem/node-local-package-source.js +110 -4
  183. package/dist/plugins/ecosystem/node-local-package-source.js.map +1 -1
  184. package/dist/plugins/ecosystem/node-package-install-host.d.ts.map +1 -1
  185. package/dist/plugins/ecosystem/node-package-install-host.js +106 -39
  186. package/dist/plugins/ecosystem/node-package-install-host.js.map +1 -1
  187. package/dist/plugins/ecosystem/node-plugin-bootstrap.d.ts.map +1 -1
  188. package/dist/plugins/ecosystem/node-plugin-bootstrap.js +85 -2
  189. package/dist/plugins/ecosystem/node-plugin-bootstrap.js.map +1 -1
  190. package/dist/suites/builtin-suites.d.ts.map +1 -1
  191. package/dist/suites/builtin-suites.js +2 -2
  192. package/dist/suites/builtin-suites.js.map +1 -1
  193. package/dist/utils/changelog.d.ts +27 -0
  194. package/dist/utils/changelog.d.ts.map +1 -1
  195. package/dist/utils/changelog.js +110 -0
  196. package/dist/utils/changelog.js.map +1 -1
  197. package/docs/keybindings.md +14 -0
  198. package/examples/extensions/with-deps/package-lock.json +2 -2
  199. package/examples/extensions/with-deps/package.json +1 -1
  200. package/examples/extensions/with-deps/plugin.json +1 -1
  201. package/package.json +1 -1
  202. package/dist/bundle/chunks/chunk-A3JYRWB6.js +0 -2
@@ -0,0 +1 @@
1
+ {"version":3,"file":"engine.js","sourceRoot":"","sources":["../src/engine.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Pure alignment state machine (设计 §5) — no host API access, no I/O.\n *\n * Every function takes JSON-safe state and returns the next state plus the\n * audit transitions to persist; index.ts owns persistence (entries + events)\n * and http-server.ts owns transport. Deterministic by construction: same\n * inputs, same outputs, no clocks, no randomness.\n */\n\nimport { createHash } from \"node:crypto\";\nimport {\n\tALIGNMENT_LIMITS,\n\ttype AlignmentBlock,\n\ttype AlignmentBlockKind,\n\ttype AlignmentComment,\n\tAlignmentError,\n\ttype AlignmentRecord,\n\ttype AlignmentRoundPost,\n\ttype AlignmentRoundResult,\n\ttype AlignmentState,\n\ttype AlignmentStepId,\n\ttype AlignmentStepState,\n\ttype AlignmentTransitionEntry,\n\ttype AlignmentVersionSnapshot,\n\ttype GateSnapshot,\n\ttype PendingItem,\n\tSTEP_ORDER,\n} from \"./types.ts\";\n\nexport interface EngineRun {\n\tstate: AlignmentState;\n\ttransitions: AlignmentTransitionEntry[];\n}\n\n/** Model-facing block input (alignment_set); comment ownership is checked against it. */\nexport interface BlockInput {\n\tid: string;\n\tkind: AlignmentBlockKind;\n\tcontent: string;\n\trationale?: string;\n\timpact?: string[];\n\t/** New assistant comments for this block (author is forced to assistant). */\n\tcomments?: { id: string; note: string; quote?: string }[];\n\t/** Resolutions the model attaches to existing comments. */\n\tcommentResolutions?: {\n\t\tcommentId: string;\n\t\tkind: \"answered\" | \"dismissed\" | \"incorporated\";\n\t\ttext?: string;\n\t}[];\n}\n\nexport interface AlignmentSetInput {\n\tid: string;\n\ttitle?: string;\n\tgoalId?: string;\n\trevision?: number;\n\t/**\n\t * Explicit confirmation that this write may rewrite blocks the user already\n\t * approved (总则 3): without it, a fingerprint change on an approved block\n\t * is rejected with `approved-blocks-conflict` instead of silently resetting\n\t * it to pending.\n\t */\n\treviseApproved?: boolean;\n\tblocks: BlockInput[];\n}\n\nexport interface AdvanceInput {\n\talignmentId: string;\n\taction: \"inspect\" | \"retreat\" | \"cancel\" | \"rollback\";\n\tstep?: AlignmentStepId;\n\tnote?: string;\n\t/** Rollback target: the active step's snapshot revision anchor; latest snapshot when omitted. */\n\tversionId?: number;\n}\n\nexport interface RoundPostOutcome {\n\trecord: AlignmentRecord;\n\ttransitions: AlignmentTransitionEntry[];\n\tresult: AlignmentRoundResult;\n}\n\nexport interface AdvanceOutcome {\n\tstate: AlignmentState;\n\ttransitions: AlignmentTransitionEntry[];\n}\n\n// ---------------------------------------------------------------------------\n// Hashing & validation\n// ---------------------------------------------------------------------------\n\nconst ID_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._-]*$/;\n\nexport function validAlignmentId(id: string): boolean {\n\t// 入参可能来自未校验的工具输入(空对象 → undefined):test() 会把实参\n\t// 字符串化为 \"undefined\" 而\"通过\"模式匹配,必须先做类型守卫。\n\treturn typeof id === \"string\" && ID_PATTERN.test(id) && id.length <= 128;\n}\n\n/** Fingerprint of the fields whose change must re-ask for approval (总则 3). */\nexport function blockFingerprint(\n\tkind: AlignmentBlockKind,\n\tcontent: string,\n\trationale: string | undefined,\n\timpact: string[] | undefined,\n): string {\n\tconst canonical = JSON.stringify([kind, content, rationale ?? null, impact ?? null]);\n\treturn createHash(\"sha256\").update(canonical, \"utf8\").digest(\"hex\");\n}\n\nfunction nonEmptyString(value: unknown, name: string, max: number): string {\n\tif (typeof value !== \"string\" || value.trim() === \"\") {\n\t\tthrow new AlignmentError(\"invalid-input\", `${name} must be a non-empty string`);\n\t}\n\tif (value.length > max) {\n\t\tthrow new AlignmentError(\"invalid-input\", `${name} exceeds ${max} characters`);\n\t}\n\treturn value;\n}\n\nfunction validateBlockInput(input: BlockInput): void {\n\tif (typeof input.id !== \"string\" || input.id.trim() === \"\" || input.id.length > 128) {\n\t\tthrow new AlignmentError(\n\t\t\t\"invalid-block\",\n\t\t\t`block id must be a non-empty string (≤128 chars): ${String(input.id)}`,\n\t\t);\n\t}\n\tif (![\"fact\", \"assumption\", \"decision\", \"missing\", \"visual\"].includes(input.kind)) {\n\t\tthrow new AlignmentError(\"invalid-block\", `invalid block kind: ${String(input.kind)}`);\n\t}\n\tnonEmptyString(input.content, `block ${input.id} content`, ALIGNMENT_LIMITS.contentMaxLength);\n\tif (input.rationale !== undefined && input.rationale.length > ALIGNMENT_LIMITS.rationaleMaxLength) {\n\t\tthrow new AlignmentError(\n\t\t\t\"invalid-block\",\n\t\t\t`block ${input.id} rationale exceeds ${ALIGNMENT_LIMITS.rationaleMaxLength} characters`,\n\t\t);\n\t}\n\tif (input.impact?.some((item) => typeof item !== \"string\" || item.trim() === \"\")) {\n\t\tthrow new AlignmentError(\"invalid-block\", `block ${input.id} impact must be a non-empty string array`);\n\t}\n\tif ((input.comments?.length ?? 0) > ALIGNMENT_LIMITS.notesPerBlockMax) {\n\t\tthrow new AlignmentError(\n\t\t\t\"invalid-block\",\n\t\t\t`block ${input.id} carries more than ${ALIGNMENT_LIMITS.notesPerBlockMax} comments`,\n\t\t);\n\t}\n\tfor (const comment of input.comments ?? []) {\n\t\tif (typeof comment.id !== \"string\" || comment.id.trim() === \"\") {\n\t\t\tthrow new AlignmentError(\"invalid-comment\", `comment id on block ${input.id} must be a non-empty string`);\n\t\t}\n\t\tnonEmptyString(comment.note, `comment ${comment.id} note`, ALIGNMENT_LIMITS.noteMaxLength);\n\t}\n}\n\n// ---------------------------------------------------------------------------\n// State helpers\n// ---------------------------------------------------------------------------\n\nexport function findRecord(state: AlignmentState, id: string): AlignmentRecord | undefined {\n\treturn state.alignments.find((record) => record.id === id);\n}\n\nexport function activeStep(record: AlignmentRecord): AlignmentStepState {\n\tconst found = record.steps.find((candidate) => candidate.step === record.activeStep);\n\tif (!found) throw new AlignmentError(\"invalid-input\", `active step missing: ${record.activeStep}`);\n\treturn found;\n}\n\n/**\n * Gate facts (总则 2): the three server-checkable conditions. A missing block\n * without a stored user answer counts as `missing-empty`; once answered it is\n * just an unapproved block waiting for the model to restructure it.\n */\nexport function gate(record: AlignmentRecord): GateSnapshot {\n\tconst step = activeStep(record);\n\tconst pending: PendingItem[] = [];\n\tlet unapproved = 0;\n\tfor (const block of step.blocks) {\n\t\tif (block.kind === \"missing\" && (block.draftAnswer ?? \"\").trim() === \"\") {\n\t\t\tpending.push({ blockId: block.id, reason: \"missing-empty\" });\n\t\t\tunapproved += 1;\n\t\t\tcontinue;\n\t\t}\n\t\tif (block.status !== \"approved\") {\n\t\t\tpending.push({ blockId: block.id, reason: \"unapproved\" });\n\t\t\tunapproved += 1;\n\t\t}\n\t}\n\tlet openComments = 0;\n\tfor (const block of step.blocks) {\n\t\tfor (const comment of block.comments) {\n\t\t\tif (comment.status !== \"open\") continue;\n\t\t\topenComments += 1;\n\t\t\tif (comment.author === \"assistant\") {\n\t\t\t\tpending.push({ blockId: block.id, reason: \"assistant-question-open\" });\n\t\t\t}\n\t\t}\n\t}\n\tconst pendingAdditions = record.pendingFeedback?.additions.length ?? 0;\n\treturn {\n\t\tunapproved,\n\t\topenComments,\n\t\tpendingAdditions,\n\t\tallGreen: unapproved === 0 && openComments === 0 && pendingAdditions === 0,\n\t\tpending,\n\t};\n}\n\nfunction nextStep(step: AlignmentStepId): AlignmentStepId | undefined {\n\tconst index = STEP_ORDER.indexOf(step);\n\treturn index >= 0 && index < STEP_ORDER.length - 1 ? STEP_ORDER[index + 1] : undefined;\n}\n\n// ---------------------------------------------------------------------------\n// alignment_set: create / update (总则 3 hash inheritance, 总则 5 comment merge)\n// ---------------------------------------------------------------------------\n\nfunction materializeBlock(\n\tinput: BlockInput,\n\tprevious: AlignmentBlock | undefined,\n\tcurrentRound: number,\n): AlignmentBlock {\n\tconst fingerprint = blockFingerprint(input.kind, input.content, input.rationale, input.impact);\n\tconst unchanged = previous !== undefined && previous.contentHash === fingerprint;\n\tconst block: AlignmentBlock = {\n\t\tid: input.id,\n\t\tkind: input.kind,\n\t\tcontent: input.content,\n\t\trationale: input.rationale,\n\t\timpact: input.impact,\n\t\t// Hash-identical resent blocks keep their approval (防确认疲劳); changed\n\t\t// content resets to pending and flags the round it changed in.\n\t\tstatus: unchanged ? previous.status : \"pending\",\n\t\tcontentHash: fingerprint,\n\t\t...(unchanged ? {} : { modifiedInRound: currentRound + 1 }),\n\t\t...(previous?.draftAnswer !== undefined ? { draftAnswer: previous.draftAnswer } : {}),\n\t\tcomments: [],\n\t};\n\tblock.comments = mergeComments(previous?.comments ?? [], input, currentRound);\n\treturn block;\n}\n\nfunction mergeComments(existing: AlignmentComment[], input: BlockInput, round: number): AlignmentComment[] {\n\tconst merged: AlignmentComment[] = existing.map((comment) => ({ ...comment }));\n\tconst resolutions = new Map((input.commentResolutions ?? []).map((item) => [item.commentId, item]));\n\t// Existing comments are append-only (总则 5): user text survives resends\n\t// verbatim, open assistant questions cannot silently disappear; only an\n\t// explicit resolution closes them.\n\tfor (const comment of merged) {\n\t\tconst resolution = resolutions.get(comment.id);\n\t\tif (!resolution) continue;\n\t\tresolutions.delete(comment.id);\n\t\tif (comment.status === \"resolved\") {\n\t\t\tthrow new AlignmentError(\"comment-ownership\", `comment ${comment.id} is already resolved`);\n\t\t}\n\t\tcomment.status = \"resolved\";\n\t\tcomment.resolution = { kind: resolution.kind, text: resolution.text, round };\n\t}\n\tif (resolutions.size > 0) {\n\t\tconst ids = [...resolutions.keys()].join(\", \");\n\t\tthrow new AlignmentError(\"comment-ownership\", `resolutions reference unknown comments: ${ids}`);\n\t}\n\t// New comments are assistant-only and deduped by note so a resent open\n\t// question never duplicates itself.\n\tfor (const fresh of input.comments ?? []) {\n\t\tif (merged.some((comment) => comment.author === \"assistant\" && comment.note === fresh.note)) continue;\n\t\tmerged.push({\n\t\t\tid: fresh.id,\n\t\t\tauthor: \"assistant\",\n\t\t\t...(fresh.quote !== undefined ? { quote: fresh.quote } : {}),\n\t\t\tnote: fresh.note,\n\t\t\tstatus: \"open\",\n\t\t\tcreatedAtRound: round,\n\t\t});\n\t}\n\treturn merged;\n}\n\nexport function applyAlignmentSet(state: AlignmentState, input: AlignmentSetInput): EngineRun {\n\tif (!validAlignmentId(input.id)) {\n\t\tthrow new AlignmentError(\n\t\t\t\"invalid-id\",\n\t\t\t`alignment id must match [A-Za-z0-9][A-Za-z0-9._-]* (no leading dot): ${input.id}`,\n\t\t);\n\t}\n\tif (!Array.isArray(input.blocks) || input.blocks.length === 0) {\n\t\tthrow new AlignmentError(\"invalid-input\", \"blocks must be a non-empty array\");\n\t}\n\tif (input.blocks.length > ALIGNMENT_LIMITS.blocksPerStepMax) {\n\t\tthrow new AlignmentError(\"invalid-input\", `a step may carry at most ${ALIGNMENT_LIMITS.blocksPerStepMax} blocks`);\n\t}\n\tconst seen = new Set<string>();\n\tfor (const block of input.blocks) {\n\t\tvalidateBlockInput(block);\n\t\tif (seen.has(block.id)) {\n\t\t\tthrow new AlignmentError(\"invalid-block\", `duplicate block id within the step: ${block.id}`);\n\t\t}\n\t\tseen.add(block.id);\n\t}\n\n\tconst existing = findRecord(state, input.id);\n\tif (!existing) {\n\t\t// Create: created-as-aligning (no draft state) and single-active (总则 9).\n\t\tconst active = state.alignments.find((record) => record.status === \"aligning\" || record.status === \"finalizing\");\n\t\tif (active) {\n\t\t\tthrow new AlignmentError(\n\t\t\t\t\"active-alignment-exists\",\n\t\t\t\t`an alignment is already in progress: ${active.id}; complete or cancel it first`,\n\t\t\t);\n\t\t}\n\t\tconst record: AlignmentRecord = {\n\t\t\tid: input.id,\n\t\t\ttitle: input.title ?? input.id,\n\t\t\t...(input.goalId !== undefined ? { goalId: input.goalId } : {}),\n\t\t\tstatus: \"aligning\",\n\t\t\trevision: 0,\n\t\t\tactiveStep: \"objective\",\n\t\t\tsteps: [\n\t\t\t\t{\n\t\t\t\t\tstep: \"objective\",\n\t\t\t\t\tstatus: \"active\",\n\t\t\t\t\tblocks: input.blocks.map((block) => materializeBlock(block, undefined, 0)),\n\t\t\t\t},\n\t\t\t\t{ step: \"detail\", status: \"pending\", blocks: [] },\n\t\t\t\t{ step: \"design\", status: \"pending\", blocks: [] },\n\t\t\t],\n\t\t\troundCount: 0,\n\t\t};\n\t\treturn { state: { alignments: [...state.alignments, record] }, transitions: [] };\n\t}\n\n\tif (existing.status !== \"aligning\") {\n\t\tthrow new AlignmentError(\"terminal-state\", `alignment is terminal and cannot be updated: ${input.id}`);\n\t}\n\tconst revision = input.revision ?? 0;\n\tif (revision <= existing.revision) {\n\t\tthrow new AlignmentError(\n\t\t\t\"stale-revision\",\n\t\t\t`stale alignment revision: ${input.id} expects > ${existing.revision}, got ${revision}`,\n\t\t);\n\t}\n\tconst step = activeStep(existing);\n\tif (step.status !== \"active\" && step.status !== \"reset\") {\n\t\tthrow new AlignmentError(\n\t\t\t\"step-not-writable\",\n\t\t\t`step ${existing.activeStep} is ${step.status}; only the active step accepts blocks`,\n\t\t);\n\t}\n\t// Deleting a block that still carries open comments is rejected (总则 3):\n\t// deletion must not become a way to dodge unresolved objections.\n\tfor (const previous of step.blocks) {\n\t\tif (input.blocks.some((block) => block.id === previous.id)) continue;\n\t\tif (previous.comments.some((comment) => comment.status === \"open\")) {\n\t\t\tthrow new AlignmentError(\n\t\t\t\t\"block-has-open-comments\",\n\t\t\t\t`block ${previous.id} carries open comments; resolve them before deleting it (edit the content instead)`,\n\t\t\t);\n\t\t}\n\t}\n\t// 已批准块写入防护(v3.7,2026-10-08 dogfood 根因):全量重写会按内容指纹\n\t// 把已确认块静默重置 pending——未显式确认时结构化拒绝,列出将被重置的块。\n\tif (!input.reviseApproved) {\n\t\tconst conflicts = input.blocks\n\t\t\t.filter((blockInput) => {\n\t\t\t\tconst previous = step.blocks.find((candidate) => candidate.id === blockInput.id);\n\t\t\t\treturn (\n\t\t\t\t\tprevious?.status === \"approved\" &&\n\t\t\t\t\tprevious.contentHash !==\n\t\t\t\t\t\tblockFingerprint(blockInput.kind, blockInput.content, blockInput.rationale, blockInput.impact)\n\t\t\t\t);\n\t\t\t})\n\t\t\t.map((blockInput) => blockInput.id);\n\t\tif (conflicts.length > 0) {\n\t\t\tthrow new AlignmentError(\n\t\t\t\t\"approved-blocks-conflict\",\n\t\t\t\t`this write would reset approved blocks to pending: ${conflicts.join(\", \")}; resubmit with reviseApproved: true, or keep the approved block content unchanged`,\n\t\t\t);\n\t\t}\n\t}\n\tconst blocks = input.blocks.map((blockInput) => {\n\t\tconst previous = step.blocks.find((candidate) => candidate.id === blockInput.id);\n\t\treturn materializeBlock(blockInput, previous, existing.roundCount);\n\t});\n\t// Version snapshot (走查 2026-10-03): archive the outgoing step block set\n\t// before it is replaced. Append-only, bounded rolling; the page views\n\t// historical versions read-only — only the latest accepts interaction.\n\t// An empty outgoing set has nothing to roll back to — skip it, otherwise\n\t// the version bar fills with chips that render a blank view.\n\tconst archive = JSON.stringify(step.blocks);\n\tconst snapshot: AlignmentVersionSnapshot = {\n\t\trevision: existing.revision,\n\t\tround: existing.roundCount,\n\t\tstep: existing.activeStep,\n\t\tblocks: archive.length <= ALIGNMENT_LIMITS.versionsSnapshotMaxBytes ? structuredClone(step.blocks) : [],\n\t\t...(archive.length > ALIGNMENT_LIMITS.versionsSnapshotMaxBytes ? { truncated: true as const } : {}),\n\t};\n\tconst priorVersions = (\n\t\tstep.blocks.length === 0 ? (existing.versions ?? []) : [...(existing.versions ?? []), snapshot]\n\t).slice(-ALIGNMENT_LIMITS.versionsMax);\n\tconst updated: AlignmentRecord = {\n\t\t...existing,\n\t\ttitle: input.title ?? existing.title,\n\t\tgoalId: input.goalId ?? existing.goalId,\n\t\trevision,\n\t\tsteps: existing.steps.map((candidate) =>\n\t\t\tcandidate.step === existing.activeStep ? { ...candidate, blocks } : candidate,\n\t\t),\n\t\tpendingFeedback: undefined,\n\t\tversions: priorVersions,\n\t};\n\treturn {\n\t\tstate: { alignments: state.alignments.map((record) => (record.id === updated.id ? updated : record)) },\n\t\ttransitions: [],\n\t};\n}\n\n// ---------------------------------------------------------------------------\n// POST /round: the user feedback round (§5 round flow, v3.2 audits)\n// ---------------------------------------------------------------------------\n\nexport function applyRoundPost(record0: AlignmentRecord, post: AlignmentRoundPost): RoundPostOutcome {\n\tif (record0.status !== \"aligning\" && record0.status !== \"finalizing\") {\n\t\tthrow new AlignmentError(\"terminal-state\", `alignment is terminal: ${record0.id}`);\n\t}\n\t// Anti-staleness gate (terminal audit D6): the page must confirm against\n\t// the exact state it rendered.\n\tif (post.baseRevision !== record0.revision) {\n\t\tthrow new AlignmentError(\n\t\t\t\"stale-state\",\n\t\t\t`page snapshot is stale (base ${post.baseRevision}, current ${record0.revision}); reload and resubmit`,\n\t\t);\n\t}\n\tconst hasNewFeedback = post.comments.length > 0 || post.additions.length > 0 || post.answers.length > 0;\n\tif (post.stepConfirmed && hasNewFeedback) {\n\t\tthrow new AlignmentError(\n\t\t\t\"confirmed-with-feedback\",\n\t\t\t\"step confirmation cannot carry new comments/additions/answers; submit the feedback first\",\n\t\t);\n\t}\n\t// 终审阶段唯一合法提交是终审确认(走查 2026-10-03)。此时所有步已锁定,\n\t// 反馈字段没有落点——尤其 approvals 镜像会把已锁定的 design 块整体重置为\n\t// pending,再被无门禁的终审分支带进 completed。显式拒绝,不做静默重置。\n\tif (\n\t\trecord0.status === \"finalizing\" &&\n\t\t(hasNewFeedback || post.commentReplies.length > 0 || post.approvals.length > 0 || !post.stepConfirmed)\n\t) {\n\t\tthrow new AlignmentError(\n\t\t\t\"invalid-input\",\n\t\t\t\"finalizing accepts only the final confirm (stepConfirmed without feedback fields)\",\n\t\t);\n\t}\n\n\tconst record: AlignmentRecord = structuredClone(record0);\n\tconst step = record.steps.find((candidate) => candidate.step === record.activeStep);\n\tif (!step) throw new AlignmentError(\"invalid-input\", \"active step missing\");\n\tconst blockById = new Map(step.blocks.map((block) => [block.id, block]));\n\tconst round = record.roundCount + 1;\n\n\t// New user comments: the quote must match the block's current content.\n\tfor (const comment of post.comments) {\n\t\tconst block = blockById.get(comment.blockId);\n\t\tif (!block) {\n\t\t\tthrow new AlignmentError(\"invalid-input\", `comment targets unknown block: ${comment.blockId}`);\n\t\t}\n\t\tconst note = nonEmptyString(comment.note, \"comment note\", ALIGNMENT_LIMITS.noteMaxLength);\n\t\tif (typeof comment.quote !== \"string\" || !block.content.includes(comment.quote)) {\n\t\t\tthrow new AlignmentError(\n\t\t\t\t\"comment-quote-mismatch\",\n\t\t\t\t`comment quote does not match block ${comment.blockId} content`,\n\t\t\t);\n\t\t}\n\t\tblock.comments.push({\n\t\t\tid: `c${round}-${block.comments.length + 1}`,\n\t\t\tauthor: \"user\",\n\t\t\tquote: comment.quote,\n\t\t\tnote,\n\t\t\t...(comment.escalate === true ? { escalate: true } : {}),\n\t\t\tstatus: \"open\",\n\t\t\tcreatedAtRound: round,\n\t\t});\n\t}\n\n\t// Replies to assistant comments (answer/dismiss are mutually exclusive).\n\tfor (const reply of post.commentReplies) {\n\t\tconst block = blockById.get(reply.blockId);\n\t\tconst comment = block?.comments.find((candidate) => candidate.id === reply.commentId);\n\t\tif (!comment || comment.author !== \"assistant\") {\n\t\t\tthrow new AlignmentError(\n\t\t\t\t\"invalid-input\",\n\t\t\t\t`reply targets unknown or non-assistant comment: ${reply.commentId}`,\n\t\t\t);\n\t\t}\n\t\tif (comment.status !== \"open\") continue; // idempotent resubmission\n\t\tif ((reply.answer !== undefined) === (reply.dismiss === true)) {\n\t\t\tthrow new AlignmentError(\n\t\t\t\t\"invalid-input\",\n\t\t\t\t`reply must carry exactly one of answer or dismiss: ${reply.commentId}`,\n\t\t\t);\n\t\t}\n\t\tcomment.status = \"resolved\";\n\t\tcomment.resolution = reply.dismiss\n\t\t\t? { kind: \"dismissed\", text: \"user marked unimportant\", round }\n\t\t\t: {\n\t\t\t\t\tkind: \"answered\",\n\t\t\t\t\ttext: nonEmptyString(reply.answer ?? \"\", \"reply answer\", ALIGNMENT_LIMITS.answerMaxLength),\n\t\t\t\t\tround,\n\t\t\t\t};\n\t}\n\n\t// Fill-in answers for missing blocks: stored verbatim as the user's words;\n\t// the model restructures them into the block on its next alignment_set.\n\tfor (const answer of post.answers) {\n\t\tconst block = blockById.get(answer.blockId);\n\t\tif (!block || block.kind !== \"missing\") {\n\t\t\tthrow new AlignmentError(\"invalid-input\", `answer targets unknown or non-missing block: ${answer.blockId}`);\n\t\t}\n\t\tif ((block.draftAnswer ?? \"\").trim() !== \"\") continue; // idempotent resubmission\n\t\tblock.draftAnswer = nonEmptyString(answer.value, \"answer\", ALIGNMENT_LIMITS.answerMaxLength);\n\t}\n\n\t// Approvals mirror the page's full approved set for the active step.\n\t// Skipped in finalizing (走查 2026-10-03): the step is locked and the\n\t// final confirm carries approvals=[] — mirroring would reopen its blocks.\n\tif (record0.status !== \"finalizing\") {\n\t\tconst approvalSet = new Set(post.approvals);\n\t\tfor (const id of approvalSet) {\n\t\t\tif (!blockById.has(id)) {\n\t\t\t\tthrow new AlignmentError(\"invalid-input\", `approval references unknown block: ${id}`);\n\t\t\t}\n\t\t}\n\t\tfor (const block of step.blocks) {\n\t\t\tblock.status = approvalSet.has(block.id) ? \"approved\" : \"pending\";\n\t\t}\n\t}\n\n\t// Additions queue as pendingFeedback — the server-side truth of gate\n\t// condition three (terminal audit D7); cleared by the next alignment_set.\n\tconst additions = [...(record.pendingFeedback?.additions ?? [])];\n\tfor (const addition of post.additions) {\n\t\tadditions.push(nonEmptyString(addition, \"addition\", ALIGNMENT_LIMITS.additionMaxLength));\n\t}\n\trecord.pendingFeedback = additions.length > 0 ? { round, additions } : undefined;\n\n\tconst transitions: AlignmentTransitionEntry[] = [\n\t\t{\n\t\t\talignmentId: record.id,\n\t\t\tstep: record.activeStep,\n\t\t\tevent: \"round.submitted\",\n\t\t\tround,\n\t\t\treason: {\n\t\t\t\tcode: \"round-submitted\",\n\t\t\t\tdetail: `approvals=${post.approvals.length} comments=${post.comments.length} replies=${post.commentReplies.length} answers=${post.answers.length} additions=${post.additions.length}`,\n\t\t\t},\n\t\t\trevision: record.revision,\n\t\t},\n\t];\n\trecord.roundCount = round;\n\n\tlet stepConfirmedNow = false;\n\tif (post.stepConfirmed && record0.status === \"finalizing\") {\n\t\t// 终审总览确认(走查 2026-10-03): the user reviewed the full plan and\n\t\t// confirmed it — the only path to `completed` + baseline write.\n\t\trecord.status = \"completed\";\n\t\trecord.revision += 1;\n\t\tfor (const locked of record.steps) locked.baselineConfirmedAtRound ??= record.roundCount;\n\t\ttransitions.push({\n\t\t\talignmentId: record.id,\n\t\t\tevent: \"alignment.completed\",\n\t\t\treason: { code: \"final-review-approved\", detail: \"final review confirmed the complete plan\" },\n\t\t\trevision: record.revision,\n\t\t});\n\t\tconst result: AlignmentRoundResult = {\n\t\t\talignmentId: record.id,\n\t\t\tround: record.roundCount,\n\t\t\tstep: record.activeStep,\n\t\t\trevision: record.revision,\n\t\t\tapprovals: post.approvals,\n\t\t\tcomments: post.comments,\n\t\t\tcommentReplies: post.commentReplies,\n\t\t\tanswers: post.answers,\n\t\t\tadditions: post.additions,\n\t\t\tstepConfirmed: true,\n\t\t};\n\t\treturn { record, transitions, result };\n\t}\n\tif (post.stepConfirmed) {\n\t\tconst snapshot = gate(record);\n\t\tif (!snapshot.allGreen) {\n\t\t\tthrow new AlignmentError(\n\t\t\t\t\"gate-not-satisfied\",\n\t\t\t\t`gate not satisfied: ${snapshot.unapproved} unapproved blocks, ${snapshot.openComments} open comments, ${snapshot.pendingAdditions} pending additions`,\n\t\t\t);\n\t\t}\n\t\tstep.status = \"locked\";\n\t\tstep.baselineConfirmedAtRound = round;\n\t\trecord.revision += 1;\n\t\ttransitions.push({\n\t\t\talignmentId: record.id,\n\t\t\tstep: record.activeStep,\n\t\t\tevent: \"step.confirmed\",\n\t\t\tround,\n\t\t\treason: { code: \"step-baseline-locked\", detail: `${step.blocks.length} blocks frozen` },\n\t\t\trevision: record.revision,\n\t\t});\n\t\tconst upcoming = nextStep(record.activeStep);\n\t\tif (upcoming) {\n\t\t\trecord.activeStep = upcoming;\n\t\t\tconst upcomingStep = record.steps.find((candidate) => candidate.step === upcoming);\n\t\t\tif (upcomingStep) upcomingStep.status = \"active\";\n\t\t\trecord.revision += 1;\n\t\t} else {\n\t\t\t// Design locked (方案确认): enter the final-review overview instead\n\t\t\t// of completing (走查 2026-10-03) — the baseline is written only\n\t\t\t// after the user confirms the full plan on the 终审 tab.\n\t\t\trecord.status = \"finalizing\";\n\t\t\trecord.revision += 1;\n\t\t\ttransitions.push({\n\t\t\t\talignmentId: record.id,\n\t\t\t\tevent: \"design.locked\",\n\t\t\t\tround,\n\t\t\t\treason: {\n\t\t\t\t\tcode: \"scheme-locked-awaiting-final-review\",\n\t\t\t\t\tdetail: \"all three baselines locked; awaiting final review\",\n\t\t\t\t},\n\t\t\t\trevision: record.revision,\n\t\t\t});\n\t\t}\n\t\tstepConfirmedNow = true;\n\t}\n\n\tconst result: AlignmentRoundResult = {\n\t\talignmentId: record.id,\n\t\tround,\n\t\tstep: record0.activeStep,\n\t\trevision: record.revision,\n\t\tapprovals: post.approvals,\n\t\tcomments: post.comments,\n\t\tcommentReplies: post.commentReplies,\n\t\tanswers: post.answers,\n\t\tadditions: post.additions,\n\t\tstepConfirmed: stepConfirmedNow,\n\t};\n\treturn { record, transitions, result };\n}\n\n/** Injection succeeded — the delivered transition closes the round (terminal audit D1). */\nexport function markDelivered(record: AlignmentRecord, round: number): AlignmentTransitionEntry[] {\n\treturn [\n\t\t{\n\t\t\talignmentId: record.id,\n\t\t\tevent: \"round.delivered\",\n\t\t\tround,\n\t\t\treason: { code: \"round-delivered\", detail: \"feedback injected into the session\" },\n\t\t\trevision: record.revision,\n\t\t},\n\t];\n}\n\n// ---------------------------------------------------------------------------\n// alignment_advance: inspect / retreat / cancel (总则 6)\n// ---------------------------------------------------------------------------\n\nexport function applyAlignmentAdvance(state: AlignmentState, input: AdvanceInput): AdvanceOutcome {\n\tconst record = findRecord(state, input.alignmentId);\n\tif (!record) {\n\t\tthrow new AlignmentError(\"not-found\", `unknown alignment: ${input.alignmentId}`);\n\t}\n\tif (input.action === \"inspect\") return { state, transitions: [] };\n\tif (input.action === \"rollback\") {\n\t\t// Rollback is routed through applyVersionRollback (设计 §6); refusing\n\t\t// here keeps the advance branch from ever treating it as a retreat.\n\t\tthrow new AlignmentError(\"invalid-input\", \"rollback routes through applyVersionRollback, not advance\");\n\t}\n\tif (record.status === \"completed\" || record.status === \"cancelled\") {\n\t\tthrow new AlignmentError(\"terminal-state\", `alignment is terminal: ${record.id}`);\n\t}\n\n\tif (input.action === \"cancel\") {\n\t\tconst cancelled: AlignmentRecord = { ...record, status: \"cancelled\" };\n\t\treturn {\n\t\t\tstate: { alignments: state.alignments.map((item) => (item.id === record.id ? cancelled : item)) },\n\t\t\ttransitions: [\n\t\t\t\t{\n\t\t\t\t\talignmentId: record.id,\n\t\t\t\t\tevent: \"alignment.cancelled\",\n\t\t\t\t\treason: { code: \"alignment-cancelled\" },\n\t\t\t\t\trevision: record.revision,\n\t\t\t\t},\n\t\t\t],\n\t\t};\n\t}\n\n\t// retreat: comments survive the reset append-only (terminal audit D5); the\n\t// escalate comments that triggered it are resolved here with the note.\n\tconst note = nonEmptyString(input.note ?? \"\", \"retreat note\", ALIGNMENT_LIMITS.noteMaxLength);\n\tconst target = input.step;\n\tif (!target || STEP_ORDER.indexOf(target) >= STEP_ORDER.indexOf(record.activeStep)) {\n\t\tthrow new AlignmentError(\n\t\t\t\"retreat-target-invalid\",\n\t\t\t`retreat target must be an earlier step than ${record.activeStep}`,\n\t\t);\n\t}\n\tconst affected: string[] = [];\n\tconst retreated: AlignmentRecord = { ...record, steps: record.steps.map((step) => ({ ...step })) };\n\tfor (const step of retreated.steps) {\n\t\tif (STEP_ORDER.indexOf(step.step) < STEP_ORDER.indexOf(target)) continue;\n\t\taffected.push(step.step);\n\t\tstep.status = \"reset\";\n\t\tstep.baselineConfirmedAtRound = undefined;\n\t\tfor (const block of step.blocks) {\n\t\t\tblock.status = \"pending\";\n\t\t\tfor (const comment of block.comments) {\n\t\t\t\tif (comment.status === \"open\" && comment.author === \"user\" && comment.escalate === true) {\n\t\t\t\t\tcomment.status = \"resolved\";\n\t\t\t\t\tcomment.resolution = { kind: \"incorporated\", text: note, round: record.roundCount };\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\tretreated.activeStep = target;\n\t// Finalizing → retreated: the final-review state is gone with the\n\t// downstream resets; the task is writable at the target step again.\n\tif (retreated.status === \"finalizing\") retreated.status = \"aligning\";\n\tretreated.revision += 1;\n\treturn {\n\t\tstate: { alignments: state.alignments.map((item) => (item.id === record.id ? retreated : item)) },\n\t\ttransitions: [\n\t\t\t{\n\t\t\t\talignmentId: record.id,\n\t\t\t\tevent: \"step.retreated\",\n\t\t\t\treason: {\n\t\t\t\t\tcode: \"step-retreated\",\n\t\t\t\t\tdetail: `target=${target}; reset=${affected.join(\",\")}; note=${note}`,\n\t\t\t\t},\n\t\t\t\trevision: retreated.revision,\n\t\t\t},\n\t\t],\n\t};\n}\n\nexport interface VersionRollbackInput {\n\talignmentId: string;\n\t/** Target snapshot revision from `record.versions` (must be the active step's). */\n\ttargetRevision: number;\n}\n\n/**\n * Step-scoped version rollback (走查 2026-10-03): drop the current unconfirmed\n * version (not archived), promote the target snapshot to live, engine-bump the\n * revision (D4). Comments survive append-only — restored blocks carry the union\n * of live and archived comments by comment id, live status winning (a\n * resolution is irreversible). Only the active (unlocked) step accepts it;\n * locked steps go through retreat. Other steps are never touched.\n */\nexport function applyVersionRollback(state: AlignmentState, input: VersionRollbackInput): EngineRun {\n\tconst record = findRecord(state, input.alignmentId);\n\tif (!record) {\n\t\tthrow new AlignmentError(\"not-found\", `unknown alignment: ${input.alignmentId}`);\n\t}\n\tif (record.status !== \"aligning\") {\n\t\tthrow new AlignmentError(\"terminal-state\", `version rollback needs an aligning task: ${record.id}`);\n\t}\n\tconst step = activeStep(record);\n\tif (step.status !== \"active\" && step.status !== \"reset\") {\n\t\tthrow new AlignmentError(\n\t\t\t\"step-not-writable\",\n\t\t\t`step ${record.activeStep} is ${step.status}; locked steps go through retreat`,\n\t\t);\n\t}\n\tconst versions = [...(record.versions ?? [])];\n\tconst index = versions.findIndex(\n\t\t(snapshot) => snapshot.revision === input.targetRevision && snapshot.step === record.activeStep,\n\t);\n\tif (index < 0) {\n\t\tthrow new AlignmentError(\n\t\t\t\"invalid-input\",\n\t\t\t`no snapshot of step ${record.activeStep} at revision ${input.targetRevision}`,\n\t\t);\n\t}\n\tconst snapshot = versions[index];\n\tif (snapshot.truncated) {\n\t\tthrow new AlignmentError(\n\t\t\t\"invalid-input\",\n\t\t\t`snapshot r${input.targetRevision} exceeded the size budget and has no blocks`,\n\t\t);\n\t}\n\tconst liveById = new Map(step.blocks.map((block) => [block.id, block]));\n\tconst restored = snapshot.blocks.map((archived) => {\n\t\tconst live = liveById.get(archived.id);\n\t\tif (!live) return structuredClone(archived);\n\t\tconst merged = new Map(archived.comments.map((comment) => [comment.id, comment]));\n\t\tfor (const comment of live.comments) merged.set(comment.id, comment); // live status wins\n\t\treturn { ...structuredClone(archived), comments: [...merged.values()] };\n\t});\n\t// The current version is dropped, the target is promoted: remove it from\n\t// the archive rather than re-archiving the live set.\n\tversions.splice(index, 1);\n\tconst rolled: AlignmentRecord = {\n\t\t...record,\n\t\trevision: record.revision + 1,\n\t\tsteps: record.steps.map((candidate) =>\n\t\t\tcandidate.step === record.activeStep\n\t\t\t\t? { ...candidate, blocks: restored, status: candidate.status === \"locked\" ? \"reset\" : candidate.status }\n\t\t\t\t: candidate,\n\t\t),\n\t\tversions,\n\t};\n\treturn {\n\t\tstate: { alignments: state.alignments.map((item) => (item.id === rolled.id ? rolled : item)) },\n\t\ttransitions: [\n\t\t\t{\n\t\t\t\talignmentId: rolled.id,\n\t\t\t\tstep: rolled.activeStep,\n\t\t\t\tevent: \"version.rolled-back\",\n\t\t\t\treason: { code: \"version-rolled-back\", detail: `target=r${input.targetRevision}` },\n\t\t\t\trevision: rolled.revision,\n\t\t\t},\n\t\t],\n\t};\n}\n\n/** Compact final baseline listing (§5 round flow 4): one line per block, answers first. */\nexport function finalBaselineLines(\n\trecord: AlignmentRecord,\n): { step: AlignmentStepId; kind: AlignmentBlockKind; id: string; line: string }[] | undefined {\n\tif (record.status !== \"completed\") return undefined;\n\tconst lines: { step: AlignmentStepId; kind: AlignmentBlockKind; id: string; line: string }[] = [];\n\tfor (const step of record.steps) {\n\t\tfor (const block of step.blocks) {\n\t\t\tconst confirmed = block.content.split(\"\\n\").find((line) => line.includes(\"→ 已确认\"));\n\t\t\tconst text = (confirmed ? confirmed.replace(/^\\s*→\\s*/, \"\") : block.content.split(\"\\n\")[0]).slice(0, 120);\n\t\t\tlines.push({ step: step.step, kind: block.kind, id: block.id, line: text });\n\t\t}\n\t}\n\treturn lines;\n}\n"]}
@@ -0,0 +1,14 @@
1
+ import type { CapabilityAPI } from "@agent-forge/plugin-sdk";
2
+ /**
3
+ * Default-export factory consumed by the host's `loadCapabilityPluginFromManifest`.
4
+ *
5
+ * The capability factory returns its registrations as an array, while the
6
+ * manifest loader contract expects `void` or a single `{ dispose() }` instance
7
+ * (`normalizePluginInstance` does not accept arrays). The wrapper collects the
8
+ * registrations and disposes them in reverse order on plugin teardown — the
9
+ * same disposal semantics as the host's embedded `syncRegistrationFactory`.
10
+ */
11
+ export default function createAlignmentPluginEntry(api: CapabilityAPI): Promise<{
12
+ dispose: () => void;
13
+ }>;
14
+ //# sourceMappingURL=entry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"entry.d.ts","sourceRoot":"","sources":["../src/entry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAG7D;;;;;;;;GAQG;AACH,wBAA8B,0BAA0B,CAAC,GAAG,EAAE,aAAa,GAAG,OAAO,CAAC;IAAE,OAAO,EAAE,MAAM,IAAI,CAAA;CAAE,CAAC,CAW7G","sourcesContent":["import type { CapabilityAPI } from \"@agent-forge/plugin-sdk\";\nimport { createCapability } from \"./index.ts\";\n\n/**\n * Default-export factory consumed by the host's `loadCapabilityPluginFromManifest`.\n *\n * The capability factory returns its registrations as an array, while the\n * manifest loader contract expects `void` or a single `{ dispose() }` instance\n * (`normalizePluginInstance` does not accept arrays). The wrapper collects the\n * registrations and disposes them in reverse order on plugin teardown — the\n * same disposal semantics as the host's embedded `syncRegistrationFactory`.\n */\nexport default async function createAlignmentPluginEntry(api: CapabilityAPI): Promise<{ dispose: () => void }> {\n\tconst registrations = await createCapability(api);\n\treturn {\n\t\tdispose: () => {\n\t\t\tfor (const registration of [...registrations].reverse()) {\n\t\t\t\t// Registration disposal in the capability runtime is synchronous;\n\t\t\t\t// void consumes the declared Promise possibility of the contract.\n\t\t\t\tvoid registration.dispose();\n\t\t\t}\n\t\t},\n\t};\n}\n"]}
@@ -0,0 +1,23 @@
1
+ import { createCapability } from "./index.js";
2
+ /**
3
+ * Default-export factory consumed by the host's `loadCapabilityPluginFromManifest`.
4
+ *
5
+ * The capability factory returns its registrations as an array, while the
6
+ * manifest loader contract expects `void` or a single `{ dispose() }` instance
7
+ * (`normalizePluginInstance` does not accept arrays). The wrapper collects the
8
+ * registrations and disposes them in reverse order on plugin teardown — the
9
+ * same disposal semantics as the host's embedded `syncRegistrationFactory`.
10
+ */
11
+ export default async function createAlignmentPluginEntry(api) {
12
+ const registrations = await createCapability(api);
13
+ return {
14
+ dispose: () => {
15
+ for (const registration of [...registrations].reverse()) {
16
+ // Registration disposal in the capability runtime is synchronous;
17
+ // void consumes the declared Promise possibility of the contract.
18
+ void registration.dispose();
19
+ }
20
+ },
21
+ };
22
+ }
23
+ //# sourceMappingURL=entry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"entry.js","sourceRoot":"","sources":["../src/entry.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAE9C;;;;;;;;GAQG;AACH,MAAM,CAAC,OAAO,CAAC,KAAK,UAAU,0BAA0B,CAAC,GAAkB,EAAoC;IAC9G,MAAM,aAAa,GAAG,MAAM,gBAAgB,CAAC,GAAG,CAAC,CAAC;IAClD,OAAO;QACN,OAAO,EAAE,GAAG,EAAE,CAAC;YACd,KAAK,MAAM,YAAY,IAAI,CAAC,GAAG,aAAa,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC;gBACzD,kEAAkE;gBAClE,kEAAkE;gBAClE,KAAK,YAAY,CAAC,OAAO,EAAE,CAAC;YAC7B,CAAC;QAAA,CACD;KACD,CAAC;AAAA,CACF","sourcesContent":["import type { CapabilityAPI } from \"@agent-forge/plugin-sdk\";\nimport { createCapability } from \"./index.ts\";\n\n/**\n * Default-export factory consumed by the host's `loadCapabilityPluginFromManifest`.\n *\n * The capability factory returns its registrations as an array, while the\n * manifest loader contract expects `void` or a single `{ dispose() }` instance\n * (`normalizePluginInstance` does not accept arrays). The wrapper collects the\n * registrations and disposes them in reverse order on plugin teardown — the\n * same disposal semantics as the host's embedded `syncRegistrationFactory`.\n */\nexport default async function createAlignmentPluginEntry(api: CapabilityAPI): Promise<{ dispose: () => void }> {\n\tconst registrations = await createCapability(api);\n\treturn {\n\t\tdispose: () => {\n\t\t\tfor (const registration of [...registrations].reverse()) {\n\t\t\t\t// Registration disposal in the capability runtime is synchronous;\n\t\t\t\t// void consumes the declared Promise possibility of the contract.\n\t\t\t\tvoid registration.dispose();\n\t\t\t}\n\t\t},\n\t};\n}\n"]}
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Self-contained export (走查裁决 2026-10-03): `/alignment export` serializes
3
+ * the alignment record + audit history into a single offline HTML file. The
4
+ * plugin never writes into the user workspace on its own — this runs only on
5
+ * an explicit user command, and the machine truth stays in the session
6
+ * entries (`alignment.state`), never in this file.
7
+ */
8
+ import type { AlignmentRecord, AlignmentTransitionEntry } from "./types.ts";
9
+ export declare function renderAlignmentExport(record: AlignmentRecord, transitions: readonly AlignmentTransitionEntry[], generatedAt: Date): string;
10
+ /** Resolve the export target path (explicit path wins; default: cwd). */
11
+ export declare function exportTargetPath(cwd: string, record: AlignmentRecord, explicitPath?: string): string;
12
+ /** Write the export file; returns the absolute path written. */
13
+ export declare function writeAlignmentExport(record: AlignmentRecord, transitions: readonly AlignmentTransitionEntry[], targetPath: string, now?: Date): string;
14
+ export declare function defaultExportPath(cwd: string, record: AlignmentRecord): string;
15
+ //# sourceMappingURL=export.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"export.d.ts","sourceRoot":"","sources":["../src/export.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,OAAO,KAAK,EAAE,eAAe,EAAE,wBAAwB,EAAE,MAAM,YAAY,CAAC;AAiC5E,wBAAgB,qBAAqB,CACpC,MAAM,EAAE,eAAe,EACvB,WAAW,EAAE,SAAS,wBAAwB,EAAE,EAChD,WAAW,EAAE,IAAI,GACf,MAAM,CAsFR;AAED,yEAAyE;AACzE,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,eAAe,EAAE,YAAY,CAAC,EAAE,MAAM,GAAG,MAAM,CAKpG;AAED,gEAAgE;AAChE,wBAAgB,oBAAoB,CACnC,MAAM,EAAE,eAAe,EACvB,WAAW,EAAE,SAAS,wBAAwB,EAAE,EAChD,UAAU,EAAE,MAAM,EAClB,GAAG,GAAE,IAAiB,GACpB,MAAM,CAGR;AAED,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,eAAe,GAAG,MAAM,CAE9E","sourcesContent":["/**\n * Self-contained export (走查裁决 2026-10-03): `/alignment export` serializes\n * the alignment record + audit history into a single offline HTML file. The\n * plugin never writes into the user workspace on its own — this runs only on\n * an explicit user command, and the machine truth stays in the session\n * entries (`alignment.state`), never in this file.\n */\n\nimport { writeFileSync } from \"node:fs\";\nimport { isAbsolute, join, resolve } from \"node:path\";\nimport type { AlignmentRecord, AlignmentTransitionEntry } from \"./types.ts\";\n\nconst KIND_CN: Record<string, string> = {\n\tfact: \"取证\",\n\tassumption: \"假设\",\n\tdecision: \"决策\",\n\tmissing: \"待补充\",\n\tvisual: \"视觉\",\n};\n\nconst STEP_CN: Record<string, string> = { objective: \"目标\", detail: \"细节\", design: \"设计\" };\n\nconst STATUS_CN: Record<string, string> = {\n\taligning: \"对齐中\",\n\tfinalizing: \"待终审\",\n\tcompleted: \"已完成\",\n\tcancelled: \"已取消\",\n};\n\nfunction esc(text: string): string {\n\treturn text.replace(/&/g, \"&amp;\").replace(/</g, \"&lt;\").replace(/>/g, \"&gt;\").replace(/\"/g, \"&quot;\");\n}\n\nfunction blockHtml(block: { id: string; kind: string; content: string; rationale?: string; status: string }): string {\n\tconst badge = `<span class=\"badge ${esc(block.kind)}\">${KIND_CN[block.kind] ?? esc(block.kind)}</span>`;\n\tconst state = block.status === \"approved\" ? '<span class=\"ok\">已确认</span>' : '<span class=\"pend\">未确认</span>';\n\tconst rationale = block.rationale ? `<div class=\"why\">理由:${esc(block.rationale)}</div>` : \"\";\n\t// 导出是只读档案:内容完整保留(多行原样),不截断首行。\n\treturn `<div class=\"block\"><div class=\"top\">${badge}<span class=\"bid\">${esc(block.id)}</span>${state}</div><div class=\"content\">${esc(\n\t\tblock.content,\n\t)}</div>${rationale}</div>`;\n}\n\nexport function renderAlignmentExport(\n\trecord: AlignmentRecord,\n\ttransitions: readonly AlignmentTransitionEntry[],\n\tgeneratedAt: Date,\n): string {\n\t// 走查裁决 2026-10-03:导出全部只读,但可切换环节查看——三步 tab + 审计页。\n\tconst steps = record.steps\n\t\t.map(\n\t\t\t(step) => `<section class=\"pane\" data-pane=\"${esc(step.step)}\">\n\t\t\t<h3>${STEP_CN[step.step] ?? esc(step.step)}\n\t\t\t<span class=\"stepmeta\">${step.status === \"locked\" ? `已锁定(第 ${step.baselineConfirmedAtRound ?? \"-\"} 轮确认)` : esc(step.status)} · ${step.blocks.length} 块</span></h3>\n\t\t\t${step.blocks.map((block) => blockHtml(block)).join(\"\") || '<div class=\"empty\">该环节暂无块。</div>'}</section>`,\n\t\t)\n\t\t.join(\"\");\n\tconst history = transitions\n\t\t.slice(-40)\n\t\t.reverse()\n\t\t.map(\n\t\t\t(entry) =>\n\t\t\t\t`<li><span class=\"rev\">r${entry.round ?? \"-\"} rev${entry.revision}</span> ${esc(entry.step ?? \"\")} ${esc(\n\t\t\t\t\tentry.event,\n\t\t\t\t)} — ${esc(entry.reason.detail ?? entry.reason.code)}</li>`,\n\t\t)\n\t\t.join(\"\");\n\tconst versions = (record.versions ?? [])\n\t\t.slice()\n\t\t.reverse()\n\t\t.map(\n\t\t\t(snapshot) =>\n\t\t\t\t`<li>rev${snapshot.revision}(第 ${snapshot.round} 轮)· ${STEP_CN[snapshot.step] ?? esc(snapshot.step)} · ${\n\t\t\t\t\tsnapshot.truncated ? \"快照超限仅存锚点\" : `${snapshot.blocks.length} 块`\n\t\t\t\t}</li>`,\n\t\t)\n\t\t.join(\"\");\n\treturn `<!DOCTYPE html>\n<html lang=\"zh-CN\"><head><meta charset=\"UTF-8\"><meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n<title>需求对齐导出 · ${esc(record.title)}</title><style>\nbody{margin:0;font-family:system-ui,-apple-system,\"Segoe UI\",sans-serif;background:#f4f2fb;color:#31344d}\n.wrap{max-width:880px;margin:0 auto;padding:32px 20px 64px}\nh1{font-size:24px;margin:8px 0 4px}.meta{color:#8b8fa7;font-size:13px;margin-bottom:20px}\n.banner{border-radius:14px;padding:12px 18px;font-size:14px;margin-bottom:22px;background:linear-gradient(120deg,#eef0ff,#fdeef6);border:1px solid #e3e0f5}\nh3{font-size:15px;margin:26px 0 10px}.stepmeta{color:#8b8fa7;font-weight:400;font-size:12px;margin-left:8px}\n.block{background:#fff;border:1px solid #ecebf5;border-radius:12px;padding:12px 14px;margin-bottom:10px}\n.top{display:flex;gap:8px;align-items:center;font-size:12px}.bid{color:#8b8fa7}\n.badge{padding:2px 10px;border-radius:99px;font-size:12px}\n.badge.fact{background:#e8f5ee;color:#1d8a5e}.badge.assumption{background:#fff4e2;color:#c07a15}\n.badge.decision{background:#efedff;color:#6a4de0}.badge.missing{background:#fde9ef;color:#d4498a}\n.badge.visual{background:#e0f5f6;color:#0e7490}\n.ok{color:#1d8a5e;margin-left:auto}.pend{color:#c0c2d4;margin-left:auto}\n.content{font-size:14px;line-height:1.6;margin-top:8px}.why{font-size:12px;color:#8b8fa7;margin-top:6px}\nul{padding-left:18px;font-size:13px;color:#565a75;line-height:1.9}.rev{color:#8b8fa7;font-size:12px;margin-right:6px}\n.note{font-size:12px;color:#8b8fa7;margin-top:28px;border-top:1px solid #ecebf5;padding-top:12px}\n.etabs{display:flex;gap:8px;margin:0 0 18px;flex-wrap:wrap}\n.etab{border:1px solid #e3e0f5;background:#fff;color:#565a75;border-radius:999px;padding:7px 18px;font-size:13px;font-weight:600;cursor:pointer}\n.etab.on{background:linear-gradient(120deg,#7c6ff0,#d946ef);border-color:transparent;color:#fff;box-shadow:0 8px 20px -8px rgba(124,111,240,.55)}\n.pane h3:first-child{margin-top:0}\n.empty{color:#8b8fa7;font-size:13px;padding:8px 0}\n.content{white-space:pre-wrap}\n</style></head><body><div class=\"wrap\">\n<h1>${esc(record.title)}</h1>\n<div class=\"meta\">${esc(record.id)} · ${STATUS_CN[record.status] ?? esc(record.status)} · revision ${record.revision} · 共 ${record.roundCount} 轮 · 导出于 ${esc(\n\t\tgeneratedAt.toLocaleString(\"zh-CN\"),\n\t)}</div>\n<div class=\"banner\">本文件是需求对齐的只读导出快照;机器真值在会话 entries(alignment.state)。实施中改动任一已确认决策,须回对齐插件重新确认。</div>\n<nav class=\"etabs\">\n<button class=\"etab on\" data-tab=\"objective\">目标</button>\n<button class=\"etab\" data-tab=\"detail\">细节</button>\n<button class=\"etab\" data-tab=\"design\">设计</button>\n<button class=\"etab\" data-tab=\"audit\">审计</button>\n</nav>\n${steps}\n<section class=\"pane\" data-pane=\"audit\" style=\"display:none\">\n<h3>历史轮次(最近 40 条)</h3><ul>${history || \"<li>无</li>\"}</ul>\n<h3>历史版本</h3><ul>${versions || \"<li>无(尚无修订归档)</li>\"}</ul>\n</section>\n<div class=\"note\">由 /alignment export 生成 · agent-forge alignment plugin</div>\n</div>\n<script>\nvar etabs=document.querySelectorAll(\".etab\");\nfor(var i=0;i<etabs.length;i++){\n\tetabs[i].addEventListener(\"click\",function(){\n\t\tvar id=this.getAttribute(\"data-tab\");\n\t\tfor(var j=0;j<etabs.length;j++)etabs[j].classList.remove(\"on\");\n\t\tthis.classList.add(\"on\");\n\t\tvar panes=document.querySelectorAll(\".pane\");\n\t\tfor(var k=0;k<panes.length;k++)panes[k].style.display=panes[k].getAttribute(\"data-pane\")===id?\"\":\"none\";\n\t});\n}\n</script>\n</body></html>`;\n}\n\n/** Resolve the export target path (explicit path wins; default: cwd). */\nexport function exportTargetPath(cwd: string, record: AlignmentRecord, explicitPath?: string): string {\n\tif (explicitPath && explicitPath.trim() !== \"\") {\n\t\treturn isAbsolute(explicitPath.trim()) ? resolve(explicitPath.trim()) : resolve(cwd, explicitPath.trim());\n\t}\n\treturn resolve(cwd, `${record.id}-alignment.html`);\n}\n\n/** Write the export file; returns the absolute path written. */\nexport function writeAlignmentExport(\n\trecord: AlignmentRecord,\n\ttransitions: readonly AlignmentTransitionEntry[],\n\ttargetPath: string,\n\tnow: Date = new Date(),\n): string {\n\twriteFileSync(targetPath, renderAlignmentExport(record, transitions, now), { encoding: \"utf8\", flag: \"wx\" });\n\treturn targetPath;\n}\n\nexport function defaultExportPath(cwd: string, record: AlignmentRecord): string {\n\treturn join(cwd, `${record.id}-alignment.html`);\n}\n"]}
@@ -0,0 +1,122 @@
1
+ /**
2
+ * Self-contained export (走查裁决 2026-10-03): `/alignment export` serializes
3
+ * the alignment record + audit history into a single offline HTML file. The
4
+ * plugin never writes into the user workspace on its own — this runs only on
5
+ * an explicit user command, and the machine truth stays in the session
6
+ * entries (`alignment.state`), never in this file.
7
+ */
8
+ import { writeFileSync } from "node:fs";
9
+ import { isAbsolute, join, resolve } from "node:path";
10
+ const KIND_CN = {
11
+ fact: "取证",
12
+ assumption: "假设",
13
+ decision: "决策",
14
+ missing: "待补充",
15
+ visual: "视觉",
16
+ };
17
+ const STEP_CN = { objective: "目标", detail: "细节", design: "设计" };
18
+ const STATUS_CN = {
19
+ aligning: "对齐中",
20
+ finalizing: "待终审",
21
+ completed: "已完成",
22
+ cancelled: "已取消",
23
+ };
24
+ function esc(text) {
25
+ return text.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
26
+ }
27
+ function blockHtml(block) {
28
+ const badge = `<span class="badge ${esc(block.kind)}">${KIND_CN[block.kind] ?? esc(block.kind)}</span>`;
29
+ const state = block.status === "approved" ? '<span class="ok">已确认</span>' : '<span class="pend">未确认</span>';
30
+ const rationale = block.rationale ? `<div class="why">理由:${esc(block.rationale)}</div>` : "";
31
+ // 导出是只读档案:内容完整保留(多行原样),不截断首行。
32
+ return `<div class="block"><div class="top">${badge}<span class="bid">${esc(block.id)}</span>${state}</div><div class="content">${esc(block.content)}</div>${rationale}</div>`;
33
+ }
34
+ export function renderAlignmentExport(record, transitions, generatedAt) {
35
+ // 走查裁决 2026-10-03:导出全部只读,但可切换环节查看——三步 tab + 审计页。
36
+ const steps = record.steps
37
+ .map((step) => `<section class="pane" data-pane="${esc(step.step)}">
38
+ <h3>${STEP_CN[step.step] ?? esc(step.step)}
39
+ <span class="stepmeta">${step.status === "locked" ? `已锁定(第 ${step.baselineConfirmedAtRound ?? "-"} 轮确认)` : esc(step.status)} · ${step.blocks.length} 块</span></h3>
40
+ ${step.blocks.map((block) => blockHtml(block)).join("") || '<div class="empty">该环节暂无块。</div>'}</section>`)
41
+ .join("");
42
+ const history = transitions
43
+ .slice(-40)
44
+ .reverse()
45
+ .map((entry) => `<li><span class="rev">r${entry.round ?? "-"} rev${entry.revision}</span> ${esc(entry.step ?? "")} ${esc(entry.event)} — ${esc(entry.reason.detail ?? entry.reason.code)}</li>`)
46
+ .join("");
47
+ const versions = (record.versions ?? [])
48
+ .slice()
49
+ .reverse()
50
+ .map((snapshot) => `<li>rev${snapshot.revision}(第 ${snapshot.round} 轮)· ${STEP_CN[snapshot.step] ?? esc(snapshot.step)} · ${snapshot.truncated ? "快照超限仅存锚点" : `${snapshot.blocks.length} 块`}</li>`)
51
+ .join("");
52
+ return `<!DOCTYPE html>
53
+ <html lang="zh-CN"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0">
54
+ <title>需求对齐导出 · ${esc(record.title)}</title><style>
55
+ body{margin:0;font-family:system-ui,-apple-system,"Segoe UI",sans-serif;background:#f4f2fb;color:#31344d}
56
+ .wrap{max-width:880px;margin:0 auto;padding:32px 20px 64px}
57
+ h1{font-size:24px;margin:8px 0 4px}.meta{color:#8b8fa7;font-size:13px;margin-bottom:20px}
58
+ .banner{border-radius:14px;padding:12px 18px;font-size:14px;margin-bottom:22px;background:linear-gradient(120deg,#eef0ff,#fdeef6);border:1px solid #e3e0f5}
59
+ h3{font-size:15px;margin:26px 0 10px}.stepmeta{color:#8b8fa7;font-weight:400;font-size:12px;margin-left:8px}
60
+ .block{background:#fff;border:1px solid #ecebf5;border-radius:12px;padding:12px 14px;margin-bottom:10px}
61
+ .top{display:flex;gap:8px;align-items:center;font-size:12px}.bid{color:#8b8fa7}
62
+ .badge{padding:2px 10px;border-radius:99px;font-size:12px}
63
+ .badge.fact{background:#e8f5ee;color:#1d8a5e}.badge.assumption{background:#fff4e2;color:#c07a15}
64
+ .badge.decision{background:#efedff;color:#6a4de0}.badge.missing{background:#fde9ef;color:#d4498a}
65
+ .badge.visual{background:#e0f5f6;color:#0e7490}
66
+ .ok{color:#1d8a5e;margin-left:auto}.pend{color:#c0c2d4;margin-left:auto}
67
+ .content{font-size:14px;line-height:1.6;margin-top:8px}.why{font-size:12px;color:#8b8fa7;margin-top:6px}
68
+ ul{padding-left:18px;font-size:13px;color:#565a75;line-height:1.9}.rev{color:#8b8fa7;font-size:12px;margin-right:6px}
69
+ .note{font-size:12px;color:#8b8fa7;margin-top:28px;border-top:1px solid #ecebf5;padding-top:12px}
70
+ .etabs{display:flex;gap:8px;margin:0 0 18px;flex-wrap:wrap}
71
+ .etab{border:1px solid #e3e0f5;background:#fff;color:#565a75;border-radius:999px;padding:7px 18px;font-size:13px;font-weight:600;cursor:pointer}
72
+ .etab.on{background:linear-gradient(120deg,#7c6ff0,#d946ef);border-color:transparent;color:#fff;box-shadow:0 8px 20px -8px rgba(124,111,240,.55)}
73
+ .pane h3:first-child{margin-top:0}
74
+ .empty{color:#8b8fa7;font-size:13px;padding:8px 0}
75
+ .content{white-space:pre-wrap}
76
+ </style></head><body><div class="wrap">
77
+ <h1>${esc(record.title)}</h1>
78
+ <div class="meta">${esc(record.id)} · ${STATUS_CN[record.status] ?? esc(record.status)} · revision ${record.revision} · 共 ${record.roundCount} 轮 · 导出于 ${esc(generatedAt.toLocaleString("zh-CN"))}</div>
79
+ <div class="banner">本文件是需求对齐的只读导出快照;机器真值在会话 entries(alignment.state)。实施中改动任一已确认决策,须回对齐插件重新确认。</div>
80
+ <nav class="etabs">
81
+ <button class="etab on" data-tab="objective">目标</button>
82
+ <button class="etab" data-tab="detail">细节</button>
83
+ <button class="etab" data-tab="design">设计</button>
84
+ <button class="etab" data-tab="audit">审计</button>
85
+ </nav>
86
+ ${steps}
87
+ <section class="pane" data-pane="audit" style="display:none">
88
+ <h3>历史轮次(最近 40 条)</h3><ul>${history || "<li>无</li>"}</ul>
89
+ <h3>历史版本</h3><ul>${versions || "<li>无(尚无修订归档)</li>"}</ul>
90
+ </section>
91
+ <div class="note">由 /alignment export 生成 · agent-forge alignment plugin</div>
92
+ </div>
93
+ <script>
94
+ var etabs=document.querySelectorAll(".etab");
95
+ for(var i=0;i<etabs.length;i++){
96
+ etabs[i].addEventListener("click",function(){
97
+ var id=this.getAttribute("data-tab");
98
+ for(var j=0;j<etabs.length;j++)etabs[j].classList.remove("on");
99
+ this.classList.add("on");
100
+ var panes=document.querySelectorAll(".pane");
101
+ for(var k=0;k<panes.length;k++)panes[k].style.display=panes[k].getAttribute("data-pane")===id?"":"none";
102
+ });
103
+ }
104
+ </script>
105
+ </body></html>`;
106
+ }
107
+ /** Resolve the export target path (explicit path wins; default: cwd). */
108
+ export function exportTargetPath(cwd, record, explicitPath) {
109
+ if (explicitPath && explicitPath.trim() !== "") {
110
+ return isAbsolute(explicitPath.trim()) ? resolve(explicitPath.trim()) : resolve(cwd, explicitPath.trim());
111
+ }
112
+ return resolve(cwd, `${record.id}-alignment.html`);
113
+ }
114
+ /** Write the export file; returns the absolute path written. */
115
+ export function writeAlignmentExport(record, transitions, targetPath, now = new Date()) {
116
+ writeFileSync(targetPath, renderAlignmentExport(record, transitions, now), { encoding: "utf8", flag: "wx" });
117
+ return targetPath;
118
+ }
119
+ export function defaultExportPath(cwd, record) {
120
+ return join(cwd, `${record.id}-alignment.html`);
121
+ }
122
+ //# sourceMappingURL=export.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"export.js","sourceRoot":"","sources":["../src/export.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Self-contained export (走查裁决 2026-10-03): `/alignment export` serializes\n * the alignment record + audit history into a single offline HTML file. The\n * plugin never writes into the user workspace on its own — this runs only on\n * an explicit user command, and the machine truth stays in the session\n * entries (`alignment.state`), never in this file.\n */\n\nimport { writeFileSync } from \"node:fs\";\nimport { isAbsolute, join, resolve } from \"node:path\";\nimport type { AlignmentRecord, AlignmentTransitionEntry } from \"./types.ts\";\n\nconst KIND_CN: Record<string, string> = {\n\tfact: \"取证\",\n\tassumption: \"假设\",\n\tdecision: \"决策\",\n\tmissing: \"待补充\",\n\tvisual: \"视觉\",\n};\n\nconst STEP_CN: Record<string, string> = { objective: \"目标\", detail: \"细节\", design: \"设计\" };\n\nconst STATUS_CN: Record<string, string> = {\n\taligning: \"对齐中\",\n\tfinalizing: \"待终审\",\n\tcompleted: \"已完成\",\n\tcancelled: \"已取消\",\n};\n\nfunction esc(text: string): string {\n\treturn text.replace(/&/g, \"&amp;\").replace(/</g, \"&lt;\").replace(/>/g, \"&gt;\").replace(/\"/g, \"&quot;\");\n}\n\nfunction blockHtml(block: { id: string; kind: string; content: string; rationale?: string; status: string }): string {\n\tconst badge = `<span class=\"badge ${esc(block.kind)}\">${KIND_CN[block.kind] ?? esc(block.kind)}</span>`;\n\tconst state = block.status === \"approved\" ? '<span class=\"ok\">已确认</span>' : '<span class=\"pend\">未确认</span>';\n\tconst rationale = block.rationale ? `<div class=\"why\">理由:${esc(block.rationale)}</div>` : \"\";\n\t// 导出是只读档案:内容完整保留(多行原样),不截断首行。\n\treturn `<div class=\"block\"><div class=\"top\">${badge}<span class=\"bid\">${esc(block.id)}</span>${state}</div><div class=\"content\">${esc(\n\t\tblock.content,\n\t)}</div>${rationale}</div>`;\n}\n\nexport function renderAlignmentExport(\n\trecord: AlignmentRecord,\n\ttransitions: readonly AlignmentTransitionEntry[],\n\tgeneratedAt: Date,\n): string {\n\t// 走查裁决 2026-10-03:导出全部只读,但可切换环节查看——三步 tab + 审计页。\n\tconst steps = record.steps\n\t\t.map(\n\t\t\t(step) => `<section class=\"pane\" data-pane=\"${esc(step.step)}\">\n\t\t\t<h3>${STEP_CN[step.step] ?? esc(step.step)}\n\t\t\t<span class=\"stepmeta\">${step.status === \"locked\" ? `已锁定(第 ${step.baselineConfirmedAtRound ?? \"-\"} 轮确认)` : esc(step.status)} · ${step.blocks.length} 块</span></h3>\n\t\t\t${step.blocks.map((block) => blockHtml(block)).join(\"\") || '<div class=\"empty\">该环节暂无块。</div>'}</section>`,\n\t\t)\n\t\t.join(\"\");\n\tconst history = transitions\n\t\t.slice(-40)\n\t\t.reverse()\n\t\t.map(\n\t\t\t(entry) =>\n\t\t\t\t`<li><span class=\"rev\">r${entry.round ?? \"-\"} rev${entry.revision}</span> ${esc(entry.step ?? \"\")} ${esc(\n\t\t\t\t\tentry.event,\n\t\t\t\t)} — ${esc(entry.reason.detail ?? entry.reason.code)}</li>`,\n\t\t)\n\t\t.join(\"\");\n\tconst versions = (record.versions ?? [])\n\t\t.slice()\n\t\t.reverse()\n\t\t.map(\n\t\t\t(snapshot) =>\n\t\t\t\t`<li>rev${snapshot.revision}(第 ${snapshot.round} 轮)· ${STEP_CN[snapshot.step] ?? esc(snapshot.step)} · ${\n\t\t\t\t\tsnapshot.truncated ? \"快照超限仅存锚点\" : `${snapshot.blocks.length} 块`\n\t\t\t\t}</li>`,\n\t\t)\n\t\t.join(\"\");\n\treturn `<!DOCTYPE html>\n<html lang=\"zh-CN\"><head><meta charset=\"UTF-8\"><meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n<title>需求对齐导出 · ${esc(record.title)}</title><style>\nbody{margin:0;font-family:system-ui,-apple-system,\"Segoe UI\",sans-serif;background:#f4f2fb;color:#31344d}\n.wrap{max-width:880px;margin:0 auto;padding:32px 20px 64px}\nh1{font-size:24px;margin:8px 0 4px}.meta{color:#8b8fa7;font-size:13px;margin-bottom:20px}\n.banner{border-radius:14px;padding:12px 18px;font-size:14px;margin-bottom:22px;background:linear-gradient(120deg,#eef0ff,#fdeef6);border:1px solid #e3e0f5}\nh3{font-size:15px;margin:26px 0 10px}.stepmeta{color:#8b8fa7;font-weight:400;font-size:12px;margin-left:8px}\n.block{background:#fff;border:1px solid #ecebf5;border-radius:12px;padding:12px 14px;margin-bottom:10px}\n.top{display:flex;gap:8px;align-items:center;font-size:12px}.bid{color:#8b8fa7}\n.badge{padding:2px 10px;border-radius:99px;font-size:12px}\n.badge.fact{background:#e8f5ee;color:#1d8a5e}.badge.assumption{background:#fff4e2;color:#c07a15}\n.badge.decision{background:#efedff;color:#6a4de0}.badge.missing{background:#fde9ef;color:#d4498a}\n.badge.visual{background:#e0f5f6;color:#0e7490}\n.ok{color:#1d8a5e;margin-left:auto}.pend{color:#c0c2d4;margin-left:auto}\n.content{font-size:14px;line-height:1.6;margin-top:8px}.why{font-size:12px;color:#8b8fa7;margin-top:6px}\nul{padding-left:18px;font-size:13px;color:#565a75;line-height:1.9}.rev{color:#8b8fa7;font-size:12px;margin-right:6px}\n.note{font-size:12px;color:#8b8fa7;margin-top:28px;border-top:1px solid #ecebf5;padding-top:12px}\n.etabs{display:flex;gap:8px;margin:0 0 18px;flex-wrap:wrap}\n.etab{border:1px solid #e3e0f5;background:#fff;color:#565a75;border-radius:999px;padding:7px 18px;font-size:13px;font-weight:600;cursor:pointer}\n.etab.on{background:linear-gradient(120deg,#7c6ff0,#d946ef);border-color:transparent;color:#fff;box-shadow:0 8px 20px -8px rgba(124,111,240,.55)}\n.pane h3:first-child{margin-top:0}\n.empty{color:#8b8fa7;font-size:13px;padding:8px 0}\n.content{white-space:pre-wrap}\n</style></head><body><div class=\"wrap\">\n<h1>${esc(record.title)}</h1>\n<div class=\"meta\">${esc(record.id)} · ${STATUS_CN[record.status] ?? esc(record.status)} · revision ${record.revision} · 共 ${record.roundCount} 轮 · 导出于 ${esc(\n\t\tgeneratedAt.toLocaleString(\"zh-CN\"),\n\t)}</div>\n<div class=\"banner\">本文件是需求对齐的只读导出快照;机器真值在会话 entries(alignment.state)。实施中改动任一已确认决策,须回对齐插件重新确认。</div>\n<nav class=\"etabs\">\n<button class=\"etab on\" data-tab=\"objective\">目标</button>\n<button class=\"etab\" data-tab=\"detail\">细节</button>\n<button class=\"etab\" data-tab=\"design\">设计</button>\n<button class=\"etab\" data-tab=\"audit\">审计</button>\n</nav>\n${steps}\n<section class=\"pane\" data-pane=\"audit\" style=\"display:none\">\n<h3>历史轮次(最近 40 条)</h3><ul>${history || \"<li>无</li>\"}</ul>\n<h3>历史版本</h3><ul>${versions || \"<li>无(尚无修订归档)</li>\"}</ul>\n</section>\n<div class=\"note\">由 /alignment export 生成 · agent-forge alignment plugin</div>\n</div>\n<script>\nvar etabs=document.querySelectorAll(\".etab\");\nfor(var i=0;i<etabs.length;i++){\n\tetabs[i].addEventListener(\"click\",function(){\n\t\tvar id=this.getAttribute(\"data-tab\");\n\t\tfor(var j=0;j<etabs.length;j++)etabs[j].classList.remove(\"on\");\n\t\tthis.classList.add(\"on\");\n\t\tvar panes=document.querySelectorAll(\".pane\");\n\t\tfor(var k=0;k<panes.length;k++)panes[k].style.display=panes[k].getAttribute(\"data-pane\")===id?\"\":\"none\";\n\t});\n}\n</script>\n</body></html>`;\n}\n\n/** Resolve the export target path (explicit path wins; default: cwd). */\nexport function exportTargetPath(cwd: string, record: AlignmentRecord, explicitPath?: string): string {\n\tif (explicitPath && explicitPath.trim() !== \"\") {\n\t\treturn isAbsolute(explicitPath.trim()) ? resolve(explicitPath.trim()) : resolve(cwd, explicitPath.trim());\n\t}\n\treturn resolve(cwd, `${record.id}-alignment.html`);\n}\n\n/** Write the export file; returns the absolute path written. */\nexport function writeAlignmentExport(\n\trecord: AlignmentRecord,\n\ttransitions: readonly AlignmentTransitionEntry[],\n\ttargetPath: string,\n\tnow: Date = new Date(),\n): string {\n\twriteFileSync(targetPath, renderAlignmentExport(record, transitions, now), { encoding: \"utf8\", flag: \"wx\" });\n\treturn targetPath;\n}\n\nexport function defaultExportPath(cwd: string, record: AlignmentRecord): string {\n\treturn join(cwd, `${record.id}-alignment.html`);\n}\n"]}
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Local confirmation-page server (设计 §7): binds 127.0.0.1, hands out a
3
+ * random token path (CSRF defense for other local pages), serves the fixed
4
+ * HTML template plus a polled state snapshot, and receives POST /round.
5
+ *
6
+ * The server owns transport only — every state decision runs through the
7
+ * `handlers` callbacks supplied by index.ts, which route into the engine,
8
+ * persist entries, and inject the feedback into the session.
9
+ */
10
+ import type { AlignmentRoundPost } from "./types.ts";
11
+ export interface RoundPostResponse {
12
+ status: number;
13
+ body: unknown;
14
+ }
15
+ export interface AlignmentServerHandlers {
16
+ /** State snapshot consumed by the page (state.json); undefined = no page data. */
17
+ getState(): unknown;
18
+ /** Process a submitted round; resolve with the HTTP response for the page. */
19
+ onRoundPost(post: AlignmentRoundPost): Promise<RoundPostResponse>;
20
+ }
21
+ export interface AlignmentServer {
22
+ readonly url: string;
23
+ readonly port: number;
24
+ stop(): Promise<void>;
25
+ }
26
+ /**
27
+ * Start the confirmation server. `port` defaults to 0 (OS-assigned) so
28
+ * concurrent sessions never fight over a fixed port (出厂默认: port 0).
29
+ */
30
+ export declare function startAlignmentServer(handlers: AlignmentServerHandlers, options?: {
31
+ port?: number;
32
+ }): Promise<AlignmentServer>;
33
+ //# sourceMappingURL=http-server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http-server.d.ts","sourceRoot":"","sources":["../src/http-server.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAKH,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAErD,MAAM,WAAW,iBAAiB;IACjC,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,OAAO,CAAC;CACd;AAED,MAAM,WAAW,uBAAuB;IACvC,kFAAkF;IAClF,QAAQ,IAAI,OAAO,CAAC;IACpB,8EAA8E;IAC9E,WAAW,CAAC,IAAI,EAAE,kBAAkB,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAAC;CAClE;AAED,MAAM,WAAW,eAAe;IAC/B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACtB;AAmCD;;;GAGG;AACH,wBAAsB,oBAAoB,CACzC,QAAQ,EAAE,uBAAuB,EACjC,OAAO,CAAC,EAAE;IAAE,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,GACzB,OAAO,CAAC,eAAe,CAAC,CAuB1B","sourcesContent":["/**\n * Local confirmation-page server (设计 §7): binds 127.0.0.1, hands out a\n * random token path (CSRF defense for other local pages), serves the fixed\n * HTML template plus a polled state snapshot, and receives POST /round.\n *\n * The server owns transport only — every state decision runs through the\n * `handlers` callbacks supplied by index.ts, which route into the engine,\n * persist entries, and inject the feedback into the session.\n */\n\nimport { randomUUID } from \"node:crypto\";\nimport { createServer, type IncomingMessage, type Server, type ServerResponse } from \"node:http\";\nimport { renderAlignmentPage } from \"./page.ts\";\nimport type { AlignmentRoundPost } from \"./types.ts\";\n\nexport interface RoundPostResponse {\n\tstatus: number;\n\tbody: unknown;\n}\n\nexport interface AlignmentServerHandlers {\n\t/** State snapshot consumed by the page (state.json); undefined = no page data. */\n\tgetState(): unknown;\n\t/** Process a submitted round; resolve with the HTTP response for the page. */\n\tonRoundPost(post: AlignmentRoundPost): Promise<RoundPostResponse>;\n}\n\nexport interface AlignmentServer {\n\treadonly url: string;\n\treadonly port: number;\n\tstop(): Promise<void>;\n}\n\nconst MAX_POST_BYTES = 1_000_000;\n\nfunction readBody(request: IncomingMessage, response: ServerResponse): Promise<string> {\n\treturn new Promise((resolve, reject) => {\n\t\tlet total = 0;\n\t\tconst chunks: Buffer[] = [];\n\t\trequest.on(\"data\", (chunk: Buffer) => {\n\t\t\ttotal += chunk.length;\n\t\t\tif (total > MAX_POST_BYTES) {\n\t\t\t\t// Answer before tearing the socket down so the page sees 413\n\t\t\t\t// instead of a network error.\n\t\t\t\tresponse.writeHead(413, { \"content-type\": \"text/plain; charset=utf-8\", connection: \"close\" });\n\t\t\t\tresponse.end(\"request body too large\");\n\t\t\t\treject(new Error(\"request body too large\"));\n\t\t\t\trequest.destroy();\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tchunks.push(chunk);\n\t\t});\n\t\trequest.on(\"end\", () => resolve(Buffer.concat(chunks).toString(\"utf8\")));\n\t\trequest.on(\"error\", reject);\n\t});\n}\n\nfunction sendJson(response: ServerResponse, status: number, body: unknown): void {\n\tconst payload = JSON.stringify(body);\n\tresponse.writeHead(status, {\n\t\t\"content-type\": \"application/json; charset=utf-8\",\n\t\t\"cache-control\": \"no-store\",\n\t});\n\tresponse.end(payload);\n}\n\n/**\n * Start the confirmation server. `port` defaults to 0 (OS-assigned) so\n * concurrent sessions never fight over a fixed port (出厂默认: port 0).\n */\nexport async function startAlignmentServer(\n\thandlers: AlignmentServerHandlers,\n\toptions?: { port?: number },\n): Promise<AlignmentServer> {\n\tconst token = randomUUID().replace(/-/g, \"\") + randomUUID().replace(/-/g, \"\");\n\tconst pageHtml = renderAlignmentPage();\n\tconst server: Server = createServer((request, response) => {\n\t\tvoid handle(server, request, response, token, pageHtml, handlers);\n\t});\n\tawait new Promise<void>((resolve, reject) => {\n\t\tserver.once(\"error\", reject);\n\t\tserver.listen(options?.port ?? 0, \"127.0.0.1\", () => resolve());\n\t});\n\tconst address = server.address();\n\tif (address === null || typeof address === \"string\") {\n\t\tserver.close();\n\t\tthrow new Error(\"alignment server failed to bind a TCP port\");\n\t}\n\treturn {\n\t\turl: `http://127.0.0.1:${address.port}/t/${token}/`,\n\t\tport: address.port,\n\t\tstop: () =>\n\t\t\tnew Promise<void>((resolve, reject) => {\n\t\t\t\tserver.close((error) => (error ? reject(error) : resolve()));\n\t\t\t}),\n\t};\n}\n\nasync function handle(\n\tserver: Server,\n\trequest: IncomingMessage,\n\tresponse: ServerResponse,\n\ttoken: string,\n\tpageHtml: string,\n\thandlers: AlignmentServerHandlers,\n): Promise<void> {\n\tconst url = request.url ?? \"/\";\n\t// Token path check: every route must live under /t/<token>/ — anything\n\t// else is an unknown party probing the port.\n\tif (!url.startsWith(`/t/${token}/`)) {\n\t\tresponse.writeHead(404, { \"content-type\": \"text/plain; charset=utf-8\" });\n\t\tresponse.end(\"not found\");\n\t\treturn;\n\t}\n\tconst route = url.slice(`/t/${token}/`.length).split(\"?\")[0] ?? \"\";\n\ttry {\n\t\tif (request.method === \"GET\" && (route === \"\" || route === \"index.html\")) {\n\t\t\tresponse.writeHead(200, {\n\t\t\t\t\"content-type\": \"text/html; charset=utf-8\",\n\t\t\t\t\"cache-control\": \"no-store\",\n\t\t\t});\n\t\t\tresponse.end(pageHtml);\n\t\t\treturn;\n\t\t}\n\t\tif (request.method === \"GET\" && route === \"state.json\") {\n\t\t\tconst state = handlers.getState();\n\t\t\tif (state === undefined) sendJson(response, 404, { error: \"no active alignment\" });\n\t\t\telse sendJson(response, 200, state);\n\t\t\treturn;\n\t\t}\n\t\tif (request.method === \"POST\" && route === \"round\") {\n\t\t\tconst raw = await readBody(request, response);\n\t\t\tconst post = JSON.parse(raw) as AlignmentRoundPost;\n\t\t\tconst result = await handlers.onRoundPost(post);\n\t\t\tsendJson(response, result.status, result.body);\n\t\t\treturn;\n\t\t}\n\t\tresponse.writeHead(404, { \"content-type\": \"text/plain; charset=utf-8\" });\n\t\tresponse.end(\"not found\");\n\t} catch (error) {\n\t\t// Transport/parse failures surface verbatim; handler-level business\n\t\t// errors are already shaped by index.ts into RoundPostResponse. A 413\n\t\t// from readBody has already ended the response.\n\t\tif (!response.writableEnded) {\n\t\t\tsendJson(response, 400, { error: error instanceof Error ? error.message : String(error) });\n\t\t}\n\t} finally {\n\t\tvoid server;\n\t}\n}\n"]}
@@ -0,0 +1,119 @@
1
+ /**
2
+ * Local confirmation-page server (设计 §7): binds 127.0.0.1, hands out a
3
+ * random token path (CSRF defense for other local pages), serves the fixed
4
+ * HTML template plus a polled state snapshot, and receives POST /round.
5
+ *
6
+ * The server owns transport only — every state decision runs through the
7
+ * `handlers` callbacks supplied by index.ts, which route into the engine,
8
+ * persist entries, and inject the feedback into the session.
9
+ */
10
+ import { randomUUID } from "node:crypto";
11
+ import { createServer } from "node:http";
12
+ import { renderAlignmentPage } from "./page.js";
13
+ const MAX_POST_BYTES = 1_000_000;
14
+ function readBody(request, response) {
15
+ return new Promise((resolve, reject) => {
16
+ let total = 0;
17
+ const chunks = [];
18
+ request.on("data", (chunk) => {
19
+ total += chunk.length;
20
+ if (total > MAX_POST_BYTES) {
21
+ // Answer before tearing the socket down so the page sees 413
22
+ // instead of a network error.
23
+ response.writeHead(413, { "content-type": "text/plain; charset=utf-8", connection: "close" });
24
+ response.end("request body too large");
25
+ reject(new Error("request body too large"));
26
+ request.destroy();
27
+ return;
28
+ }
29
+ chunks.push(chunk);
30
+ });
31
+ request.on("end", () => resolve(Buffer.concat(chunks).toString("utf8")));
32
+ request.on("error", reject);
33
+ });
34
+ }
35
+ function sendJson(response, status, body) {
36
+ const payload = JSON.stringify(body);
37
+ response.writeHead(status, {
38
+ "content-type": "application/json; charset=utf-8",
39
+ "cache-control": "no-store",
40
+ });
41
+ response.end(payload);
42
+ }
43
+ /**
44
+ * Start the confirmation server. `port` defaults to 0 (OS-assigned) so
45
+ * concurrent sessions never fight over a fixed port (出厂默认: port 0).
46
+ */
47
+ export async function startAlignmentServer(handlers, options) {
48
+ const token = randomUUID().replace(/-/g, "") + randomUUID().replace(/-/g, "");
49
+ const pageHtml = renderAlignmentPage();
50
+ const server = createServer((request, response) => {
51
+ void handle(server, request, response, token, pageHtml, handlers);
52
+ });
53
+ await new Promise((resolve, reject) => {
54
+ server.once("error", reject);
55
+ server.listen(options?.port ?? 0, "127.0.0.1", () => resolve());
56
+ });
57
+ const address = server.address();
58
+ if (address === null || typeof address === "string") {
59
+ server.close();
60
+ throw new Error("alignment server failed to bind a TCP port");
61
+ }
62
+ return {
63
+ url: `http://127.0.0.1:${address.port}/t/${token}/`,
64
+ port: address.port,
65
+ stop: () => new Promise((resolve, reject) => {
66
+ server.close((error) => (error ? reject(error) : resolve()));
67
+ }),
68
+ };
69
+ }
70
+ async function handle(server, request, response, token, pageHtml, handlers) {
71
+ const url = request.url ?? "/";
72
+ // Token path check: every route must live under /t/<token>/ — anything
73
+ // else is an unknown party probing the port.
74
+ if (!url.startsWith(`/t/${token}/`)) {
75
+ response.writeHead(404, { "content-type": "text/plain; charset=utf-8" });
76
+ response.end("not found");
77
+ return;
78
+ }
79
+ const route = url.slice(`/t/${token}/`.length).split("?")[0] ?? "";
80
+ try {
81
+ if (request.method === "GET" && (route === "" || route === "index.html")) {
82
+ response.writeHead(200, {
83
+ "content-type": "text/html; charset=utf-8",
84
+ "cache-control": "no-store",
85
+ });
86
+ response.end(pageHtml);
87
+ return;
88
+ }
89
+ if (request.method === "GET" && route === "state.json") {
90
+ const state = handlers.getState();
91
+ if (state === undefined)
92
+ sendJson(response, 404, { error: "no active alignment" });
93
+ else
94
+ sendJson(response, 200, state);
95
+ return;
96
+ }
97
+ if (request.method === "POST" && route === "round") {
98
+ const raw = await readBody(request, response);
99
+ const post = JSON.parse(raw);
100
+ const result = await handlers.onRoundPost(post);
101
+ sendJson(response, result.status, result.body);
102
+ return;
103
+ }
104
+ response.writeHead(404, { "content-type": "text/plain; charset=utf-8" });
105
+ response.end("not found");
106
+ }
107
+ catch (error) {
108
+ // Transport/parse failures surface verbatim; handler-level business
109
+ // errors are already shaped by index.ts into RoundPostResponse. A 413
110
+ // from readBody has already ended the response.
111
+ if (!response.writableEnded) {
112
+ sendJson(response, 400, { error: error instanceof Error ? error.message : String(error) });
113
+ }
114
+ }
115
+ finally {
116
+ void server;
117
+ }
118
+ }
119
+ //# sourceMappingURL=http-server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http-server.js","sourceRoot":"","sources":["../src/http-server.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Local confirmation-page server (设计 §7): binds 127.0.0.1, hands out a\n * random token path (CSRF defense for other local pages), serves the fixed\n * HTML template plus a polled state snapshot, and receives POST /round.\n *\n * The server owns transport only — every state decision runs through the\n * `handlers` callbacks supplied by index.ts, which route into the engine,\n * persist entries, and inject the feedback into the session.\n */\n\nimport { randomUUID } from \"node:crypto\";\nimport { createServer, type IncomingMessage, type Server, type ServerResponse } from \"node:http\";\nimport { renderAlignmentPage } from \"./page.ts\";\nimport type { AlignmentRoundPost } from \"./types.ts\";\n\nexport interface RoundPostResponse {\n\tstatus: number;\n\tbody: unknown;\n}\n\nexport interface AlignmentServerHandlers {\n\t/** State snapshot consumed by the page (state.json); undefined = no page data. */\n\tgetState(): unknown;\n\t/** Process a submitted round; resolve with the HTTP response for the page. */\n\tonRoundPost(post: AlignmentRoundPost): Promise<RoundPostResponse>;\n}\n\nexport interface AlignmentServer {\n\treadonly url: string;\n\treadonly port: number;\n\tstop(): Promise<void>;\n}\n\nconst MAX_POST_BYTES = 1_000_000;\n\nfunction readBody(request: IncomingMessage, response: ServerResponse): Promise<string> {\n\treturn new Promise((resolve, reject) => {\n\t\tlet total = 0;\n\t\tconst chunks: Buffer[] = [];\n\t\trequest.on(\"data\", (chunk: Buffer) => {\n\t\t\ttotal += chunk.length;\n\t\t\tif (total > MAX_POST_BYTES) {\n\t\t\t\t// Answer before tearing the socket down so the page sees 413\n\t\t\t\t// instead of a network error.\n\t\t\t\tresponse.writeHead(413, { \"content-type\": \"text/plain; charset=utf-8\", connection: \"close\" });\n\t\t\t\tresponse.end(\"request body too large\");\n\t\t\t\treject(new Error(\"request body too large\"));\n\t\t\t\trequest.destroy();\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tchunks.push(chunk);\n\t\t});\n\t\trequest.on(\"end\", () => resolve(Buffer.concat(chunks).toString(\"utf8\")));\n\t\trequest.on(\"error\", reject);\n\t});\n}\n\nfunction sendJson(response: ServerResponse, status: number, body: unknown): void {\n\tconst payload = JSON.stringify(body);\n\tresponse.writeHead(status, {\n\t\t\"content-type\": \"application/json; charset=utf-8\",\n\t\t\"cache-control\": \"no-store\",\n\t});\n\tresponse.end(payload);\n}\n\n/**\n * Start the confirmation server. `port` defaults to 0 (OS-assigned) so\n * concurrent sessions never fight over a fixed port (出厂默认: port 0).\n */\nexport async function startAlignmentServer(\n\thandlers: AlignmentServerHandlers,\n\toptions?: { port?: number },\n): Promise<AlignmentServer> {\n\tconst token = randomUUID().replace(/-/g, \"\") + randomUUID().replace(/-/g, \"\");\n\tconst pageHtml = renderAlignmentPage();\n\tconst server: Server = createServer((request, response) => {\n\t\tvoid handle(server, request, response, token, pageHtml, handlers);\n\t});\n\tawait new Promise<void>((resolve, reject) => {\n\t\tserver.once(\"error\", reject);\n\t\tserver.listen(options?.port ?? 0, \"127.0.0.1\", () => resolve());\n\t});\n\tconst address = server.address();\n\tif (address === null || typeof address === \"string\") {\n\t\tserver.close();\n\t\tthrow new Error(\"alignment server failed to bind a TCP port\");\n\t}\n\treturn {\n\t\turl: `http://127.0.0.1:${address.port}/t/${token}/`,\n\t\tport: address.port,\n\t\tstop: () =>\n\t\t\tnew Promise<void>((resolve, reject) => {\n\t\t\t\tserver.close((error) => (error ? reject(error) : resolve()));\n\t\t\t}),\n\t};\n}\n\nasync function handle(\n\tserver: Server,\n\trequest: IncomingMessage,\n\tresponse: ServerResponse,\n\ttoken: string,\n\tpageHtml: string,\n\thandlers: AlignmentServerHandlers,\n): Promise<void> {\n\tconst url = request.url ?? \"/\";\n\t// Token path check: every route must live under /t/<token>/ — anything\n\t// else is an unknown party probing the port.\n\tif (!url.startsWith(`/t/${token}/`)) {\n\t\tresponse.writeHead(404, { \"content-type\": \"text/plain; charset=utf-8\" });\n\t\tresponse.end(\"not found\");\n\t\treturn;\n\t}\n\tconst route = url.slice(`/t/${token}/`.length).split(\"?\")[0] ?? \"\";\n\ttry {\n\t\tif (request.method === \"GET\" && (route === \"\" || route === \"index.html\")) {\n\t\t\tresponse.writeHead(200, {\n\t\t\t\t\"content-type\": \"text/html; charset=utf-8\",\n\t\t\t\t\"cache-control\": \"no-store\",\n\t\t\t});\n\t\t\tresponse.end(pageHtml);\n\t\t\treturn;\n\t\t}\n\t\tif (request.method === \"GET\" && route === \"state.json\") {\n\t\t\tconst state = handlers.getState();\n\t\t\tif (state === undefined) sendJson(response, 404, { error: \"no active alignment\" });\n\t\t\telse sendJson(response, 200, state);\n\t\t\treturn;\n\t\t}\n\t\tif (request.method === \"POST\" && route === \"round\") {\n\t\t\tconst raw = await readBody(request, response);\n\t\t\tconst post = JSON.parse(raw) as AlignmentRoundPost;\n\t\t\tconst result = await handlers.onRoundPost(post);\n\t\t\tsendJson(response, result.status, result.body);\n\t\t\treturn;\n\t\t}\n\t\tresponse.writeHead(404, { \"content-type\": \"text/plain; charset=utf-8\" });\n\t\tresponse.end(\"not found\");\n\t} catch (error) {\n\t\t// Transport/parse failures surface verbatim; handler-level business\n\t\t// errors are already shaped by index.ts into RoundPostResponse. A 413\n\t\t// from readBody has already ended the response.\n\t\tif (!response.writableEnded) {\n\t\t\tsendJson(response, 400, { error: error instanceof Error ? error.message : String(error) });\n\t\t}\n\t} finally {\n\t\tvoid server;\n\t}\n}\n"]}