@covro/covro 0.5.1-dev.3 → 0.5.1-dev.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (119) hide show
  1. package/README.md +14 -43
  2. package/README.zh-CN.md +14 -43
  3. package/dist/codex/adapter.js +62 -4
  4. package/dist/codex/adapter.js.map +2 -2
  5. package/dist/codex/collaboration.js +28 -0
  6. package/dist/codex/collaboration.js.map +7 -0
  7. package/dist/codex/guardian-denials.js +67 -0
  8. package/dist/codex/guardian-denials.js.map +7 -0
  9. package/dist/codex/thread-goals.js +15 -0
  10. package/dist/codex/thread-goals.js.map +7 -0
  11. package/dist/codex/thread-titles.js +135 -60
  12. package/dist/codex/thread-titles.js.map +2 -2
  13. package/dist/server/http.js +37 -0
  14. package/dist/server/http.js.map +2 -2
  15. package/dist/server/project-init.js +28 -0
  16. package/dist/server/project-init.js.map +7 -0
  17. package/dist/server/projection.js +1 -0
  18. package/dist/server/projection.js.map +2 -2
  19. package/dist/server/service.js +181 -3
  20. package/dist/server/service.js.map +2 -2
  21. package/dist/server/thread-recap.js +34 -0
  22. package/dist/server/thread-recap.js.map +7 -0
  23. package/dist/server/workspace-diff.js +149 -0
  24. package/dist/server/workspace-diff.js.map +7 -0
  25. package/dist/shared/guardian-denials.js +1 -0
  26. package/dist/shared/guardian-denials.js.map +7 -0
  27. package/dist/shared/thread-goal.js +1 -0
  28. package/dist/shared/thread-goal.js.map +7 -0
  29. package/dist/shared/validation.js +51 -3
  30. package/dist/shared/validation.js.map +2 -2
  31. package/dist/shared/workspace-diff.js +1 -0
  32. package/dist/shared/workspace-diff.js.map +7 -0
  33. package/dist/web/assets/{abnfDiagram-WEYOIA3C-ATf52olP.js → abnfDiagram-WEYOIA3C-BMy2AwDH.js} +1 -1
  34. package/dist/web/assets/{arc-ChLnTnZI.js → arc-DeUcXVmK.js} +1 -1
  35. package/dist/web/assets/{architecture-WOLXFQ4H-B2oEg329.js → architecture-WOLXFQ4H-B5DscTAH.js} +1 -1
  36. package/dist/web/assets/{architectureDiagram-ZHVYKT53-BzSXU9d0.js → architectureDiagram-ZHVYKT53-CwmVMMBS.js} +1 -1
  37. package/dist/web/assets/{blockDiagram-RJAE7QA3-xhCZ7iUm.js → blockDiagram-RJAE7QA3-CebOV20Y.js} +1 -1
  38. package/dist/web/assets/{c4Diagram-XDPPPE54-DZ8j79Mx.js → c4Diagram-XDPPPE54-ssP1dgbB.js} +1 -1
  39. package/dist/web/assets/channel-BONlMBPL.js +1 -0
  40. package/dist/web/assets/{chunk-2E7WHVMD-y5rSOViW.js → chunk-2E7WHVMD-BvN6p7-r.js} +1 -1
  41. package/dist/web/assets/{chunk-4EMNKR2T-B7WVoonr.js → chunk-4EMNKR2T-B5lsOa5d.js} +1 -1
  42. package/dist/web/assets/{chunk-55XCU76K-D-tlN44X.js → chunk-55XCU76K-C7v-VLmv.js} +1 -1
  43. package/dist/web/assets/{chunk-7S6XSTFO-31xOZx-Y.js → chunk-7S6XSTFO-DlQvFeJv.js} +1 -1
  44. package/dist/web/assets/{chunk-AQDTSKZB-CeCjUBmu.js → chunk-AQDTSKZB-DY66z9o6.js} +1 -1
  45. package/dist/web/assets/{chunk-DSNLSHJZ-DgzXTo3_.js → chunk-DSNLSHJZ-CNTCEJar.js} +1 -1
  46. package/dist/web/assets/{chunk-HAGFOTED-Dm22rez0.js → chunk-HAGFOTED-Ds8gP_pC.js} +1 -1
  47. package/dist/web/assets/{chunk-HNE4Q36P-CnFLQjbZ.js → chunk-HNE4Q36P-DmElQsSf.js} +1 -1
  48. package/dist/web/assets/{chunk-NQOKRVIF-7DXXp2d_.js → chunk-NQOKRVIF-PvGRAuAw.js} +1 -1
  49. package/dist/web/assets/{chunk-UHW7PFBP-Bw9-oVzV.js → chunk-UHW7PFBP-CtgMZDoT.js} +1 -1
  50. package/dist/web/assets/{chunk-VQ5W62QI-C9PHAHIJ.js → chunk-VQ5W62QI-6NJrEIzR.js} +1 -1
  51. package/dist/web/assets/{chunk-WQQL4CDK-C9nKxc0i.js → chunk-WQQL4CDK-DI2mRFvc.js} +1 -1
  52. package/dist/web/assets/{chunk-XXDRQBXY-DjdTeNXE.js → chunk-XXDRQBXY-CiBCRo3T.js} +1 -1
  53. package/dist/web/assets/{chunk-YZO67HFG-C1z77_dC.js → chunk-YZO67HFG-DtCoGutI.js} +1 -1
  54. package/dist/web/assets/{chunk-ZAUX2LTX-C7e41NBP.js → chunk-ZAUX2LTX-B7ylZUnx.js} +1 -1
  55. package/dist/web/assets/{chunk-ZCHMQSOR-Gv41Qgvd.js → chunk-ZCHMQSOR-BwN6F2pb.js} +1 -1
  56. package/dist/web/assets/{classDiagram-v2-4MYWR3UA-PjZDyaSs.js → classDiagram-v2-4MYWR3UA-DI-dMW0L.js} +1 -1
  57. package/dist/web/assets/{cose-bilkent-JH36ORCC-CvwZK3HN.js → cose-bilkent-JH36ORCC-BqNb8Qsf.js} +1 -1
  58. package/dist/web/assets/{cynefin-EF2NZ3EQ-Yn6p93cE.js → cynefin-EF2NZ3EQ-B9F8Lxxt.js} +1 -1
  59. package/dist/web/assets/{cynefinDiagram-WF24UDRP-BXa5Guxe.js → cynefinDiagram-WF24UDRP-V8w1XJro.js} +1 -1
  60. package/dist/web/assets/{dagre-NK4GIZVX-Cnskqb30.js → dagre-NK4GIZVX-CrQEcCfE.js} +1 -1
  61. package/dist/web/assets/{diagram-CBK3MWTC-K8WEazkZ.js → diagram-CBK3MWTC-CPcuEQV3.js} +1 -1
  62. package/dist/web/assets/{diagram-I5XIIV2D-CLzouqUh.js → diagram-I5XIIV2D-_QhPHtw6.js} +1 -1
  63. package/dist/web/assets/{diagram-ODIL2UCW-B_9ysyHU.js → diagram-ODIL2UCW-RA65VX6F.js} +1 -1
  64. package/dist/web/assets/{diagram-PFBEJUXE-D1ge5Ebx.js → diagram-PFBEJUXE-9OI5etAn.js} +1 -1
  65. package/dist/web/assets/{diagram-RJA3I4VV-DWF6V26r.js → diagram-RJA3I4VV-B10DlhGR.js} +1 -1
  66. package/dist/web/assets/{diagram-TYUNFSNR-BNM1pCS4.js → diagram-TYUNFSNR-BLwN-9mB.js} +1 -1
  67. package/dist/web/assets/{dist-_uWZFvFF.js → dist-DwHukJTB.js} +1 -1
  68. package/dist/web/assets/{ebnfDiagram-V4P3TTPT-Cge9YHFL.js → ebnfDiagram-V4P3TTPT-J7MBvK86.js} +1 -1
  69. package/dist/web/assets/{elk-QONTBCTQ-CY_393oL.js → elk-QONTBCTQ-DgtewEoX.js} +1 -1
  70. package/dist/web/assets/{erDiagram-KYQIGQAA-CCOr67SS.js → erDiagram-KYQIGQAA-Cn5kVne3.js} +1 -1
  71. package/dist/web/assets/{eventmodeling-K75KTNOO-BzNNWwRQ.js → eventmodeling-K75KTNOO-Cx1OdjIB.js} +1 -1
  72. package/dist/web/assets/flowDiagram-IUGLLWBU-HLbjrYlZ.js +1 -0
  73. package/dist/web/assets/{ganttDiagram-R7GPNTJY-8BewtZrJ.js → ganttDiagram-R7GPNTJY-x2B7XlcJ.js} +1 -1
  74. package/dist/web/assets/{gitGraph-VSP46ZUC-CrqJbic_.js → gitGraph-VSP46ZUC-CP1CGXSo.js} +1 -1
  75. package/dist/web/assets/{gitGraphDiagram-PDYL7XHY-Ddr5Q6Is.js → gitGraphDiagram-PDYL7XHY-B32E1dRa.js} +1 -1
  76. package/dist/web/assets/index-DXEj9ZMB.js +156 -0
  77. package/dist/web/assets/{index-C_i_PNi6.css → index-qYBdGqKM.css} +1 -1
  78. package/dist/web/assets/{info-OHQRW6UA-DgPvuC2J.js → info-OHQRW6UA-BqgII2wT.js} +1 -1
  79. package/dist/web/assets/{infoDiagram-MVDRKAX5-zlubFwKS.js → infoDiagram-MVDRKAX5-BV-WLQ_Y.js} +1 -1
  80. package/dist/web/assets/{ishikawaDiagram-HPEHV2GE-DdQfvqVi.js → ishikawaDiagram-HPEHV2GE-D2d2TDHI.js} +1 -1
  81. package/dist/web/assets/{journeyDiagram-BOSHW7O7-DZ4XswBd.js → journeyDiagram-BOSHW7O7-DdgHsdHz.js} +1 -1
  82. package/dist/web/assets/{kanban-definition-FNSA4HC5-B1BQdpKc.js → kanban-definition-FNSA4HC5-bzF0Iyr6.js} +1 -1
  83. package/dist/web/assets/{line-jQDqs207.js → line-DA04Ug-X.js} +1 -1
  84. package/dist/web/assets/{linear-DbYz4fU8.js → linear-DIrAIB_A.js} +1 -1
  85. package/dist/web/assets/{mermaid-parser.core-CY5CVNe8.js → mermaid-parser.core-DhCddf6t.js} +3 -3
  86. package/dist/web/assets/{mermaid.core-mETL7nBW.js → mermaid.core-sAbEeclG.js} +4 -4
  87. package/dist/web/assets/{mindmap-definition-6OY57UG3-CxgWFLxa.js → mindmap-definition-6OY57UG3-B7pbG4qr.js} +1 -1
  88. package/dist/web/assets/{packet-JDAUHWVQ-Czsr9kk7.js → packet-JDAUHWVQ-BpXWi4v7.js} +1 -1
  89. package/dist/web/assets/{pegDiagram-ECIUJNBX-BqYq-SA-.js → pegDiagram-ECIUJNBX-CnIz50ZX.js} +1 -1
  90. package/dist/web/assets/{pie-XZMESJXO-CRpxJzCy.js → pie-XZMESJXO-Cif1Ynbj.js} +1 -1
  91. package/dist/web/assets/{pieDiagram-GNMPY74T-Bt2wKk8z.js → pieDiagram-GNMPY74T-Ck5nOYI8.js} +1 -1
  92. package/dist/web/assets/{quadrantDiagram-D57K4MC3-VOKqYTgn.js → quadrantDiagram-D57K4MC3-DGWT1xA2.js} +1 -1
  93. package/dist/web/assets/{radar-ABXABTNO-wXmArQH-.js → radar-ABXABTNO-Cs5Evg0F.js} +1 -1
  94. package/dist/web/assets/{railroad-I3PHUGI6-CKPK4tQV.js → railroad-I3PHUGI6-bPE2bl6t.js} +1 -1
  95. package/dist/web/assets/{railroad-abnf-LNEFI6M7-BLEs3xqV.js → railroad-abnf-LNEFI6M7-Bf9uUUsQ.js} +1 -1
  96. package/dist/web/assets/{railroad-ebnf-DWYD2UWJ-DS5QZgky.js → railroad-ebnf-DWYD2UWJ-M2tmC6nN.js} +1 -1
  97. package/dist/web/assets/{railroad-peg-JR7BVNR7-DHWXNOSl.js → railroad-peg-JR7BVNR7-BLrv00Iy.js} +1 -1
  98. package/dist/web/assets/{railroadDiagram-Y72NRBL7-Cy4eWKH1.js → railroadDiagram-Y72NRBL7-BKzTLgo8.js} +1 -1
  99. package/dist/web/assets/{requirementDiagram-EQYSW5RA-Bvbk8wwe.js → requirementDiagram-EQYSW5RA-B99o2Aj1.js} +1 -1
  100. package/dist/web/assets/{sankeyDiagram-SY24JHO5-B4jGjMzu.js → sankeyDiagram-SY24JHO5-Bf5ZtsJ_.js} +1 -1
  101. package/dist/web/assets/{sequenceDiagram-BLEHNHQU-BpgUogv_.js → sequenceDiagram-BLEHNHQU-BGuIX9o_.js} +1 -1
  102. package/dist/web/assets/{src-DigPeGm7.js → src-CohAWB0C.js} +1 -1
  103. package/dist/web/assets/{stateDiagram-v2-A6IESKWZ-tHq7e40Q.js → stateDiagram-v2-A6IESKWZ-26L-tE9O.js} +1 -1
  104. package/dist/web/assets/{swimlanes-B3ENRKFQ-DVUPAaDR.js → swimlanes-B3ENRKFQ-C15cbuwK.js} +1 -1
  105. package/dist/web/assets/swimlanesDiagram-AYQRV4AK-CJVz2uN5.js +8 -0
  106. package/dist/web/assets/{timeline-definition-JXYKGLGB-BHMM9AHV.js → timeline-definition-JXYKGLGB-BeL4WpaZ.js} +1 -1
  107. package/dist/web/assets/{treeView-D4JQ5SDB-DZ7k_TTS.js → treeView-D4JQ5SDB-DizQY9xz.js} +1 -1
  108. package/dist/web/assets/{treemap-SAJKECNS-C1wGfVb4.js → treemap-SAJKECNS-D91-mGk5.js} +1 -1
  109. package/dist/web/assets/{usecaseDiagram-WPOLBNNX-BTg0K_GO.js → usecaseDiagram-WPOLBNNX-Ba0T4eoq.js} +1 -1
  110. package/dist/web/assets/{vennDiagram-Q3Y3IDCW-BTKShPx1.js → vennDiagram-Q3Y3IDCW-B0Q_6_0E.js} +1 -1
  111. package/dist/web/assets/{wardley-7MLQ67FV-DnYPM5OB.js → wardley-7MLQ67FV-BMqvKWF0.js} +1 -1
  112. package/dist/web/assets/{wardleyDiagram-IVAIDKWA-Dzb67Boa.js → wardleyDiagram-IVAIDKWA-shZdkY_1.js} +1 -1
  113. package/dist/web/assets/{xychartDiagram-4URNHDU4-qijltKIO.js → xychartDiagram-4URNHDU4-DAt5ftPl.js} +1 -1
  114. package/dist/web/index.html +2 -2
  115. package/package.json +3 -3
  116. package/dist/web/assets/channel-COC5jFhc.js +0 -1
  117. package/dist/web/assets/flowDiagram-IUGLLWBU-C8dLq0uV.js +0 -1
  118. package/dist/web/assets/index-DHENTsqN.js +0 -148
  119. package/dist/web/assets/swimlanesDiagram-AYQRV4AK-jJ6zDGAv.js +0 -8
