@ai-agent-forge/plugin-alignment 0.88.1 → 0.88.4

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.
@@ -1 +1 @@
1
- {"version":3,"file":"export.js","sourceRoot":"","sources":["../src/export.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AACxC,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAGtD,MAAM,OAAO,GAA2B;IACvC,IAAI,EAAE,QAAI;IACV,UAAU,EAAE,QAAI;IAChB,QAAQ,EAAE,QAAI;IACd,OAAO,EAAE,WAAK;CACd,CAAC;AAEF,MAAM,OAAO,GAA2B,EAAE,SAAS,EAAE,QAAI,EAAE,MAAM,EAAE,QAAI,EAAE,MAAM,EAAE,QAAI,EAAE,CAAC;AAExF,MAAM,SAAS,GAA2B;IACzC,QAAQ,EAAE,WAAK;IACf,UAAU,EAAE,WAAK;IACjB,SAAS,EAAE,WAAK;IAChB,SAAS,EAAE,WAAK;CAChB,CAAC;AAEF,SAAS,GAAG,CAAC,IAAY,EAAU;IAClC,OAAO,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;AAAA,CACvG;AAED,SAAS,SAAS,CAAC,KAAwF,EAAU;IACpH,MAAM,KAAK,GAAG,sBAAsB,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC;IACxG,MAAM,KAAK,GAAG,KAAK,CAAC,MAAM,KAAK,UAAU,CAAC,CAAC,CAAC,mCAA6B,CAAC,CAAC,CAAC,qCAA+B,CAAC;IAC5G,MAAM,SAAS,GAAG,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,6BAAuB,GAAG,CAAC,KAAK,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC;IAC7F,oFAA8B;IAC9B,OAAO,uCAAuC,KAAK,qBAAqB,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,UAAU,KAAK,8BAA8B,GAAG,CACpI,KAAK,CAAC,OAAO,CACb,SAAS,SAAS,QAAQ,CAAC;AAAA,CAC5B;AAED,MAAM,UAAU,qBAAqB,CACpC,MAAuB,EACvB,WAAgD,EAChD,WAAiB,EACR;IACT,yGAAiD;IACjD,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK;SACxB,GAAG,CACH,CAAC,IAAI,EAAE,EAAE,CAAC,oCAAoC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC;SACtD,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC;4BACjB,IAAI,CAAC,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,mBAAS,IAAI,CAAC,wBAAwB,IAAI,GAAG,eAAO,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,OAAM,IAAI,CAAC,MAAM,CAAC,MAAM;KACjJ,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,gDAAkC,YAAY,CACzG;SACA,IAAI,CAAC,EAAE,CAAC,CAAC;IACX,MAAM,OAAO,GAAG,WAAW;SACzB,KAAK,CAAC,CAAC,EAAE,CAAC;SACV,OAAO,EAAE;SACT,GAAG,CACH,CAAC,KAAK,EAAE,EAAE,CACT,0BAA0B,KAAK,CAAC,KAAK,IAAI,GAAG,OAAO,KAAK,CAAC,QAAQ,WAAW,GAAG,CAAC,KAAK,CAAC,IAAI,IAAI,EAAE,CAAC,IAAI,GAAG,CACvG,KAAK,CAAC,KAAK,CACX,QAAM,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,IAAI,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,CAC5D;SACA,IAAI,CAAC,EAAE,CAAC,CAAC;IACX,MAAM,QAAQ,GAAG,CAAC,MAAM,CAAC,QAAQ,IAAI,EAAE,CAAC;SACtC,KAAK,EAAE;SACP,OAAO,EAAE;SACT,GAAG,CACH,CAAC,QAAQ,EAAE,EAAE,CACZ,UAAU,QAAQ,CAAC,QAAQ,UAAM,QAAQ,CAAC,KAAK,aAAQ,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,OAClG,QAAQ,CAAC,SAAS,CAAC,CAAC,CAAC,0BAAU,CAAC,CAAC,CAAC,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,MAC5D,OAAO,CACR;SACA,IAAI,CAAC,EAAE,CAAC,CAAC;IACX,OAAO;;+BAEU,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC;;;;;;;;;;;;;;;;;;;;;;MAsB7B,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC;oBACH,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,OAAM,SAAS,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,gBAAe,MAAM,CAAC,QAAQ,WAAQ,MAAM,CAAC,UAAU,qBAAY,GAAG,CAC1J,WAAW,CAAC,cAAc,CAAC,OAAO,CAAC,CACnC;;;;;;;;EAQA,KAAK;;8CAEqB,OAAO,IAAI,cAAY;2BAChC,QAAQ,IAAI,sCAAoB;;;;;;;;;;;;;;;;eAgBpC,CAAC;AAAA,CACf;AAED,yEAAyE;AACzE,MAAM,UAAU,gBAAgB,CAAC,GAAW,EAAE,MAAuB,EAAE,YAAqB,EAAU;IACrG,IAAI,YAAY,IAAI,YAAY,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC;QAChD,OAAO,UAAU,CAAC,YAAY,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,YAAY,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,EAAE,YAAY,CAAC,IAAI,EAAE,CAAC,CAAC;IAC3G,CAAC;IACD,OAAO,OAAO,CAAC,GAAG,EAAE,GAAG,MAAM,CAAC,EAAE,iBAAiB,CAAC,CAAC;AAAA,CACnD;AAED,gEAAgE;AAChE,MAAM,UAAU,oBAAoB,CACnC,MAAuB,EACvB,WAAgD,EAChD,UAAkB,EAClB,GAAG,GAAS,IAAI,IAAI,EAAE,EACb;IACT,aAAa,CAAC,UAAU,EAAE,qBAAqB,CAAC,MAAM,EAAE,WAAW,EAAE,GAAG,CAAC,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;IAC7G,OAAO,UAAU,CAAC;AAAA,CAClB;AAED,MAAM,UAAU,iBAAiB,CAAC,GAAW,EAAE,MAAuB,EAAU;IAC/E,OAAO,IAAI,CAAC,GAAG,EAAE,GAAG,MAAM,CAAC,EAAE,iBAAiB,CAAC,CAAC;AAAA,CAChD","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};\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.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"]}
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"]}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,KAAK,EAAE,aAAa,EAA2B,sBAAsB,EAAE,MAAM,yBAAyB,CAAC;AAuC9G,MAAM,WAAW,0BAA0B;IAC1C,oFAAoF;IACpF,UAAU,CAAC,EAAE,MAAM,CAAC;CACpB;AA8SD,wBAAgB,gBAAgB,CAC/B,GAAG,EAAE,aAAa,EAClB,OAAO,GAAE,0BAA+B,GACtC,SAAS,sBAAsB,EAAE,CA2YnC","sourcesContent":["/**\n * Alignment capability plugin (M1 of `docs/design/需求对齐插件设计.md`): a\n * three-step requirement-alignment funnel (objective → detail → design) with\n * block-level bidirectional feedback confirmed on a local HTML page.\n *\n * Persistence protocol, structurally identical to the goal/plan/todo/workflow\n * plugins: append-only `alignment.state` full snapshots (the single rebuild\n * source) plus one `alignment.transition` audit entry per conversion,\n * announced as `alignment.changed` (version 1, correlationId\n * \"alignment.state\", data = the complete AlignmentState snapshot).\n *\n * The round wait is non-blocking (设计 §5 总则 8): alignment_round returns the\n * page URL immediately; page feedback arrives as a `alignment.feedback`\n * custom message injected through SessionAPI.sendMessage (triggerTurn), and a\n * round only closes after the injection succeeded (`round.delivered`,\n * terminal audit D1).\n */\n\nimport type { CapabilityAPI, CapabilityCommandResult, DisposableRegistration } from \"@agent-forge/plugin-sdk\";\nimport { Type } from \"typebox\";\nimport {\n\ttype AdvanceInput,\n\ttype AlignmentSetInput,\n\tactiveStep,\n\tapplyAlignmentAdvance,\n\tapplyAlignmentSet,\n\tapplyRoundPost,\n\tapplyVersionRollback,\n\ttype EngineRun,\n\tfinalBaselineLines,\n\tgate,\n\tmarkDelivered,\n} from \"./engine.ts\";\nimport { exportTargetPath, writeAlignmentExport } from \"./export.ts\";\nimport { type AlignmentServer, startAlignmentServer } from \"./http-server.ts\";\nimport { alignmentToolResultRenderer } from \"./render.ts\";\nimport {\n\tAlignmentError,\n\ttype AlignmentRecord,\n\ttype AlignmentRoundPost,\n\ttype AlignmentRoundResult,\n\ttype AlignmentState,\n\ttype AlignmentTransitionEntry,\n\ttype PendingItem,\n} from \"./types.ts\";\n\nconst STATE_ENTRY = \"alignment.state\";\nconst TRANSITION_ENTRY = \"alignment.transition\";\nconst GOAL_STATE_ENTRY = \"goal.state\";\n/** Round post outcomes cached until delivered — the retry-injection window (终审 D1). */\ninterface CachedRound {\n\tpost: AlignmentRoundPost;\n\trecord: AlignmentRecord;\n\ttransitions: AlignmentTransitionEntry[];\n\tresult: AlignmentRoundResult;\n}\n\nexport interface AlignmentCapabilityOptions {\n\t/** Injection seam for deterministic tests; production binds an OS-assigned port. */\n\tserverPort?: number;\n}\n\nfunction isObject(value: unknown): value is Record<string, unknown> {\n\treturn value !== null && typeof value === \"object\" && !Array.isArray(value);\n}\n\n/**\n * 双调用约定(走查 2026-10-04,goal 插件同款问题的严谨版):会话路径以\n * (toolCallId, params, signal, onUpdate) 调用插件工具——first 是调用 id 字符串;\n * runtime facade 以 (input, context?, signal?) 调用——first 是入参对象。\n * 按 first 的类型区分,两条路径(含 runtime 携带 context)都取到真实入参。\n */\nfunction toolInput(first: unknown, second?: unknown): Record<string, unknown> {\n\tif (typeof first === \"string\") {\n\t\tif (!isObject(second)) return {};\n\t\treturn second;\n\t}\n\tif (!isObject(first)) throw new Error(\"alignment tool input must be an object\");\n\treturn first;\n}\n\nfunction loadState(api: CapabilityAPI): AlignmentState {\n\tconst entries = api.session?.getBranchEntries() ?? [];\n\tconst entry = [...entries].reverse().find((item) => item.customType === STATE_ENTRY);\n\tif (!entry?.data || !isObject(entry.data)) return { alignments: [] };\n\tconst data = entry.data as { alignments?: unknown };\n\treturn { alignments: Array.isArray(data.alignments) ? [...(data.alignments as AlignmentRecord[])] : [] };\n}\n\nfunction loadTransitions(api: CapabilityAPI): AlignmentTransitionEntry[] {\n\tconst entries = api.session?.getBranchEntries() ?? [];\n\treturn entries\n\t\t.filter((item) => item.customType === TRANSITION_ENTRY)\n\t\t.map((item) => item.data as AlignmentTransitionEntry)\n\t\t.filter((item): item is AlignmentTransitionEntry => isObject(item));\n}\n\n/** Advisory goalId check (#10 soft-reference discipline, goal/plan precedent). */\nfunction goalKnownToSession(api: CapabilityAPI, goalId: string): boolean {\n\tconst entries = api.session?.getBranchEntries() ?? [];\n\tfor (let index = entries.length - 1; index >= 0; index -= 1) {\n\t\tconst entry = entries[index];\n\t\tif (entry.customType !== GOAL_STATE_ENTRY) continue;\n\t\tconst data = entry.data;\n\t\tif (!isObject(data)) return false;\n\t\tconst goals = data.goals;\n\t\tif (!Array.isArray(goals)) return false;\n\t\treturn goals.some((goal) => isObject(goal) && goal.id === goalId);\n\t}\n\treturn false;\n}\n\n/** Page projection (state.json): everything the fixed template renders. */\nfunction pageView(\n\trecord: AlignmentRecord,\n\tbaselineFile: string | undefined,\n\tawaitingRevision: boolean,\n): Record<string, unknown> {\n\tconst snapshot = gate(record);\n\t// gate already validated the active step exists (it throws otherwise).\n\tconst blocks = activeStep(record).blocks;\n\t// 终审/终态头部展示跨步总口径(走查 2026-10-03):completed 后仍按当前步\n\t// 计数会显示「已确认 0/1」这类误导数字。\n\tconst countedBlocks = record.status === \"aligning\" ? blocks : record.steps.flatMap((s) => s.blocks);\n\treturn {\n\t\talignmentId: record.id,\n\t\ttitle: record.title,\n\t\tgoalId: record.goalId,\n\t\tstatus: record.status,\n\t\trevision: record.revision,\n\t\tround: record.roundCount,\n\t\tactiveStep: record.activeStep,\n\t\tsteps: record.steps.map((step) => ({\n\t\t\tstep: step.step,\n\t\t\tstatus: step.status,\n\t\t\tblocks: step.blocks.map((block) => ({\n\t\t\t\tid: block.id,\n\t\t\t\tkind: block.kind,\n\t\t\t\tcontent: block.content,\n\t\t\t\trationale: block.rationale,\n\t\t\t\timpact: block.impact,\n\t\t\t\tstatus: block.status,\n\t\t\t\tmodifiedInRound: block.modifiedInRound,\n\t\t\t\tdraftAnswer: block.draftAnswer,\n\t\t\t\tcomments: block.comments,\n\t\t\t})),\n\t\t})),\n\t\tgate: {\n\t\t\t...snapshot,\n\t\t\tapprovedCount: countedBlocks.filter((block) => block.status === \"approved\").length,\n\t\t\tblockCount: countedBlocks.length,\n\t\t},\n\t\tpendingFeedback: record.pendingFeedback,\n\t\t// Version snapshots for the read-only history switcher (走查 2026-10-03).\n\t\tversions: record.versions ?? [],\n\t\tawaitingRevision,\n\t\tbaselineFile,\n\t};\n}\n\nfunction blockStateLine(block: AlignmentRecord[\"steps\"][number][\"blocks\"][number]): string {\n\tconst state = block.status === \"approved\" ? \"已确认\" : \"待确认\";\n\tconst first = block.content.split(\"\\n\")[0]?.slice(0, 80) ?? \"\";\n\tconst notes: string[] = [];\n\tfor (const comment of block.comments) {\n\t\tif (comment.status !== \"open\") continue;\n\t\tnotes.push(\n\t\t\tcomment.author === \"assistant\"\n\t\t\t\t? `AI疑问待回应:${comment.note.slice(0, 40)}`\n\t\t\t\t: `用户批注:${comment.note.slice(0, 40)}`,\n\t\t);\n\t}\n\treturn `- ${block.id}[${block.kind}|${state}] ${first}${notes.length ? `(${notes.join(\";\")})` : \"\"}`;\n}\n\nfunction historyLines(transitions: AlignmentTransitionEntry[]): string {\n\tif (transitions.length === 0) return \"(无)\";\n\treturn transitions\n\t\t.slice(-20)\n\t\t.map((entry) => {\n\t\t\tconst where = entry.step ? `${entry.step} ` : \"\";\n\t\t\treturn `rev${entry.revision} ${where}${entry.event}${entry.reason.detail ? `(${entry.reason.detail.slice(0, 60)})` : \"\"}`;\n\t\t})\n\t\t.join(\"\\n\");\n}\n\nfunction feedbackMessage(\n\trecord: AlignmentRecord,\n\tresult: AlignmentRoundResult,\n\ttransitions: AlignmentTransitionEntry[],\n): string {\n\tconst snapshot = gate(record);\n\tconst lines: string[] = [];\n\tlines.push(\n\t\t`[alignment.feedback] ${result.alignmentId} 第 ${result.round} 轮(${result.step} 步,revision ${result.revision},status ${record.status})`,\n\t);\n\tlines.push(\"== 本轮反馈 ==\");\n\tif (result.approvals.length > 0) lines.push(`确认块:${result.approvals.join(\", \")}`);\n\tfor (const comment of result.comments) {\n\t\tlines.push(\n\t\t\t`用户批注[${comment.blockId}]${comment.escalate ? \"(上游问题)\" : \"\"}:「${comment.quote}」→ ${comment.note}`,\n\t\t);\n\t}\n\tfor (const reply of result.commentReplies) {\n\t\tlines.push(\n\t\t\treply.dismiss\n\t\t\t\t? `AI 疑问 ${reply.commentId}:用户标记不重要`\n\t\t\t\t: `AI 疑问 ${reply.commentId} 的回答:${reply.answer}`,\n\t\t);\n\t}\n\tfor (const answer of result.answers) {\n\t\tlines.push(`补充答案[${answer.blockId}]:${answer.value}`);\n\t}\n\tfor (const addition of result.additions) {\n\t\tlines.push(`自由补充:${addition}`);\n\t}\n\tif (result.stepConfirmed) {\n\t\tif (record.status === \"completed\") {\n\t\t\tlines.push(\"用户已在终审总览确认基线——对齐完成。请输出最终基线总结(plan 输入)。\");\n\t\t\tif (result.finalBaseline) {\n\t\t\t\tlines.push(\"最终基线紧凑清单:\");\n\t\t\t\tfor (const line of result.finalBaseline) {\n\t\t\t\t\tlines.push(` [${line.kind}] ${line.id}: ${line.line}`);\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\tlines.push(\"用户已确认本步——基线锁定。请 alignment_set 出下一步块集并 alignment_round 刷新。\");\n\t\t}\n\t}\n\tlines.push(\"== 当前块集(全量状态)==\");\n\tif (record.status === \"finalizing\") {\n\t\tlines.push(\"三步基线已全部锁定,等待用户终审总览确认;此阶段无需你操作。\");\n\t} else {\n\t\tfor (const step of record.steps) {\n\t\t\tif (step.blocks.length === 0) continue;\n\t\t\tlines.push(`[${step.step}|${step.status}]`);\n\t\t\tfor (const block of step.blocks) lines.push(blockStateLine(block));\n\t\t}\n\t\tlines.push(\n\t\t\t`待办:${snapshot.unapproved} 块待确认、${snapshot.openComments} 批注未清、${snapshot.pendingAdditions} 补充未落账。`,\n\t\t);\n\t}\n\tlines.push(\"== 历史轮次(revision 锚点)==\");\n\tlines.push(historyLines(transitions));\n\treturn lines.join(\"\\n\");\n}\n\nconst PROMPT_GUIDELINES: readonly string[] = [\n\t\"进入分流(预检规则):用户显式要求对齐时直接进入;否则先做零成本预检——列出缺失信息、被迫假设、矛盾歧义。三项全空则一行结论直接出方案(跳过证据必须可见,禁止静默跳过);有任一项则列出要点并建议对齐,用户说直接做则跳过、但未决假设须在方案中显式标注。预检清单在对齐时直接作为第一轮块种子。\",\n\t\"三步铁律:objective 只谈方向与非目标(≤10 块);detail 只谈业务规则/公式/数据流/异常(禁止技术选型);design 谈技术方案且不得与已锁定基线矛盾,发现矛盾必须停下向用户提出。\",\n\t\"块纪律:假设单独成 assumption 块;缺信息产 missing 块而不是脑补;可自查的先取证落 fact;assistant 批注只用于真实不确定点(公式口径、二义表述、潜在矛盾、与基线冲突)。\",\n\t\"修订纪律:最小改动已确认的块(内容不变即继承确认);每次 alignment_set 之后必须跟 alignment_round 告知用户去看新版;用户批注的 quote 匹配失败时向用户说明而不是猜。\",\n\t\"填空落账:收到补充答案(补充答案[blockId])后,下一次 alignment_set 必须把答案重写进对应块内容并转为 fact/decision(missing 块不得带着未并入的答案被确认锁定);注入消息的「当前块集(全量状态)」是权威现状,以它为准做最小修订。\",\n\t\"终审阶段(status finalizing):三步基线已全部锁定,页面进入只读总览,唯一动作是用户最终确认——此阶段不要调用 alignment_set;收到终审确认消息(alignment completed)即视为开发授权:先输出一行极简基线摘要,然后直接按基线实现——用 plan/todo 把基线拆成可执行任务,实现并自测,完成后向用户报告结果与验收方式。不要停在基线总结等用户再次指令(dogfood 2026-10-04:等指令会打断对齐→开发衔接)。\",\n\t\"页面回退:用户可在页面上把任务回退到更早环节(step.retreated,后续环节作废重走)或把当前步回退到历史版本(version.rolled-back,当前未确认版本丢弃、批注保留)。收到这类消息后,以注入消息里的全量块集为准重新修订,不要复用回退前的块集。\",\n];\n\nconst setSchema = Type.Object({\n\tid: Type.String({ description: \"Stable alignment id; charset [A-Za-z0-9._-], no leading dot\" }),\n\ttitle: Type.Optional(Type.String({ description: \"Human-readable alignment title\" })),\n\tgoalId: Type.Optional(Type.String({ description: \"Soft goal reference; unknown ids only warn\" })),\n\trevision: Type.Optional(Type.Integer({ description: \"Monotonic revision; must exceed the stored one\", minimum: 0 })),\n\tblocks: Type.Array(\n\t\tType.Object({\n\t\t\tid: Type.String({ description: \"Stable block id within the step\" }),\n\t\t\tkind: Type.Union(\n\t\t\t\t[Type.Literal(\"fact\"), Type.Literal(\"assumption\"), Type.Literal(\"decision\"), Type.Literal(\"missing\")],\n\t\t\t\t{ description: \"fact=取证 assumption=假设 decision=决策 missing=待补充\" },\n\t\t\t),\n\t\t\tcontent: Type.String({ description: \"Block content (markdown text, ≤8192 chars)\" }),\n\t\t\trationale: Type.Optional(Type.String({ description: \"Why this decision/assumption (≤2048 chars)\" })),\n\t\t\timpact: Type.Optional(Type.Array(Type.String(), { description: \"Affected modules/files/interfaces\" })),\n\t\t\tcomments: Type.Optional(\n\t\t\t\tType.Array(\n\t\t\t\t\tType.Object({\n\t\t\t\t\t\tid: Type.String(),\n\t\t\t\t\t\tnote: Type.String({ description: \"Assistant question; only real uncertainty\" }),\n\t\t\t\t\t\tquote: Type.Optional(Type.String()),\n\t\t\t\t\t}),\n\t\t\t\t\t{ description: \"New assistant comments (AI 主动标注的不确定点)\" },\n\t\t\t\t),\n\t\t\t),\n\t\t\tcommentResolutions: Type.Optional(\n\t\t\t\tType.Array(\n\t\t\t\t\tType.Object({\n\t\t\t\t\t\tcommentId: Type.String(),\n\t\t\t\t\t\tkind: Type.Union([Type.Literal(\"answered\"), Type.Literal(\"dismissed\"), Type.Literal(\"incorporated\")]),\n\t\t\t\t\t\ttext: Type.Optional(Type.String()),\n\t\t\t\t\t}),\n\t\t\t\t\t{\n\t\t\t\t\t\tdescription:\n\t\t\t\t\t\t\t\"Resolutions for existing comments (user comments may only be resolved, never rewritten)\",\n\t\t\t\t\t},\n\t\t\t\t),\n\t\t\t),\n\t\t}),\n\t\t{ description: \"Full block set of the active step (全量提交;未变块按内容指纹继承确认)\" },\n\t),\n});\n\nconst roundSchema = Type.Object({\n\talignmentId: Type.String({ description: \"Alignment id to open the confirmation page for\" }),\n});\n\nconst advanceSchema = Type.Object({\n\talignmentId: Type.String(),\n\taction: Type.Union([Type.Literal(\"inspect\"), Type.Literal(\"retreat\"), Type.Literal(\"cancel\")]),\n\tstep: Type.Optional(\n\t\tType.Union([Type.Literal(\"objective\"), Type.Literal(\"detail\"), Type.Literal(\"design\")], {\n\t\t\tdescription: \"Retreat target; must be an earlier step\",\n\t\t}),\n\t),\n\tnote: Type.Optional(Type.String({ description: \"Retreat reason (required for retreat)\" })),\n});\n\nfunction pendingText(items: PendingItem[]): string {\n\tif (items.length === 0) return \"nothing pending\";\n\tconst reasons = items.map((item) => `${item.blockId}(${item.reason})`);\n\treturn reasons.join(\" \");\n}\n\nfunction listLines(state: AlignmentState): string {\n\tif (state.alignments.length === 0) return \"no alignments in this session; create one with alignment_set\";\n\tconst lines = [`alignments: ${state.alignments.length}`];\n\tfor (const record of state.alignments) {\n\t\tconst snapshot = gate(record);\n\t\tlines.push(\n\t\t\t`- ${record.id} [${record.status} → ${record.goalId ?? \"-\"}] ${record.title} · ${record.activeStep} r${record.roundCount} · ${snapshot.unapproved} pending / ${snapshot.openComments} open`,\n\t\t);\n\t}\n\treturn lines.join(\"\\n\");\n}\n\nfunction whyLines(record: AlignmentRecord): string {\n\tconst snapshot = gate(record);\n\tconst lines = [`${record.id} · ${record.activeStep} · round ${record.roundCount}`];\n\tif (record.status !== \"aligning\") {\n\t\tlines.push(`status ${record.status} — nothing to wait for`);\n\t\treturn lines.join(\"\\n\");\n\t}\n\tif (snapshot.allGreen) {\n\t\tlines.push(\"ALL GREEN — waiting for the user to click 确认完成 on the page\");\n\t\treturn lines.join(\"\\n\");\n\t}\n\tlines.push(`pending: ${pendingText(snapshot.pending)}`);\n\tif (snapshot.pendingAdditions > 0) {\n\t\tlines.push(`undelivered additions: ${record.pendingFeedback?.additions.join(\" | \")}`);\n\t}\n\treturn lines.join(\"\\n\");\n}\n\nfunction logLines(transitions: AlignmentTransitionEntry[], count: number): string {\n\tif (transitions.length === 0) return \"no alignment transitions recorded\";\n\tconst slice = transitions.slice(-count).reverse();\n\treturn slice\n\t\t.map((entry, index) => {\n\t\t\tconst where = entry.step ? `${entry.step} ` : \"\";\n\t\t\treturn `${slice.length - index}. [r${entry.round ?? \"-\"} rev${entry.revision}] ${where}${entry.event} ${entry.reason.code}${entry.reason.detail ? ` — ${entry.reason.detail}` : \"\"}`;\n\t\t})\n\t\t.join(\"\\n\");\n}\n\nexport function createCapability(\n\tapi: CapabilityAPI,\n\toptions: AlignmentCapabilityOptions = {},\n): readonly DisposableRegistration[] {\n\tlet state = loadState(api);\n\tlet server: AlignmentServer | undefined;\n\tlet cachedRound: CachedRound | undefined;\n\tconst deliveredRoundByAlignment = new Map<string, number>();\n\t/** Revision at last successful injection — awaitingRevision = delivered and not yet superseded by a set. */\n\tconst deliveredRevisionByAlignment = new Map<string, number>();\n\n\tconst persist = (next: AlignmentState, transitions: AlignmentTransitionEntry[]): AlignmentState => {\n\t\tstate = next;\n\t\tapi.session?.appendEntry(STATE_ENTRY, state);\n\t\tfor (const entry of transitions) api.session?.appendEntry(TRANSITION_ENTRY, entry);\n\t\tvoid api.publish({ type: \"alignment.changed\", version: 1, correlationId: STATE_ENTRY, data: state });\n\t\treturn state;\n\t};\n\n\tconst activeRecord = (): AlignmentRecord | undefined =>\n\t\tstate.alignments.find((record) => record.status === \"aligning\") ??\n\t\t[...state.alignments].reverse().find((record) => record.status !== \"aligning\");\n\n\tconst ensureServer = async (): Promise<AlignmentServer> => {\n\t\t// 页面生命周期(走查 2026-10-04 用户裁决):服务随第一个 alignment_round\n\t\t// 启动后常驻到插件 dispose(会话关闭);终态对齐的页面保持可查看,直到\n\t\t// 下一次对齐在同一 URL 上覆盖内容。不再做终态 idle 停服。\n\t\tif (server) return server;\n\t\tserver = await startAlignmentServer(\n\t\t\t{\n\t\t\t\tgetState: () => {\n\t\t\t\t\tconst record = activeRecord();\n\t\t\t\t\tif (!record) return undefined;\n\t\t\t\t\t// awaitingRevision: feedback was delivered and the model has not\n\t\t\t\t\t// bumped the revision yet — the page shows \"AI revising…\".\n\t\t\t\t\tconst awaiting =\n\t\t\t\t\t\trecord.status === \"aligning\" && deliveredRevisionByAlignment.get(record.id) === record.revision;\n\t\t\t\t\treturn pageView(record, undefined, awaiting);\n\t\t\t\t},\n\t\t\t\tonRoundPost: (post) => handleRoundPost(post),\n\t\t\t},\n\t\t\t{ port: options.serverPort },\n\t\t);\n\t\treturn server;\n\t};\n\n\tconst injectFeedback = async (cached: CachedRound): Promise<void> => {\n\t\tconst message = feedbackMessage(cached.record, cached.result, loadTransitions(api));\n\t\tconst send = api.session?.sendMessage;\n\t\tif (!send) {\n\t\t\tthrow new AlignmentError(\n\t\t\t\t\"invalid-input\",\n\t\t\t\t\"host session does not expose sendMessage; feedback cannot be injected\",\n\t\t\t);\n\t\t}\n\t\tawait send({ customType: \"alignment.feedback\", content: message, display: true }, { triggerTurn: true });\n\t};\n\n\tconst handleRoundPost = async (post: AlignmentRoundPost): Promise<{ status: number; body: unknown }> => {\n\t\tconst record = activeRecord();\n\t\tif (!record || (record.status !== \"aligning\" && record.status !== \"finalizing\")) {\n\t\t\treturn { status: 409, body: { error: \"no alignment in progress\" } };\n\t\t}\n\t\tconst samePost = (candidate: CachedRound): boolean =>\n\t\t\tcandidate.result.alignmentId === record.id && JSON.stringify(candidate.post) === JSON.stringify(post);\n\t\t// Delivered idempotency: an identical replay of an already-delivered\n\t\t// round returns the snapshot without re-injecting.\n\t\tconst pending = cachedRound;\n\t\tif (pending && samePost(pending) && deliveredRoundByAlignment.get(record.id) === pending.result.round) {\n\t\t\treturn {\n\t\t\t\tstatus: 200,\n\t\t\t\tbody: {\n\t\t\t\t\tok: true,\n\t\t\t\t\tdelivered: true,\n\t\t\t\t\tstepConfirmed: pending.result.stepConfirmed,\n\t\t\t\t\trevision: pending.record.revision,\n\t\t\t\t},\n\t\t\t};\n\t\t}\n\t\t// Submitted-but-undelivered replay retries only the injection.\n\t\tif (pending && samePost(pending)) {\n\t\t\ttry {\n\t\t\t\tawait injectFeedback(pending);\n\t\t\t\t// 同主路径:注入可能同步驱动模型回合,不回写回合前快照(走查 2026-10-04)。\n\t\t\t\tfor (const entry of markDelivered(pending.record, pending.result.round)) {\n\t\t\t\t\tapi.session?.appendEntry(TRANSITION_ENTRY, entry);\n\t\t\t\t}\n\t\t\t\tvoid api.publish({\n\t\t\t\t\ttype: \"alignment.changed\",\n\t\t\t\t\tversion: 1,\n\t\t\t\t\tcorrelationId: STATE_ENTRY,\n\t\t\t\t\tdata: loadState(api),\n\t\t\t\t});\n\t\t\t\tstate = loadState(api);\n\t\t\t\tdeliveredRoundByAlignment.set(record.id, pending.result.round);\n\t\t\t\t// 重放路径同主路径:纯确认轮不进入\"AI 修订中\"(走查 2026-10-04)。\n\t\t\t\tconst replayHasContent =\n\t\t\t\t\tpending.result.comments.length > 0 ||\n\t\t\t\t\tpending.result.commentReplies.length > 0 ||\n\t\t\t\t\tpending.result.answers.length > 0 ||\n\t\t\t\t\tpending.result.additions.length > 0;\n\t\t\t\tif (replayHasContent) deliveredRevisionByAlignment.set(record.id, pending.record.revision);\n\t\t\t\treturn {\n\t\t\t\t\tstatus: 200,\n\t\t\t\t\tbody: {\n\t\t\t\t\t\tok: true,\n\t\t\t\t\t\tdelivered: true,\n\t\t\t\t\t\tstepConfirmed: pending.result.stepConfirmed,\n\t\t\t\t\t\trevision: pending.record.revision,\n\t\t\t\t\t},\n\t\t\t\t};\n\t\t\t} catch (error) {\n\t\t\t\treturn {\n\t\t\t\t\tstatus: 503,\n\t\t\t\t\tbody: {\n\t\t\t\t\t\terror: `feedback delivery failed: ${error instanceof Error ? error.message : String(error)}`,\n\t\t\t\t\t\tretry: true,\n\t\t\t\t\t},\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\t\t// Page-initiated rollbacks (走查 2026-10-03) share the POST /round\n\t\t// entry so the submission→injection→delivered protocol is identical.\n\t\tlet outcome: ReturnType<typeof applyRoundPost> | undefined;\n\t\tlet runOutcome: ReturnType<typeof applyAlignmentAdvance> | undefined;\n\t\ttry {\n\t\t\tif (post.action === \"retreat\" || post.action === \"rollback\") {\n\t\t\t\tif (post.baseRevision !== record.revision) {\n\t\t\t\t\treturn {\n\t\t\t\t\t\tstatus: 409,\n\t\t\t\t\t\tbody: { code: \"stale-state\", error: \"page snapshot is stale; reload and retry\" },\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (post.action === \"retreat\") {\n\t\t\t\trunOutcome = applyAlignmentAdvance(state, {\n\t\t\t\t\talignmentId: record.id,\n\t\t\t\t\taction: \"retreat\",\n\t\t\t\t\tstep: post.targetStep,\n\t\t\t\t\tnote: \"回退自确认页:用户在页面上点击了更早的环节\",\n\t\t\t\t});\n\t\t\t} else if (post.action === \"rollback\") {\n\t\t\t\trunOutcome = applyVersionRollback(state, {\n\t\t\t\t\talignmentId: record.id,\n\t\t\t\t\ttargetRevision: post.targetRevision ?? -1,\n\t\t\t\t});\n\t\t\t} else {\n\t\t\t\toutcome = applyRoundPost(record, post);\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tif (error instanceof AlignmentError) {\n\t\t\t\treturn {\n\t\t\t\t\tstatus: error.code === \"stale-state\" ? 409 : 400,\n\t\t\t\t\tbody: { code: error.code, error: error.message },\n\t\t\t\t};\n\t\t\t}\n\t\t\treturn { status: 500, body: { error: error instanceof Error ? error.message : String(error) } };\n\t\t}\n\t\t// Persist the submission first (append-only fact), then attempt delivery.\n\t\tconst record2 = outcome\n\t\t\t? outcome.record\n\t\t\t: (runOutcome!.state.alignments.find((candidate) => candidate.id === record.id) as AlignmentRecord);\n\t\tconst transitions2 = outcome ? outcome.transitions : runOutcome!.transitions;\n\t\tpersist(\n\t\t\t{\n\t\t\t\talignments: state.alignments.map((candidate) => (candidate.id === record2.id ? record2 : candidate)),\n\t\t\t},\n\t\t\ttransitions2,\n\t\t);\n\t\tconst syntheticResult: AlignmentRoundResult = outcome?.result ?? {\n\t\t\talignmentId: record2.id,\n\t\t\tround: record2.roundCount,\n\t\t\tstep: record2.activeStep,\n\t\t\trevision: record2.revision,\n\t\t\tapprovals: [],\n\t\t\tcomments: [],\n\t\t\tcommentReplies: [],\n\t\t\tanswers: [],\n\t\t\tadditions: [],\n\t\t\tstepConfirmed: false,\n\t\t};\n\t\tlet cached: CachedRound = { post, record: record2, transitions: [], result: syntheticResult };\n\t\tif (outcome?.result.stepConfirmed && outcome.record.status === \"completed\") {\n\t\t\t// 终审确认(走查 2026-10-03):no workspace file is written; the\n\t\t\t// compact listing rides the feedback message and `/alignment\n\t\t\t// export` produces a file only on explicit request.\n\t\t\tconst lines = finalBaselineLines(outcome.record);\n\t\t\toutcome.result.finalBaseline = lines;\n\t\t\tcached = { ...cached, result: outcome.result };\n\t\t}\n\t\tcachedRound = cached;\n\t\ttry {\n\t\t\tawait injectFeedback(cached);\n\t\t\t// injectFeedback 的 sendMessage(triggerTurn) 会同步驱动整个模型回合\n\t\t\t//(agent-session sendCustomMessage → _runAgentPrompt):回合内的\n\t\t\t// alignment_set 已把修订落账 entries。此处若回写回合前快照,会把模型\n\t\t\t// 刚提交的修订整体抹掉(走查 2026-10-04 dogfood:细节步 10 块被还原成\n\t\t\t// 空步)。只追加 round.delivered 审计条目,并从 entries 重建内存态。\n\t\t\tfor (const entry of markDelivered(cached.record, cached.result.round)) {\n\t\t\t\tapi.session?.appendEntry(TRANSITION_ENTRY, entry);\n\t\t\t}\n\t\t\tvoid api.publish({ type: \"alignment.changed\", version: 1, correlationId: STATE_ENTRY, data: loadState(api) });\n\t\t\tstate = loadState(api);\n\t\t\tdeliveredRoundByAlignment.set(cached.record.id, cached.result.round);\n\t\t\t// 只有携带内容反馈(批注/回复/答案/补充)的轮次才进入\"AI 修订中\":\n\t\t\t// 纯确认轮模型正确地不重发块,revision 不变——若也标记 awaiting,\n\t\t\t// 页面会永远钉在机器人等待屏,用户反而无法确认剩余块(走查 2026-10-04)。\n\t\t\tconst hasContentFeedback =\n\t\t\t\tpost.comments.length > 0 ||\n\t\t\t\tpost.commentReplies.length > 0 ||\n\t\t\t\tpost.answers.length > 0 ||\n\t\t\t\tpost.additions.length > 0;\n\t\t\tif (hasContentFeedback) deliveredRevisionByAlignment.set(cached.record.id, cached.record.revision);\n\t\t\treturn {\n\t\t\t\tstatus: 200,\n\t\t\t\tbody: {\n\t\t\t\t\tok: true,\n\t\t\t\t\tdelivered: true,\n\t\t\t\t\tstepConfirmed: cached.result.stepConfirmed,\n\t\t\t\t\trevision: cached.record.revision,\n\t\t\t\t},\n\t\t\t};\n\t\t} catch (error) {\n\t\t\treturn {\n\t\t\t\tstatus: 503,\n\t\t\t\tbody: {\n\t\t\t\t\terror: `feedback delivery failed: ${error instanceof Error ? error.message : String(error)}`,\n\t\t\t\t\tretry: true,\n\t\t\t\t},\n\t\t\t};\n\t\t}\n\t};\n\n\tconst runSet = (input: AlignmentSetInput): Record<string, unknown> => {\n\t\tconst run: EngineRun = applyAlignmentSet(state, input);\n\t\tconst record = run.state.alignments.find((candidate) => candidate.id === input.id);\n\t\tpersist(run.state, run.transitions);\n\t\tconst warning =\n\t\t\trecord?.goalId && !goalKnownToSession(api, record.goalId)\n\t\t\t\t? `goalId \"${record.goalId}\" does not match any goal in this session's goal state; the alignment keeps the soft reference`\n\t\t\t\t: undefined;\n\t\treturn { state, alignmentId: input.id, ...(warning ? { warning } : {}) };\n\t};\n\n\tconst setTool = api.registerTool({\n\t\tname: \"alignment_set\",\n\t\tlabel: \"Set alignment\",\n\t\tdescription:\n\t\t\t\"Create or update a requirement alignment task: full block set of the active step (goal→detail→design funnel). Unchanged blocks inherit user approval by content fingerprint\",\n\t\tparameters: setSchema,\n\t\tpromptGuidelines: PROMPT_GUIDELINES,\n\t\trenderResult: alignmentToolResultRenderer,\n\t\t// 双调用约定(goal 插件同款,走查 2026-10-04):会话路径传\n\t\t// (toolCallId, params, signal, onUpdate),runtime facade 路径传\n\t\t// (input, context?, signal?)——second 缺省时取 first。\n\t\texecute: async (first: unknown, second?: unknown) => {\n\t\t\tconst input = toolInput(first, second);\n\t\t\treturn runSet(input as unknown as AlignmentSetInput);\n\t\t},\n\t});\n\n\tconst roundTool = api.registerTool({\n\t\tname: \"alignment_round\",\n\t\tlabel: \"Open alignment page\",\n\t\tdescription:\n\t\t\t\"Open (or refresh) the local confirmation page for the active alignment and return its URL plus progress facts. Non-blocking: feedback arrives later as an alignment.feedback message\",\n\t\tparameters: roundSchema,\n\t\tpromptGuidelines: PROMPT_GUIDELINES,\n\t\trenderResult: alignmentToolResultRenderer,\n\t\texecute: async (first: unknown, second?: unknown) => {\n\t\t\tconst input = toolInput(first, second);\n\t\t\tconst id = typeof input.alignmentId === \"string\" ? input.alignmentId : \"\";\n\t\t\tconst record = state.alignments.find((candidate) => candidate.id === id);\n\t\t\tif (!record) throw new Error(`unknown alignment: ${id}`);\n\t\t\tif (record.status !== \"aligning\") throw new Error(`alignment is ${record.status}: ${id}`);\n\t\t\tif (!api.session?.sendMessage) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t\"host session does not expose sendMessage; the alignment confirmation page cannot deliver feedback on this host\",\n\t\t\t\t);\n\t\t\t}\n\t\t\tconst running = await ensureServer();\n\t\t\tconst snapshot = gate(record);\n\t\t\treturn {\n\t\t\t\tstate,\n\t\t\t\talignmentId: record.id,\n\t\t\t\turl: running.url,\n\t\t\t\tstep: record.activeStep,\n\t\t\t\tround: record.roundCount,\n\t\t\t\trevision: record.revision,\n\t\t\t\tprogress: {\n\t\t\t\t\tunapproved: snapshot.unapproved,\n\t\t\t\t\topenComments: snapshot.openComments,\n\t\t\t\t\tpendingAdditions: snapshot.pendingAdditions,\n\t\t\t\t\tallGreen: snapshot.allGreen,\n\t\t\t\t},\n\t\t\t};\n\t\t},\n\t});\n\n\tconst advanceTool = api.registerTool({\n\t\tname: \"alignment_advance\",\n\t\tlabel: \"Advance alignment\",\n\t\tdescription:\n\t\t\t\"inspect (read-only status/gate/baseline), retreat (roll back to an earlier step, resets downstream confirmations), or cancel the alignment\",\n\t\tparameters: advanceSchema,\n\t\tpromptGuidelines: PROMPT_GUIDELINES,\n\t\trenderResult: alignmentToolResultRenderer,\n\t\texecute: async (first: unknown, second?: unknown) => {\n\t\t\tconst input = toolInput(first, second) as unknown as AdvanceInput;\n\t\t\tif (input.action === \"inspect\") {\n\t\t\t\tconst record = state.alignments.find((candidate) => candidate.id === input.alignmentId);\n\t\t\t\tif (!record) throw new Error(`unknown alignment: ${input.alignmentId}`);\n\t\t\t\treturn {\n\t\t\t\t\tstate,\n\t\t\t\t\talignmentId: record.id,\n\t\t\t\t\tgate: gate(record),\n\t\t\t\t\tbaseline: record.status === \"completed\" ? finalBaselineLines(record) : undefined,\n\t\t\t\t};\n\t\t\t}\n\t\t\tconst run = applyAlignmentAdvance(state, input);\n\t\t\tpersist(run.state, run.transitions);\n\t\t\treturn { state, alignmentId: input.alignmentId };\n\t\t},\n\t});\n\n\tconst command = api.registerCommand({\n\t\tname: \"alignment\",\n\t\tdescription:\n\t\t\t\"Show this session's alignments (progress, blockers, audit log); `export [id] [path]` writes a self-contained read-only HTML snapshot\",\n\t\texecute: async (args: string, context?: { cwd?: string }): Promise<CapabilityCommandResult> => {\n\t\t\ttry {\n\t\t\t\tconst parts = args\n\t\t\t\t\t.trim()\n\t\t\t\t\t.split(/\\s+/)\n\t\t\t\t\t.filter((part) => part !== \"\");\n\t\t\t\tif (parts.length === 0) return { status: \"success\", message: listLines(state) };\n\t\t\t\tif (parts[0] === \"why\") {\n\t\t\t\t\tconst record =\n\t\t\t\t\t\tstate.alignments.find((candidate) => candidate.status === \"aligning\") ?? state.alignments.at(-1);\n\t\t\t\t\tif (!record) return { status: \"error\", message: \"no alignments in this session\" };\n\t\t\t\t\tconst extra =\n\t\t\t\t\t\tcachedRound && deliveredRoundByAlignment.get(record.id) !== cachedRound.result.round\n\t\t\t\t\t\t\t? `\\nundelivered round: r${cachedRound.result.round} (injection failed; the page can retry)`\n\t\t\t\t\t\t\t: \"\";\n\t\t\t\t\treturn { status: \"success\", message: whyLines(record) + extra };\n\t\t\t\t}\n\t\t\t\tif (parts[0] === \"log\") {\n\t\t\t\t\tconst count = Number.parseInt(parts[1] ?? \"20\", 10);\n\t\t\t\t\treturn {\n\t\t\t\t\t\tstatus: \"success\",\n\t\t\t\t\t\tmessage: logLines(loadTransitions(api), Number.isFinite(count) && count > 0 ? count : 20),\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t\tif (parts[0] === \"export\") {\n\t\t\t\t\tconst id = parts[1];\n\t\t\t\t\tconst record = id\n\t\t\t\t\t\t? state.alignments.find((candidate) => candidate.id === id)\n\t\t\t\t\t\t: (state.alignments.find((candidate) => candidate.status === \"aligning\") ??\n\t\t\t\t\t\t\tstate.alignments.find((candidate) => candidate.status === \"finalizing\") ??\n\t\t\t\t\t\t\tstate.alignments.at(-1));\n\t\t\t\t\tif (!record) return { status: \"error\", message: `unknown alignment: ${id ?? \"(none in session)\"}` };\n\t\t\t\t\t// Explicit user request — the only path that writes a file.\n\t\t\t\t\tconst target = exportTargetPath(context?.cwd ?? process.cwd(), record, parts[2]);\n\t\t\t\t\tconst written = writeAlignmentExport(record, loadTransitions(api), target);\n\t\t\t\t\treturn {\n\t\t\t\t\t\tstatus: \"success\",\n\t\t\t\t\t\tmessage: `exported: ${written}`,\n\t\t\t\t\t\tlinks: [{ label: written, url: `file:///${written.split(\"\\\\\").join(\"/\")}` }],\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t\treturn {\n\t\t\t\t\tstatus: \"error\",\n\t\t\t\t\tmessage: \"Usage: /alignment | /alignment why | /alignment log [N] | /alignment export [id] [path]\",\n\t\t\t\t};\n\t\t\t} catch (error) {\n\t\t\t\treturn { status: \"error\", message: error instanceof Error ? error.message : String(error) };\n\t\t\t}\n\t\t},\n\t});\n\n\tconst stopServer = (): void => {\n\t\tconst stopping = server;\n\t\tserver = undefined;\n\t\tif (stopping) void stopping.stop().catch(() => undefined);\n\t};\n\n\t// The command registration doubles as the teardown hook for the local\n\t// confirmation server (plugin dispose must release the port).\n\tconst commandWithTeardown: DisposableRegistration = {\n\t\tid: command.id,\n\t\tkind: command.kind,\n\t\tdispose: () => {\n\t\t\tvoid command.dispose();\n\t\t\tstopServer();\n\t\t},\n\t};\n\n\treturn [setTool, roundTool, advanceTool, commandWithTeardown];\n}\n"]}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,KAAK,EAAE,aAAa,EAA2B,sBAAsB,EAAE,MAAM,yBAAyB,CAAC;AAuC9G,MAAM,WAAW,0BAA0B;IAC1C,oFAAoF;IACpF,UAAU,CAAC,EAAE,MAAM,CAAC;CACpB;AAqTD,wBAAgB,gBAAgB,CAC/B,GAAG,EAAE,aAAa,EAClB,OAAO,GAAE,0BAA+B,GACtC,SAAS,sBAAsB,EAAE,CA2YnC","sourcesContent":["/**\n * Alignment capability plugin (M1 of `docs/design/需求对齐插件设计.md`): a\n * three-step requirement-alignment funnel (objective → detail → design) with\n * block-level bidirectional feedback confirmed on a local HTML page.\n *\n * Persistence protocol, structurally identical to the goal/plan/todo/workflow\n * plugins: append-only `alignment.state` full snapshots (the single rebuild\n * source) plus one `alignment.transition` audit entry per conversion,\n * announced as `alignment.changed` (version 1, correlationId\n * \"alignment.state\", data = the complete AlignmentState snapshot).\n *\n * The round wait is non-blocking (设计 §5 总则 8): alignment_round returns the\n * page URL immediately; page feedback arrives as a `alignment.feedback`\n * custom message injected through SessionAPI.sendMessage (triggerTurn), and a\n * round only closes after the injection succeeded (`round.delivered`,\n * terminal audit D1).\n */\n\nimport type { CapabilityAPI, CapabilityCommandResult, DisposableRegistration } from \"@agent-forge/plugin-sdk\";\nimport { Type } from \"typebox\";\nimport {\n\ttype AdvanceInput,\n\ttype AlignmentSetInput,\n\tactiveStep,\n\tapplyAlignmentAdvance,\n\tapplyAlignmentSet,\n\tapplyRoundPost,\n\tapplyVersionRollback,\n\ttype EngineRun,\n\tfinalBaselineLines,\n\tgate,\n\tmarkDelivered,\n} from \"./engine.ts\";\nimport { exportTargetPath, writeAlignmentExport } from \"./export.ts\";\nimport { type AlignmentServer, startAlignmentServer } from \"./http-server.ts\";\nimport { alignmentToolResultRenderer } from \"./render.ts\";\nimport {\n\tAlignmentError,\n\ttype AlignmentRecord,\n\ttype AlignmentRoundPost,\n\ttype AlignmentRoundResult,\n\ttype AlignmentState,\n\ttype AlignmentTransitionEntry,\n\ttype PendingItem,\n} from \"./types.ts\";\n\nconst STATE_ENTRY = \"alignment.state\";\nconst TRANSITION_ENTRY = \"alignment.transition\";\nconst GOAL_STATE_ENTRY = \"goal.state\";\n/** Round post outcomes cached until delivered — the retry-injection window (终审 D1). */\ninterface CachedRound {\n\tpost: AlignmentRoundPost;\n\trecord: AlignmentRecord;\n\ttransitions: AlignmentTransitionEntry[];\n\tresult: AlignmentRoundResult;\n}\n\nexport interface AlignmentCapabilityOptions {\n\t/** Injection seam for deterministic tests; production binds an OS-assigned port. */\n\tserverPort?: number;\n}\n\nfunction isObject(value: unknown): value is Record<string, unknown> {\n\treturn value !== null && typeof value === \"object\" && !Array.isArray(value);\n}\n\n/**\n * 双调用约定(走查 2026-10-04,goal 插件同款问题的严谨版):会话路径以\n * (toolCallId, params, signal, onUpdate) 调用插件工具——first 是调用 id 字符串;\n * runtime facade 以 (input, context?, signal?) 调用——first 是入参对象。\n * 按 first 的类型区分,两条路径(含 runtime 携带 context)都取到真实入参。\n */\nfunction toolInput(first: unknown, second?: unknown): Record<string, unknown> {\n\tif (typeof first === \"string\") {\n\t\tif (!isObject(second)) return {};\n\t\treturn second;\n\t}\n\tif (!isObject(first)) throw new Error(\"alignment tool input must be an object\");\n\treturn first;\n}\n\nfunction loadState(api: CapabilityAPI): AlignmentState {\n\tconst entries = api.session?.getBranchEntries() ?? [];\n\tconst entry = [...entries].reverse().find((item) => item.customType === STATE_ENTRY);\n\tif (!entry?.data || !isObject(entry.data)) return { alignments: [] };\n\tconst data = entry.data as { alignments?: unknown };\n\treturn { alignments: Array.isArray(data.alignments) ? [...(data.alignments as AlignmentRecord[])] : [] };\n}\n\nfunction loadTransitions(api: CapabilityAPI): AlignmentTransitionEntry[] {\n\tconst entries = api.session?.getBranchEntries() ?? [];\n\treturn entries\n\t\t.filter((item) => item.customType === TRANSITION_ENTRY)\n\t\t.map((item) => item.data as AlignmentTransitionEntry)\n\t\t.filter((item): item is AlignmentTransitionEntry => isObject(item));\n}\n\n/** Advisory goalId check (#10 soft-reference discipline, goal/plan precedent). */\nfunction goalKnownToSession(api: CapabilityAPI, goalId: string): boolean {\n\tconst entries = api.session?.getBranchEntries() ?? [];\n\tfor (let index = entries.length - 1; index >= 0; index -= 1) {\n\t\tconst entry = entries[index];\n\t\tif (entry.customType !== GOAL_STATE_ENTRY) continue;\n\t\tconst data = entry.data;\n\t\tif (!isObject(data)) return false;\n\t\tconst goals = data.goals;\n\t\tif (!Array.isArray(goals)) return false;\n\t\treturn goals.some((goal) => isObject(goal) && goal.id === goalId);\n\t}\n\treturn false;\n}\n\n/** Page projection (state.json): everything the fixed template renders. */\nfunction pageView(\n\trecord: AlignmentRecord,\n\tbaselineFile: string | undefined,\n\tawaitingRevision: boolean,\n): Record<string, unknown> {\n\tconst snapshot = gate(record);\n\t// gate already validated the active step exists (it throws otherwise).\n\tconst blocks = activeStep(record).blocks;\n\t// 终审/终态头部展示跨步总口径(走查 2026-10-03):completed 后仍按当前步\n\t// 计数会显示「已确认 0/1」这类误导数字。\n\tconst countedBlocks = record.status === \"aligning\" ? blocks : record.steps.flatMap((s) => s.blocks);\n\treturn {\n\t\talignmentId: record.id,\n\t\ttitle: record.title,\n\t\tgoalId: record.goalId,\n\t\tstatus: record.status,\n\t\trevision: record.revision,\n\t\tround: record.roundCount,\n\t\tactiveStep: record.activeStep,\n\t\tsteps: record.steps.map((step) => ({\n\t\t\tstep: step.step,\n\t\t\tstatus: step.status,\n\t\t\tblocks: step.blocks.map((block) => ({\n\t\t\t\tid: block.id,\n\t\t\t\tkind: block.kind,\n\t\t\t\tcontent: block.content,\n\t\t\t\trationale: block.rationale,\n\t\t\t\timpact: block.impact,\n\t\t\t\tstatus: block.status,\n\t\t\t\tmodifiedInRound: block.modifiedInRound,\n\t\t\t\tdraftAnswer: block.draftAnswer,\n\t\t\t\tcomments: block.comments,\n\t\t\t})),\n\t\t})),\n\t\tgate: {\n\t\t\t...snapshot,\n\t\t\tapprovedCount: countedBlocks.filter((block) => block.status === \"approved\").length,\n\t\t\tblockCount: countedBlocks.length,\n\t\t},\n\t\tpendingFeedback: record.pendingFeedback,\n\t\t// Version snapshots for the read-only history switcher (走查 2026-10-03).\n\t\tversions: record.versions ?? [],\n\t\tawaitingRevision,\n\t\tbaselineFile,\n\t};\n}\n\nfunction blockStateLine(block: AlignmentRecord[\"steps\"][number][\"blocks\"][number]): string {\n\tconst state = block.status === \"approved\" ? \"已确认\" : \"待确认\";\n\tconst first = block.content.split(\"\\n\")[0]?.slice(0, 80) ?? \"\";\n\tconst notes: string[] = [];\n\tfor (const comment of block.comments) {\n\t\tif (comment.status !== \"open\") continue;\n\t\tnotes.push(\n\t\t\tcomment.author === \"assistant\"\n\t\t\t\t? `AI疑问待回应:${comment.note.slice(0, 40)}`\n\t\t\t\t: `用户批注:${comment.note.slice(0, 40)}`,\n\t\t);\n\t}\n\treturn `- ${block.id}[${block.kind}|${state}] ${first}${notes.length ? `(${notes.join(\";\")})` : \"\"}`;\n}\n\nfunction historyLines(transitions: AlignmentTransitionEntry[]): string {\n\tif (transitions.length === 0) return \"(无)\";\n\treturn transitions\n\t\t.slice(-20)\n\t\t.map((entry) => {\n\t\t\tconst where = entry.step ? `${entry.step} ` : \"\";\n\t\t\treturn `rev${entry.revision} ${where}${entry.event}${entry.reason.detail ? `(${entry.reason.detail.slice(0, 60)})` : \"\"}`;\n\t\t})\n\t\t.join(\"\\n\");\n}\n\nfunction feedbackMessage(\n\trecord: AlignmentRecord,\n\tresult: AlignmentRoundResult,\n\ttransitions: AlignmentTransitionEntry[],\n): string {\n\tconst snapshot = gate(record);\n\tconst lines: string[] = [];\n\tlines.push(\n\t\t`[alignment.feedback] ${result.alignmentId} 第 ${result.round} 轮(${result.step} 步,revision ${result.revision},status ${record.status})`,\n\t);\n\tlines.push(\"== 本轮反馈 ==\");\n\tif (result.approvals.length > 0) lines.push(`确认块:${result.approvals.join(\", \")}`);\n\tfor (const comment of result.comments) {\n\t\tlines.push(\n\t\t\t`用户批注[${comment.blockId}]${comment.escalate ? \"(上游问题)\" : \"\"}:「${comment.quote}」→ ${comment.note}`,\n\t\t);\n\t}\n\tfor (const reply of result.commentReplies) {\n\t\tlines.push(\n\t\t\treply.dismiss\n\t\t\t\t? `AI 疑问 ${reply.commentId}:用户标记不重要`\n\t\t\t\t: `AI 疑问 ${reply.commentId} 的回答:${reply.answer}`,\n\t\t);\n\t}\n\tfor (const answer of result.answers) {\n\t\tlines.push(`补充答案[${answer.blockId}]:${answer.value}`);\n\t}\n\tfor (const addition of result.additions) {\n\t\tlines.push(`自由补充:${addition}`);\n\t}\n\tif (result.stepConfirmed) {\n\t\tif (record.status === \"completed\") {\n\t\t\tlines.push(\"用户已在终审总览确认基线——对齐完成。请输出最终基线总结(plan 输入)。\");\n\t\t\tif (result.finalBaseline) {\n\t\t\t\tlines.push(\"最终基线紧凑清单:\");\n\t\t\t\tfor (const line of result.finalBaseline) {\n\t\t\t\t\tlines.push(` [${line.kind}] ${line.id}: ${line.line}`);\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\tlines.push(\"用户已确认本步——基线锁定。请 alignment_set 出下一步块集并 alignment_round 刷新。\");\n\t\t}\n\t}\n\tlines.push(\"== 当前块集(全量状态)==\");\n\tif (record.status === \"finalizing\") {\n\t\tlines.push(\"三步基线已全部锁定,等待用户终审总览确认;此阶段无需你操作。\");\n\t} else {\n\t\tfor (const step of record.steps) {\n\t\t\tif (step.blocks.length === 0) continue;\n\t\t\tlines.push(`[${step.step}|${step.status}]`);\n\t\t\tfor (const block of step.blocks) lines.push(blockStateLine(block));\n\t\t}\n\t\tlines.push(\n\t\t\t`待办:${snapshot.unapproved} 块待确认、${snapshot.openComments} 批注未清、${snapshot.pendingAdditions} 补充未落账。`,\n\t\t);\n\t}\n\tlines.push(\"== 历史轮次(revision 锚点)==\");\n\tlines.push(historyLines(transitions));\n\treturn lines.join(\"\\n\");\n}\n\nconst PROMPT_GUIDELINES: readonly string[] = [\n\t\"进入分流(预检规则):用户显式要求对齐时直接进入;否则先做零成本预检——列出缺失信息、被迫假设、矛盾歧义。三项全空则一行结论直接出方案(跳过证据必须可见,禁止静默跳过);有任一项则列出要点并建议对齐,用户说直接做则跳过、但未决假设须在方案中显式标注。预检清单在对齐时直接作为第一轮块种子。\",\n\t\"三步铁律:objective 只谈方向与非目标(≤10 块);detail 只谈业务规则/公式/数据流/异常(禁止技术选型);design 谈技术方案且不得与已锁定基线矛盾,发现矛盾必须停下向用户提出。\",\n\t\"视觉对齐(涉及用户可见界面的任务):design 步必须产出 visual 视觉方向块——按六节契约(风格宣言/配色角色表/布局与层级策略/文案密度预算/视觉验收清单/明确不做项)逐节落块,建议委派 design-proposer 出厂角色产出(subagent_run role=design-proposer,其指令内嵌保底资产);纯后端/重构任务不产 visual 块;实现完成后渲染产物交 visual-reviewer 角色做视觉验收(防丑下限)。\",\n\t\"块纪律:假设单独成 assumption 块;缺信息产 missing 块而不是脑补;可自查的先取证落 fact;assistant 批注只用于真实不确定点(公式口径、二义表述、潜在矛盾、与基线冲突)。\",\n\t\"修订纪律:最小改动已确认的块(内容不变即继承确认);每次 alignment_set 之后必须跟 alignment_round 告知用户去看新版;用户批注的 quote 匹配失败时向用户说明而不是猜。\",\n\t\"填空落账:收到补充答案(补充答案[blockId])后,下一次 alignment_set 必须把答案重写进对应块内容并转为 fact/decision(missing 块不得带着未并入的答案被确认锁定);注入消息的「当前块集(全量状态)」是权威现状,以它为准做最小修订。\",\n\t\"终审阶段(status finalizing):三步基线已全部锁定,页面进入只读总览,唯一动作是用户最终确认——此阶段不要调用 alignment_set;收到终审确认消息(alignment completed)即视为开发授权:先输出一行极简基线摘要,然后直接按基线实现——用 plan/todo 把基线拆成可执行任务,实现并自测,完成后向用户报告结果与验收方式。不要停在基线总结等用户再次指令(dogfood 2026-10-04:等指令会打断对齐→开发衔接)。\",\n\t\"页面回退:用户可在页面上把任务回退到更早环节(step.retreated,后续环节作废重走)或把当前步回退到历史版本(version.rolled-back,当前未确认版本丢弃、批注保留)。收到这类消息后,以注入消息里的全量块集为准重新修订,不要复用回退前的块集。\",\n];\n\nconst setSchema = Type.Object({\n\tid: Type.String({ description: \"Stable alignment id; charset [A-Za-z0-9._-], no leading dot\" }),\n\ttitle: Type.Optional(Type.String({ description: \"Human-readable alignment title\" })),\n\tgoalId: Type.Optional(Type.String({ description: \"Soft goal reference; unknown ids only warn\" })),\n\trevision: Type.Optional(Type.Integer({ description: \"Monotonic revision; must exceed the stored one\", minimum: 0 })),\n\tblocks: Type.Array(\n\t\tType.Object({\n\t\t\tid: Type.String({ description: \"Stable block id within the step\" }),\n\t\t\tkind: Type.Union(\n\t\t\t\t[\n\t\t\t\t\tType.Literal(\"fact\"),\n\t\t\t\t\tType.Literal(\"assumption\"),\n\t\t\t\t\tType.Literal(\"decision\"),\n\t\t\t\t\tType.Literal(\"missing\"),\n\t\t\t\t\tType.Literal(\"visual\"),\n\t\t\t\t],\n\t\t\t\t{ description: \"fact=取证 assumption=假设 decision=决策 missing=待补充\" },\n\t\t\t),\n\t\t\tcontent: Type.String({ description: \"Block content (markdown text, ≤8192 chars)\" }),\n\t\t\trationale: Type.Optional(Type.String({ description: \"Why this decision/assumption (≤2048 chars)\" })),\n\t\t\timpact: Type.Optional(Type.Array(Type.String(), { description: \"Affected modules/files/interfaces\" })),\n\t\t\tcomments: Type.Optional(\n\t\t\t\tType.Array(\n\t\t\t\t\tType.Object({\n\t\t\t\t\t\tid: Type.String(),\n\t\t\t\t\t\tnote: Type.String({ description: \"Assistant question; only real uncertainty\" }),\n\t\t\t\t\t\tquote: Type.Optional(Type.String()),\n\t\t\t\t\t}),\n\t\t\t\t\t{ description: \"New assistant comments (AI 主动标注的不确定点)\" },\n\t\t\t\t),\n\t\t\t),\n\t\t\tcommentResolutions: Type.Optional(\n\t\t\t\tType.Array(\n\t\t\t\t\tType.Object({\n\t\t\t\t\t\tcommentId: Type.String(),\n\t\t\t\t\t\tkind: Type.Union([Type.Literal(\"answered\"), Type.Literal(\"dismissed\"), Type.Literal(\"incorporated\")]),\n\t\t\t\t\t\ttext: Type.Optional(Type.String()),\n\t\t\t\t\t}),\n\t\t\t\t\t{\n\t\t\t\t\t\tdescription:\n\t\t\t\t\t\t\t\"Resolutions for existing comments (user comments may only be resolved, never rewritten)\",\n\t\t\t\t\t},\n\t\t\t\t),\n\t\t\t),\n\t\t}),\n\t\t{ description: \"Full block set of the active step (全量提交;未变块按内容指纹继承确认)\" },\n\t),\n});\n\nconst roundSchema = Type.Object({\n\talignmentId: Type.String({ description: \"Alignment id to open the confirmation page for\" }),\n});\n\nconst advanceSchema = Type.Object({\n\talignmentId: Type.String(),\n\taction: Type.Union([Type.Literal(\"inspect\"), Type.Literal(\"retreat\"), Type.Literal(\"cancel\")]),\n\tstep: Type.Optional(\n\t\tType.Union([Type.Literal(\"objective\"), Type.Literal(\"detail\"), Type.Literal(\"design\")], {\n\t\t\tdescription: \"Retreat target; must be an earlier step\",\n\t\t}),\n\t),\n\tnote: Type.Optional(Type.String({ description: \"Retreat reason (required for retreat)\" })),\n});\n\nfunction pendingText(items: PendingItem[]): string {\n\tif (items.length === 0) return \"nothing pending\";\n\tconst reasons = items.map((item) => `${item.blockId}(${item.reason})`);\n\treturn reasons.join(\" \");\n}\n\nfunction listLines(state: AlignmentState): string {\n\tif (state.alignments.length === 0) return \"no alignments in this session; create one with alignment_set\";\n\tconst lines = [`alignments: ${state.alignments.length}`];\n\tfor (const record of state.alignments) {\n\t\tconst snapshot = gate(record);\n\t\tlines.push(\n\t\t\t`- ${record.id} [${record.status} → ${record.goalId ?? \"-\"}] ${record.title} · ${record.activeStep} r${record.roundCount} · ${snapshot.unapproved} pending / ${snapshot.openComments} open`,\n\t\t);\n\t}\n\treturn lines.join(\"\\n\");\n}\n\nfunction whyLines(record: AlignmentRecord): string {\n\tconst snapshot = gate(record);\n\tconst lines = [`${record.id} · ${record.activeStep} · round ${record.roundCount}`];\n\tif (record.status !== \"aligning\") {\n\t\tlines.push(`status ${record.status} — nothing to wait for`);\n\t\treturn lines.join(\"\\n\");\n\t}\n\tif (snapshot.allGreen) {\n\t\tlines.push(\"ALL GREEN — waiting for the user to click 确认完成 on the page\");\n\t\treturn lines.join(\"\\n\");\n\t}\n\tlines.push(`pending: ${pendingText(snapshot.pending)}`);\n\tif (snapshot.pendingAdditions > 0) {\n\t\tlines.push(`undelivered additions: ${record.pendingFeedback?.additions.join(\" | \")}`);\n\t}\n\treturn lines.join(\"\\n\");\n}\n\nfunction logLines(transitions: AlignmentTransitionEntry[], count: number): string {\n\tif (transitions.length === 0) return \"no alignment transitions recorded\";\n\tconst slice = transitions.slice(-count).reverse();\n\treturn slice\n\t\t.map((entry, index) => {\n\t\t\tconst where = entry.step ? `${entry.step} ` : \"\";\n\t\t\treturn `${slice.length - index}. [r${entry.round ?? \"-\"} rev${entry.revision}] ${where}${entry.event} ${entry.reason.code}${entry.reason.detail ? ` — ${entry.reason.detail}` : \"\"}`;\n\t\t})\n\t\t.join(\"\\n\");\n}\n\nexport function createCapability(\n\tapi: CapabilityAPI,\n\toptions: AlignmentCapabilityOptions = {},\n): readonly DisposableRegistration[] {\n\tlet state = loadState(api);\n\tlet server: AlignmentServer | undefined;\n\tlet cachedRound: CachedRound | undefined;\n\tconst deliveredRoundByAlignment = new Map<string, number>();\n\t/** Revision at last successful injection — awaitingRevision = delivered and not yet superseded by a set. */\n\tconst deliveredRevisionByAlignment = new Map<string, number>();\n\n\tconst persist = (next: AlignmentState, transitions: AlignmentTransitionEntry[]): AlignmentState => {\n\t\tstate = next;\n\t\tapi.session?.appendEntry(STATE_ENTRY, state);\n\t\tfor (const entry of transitions) api.session?.appendEntry(TRANSITION_ENTRY, entry);\n\t\tvoid api.publish({ type: \"alignment.changed\", version: 1, correlationId: STATE_ENTRY, data: state });\n\t\treturn state;\n\t};\n\n\tconst activeRecord = (): AlignmentRecord | undefined =>\n\t\tstate.alignments.find((record) => record.status === \"aligning\") ??\n\t\t[...state.alignments].reverse().find((record) => record.status !== \"aligning\");\n\n\tconst ensureServer = async (): Promise<AlignmentServer> => {\n\t\t// 页面生命周期(走查 2026-10-04 用户裁决):服务随第一个 alignment_round\n\t\t// 启动后常驻到插件 dispose(会话关闭);终态对齐的页面保持可查看,直到\n\t\t// 下一次对齐在同一 URL 上覆盖内容。不再做终态 idle 停服。\n\t\tif (server) return server;\n\t\tserver = await startAlignmentServer(\n\t\t\t{\n\t\t\t\tgetState: () => {\n\t\t\t\t\tconst record = activeRecord();\n\t\t\t\t\tif (!record) return undefined;\n\t\t\t\t\t// awaitingRevision: feedback was delivered and the model has not\n\t\t\t\t\t// bumped the revision yet — the page shows \"AI revising…\".\n\t\t\t\t\tconst awaiting =\n\t\t\t\t\t\trecord.status === \"aligning\" && deliveredRevisionByAlignment.get(record.id) === record.revision;\n\t\t\t\t\treturn pageView(record, undefined, awaiting);\n\t\t\t\t},\n\t\t\t\tonRoundPost: (post) => handleRoundPost(post),\n\t\t\t},\n\t\t\t{ port: options.serverPort },\n\t\t);\n\t\treturn server;\n\t};\n\n\tconst injectFeedback = async (cached: CachedRound): Promise<void> => {\n\t\tconst message = feedbackMessage(cached.record, cached.result, loadTransitions(api));\n\t\tconst send = api.session?.sendMessage;\n\t\tif (!send) {\n\t\t\tthrow new AlignmentError(\n\t\t\t\t\"invalid-input\",\n\t\t\t\t\"host session does not expose sendMessage; feedback cannot be injected\",\n\t\t\t);\n\t\t}\n\t\tawait send({ customType: \"alignment.feedback\", content: message, display: true }, { triggerTurn: true });\n\t};\n\n\tconst handleRoundPost = async (post: AlignmentRoundPost): Promise<{ status: number; body: unknown }> => {\n\t\tconst record = activeRecord();\n\t\tif (!record || (record.status !== \"aligning\" && record.status !== \"finalizing\")) {\n\t\t\treturn { status: 409, body: { error: \"no alignment in progress\" } };\n\t\t}\n\t\tconst samePost = (candidate: CachedRound): boolean =>\n\t\t\tcandidate.result.alignmentId === record.id && JSON.stringify(candidate.post) === JSON.stringify(post);\n\t\t// Delivered idempotency: an identical replay of an already-delivered\n\t\t// round returns the snapshot without re-injecting.\n\t\tconst pending = cachedRound;\n\t\tif (pending && samePost(pending) && deliveredRoundByAlignment.get(record.id) === pending.result.round) {\n\t\t\treturn {\n\t\t\t\tstatus: 200,\n\t\t\t\tbody: {\n\t\t\t\t\tok: true,\n\t\t\t\t\tdelivered: true,\n\t\t\t\t\tstepConfirmed: pending.result.stepConfirmed,\n\t\t\t\t\trevision: pending.record.revision,\n\t\t\t\t},\n\t\t\t};\n\t\t}\n\t\t// Submitted-but-undelivered replay retries only the injection.\n\t\tif (pending && samePost(pending)) {\n\t\t\ttry {\n\t\t\t\tawait injectFeedback(pending);\n\t\t\t\t// 同主路径:注入可能同步驱动模型回合,不回写回合前快照(走查 2026-10-04)。\n\t\t\t\tfor (const entry of markDelivered(pending.record, pending.result.round)) {\n\t\t\t\t\tapi.session?.appendEntry(TRANSITION_ENTRY, entry);\n\t\t\t\t}\n\t\t\t\tvoid api.publish({\n\t\t\t\t\ttype: \"alignment.changed\",\n\t\t\t\t\tversion: 1,\n\t\t\t\t\tcorrelationId: STATE_ENTRY,\n\t\t\t\t\tdata: loadState(api),\n\t\t\t\t});\n\t\t\t\tstate = loadState(api);\n\t\t\t\tdeliveredRoundByAlignment.set(record.id, pending.result.round);\n\t\t\t\t// 重放路径同主路径:纯确认轮不进入\"AI 修订中\"(走查 2026-10-04)。\n\t\t\t\tconst replayHasContent =\n\t\t\t\t\tpending.result.comments.length > 0 ||\n\t\t\t\t\tpending.result.commentReplies.length > 0 ||\n\t\t\t\t\tpending.result.answers.length > 0 ||\n\t\t\t\t\tpending.result.additions.length > 0;\n\t\t\t\tif (replayHasContent) deliveredRevisionByAlignment.set(record.id, pending.record.revision);\n\t\t\t\treturn {\n\t\t\t\t\tstatus: 200,\n\t\t\t\t\tbody: {\n\t\t\t\t\t\tok: true,\n\t\t\t\t\t\tdelivered: true,\n\t\t\t\t\t\tstepConfirmed: pending.result.stepConfirmed,\n\t\t\t\t\t\trevision: pending.record.revision,\n\t\t\t\t\t},\n\t\t\t\t};\n\t\t\t} catch (error) {\n\t\t\t\treturn {\n\t\t\t\t\tstatus: 503,\n\t\t\t\t\tbody: {\n\t\t\t\t\t\terror: `feedback delivery failed: ${error instanceof Error ? error.message : String(error)}`,\n\t\t\t\t\t\tretry: true,\n\t\t\t\t\t},\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\t\t// Page-initiated rollbacks (走查 2026-10-03) share the POST /round\n\t\t// entry so the submission→injection→delivered protocol is identical.\n\t\tlet outcome: ReturnType<typeof applyRoundPost> | undefined;\n\t\tlet runOutcome: ReturnType<typeof applyAlignmentAdvance> | undefined;\n\t\ttry {\n\t\t\tif (post.action === \"retreat\" || post.action === \"rollback\") {\n\t\t\t\tif (post.baseRevision !== record.revision) {\n\t\t\t\t\treturn {\n\t\t\t\t\t\tstatus: 409,\n\t\t\t\t\t\tbody: { code: \"stale-state\", error: \"page snapshot is stale; reload and retry\" },\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (post.action === \"retreat\") {\n\t\t\t\trunOutcome = applyAlignmentAdvance(state, {\n\t\t\t\t\talignmentId: record.id,\n\t\t\t\t\taction: \"retreat\",\n\t\t\t\t\tstep: post.targetStep,\n\t\t\t\t\tnote: \"回退自确认页:用户在页面上点击了更早的环节\",\n\t\t\t\t});\n\t\t\t} else if (post.action === \"rollback\") {\n\t\t\t\trunOutcome = applyVersionRollback(state, {\n\t\t\t\t\talignmentId: record.id,\n\t\t\t\t\ttargetRevision: post.targetRevision ?? -1,\n\t\t\t\t});\n\t\t\t} else {\n\t\t\t\toutcome = applyRoundPost(record, post);\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tif (error instanceof AlignmentError) {\n\t\t\t\treturn {\n\t\t\t\t\tstatus: error.code === \"stale-state\" ? 409 : 400,\n\t\t\t\t\tbody: { code: error.code, error: error.message },\n\t\t\t\t};\n\t\t\t}\n\t\t\treturn { status: 500, body: { error: error instanceof Error ? error.message : String(error) } };\n\t\t}\n\t\t// Persist the submission first (append-only fact), then attempt delivery.\n\t\tconst record2 = outcome\n\t\t\t? outcome.record\n\t\t\t: (runOutcome!.state.alignments.find((candidate) => candidate.id === record.id) as AlignmentRecord);\n\t\tconst transitions2 = outcome ? outcome.transitions : runOutcome!.transitions;\n\t\tpersist(\n\t\t\t{\n\t\t\t\talignments: state.alignments.map((candidate) => (candidate.id === record2.id ? record2 : candidate)),\n\t\t\t},\n\t\t\ttransitions2,\n\t\t);\n\t\tconst syntheticResult: AlignmentRoundResult = outcome?.result ?? {\n\t\t\talignmentId: record2.id,\n\t\t\tround: record2.roundCount,\n\t\t\tstep: record2.activeStep,\n\t\t\trevision: record2.revision,\n\t\t\tapprovals: [],\n\t\t\tcomments: [],\n\t\t\tcommentReplies: [],\n\t\t\tanswers: [],\n\t\t\tadditions: [],\n\t\t\tstepConfirmed: false,\n\t\t};\n\t\tlet cached: CachedRound = { post, record: record2, transitions: [], result: syntheticResult };\n\t\tif (outcome?.result.stepConfirmed && outcome.record.status === \"completed\") {\n\t\t\t// 终审确认(走查 2026-10-03):no workspace file is written; the\n\t\t\t// compact listing rides the feedback message and `/alignment\n\t\t\t// export` produces a file only on explicit request.\n\t\t\tconst lines = finalBaselineLines(outcome.record);\n\t\t\toutcome.result.finalBaseline = lines;\n\t\t\tcached = { ...cached, result: outcome.result };\n\t\t}\n\t\tcachedRound = cached;\n\t\ttry {\n\t\t\tawait injectFeedback(cached);\n\t\t\t// injectFeedback 的 sendMessage(triggerTurn) 会同步驱动整个模型回合\n\t\t\t//(agent-session sendCustomMessage → _runAgentPrompt):回合内的\n\t\t\t// alignment_set 已把修订落账 entries。此处若回写回合前快照,会把模型\n\t\t\t// 刚提交的修订整体抹掉(走查 2026-10-04 dogfood:细节步 10 块被还原成\n\t\t\t// 空步)。只追加 round.delivered 审计条目,并从 entries 重建内存态。\n\t\t\tfor (const entry of markDelivered(cached.record, cached.result.round)) {\n\t\t\t\tapi.session?.appendEntry(TRANSITION_ENTRY, entry);\n\t\t\t}\n\t\t\tvoid api.publish({ type: \"alignment.changed\", version: 1, correlationId: STATE_ENTRY, data: loadState(api) });\n\t\t\tstate = loadState(api);\n\t\t\tdeliveredRoundByAlignment.set(cached.record.id, cached.result.round);\n\t\t\t// 只有携带内容反馈(批注/回复/答案/补充)的轮次才进入\"AI 修订中\":\n\t\t\t// 纯确认轮模型正确地不重发块,revision 不变——若也标记 awaiting,\n\t\t\t// 页面会永远钉在机器人等待屏,用户反而无法确认剩余块(走查 2026-10-04)。\n\t\t\tconst hasContentFeedback =\n\t\t\t\tpost.comments.length > 0 ||\n\t\t\t\tpost.commentReplies.length > 0 ||\n\t\t\t\tpost.answers.length > 0 ||\n\t\t\t\tpost.additions.length > 0;\n\t\t\tif (hasContentFeedback) deliveredRevisionByAlignment.set(cached.record.id, cached.record.revision);\n\t\t\treturn {\n\t\t\t\tstatus: 200,\n\t\t\t\tbody: {\n\t\t\t\t\tok: true,\n\t\t\t\t\tdelivered: true,\n\t\t\t\t\tstepConfirmed: cached.result.stepConfirmed,\n\t\t\t\t\trevision: cached.record.revision,\n\t\t\t\t},\n\t\t\t};\n\t\t} catch (error) {\n\t\t\treturn {\n\t\t\t\tstatus: 503,\n\t\t\t\tbody: {\n\t\t\t\t\terror: `feedback delivery failed: ${error instanceof Error ? error.message : String(error)}`,\n\t\t\t\t\tretry: true,\n\t\t\t\t},\n\t\t\t};\n\t\t}\n\t};\n\n\tconst runSet = (input: AlignmentSetInput): Record<string, unknown> => {\n\t\tconst run: EngineRun = applyAlignmentSet(state, input);\n\t\tconst record = run.state.alignments.find((candidate) => candidate.id === input.id);\n\t\tpersist(run.state, run.transitions);\n\t\tconst warning =\n\t\t\trecord?.goalId && !goalKnownToSession(api, record.goalId)\n\t\t\t\t? `goalId \"${record.goalId}\" does not match any goal in this session's goal state; the alignment keeps the soft reference`\n\t\t\t\t: undefined;\n\t\treturn { state, alignmentId: input.id, ...(warning ? { warning } : {}) };\n\t};\n\n\tconst setTool = api.registerTool({\n\t\tname: \"alignment_set\",\n\t\tlabel: \"Set alignment\",\n\t\tdescription:\n\t\t\t\"Create or update a requirement alignment task: full block set of the active step (goal→detail→design funnel). Unchanged blocks inherit user approval by content fingerprint\",\n\t\tparameters: setSchema,\n\t\tpromptGuidelines: PROMPT_GUIDELINES,\n\t\trenderResult: alignmentToolResultRenderer,\n\t\t// 双调用约定(goal 插件同款,走查 2026-10-04):会话路径传\n\t\t// (toolCallId, params, signal, onUpdate),runtime facade 路径传\n\t\t// (input, context?, signal?)——second 缺省时取 first。\n\t\texecute: async (first: unknown, second?: unknown) => {\n\t\t\tconst input = toolInput(first, second);\n\t\t\treturn runSet(input as unknown as AlignmentSetInput);\n\t\t},\n\t});\n\n\tconst roundTool = api.registerTool({\n\t\tname: \"alignment_round\",\n\t\tlabel: \"Open alignment page\",\n\t\tdescription:\n\t\t\t\"Open (or refresh) the local confirmation page for the active alignment and return its URL plus progress facts. Non-blocking: feedback arrives later as an alignment.feedback message\",\n\t\tparameters: roundSchema,\n\t\tpromptGuidelines: PROMPT_GUIDELINES,\n\t\trenderResult: alignmentToolResultRenderer,\n\t\texecute: async (first: unknown, second?: unknown) => {\n\t\t\tconst input = toolInput(first, second);\n\t\t\tconst id = typeof input.alignmentId === \"string\" ? input.alignmentId : \"\";\n\t\t\tconst record = state.alignments.find((candidate) => candidate.id === id);\n\t\t\tif (!record) throw new Error(`unknown alignment: ${id}`);\n\t\t\tif (record.status !== \"aligning\") throw new Error(`alignment is ${record.status}: ${id}`);\n\t\t\tif (!api.session?.sendMessage) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t\"host session does not expose sendMessage; the alignment confirmation page cannot deliver feedback on this host\",\n\t\t\t\t);\n\t\t\t}\n\t\t\tconst running = await ensureServer();\n\t\t\tconst snapshot = gate(record);\n\t\t\treturn {\n\t\t\t\tstate,\n\t\t\t\talignmentId: record.id,\n\t\t\t\turl: running.url,\n\t\t\t\tstep: record.activeStep,\n\t\t\t\tround: record.roundCount,\n\t\t\t\trevision: record.revision,\n\t\t\t\tprogress: {\n\t\t\t\t\tunapproved: snapshot.unapproved,\n\t\t\t\t\topenComments: snapshot.openComments,\n\t\t\t\t\tpendingAdditions: snapshot.pendingAdditions,\n\t\t\t\t\tallGreen: snapshot.allGreen,\n\t\t\t\t},\n\t\t\t};\n\t\t},\n\t});\n\n\tconst advanceTool = api.registerTool({\n\t\tname: \"alignment_advance\",\n\t\tlabel: \"Advance alignment\",\n\t\tdescription:\n\t\t\t\"inspect (read-only status/gate/baseline), retreat (roll back to an earlier step, resets downstream confirmations), or cancel the alignment\",\n\t\tparameters: advanceSchema,\n\t\tpromptGuidelines: PROMPT_GUIDELINES,\n\t\trenderResult: alignmentToolResultRenderer,\n\t\texecute: async (first: unknown, second?: unknown) => {\n\t\t\tconst input = toolInput(first, second) as unknown as AdvanceInput;\n\t\t\tif (input.action === \"inspect\") {\n\t\t\t\tconst record = state.alignments.find((candidate) => candidate.id === input.alignmentId);\n\t\t\t\tif (!record) throw new Error(`unknown alignment: ${input.alignmentId}`);\n\t\t\t\treturn {\n\t\t\t\t\tstate,\n\t\t\t\t\talignmentId: record.id,\n\t\t\t\t\tgate: gate(record),\n\t\t\t\t\tbaseline: record.status === \"completed\" ? finalBaselineLines(record) : undefined,\n\t\t\t\t};\n\t\t\t}\n\t\t\tconst run = applyAlignmentAdvance(state, input);\n\t\t\tpersist(run.state, run.transitions);\n\t\t\treturn { state, alignmentId: input.alignmentId };\n\t\t},\n\t});\n\n\tconst command = api.registerCommand({\n\t\tname: \"alignment\",\n\t\tdescription:\n\t\t\t\"Show this session's alignments (progress, blockers, audit log); `export [id] [path]` writes a self-contained read-only HTML snapshot\",\n\t\texecute: async (args: string, context?: { cwd?: string }): Promise<CapabilityCommandResult> => {\n\t\t\ttry {\n\t\t\t\tconst parts = args\n\t\t\t\t\t.trim()\n\t\t\t\t\t.split(/\\s+/)\n\t\t\t\t\t.filter((part) => part !== \"\");\n\t\t\t\tif (parts.length === 0) return { status: \"success\", message: listLines(state) };\n\t\t\t\tif (parts[0] === \"why\") {\n\t\t\t\t\tconst record =\n\t\t\t\t\t\tstate.alignments.find((candidate) => candidate.status === \"aligning\") ?? state.alignments.at(-1);\n\t\t\t\t\tif (!record) return { status: \"error\", message: \"no alignments in this session\" };\n\t\t\t\t\tconst extra =\n\t\t\t\t\t\tcachedRound && deliveredRoundByAlignment.get(record.id) !== cachedRound.result.round\n\t\t\t\t\t\t\t? `\\nundelivered round: r${cachedRound.result.round} (injection failed; the page can retry)`\n\t\t\t\t\t\t\t: \"\";\n\t\t\t\t\treturn { status: \"success\", message: whyLines(record) + extra };\n\t\t\t\t}\n\t\t\t\tif (parts[0] === \"log\") {\n\t\t\t\t\tconst count = Number.parseInt(parts[1] ?? \"20\", 10);\n\t\t\t\t\treturn {\n\t\t\t\t\t\tstatus: \"success\",\n\t\t\t\t\t\tmessage: logLines(loadTransitions(api), Number.isFinite(count) && count > 0 ? count : 20),\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t\tif (parts[0] === \"export\") {\n\t\t\t\t\tconst id = parts[1];\n\t\t\t\t\tconst record = id\n\t\t\t\t\t\t? state.alignments.find((candidate) => candidate.id === id)\n\t\t\t\t\t\t: (state.alignments.find((candidate) => candidate.status === \"aligning\") ??\n\t\t\t\t\t\t\tstate.alignments.find((candidate) => candidate.status === \"finalizing\") ??\n\t\t\t\t\t\t\tstate.alignments.at(-1));\n\t\t\t\t\tif (!record) return { status: \"error\", message: `unknown alignment: ${id ?? \"(none in session)\"}` };\n\t\t\t\t\t// Explicit user request — the only path that writes a file.\n\t\t\t\t\tconst target = exportTargetPath(context?.cwd ?? process.cwd(), record, parts[2]);\n\t\t\t\t\tconst written = writeAlignmentExport(record, loadTransitions(api), target);\n\t\t\t\t\treturn {\n\t\t\t\t\t\tstatus: \"success\",\n\t\t\t\t\t\tmessage: `exported: ${written}`,\n\t\t\t\t\t\tlinks: [{ label: written, url: `file:///${written.split(\"\\\\\").join(\"/\")}` }],\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t\treturn {\n\t\t\t\t\tstatus: \"error\",\n\t\t\t\t\tmessage: \"Usage: /alignment | /alignment why | /alignment log [N] | /alignment export [id] [path]\",\n\t\t\t\t};\n\t\t\t} catch (error) {\n\t\t\t\treturn { status: \"error\", message: error instanceof Error ? error.message : String(error) };\n\t\t\t}\n\t\t},\n\t});\n\n\tconst stopServer = (): void => {\n\t\tconst stopping = server;\n\t\tserver = undefined;\n\t\tif (stopping) void stopping.stop().catch(() => undefined);\n\t};\n\n\t// The command registration doubles as the teardown hook for the local\n\t// confirmation server (plugin dispose must release the port).\n\tconst commandWithTeardown: DisposableRegistration = {\n\t\tid: command.id,\n\t\tkind: command.kind,\n\t\tdispose: () => {\n\t\t\tvoid command.dispose();\n\t\t\tstopServer();\n\t\t},\n\t};\n\n\treturn [setTool, roundTool, advanceTool, commandWithTeardown];\n}\n"]}
package/dist/index.js CHANGED
@@ -198,6 +198,7 @@ function feedbackMessage(record, result, transitions) {
198
198
  const PROMPT_GUIDELINES = [
199
199
  "进入分流(预检规则):用户显式要求对齐时直接进入;否则先做零成本预检——列出缺失信息、被迫假设、矛盾歧义。三项全空则一行结论直接出方案(跳过证据必须可见,禁止静默跳过);有任一项则列出要点并建议对齐,用户说直接做则跳过、但未决假设须在方案中显式标注。预检清单在对齐时直接作为第一轮块种子。",
200
200
  "三步铁律:objective 只谈方向与非目标(≤10 块);detail 只谈业务规则/公式/数据流/异常(禁止技术选型);design 谈技术方案且不得与已锁定基线矛盾,发现矛盾必须停下向用户提出。",
201
+ "视觉对齐(涉及用户可见界面的任务):design 步必须产出 visual 视觉方向块——按六节契约(风格宣言/配色角色表/布局与层级策略/文案密度预算/视觉验收清单/明确不做项)逐节落块,建议委派 design-proposer 出厂角色产出(subagent_run role=design-proposer,其指令内嵌保底资产);纯后端/重构任务不产 visual 块;实现完成后渲染产物交 visual-reviewer 角色做视觉验收(防丑下限)。",
201
202
  "块纪律:假设单独成 assumption 块;缺信息产 missing 块而不是脑补;可自查的先取证落 fact;assistant 批注只用于真实不确定点(公式口径、二义表述、潜在矛盾、与基线冲突)。",
202
203
  "修订纪律:最小改动已确认的块(内容不变即继承确认);每次 alignment_set 之后必须跟 alignment_round 告知用户去看新版;用户批注的 quote 匹配失败时向用户说明而不是猜。",
203
204
  "填空落账:收到补充答案(补充答案[blockId])后,下一次 alignment_set 必须把答案重写进对应块内容并转为 fact/decision(missing 块不得带着未并入的答案被确认锁定);注入消息的「当前块集(全量状态)」是权威现状,以它为准做最小修订。",
@@ -211,7 +212,13 @@ const setSchema = Type.Object({
211
212
  revision: Type.Optional(Type.Integer({ description: "Monotonic revision; must exceed the stored one", minimum: 0 })),
212
213
  blocks: Type.Array(Type.Object({
213
214
  id: Type.String({ description: "Stable block id within the step" }),
214
- kind: Type.Union([Type.Literal("fact"), Type.Literal("assumption"), Type.Literal("decision"), Type.Literal("missing")], { description: "fact=取证 assumption=假设 decision=决策 missing=待补充" }),
215
+ kind: Type.Union([
216
+ Type.Literal("fact"),
217
+ Type.Literal("assumption"),
218
+ Type.Literal("decision"),
219
+ Type.Literal("missing"),
220
+ Type.Literal("visual"),
221
+ ], { description: "fact=取证 assumption=假设 decision=决策 missing=待补充" }),
215
222
  content: Type.String({ description: "Block content (markdown text, ≤8192 chars)" }),
216
223
  rationale: Type.Optional(Type.String({ description: "Why this decision/assumption (≤2048 chars)" })),
217
224
  impact: Type.Optional(Type.Array(Type.String(), { description: "Affected modules/files/interfaces" })),
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Alignment capability plugin (M1 of `docs/design/需求对齐插件设计.md`): a\n * three-step requirement-alignment funnel (objective → detail → design) with\n * block-level bidirectional feedback confirmed on a local HTML page.\n *\n * Persistence protocol, structurally identical to the goal/plan/todo/workflow\n * plugins: append-only `alignment.state` full snapshots (the single rebuild\n * source) plus one `alignment.transition` audit entry per conversion,\n * announced as `alignment.changed` (version 1, correlationId\n * \"alignment.state\", data = the complete AlignmentState snapshot).\n *\n * The round wait is non-blocking (设计 §5 总则 8): alignment_round returns the\n * page URL immediately; page feedback arrives as a `alignment.feedback`\n * custom message injected through SessionAPI.sendMessage (triggerTurn), and a\n * round only closes after the injection succeeded (`round.delivered`,\n * terminal audit D1).\n */\n\nimport type { CapabilityAPI, CapabilityCommandResult, DisposableRegistration } from \"@agent-forge/plugin-sdk\";\nimport { Type } from \"typebox\";\nimport {\n\ttype AdvanceInput,\n\ttype AlignmentSetInput,\n\tactiveStep,\n\tapplyAlignmentAdvance,\n\tapplyAlignmentSet,\n\tapplyRoundPost,\n\tapplyVersionRollback,\n\ttype EngineRun,\n\tfinalBaselineLines,\n\tgate,\n\tmarkDelivered,\n} from \"./engine.ts\";\nimport { exportTargetPath, writeAlignmentExport } from \"./export.ts\";\nimport { type AlignmentServer, startAlignmentServer } from \"./http-server.ts\";\nimport { alignmentToolResultRenderer } from \"./render.ts\";\nimport {\n\tAlignmentError,\n\ttype AlignmentRecord,\n\ttype AlignmentRoundPost,\n\ttype AlignmentRoundResult,\n\ttype AlignmentState,\n\ttype AlignmentTransitionEntry,\n\ttype PendingItem,\n} from \"./types.ts\";\n\nconst STATE_ENTRY = \"alignment.state\";\nconst TRANSITION_ENTRY = \"alignment.transition\";\nconst GOAL_STATE_ENTRY = \"goal.state\";\n/** Round post outcomes cached until delivered — the retry-injection window (终审 D1). */\ninterface CachedRound {\n\tpost: AlignmentRoundPost;\n\trecord: AlignmentRecord;\n\ttransitions: AlignmentTransitionEntry[];\n\tresult: AlignmentRoundResult;\n}\n\nexport interface AlignmentCapabilityOptions {\n\t/** Injection seam for deterministic tests; production binds an OS-assigned port. */\n\tserverPort?: number;\n}\n\nfunction isObject(value: unknown): value is Record<string, unknown> {\n\treturn value !== null && typeof value === \"object\" && !Array.isArray(value);\n}\n\n/**\n * 双调用约定(走查 2026-10-04,goal 插件同款问题的严谨版):会话路径以\n * (toolCallId, params, signal, onUpdate) 调用插件工具——first 是调用 id 字符串;\n * runtime facade 以 (input, context?, signal?) 调用——first 是入参对象。\n * 按 first 的类型区分,两条路径(含 runtime 携带 context)都取到真实入参。\n */\nfunction toolInput(first: unknown, second?: unknown): Record<string, unknown> {\n\tif (typeof first === \"string\") {\n\t\tif (!isObject(second)) return {};\n\t\treturn second;\n\t}\n\tif (!isObject(first)) throw new Error(\"alignment tool input must be an object\");\n\treturn first;\n}\n\nfunction loadState(api: CapabilityAPI): AlignmentState {\n\tconst entries = api.session?.getBranchEntries() ?? [];\n\tconst entry = [...entries].reverse().find((item) => item.customType === STATE_ENTRY);\n\tif (!entry?.data || !isObject(entry.data)) return { alignments: [] };\n\tconst data = entry.data as { alignments?: unknown };\n\treturn { alignments: Array.isArray(data.alignments) ? [...(data.alignments as AlignmentRecord[])] : [] };\n}\n\nfunction loadTransitions(api: CapabilityAPI): AlignmentTransitionEntry[] {\n\tconst entries = api.session?.getBranchEntries() ?? [];\n\treturn entries\n\t\t.filter((item) => item.customType === TRANSITION_ENTRY)\n\t\t.map((item) => item.data as AlignmentTransitionEntry)\n\t\t.filter((item): item is AlignmentTransitionEntry => isObject(item));\n}\n\n/** Advisory goalId check (#10 soft-reference discipline, goal/plan precedent). */\nfunction goalKnownToSession(api: CapabilityAPI, goalId: string): boolean {\n\tconst entries = api.session?.getBranchEntries() ?? [];\n\tfor (let index = entries.length - 1; index >= 0; index -= 1) {\n\t\tconst entry = entries[index];\n\t\tif (entry.customType !== GOAL_STATE_ENTRY) continue;\n\t\tconst data = entry.data;\n\t\tif (!isObject(data)) return false;\n\t\tconst goals = data.goals;\n\t\tif (!Array.isArray(goals)) return false;\n\t\treturn goals.some((goal) => isObject(goal) && goal.id === goalId);\n\t}\n\treturn false;\n}\n\n/** Page projection (state.json): everything the fixed template renders. */\nfunction pageView(\n\trecord: AlignmentRecord,\n\tbaselineFile: string | undefined,\n\tawaitingRevision: boolean,\n): Record<string, unknown> {\n\tconst snapshot = gate(record);\n\t// gate already validated the active step exists (it throws otherwise).\n\tconst blocks = activeStep(record).blocks;\n\t// 终审/终态头部展示跨步总口径(走查 2026-10-03):completed 后仍按当前步\n\t// 计数会显示「已确认 0/1」这类误导数字。\n\tconst countedBlocks = record.status === \"aligning\" ? blocks : record.steps.flatMap((s) => s.blocks);\n\treturn {\n\t\talignmentId: record.id,\n\t\ttitle: record.title,\n\t\tgoalId: record.goalId,\n\t\tstatus: record.status,\n\t\trevision: record.revision,\n\t\tround: record.roundCount,\n\t\tactiveStep: record.activeStep,\n\t\tsteps: record.steps.map((step) => ({\n\t\t\tstep: step.step,\n\t\t\tstatus: step.status,\n\t\t\tblocks: step.blocks.map((block) => ({\n\t\t\t\tid: block.id,\n\t\t\t\tkind: block.kind,\n\t\t\t\tcontent: block.content,\n\t\t\t\trationale: block.rationale,\n\t\t\t\timpact: block.impact,\n\t\t\t\tstatus: block.status,\n\t\t\t\tmodifiedInRound: block.modifiedInRound,\n\t\t\t\tdraftAnswer: block.draftAnswer,\n\t\t\t\tcomments: block.comments,\n\t\t\t})),\n\t\t})),\n\t\tgate: {\n\t\t\t...snapshot,\n\t\t\tapprovedCount: countedBlocks.filter((block) => block.status === \"approved\").length,\n\t\t\tblockCount: countedBlocks.length,\n\t\t},\n\t\tpendingFeedback: record.pendingFeedback,\n\t\t// Version snapshots for the read-only history switcher (走查 2026-10-03).\n\t\tversions: record.versions ?? [],\n\t\tawaitingRevision,\n\t\tbaselineFile,\n\t};\n}\n\nfunction blockStateLine(block: AlignmentRecord[\"steps\"][number][\"blocks\"][number]): string {\n\tconst state = block.status === \"approved\" ? \"已确认\" : \"待确认\";\n\tconst first = block.content.split(\"\\n\")[0]?.slice(0, 80) ?? \"\";\n\tconst notes: string[] = [];\n\tfor (const comment of block.comments) {\n\t\tif (comment.status !== \"open\") continue;\n\t\tnotes.push(\n\t\t\tcomment.author === \"assistant\"\n\t\t\t\t? `AI疑问待回应:${comment.note.slice(0, 40)}`\n\t\t\t\t: `用户批注:${comment.note.slice(0, 40)}`,\n\t\t);\n\t}\n\treturn `- ${block.id}[${block.kind}|${state}] ${first}${notes.length ? `(${notes.join(\";\")})` : \"\"}`;\n}\n\nfunction historyLines(transitions: AlignmentTransitionEntry[]): string {\n\tif (transitions.length === 0) return \"(无)\";\n\treturn transitions\n\t\t.slice(-20)\n\t\t.map((entry) => {\n\t\t\tconst where = entry.step ? `${entry.step} ` : \"\";\n\t\t\treturn `rev${entry.revision} ${where}${entry.event}${entry.reason.detail ? `(${entry.reason.detail.slice(0, 60)})` : \"\"}`;\n\t\t})\n\t\t.join(\"\\n\");\n}\n\nfunction feedbackMessage(\n\trecord: AlignmentRecord,\n\tresult: AlignmentRoundResult,\n\ttransitions: AlignmentTransitionEntry[],\n): string {\n\tconst snapshot = gate(record);\n\tconst lines: string[] = [];\n\tlines.push(\n\t\t`[alignment.feedback] ${result.alignmentId} 第 ${result.round} 轮(${result.step} 步,revision ${result.revision},status ${record.status})`,\n\t);\n\tlines.push(\"== 本轮反馈 ==\");\n\tif (result.approvals.length > 0) lines.push(`确认块:${result.approvals.join(\", \")}`);\n\tfor (const comment of result.comments) {\n\t\tlines.push(\n\t\t\t`用户批注[${comment.blockId}]${comment.escalate ? \"(上游问题)\" : \"\"}:「${comment.quote}」→ ${comment.note}`,\n\t\t);\n\t}\n\tfor (const reply of result.commentReplies) {\n\t\tlines.push(\n\t\t\treply.dismiss\n\t\t\t\t? `AI 疑问 ${reply.commentId}:用户标记不重要`\n\t\t\t\t: `AI 疑问 ${reply.commentId} 的回答:${reply.answer}`,\n\t\t);\n\t}\n\tfor (const answer of result.answers) {\n\t\tlines.push(`补充答案[${answer.blockId}]:${answer.value}`);\n\t}\n\tfor (const addition of result.additions) {\n\t\tlines.push(`自由补充:${addition}`);\n\t}\n\tif (result.stepConfirmed) {\n\t\tif (record.status === \"completed\") {\n\t\t\tlines.push(\"用户已在终审总览确认基线——对齐完成。请输出最终基线总结(plan 输入)。\");\n\t\t\tif (result.finalBaseline) {\n\t\t\t\tlines.push(\"最终基线紧凑清单:\");\n\t\t\t\tfor (const line of result.finalBaseline) {\n\t\t\t\t\tlines.push(` [${line.kind}] ${line.id}: ${line.line}`);\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\tlines.push(\"用户已确认本步——基线锁定。请 alignment_set 出下一步块集并 alignment_round 刷新。\");\n\t\t}\n\t}\n\tlines.push(\"== 当前块集(全量状态)==\");\n\tif (record.status === \"finalizing\") {\n\t\tlines.push(\"三步基线已全部锁定,等待用户终审总览确认;此阶段无需你操作。\");\n\t} else {\n\t\tfor (const step of record.steps) {\n\t\t\tif (step.blocks.length === 0) continue;\n\t\t\tlines.push(`[${step.step}|${step.status}]`);\n\t\t\tfor (const block of step.blocks) lines.push(blockStateLine(block));\n\t\t}\n\t\tlines.push(\n\t\t\t`待办:${snapshot.unapproved} 块待确认、${snapshot.openComments} 批注未清、${snapshot.pendingAdditions} 补充未落账。`,\n\t\t);\n\t}\n\tlines.push(\"== 历史轮次(revision 锚点)==\");\n\tlines.push(historyLines(transitions));\n\treturn lines.join(\"\\n\");\n}\n\nconst PROMPT_GUIDELINES: readonly string[] = [\n\t\"进入分流(预检规则):用户显式要求对齐时直接进入;否则先做零成本预检——列出缺失信息、被迫假设、矛盾歧义。三项全空则一行结论直接出方案(跳过证据必须可见,禁止静默跳过);有任一项则列出要点并建议对齐,用户说直接做则跳过、但未决假设须在方案中显式标注。预检清单在对齐时直接作为第一轮块种子。\",\n\t\"三步铁律:objective 只谈方向与非目标(≤10 块);detail 只谈业务规则/公式/数据流/异常(禁止技术选型);design 谈技术方案且不得与已锁定基线矛盾,发现矛盾必须停下向用户提出。\",\n\t\"块纪律:假设单独成 assumption 块;缺信息产 missing 块而不是脑补;可自查的先取证落 fact;assistant 批注只用于真实不确定点(公式口径、二义表述、潜在矛盾、与基线冲突)。\",\n\t\"修订纪律:最小改动已确认的块(内容不变即继承确认);每次 alignment_set 之后必须跟 alignment_round 告知用户去看新版;用户批注的 quote 匹配失败时向用户说明而不是猜。\",\n\t\"填空落账:收到补充答案(补充答案[blockId])后,下一次 alignment_set 必须把答案重写进对应块内容并转为 fact/decision(missing 块不得带着未并入的答案被确认锁定);注入消息的「当前块集(全量状态)」是权威现状,以它为准做最小修订。\",\n\t\"终审阶段(status finalizing):三步基线已全部锁定,页面进入只读总览,唯一动作是用户最终确认——此阶段不要调用 alignment_set;收到终审确认消息(alignment completed)即视为开发授权:先输出一行极简基线摘要,然后直接按基线实现——用 plan/todo 把基线拆成可执行任务,实现并自测,完成后向用户报告结果与验收方式。不要停在基线总结等用户再次指令(dogfood 2026-10-04:等指令会打断对齐→开发衔接)。\",\n\t\"页面回退:用户可在页面上把任务回退到更早环节(step.retreated,后续环节作废重走)或把当前步回退到历史版本(version.rolled-back,当前未确认版本丢弃、批注保留)。收到这类消息后,以注入消息里的全量块集为准重新修订,不要复用回退前的块集。\",\n];\n\nconst setSchema = Type.Object({\n\tid: Type.String({ description: \"Stable alignment id; charset [A-Za-z0-9._-], no leading dot\" }),\n\ttitle: Type.Optional(Type.String({ description: \"Human-readable alignment title\" })),\n\tgoalId: Type.Optional(Type.String({ description: \"Soft goal reference; unknown ids only warn\" })),\n\trevision: Type.Optional(Type.Integer({ description: \"Monotonic revision; must exceed the stored one\", minimum: 0 })),\n\tblocks: Type.Array(\n\t\tType.Object({\n\t\t\tid: Type.String({ description: \"Stable block id within the step\" }),\n\t\t\tkind: Type.Union(\n\t\t\t\t[Type.Literal(\"fact\"), Type.Literal(\"assumption\"), Type.Literal(\"decision\"), Type.Literal(\"missing\")],\n\t\t\t\t{ description: \"fact=取证 assumption=假设 decision=决策 missing=待补充\" },\n\t\t\t),\n\t\t\tcontent: Type.String({ description: \"Block content (markdown text, ≤8192 chars)\" }),\n\t\t\trationale: Type.Optional(Type.String({ description: \"Why this decision/assumption (≤2048 chars)\" })),\n\t\t\timpact: Type.Optional(Type.Array(Type.String(), { description: \"Affected modules/files/interfaces\" })),\n\t\t\tcomments: Type.Optional(\n\t\t\t\tType.Array(\n\t\t\t\t\tType.Object({\n\t\t\t\t\t\tid: Type.String(),\n\t\t\t\t\t\tnote: Type.String({ description: \"Assistant question; only real uncertainty\" }),\n\t\t\t\t\t\tquote: Type.Optional(Type.String()),\n\t\t\t\t\t}),\n\t\t\t\t\t{ description: \"New assistant comments (AI 主动标注的不确定点)\" },\n\t\t\t\t),\n\t\t\t),\n\t\t\tcommentResolutions: Type.Optional(\n\t\t\t\tType.Array(\n\t\t\t\t\tType.Object({\n\t\t\t\t\t\tcommentId: Type.String(),\n\t\t\t\t\t\tkind: Type.Union([Type.Literal(\"answered\"), Type.Literal(\"dismissed\"), Type.Literal(\"incorporated\")]),\n\t\t\t\t\t\ttext: Type.Optional(Type.String()),\n\t\t\t\t\t}),\n\t\t\t\t\t{\n\t\t\t\t\t\tdescription:\n\t\t\t\t\t\t\t\"Resolutions for existing comments (user comments may only be resolved, never rewritten)\",\n\t\t\t\t\t},\n\t\t\t\t),\n\t\t\t),\n\t\t}),\n\t\t{ description: \"Full block set of the active step (全量提交;未变块按内容指纹继承确认)\" },\n\t),\n});\n\nconst roundSchema = Type.Object({\n\talignmentId: Type.String({ description: \"Alignment id to open the confirmation page for\" }),\n});\n\nconst advanceSchema = Type.Object({\n\talignmentId: Type.String(),\n\taction: Type.Union([Type.Literal(\"inspect\"), Type.Literal(\"retreat\"), Type.Literal(\"cancel\")]),\n\tstep: Type.Optional(\n\t\tType.Union([Type.Literal(\"objective\"), Type.Literal(\"detail\"), Type.Literal(\"design\")], {\n\t\t\tdescription: \"Retreat target; must be an earlier step\",\n\t\t}),\n\t),\n\tnote: Type.Optional(Type.String({ description: \"Retreat reason (required for retreat)\" })),\n});\n\nfunction pendingText(items: PendingItem[]): string {\n\tif (items.length === 0) return \"nothing pending\";\n\tconst reasons = items.map((item) => `${item.blockId}(${item.reason})`);\n\treturn reasons.join(\" \");\n}\n\nfunction listLines(state: AlignmentState): string {\n\tif (state.alignments.length === 0) return \"no alignments in this session; create one with alignment_set\";\n\tconst lines = [`alignments: ${state.alignments.length}`];\n\tfor (const record of state.alignments) {\n\t\tconst snapshot = gate(record);\n\t\tlines.push(\n\t\t\t`- ${record.id} [${record.status} → ${record.goalId ?? \"-\"}] ${record.title} · ${record.activeStep} r${record.roundCount} · ${snapshot.unapproved} pending / ${snapshot.openComments} open`,\n\t\t);\n\t}\n\treturn lines.join(\"\\n\");\n}\n\nfunction whyLines(record: AlignmentRecord): string {\n\tconst snapshot = gate(record);\n\tconst lines = [`${record.id} · ${record.activeStep} · round ${record.roundCount}`];\n\tif (record.status !== \"aligning\") {\n\t\tlines.push(`status ${record.status} — nothing to wait for`);\n\t\treturn lines.join(\"\\n\");\n\t}\n\tif (snapshot.allGreen) {\n\t\tlines.push(\"ALL GREEN — waiting for the user to click 确认完成 on the page\");\n\t\treturn lines.join(\"\\n\");\n\t}\n\tlines.push(`pending: ${pendingText(snapshot.pending)}`);\n\tif (snapshot.pendingAdditions > 0) {\n\t\tlines.push(`undelivered additions: ${record.pendingFeedback?.additions.join(\" | \")}`);\n\t}\n\treturn lines.join(\"\\n\");\n}\n\nfunction logLines(transitions: AlignmentTransitionEntry[], count: number): string {\n\tif (transitions.length === 0) return \"no alignment transitions recorded\";\n\tconst slice = transitions.slice(-count).reverse();\n\treturn slice\n\t\t.map((entry, index) => {\n\t\t\tconst where = entry.step ? `${entry.step} ` : \"\";\n\t\t\treturn `${slice.length - index}. [r${entry.round ?? \"-\"} rev${entry.revision}] ${where}${entry.event} ${entry.reason.code}${entry.reason.detail ? ` — ${entry.reason.detail}` : \"\"}`;\n\t\t})\n\t\t.join(\"\\n\");\n}\n\nexport function createCapability(\n\tapi: CapabilityAPI,\n\toptions: AlignmentCapabilityOptions = {},\n): readonly DisposableRegistration[] {\n\tlet state = loadState(api);\n\tlet server: AlignmentServer | undefined;\n\tlet cachedRound: CachedRound | undefined;\n\tconst deliveredRoundByAlignment = new Map<string, number>();\n\t/** Revision at last successful injection — awaitingRevision = delivered and not yet superseded by a set. */\n\tconst deliveredRevisionByAlignment = new Map<string, number>();\n\n\tconst persist = (next: AlignmentState, transitions: AlignmentTransitionEntry[]): AlignmentState => {\n\t\tstate = next;\n\t\tapi.session?.appendEntry(STATE_ENTRY, state);\n\t\tfor (const entry of transitions) api.session?.appendEntry(TRANSITION_ENTRY, entry);\n\t\tvoid api.publish({ type: \"alignment.changed\", version: 1, correlationId: STATE_ENTRY, data: state });\n\t\treturn state;\n\t};\n\n\tconst activeRecord = (): AlignmentRecord | undefined =>\n\t\tstate.alignments.find((record) => record.status === \"aligning\") ??\n\t\t[...state.alignments].reverse().find((record) => record.status !== \"aligning\");\n\n\tconst ensureServer = async (): Promise<AlignmentServer> => {\n\t\t// 页面生命周期(走查 2026-10-04 用户裁决):服务随第一个 alignment_round\n\t\t// 启动后常驻到插件 dispose(会话关闭);终态对齐的页面保持可查看,直到\n\t\t// 下一次对齐在同一 URL 上覆盖内容。不再做终态 idle 停服。\n\t\tif (server) return server;\n\t\tserver = await startAlignmentServer(\n\t\t\t{\n\t\t\t\tgetState: () => {\n\t\t\t\t\tconst record = activeRecord();\n\t\t\t\t\tif (!record) return undefined;\n\t\t\t\t\t// awaitingRevision: feedback was delivered and the model has not\n\t\t\t\t\t// bumped the revision yet — the page shows \"AI revising…\".\n\t\t\t\t\tconst awaiting =\n\t\t\t\t\t\trecord.status === \"aligning\" && deliveredRevisionByAlignment.get(record.id) === record.revision;\n\t\t\t\t\treturn pageView(record, undefined, awaiting);\n\t\t\t\t},\n\t\t\t\tonRoundPost: (post) => handleRoundPost(post),\n\t\t\t},\n\t\t\t{ port: options.serverPort },\n\t\t);\n\t\treturn server;\n\t};\n\n\tconst injectFeedback = async (cached: CachedRound): Promise<void> => {\n\t\tconst message = feedbackMessage(cached.record, cached.result, loadTransitions(api));\n\t\tconst send = api.session?.sendMessage;\n\t\tif (!send) {\n\t\t\tthrow new AlignmentError(\n\t\t\t\t\"invalid-input\",\n\t\t\t\t\"host session does not expose sendMessage; feedback cannot be injected\",\n\t\t\t);\n\t\t}\n\t\tawait send({ customType: \"alignment.feedback\", content: message, display: true }, { triggerTurn: true });\n\t};\n\n\tconst handleRoundPost = async (post: AlignmentRoundPost): Promise<{ status: number; body: unknown }> => {\n\t\tconst record = activeRecord();\n\t\tif (!record || (record.status !== \"aligning\" && record.status !== \"finalizing\")) {\n\t\t\treturn { status: 409, body: { error: \"no alignment in progress\" } };\n\t\t}\n\t\tconst samePost = (candidate: CachedRound): boolean =>\n\t\t\tcandidate.result.alignmentId === record.id && JSON.stringify(candidate.post) === JSON.stringify(post);\n\t\t// Delivered idempotency: an identical replay of an already-delivered\n\t\t// round returns the snapshot without re-injecting.\n\t\tconst pending = cachedRound;\n\t\tif (pending && samePost(pending) && deliveredRoundByAlignment.get(record.id) === pending.result.round) {\n\t\t\treturn {\n\t\t\t\tstatus: 200,\n\t\t\t\tbody: {\n\t\t\t\t\tok: true,\n\t\t\t\t\tdelivered: true,\n\t\t\t\t\tstepConfirmed: pending.result.stepConfirmed,\n\t\t\t\t\trevision: pending.record.revision,\n\t\t\t\t},\n\t\t\t};\n\t\t}\n\t\t// Submitted-but-undelivered replay retries only the injection.\n\t\tif (pending && samePost(pending)) {\n\t\t\ttry {\n\t\t\t\tawait injectFeedback(pending);\n\t\t\t\t// 同主路径:注入可能同步驱动模型回合,不回写回合前快照(走查 2026-10-04)。\n\t\t\t\tfor (const entry of markDelivered(pending.record, pending.result.round)) {\n\t\t\t\t\tapi.session?.appendEntry(TRANSITION_ENTRY, entry);\n\t\t\t\t}\n\t\t\t\tvoid api.publish({\n\t\t\t\t\ttype: \"alignment.changed\",\n\t\t\t\t\tversion: 1,\n\t\t\t\t\tcorrelationId: STATE_ENTRY,\n\t\t\t\t\tdata: loadState(api),\n\t\t\t\t});\n\t\t\t\tstate = loadState(api);\n\t\t\t\tdeliveredRoundByAlignment.set(record.id, pending.result.round);\n\t\t\t\t// 重放路径同主路径:纯确认轮不进入\"AI 修订中\"(走查 2026-10-04)。\n\t\t\t\tconst replayHasContent =\n\t\t\t\t\tpending.result.comments.length > 0 ||\n\t\t\t\t\tpending.result.commentReplies.length > 0 ||\n\t\t\t\t\tpending.result.answers.length > 0 ||\n\t\t\t\t\tpending.result.additions.length > 0;\n\t\t\t\tif (replayHasContent) deliveredRevisionByAlignment.set(record.id, pending.record.revision);\n\t\t\t\treturn {\n\t\t\t\t\tstatus: 200,\n\t\t\t\t\tbody: {\n\t\t\t\t\t\tok: true,\n\t\t\t\t\t\tdelivered: true,\n\t\t\t\t\t\tstepConfirmed: pending.result.stepConfirmed,\n\t\t\t\t\t\trevision: pending.record.revision,\n\t\t\t\t\t},\n\t\t\t\t};\n\t\t\t} catch (error) {\n\t\t\t\treturn {\n\t\t\t\t\tstatus: 503,\n\t\t\t\t\tbody: {\n\t\t\t\t\t\terror: `feedback delivery failed: ${error instanceof Error ? error.message : String(error)}`,\n\t\t\t\t\t\tretry: true,\n\t\t\t\t\t},\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\t\t// Page-initiated rollbacks (走查 2026-10-03) share the POST /round\n\t\t// entry so the submission→injection→delivered protocol is identical.\n\t\tlet outcome: ReturnType<typeof applyRoundPost> | undefined;\n\t\tlet runOutcome: ReturnType<typeof applyAlignmentAdvance> | undefined;\n\t\ttry {\n\t\t\tif (post.action === \"retreat\" || post.action === \"rollback\") {\n\t\t\t\tif (post.baseRevision !== record.revision) {\n\t\t\t\t\treturn {\n\t\t\t\t\t\tstatus: 409,\n\t\t\t\t\t\tbody: { code: \"stale-state\", error: \"page snapshot is stale; reload and retry\" },\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (post.action === \"retreat\") {\n\t\t\t\trunOutcome = applyAlignmentAdvance(state, {\n\t\t\t\t\talignmentId: record.id,\n\t\t\t\t\taction: \"retreat\",\n\t\t\t\t\tstep: post.targetStep,\n\t\t\t\t\tnote: \"回退自确认页:用户在页面上点击了更早的环节\",\n\t\t\t\t});\n\t\t\t} else if (post.action === \"rollback\") {\n\t\t\t\trunOutcome = applyVersionRollback(state, {\n\t\t\t\t\talignmentId: record.id,\n\t\t\t\t\ttargetRevision: post.targetRevision ?? -1,\n\t\t\t\t});\n\t\t\t} else {\n\t\t\t\toutcome = applyRoundPost(record, post);\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tif (error instanceof AlignmentError) {\n\t\t\t\treturn {\n\t\t\t\t\tstatus: error.code === \"stale-state\" ? 409 : 400,\n\t\t\t\t\tbody: { code: error.code, error: error.message },\n\t\t\t\t};\n\t\t\t}\n\t\t\treturn { status: 500, body: { error: error instanceof Error ? error.message : String(error) } };\n\t\t}\n\t\t// Persist the submission first (append-only fact), then attempt delivery.\n\t\tconst record2 = outcome\n\t\t\t? outcome.record\n\t\t\t: (runOutcome!.state.alignments.find((candidate) => candidate.id === record.id) as AlignmentRecord);\n\t\tconst transitions2 = outcome ? outcome.transitions : runOutcome!.transitions;\n\t\tpersist(\n\t\t\t{\n\t\t\t\talignments: state.alignments.map((candidate) => (candidate.id === record2.id ? record2 : candidate)),\n\t\t\t},\n\t\t\ttransitions2,\n\t\t);\n\t\tconst syntheticResult: AlignmentRoundResult = outcome?.result ?? {\n\t\t\talignmentId: record2.id,\n\t\t\tround: record2.roundCount,\n\t\t\tstep: record2.activeStep,\n\t\t\trevision: record2.revision,\n\t\t\tapprovals: [],\n\t\t\tcomments: [],\n\t\t\tcommentReplies: [],\n\t\t\tanswers: [],\n\t\t\tadditions: [],\n\t\t\tstepConfirmed: false,\n\t\t};\n\t\tlet cached: CachedRound = { post, record: record2, transitions: [], result: syntheticResult };\n\t\tif (outcome?.result.stepConfirmed && outcome.record.status === \"completed\") {\n\t\t\t// 终审确认(走查 2026-10-03):no workspace file is written; the\n\t\t\t// compact listing rides the feedback message and `/alignment\n\t\t\t// export` produces a file only on explicit request.\n\t\t\tconst lines = finalBaselineLines(outcome.record);\n\t\t\toutcome.result.finalBaseline = lines;\n\t\t\tcached = { ...cached, result: outcome.result };\n\t\t}\n\t\tcachedRound = cached;\n\t\ttry {\n\t\t\tawait injectFeedback(cached);\n\t\t\t// injectFeedback 的 sendMessage(triggerTurn) 会同步驱动整个模型回合\n\t\t\t//(agent-session sendCustomMessage → _runAgentPrompt):回合内的\n\t\t\t// alignment_set 已把修订落账 entries。此处若回写回合前快照,会把模型\n\t\t\t// 刚提交的修订整体抹掉(走查 2026-10-04 dogfood:细节步 10 块被还原成\n\t\t\t// 空步)。只追加 round.delivered 审计条目,并从 entries 重建内存态。\n\t\t\tfor (const entry of markDelivered(cached.record, cached.result.round)) {\n\t\t\t\tapi.session?.appendEntry(TRANSITION_ENTRY, entry);\n\t\t\t}\n\t\t\tvoid api.publish({ type: \"alignment.changed\", version: 1, correlationId: STATE_ENTRY, data: loadState(api) });\n\t\t\tstate = loadState(api);\n\t\t\tdeliveredRoundByAlignment.set(cached.record.id, cached.result.round);\n\t\t\t// 只有携带内容反馈(批注/回复/答案/补充)的轮次才进入\"AI 修订中\":\n\t\t\t// 纯确认轮模型正确地不重发块,revision 不变——若也标记 awaiting,\n\t\t\t// 页面会永远钉在机器人等待屏,用户反而无法确认剩余块(走查 2026-10-04)。\n\t\t\tconst hasContentFeedback =\n\t\t\t\tpost.comments.length > 0 ||\n\t\t\t\tpost.commentReplies.length > 0 ||\n\t\t\t\tpost.answers.length > 0 ||\n\t\t\t\tpost.additions.length > 0;\n\t\t\tif (hasContentFeedback) deliveredRevisionByAlignment.set(cached.record.id, cached.record.revision);\n\t\t\treturn {\n\t\t\t\tstatus: 200,\n\t\t\t\tbody: {\n\t\t\t\t\tok: true,\n\t\t\t\t\tdelivered: true,\n\t\t\t\t\tstepConfirmed: cached.result.stepConfirmed,\n\t\t\t\t\trevision: cached.record.revision,\n\t\t\t\t},\n\t\t\t};\n\t\t} catch (error) {\n\t\t\treturn {\n\t\t\t\tstatus: 503,\n\t\t\t\tbody: {\n\t\t\t\t\terror: `feedback delivery failed: ${error instanceof Error ? error.message : String(error)}`,\n\t\t\t\t\tretry: true,\n\t\t\t\t},\n\t\t\t};\n\t\t}\n\t};\n\n\tconst runSet = (input: AlignmentSetInput): Record<string, unknown> => {\n\t\tconst run: EngineRun = applyAlignmentSet(state, input);\n\t\tconst record = run.state.alignments.find((candidate) => candidate.id === input.id);\n\t\tpersist(run.state, run.transitions);\n\t\tconst warning =\n\t\t\trecord?.goalId && !goalKnownToSession(api, record.goalId)\n\t\t\t\t? `goalId \"${record.goalId}\" does not match any goal in this session's goal state; the alignment keeps the soft reference`\n\t\t\t\t: undefined;\n\t\treturn { state, alignmentId: input.id, ...(warning ? { warning } : {}) };\n\t};\n\n\tconst setTool = api.registerTool({\n\t\tname: \"alignment_set\",\n\t\tlabel: \"Set alignment\",\n\t\tdescription:\n\t\t\t\"Create or update a requirement alignment task: full block set of the active step (goal→detail→design funnel). Unchanged blocks inherit user approval by content fingerprint\",\n\t\tparameters: setSchema,\n\t\tpromptGuidelines: PROMPT_GUIDELINES,\n\t\trenderResult: alignmentToolResultRenderer,\n\t\t// 双调用约定(goal 插件同款,走查 2026-10-04):会话路径传\n\t\t// (toolCallId, params, signal, onUpdate),runtime facade 路径传\n\t\t// (input, context?, signal?)——second 缺省时取 first。\n\t\texecute: async (first: unknown, second?: unknown) => {\n\t\t\tconst input = toolInput(first, second);\n\t\t\treturn runSet(input as unknown as AlignmentSetInput);\n\t\t},\n\t});\n\n\tconst roundTool = api.registerTool({\n\t\tname: \"alignment_round\",\n\t\tlabel: \"Open alignment page\",\n\t\tdescription:\n\t\t\t\"Open (or refresh) the local confirmation page for the active alignment and return its URL plus progress facts. Non-blocking: feedback arrives later as an alignment.feedback message\",\n\t\tparameters: roundSchema,\n\t\tpromptGuidelines: PROMPT_GUIDELINES,\n\t\trenderResult: alignmentToolResultRenderer,\n\t\texecute: async (first: unknown, second?: unknown) => {\n\t\t\tconst input = toolInput(first, second);\n\t\t\tconst id = typeof input.alignmentId === \"string\" ? input.alignmentId : \"\";\n\t\t\tconst record = state.alignments.find((candidate) => candidate.id === id);\n\t\t\tif (!record) throw new Error(`unknown alignment: ${id}`);\n\t\t\tif (record.status !== \"aligning\") throw new Error(`alignment is ${record.status}: ${id}`);\n\t\t\tif (!api.session?.sendMessage) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t\"host session does not expose sendMessage; the alignment confirmation page cannot deliver feedback on this host\",\n\t\t\t\t);\n\t\t\t}\n\t\t\tconst running = await ensureServer();\n\t\t\tconst snapshot = gate(record);\n\t\t\treturn {\n\t\t\t\tstate,\n\t\t\t\talignmentId: record.id,\n\t\t\t\turl: running.url,\n\t\t\t\tstep: record.activeStep,\n\t\t\t\tround: record.roundCount,\n\t\t\t\trevision: record.revision,\n\t\t\t\tprogress: {\n\t\t\t\t\tunapproved: snapshot.unapproved,\n\t\t\t\t\topenComments: snapshot.openComments,\n\t\t\t\t\tpendingAdditions: snapshot.pendingAdditions,\n\t\t\t\t\tallGreen: snapshot.allGreen,\n\t\t\t\t},\n\t\t\t};\n\t\t},\n\t});\n\n\tconst advanceTool = api.registerTool({\n\t\tname: \"alignment_advance\",\n\t\tlabel: \"Advance alignment\",\n\t\tdescription:\n\t\t\t\"inspect (read-only status/gate/baseline), retreat (roll back to an earlier step, resets downstream confirmations), or cancel the alignment\",\n\t\tparameters: advanceSchema,\n\t\tpromptGuidelines: PROMPT_GUIDELINES,\n\t\trenderResult: alignmentToolResultRenderer,\n\t\texecute: async (first: unknown, second?: unknown) => {\n\t\t\tconst input = toolInput(first, second) as unknown as AdvanceInput;\n\t\t\tif (input.action === \"inspect\") {\n\t\t\t\tconst record = state.alignments.find((candidate) => candidate.id === input.alignmentId);\n\t\t\t\tif (!record) throw new Error(`unknown alignment: ${input.alignmentId}`);\n\t\t\t\treturn {\n\t\t\t\t\tstate,\n\t\t\t\t\talignmentId: record.id,\n\t\t\t\t\tgate: gate(record),\n\t\t\t\t\tbaseline: record.status === \"completed\" ? finalBaselineLines(record) : undefined,\n\t\t\t\t};\n\t\t\t}\n\t\t\tconst run = applyAlignmentAdvance(state, input);\n\t\t\tpersist(run.state, run.transitions);\n\t\t\treturn { state, alignmentId: input.alignmentId };\n\t\t},\n\t});\n\n\tconst command = api.registerCommand({\n\t\tname: \"alignment\",\n\t\tdescription:\n\t\t\t\"Show this session's alignments (progress, blockers, audit log); `export [id] [path]` writes a self-contained read-only HTML snapshot\",\n\t\texecute: async (args: string, context?: { cwd?: string }): Promise<CapabilityCommandResult> => {\n\t\t\ttry {\n\t\t\t\tconst parts = args\n\t\t\t\t\t.trim()\n\t\t\t\t\t.split(/\\s+/)\n\t\t\t\t\t.filter((part) => part !== \"\");\n\t\t\t\tif (parts.length === 0) return { status: \"success\", message: listLines(state) };\n\t\t\t\tif (parts[0] === \"why\") {\n\t\t\t\t\tconst record =\n\t\t\t\t\t\tstate.alignments.find((candidate) => candidate.status === \"aligning\") ?? state.alignments.at(-1);\n\t\t\t\t\tif (!record) return { status: \"error\", message: \"no alignments in this session\" };\n\t\t\t\t\tconst extra =\n\t\t\t\t\t\tcachedRound && deliveredRoundByAlignment.get(record.id) !== cachedRound.result.round\n\t\t\t\t\t\t\t? `\\nundelivered round: r${cachedRound.result.round} (injection failed; the page can retry)`\n\t\t\t\t\t\t\t: \"\";\n\t\t\t\t\treturn { status: \"success\", message: whyLines(record) + extra };\n\t\t\t\t}\n\t\t\t\tif (parts[0] === \"log\") {\n\t\t\t\t\tconst count = Number.parseInt(parts[1] ?? \"20\", 10);\n\t\t\t\t\treturn {\n\t\t\t\t\t\tstatus: \"success\",\n\t\t\t\t\t\tmessage: logLines(loadTransitions(api), Number.isFinite(count) && count > 0 ? count : 20),\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t\tif (parts[0] === \"export\") {\n\t\t\t\t\tconst id = parts[1];\n\t\t\t\t\tconst record = id\n\t\t\t\t\t\t? state.alignments.find((candidate) => candidate.id === id)\n\t\t\t\t\t\t: (state.alignments.find((candidate) => candidate.status === \"aligning\") ??\n\t\t\t\t\t\t\tstate.alignments.find((candidate) => candidate.status === \"finalizing\") ??\n\t\t\t\t\t\t\tstate.alignments.at(-1));\n\t\t\t\t\tif (!record) return { status: \"error\", message: `unknown alignment: ${id ?? \"(none in session)\"}` };\n\t\t\t\t\t// Explicit user request — the only path that writes a file.\n\t\t\t\t\tconst target = exportTargetPath(context?.cwd ?? process.cwd(), record, parts[2]);\n\t\t\t\t\tconst written = writeAlignmentExport(record, loadTransitions(api), target);\n\t\t\t\t\treturn {\n\t\t\t\t\t\tstatus: \"success\",\n\t\t\t\t\t\tmessage: `exported: ${written}`,\n\t\t\t\t\t\tlinks: [{ label: written, url: `file:///${written.split(\"\\\\\").join(\"/\")}` }],\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t\treturn {\n\t\t\t\t\tstatus: \"error\",\n\t\t\t\t\tmessage: \"Usage: /alignment | /alignment why | /alignment log [N] | /alignment export [id] [path]\",\n\t\t\t\t};\n\t\t\t} catch (error) {\n\t\t\t\treturn { status: \"error\", message: error instanceof Error ? error.message : String(error) };\n\t\t\t}\n\t\t},\n\t});\n\n\tconst stopServer = (): void => {\n\t\tconst stopping = server;\n\t\tserver = undefined;\n\t\tif (stopping) void stopping.stop().catch(() => undefined);\n\t};\n\n\t// The command registration doubles as the teardown hook for the local\n\t// confirmation server (plugin dispose must release the port).\n\tconst commandWithTeardown: DisposableRegistration = {\n\t\tid: command.id,\n\t\tkind: command.kind,\n\t\tdispose: () => {\n\t\t\tvoid command.dispose();\n\t\t\tstopServer();\n\t\t},\n\t};\n\n\treturn [setTool, roundTool, advanceTool, commandWithTeardown];\n}\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Alignment capability plugin (M1 of `docs/design/需求对齐插件设计.md`): a\n * three-step requirement-alignment funnel (objective → detail → design) with\n * block-level bidirectional feedback confirmed on a local HTML page.\n *\n * Persistence protocol, structurally identical to the goal/plan/todo/workflow\n * plugins: append-only `alignment.state` full snapshots (the single rebuild\n * source) plus one `alignment.transition` audit entry per conversion,\n * announced as `alignment.changed` (version 1, correlationId\n * \"alignment.state\", data = the complete AlignmentState snapshot).\n *\n * The round wait is non-blocking (设计 §5 总则 8): alignment_round returns the\n * page URL immediately; page feedback arrives as a `alignment.feedback`\n * custom message injected through SessionAPI.sendMessage (triggerTurn), and a\n * round only closes after the injection succeeded (`round.delivered`,\n * terminal audit D1).\n */\n\nimport type { CapabilityAPI, CapabilityCommandResult, DisposableRegistration } from \"@agent-forge/plugin-sdk\";\nimport { Type } from \"typebox\";\nimport {\n\ttype AdvanceInput,\n\ttype AlignmentSetInput,\n\tactiveStep,\n\tapplyAlignmentAdvance,\n\tapplyAlignmentSet,\n\tapplyRoundPost,\n\tapplyVersionRollback,\n\ttype EngineRun,\n\tfinalBaselineLines,\n\tgate,\n\tmarkDelivered,\n} from \"./engine.ts\";\nimport { exportTargetPath, writeAlignmentExport } from \"./export.ts\";\nimport { type AlignmentServer, startAlignmentServer } from \"./http-server.ts\";\nimport { alignmentToolResultRenderer } from \"./render.ts\";\nimport {\n\tAlignmentError,\n\ttype AlignmentRecord,\n\ttype AlignmentRoundPost,\n\ttype AlignmentRoundResult,\n\ttype AlignmentState,\n\ttype AlignmentTransitionEntry,\n\ttype PendingItem,\n} from \"./types.ts\";\n\nconst STATE_ENTRY = \"alignment.state\";\nconst TRANSITION_ENTRY = \"alignment.transition\";\nconst GOAL_STATE_ENTRY = \"goal.state\";\n/** Round post outcomes cached until delivered — the retry-injection window (终审 D1). */\ninterface CachedRound {\n\tpost: AlignmentRoundPost;\n\trecord: AlignmentRecord;\n\ttransitions: AlignmentTransitionEntry[];\n\tresult: AlignmentRoundResult;\n}\n\nexport interface AlignmentCapabilityOptions {\n\t/** Injection seam for deterministic tests; production binds an OS-assigned port. */\n\tserverPort?: number;\n}\n\nfunction isObject(value: unknown): value is Record<string, unknown> {\n\treturn value !== null && typeof value === \"object\" && !Array.isArray(value);\n}\n\n/**\n * 双调用约定(走查 2026-10-04,goal 插件同款问题的严谨版):会话路径以\n * (toolCallId, params, signal, onUpdate) 调用插件工具——first 是调用 id 字符串;\n * runtime facade 以 (input, context?, signal?) 调用——first 是入参对象。\n * 按 first 的类型区分,两条路径(含 runtime 携带 context)都取到真实入参。\n */\nfunction toolInput(first: unknown, second?: unknown): Record<string, unknown> {\n\tif (typeof first === \"string\") {\n\t\tif (!isObject(second)) return {};\n\t\treturn second;\n\t}\n\tif (!isObject(first)) throw new Error(\"alignment tool input must be an object\");\n\treturn first;\n}\n\nfunction loadState(api: CapabilityAPI): AlignmentState {\n\tconst entries = api.session?.getBranchEntries() ?? [];\n\tconst entry = [...entries].reverse().find((item) => item.customType === STATE_ENTRY);\n\tif (!entry?.data || !isObject(entry.data)) return { alignments: [] };\n\tconst data = entry.data as { alignments?: unknown };\n\treturn { alignments: Array.isArray(data.alignments) ? [...(data.alignments as AlignmentRecord[])] : [] };\n}\n\nfunction loadTransitions(api: CapabilityAPI): AlignmentTransitionEntry[] {\n\tconst entries = api.session?.getBranchEntries() ?? [];\n\treturn entries\n\t\t.filter((item) => item.customType === TRANSITION_ENTRY)\n\t\t.map((item) => item.data as AlignmentTransitionEntry)\n\t\t.filter((item): item is AlignmentTransitionEntry => isObject(item));\n}\n\n/** Advisory goalId check (#10 soft-reference discipline, goal/plan precedent). */\nfunction goalKnownToSession(api: CapabilityAPI, goalId: string): boolean {\n\tconst entries = api.session?.getBranchEntries() ?? [];\n\tfor (let index = entries.length - 1; index >= 0; index -= 1) {\n\t\tconst entry = entries[index];\n\t\tif (entry.customType !== GOAL_STATE_ENTRY) continue;\n\t\tconst data = entry.data;\n\t\tif (!isObject(data)) return false;\n\t\tconst goals = data.goals;\n\t\tif (!Array.isArray(goals)) return false;\n\t\treturn goals.some((goal) => isObject(goal) && goal.id === goalId);\n\t}\n\treturn false;\n}\n\n/** Page projection (state.json): everything the fixed template renders. */\nfunction pageView(\n\trecord: AlignmentRecord,\n\tbaselineFile: string | undefined,\n\tawaitingRevision: boolean,\n): Record<string, unknown> {\n\tconst snapshot = gate(record);\n\t// gate already validated the active step exists (it throws otherwise).\n\tconst blocks = activeStep(record).blocks;\n\t// 终审/终态头部展示跨步总口径(走查 2026-10-03):completed 后仍按当前步\n\t// 计数会显示「已确认 0/1」这类误导数字。\n\tconst countedBlocks = record.status === \"aligning\" ? blocks : record.steps.flatMap((s) => s.blocks);\n\treturn {\n\t\talignmentId: record.id,\n\t\ttitle: record.title,\n\t\tgoalId: record.goalId,\n\t\tstatus: record.status,\n\t\trevision: record.revision,\n\t\tround: record.roundCount,\n\t\tactiveStep: record.activeStep,\n\t\tsteps: record.steps.map((step) => ({\n\t\t\tstep: step.step,\n\t\t\tstatus: step.status,\n\t\t\tblocks: step.blocks.map((block) => ({\n\t\t\t\tid: block.id,\n\t\t\t\tkind: block.kind,\n\t\t\t\tcontent: block.content,\n\t\t\t\trationale: block.rationale,\n\t\t\t\timpact: block.impact,\n\t\t\t\tstatus: block.status,\n\t\t\t\tmodifiedInRound: block.modifiedInRound,\n\t\t\t\tdraftAnswer: block.draftAnswer,\n\t\t\t\tcomments: block.comments,\n\t\t\t})),\n\t\t})),\n\t\tgate: {\n\t\t\t...snapshot,\n\t\t\tapprovedCount: countedBlocks.filter((block) => block.status === \"approved\").length,\n\t\t\tblockCount: countedBlocks.length,\n\t\t},\n\t\tpendingFeedback: record.pendingFeedback,\n\t\t// Version snapshots for the read-only history switcher (走查 2026-10-03).\n\t\tversions: record.versions ?? [],\n\t\tawaitingRevision,\n\t\tbaselineFile,\n\t};\n}\n\nfunction blockStateLine(block: AlignmentRecord[\"steps\"][number][\"blocks\"][number]): string {\n\tconst state = block.status === \"approved\" ? \"已确认\" : \"待确认\";\n\tconst first = block.content.split(\"\\n\")[0]?.slice(0, 80) ?? \"\";\n\tconst notes: string[] = [];\n\tfor (const comment of block.comments) {\n\t\tif (comment.status !== \"open\") continue;\n\t\tnotes.push(\n\t\t\tcomment.author === \"assistant\"\n\t\t\t\t? `AI疑问待回应:${comment.note.slice(0, 40)}`\n\t\t\t\t: `用户批注:${comment.note.slice(0, 40)}`,\n\t\t);\n\t}\n\treturn `- ${block.id}[${block.kind}|${state}] ${first}${notes.length ? `(${notes.join(\";\")})` : \"\"}`;\n}\n\nfunction historyLines(transitions: AlignmentTransitionEntry[]): string {\n\tif (transitions.length === 0) return \"(无)\";\n\treturn transitions\n\t\t.slice(-20)\n\t\t.map((entry) => {\n\t\t\tconst where = entry.step ? `${entry.step} ` : \"\";\n\t\t\treturn `rev${entry.revision} ${where}${entry.event}${entry.reason.detail ? `(${entry.reason.detail.slice(0, 60)})` : \"\"}`;\n\t\t})\n\t\t.join(\"\\n\");\n}\n\nfunction feedbackMessage(\n\trecord: AlignmentRecord,\n\tresult: AlignmentRoundResult,\n\ttransitions: AlignmentTransitionEntry[],\n): string {\n\tconst snapshot = gate(record);\n\tconst lines: string[] = [];\n\tlines.push(\n\t\t`[alignment.feedback] ${result.alignmentId} 第 ${result.round} 轮(${result.step} 步,revision ${result.revision},status ${record.status})`,\n\t);\n\tlines.push(\"== 本轮反馈 ==\");\n\tif (result.approvals.length > 0) lines.push(`确认块:${result.approvals.join(\", \")}`);\n\tfor (const comment of result.comments) {\n\t\tlines.push(\n\t\t\t`用户批注[${comment.blockId}]${comment.escalate ? \"(上游问题)\" : \"\"}:「${comment.quote}」→ ${comment.note}`,\n\t\t);\n\t}\n\tfor (const reply of result.commentReplies) {\n\t\tlines.push(\n\t\t\treply.dismiss\n\t\t\t\t? `AI 疑问 ${reply.commentId}:用户标记不重要`\n\t\t\t\t: `AI 疑问 ${reply.commentId} 的回答:${reply.answer}`,\n\t\t);\n\t}\n\tfor (const answer of result.answers) {\n\t\tlines.push(`补充答案[${answer.blockId}]:${answer.value}`);\n\t}\n\tfor (const addition of result.additions) {\n\t\tlines.push(`自由补充:${addition}`);\n\t}\n\tif (result.stepConfirmed) {\n\t\tif (record.status === \"completed\") {\n\t\t\tlines.push(\"用户已在终审总览确认基线——对齐完成。请输出最终基线总结(plan 输入)。\");\n\t\t\tif (result.finalBaseline) {\n\t\t\t\tlines.push(\"最终基线紧凑清单:\");\n\t\t\t\tfor (const line of result.finalBaseline) {\n\t\t\t\t\tlines.push(` [${line.kind}] ${line.id}: ${line.line}`);\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\tlines.push(\"用户已确认本步——基线锁定。请 alignment_set 出下一步块集并 alignment_round 刷新。\");\n\t\t}\n\t}\n\tlines.push(\"== 当前块集(全量状态)==\");\n\tif (record.status === \"finalizing\") {\n\t\tlines.push(\"三步基线已全部锁定,等待用户终审总览确认;此阶段无需你操作。\");\n\t} else {\n\t\tfor (const step of record.steps) {\n\t\t\tif (step.blocks.length === 0) continue;\n\t\t\tlines.push(`[${step.step}|${step.status}]`);\n\t\t\tfor (const block of step.blocks) lines.push(blockStateLine(block));\n\t\t}\n\t\tlines.push(\n\t\t\t`待办:${snapshot.unapproved} 块待确认、${snapshot.openComments} 批注未清、${snapshot.pendingAdditions} 补充未落账。`,\n\t\t);\n\t}\n\tlines.push(\"== 历史轮次(revision 锚点)==\");\n\tlines.push(historyLines(transitions));\n\treturn lines.join(\"\\n\");\n}\n\nconst PROMPT_GUIDELINES: readonly string[] = [\n\t\"进入分流(预检规则):用户显式要求对齐时直接进入;否则先做零成本预检——列出缺失信息、被迫假设、矛盾歧义。三项全空则一行结论直接出方案(跳过证据必须可见,禁止静默跳过);有任一项则列出要点并建议对齐,用户说直接做则跳过、但未决假设须在方案中显式标注。预检清单在对齐时直接作为第一轮块种子。\",\n\t\"三步铁律:objective 只谈方向与非目标(≤10 块);detail 只谈业务规则/公式/数据流/异常(禁止技术选型);design 谈技术方案且不得与已锁定基线矛盾,发现矛盾必须停下向用户提出。\",\n\t\"视觉对齐(涉及用户可见界面的任务):design 步必须产出 visual 视觉方向块——按六节契约(风格宣言/配色角色表/布局与层级策略/文案密度预算/视觉验收清单/明确不做项)逐节落块,建议委派 design-proposer 出厂角色产出(subagent_run role=design-proposer,其指令内嵌保底资产);纯后端/重构任务不产 visual 块;实现完成后渲染产物交 visual-reviewer 角色做视觉验收(防丑下限)。\",\n\t\"块纪律:假设单独成 assumption 块;缺信息产 missing 块而不是脑补;可自查的先取证落 fact;assistant 批注只用于真实不确定点(公式口径、二义表述、潜在矛盾、与基线冲突)。\",\n\t\"修订纪律:最小改动已确认的块(内容不变即继承确认);每次 alignment_set 之后必须跟 alignment_round 告知用户去看新版;用户批注的 quote 匹配失败时向用户说明而不是猜。\",\n\t\"填空落账:收到补充答案(补充答案[blockId])后,下一次 alignment_set 必须把答案重写进对应块内容并转为 fact/decision(missing 块不得带着未并入的答案被确认锁定);注入消息的「当前块集(全量状态)」是权威现状,以它为准做最小修订。\",\n\t\"终审阶段(status finalizing):三步基线已全部锁定,页面进入只读总览,唯一动作是用户最终确认——此阶段不要调用 alignment_set;收到终审确认消息(alignment completed)即视为开发授权:先输出一行极简基线摘要,然后直接按基线实现——用 plan/todo 把基线拆成可执行任务,实现并自测,完成后向用户报告结果与验收方式。不要停在基线总结等用户再次指令(dogfood 2026-10-04:等指令会打断对齐→开发衔接)。\",\n\t\"页面回退:用户可在页面上把任务回退到更早环节(step.retreated,后续环节作废重走)或把当前步回退到历史版本(version.rolled-back,当前未确认版本丢弃、批注保留)。收到这类消息后,以注入消息里的全量块集为准重新修订,不要复用回退前的块集。\",\n];\n\nconst setSchema = Type.Object({\n\tid: Type.String({ description: \"Stable alignment id; charset [A-Za-z0-9._-], no leading dot\" }),\n\ttitle: Type.Optional(Type.String({ description: \"Human-readable alignment title\" })),\n\tgoalId: Type.Optional(Type.String({ description: \"Soft goal reference; unknown ids only warn\" })),\n\trevision: Type.Optional(Type.Integer({ description: \"Monotonic revision; must exceed the stored one\", minimum: 0 })),\n\tblocks: Type.Array(\n\t\tType.Object({\n\t\t\tid: Type.String({ description: \"Stable block id within the step\" }),\n\t\t\tkind: Type.Union(\n\t\t\t\t[\n\t\t\t\t\tType.Literal(\"fact\"),\n\t\t\t\t\tType.Literal(\"assumption\"),\n\t\t\t\t\tType.Literal(\"decision\"),\n\t\t\t\t\tType.Literal(\"missing\"),\n\t\t\t\t\tType.Literal(\"visual\"),\n\t\t\t\t],\n\t\t\t\t{ description: \"fact=取证 assumption=假设 decision=决策 missing=待补充\" },\n\t\t\t),\n\t\t\tcontent: Type.String({ description: \"Block content (markdown text, ≤8192 chars)\" }),\n\t\t\trationale: Type.Optional(Type.String({ description: \"Why this decision/assumption (≤2048 chars)\" })),\n\t\t\timpact: Type.Optional(Type.Array(Type.String(), { description: \"Affected modules/files/interfaces\" })),\n\t\t\tcomments: Type.Optional(\n\t\t\t\tType.Array(\n\t\t\t\t\tType.Object({\n\t\t\t\t\t\tid: Type.String(),\n\t\t\t\t\t\tnote: Type.String({ description: \"Assistant question; only real uncertainty\" }),\n\t\t\t\t\t\tquote: Type.Optional(Type.String()),\n\t\t\t\t\t}),\n\t\t\t\t\t{ description: \"New assistant comments (AI 主动标注的不确定点)\" },\n\t\t\t\t),\n\t\t\t),\n\t\t\tcommentResolutions: Type.Optional(\n\t\t\t\tType.Array(\n\t\t\t\t\tType.Object({\n\t\t\t\t\t\tcommentId: Type.String(),\n\t\t\t\t\t\tkind: Type.Union([Type.Literal(\"answered\"), Type.Literal(\"dismissed\"), Type.Literal(\"incorporated\")]),\n\t\t\t\t\t\ttext: Type.Optional(Type.String()),\n\t\t\t\t\t}),\n\t\t\t\t\t{\n\t\t\t\t\t\tdescription:\n\t\t\t\t\t\t\t\"Resolutions for existing comments (user comments may only be resolved, never rewritten)\",\n\t\t\t\t\t},\n\t\t\t\t),\n\t\t\t),\n\t\t}),\n\t\t{ description: \"Full block set of the active step (全量提交;未变块按内容指纹继承确认)\" },\n\t),\n});\n\nconst roundSchema = Type.Object({\n\talignmentId: Type.String({ description: \"Alignment id to open the confirmation page for\" }),\n});\n\nconst advanceSchema = Type.Object({\n\talignmentId: Type.String(),\n\taction: Type.Union([Type.Literal(\"inspect\"), Type.Literal(\"retreat\"), Type.Literal(\"cancel\")]),\n\tstep: Type.Optional(\n\t\tType.Union([Type.Literal(\"objective\"), Type.Literal(\"detail\"), Type.Literal(\"design\")], {\n\t\t\tdescription: \"Retreat target; must be an earlier step\",\n\t\t}),\n\t),\n\tnote: Type.Optional(Type.String({ description: \"Retreat reason (required for retreat)\" })),\n});\n\nfunction pendingText(items: PendingItem[]): string {\n\tif (items.length === 0) return \"nothing pending\";\n\tconst reasons = items.map((item) => `${item.blockId}(${item.reason})`);\n\treturn reasons.join(\" \");\n}\n\nfunction listLines(state: AlignmentState): string {\n\tif (state.alignments.length === 0) return \"no alignments in this session; create one with alignment_set\";\n\tconst lines = [`alignments: ${state.alignments.length}`];\n\tfor (const record of state.alignments) {\n\t\tconst snapshot = gate(record);\n\t\tlines.push(\n\t\t\t`- ${record.id} [${record.status} → ${record.goalId ?? \"-\"}] ${record.title} · ${record.activeStep} r${record.roundCount} · ${snapshot.unapproved} pending / ${snapshot.openComments} open`,\n\t\t);\n\t}\n\treturn lines.join(\"\\n\");\n}\n\nfunction whyLines(record: AlignmentRecord): string {\n\tconst snapshot = gate(record);\n\tconst lines = [`${record.id} · ${record.activeStep} · round ${record.roundCount}`];\n\tif (record.status !== \"aligning\") {\n\t\tlines.push(`status ${record.status} — nothing to wait for`);\n\t\treturn lines.join(\"\\n\");\n\t}\n\tif (snapshot.allGreen) {\n\t\tlines.push(\"ALL GREEN — waiting for the user to click 确认完成 on the page\");\n\t\treturn lines.join(\"\\n\");\n\t}\n\tlines.push(`pending: ${pendingText(snapshot.pending)}`);\n\tif (snapshot.pendingAdditions > 0) {\n\t\tlines.push(`undelivered additions: ${record.pendingFeedback?.additions.join(\" | \")}`);\n\t}\n\treturn lines.join(\"\\n\");\n}\n\nfunction logLines(transitions: AlignmentTransitionEntry[], count: number): string {\n\tif (transitions.length === 0) return \"no alignment transitions recorded\";\n\tconst slice = transitions.slice(-count).reverse();\n\treturn slice\n\t\t.map((entry, index) => {\n\t\t\tconst where = entry.step ? `${entry.step} ` : \"\";\n\t\t\treturn `${slice.length - index}. [r${entry.round ?? \"-\"} rev${entry.revision}] ${where}${entry.event} ${entry.reason.code}${entry.reason.detail ? ` — ${entry.reason.detail}` : \"\"}`;\n\t\t})\n\t\t.join(\"\\n\");\n}\n\nexport function createCapability(\n\tapi: CapabilityAPI,\n\toptions: AlignmentCapabilityOptions = {},\n): readonly DisposableRegistration[] {\n\tlet state = loadState(api);\n\tlet server: AlignmentServer | undefined;\n\tlet cachedRound: CachedRound | undefined;\n\tconst deliveredRoundByAlignment = new Map<string, number>();\n\t/** Revision at last successful injection — awaitingRevision = delivered and not yet superseded by a set. */\n\tconst deliveredRevisionByAlignment = new Map<string, number>();\n\n\tconst persist = (next: AlignmentState, transitions: AlignmentTransitionEntry[]): AlignmentState => {\n\t\tstate = next;\n\t\tapi.session?.appendEntry(STATE_ENTRY, state);\n\t\tfor (const entry of transitions) api.session?.appendEntry(TRANSITION_ENTRY, entry);\n\t\tvoid api.publish({ type: \"alignment.changed\", version: 1, correlationId: STATE_ENTRY, data: state });\n\t\treturn state;\n\t};\n\n\tconst activeRecord = (): AlignmentRecord | undefined =>\n\t\tstate.alignments.find((record) => record.status === \"aligning\") ??\n\t\t[...state.alignments].reverse().find((record) => record.status !== \"aligning\");\n\n\tconst ensureServer = async (): Promise<AlignmentServer> => {\n\t\t// 页面生命周期(走查 2026-10-04 用户裁决):服务随第一个 alignment_round\n\t\t// 启动后常驻到插件 dispose(会话关闭);终态对齐的页面保持可查看,直到\n\t\t// 下一次对齐在同一 URL 上覆盖内容。不再做终态 idle 停服。\n\t\tif (server) return server;\n\t\tserver = await startAlignmentServer(\n\t\t\t{\n\t\t\t\tgetState: () => {\n\t\t\t\t\tconst record = activeRecord();\n\t\t\t\t\tif (!record) return undefined;\n\t\t\t\t\t// awaitingRevision: feedback was delivered and the model has not\n\t\t\t\t\t// bumped the revision yet — the page shows \"AI revising…\".\n\t\t\t\t\tconst awaiting =\n\t\t\t\t\t\trecord.status === \"aligning\" && deliveredRevisionByAlignment.get(record.id) === record.revision;\n\t\t\t\t\treturn pageView(record, undefined, awaiting);\n\t\t\t\t},\n\t\t\t\tonRoundPost: (post) => handleRoundPost(post),\n\t\t\t},\n\t\t\t{ port: options.serverPort },\n\t\t);\n\t\treturn server;\n\t};\n\n\tconst injectFeedback = async (cached: CachedRound): Promise<void> => {\n\t\tconst message = feedbackMessage(cached.record, cached.result, loadTransitions(api));\n\t\tconst send = api.session?.sendMessage;\n\t\tif (!send) {\n\t\t\tthrow new AlignmentError(\n\t\t\t\t\"invalid-input\",\n\t\t\t\t\"host session does not expose sendMessage; feedback cannot be injected\",\n\t\t\t);\n\t\t}\n\t\tawait send({ customType: \"alignment.feedback\", content: message, display: true }, { triggerTurn: true });\n\t};\n\n\tconst handleRoundPost = async (post: AlignmentRoundPost): Promise<{ status: number; body: unknown }> => {\n\t\tconst record = activeRecord();\n\t\tif (!record || (record.status !== \"aligning\" && record.status !== \"finalizing\")) {\n\t\t\treturn { status: 409, body: { error: \"no alignment in progress\" } };\n\t\t}\n\t\tconst samePost = (candidate: CachedRound): boolean =>\n\t\t\tcandidate.result.alignmentId === record.id && JSON.stringify(candidate.post) === JSON.stringify(post);\n\t\t// Delivered idempotency: an identical replay of an already-delivered\n\t\t// round returns the snapshot without re-injecting.\n\t\tconst pending = cachedRound;\n\t\tif (pending && samePost(pending) && deliveredRoundByAlignment.get(record.id) === pending.result.round) {\n\t\t\treturn {\n\t\t\t\tstatus: 200,\n\t\t\t\tbody: {\n\t\t\t\t\tok: true,\n\t\t\t\t\tdelivered: true,\n\t\t\t\t\tstepConfirmed: pending.result.stepConfirmed,\n\t\t\t\t\trevision: pending.record.revision,\n\t\t\t\t},\n\t\t\t};\n\t\t}\n\t\t// Submitted-but-undelivered replay retries only the injection.\n\t\tif (pending && samePost(pending)) {\n\t\t\ttry {\n\t\t\t\tawait injectFeedback(pending);\n\t\t\t\t// 同主路径:注入可能同步驱动模型回合,不回写回合前快照(走查 2026-10-04)。\n\t\t\t\tfor (const entry of markDelivered(pending.record, pending.result.round)) {\n\t\t\t\t\tapi.session?.appendEntry(TRANSITION_ENTRY, entry);\n\t\t\t\t}\n\t\t\t\tvoid api.publish({\n\t\t\t\t\ttype: \"alignment.changed\",\n\t\t\t\t\tversion: 1,\n\t\t\t\t\tcorrelationId: STATE_ENTRY,\n\t\t\t\t\tdata: loadState(api),\n\t\t\t\t});\n\t\t\t\tstate = loadState(api);\n\t\t\t\tdeliveredRoundByAlignment.set(record.id, pending.result.round);\n\t\t\t\t// 重放路径同主路径:纯确认轮不进入\"AI 修订中\"(走查 2026-10-04)。\n\t\t\t\tconst replayHasContent =\n\t\t\t\t\tpending.result.comments.length > 0 ||\n\t\t\t\t\tpending.result.commentReplies.length > 0 ||\n\t\t\t\t\tpending.result.answers.length > 0 ||\n\t\t\t\t\tpending.result.additions.length > 0;\n\t\t\t\tif (replayHasContent) deliveredRevisionByAlignment.set(record.id, pending.record.revision);\n\t\t\t\treturn {\n\t\t\t\t\tstatus: 200,\n\t\t\t\t\tbody: {\n\t\t\t\t\t\tok: true,\n\t\t\t\t\t\tdelivered: true,\n\t\t\t\t\t\tstepConfirmed: pending.result.stepConfirmed,\n\t\t\t\t\t\trevision: pending.record.revision,\n\t\t\t\t\t},\n\t\t\t\t};\n\t\t\t} catch (error) {\n\t\t\t\treturn {\n\t\t\t\t\tstatus: 503,\n\t\t\t\t\tbody: {\n\t\t\t\t\t\terror: `feedback delivery failed: ${error instanceof Error ? error.message : String(error)}`,\n\t\t\t\t\t\tretry: true,\n\t\t\t\t\t},\n\t\t\t\t};\n\t\t\t}\n\t\t}\n\t\t// Page-initiated rollbacks (走查 2026-10-03) share the POST /round\n\t\t// entry so the submission→injection→delivered protocol is identical.\n\t\tlet outcome: ReturnType<typeof applyRoundPost> | undefined;\n\t\tlet runOutcome: ReturnType<typeof applyAlignmentAdvance> | undefined;\n\t\ttry {\n\t\t\tif (post.action === \"retreat\" || post.action === \"rollback\") {\n\t\t\t\tif (post.baseRevision !== record.revision) {\n\t\t\t\t\treturn {\n\t\t\t\t\t\tstatus: 409,\n\t\t\t\t\t\tbody: { code: \"stale-state\", error: \"page snapshot is stale; reload and retry\" },\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (post.action === \"retreat\") {\n\t\t\t\trunOutcome = applyAlignmentAdvance(state, {\n\t\t\t\t\talignmentId: record.id,\n\t\t\t\t\taction: \"retreat\",\n\t\t\t\t\tstep: post.targetStep,\n\t\t\t\t\tnote: \"回退自确认页:用户在页面上点击了更早的环节\",\n\t\t\t\t});\n\t\t\t} else if (post.action === \"rollback\") {\n\t\t\t\trunOutcome = applyVersionRollback(state, {\n\t\t\t\t\talignmentId: record.id,\n\t\t\t\t\ttargetRevision: post.targetRevision ?? -1,\n\t\t\t\t});\n\t\t\t} else {\n\t\t\t\toutcome = applyRoundPost(record, post);\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tif (error instanceof AlignmentError) {\n\t\t\t\treturn {\n\t\t\t\t\tstatus: error.code === \"stale-state\" ? 409 : 400,\n\t\t\t\t\tbody: { code: error.code, error: error.message },\n\t\t\t\t};\n\t\t\t}\n\t\t\treturn { status: 500, body: { error: error instanceof Error ? error.message : String(error) } };\n\t\t}\n\t\t// Persist the submission first (append-only fact), then attempt delivery.\n\t\tconst record2 = outcome\n\t\t\t? outcome.record\n\t\t\t: (runOutcome!.state.alignments.find((candidate) => candidate.id === record.id) as AlignmentRecord);\n\t\tconst transitions2 = outcome ? outcome.transitions : runOutcome!.transitions;\n\t\tpersist(\n\t\t\t{\n\t\t\t\talignments: state.alignments.map((candidate) => (candidate.id === record2.id ? record2 : candidate)),\n\t\t\t},\n\t\t\ttransitions2,\n\t\t);\n\t\tconst syntheticResult: AlignmentRoundResult = outcome?.result ?? {\n\t\t\talignmentId: record2.id,\n\t\t\tround: record2.roundCount,\n\t\t\tstep: record2.activeStep,\n\t\t\trevision: record2.revision,\n\t\t\tapprovals: [],\n\t\t\tcomments: [],\n\t\t\tcommentReplies: [],\n\t\t\tanswers: [],\n\t\t\tadditions: [],\n\t\t\tstepConfirmed: false,\n\t\t};\n\t\tlet cached: CachedRound = { post, record: record2, transitions: [], result: syntheticResult };\n\t\tif (outcome?.result.stepConfirmed && outcome.record.status === \"completed\") {\n\t\t\t// 终审确认(走查 2026-10-03):no workspace file is written; the\n\t\t\t// compact listing rides the feedback message and `/alignment\n\t\t\t// export` produces a file only on explicit request.\n\t\t\tconst lines = finalBaselineLines(outcome.record);\n\t\t\toutcome.result.finalBaseline = lines;\n\t\t\tcached = { ...cached, result: outcome.result };\n\t\t}\n\t\tcachedRound = cached;\n\t\ttry {\n\t\t\tawait injectFeedback(cached);\n\t\t\t// injectFeedback 的 sendMessage(triggerTurn) 会同步驱动整个模型回合\n\t\t\t//(agent-session sendCustomMessage → _runAgentPrompt):回合内的\n\t\t\t// alignment_set 已把修订落账 entries。此处若回写回合前快照,会把模型\n\t\t\t// 刚提交的修订整体抹掉(走查 2026-10-04 dogfood:细节步 10 块被还原成\n\t\t\t// 空步)。只追加 round.delivered 审计条目,并从 entries 重建内存态。\n\t\t\tfor (const entry of markDelivered(cached.record, cached.result.round)) {\n\t\t\t\tapi.session?.appendEntry(TRANSITION_ENTRY, entry);\n\t\t\t}\n\t\t\tvoid api.publish({ type: \"alignment.changed\", version: 1, correlationId: STATE_ENTRY, data: loadState(api) });\n\t\t\tstate = loadState(api);\n\t\t\tdeliveredRoundByAlignment.set(cached.record.id, cached.result.round);\n\t\t\t// 只有携带内容反馈(批注/回复/答案/补充)的轮次才进入\"AI 修订中\":\n\t\t\t// 纯确认轮模型正确地不重发块,revision 不变——若也标记 awaiting,\n\t\t\t// 页面会永远钉在机器人等待屏,用户反而无法确认剩余块(走查 2026-10-04)。\n\t\t\tconst hasContentFeedback =\n\t\t\t\tpost.comments.length > 0 ||\n\t\t\t\tpost.commentReplies.length > 0 ||\n\t\t\t\tpost.answers.length > 0 ||\n\t\t\t\tpost.additions.length > 0;\n\t\t\tif (hasContentFeedback) deliveredRevisionByAlignment.set(cached.record.id, cached.record.revision);\n\t\t\treturn {\n\t\t\t\tstatus: 200,\n\t\t\t\tbody: {\n\t\t\t\t\tok: true,\n\t\t\t\t\tdelivered: true,\n\t\t\t\t\tstepConfirmed: cached.result.stepConfirmed,\n\t\t\t\t\trevision: cached.record.revision,\n\t\t\t\t},\n\t\t\t};\n\t\t} catch (error) {\n\t\t\treturn {\n\t\t\t\tstatus: 503,\n\t\t\t\tbody: {\n\t\t\t\t\terror: `feedback delivery failed: ${error instanceof Error ? error.message : String(error)}`,\n\t\t\t\t\tretry: true,\n\t\t\t\t},\n\t\t\t};\n\t\t}\n\t};\n\n\tconst runSet = (input: AlignmentSetInput): Record<string, unknown> => {\n\t\tconst run: EngineRun = applyAlignmentSet(state, input);\n\t\tconst record = run.state.alignments.find((candidate) => candidate.id === input.id);\n\t\tpersist(run.state, run.transitions);\n\t\tconst warning =\n\t\t\trecord?.goalId && !goalKnownToSession(api, record.goalId)\n\t\t\t\t? `goalId \"${record.goalId}\" does not match any goal in this session's goal state; the alignment keeps the soft reference`\n\t\t\t\t: undefined;\n\t\treturn { state, alignmentId: input.id, ...(warning ? { warning } : {}) };\n\t};\n\n\tconst setTool = api.registerTool({\n\t\tname: \"alignment_set\",\n\t\tlabel: \"Set alignment\",\n\t\tdescription:\n\t\t\t\"Create or update a requirement alignment task: full block set of the active step (goal→detail→design funnel). Unchanged blocks inherit user approval by content fingerprint\",\n\t\tparameters: setSchema,\n\t\tpromptGuidelines: PROMPT_GUIDELINES,\n\t\trenderResult: alignmentToolResultRenderer,\n\t\t// 双调用约定(goal 插件同款,走查 2026-10-04):会话路径传\n\t\t// (toolCallId, params, signal, onUpdate),runtime facade 路径传\n\t\t// (input, context?, signal?)——second 缺省时取 first。\n\t\texecute: async (first: unknown, second?: unknown) => {\n\t\t\tconst input = toolInput(first, second);\n\t\t\treturn runSet(input as unknown as AlignmentSetInput);\n\t\t},\n\t});\n\n\tconst roundTool = api.registerTool({\n\t\tname: \"alignment_round\",\n\t\tlabel: \"Open alignment page\",\n\t\tdescription:\n\t\t\t\"Open (or refresh) the local confirmation page for the active alignment and return its URL plus progress facts. Non-blocking: feedback arrives later as an alignment.feedback message\",\n\t\tparameters: roundSchema,\n\t\tpromptGuidelines: PROMPT_GUIDELINES,\n\t\trenderResult: alignmentToolResultRenderer,\n\t\texecute: async (first: unknown, second?: unknown) => {\n\t\t\tconst input = toolInput(first, second);\n\t\t\tconst id = typeof input.alignmentId === \"string\" ? input.alignmentId : \"\";\n\t\t\tconst record = state.alignments.find((candidate) => candidate.id === id);\n\t\t\tif (!record) throw new Error(`unknown alignment: ${id}`);\n\t\t\tif (record.status !== \"aligning\") throw new Error(`alignment is ${record.status}: ${id}`);\n\t\t\tif (!api.session?.sendMessage) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t\"host session does not expose sendMessage; the alignment confirmation page cannot deliver feedback on this host\",\n\t\t\t\t);\n\t\t\t}\n\t\t\tconst running = await ensureServer();\n\t\t\tconst snapshot = gate(record);\n\t\t\treturn {\n\t\t\t\tstate,\n\t\t\t\talignmentId: record.id,\n\t\t\t\turl: running.url,\n\t\t\t\tstep: record.activeStep,\n\t\t\t\tround: record.roundCount,\n\t\t\t\trevision: record.revision,\n\t\t\t\tprogress: {\n\t\t\t\t\tunapproved: snapshot.unapproved,\n\t\t\t\t\topenComments: snapshot.openComments,\n\t\t\t\t\tpendingAdditions: snapshot.pendingAdditions,\n\t\t\t\t\tallGreen: snapshot.allGreen,\n\t\t\t\t},\n\t\t\t};\n\t\t},\n\t});\n\n\tconst advanceTool = api.registerTool({\n\t\tname: \"alignment_advance\",\n\t\tlabel: \"Advance alignment\",\n\t\tdescription:\n\t\t\t\"inspect (read-only status/gate/baseline), retreat (roll back to an earlier step, resets downstream confirmations), or cancel the alignment\",\n\t\tparameters: advanceSchema,\n\t\tpromptGuidelines: PROMPT_GUIDELINES,\n\t\trenderResult: alignmentToolResultRenderer,\n\t\texecute: async (first: unknown, second?: unknown) => {\n\t\t\tconst input = toolInput(first, second) as unknown as AdvanceInput;\n\t\t\tif (input.action === \"inspect\") {\n\t\t\t\tconst record = state.alignments.find((candidate) => candidate.id === input.alignmentId);\n\t\t\t\tif (!record) throw new Error(`unknown alignment: ${input.alignmentId}`);\n\t\t\t\treturn {\n\t\t\t\t\tstate,\n\t\t\t\t\talignmentId: record.id,\n\t\t\t\t\tgate: gate(record),\n\t\t\t\t\tbaseline: record.status === \"completed\" ? finalBaselineLines(record) : undefined,\n\t\t\t\t};\n\t\t\t}\n\t\t\tconst run = applyAlignmentAdvance(state, input);\n\t\t\tpersist(run.state, run.transitions);\n\t\t\treturn { state, alignmentId: input.alignmentId };\n\t\t},\n\t});\n\n\tconst command = api.registerCommand({\n\t\tname: \"alignment\",\n\t\tdescription:\n\t\t\t\"Show this session's alignments (progress, blockers, audit log); `export [id] [path]` writes a self-contained read-only HTML snapshot\",\n\t\texecute: async (args: string, context?: { cwd?: string }): Promise<CapabilityCommandResult> => {\n\t\t\ttry {\n\t\t\t\tconst parts = args\n\t\t\t\t\t.trim()\n\t\t\t\t\t.split(/\\s+/)\n\t\t\t\t\t.filter((part) => part !== \"\");\n\t\t\t\tif (parts.length === 0) return { status: \"success\", message: listLines(state) };\n\t\t\t\tif (parts[0] === \"why\") {\n\t\t\t\t\tconst record =\n\t\t\t\t\t\tstate.alignments.find((candidate) => candidate.status === \"aligning\") ?? state.alignments.at(-1);\n\t\t\t\t\tif (!record) return { status: \"error\", message: \"no alignments in this session\" };\n\t\t\t\t\tconst extra =\n\t\t\t\t\t\tcachedRound && deliveredRoundByAlignment.get(record.id) !== cachedRound.result.round\n\t\t\t\t\t\t\t? `\\nundelivered round: r${cachedRound.result.round} (injection failed; the page can retry)`\n\t\t\t\t\t\t\t: \"\";\n\t\t\t\t\treturn { status: \"success\", message: whyLines(record) + extra };\n\t\t\t\t}\n\t\t\t\tif (parts[0] === \"log\") {\n\t\t\t\t\tconst count = Number.parseInt(parts[1] ?? \"20\", 10);\n\t\t\t\t\treturn {\n\t\t\t\t\t\tstatus: \"success\",\n\t\t\t\t\t\tmessage: logLines(loadTransitions(api), Number.isFinite(count) && count > 0 ? count : 20),\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t\tif (parts[0] === \"export\") {\n\t\t\t\t\tconst id = parts[1];\n\t\t\t\t\tconst record = id\n\t\t\t\t\t\t? state.alignments.find((candidate) => candidate.id === id)\n\t\t\t\t\t\t: (state.alignments.find((candidate) => candidate.status === \"aligning\") ??\n\t\t\t\t\t\t\tstate.alignments.find((candidate) => candidate.status === \"finalizing\") ??\n\t\t\t\t\t\t\tstate.alignments.at(-1));\n\t\t\t\t\tif (!record) return { status: \"error\", message: `unknown alignment: ${id ?? \"(none in session)\"}` };\n\t\t\t\t\t// Explicit user request — the only path that writes a file.\n\t\t\t\t\tconst target = exportTargetPath(context?.cwd ?? process.cwd(), record, parts[2]);\n\t\t\t\t\tconst written = writeAlignmentExport(record, loadTransitions(api), target);\n\t\t\t\t\treturn {\n\t\t\t\t\t\tstatus: \"success\",\n\t\t\t\t\t\tmessage: `exported: ${written}`,\n\t\t\t\t\t\tlinks: [{ label: written, url: `file:///${written.split(\"\\\\\").join(\"/\")}` }],\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t\treturn {\n\t\t\t\t\tstatus: \"error\",\n\t\t\t\t\tmessage: \"Usage: /alignment | /alignment why | /alignment log [N] | /alignment export [id] [path]\",\n\t\t\t\t};\n\t\t\t} catch (error) {\n\t\t\t\treturn { status: \"error\", message: error instanceof Error ? error.message : String(error) };\n\t\t\t}\n\t\t},\n\t});\n\n\tconst stopServer = (): void => {\n\t\tconst stopping = server;\n\t\tserver = undefined;\n\t\tif (stopping) void stopping.stop().catch(() => undefined);\n\t};\n\n\t// The command registration doubles as the teardown hook for the local\n\t// confirmation server (plugin dispose must release the port).\n\tconst commandWithTeardown: DisposableRegistration = {\n\t\tid: command.id,\n\t\tkind: command.kind,\n\t\tdispose: () => {\n\t\t\tvoid command.dispose();\n\t\t\tstopServer();\n\t\t},\n\t};\n\n\treturn [setTool, roundTool, advanceTool, commandWithTeardown];\n}\n"]}