@tea-agent/loop-agent 0.43.0-next.17 → 0.43.0-next.3

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 (187) hide show
  1. package/CHANGELOG.md +9 -140
  2. package/dist/application/task-lifecycle/advance.js +4 -17
  3. package/dist/application/task-lifecycle/observe.js +29 -43
  4. package/dist/application/task-lifecycle/plan-transitions.js +4 -5
  5. package/dist/build-stamp.json +3 -3
  6. package/dist/commands/client-recovery.js +55 -20
  7. package/dist/commands/new-task.js +5 -0
  8. package/dist/commands/status.js +57 -0
  9. package/dist/commands/task-contract.js +269 -0
  10. package/dist/executors/dag-pi-executor.js +230 -269
  11. package/dist/executors/pi-executor.js +0 -2
  12. package/dist/executors/pi-sdk-executor.js +39 -77
  13. package/dist/executors/shell-executor.js +2 -3
  14. package/dist/executors/shell-write-guard.js +32 -27
  15. package/dist/shared/pi-context-pressure/extension.js +16 -26
  16. package/dist/shared/pi-retry-settings.js +0 -40
  17. package/dist/shared/prompts.js +26 -0
  18. package/dist/task/config.js +2 -0
  19. package/dist/task/contract/validate-draft.js +106 -0
  20. package/dist/task/goal.js +3 -0
  21. package/dist/task/index.js +12 -0
  22. package/dist/task/lifecycle.js +1 -0
  23. package/dist/task/operator/capabilities.js +6 -0
  24. package/dist/task/operator/envelope.js +2 -0
  25. package/dist/task/operator/index.js +5 -0
  26. package/dist/task/operator/registry.js +2 -0
  27. package/dist/task/operator/types.js +1 -0
  28. package/dist/task/paths.js +1 -0
  29. package/dist/task/source-prepare/source-fidelity-pi.js +2 -2
  30. package/dist/task/source-references.js +23 -48
  31. package/dist/task/source-state.js +1 -0
  32. package/dist/task/subagent-guidance.js +1 -0
  33. package/dist/worker/console/chat/assistant-content.js +2 -23
  34. package/dist/worker/console/chat/explore-tools.js +0 -13
  35. package/dist/worker/console/chat/pi-runtime.js +1182 -221
  36. package/dist/worker/console/chat/routes.js +71 -213
  37. package/dist/worker/console/chat/sdd-data-alignment.js +9 -65
  38. package/dist/worker/console/chat/session-catalog.js +0 -32
  39. package/dist/worker/console/chat/session-store.js +6 -22
  40. package/dist/worker/console/chat/shortcuts.js +0 -6
  41. package/dist/worker/console/chat/sift-bridge.js +1 -0
  42. package/dist/worker/console/chat/tool-preview.js +0 -11
  43. package/dist/worker/console/chat/tools.js +0 -6
  44. package/dist/worker/console/console-update-and-init.js +19 -1
  45. package/dist/worker/console/console-update-runtime.js +20 -5
  46. package/dist/worker/console/index.js +20 -0
  47. package/dist/worker/console/operator-actions.js +1 -13
  48. package/dist/worker/console/routes.js +0 -8
  49. package/dist/worker/console/server.js +29 -11
  50. package/dist/worker/console/static/assets/{abnfDiagram-N423BO3Z-C4NXyedy.js → abnfDiagram-N423BO3Z-hUmM_GRf.js} +1 -1
  51. package/dist/worker/console/static/assets/{arc-NZ3qXvBI.js → arc-Bt-xuieW.js} +1 -1
  52. package/dist/worker/console/static/assets/{architectureDiagram-T3A2C74G-COZSRvml.js → architectureDiagram-T3A2C74G-DTqkL4DJ.js} +1 -1
  53. package/dist/worker/console/static/assets/{blockDiagram-VBNYF7ZC-Ck0Gxi9C.js → blockDiagram-VBNYF7ZC-Cy0MNnzV.js} +1 -1
  54. package/dist/worker/console/static/assets/{c4Diagram-5PPSVZJV-BX5HQ4Ox.js → c4Diagram-5PPSVZJV-DDdlT0Pd.js} +1 -1
  55. package/dist/worker/console/static/assets/channel-BpzRnZmU.js +1 -0
  56. package/dist/worker/console/static/assets/{chunk-2GRJ4B5K-CoviemSL.js → chunk-2GRJ4B5K-3JawwNZ6.js} +1 -1
  57. package/dist/worker/console/static/assets/{chunk-2Q5K7J3B-DbOdOkbZ.js → chunk-2Q5K7J3B-DoTp7Cri.js} +1 -1
  58. package/dist/worker/console/static/assets/{chunk-5RXB4S5H-BsG2pmdQ.js → chunk-5RXB4S5H-CcirhZaS.js} +1 -1
  59. package/dist/worker/console/static/assets/{chunk-5VM5RSS4-DGdvrNm8.js → chunk-5VM5RSS4-VrG21gnP.js} +1 -1
  60. package/dist/worker/console/static/assets/{chunk-6Q2QTUOP-BAy7Yd6y.js → chunk-6Q2QTUOP-DDOgIS70.js} +1 -1
  61. package/dist/worker/console/static/assets/{chunk-GF5L2VYU-D9UA7hUb.js → chunk-GF5L2VYU-CBjmgvJ_.js} +1 -1
  62. package/dist/worker/console/static/assets/{chunk-JWPE2WC7-DPz7SZ8V.js → chunk-JWPE2WC7-CCQSht8M.js} +1 -1
  63. package/dist/worker/console/static/assets/{chunk-KBJHAD2P-BmuEOIh7.js → chunk-KBJHAD2P-BpGMkUUV.js} +1 -1
  64. package/dist/worker/console/static/assets/{chunk-RYQCIY6F-CIhBWnd8.js → chunk-RYQCIY6F-DNDT41QL.js} +1 -1
  65. package/dist/worker/console/static/assets/{chunk-XXDRQBXY-CScR6mDD.js → chunk-XXDRQBXY-euXnDFbn.js} +1 -1
  66. package/dist/worker/console/static/assets/classDiagram-JCYQIIEL-BhlMVqCc.js +1 -0
  67. package/dist/worker/console/static/assets/classDiagram-v2-OCEON4UE-BhlMVqCc.js +1 -0
  68. package/dist/worker/console/static/assets/{cose-bilkent-JH36ORCC-BjpfWaUr.js → cose-bilkent-JH36ORCC-BJ6NAeql.js} +1 -1
  69. package/dist/worker/console/static/assets/{cynefin-VYW2F7L2-BFQohJgT.js → cynefin-VYW2F7L2-F5JKIvIq.js} +1 -1
  70. package/dist/worker/console/static/assets/{cynefinDiagram-MW4NZA55-D3gzRJnS.js → cynefinDiagram-MW4NZA55-Cwmkl_Gi.js} +1 -1
  71. package/dist/worker/console/static/assets/{dagre-VZM6K2ZE-5eojkhoA.js → dagre-VZM6K2ZE-BmCZ8815.js} +1 -1
  72. package/dist/worker/console/static/assets/{diagram-7IWD3JNH-CpD8LWu_.js → diagram-7IWD3JNH-zWA3hUnX.js} +1 -1
  73. package/dist/worker/console/static/assets/{diagram-B4RE2ZJO-B8_4qJ2a.js → diagram-B4RE2ZJO-BzA-888F.js} +1 -1
  74. package/dist/worker/console/static/assets/{diagram-LBJQPF4R-HOsXf0eu.js → diagram-LBJQPF4R-tPNheoch.js} +1 -1
  75. package/dist/worker/console/static/assets/{diagram-Q27KOJAE-BqwRwiWP.js → diagram-Q27KOJAE-Cdi7Fyqp.js} +1 -1
  76. package/dist/worker/console/static/assets/{diagram-UB23O5K3-BRVCNZe1.js → diagram-UB23O5K3-DFK9VBf1.js} +1 -1
  77. package/dist/worker/console/static/assets/{ebnfDiagram-BXEA7PRR-Cvb1TgGh.js → ebnfDiagram-BXEA7PRR-xCUr1kpg.js} +1 -1
  78. package/dist/worker/console/static/assets/{erDiagram-JOGREHBK-DS0O0qG9.js → erDiagram-JOGREHBK-BANQHY_A.js} +1 -1
  79. package/dist/worker/console/static/assets/{flowDiagram-UKHOOZJN-BHIRvRr3.js → flowDiagram-UKHOOZJN-VHJYEMkP.js} +1 -1
  80. package/dist/worker/console/static/assets/{ganttDiagram-PKOTCBZU-DcCJ1JWx.js → ganttDiagram-PKOTCBZU-DiyZQ0C6.js} +1 -1
  81. package/dist/worker/console/static/assets/{gitGraphDiagram-DS77QQ5N-B9ia5ony.js → gitGraphDiagram-DS77QQ5N-CZtIeBBa.js} +1 -1
  82. package/dist/worker/console/static/assets/index-BlN6ytLr.css +1 -0
  83. package/dist/worker/console/static/assets/index-CA-jfWlE.js +449 -0
  84. package/dist/worker/console/static/assets/{infoDiagram-6WML65LV-3ogpgegn.js → infoDiagram-6WML65LV-BuSspC0X.js} +1 -1
  85. package/dist/worker/console/static/assets/{ishikawaDiagram-WSZJBQD7-4tgpQ5SL.js → ishikawaDiagram-WSZJBQD7-DRJZyPFy.js} +1 -1
  86. package/dist/worker/console/static/assets/{journeyDiagram-NVQOT4AX-DNfgHqFx.js → journeyDiagram-NVQOT4AX-DIfXIVuE.js} +1 -1
  87. package/dist/worker/console/static/assets/{kanban-definition-27J2QSJJ-Dz7ngC8z.js → kanban-definition-27J2QSJJ-CT10_7Lt.js} +1 -1
  88. package/dist/worker/console/static/assets/{linear-DI7Jv62E.js → linear-ufemj74H.js} +1 -1
  89. package/dist/worker/console/static/assets/{mermaid.core-CQA4Nzmo.js → mermaid.core-DEQe8-_m.js} +5 -5
  90. package/dist/worker/console/static/assets/{mindmap-definition-FAOFIHXS-CtsMc8Mf.js → mindmap-definition-FAOFIHXS-BRLUrbrC.js} +1 -1
  91. package/dist/worker/console/static/assets/{pegDiagram-VL7TDLO6-ByppE9yH.js → pegDiagram-VL7TDLO6-BgibKtiF.js} +1 -1
  92. package/dist/worker/console/static/assets/{pieDiagram-7S7Q4E2Y-B5PtgFgt.js → pieDiagram-7S7Q4E2Y-D3eyfdV9.js} +1 -1
  93. package/dist/worker/console/static/assets/{quadrantDiagram-CIZ2JOQS-Cq4p0k2K.js → quadrantDiagram-CIZ2JOQS-DXeTk5Px.js} +1 -1
  94. package/dist/worker/console/static/assets/{railroadDiagram-AXF67PYL-DjfkyljN.js → railroadDiagram-AXF67PYL-BgXdFEe7.js} +1 -1
  95. package/dist/worker/console/static/assets/{requirementDiagram-LRYGKXZP-DzynNRSl.js → requirementDiagram-LRYGKXZP-CseC2A7R.js} +1 -1
  96. package/dist/worker/console/static/assets/{sankeyDiagram-W5VNT64P-Cj7TCpTJ.js → sankeyDiagram-W5VNT64P-D80PFzfJ.js} +1 -1
  97. package/dist/worker/console/static/assets/{sequenceDiagram-SI44F4Z6-C73C6ykA.js → sequenceDiagram-SI44F4Z6-BWzHW7LS.js} +1 -1
  98. package/dist/worker/console/static/assets/{sizeCapture-X5ZJPWSS-BiNLgN2x.js → sizeCapture-X5ZJPWSS-xWQYTLAn.js} +1 -1
  99. package/dist/worker/console/static/assets/{stateDiagram-OKZ733FA-UwvjS64-.js → stateDiagram-OKZ733FA-CLxtpZeL.js} +1 -1
  100. package/dist/worker/console/static/assets/stateDiagram-v2-UEYNNEHI-CiVoq4G-.js +1 -0
  101. package/dist/worker/console/static/assets/{swimlanes-SLNWSIFB-CC7DH98r.js → swimlanes-SLNWSIFB-DwugtmWV.js} +2 -2
  102. package/dist/worker/console/static/assets/swimlanesDiagram-ULZ7WXOC-BkdgdpfR.js +8 -0
  103. package/dist/worker/console/static/assets/{timeline-definition-Z64GVDOM-LSBXTR70.js → timeline-definition-Z64GVDOM-DHEOwHIe.js} +1 -1
  104. package/dist/worker/console/static/assets/{vennDiagram-T6HMQDX7-BAuxWwGP.js → vennDiagram-T6HMQDX7-pmbZKlBK.js} +1 -1
  105. package/dist/worker/console/static/assets/{wardleyDiagram-T6FBY63Y--E5_gjZx.js → wardleyDiagram-T6FBY63Y-CivHoM5q.js} +1 -1
  106. package/dist/worker/console/static/assets/{xychartDiagram-ELKLHX3M-dJWNmyzF.js → xychartDiagram-ELKLHX3M-BfHIE7o6.js} +1 -1
  107. package/dist/worker/console/static/index.html +2 -2
  108. package/dist/worker/console/static-src/operator-chat/chat-sse-events.js +10 -122
  109. package/dist/worker/console/static-src/operator-chat/compaction-message.js +0 -7
  110. package/dist/worker/console/static-src/operator-chat/pending-user-message.js +15 -35
  111. package/dist/worker/console/static-src/operator-chat/useChatSessions.js +62 -136
  112. package/dist/worker/console/static-src/operator-chat/useChatStream.js +68 -159
  113. package/dist/worker/console/static-src/operator-chat/useChatThread.js +56 -75
  114. package/dist/worker/console/static-src/operator-chat/useComposer.js +78 -206
  115. package/dist/worker/console/workspace-context.js +1 -21
  116. package/dist/worker/observe/static/router.js +1 -1
  117. package/dist/worker/observe/static/styles.css +4 -7
  118. package/dist/worker/observe/static/views/dag-inspector.js +19 -12
  119. package/dist/worker/observe/static/views/dag.js +2 -2
  120. package/dist/worker/scheduler/index.js +25 -0
  121. package/dist/workflows/dag/facts.js +4 -0
  122. package/dist/workflows/dag/frontend-closeout.js +1 -1
  123. package/dist/workflows/dag/frontend-design-policy.js +1 -2
  124. package/dist/workflows/dag/frontend-implementation-contract.js +4 -8
  125. package/dist/workflows/dag/frontend-prewrite-gate.js +3 -3
  126. package/dist/workflows/dag/frontend-repair.js +76 -55
  127. package/dist/workflows/dag/frontend-review-context.js +1 -2
  128. package/dist/workflows/dag/frontend-review-scopes.js +12 -34
  129. package/dist/workflows/dag/frontend-shape-facts.js +2 -12
  130. package/dist/workflows/dag/frontend-verification-trace.js +42 -8
  131. package/dist/workflows/dag/index.js +6 -0
  132. package/dist/workflows/dag/init-hybrid.js +160 -97
  133. package/dist/workflows/dynamic/index.js +7 -0
  134. package/docs/architecture/runtime-boundaries.md +3 -3
  135. package/docs/templates/frontend-implementation-dag.json +8 -9
  136. package/package.json +3 -7
  137. package/skills/frontend-bounded-implement/SKILL.md +3 -4
  138. package/skills/frontend-bounded-implement/references/code-standards.md +3 -3
  139. package/skills/frontend-contract/references/contract-protocol.md +1 -3
  140. package/skills/frontend-design-review/SKILL.md +7 -12
  141. package/skills/frontend-design-review/references/review-checklist.md +7 -7
  142. package/skills/frontend-plan/SKILL.md +0 -19
  143. package/skills/frontend-plan/references/decision-contract.md +19 -26
  144. package/skills/frontend-review/SKILL.md +18 -12
  145. package/skills/frontend-review/references/review-findings.md +43 -24
  146. package/dist/shared/pi-provider-recovery.js +0 -182
  147. package/dist/worker/console/chat/browser-automation.js +0 -363
  148. package/dist/worker/console/chat/browser-policy.js +0 -113
  149. package/dist/worker/console/chat/browser-routes.js +0 -162
  150. package/dist/worker/console/chat/pi-runtime/custom-tools/ask-user-question.js +0 -44
  151. package/dist/worker/console/chat/pi-runtime/custom-tools/browser-tools.js +0 -89
  152. package/dist/worker/console/chat/pi-runtime/custom-tools/explore-tools.js +0 -202
  153. package/dist/worker/console/chat/pi-runtime/custom-tools/goal-tools.js +0 -79
  154. package/dist/worker/console/chat/pi-runtime/custom-tools/operator-tools.js +0 -86
  155. package/dist/worker/console/chat/pi-runtime/custom-tools/todo-write.js +0 -38
  156. package/dist/worker/console/chat/pi-runtime/inspection-types.js +0 -28
  157. package/dist/worker/console/chat/pi-runtime/inspection.js +0 -439
  158. package/dist/worker/console/chat/pi-runtime/sdk-bindings.js +0 -153
  159. package/dist/worker/console/chat/pi-runtime/sdk-session.js +0 -5
  160. package/dist/worker/console/chat/scm-routes.js +0 -217
  161. package/dist/worker/console/chat/scm-service.js +0 -283
  162. package/dist/worker/console/chat/scm-tools.js +0 -111
  163. package/dist/worker/console/chat/session-mode-view.js +0 -49
  164. package/dist/worker/console/chat/session-mode.js +0 -220
  165. package/dist/worker/console/chat/terminal-routes.js +0 -216
  166. package/dist/worker/console/chat/terminal-sessions.js +0 -348
  167. package/dist/worker/console/chat/terminal-tools.js +0 -211
  168. package/dist/worker/console/static/assets/channel-BxdTlb_5.js +0 -1
  169. package/dist/worker/console/static/assets/classDiagram-JCYQIIEL-_ByA1Nf8.js +0 -1
  170. package/dist/worker/console/static/assets/classDiagram-v2-OCEON4UE-_ByA1Nf8.js +0 -1
  171. package/dist/worker/console/static/assets/index-B9goN3S5.css +0 -1
  172. package/dist/worker/console/static/assets/index-wXlQohNs.js +0 -469
  173. package/dist/worker/console/static/assets/stateDiagram-v2-UEYNNEHI-nLgMZ0D3.js +0 -1
  174. package/dist/worker/console/static/assets/swimlanesDiagram-ULZ7WXOC-BcYqTady.js +0 -8
  175. package/dist/worker/console/static-src/operator-chat/active-turn-tail.js +0 -10
  176. package/dist/worker/console/static-src/operator-chat/chat-link.js +0 -94
  177. package/dist/worker/console/static-src/operator-chat/chat-scroll-position.js +0 -24
  178. package/dist/worker/console/static-src/operator-chat/composer-session-ledger.js +0 -192
  179. package/dist/worker/console/static-src/operator-chat/process-label.js +0 -41
  180. package/dist/worker/console/static-src/operator-chat/turn-group-equality.js +0 -13
  181. package/dist/worker/console/static-src/operator-chat/turn-process-disclosure.js +0 -10
  182. package/dist/worker/console/static-src/operator-chat/use-searchable-hidden.js +0 -51
  183. package/dist/worker/console/static-src/operator-chat/user-turn-anchor-equality.js +0 -21
  184. package/dist/worker/console/workspace-initialization.js +0 -209
  185. package/dist/workflows/dag/frontend-capacity.js +0 -9
  186. package/dist/workflows/dag/frontend-plan-completeness.js +0 -186
  187. package/dist/workflows/dag/frontend-plan-recovery-policy.js +0 -18