@@ -0,0 +1,28 @@
1
+ import { lstat } from "node:fs/promises";
2
+ import { join } from "node:path";
3
+ import { AppError } from "../shared/errors.js";
4
+ const PROJECT_INIT_PROMPT = `Create AGENTS.md in the current working directory as a concise contributor guide for this repository.
5
+ First check whether any AGENTS.md entry already exists. If it does, stop without modifying or replacing it.
6
+ Inspect the repository before writing. Describe its layout, actual build/test/development commands, coding conventions, testing expectations, and commit/pull-request practices. Adapt the content to the project, use concrete examples, and do not invent commands or policies. Aim for 200\u2013400 words with clear Markdown headings. Respect the current permissions and approval policy. Report what was created, or why initialization could not be completed.`;
7
+ async function assertProjectInstructionsMissing(cwd) {
8
+ try {
9
+ await lstat(join(cwd, "AGENTS.md"));
10
+ } catch (error) {
11
+ if (error.code === "ENOENT") return;
12
+ throw new AppError(
13
+ "AGENTS_CHECK_FAILED",
14
+ "Cannot verify whether AGENTS.md already exists",
15
+ 409
16
+ );
17
+ }
18
+ throw new AppError(
19
+ "AGENTS_EXISTS",
20
+ "AGENTS.md already exists; the existing entry was preserved",
21
+ 409
22
+ );
23
+ }
24
+ export {
25
+ PROJECT_INIT_PROMPT,
26
+ assertProjectInstructionsMissing
27
+ };
28
+ //# sourceMappingURL=project-init.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/server/project-init.ts"],
4
+ "sourcesContent": ["import { lstat } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport { AppError } from '../shared/errors.js';\n\n/** A normal agent task, following the native CLI /init contract. */\nexport const PROJECT_INIT_PROMPT = `Create AGENTS.md in the current working directory as a concise contributor guide for this repository.\nFirst check whether any AGENTS.md entry already exists. If it does, stop without modifying or replacing it.\nInspect the repository before writing. Describe its layout, actual build/test/development commands, coding conventions, testing expectations, and commit/pull-request practices. Adapt the content to the project, use concrete examples, and do not invent commands or policies. Aim for 200\u2013400 words with clear Markdown headings. Respect the current permissions and approval policy. Report what was created, or why initialization could not be completed.`;\n\nexport async function assertProjectInstructionsMissing(cwd: string): Promise<void> {\n try {\n await lstat(join(cwd, 'AGENTS.md'));\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === 'ENOENT') return;\n throw new AppError(\n 'AGENTS_CHECK_FAILED',\n 'Cannot verify whether AGENTS.md already exists',\n 409,\n );\n }\n throw new AppError(\n 'AGENTS_EXISTS',\n 'AGENTS.md already exists; the existing entry was preserved',\n 409,\n );\n}\n"],
5
+ "mappings": "AAAA,SAAS,aAAa;AACtB,SAAS,YAAY;AACrB,SAAS,gBAAgB;AAGlB,MAAM,sBAAsB;AAAA;AAAA;AAInC,eAAsB,iCAAiC,KAA4B;AACjF,MAAI;AACF,UAAM,MAAM,KAAK,KAAK,WAAW,CAAC;AAAA,EACpC,SAAS,OAAO;AACd,QAAK,MAAgC,SAAS,SAAU;AACxD,UAAM,IAAI;AAAA,MACR;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AACA,QAAM,IAAI;AAAA,IACR;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;",
6
+ "names": []
7
+ }
@@ -249,6 +249,7 @@ class Projection {
249
249
  this.resolveAction(action.actionId, "expired");
250
250
  }
251
251
  runtimeReset() {
252
+ for (const thread of this.values()) delete thread.goal;
252
253
  for (const action of this.actions.values())
253
254
  if (action.status === "pending" || action.status === "responding")
254
255
  this.resolveAction(action.actionId, "expired");
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/server/projection.ts"],
4
- "sourcesContent": ["import { endCompactions, mergeCompaction, settleCompactions } from './compaction.js';\nimport type {\n AutoReviewView,\n ItemView,\n PendingAction,\n RunStatus,\n ThreadView,\n TurnView,\n TurnErrorMetadata,\n} from '../shared/types.js';\n\nexport const isActive = (status: RunStatus): boolean =>\n status === 'running' || status === 'waitingApproval' || status === 'waitingInput';\nexport const isTerminal = (status: RunStatus): boolean =>\n status === 'completed' || status === 'failed' || status === 'interrupted';\n\nexport class Projection {\n private readonly threads = new Map<string, ThreadView>();\n readonly actions = new Map<string, PendingAction>();\n private readonly revisions = new Map<string, number>();\n // Notifications may precede thread/turn history. Keep only a bounded, per-thread inbox.\n private readonly earlyAutoReviews = new Map<\n string,\n { threadId: string; turnId: string; item: ItemView; bytes: number }\n >();\n private earlyAutoReviewBytes = 0;\n constructor(private readonly maxItemBytes = 2 * 1024 * 1024) {}\n\n get(threadId: string): ThreadView | undefined {\n return this.threads.get(threadId);\n }\n values(): ThreadView[] {\n return [...this.threads.values()];\n }\n revision(threadId: string): number {\n return this.revisions.get(threadId) ?? 0;\n }\n touch(threadId: string): void {\n this.revisions.set(threadId, this.revision(threadId) + 1);\n }\n\n thread(\n incoming: ThreadView,\n preserveCurrent = false,\n preserveRuntimeSettings = preserveCurrent,\n ): ThreadView {\n const current = this.threads.get(incoming.id);\n if (!current) {\n const thread = structuredClone(incoming);\n for (const turn of thread.turns) turn.items = turn.items.map((item) => this.limit(item));\n thread.actions = [...this.actions.values()].filter((action) => action.threadId === thread.id);\n this.threads.set(thread.id, thread);\n for (const turn of thread.turns) {\n this.flushAutoReviews(thread.id, turn.id);\n this.finishReconnect(turn);\n settleCompactions(turn);\n if (isTerminal(turn.status)) this.finishAutoReviews(turn);\n }\n } else {\n const oldTurns = current.turns;\n const oldStatus = current.status;\n const oldRuntimeSettings = current.runtimeSettings;\n const oldTitle = current.title;\n Object.assign(current, incoming, { turns: oldTurns, actions: current.actions });\n if (oldRuntimeSettings && incoming.runtimeSettings)\n current.runtimeSettings = { ...oldRuntimeSettings, ...incoming.runtimeSettings };\n if (preserveCurrent) {\n current.status = oldStatus;\n current.title = oldTitle;\n }\n if (preserveRuntimeSettings) current.runtimeSettings = oldRuntimeSettings;\n for (const turn of incoming.turns) this.turn(incoming.id, turn, preserveCurrent);\n }\n this.touch(incoming.id);\n return this.threads.get(incoming.id)!;\n }\n\n turn(threadId: string, incoming: TurnView, preserveCurrent = false): void {\n const thread = this.threads.get(threadId);\n if (!thread) return;\n thread.hasMessages = true;\n const current = thread.turns.find((turn) => turn.id === incoming.id);\n if (!current)\n thread.turns.push({\n ...structuredClone(incoming),\n items: incoming.items.map((item) => this.limit(item)),\n });\n else {\n const items = current.items;\n if (!preserveCurrent) Object.assign(current, incoming, { items });\n for (const item of incoming.items) this.item(threadId, incoming.id, item, preserveCurrent);\n }\n // Tool cancellation can finish after a new turn starts. Only the latest\n // turn owns the thread status; older events still update their own history.\n if (!preserveCurrent && thread.turns.at(-1)?.id === incoming.id)\n thread.status = incoming.status;\n this.flushAutoReviews(threadId, incoming.id);\n const updated = thread.turns.find((turn) => turn.id === incoming.id)!;\n this.finishReconnect(updated);\n settleCompactions(updated);\n if (isTerminal(updated.status)) this.finishAutoReviews(updated);\n this.touch(threadId);\n }\n\n turnError(\n threadId: string,\n turnId: string,\n message: string,\n willRetry: boolean,\n metadata: TurnErrorMetadata = {},\n ): boolean {\n const turn = this.threads.get(threadId)?.turns.find((entry) => entry.id === turnId);\n if (!turn || !isActive(turn.status)) return false;\n // Keep display-only diagnostics bounded, without changing the execution reservation.\n const detail = message.slice(0, 4096);\n const info = {\n ...(metadata.errorCode ? { errorCode: metadata.errorCode.slice(0, 100) } : {}),\n ...(metadata.errorDetails ? { errorDetails: metadata.errorDetails.slice(0, 4096) } : {}),\n };\n if (willRetry) turn.reconnect = { status: 'retrying', message: detail, ...info };\n else {\n turn.error = detail;\n Object.assign(turn, info);\n endCompactions(turn, 'failed', detail);\n if (turn.reconnect)\n turn.reconnect = { ...turn.reconnect, ...info, status: 'failed', message: detail };\n }\n this.touch(threadId);\n return true;\n }\n\n compactionCompleted(threadId: string, turnId: string): boolean {\n const turn = this.threads.get(threadId)?.turns.find((entry) => entry.id === turnId);\n if (!turn || !endCompactions(turn, 'completed')) return false;\n this.touch(threadId);\n return true;\n }\n\n endThreadCompactions(threadId: string): void {\n for (const turn of this.threads.get(threadId)?.turns ?? []) endCompactions(turn, 'unknown');\n this.touch(threadId);\n }\n\n turnProgress(threadId: string, turnId: string): boolean {\n const turn = this.threads.get(threadId)?.turns.find((entry) => entry.id === turnId);\n if (!turn || !isActive(turn.status) || turn.reconnect?.status !== 'retrying') return false;\n delete turn.reconnect;\n this.touch(threadId);\n return true;\n }\n\n private finishReconnect(turn: TurnView): void {\n if (!turn.reconnect || !isTerminal(turn.status)) return;\n if (turn.status === 'failed') {\n turn.reconnect = {\n ...turn.reconnect,\n status: 'failed',\n message: (turn.error ?? turn.reconnect.message).slice(0, 4096),\n };\n } else delete turn.reconnect;\n }\n\n autoReview(threadId: string, turnId: string, review: AutoReviewView): boolean {\n const item = this.limit({\n id: `auto-review:${review.reviewId}`,\n type: 'autoApprovalReview',\n status: review.status,\n autoReview: review,\n });\n const turn = this.threads.get(threadId)?.turns.find((entry) => entry.id === turnId);\n if (turn) return this.applyAutoReview(threadId, turn, item);\n const key = JSON.stringify([threadId, turnId, review.reviewId]);\n const current = this.earlyAutoReviews.get(key);\n if (current && !this.reviewCanReplace(current.item, item)) return false;\n const bytes = Buffer.byteLength(JSON.stringify({ threadId, turnId, item }));\n if (current) this.earlyAutoReviewBytes -= current.bytes;\n this.earlyAutoReviews.set(key, { threadId, turnId, item, bytes });\n this.earlyAutoReviewBytes += bytes;\n while (this.earlyAutoReviews.size > 128 || this.earlyAutoReviewBytes > 4 * 1024 * 1024) {\n const oldest = this.earlyAutoReviews.keys().next().value!;\n this.earlyAutoReviewBytes -= this.earlyAutoReviews.get(oldest)!.bytes;\n this.earlyAutoReviews.delete(oldest);\n }\n return false;\n }\n\n private reviewCanReplace(current: ItemView, incoming: ItemView): boolean {\n const previous = current.autoReview!;\n const next = incoming.autoReview!;\n if (previous.status !== 'inProgress' && next.status === 'inProgress') return false;\n if (\n previous.completedAtMs !== undefined &&\n (next.completedAtMs === undefined || previous.completedAtMs > next.completedAtMs)\n )\n return false;\n return JSON.stringify(current) !== JSON.stringify(incoming);\n }\n\n private applyAutoReview(threadId: string, turn: TurnView, item: ItemView): boolean {\n const index = turn.items.findIndex(\n (entry) =>\n entry.type === 'autoApprovalReview' &&\n entry.autoReview?.reviewId === item.autoReview!.reviewId,\n );\n // Check the original event before converting an unfinished late review to unknown.\n if (index >= 0 && !this.reviewCanReplace(turn.items[index]!, item)) return false;\n if (isTerminal(turn.status) && item.autoReview!.status === 'inProgress') {\n item.autoReview!.status = 'unknown';\n item.status = 'unknown';\n }\n if (index < 0) turn.items.push(item);\n else {\n turn.items[index] = item;\n }\n this.touch(threadId);\n return true;\n }\n\n private flushAutoReviews(threadId: string, turnId: string): void {\n const turn = this.threads.get(threadId)?.turns.find((entry) => entry.id === turnId);\n if (!turn) return;\n for (const [key, entry] of this.earlyAutoReviews) {\n if (entry.threadId !== threadId || entry.turnId !== turnId) continue;\n this.earlyAutoReviews.delete(key);\n this.earlyAutoReviewBytes -= entry.bytes;\n this.applyAutoReview(threadId, turn, entry.item);\n }\n }\n\n private finishAutoReviews(turn: TurnView): void {\n for (const item of turn.items) {\n if (item.autoReview?.status !== 'inProgress') continue;\n item.autoReview.status = 'unknown';\n item.status = 'unknown';\n }\n }\n\n item(threadId: string, turnId: string, item: ItemView, preserveCurrent = false): void {\n const turn = this.threads.get(threadId)?.turns.find((entry) => entry.id === turnId);\n if (!turn) return;\n const index = turn.items.findIndex((entry) => entry.id === item.id);\n if (index < 0) turn.items.push(this.limit(item));\n else if (!preserveCurrent)\n turn.items[index] = this.limit(mergeCompaction(item, turn.items[index]));\n settleCompactions(turn);\n this.touch(threadId);\n }\n\n delta(\n threadId: string,\n turnId: string,\n itemId: string,\n field: 'text' | 'output',\n delta: string,\n itemType?: string,\n ): void {\n const turn = this.threads.get(threadId)?.turns.find((entry) => entry.id === turnId);\n if (!turn) return;\n let item = turn.items.find((entry) => entry.id === itemId);\n if (!item) {\n item = {\n id: itemId,\n type: itemType ?? (field === 'text' ? 'agentMessage' : 'commandExecution'),\n };\n turn.items.push(item);\n }\n if (item.truncated) return;\n item[field] = (item[field] ?? '') + delta;\n Object.assign(item, this.limit(item));\n this.touch(threadId);\n }\n\n diff(threadId: string, turnId: string, diff: string): void {\n const turn = this.threads.get(threadId)?.turns.find((entry) => entry.id === turnId);\n if (turn) turn.diff = this.clip(diff).value;\n this.touch(threadId);\n }\n\n action(action: PendingAction): void {\n const owner = action.threadId\n ? this.threads.get(action.threadId)?.turns.find((turn) => turn.id === action.turnId)\n : undefined;\n if (owner && isTerminal(owner.status) && ['pending', 'responding'].includes(action.status))\n action = { ...action, status: 'expired' };\n this.actions.set(action.actionId, action);\n const thread = action.threadId ? this.threads.get(action.threadId) : undefined;\n if (thread) {\n thread.actions = [...this.actions.values()].filter((entry) => entry.threadId === thread.id);\n this.updateActionStatus(thread);\n this.touch(thread.id);\n }\n }\n\n resolveAction(actionId: string, status: PendingAction['status']): PendingAction | undefined {\n const action = this.actions.get(actionId);\n if (!action) return undefined;\n action.status = status;\n const thread = action.threadId ? this.threads.get(action.threadId) : undefined;\n if (thread) {\n this.updateActionStatus(thread);\n this.touch(thread.id);\n }\n return action;\n }\n\n expireTurn(threadId: string, turnId: string): void {\n for (const action of this.actions.values())\n if (\n action.threadId === threadId &&\n action.turnId === turnId &&\n (action.status === 'pending' || action.status === 'responding')\n )\n this.resolveAction(action.actionId, 'expired');\n }\n\n runtimeReset(): void {\n for (const action of this.actions.values())\n if (action.status === 'pending' || action.status === 'responding')\n this.resolveAction(action.actionId, 'expired');\n for (const thread of this.threads.values()) {\n thread.managed = false;\n delete thread.resumeError;\n if (thread.runtimeSettings) {\n const { model, reasoningEffort } = thread.runtimeSettings;\n thread.runtimeSettings = { model, reasoningEffort };\n }\n if (isActive(thread.status)) thread.status = 'unknown';\n for (const turn of thread.turns) {\n if (turn.reconnect?.status === 'retrying') delete turn.reconnect;\n if (isActive(turn.status)) turn.status = 'unknown';\n endCompactions(turn, 'unknown');\n this.finishAutoReviews(turn);\n }\n this.touch(thread.id);\n }\n for (const entry of this.earlyAutoReviews.values()) {\n if (entry.item.autoReview?.status === 'inProgress') {\n this.earlyAutoReviewBytes -= entry.bytes;\n entry.item.autoReview.status = 'unknown';\n entry.item.status = 'unknown';\n entry.bytes = Buffer.byteLength(\n JSON.stringify({ threadId: entry.threadId, turnId: entry.turnId, item: entry.item }),\n );\n this.earlyAutoReviewBytes += entry.bytes;\n }\n }\n }\n\n private updateActionStatus(thread: ThreadView): void {\n const active = thread.actions.filter(\n (action) =>\n action.blocking !== false &&\n (action.status === 'pending' || action.status === 'responding'),\n );\n const turn = [...thread.turns].reverse().find((entry) => isActive(entry.status));\n if (!turn) return;\n const status = active.some(\n (action) => action.kind === 'questions' || action.kind === 'elicitation',\n )\n ? 'waitingInput'\n : active.length > 0\n ? 'waitingApproval'\n : 'running';\n thread.status = status;\n turn.status = status;\n }\n\n private limit(item: ItemView): ItemView {\n const result = structuredClone(item);\n if (result.images) {\n let bytes = 0;\n result.imageCount ??= result.images.length;\n result.images = result.images.filter((image) => {\n bytes += Buffer.byteLength(image);\n return bytes <= this.maxItemBytes;\n });\n }\n for (const field of ['text', 'output', 'command'] as const) {\n const value = result[field];\n if (value) {\n const clipped = this.clip(value);\n result[field] = clipped.value;\n if (clipped.truncated) result.truncated = true;\n }\n }\n if (result.changes)\n result.changes = result.changes.map((change) => {\n const clipped = this.clip(change.diff);\n if (clipped.truncated) result.truncated = true;\n return { ...change, diff: clipped.value };\n });\n if (result.details !== undefined) {\n const clipped = this.clip(JSON.stringify(result.details));\n if (clipped.truncated) {\n result.details = clipped.value;\n result.truncated = true;\n }\n }\n if (result.autoReview) {\n for (const field of ['actionLabel', 'actionSummary', 'cwd', 'rationale'] as const) {\n const value = result.autoReview[field];\n if (value === undefined) continue;\n const clipped = this.clip(value);\n result.autoReview[field] = clipped.value;\n if (clipped.truncated) result.truncated = true;\n }\n }\n return result;\n }\n\n private clip(value: string): { value: string; truncated: boolean } {\n if (Buffer.byteLength(value) <= this.maxItemBytes) return { value, truncated: false };\n // Iterating code points avoids a half UTF-8 character at the truncation boundary.\n let kept = '';\n let bytes = 0;\n for (const point of value) {\n bytes += Buffer.byteLength(point);\n if (bytes > this.maxItemBytes) break;\n kept += point;\n }\n return { value: `${kept}\\n[\u8F93\u51FA\u5DF2\u622A\u65AD]`, truncated: true };\n }\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import { endCompactions, mergeCompaction, settleCompactions } from './compaction.js';\nimport type {\n AutoReviewView,\n ItemView,\n PendingAction,\n RunStatus,\n ThreadView,\n TurnView,\n TurnErrorMetadata,\n} from '../shared/types.js';\n\nexport const isActive = (status: RunStatus): boolean =>\n status === 'running' || status === 'waitingApproval' || status === 'waitingInput';\nexport const isTerminal = (status: RunStatus): boolean =>\n status === 'completed' || status === 'failed' || status === 'interrupted';\n\nexport class Projection {\n private readonly threads = new Map<string, ThreadView>();\n readonly actions = new Map<string, PendingAction>();\n private readonly revisions = new Map<string, number>();\n // Notifications may precede thread/turn history. Keep only a bounded, per-thread inbox.\n private readonly earlyAutoReviews = new Map<\n string,\n { threadId: string; turnId: string; item: ItemView; bytes: number }\n >();\n private earlyAutoReviewBytes = 0;\n constructor(private readonly maxItemBytes = 2 * 1024 * 1024) {}\n\n get(threadId: string): ThreadView | undefined {\n return this.threads.get(threadId);\n }\n values(): ThreadView[] {\n return [...this.threads.values()];\n }\n revision(threadId: string): number {\n return this.revisions.get(threadId) ?? 0;\n }\n touch(threadId: string): void {\n this.revisions.set(threadId, this.revision(threadId) + 1);\n }\n\n thread(\n incoming: ThreadView,\n preserveCurrent = false,\n preserveRuntimeSettings = preserveCurrent,\n ): ThreadView {\n const current = this.threads.get(incoming.id);\n if (!current) {\n const thread = structuredClone(incoming);\n for (const turn of thread.turns) turn.items = turn.items.map((item) => this.limit(item));\n thread.actions = [...this.actions.values()].filter((action) => action.threadId === thread.id);\n this.threads.set(thread.id, thread);\n for (const turn of thread.turns) {\n this.flushAutoReviews(thread.id, turn.id);\n this.finishReconnect(turn);\n settleCompactions(turn);\n if (isTerminal(turn.status)) this.finishAutoReviews(turn);\n }\n } else {\n const oldTurns = current.turns;\n const oldStatus = current.status;\n const oldRuntimeSettings = current.runtimeSettings;\n const oldTitle = current.title;\n Object.assign(current, incoming, { turns: oldTurns, actions: current.actions });\n if (oldRuntimeSettings && incoming.runtimeSettings)\n current.runtimeSettings = { ...oldRuntimeSettings, ...incoming.runtimeSettings };\n if (preserveCurrent) {\n current.status = oldStatus;\n current.title = oldTitle;\n }\n if (preserveRuntimeSettings) current.runtimeSettings = oldRuntimeSettings;\n for (const turn of incoming.turns) this.turn(incoming.id, turn, preserveCurrent);\n }\n this.touch(incoming.id);\n return this.threads.get(incoming.id)!;\n }\n\n turn(threadId: string, incoming: TurnView, preserveCurrent = false): void {\n const thread = this.threads.get(threadId);\n if (!thread) return;\n thread.hasMessages = true;\n const current = thread.turns.find((turn) => turn.id === incoming.id);\n if (!current)\n thread.turns.push({\n ...structuredClone(incoming),\n items: incoming.items.map((item) => this.limit(item)),\n });\n else {\n const items = current.items;\n if (!preserveCurrent) Object.assign(current, incoming, { items });\n for (const item of incoming.items) this.item(threadId, incoming.id, item, preserveCurrent);\n }\n // Tool cancellation can finish after a new turn starts. Only the latest\n // turn owns the thread status; older events still update their own history.\n if (!preserveCurrent && thread.turns.at(-1)?.id === incoming.id)\n thread.status = incoming.status;\n this.flushAutoReviews(threadId, incoming.id);\n const updated = thread.turns.find((turn) => turn.id === incoming.id)!;\n this.finishReconnect(updated);\n settleCompactions(updated);\n if (isTerminal(updated.status)) this.finishAutoReviews(updated);\n this.touch(threadId);\n }\n\n turnError(\n threadId: string,\n turnId: string,\n message: string,\n willRetry: boolean,\n metadata: TurnErrorMetadata = {},\n ): boolean {\n const turn = this.threads.get(threadId)?.turns.find((entry) => entry.id === turnId);\n if (!turn || !isActive(turn.status)) return false;\n // Keep display-only diagnostics bounded, without changing the execution reservation.\n const detail = message.slice(0, 4096);\n const info = {\n ...(metadata.errorCode ? { errorCode: metadata.errorCode.slice(0, 100) } : {}),\n ...(metadata.errorDetails ? { errorDetails: metadata.errorDetails.slice(0, 4096) } : {}),\n };\n if (willRetry) turn.reconnect = { status: 'retrying', message: detail, ...info };\n else {\n turn.error = detail;\n Object.assign(turn, info);\n endCompactions(turn, 'failed', detail);\n if (turn.reconnect)\n turn.reconnect = { ...turn.reconnect, ...info, status: 'failed', message: detail };\n }\n this.touch(threadId);\n return true;\n }\n\n compactionCompleted(threadId: string, turnId: string): boolean {\n const turn = this.threads.get(threadId)?.turns.find((entry) => entry.id === turnId);\n if (!turn || !endCompactions(turn, 'completed')) return false;\n this.touch(threadId);\n return true;\n }\n\n endThreadCompactions(threadId: string): void {\n for (const turn of this.threads.get(threadId)?.turns ?? []) endCompactions(turn, 'unknown');\n this.touch(threadId);\n }\n\n turnProgress(threadId: string, turnId: string): boolean {\n const turn = this.threads.get(threadId)?.turns.find((entry) => entry.id === turnId);\n if (!turn || !isActive(turn.status) || turn.reconnect?.status !== 'retrying') return false;\n delete turn.reconnect;\n this.touch(threadId);\n return true;\n }\n\n private finishReconnect(turn: TurnView): void {\n if (!turn.reconnect || !isTerminal(turn.status)) return;\n if (turn.status === 'failed') {\n turn.reconnect = {\n ...turn.reconnect,\n status: 'failed',\n message: (turn.error ?? turn.reconnect.message).slice(0, 4096),\n };\n } else delete turn.reconnect;\n }\n\n autoReview(threadId: string, turnId: string, review: AutoReviewView): boolean {\n const item = this.limit({\n id: `auto-review:${review.reviewId}`,\n type: 'autoApprovalReview',\n status: review.status,\n autoReview: review,\n });\n const turn = this.threads.get(threadId)?.turns.find((entry) => entry.id === turnId);\n if (turn) return this.applyAutoReview(threadId, turn, item);\n const key = JSON.stringify([threadId, turnId, review.reviewId]);\n const current = this.earlyAutoReviews.get(key);\n if (current && !this.reviewCanReplace(current.item, item)) return false;\n const bytes = Buffer.byteLength(JSON.stringify({ threadId, turnId, item }));\n if (current) this.earlyAutoReviewBytes -= current.bytes;\n this.earlyAutoReviews.set(key, { threadId, turnId, item, bytes });\n this.earlyAutoReviewBytes += bytes;\n while (this.earlyAutoReviews.size > 128 || this.earlyAutoReviewBytes > 4 * 1024 * 1024) {\n const oldest = this.earlyAutoReviews.keys().next().value!;\n this.earlyAutoReviewBytes -= this.earlyAutoReviews.get(oldest)!.bytes;\n this.earlyAutoReviews.delete(oldest);\n }\n return false;\n }\n\n private reviewCanReplace(current: ItemView, incoming: ItemView): boolean {\n const previous = current.autoReview!;\n const next = incoming.autoReview!;\n if (previous.status !== 'inProgress' && next.status === 'inProgress') return false;\n if (\n previous.completedAtMs !== undefined &&\n (next.completedAtMs === undefined || previous.completedAtMs > next.completedAtMs)\n )\n return false;\n return JSON.stringify(current) !== JSON.stringify(incoming);\n }\n\n private applyAutoReview(threadId: string, turn: TurnView, item: ItemView): boolean {\n const index = turn.items.findIndex(\n (entry) =>\n entry.type === 'autoApprovalReview' &&\n entry.autoReview?.reviewId === item.autoReview!.reviewId,\n );\n // Check the original event before converting an unfinished late review to unknown.\n if (index >= 0 && !this.reviewCanReplace(turn.items[index]!, item)) return false;\n if (isTerminal(turn.status) && item.autoReview!.status === 'inProgress') {\n item.autoReview!.status = 'unknown';\n item.status = 'unknown';\n }\n if (index < 0) turn.items.push(item);\n else {\n turn.items[index] = item;\n }\n this.touch(threadId);\n return true;\n }\n\n private flushAutoReviews(threadId: string, turnId: string): void {\n const turn = this.threads.get(threadId)?.turns.find((entry) => entry.id === turnId);\n if (!turn) return;\n for (const [key, entry] of this.earlyAutoReviews) {\n if (entry.threadId !== threadId || entry.turnId !== turnId) continue;\n this.earlyAutoReviews.delete(key);\n this.earlyAutoReviewBytes -= entry.bytes;\n this.applyAutoReview(threadId, turn, entry.item);\n }\n }\n\n private finishAutoReviews(turn: TurnView): void {\n for (const item of turn.items) {\n if (item.autoReview?.status !== 'inProgress') continue;\n item.autoReview.status = 'unknown';\n item.status = 'unknown';\n }\n }\n\n item(threadId: string, turnId: string, item: ItemView, preserveCurrent = false): void {\n const turn = this.threads.get(threadId)?.turns.find((entry) => entry.id === turnId);\n if (!turn) return;\n const index = turn.items.findIndex((entry) => entry.id === item.id);\n if (index < 0) turn.items.push(this.limit(item));\n else if (!preserveCurrent)\n turn.items[index] = this.limit(mergeCompaction(item, turn.items[index]));\n settleCompactions(turn);\n this.touch(threadId);\n }\n\n delta(\n threadId: string,\n turnId: string,\n itemId: string,\n field: 'text' | 'output',\n delta: string,\n itemType?: string,\n ): void {\n const turn = this.threads.get(threadId)?.turns.find((entry) => entry.id === turnId);\n if (!turn) return;\n let item = turn.items.find((entry) => entry.id === itemId);\n if (!item) {\n item = {\n id: itemId,\n type: itemType ?? (field === 'text' ? 'agentMessage' : 'commandExecution'),\n };\n turn.items.push(item);\n }\n if (item.truncated) return;\n item[field] = (item[field] ?? '') + delta;\n Object.assign(item, this.limit(item));\n this.touch(threadId);\n }\n\n diff(threadId: string, turnId: string, diff: string): void {\n const turn = this.threads.get(threadId)?.turns.find((entry) => entry.id === turnId);\n if (turn) turn.diff = this.clip(diff).value;\n this.touch(threadId);\n }\n\n action(action: PendingAction): void {\n const owner = action.threadId\n ? this.threads.get(action.threadId)?.turns.find((turn) => turn.id === action.turnId)\n : undefined;\n if (owner && isTerminal(owner.status) && ['pending', 'responding'].includes(action.status))\n action = { ...action, status: 'expired' };\n this.actions.set(action.actionId, action);\n const thread = action.threadId ? this.threads.get(action.threadId) : undefined;\n if (thread) {\n thread.actions = [...this.actions.values()].filter((entry) => entry.threadId === thread.id);\n this.updateActionStatus(thread);\n this.touch(thread.id);\n }\n }\n\n resolveAction(actionId: string, status: PendingAction['status']): PendingAction | undefined {\n const action = this.actions.get(actionId);\n if (!action) return undefined;\n action.status = status;\n const thread = action.threadId ? this.threads.get(action.threadId) : undefined;\n if (thread) {\n this.updateActionStatus(thread);\n this.touch(thread.id);\n }\n return action;\n }\n\n expireTurn(threadId: string, turnId: string): void {\n for (const action of this.actions.values())\n if (\n action.threadId === threadId &&\n action.turnId === turnId &&\n (action.status === 'pending' || action.status === 'responding')\n )\n this.resolveAction(action.actionId, 'expired');\n }\n\n runtimeReset(): void {\n for (const thread of this.values()) delete thread.goal;\n for (const action of this.actions.values())\n if (action.status === 'pending' || action.status === 'responding')\n this.resolveAction(action.actionId, 'expired');\n for (const thread of this.threads.values()) {\n thread.managed = false;\n delete thread.resumeError;\n if (thread.runtimeSettings) {\n const { model, reasoningEffort } = thread.runtimeSettings;\n thread.runtimeSettings = { model, reasoningEffort };\n }\n if (isActive(thread.status)) thread.status = 'unknown';\n for (const turn of thread.turns) {\n if (turn.reconnect?.status === 'retrying') delete turn.reconnect;\n if (isActive(turn.status)) turn.status = 'unknown';\n endCompactions(turn, 'unknown');\n this.finishAutoReviews(turn);\n }\n this.touch(thread.id);\n }\n for (const entry of this.earlyAutoReviews.values()) {\n if (entry.item.autoReview?.status === 'inProgress') {\n this.earlyAutoReviewBytes -= entry.bytes;\n entry.item.autoReview.status = 'unknown';\n entry.item.status = 'unknown';\n entry.bytes = Buffer.byteLength(\n JSON.stringify({ threadId: entry.threadId, turnId: entry.turnId, item: entry.item }),\n );\n this.earlyAutoReviewBytes += entry.bytes;\n }\n }\n }\n\n private updateActionStatus(thread: ThreadView): void {\n const active = thread.actions.filter(\n (action) =>\n action.blocking !== false &&\n (action.status === 'pending' || action.status === 'responding'),\n );\n const turn = [...thread.turns].reverse().find((entry) => isActive(entry.status));\n if (!turn) return;\n const status = active.some(\n (action) => action.kind === 'questions' || action.kind === 'elicitation',\n )\n ? 'waitingInput'\n : active.length > 0\n ? 'waitingApproval'\n : 'running';\n thread.status = status;\n turn.status = status;\n }\n\n private limit(item: ItemView): ItemView {\n const result = structuredClone(item);\n if (result.images) {\n let bytes = 0;\n result.imageCount ??= result.images.length;\n result.images = result.images.filter((image) => {\n bytes += Buffer.byteLength(image);\n return bytes <= this.maxItemBytes;\n });\n }\n for (const field of ['text', 'output', 'command'] as const) {\n const value = result[field];\n if (value) {\n const clipped = this.clip(value);\n result[field] = clipped.value;\n if (clipped.truncated) result.truncated = true;\n }\n }\n if (result.changes)\n result.changes = result.changes.map((change) => {\n const clipped = this.clip(change.diff);\n if (clipped.truncated) result.truncated = true;\n return { ...change, diff: clipped.value };\n });\n if (result.details !== undefined) {\n const clipped = this.clip(JSON.stringify(result.details));\n if (clipped.truncated) {\n result.details = clipped.value;\n result.truncated = true;\n }\n }\n if (result.autoReview) {\n for (const field of ['actionLabel', 'actionSummary', 'cwd', 'rationale'] as const) {\n const value = result.autoReview[field];\n if (value === undefined) continue;\n const clipped = this.clip(value);\n result.autoReview[field] = clipped.value;\n if (clipped.truncated) result.truncated = true;\n }\n }\n return result;\n }\n\n private clip(value: string): { value: string; truncated: boolean } {\n if (Buffer.byteLength(value) <= this.maxItemBytes) return { value, truncated: false };\n // Iterating code points avoids a half UTF-8 character at the truncation boundary.\n let kept = '';\n let bytes = 0;\n for (const point of value) {\n bytes += Buffer.byteLength(point);\n if (bytes > this.maxItemBytes) break;\n kept += point;\n }\n return { value: `${kept}\\n[\u8F93\u51FA\u5DF2\u622A\u65AD]`, truncated: true };\n }\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -1,8 +1,12 @@
1
1
  import { CapacityRetries } from "./capacity-retry.js";
2
2
  import { isModelCapacityError } from "../shared/turn-errors.js";
3
+ import { randomUUID } from "node:crypto";
3
4
  import { attentionKey, pendingAttention } from "../shared/thread-attention.js";
4
5
  import { ShellService } from "./shell.js";
6
+ import { assertProjectInstructionsMissing, PROJECT_INIT_PROMPT } from "./project-init.js";
7
+ import { recapInput } from "./thread-recap.js";
5
8
  import { readGithubRepository } from "./github-repository.js";
9
+ import { readWorkspaceDiff } from "./workspace-diff.js";
6
10
  import { realpathSync } from "node:fs";
7
11
  import { cp } from "node:fs/promises";
8
12
  import { WorkspaceRegistry } from "./workspaces.js";
@@ -15,6 +19,7 @@ import {
15
19
  } from "../shared/elicitation.js";
16
20
  import { toThreadSummary } from "../shared/thread-summary.js";
17
21
  import {
22
+ requestDigest,
18
23
  StoreConflict
19
24
  } from "./db/operations.js";
20
25
  import { EventHub } from "./events.js";
@@ -81,6 +86,7 @@ class GatewayService {
81
86
  archiveRevisions = /* @__PURE__ */ new Map();
82
87
  turnBaselines = /* @__PURE__ */ new Map();
83
88
  renameChanges = /* @__PURE__ */ new Set();
89
+ goalWrites = /* @__PURE__ */ new Set();
84
90
  reads = /* @__PURE__ */ new Map();
85
91
  resumes = /* @__PURE__ */ new Map();
86
92
  executionReads = /* @__PURE__ */ new Map();
@@ -103,6 +109,29 @@ class GatewayService {
103
109
  this.projects.get(projectId);
104
110
  return { url };
105
111
  }
112
+ async getProjectDiff(projectId) {
113
+ const project = this.projects.get(projectId);
114
+ const result = await readWorkspaceDiff(
115
+ project.canonicalRoot,
116
+ this.workspaces.allocations().map((row) => row.canonicalRoot)
117
+ );
118
+ this.projects.get(projectId);
119
+ return result;
120
+ }
121
+ async getThreadDiff(threadId) {
122
+ let link = this.store.getThreadLink(threadId);
123
+ if (!link) {
124
+ this.normalize(await this.codex.readThreadMetadata(threadId));
125
+ link = this.store.getThreadLink(threadId);
126
+ }
127
+ const { cwd } = this.workspaces.assertOwnership(link.projectId, link.cwd, threadId);
128
+ const result = await readWorkspaceDiff(
129
+ cwd,
130
+ this.workspaces.allocations().filter((row) => row.threadId !== threadId).map((row) => row.canonicalRoot)
131
+ );
132
+ this.workspaces.assertOwnership(link.projectId, link.cwd, threadId);
133
+ return result;
134
+ }
106
135
  async getThreadGithubRepository(threadId) {
107
136
  let link = this.store.getThreadLink(threadId);
108
137
  if (!link) {
@@ -470,15 +499,27 @@ class GatewayService {
470
499
  this.projection.touch(threadId);
471
500
  if (!this.archiveChanges.has(threadId)) this.publishThread(threadId);
472
501
  }
502
+ async refreshGoal(thread) {
503
+ if (thread.goal !== void 0 || !this.codex.ready || !this.codex.getGoal) return;
504
+ try {
505
+ const goal = await this.codex.getGoal(thread.id);
506
+ this.workspaces.assertOwnership(thread.projectId, thread.cwd, thread.id);
507
+ if (thread.goal === void 0) thread.goal = goal;
508
+ } catch {
509
+ }
510
+ }
473
511
  async getThreadMetadata(threadId) {
474
512
  const cached = this.projection.get(threadId);
475
513
  if (cached) {
476
514
  this.workspaces.assertOwnership(cached.projectId, cached.cwd, cached.id);
477
515
  if (this.codex.ready) await this.refreshThreadMetadata(threadId);
478
516
  this.workspaces.assertOwnership(cached.projectId, cached.cwd, cached.id);
517
+ await this.refreshGoal(cached);
479
518
  return { ...this.threadView(cached), turns: [], actions: [] };
480
519
  }
481
520
  const metadata = this.threadView(this.normalize(await this.codex.readThreadMetadata(threadId)));
521
+ await this.refreshGoal(metadata);
522
+ metadata.historyVisible = this.historyVisible(metadata);
482
523
  return { ...metadata, turns: [], actions: [] };
483
524
  }
484
525
  async getThread(threadId) {
@@ -487,6 +528,7 @@ class GatewayService {
487
528
  if (cached && this.codex.ready) await this.refreshThreadMetadata(threadId);
488
529
  const thread = this.projection.get(threadId);
489
530
  this.workspaces.assertOwnership(thread.projectId, thread.cwd, thread.id);
531
+ await this.refreshGoal(thread);
490
532
  return this.threadView(thread);
491
533
  }
492
534
  getThreadAttention(threadId) {
@@ -755,6 +797,7 @@ class GatewayService {
755
797
  if (isActive(this.projection.get(threadId)?.status ?? thread.status))
756
798
  throw new AppError("THREAD_BUSY", "\u4F1A\u8BDD\u5DF2\u6709\u6D3B\u52A8\u4EFB\u52A1\uFF0C\u8BF7\u8FFD\u52A0\u8981\u6C42\u6216\u4E2D\u65AD", 409, { threadId });
757
799
  this.ensureCompatibilityConfirmed();
800
+ if (input.taskKind === "init") await assertProjectInstructionsMissing(ownership.cwd);
758
801
  this.store.dispatch(input.clientOperationId, {
759
802
  threadId,
760
803
  workspaceKey: ownership.workspaceKey,
@@ -775,7 +818,7 @@ class GatewayService {
775
818
  const turn = await this.codex.startTurn(
776
819
  threadId,
777
820
  ownership.cwd,
778
- input.text,
821
+ input.taskKind === "init" ? PROJECT_INIT_PROMPT : input.text,
779
822
  input.settings,
780
823
  input.images
781
824
  );
@@ -843,6 +886,109 @@ class GatewayService {
843
886
  async retryTurn(threadId, input) {
844
887
  return this.dispatchTurn(threadId, { ...input, text: "" }, void 0, input.expectedTurnId);
845
888
  }
889
+ async getGoal(threadId) {
890
+ const thread = await this.loadThread(threadId);
891
+ this.workspaces.assertOwnership(thread.projectId, thread.cwd, thread.id);
892
+ this.ensureReady();
893
+ if (!this.codex.getGoal) throw new AppError("GOAL_UNAVAILABLE", "\u5F53\u524D Codex \u4E0D\u652F\u6301\u76EE\u6807", 409);
894
+ const goal = await this.codex.getGoal(threadId);
895
+ this.workspaces.assertOwnership(thread.projectId, thread.cwd, thread.id);
896
+ const current = this.projection.get(threadId);
897
+ if (current) {
898
+ current.goal = goal;
899
+ this.projection.touch(threadId);
900
+ this.publishThread(threadId);
901
+ }
902
+ return { goal, version: requestDigest(goal) };
903
+ }
904
+ async mutateGoal(threadId, input) {
905
+ return this.perform("goal.update", threadId, input, async () => {
906
+ if (this.goalWrites.has(threadId))
907
+ throw new AppError("GOAL_BUSY", "\u76EE\u6807\u66F4\u65B0\u6B63\u5728\u8FDB\u884C\uFF0C\u8BF7\u7B49\u5F85\u56DE\u6267", 409);
908
+ this.goalWrites.add(threadId);
909
+ try {
910
+ const thread = await this.loadThread(threadId);
911
+ this.ensureManaged(thread);
912
+ this.workspaces.assertOwnership(thread.projectId, thread.cwd, thread.id);
913
+ const stopping = input.action === "clear" || input.action === "set" && input.status !== "active" && input.status !== void 0 && input.objective === void 0 && input.tokenBudget === void 0;
914
+ if (!stopping && (thread.status === "unknown" || isActive(thread.status) || thread.turns.some((turn) => isActive(turn.status)) || this.store.activeForThread(threadId)))
915
+ throw new AppError("THREAD_BUSY", "\u8BF7\u7B49\u5F85\u5F53\u524D\u4EFB\u52A1\u7ED3\u675F\u5E76\u6838\u5BF9\u72B6\u6001\u540E\u518D\u4FEE\u6539\u6216\u6062\u590D\u76EE\u6807", 409);
916
+ this.ensureCompatibilityConfirmed();
917
+ if (!this.codex.getGoal || !this.codex.mutateGoal)
918
+ throw new AppError("GOAL_UNAVAILABLE", "\u5F53\u524D Codex \u4E0D\u652F\u6301\u76EE\u6807", 409);
919
+ const before = await this.getGoal(threadId);
920
+ if (before.version !== input.expectedVersion)
921
+ throw new AppError("GOAL_CONFLICT", "\u76EE\u6807\u5DF2\u53D1\u751F\u53D8\u5316\uFF0C\u8BF7\u91CD\u65B0\u8BFB\u53D6\u540E\u64CD\u4F5C", 409);
922
+ this.store.dispatch(input.clientOperationId);
923
+ const mutation = input.action === "clear" ? { action: "clear" } : {
924
+ action: "set",
925
+ ...input.objective === void 0 ? {} : { objective: input.objective },
926
+ ...input.status === void 0 ? {} : { status: input.status },
927
+ ...input.tokenBudget === void 0 ? {} : { tokenBudget: input.tokenBudget }
928
+ };
929
+ const previousGoal = this.projection.get(threadId)?.goal;
930
+ const goal = await this.codex.mutateGoal(threadId, mutation);
931
+ const current = this.projection.get(threadId);
932
+ if (current && current.goal === previousGoal) {
933
+ current.goal = goal;
934
+ this.projection.touch(threadId);
935
+ this.publishThread(threadId);
936
+ }
937
+ return { result: { goal } };
938
+ } finally {
939
+ this.goalWrites.delete(threadId);
940
+ }
941
+ });
942
+ }
943
+ async recapThread(threadId, input) {
944
+ return this.perform("thread.recap", threadId, input, async () => {
945
+ const thread = await this.loadThread(threadId);
946
+ this.ensureManaged(thread);
947
+ this.workspaces.assertOwnership(thread.projectId, thread.cwd, thread.id);
948
+ if (thread.status === "unknown" || isActive(thread.status) || thread.turns.some((turn) => isActive(turn.status)))
949
+ throw new AppError("THREAD_BUSY", "\u8BF7\u7B49\u5F85\u4EFB\u52A1\u7ED3\u675F\u5E76\u6838\u5BF9\u72B6\u6001\u540E\u518D\u751F\u6210\u6458\u8981", 409);
950
+ this.ensureCompatibilityConfirmed();
951
+ if (!this.codex.recapThread)
952
+ throw new AppError("METHOD_UNAVAILABLE", "Codex \u4E0D\u652F\u6301\u4F1A\u8BDD\u6458\u8981", 409);
953
+ const history = await (this.codex.readThreadPage?.(threadId) ?? this.codex.readThread(threadId));
954
+ this.workspaces.assertOwnership(thread.projectId, history.cwd, history.id);
955
+ const { prompt, partial } = recapInput(history, input.language);
956
+ if (!history.turns.some(
957
+ (turn) => turn.items.some(
958
+ (item) => (item.type === "userMessage" || item.type === "agentMessage") && item.text?.trim()
959
+ )
960
+ ))
961
+ throw new AppError("EMPTY_THREAD", "\u5F53\u524D\u4F1A\u8BDD\u6CA1\u6709\u53EF\u751F\u6210\u6458\u8981\u7684\u6D88\u606F", 409);
962
+ this.store.dispatch(input.clientOperationId);
963
+ const summary = await this.codex.recapThread(threadId, prompt);
964
+ this.workspaces.assertOwnership(thread.projectId, thread.cwd, thread.id);
965
+ return { result: { summary, partial, readAt: Date.now() } };
966
+ });
967
+ }
968
+ async getGuardianDenials(threadId) {
969
+ const thread = await this.loadThread(threadId);
970
+ this.ensureManaged(thread);
971
+ this.workspaces.assertOwnership(thread.projectId, thread.cwd, thread.id);
972
+ if (!this.codex.listGuardianDenials)
973
+ throw new AppError("METHOD_UNAVAILABLE", "Codex \u4E0D\u652F\u6301\u62D2\u7EDD\u8BB0\u5F55\u8BFB\u53D6", 409);
974
+ return { data: this.codex.listGuardianDenials(threadId) };
975
+ }
976
+ async approveGuardianDenial(threadId, input) {
977
+ return this.perform("guardian.approve", threadId, input, async () => {
978
+ const thread = await this.loadThread(threadId);
979
+ this.ensureManaged(thread);
980
+ this.workspaces.assertOwnership(thread.projectId, thread.cwd, thread.id);
981
+ if (thread.status === "unknown" || isActive(thread.status) || thread.turns.some((turn) => isActive(turn.status)))
982
+ throw new AppError("THREAD_BUSY", "\u8BF7\u7B49\u5F85\u5F53\u524D\u4EFB\u52A1\u7ED3\u675F\u5E76\u786E\u8BA4\u72B6\u6001\u540E\u518D\u6388\u6743\u91CD\u8BD5", 409);
983
+ this.ensureCompatibilityConfirmed();
984
+ if (!this.codex.approveGuardianDenial || !this.codex.listGuardianDenials?.(threadId).some((entry) => entry.id === input.denialId))
985
+ throw new AppError("DENIAL_EXPIRED", "\u62D2\u7EDD\u8BB0\u5F55\u5DF2\u5931\u6548\uFF0C\u8BF7\u91CD\u65B0\u67E5\u770B\u5F53\u524D\u4F1A\u8BDD", 409);
986
+ this.store.dispatch(input.clientOperationId);
987
+ await this.codex.approveGuardianDenial(threadId, input.denialId);
988
+ this.publishThread(threadId);
989
+ return { result: { threadId } };
990
+ });
991
+ }
846
992
  async compactThread(threadId, input) {
847
993
  return this.perform("thread.compact", threadId, input, async () => {
848
994
  this.capacityRetries.clear(threadId);
@@ -888,7 +1034,7 @@ class GatewayService {
888
1034
  });
889
1035
  const revision = this.projection.revision(threadId);
890
1036
  this.turnBaselines.set(input.clientOperationId, new Set(thread.turns.map((turn2) => turn2.id)));
891
- const turn = await this.codex.startReview(threadId);
1037
+ const turn = await this.codex.startReview(threadId, input.target);
892
1038
  this.store.attachTurn(input.clientOperationId, turn.id);
893
1039
  this.turnBaselines.delete(input.clientOperationId);
894
1040
  this.projection.turn(threadId, turn, this.projection.revision(threadId) !== revision);
@@ -1282,7 +1428,7 @@ class GatewayService {
1282
1428
  }
1283
1429
  historyVisible(thread) {
1284
1430
  return Boolean(
1285
- thread.hasMessages || thread.archived || thread.turns.length || this.store.activeForThread(thread.id) || isActive(thread.status) || thread.actions.some((action) => ["pending", "responding"].includes(action.status))
1431
+ thread.hasMessages || thread.archived || thread.goal || thread.turns.length || this.store.activeForThread(thread.id) || isActive(thread.status) || thread.actions.some((action) => ["pending", "responding"].includes(action.status))
1286
1432
  );
1287
1433
  }
1288
1434
  retryLinks(threadId) {
@@ -1418,6 +1564,12 @@ class GatewayService {
1418
1564
  }
1419
1565
  const thread = this.projection.get(event.threadId);
1420
1566
  if (!thread) return;
1567
+ if (event.type === "goal") {
1568
+ thread.goal = event.goal;
1569
+ this.projection.touch(thread.id);
1570
+ this.publishThread(thread.id);
1571
+ return;
1572
+ }
1421
1573
  const previousAttention = new Set(
1422
1574
  event.type === "item" || event.type === "turn" ? pendingAttention(thread).map(attentionKey) : []
1423
1575
  );
@@ -1453,6 +1605,32 @@ class GatewayService {
1453
1605
  this.projection.touch(thread.id);
1454
1606
  } else if (event.type === "turn") {
1455
1607
  const previous = thread.turns.find((turn) => turn.id === event.turn.id);
1608
+ if (thread.goal && !isTerminal(event.turn.status) && (!previous || !isTerminal(previous.status)) && !this.store.activeForThread(thread.id) && this.store.getThreadLink(thread.id)?.managedEpoch === this.codex.epoch) {
1609
+ try {
1610
+ const ownership = this.workspaces.assertOwnership(
1611
+ thread.projectId,
1612
+ thread.cwd,
1613
+ thread.id
1614
+ );
1615
+ const operationId = randomUUID();
1616
+ this.store.accept(operationId, "goal.continue", thread.id, {
1617
+ turnId: event.turn.id,
1618
+ codexEpoch: this.codex.epoch
1619
+ });
1620
+ this.store.dispatch(operationId, {
1621
+ threadId: thread.id,
1622
+ workspaceKey: ownership.workspaceKey,
1623
+ codexEpoch: this.codex.epoch
1624
+ });
1625
+ this.store.attachTurn(operationId, event.turn.id);
1626
+ this.store.acknowledge(
1627
+ operationId,
1628
+ { threadId: thread.id, turnId: event.turn.id },
1629
+ event.turn.id
1630
+ );
1631
+ } catch {
1632
+ }
1633
+ }
1456
1634
  const newCompletion = !previous || !isTerminal(previous.status);
1457
1635
  if (isTerminal(event.turn.status)) this.turnUsage.save(thread.id, event.turn);
1458
1636
  this.projection.turn(thread.id, event.turn);