@@ -1,209 +0,0 @@
1
- import { lstat, readFile } from "node:fs/promises";
2
- import path from "node:path";
3
- import { acquireUpdateLock, updateLockPath } from "../../shared/update/state.js";
4
- import os from "node:os";
5
- import { TERMINAL_OPERATION_STATES } from "../../infrastructure/console/operation-store.js";
6
- import { readInitRuntimeActivity } from "../observability/init-runtime-activity.js";
7
- const record = (value) => {
8
- if (!value || typeof value !== "object" || Array.isArray(value))
9
- throw new Error("初始化检查返回了无效数据");
10
- return value;
11
- };
12
- const entries = (value) => {
13
- if (!Array.isArray(value))
14
- throw new Error("初始化检查缺少状态清单");
15
- return value.map(record);
16
- };
17
- /** A single registered workspace owns checks, CLI cwd and durable operations. */
18
- export class WorkspaceInitializationService {
19
- options;
20
- cached;
21
- pending;
22
- activeOperationId;
23
- generation = 0;
24
- constructor(options) {
25
- this.options = options;
26
- }
27
- snapshot(state, message, pendingPaths = []) {
28
- const { workspaceId, name, repoRoot } = this.options;
29
- return { workspaceId, name, displayPath: repoRoot, state, message, pendingPaths, canUpdate: false, pendingItems: [] };
30
- }
31
- async jsonFile(relative) {
32
- const file = path.join(this.options.repoRoot, relative);
33
- try {
34
- const stat = await lstat(file);
35
- if (!stat.isFile() || stat.isSymbolicLink())
36
- throw new Error(`${relative} 不是普通配置文件`);
37
- return record(JSON.parse(await readFile(file, "utf8")));
38
- }
39
- catch (error) {
40
- if (error.code === "ENOENT")
41
- return undefined;
42
- throw new Error(`${relative} 无法读取,请检查文件内容与权限`);
43
- }
44
- }
45
- async command(args, name) {
46
- const result = await this.options.client.run(args, {
47
- cwd: this.options.repoRoot, artifactName: `workspace-init-${name}`,
48
- expectJson: true, timeoutMs: 120_000,
49
- });
50
- if (!result.ok || result.exitCode !== 0 || result.timedOut || result.parseFailure) {
51
- throw new Error(`工作区配置${name === "check" ? "检查" : "操作"}失败,请查看操作记录或检查模型与初始化配置`);
52
- }
53
- return record(result.json);
54
- }
55
- async catalog() {
56
- const catalog = await this.command(["init", "model-catalog", "--json"], "models");
57
- return entries(catalog.models).filter(item => item.eligibleForHarness === true && typeof item.reference === "string")
58
- .map(item => ({ reference: item.reference, name: typeof item.name === "string" ? item.name : item.reference }));
59
- }
60
- async inspect() {
61
- try {
62
- try {
63
- const harnessDir = await lstat(path.join(this.options.repoRoot, ".harness"));
64
- if (!harnessDir.isDirectory() || harnessDir.isSymbolicLink())
65
- throw new Error(".harness 必须是仓库内的普通目录");
66
- }
67
- catch (error) {
68
- if (error.code !== "ENOENT")
69
- throw error;
70
- }
71
- const surface = await this.jsonFile(".harness/init-surface.json");
72
- const harness = await this.jsonFile("harness.json");
73
- if (surface && (surface.schemaVersion !== 1 || !surface.files || typeof surface.files !== "object" || Array.isArray(surface.files))) {
74
- throw new Error("初始化记录不完整,请检查 .harness/init-surface.json");
75
- }
76
- if (!surface && !harness) {
77
- const snapshot = this.snapshot("uninitialized", "此仓库尚未初始化。初始化后可使用项目任务与工作流配置。");
78
- try {
79
- snapshot.models = await this.catalog();
80
- }
81
- catch {
82
- snapshot.message = "此仓库尚未初始化;可用模型读取失败,请检查模型设置后重新检查。";
83
- }
84
- return snapshot;
85
- }
86
- const report = await this.command(["init", "check-update", "--json"], "check");
87
- if (!["recorded", "inferred-baseline", "missing"].includes(String(report.surfaceState)) || typeof report.ok !== "boolean") {
88
- throw new Error("初始化检查返回了未知状态");
89
- }
90
- const actions = entries(report.deterministicActions);
91
- const merges = entries(report.modelMergeTasks);
92
- const decisions = entries(report.humanDecisions);
93
- const pendingItems = [];
94
- for (const [kind, list] of [["safe-update", actions], ["merge", merges], ["confirmation", decisions]]) {
95
- for (const item of list) {
96
- if (typeof item.path !== "string")
97
- continue;
98
- const detail = typeof item.reason === "string" ? item.reason : undefined;
99
- const baseline = item.type === "bootstrap-surface";
100
- const itemKind = baseline ? "confirmation" : kind;
101
- const reason = baseline ? "缺少可靠的初始化记录,不能直接判断哪些内容可覆盖。"
102
- : kind === "safe-update" ? "此项可由程序安全更新,保留项目自定义内容。"
103
- : kind === "merge" ? "现有内容与新版初始化模板不同,需要保留项目配置后合并。"
104
- : /not a directory/.test(detail ?? "") ? "这里需要一个目录,但当前路径被文件占用。"
105
- : /removed.*local changes/.test(detail ?? "") ? "新版不再使用此文件,但它包含本地修改,需要决定保留还是删除。"
106
- : /target path.*already exists/.test(detail ?? "") ? "迁移目标已有不同内容,需要确认两份文件如何保留。"
107
- : "此项无法安全自动处理,请先核对检查详情,再确定处理方式。";
108
- pendingItems.push({ path: item.path, kind: itemKind, reason,
109
- nextStep: itemKind === "safe-update" ? "点击更新按钮即可处理。"
110
- : itemKind === "merge" ? "可将下方处理说明交给智能体合并;只有需求冲突时才需你确认。"
111
- : "将处理说明交给智能体检查;需要取舍时确认方案,处理后重新检查。",
112
- ...(detail ? { detail } : {}) });
113
- }
114
- }
115
- const modelsReady = record(report.modelReadiness).status === "ready";
116
- if (!modelsReady)
117
- pendingItems.push({ path: "模型配置", kind: "model",
118
- reason: "当前模型配置或认证尚未就绪,更新文件不能解决此问题。",
119
- nextStep: "检查模型定义及提供商认证,保留仍可用的模型配置,完成后重新检查。" });
120
- const canUpdate = pendingItems.some(item => item.kind === "safe-update");
121
- const needsAttention = pendingItems.some(item => item.kind !== "safe-update") || !report.ok || report.surfaceState !== "recorded" && !canUpdate;
122
- if (needsAttention || canUpdate) {
123
- const safeCount = pendingItems.filter(item => item.kind === "safe-update").length;
124
- const message = canUpdate
125
- ? `有 ${safeCount} 项可在此更新。${needsAttention ? "其余待处理项的原因和下一步见下方。" : "更新会保留项目自定义内容。"}`
126
- : "暂无可直接更新的内容。请按下方原因处理,完成后重新检查。";
127
- if (!pendingItems.length)
128
- pendingItems.push({ path: "初始化配置", kind: "confirmation",
129
- reason: "检查尚未通过,但没有返回可自动更新的项目。",
130
- nextStep: "复制处理说明交给智能体检查初始化记录,完成后重新检查。" });
131
- return { ...this.snapshot(needsAttention ? "needs-attention" : "update-available", message, [...new Set(pendingItems.map(item => item.path))]), canUpdate, pendingItems };
132
- }
133
- return this.snapshot("ready", "工作区配置已就绪");
134
- }
135
- catch (error) {
136
- return this.snapshot("error", error instanceof Error ? error.message : "初始化状态检查失败");
137
- }
138
- }
139
- async check(refresh = false) {
140
- const latest = (await this.options.operations.list()).filter(op => op.action === "workspaceInitialize").at(-1);
141
- const running = latest && !TERMINAL_OPERATION_STATES.has(latest.state) && latest.state !== "needs-reconcile";
142
- if (!running && (refresh || !this.cached || Date.now() - this.cached.at > 30_000)) {
143
- const generation = this.generation;
144
- this.pending ??= this.inspect().then(value => { if (generation === this.generation)
145
- this.cached = { value, at: Date.now() }; return value; }).finally(() => { this.pending = undefined; });
146
- await this.pending;
147
- }
148
- const value = this.cached?.value ?? this.snapshot("uninitialized", "正在初始化工作区…");
149
- return { ...value, ...(latest ? { operation: { operationId: latest.operationId, state: latest.state, ...(latest.errorMessage ? { message: latest.errorMessage } : {}) } } : {}) };
150
- }
151
- async start(clientRequestId, model) {
152
- const created = await this.options.operations.create({ clientRequestId, action: "workspaceInitialize", actionParams: { ...(model ? { model } : {}) } });
153
- if (created.kind !== "created")
154
- return created;
155
- const operationId = created.operation.operationId;
156
- if (this.activeOperationId) {
157
- await this.options.operations.update(operationId, { state: "failed", finishedAt: new Date().toISOString(), errorCode: "WORKSPACE_INIT_BUSY", errorMessage: "此工作区已有初始化操作正在运行" });
158
- return created;
159
- }
160
- this.activeOperationId = operationId;
161
- this.generation += 1;
162
- queueMicrotask(() => { void this.execute(operationId, model); });
163
- return created;
164
- }
165
- async execute(operationId, model) {
166
- let release;
167
- try {
168
- await this.options.operations.update(operationId, { state: "running", startedAt: new Date().toISOString() });
169
- this.options.events.append(operationId, { at: new Date().toISOString(), kind: "state", state: "running", message: `正在检查并配置 ${this.options.name}` });
170
- release = await (this.options.acquireLock ?? (() => acquireUpdateLock(updateLockPath(os.homedir()))))();
171
- if (!release)
172
- throw new Error("程序更新或其他初始化操作正在进行,请稍后重试");
173
- const activity = await (this.options.readActivity ?? readInitRuntimeActivity)(this.options.repoRoot);
174
- if (activity.workerProjectionError || activity.activeDagRunIds.length || activity.activeWorkerTasks || activity.activeWorkerBatches || this.options.activeChatTurnCount())
175
- throw new Error("当前工作区有任务或对话正在运行,请结束后重试");
176
- const operations = await this.options.operations.list();
177
- if (operations.some(op => op.operationId !== operationId && !TERMINAL_OPERATION_STATES.has(op.state) && op.state !== "needs-reconcile"))
178
- throw new Error("当前工作区有其他操作正在运行,请稍后重试");
179
- const before = await this.inspect();
180
- if (before.state === "error")
181
- throw new Error(before.message);
182
- if (before.state === "uninitialized") {
183
- if (!model || !before.models?.some(item => item.reference === model))
184
- throw new Error("请选择一个可用的初始模型;可在模型设置中完成认证后重新检查");
185
- await this.command(["init", "--profile", "full", "--merge", "--client-recovery", "project", "--model", model, "--json"], "apply");
186
- }
187
- else if (before.canUpdate) {
188
- await this.command(["init", "update", "--apply-safe", "--client-recovery", "project", "--json"], "apply");
189
- }
190
- else if (before.state !== "ready")
191
- throw new Error("没有可安全更新的内容;请查看待处理项的原因和下一步。");
192
- const after = await this.inspect();
193
- this.cached = { value: after, at: Date.now() };
194
- const state = after.state === "ready" ? "succeeded" : "needs-reconcile";
195
- await this.options.operations.update(operationId, { state, finishedAt: new Date().toISOString(), result: { initialization: after }, ...(state !== "succeeded" ? { errorCode: "INIT_NEEDS_RECONCILE", errorMessage: after.message } : {}) });
196
- this.options.events.append(operationId, { at: new Date().toISOString(), kind: "state", state, message: after.message });
197
- }
198
- catch (error) {
199
- this.cached = undefined;
200
- const message = error instanceof Error ? error.message : "工作区初始化失败";
201
- await this.options.operations.update(operationId, { state: "failed", finishedAt: new Date().toISOString(), errorCode: "WORKSPACE_INIT_FAILED", errorMessage: message });
202
- this.options.events.append(operationId, { at: new Date().toISOString(), kind: "error", state: "failed", message });
203
- }
204
- finally {
205
- this.activeOperationId = undefined;
206
- await release?.().catch(() => undefined);
207
- }
208
- }
209
- }
@@ -1,9 +0,0 @@
1
- /** Shared Contract/Plan bound. Permissions and directory globs are not files. */
2
- export const FRONTEND_MAX_IMPLEMENTATION_FILES = 15;
3
- export function frontendConcreteDeliveryFiles(files) {
4
- if (!Array.isArray(files))
5
- return [];
6
- return [...new Set(files.filter((file) => typeof file === "string")
7
- .map(file => file.trim().replace(/\\/g, "/").replace(/^(\.\/)+/, ""))
8
- .filter(file => file.length > 0 && !/[*?{}]/.test(file) && !file.endsWith("/")))];
9
- }
@@ -1,186 +0,0 @@
1
- import { collectCanonicalStateFlowNames } from "./frontend-contract-facts.js";
2
- export function committedFactFromPlanRecord(value) {
3
- if (!value || typeof value !== "object" || Array.isArray(value))
4
- return undefined;
5
- const record = value;
6
- if (record.phase !== undefined && record.phase !== "committed")
7
- return undefined;
8
- const fact = record.fact;
9
- return fact && typeof fact === "object" && !Array.isArray(fact)
10
- ? fact
11
- : typeof record.kind === "string"
12
- ? record
13
- : undefined;
14
- }
15
- export function planFactStringList(value) {
16
- if (!Array.isArray(value))
17
- return [];
18
- return value.filter((item) => typeof item === "string" && item.trim().length > 0);
19
- }
20
- export function planFactScopeIntersects(fact, requirementIds) {
21
- return planFactStringList(fact.scopeRequirementIds).some((id) => requirementIds.has(id));
22
- }
23
- /** Compute the authoritative coverage queue from the committed plan ledger. */
24
- export function collectFrontendPlanMissingFacts(input) {
25
- const requirements = new Map();
26
- const standaloneEvidenceGaps = new Set();
27
- const verificationTargetIds = new Set();
28
- const verificationTargetRequirements = new Map();
29
- for (const value of input.committedFacts) {
30
- const fact = committedFactFromPlanRecord(value);
31
- if (!fact || fact.origin !== "plan")
32
- continue;
33
- if (fact.kind === "plan-requirement" && fact.entry && typeof fact.entry === "object") {
34
- const entry = fact.entry;
35
- if (typeof entry.id === "string" && entry.id.trim())
36
- requirements.set(entry.id, entry);
37
- }
38
- if (fact.kind === "plan-verification-target" && fact.entry && typeof fact.entry === "object") {
39
- const entry = fact.entry;
40
- const id = entry.id;
41
- if (typeof id === "string" && id.trim()) {
42
- verificationTargetIds.add(id);
43
- verificationTargetRequirements.set(id, new Set(Array.isArray(entry.requirementIds)
44
- ? entry.requirementIds.filter((value) => typeof value === "string")
45
- : []));
46
- }
47
- }
48
- if (fact.kind === "plan-evidence-gap" && fact.entry && typeof fact.entry === "object") {
49
- const entry = fact.entry;
50
- const requirementId = entry.requirementId;
51
- const description = entry.description;
52
- if (typeof requirementId === "string" && requirementId.trim() && typeof description === "string" && description.trim()) {
53
- standaloneEvidenceGaps.add(requirementId);
54
- }
55
- }
56
- }
57
- const missing = [];
58
- for (const id of input.requirementIds) {
59
- const entry = requirements.get(id);
60
- if (!entry) {
61
- missing.push({
62
- kind: "plan-requirement",
63
- id,
64
- requirementIds: [id],
65
- reason: `requirement ${id} has no committed plan-requirement fact`,
66
- });
67
- continue;
68
- }
69
- const targetIds = Array.isArray(entry.verificationTargetIds)
70
- ? entry.verificationTargetIds.filter((value) => typeof value === "string" && value.trim().length > 0)
71
- : [];
72
- const gap = entry.evidenceGap && typeof entry.evidenceGap === "object"
73
- ? entry.evidenceGap
74
- : undefined;
75
- const hasEvidenceGap = (typeof gap?.description === "string" && gap.description.trim().length > 0) ||
76
- standaloneEvidenceGaps.has(id);
77
- if (targetIds.length === 0 && !hasEvidenceGap) {
78
- missing.push({
79
- kind: "plan-verification-target",
80
- requirementIds: [id],
81
- reason: `requirement ${id} declares neither a verification target nor a non-empty evidenceGap`,
82
- });
83
- continue;
84
- }
85
- for (const targetId of targetIds) {
86
- if (!verificationTargetIds.has(targetId) ||
87
- !verificationTargetRequirements.get(targetId)?.has(id)) {
88
- missing.push({
89
- kind: "plan-verification-target",
90
- id: targetId,
91
- requirementIds: [id],
92
- reason: `requirement ${id} references verification target ${targetId}, but that target is not committed`,
93
- });
94
- }
95
- }
96
- }
97
- return missing;
98
- }
99
- /** Completeness checks for phases whose facts are committed incrementally. */
100
- export function collectFrontendPlanPhaseMissingFacts(input) {
101
- const facts = input.committedFacts
102
- .map(committedFactFromPlanRecord)
103
- .filter((fact) => Boolean(fact && fact.origin === "plan"));
104
- if (input.phase === "ux-registry") {
105
- return facts.some((fact) => fact.kind === "state-registry")
106
- ? []
107
- : [
108
- {
109
- kind: "state-registry",
110
- requirementIds: [...input.requirementIds],
111
- reason: "global UX vocabulary phase has no committed state-registry fact",
112
- },
113
- ];
114
- }
115
- if (input.phase === "ux-local") {
116
- // One snapshot per check: no cross-revision cache to invalidate.
117
- const required = new Set(input.behaviorRequiredRequirementIds ?? []);
118
- const requested = new Set(input.requirementIds.filter(id => required.has(id)));
119
- if (!requested.size)
120
- return [];
121
- const byRequirement = new Map();
122
- for (const fact of facts) {
123
- for (const id of new Set(planFactStringList(fact.scopeRequirementIds))) {
124
- if (!requested.has(id))
125
- continue;
126
- const entries = byRequirement.get(id) ?? [];
127
- entries.push(fact);
128
- byRequirement.set(id, entries);
129
- }
130
- }
131
- const liveStateFlow = collectCanonicalStateFlowNames(facts);
132
- const missing = [];
133
- for (const id of input.requirementIds) {
134
- if (!required.has(id))
135
- continue;
136
- const scopedFacts = byRequirement.get(id) ?? [];
137
- const hasChoice = scopedFacts.some((fact) => fact.kind === "component-choice" &&
138
- Array.isArray(fact.uiComponentChoices) &&
139
- fact.uiComponentChoices.length > 0);
140
- const canonicalStateFlow = collectCanonicalStateFlowNames(scopedFacts);
141
- const hasStateFlow = [...canonicalStateFlow.uiStateNames].some(name => liveStateFlow.uiStateNames.has(name)) ||
142
- [...canonicalStateFlow.interactionNames].some(name => liveStateFlow.interactionNames.has(name));
143
- if (!hasChoice) {
144
- missing.push({
145
- kind: "component-choice",
146
- requirementIds: [id],
147
- reason: "behaviour-required UX slice has no committed component-choice fact",
148
- });
149
- }
150
- if (!hasStateFlow) {
151
- missing.push({
152
- kind: "state-flow",
153
- requirementIds: [id],
154
- reason: "behaviour-required UX slice has no committed state-flow fact",
155
- });
156
- }
157
- }
158
- return missing;
159
- }
160
- const hasMockApi = facts.some((fact) => fact.kind === "mock-api");
161
- const allInteractions = collectCanonicalStateFlowNames(facts).interactionNames;
162
- const requested = new Set(input.requirementIds);
163
- const liveInteractions = new Set([...collectCanonicalStateFlowNames(facts.filter(f => !planFactStringList(f.scopeRequirementIds).length || planFactScopeIntersects(f, requested))).interactionNames].filter(name => allInteractions.has(name)));
164
- const coveredInteractions = new Set(facts
165
- .filter((fact) => fact.kind === "data-flow")
166
- .flatMap((fact) => planFactStringList(fact.interactions)));
167
- const missing = [];
168
- if (!hasMockApi) {
169
- missing.push({
170
- kind: "mock-api",
171
- requirementIds: [...input.requirementIds],
172
- reason: "global Mock/data phase has no committed mock-api fact",
173
- });
174
- }
175
- for (const interaction of liveInteractions) {
176
- if (coveredInteractions.has(interaction))
177
- continue;
178
- missing.push({
179
- kind: "data-flow",
180
- id: interaction,
181
- requirementIds: [...input.requirementIds],
182
- reason: `interaction ${interaction} has no committed data-flow fact`,
183
- });
184
- }
185
- return missing;
186
- }
@@ -1,18 +0,0 @@
1
- /** Precise failures own their recovery. A stale transport length marker must
2
- * never turn cancellation, provider rejection or policy failure into progress. */
3
- export function classifyFrontendPlanRecovery(result) {
4
- const category = result.failureCategory ?? "";
5
- if (result.timedOut || result.stopReason === "aborted" ||
6
- /interrupt|termination-unconfirmed|budget_breach/.test(category) ||
7
- ["cancelled", "auth", "missing-api-key", "rate-limit", "quota", "timeout", "tool-policy", "write-guard", "path-violation", "governance-blocked", "human-rejected"].includes(category))
8
- return "stop";
9
- if (result.ok)
10
- return "none";
11
- if (category === "output-limit")
12
- return "output";
13
- if (["context-overflow", "context-budget-exhausted"].includes(category))
14
- return "context";
15
- if (result.stopReason === "length" && ["", "empty-output", "network", "nonzero-exit", "unknown"].includes(category))
16
- return "output";
17
- return "none";
18
- }