@tea-agent/loop-agent 0.43.0-next.1 → 0.43.0-next.10

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 (199) hide show
  1. package/CHANGELOG.md +129 -9
  2. package/dist/application/dag/run-dag.js +5 -0
  3. package/dist/application/evaluation/budget.js +19 -1
  4. package/dist/application/task-lifecycle/advance.js +17 -4
  5. package/dist/application/task-lifecycle/observe.js +43 -29
  6. package/dist/application/task-lifecycle/plan-transitions.js +5 -4
  7. package/dist/build-stamp.json +3 -3
  8. package/dist/executors/dag-pi-executor.js +1214 -584
  9. package/dist/executors/pi-executor.js +22 -1
  10. package/dist/executors/pi-sdk-executor.js +140 -39
  11. package/dist/executors/shell-executor.js +5 -2
  12. package/dist/shared/frontend-execution-policy.js +23 -0
  13. package/dist/task/config-types.js +4 -0
  14. package/dist/task/source-prepare/ledger-reconciliation.js +2 -2
  15. package/dist/task/source-prepare/ledger-review.js +6 -9
  16. package/dist/task/source-prepare/semantic-intake.js +16 -26
  17. package/dist/task/source-prepare/source-fidelity-pi.js +28 -9
  18. package/dist/task/source-references.js +48 -23
  19. package/dist/worker/console/chat/assistant-content.js +23 -2
  20. package/dist/worker/console/chat/browser-policy.js +143 -0
  21. package/dist/worker/console/chat/browser-routes.js +148 -0
  22. package/dist/worker/console/chat/explore-tools.js +13 -0
  23. package/dist/worker/console/chat/pi-runtime/custom-tools/ask-user-question.js +44 -0
  24. package/dist/worker/console/chat/pi-runtime/custom-tools/explore-tools.js +202 -0
  25. package/dist/worker/console/chat/pi-runtime/custom-tools/goal-tools.js +78 -0
  26. package/dist/worker/console/chat/pi-runtime/custom-tools/operator-tools.js +86 -0
  27. package/dist/worker/console/chat/pi-runtime/custom-tools/todo-write.js +38 -0
  28. package/dist/worker/console/chat/pi-runtime/inspection-types.js +28 -0
  29. package/dist/worker/console/chat/pi-runtime/inspection.js +439 -0
  30. package/dist/worker/console/chat/pi-runtime/sdk-bindings.js +153 -0
  31. package/dist/worker/console/chat/pi-runtime/sdk-session.js +5 -0
  32. package/dist/worker/console/chat/pi-runtime.js +213 -1181
  33. package/dist/worker/console/chat/routes.js +212 -71
  34. package/dist/worker/console/chat/scm-routes.js +217 -0
  35. package/dist/worker/console/chat/scm-service.js +283 -0
  36. package/dist/worker/console/chat/scm-tools.js +111 -0
  37. package/dist/worker/console/chat/sdd-data-alignment.js +65 -9
  38. package/dist/worker/console/chat/session-catalog.js +32 -0
  39. package/dist/worker/console/chat/session-mode-view.js +48 -0
  40. package/dist/worker/console/chat/session-mode.js +218 -0
  41. package/dist/worker/console/chat/session-store.js +22 -6
  42. package/dist/worker/console/chat/shortcuts.js +6 -0
  43. package/dist/worker/console/chat/terminal-routes.js +216 -0
  44. package/dist/worker/console/chat/terminal-sessions.js +348 -0
  45. package/dist/worker/console/chat/terminal-tools.js +211 -0
  46. package/dist/worker/console/chat/tool-preview.js +11 -0
  47. package/dist/worker/console/chat/tools.js +2 -0
  48. package/dist/worker/console/server.js +2 -28
  49. package/dist/worker/console/static/assets/{abnfDiagram-N423BO3Z-B0Q0nClf.js → abnfDiagram-N423BO3Z-D_fNbWc_.js} +1 -1
  50. package/dist/worker/console/static/assets/{arc-DCPjC19G.js → arc-_HuqLW6m.js} +1 -1
  51. package/dist/worker/console/static/assets/{architectureDiagram-T3A2C74G-CP5n9jmG.js → architectureDiagram-T3A2C74G-Djy2qY1m.js} +1 -1
  52. package/dist/worker/console/static/assets/{blockDiagram-VBNYF7ZC-CmaWi_Wg.js → blockDiagram-VBNYF7ZC-bB-1TSyY.js} +1 -1
  53. package/dist/worker/console/static/assets/{c4Diagram-5PPSVZJV-Ct5tcMfZ.js → c4Diagram-5PPSVZJV-C5Hmghrz.js} +1 -1
  54. package/dist/worker/console/static/assets/channel-C0A6UEIa.js +1 -0
  55. package/dist/worker/console/static/assets/{chunk-2GRJ4B5K-C0osm1Zf.js → chunk-2GRJ4B5K-Duyl39oy.js} +1 -1
  56. package/dist/worker/console/static/assets/{chunk-2Q5K7J3B-CDWviED7.js → chunk-2Q5K7J3B-x6mdnSyf.js} +1 -1
  57. package/dist/worker/console/static/assets/{chunk-5RXB4S5H-mtSk1-j7.js → chunk-5RXB4S5H-WlBuFj7W.js} +1 -1
  58. package/dist/worker/console/static/assets/{chunk-5VM5RSS4-D5J9PHC7.js → chunk-5VM5RSS4-CTF429HX.js} +1 -1
  59. package/dist/worker/console/static/assets/{chunk-6Q2QTUOP-Begg4WAa.js → chunk-6Q2QTUOP-Dwd6r-SF.js} +1 -1
  60. package/dist/worker/console/static/assets/{chunk-GF5L2VYU-sF1AEy7T.js → chunk-GF5L2VYU-C-Br82D1.js} +1 -1
  61. package/dist/worker/console/static/assets/{chunk-JWPE2WC7-BqbsWXZb.js → chunk-JWPE2WC7-CuGp0DeE.js} +1 -1
  62. package/dist/worker/console/static/assets/{chunk-KBJHAD2P-BKJrPcJ6.js → chunk-KBJHAD2P-CJhFX6Lh.js} +1 -1
  63. package/dist/worker/console/static/assets/{chunk-RYQCIY6F-CcwNMRho.js → chunk-RYQCIY6F-DpGOa_jT.js} +1 -1
  64. package/dist/worker/console/static/assets/{chunk-XXDRQBXY-BEJi3iIs.js → chunk-XXDRQBXY-DXJaTynd.js} +1 -1
  65. package/dist/worker/console/static/assets/classDiagram-JCYQIIEL-DzguNppy.js +1 -0
  66. package/dist/worker/console/static/assets/classDiagram-v2-OCEON4UE-DzguNppy.js +1 -0
  67. package/dist/worker/console/static/assets/{cose-bilkent-JH36ORCC-DRLgTvVu.js → cose-bilkent-JH36ORCC-CRBZWjE4.js} +1 -1
  68. package/dist/worker/console/static/assets/{cynefin-VYW2F7L2-BoAVG3cs.js → cynefin-VYW2F7L2-BdXcxtlb.js} +1 -1
  69. package/dist/worker/console/static/assets/{cynefinDiagram-MW4NZA55-Bzol06hR.js → cynefinDiagram-MW4NZA55-07UKsOts.js} +1 -1
  70. package/dist/worker/console/static/assets/{dagre-VZM6K2ZE-UmliJM77.js → dagre-VZM6K2ZE-D38p9__S.js} +1 -1
  71. package/dist/worker/console/static/assets/{diagram-7IWD3JNH-BWLcJkFo.js → diagram-7IWD3JNH-nSiBNNjH.js} +1 -1
  72. package/dist/worker/console/static/assets/{diagram-B4RE2ZJO-CgApOm-O.js → diagram-B4RE2ZJO-BFOTot5D.js} +1 -1
  73. package/dist/worker/console/static/assets/{diagram-LBJQPF4R-Bh3RgTLs.js → diagram-LBJQPF4R-DypKaZ6k.js} +1 -1
  74. package/dist/worker/console/static/assets/{diagram-Q27KOJAE-Dsh-D5nE.js → diagram-Q27KOJAE-B6yoOQeW.js} +1 -1
  75. package/dist/worker/console/static/assets/{diagram-UB23O5K3-Dkbbpcpb.js → diagram-UB23O5K3-BHYS6viX.js} +1 -1
  76. package/dist/worker/console/static/assets/{ebnfDiagram-BXEA7PRR-3EBaA3t3.js → ebnfDiagram-BXEA7PRR-D2VD5Snj.js} +1 -1
  77. package/dist/worker/console/static/assets/{erDiagram-JOGREHBK-Bq2Dc5ok.js → erDiagram-JOGREHBK-E98mWxN1.js} +1 -1
  78. package/dist/worker/console/static/assets/{flowDiagram-UKHOOZJN-De7y55ha.js → flowDiagram-UKHOOZJN-CT1zxhqP.js} +1 -1
  79. package/dist/worker/console/static/assets/{ganttDiagram-PKOTCBZU-fLiDbQRh.js → ganttDiagram-PKOTCBZU-6GcngNcy.js} +1 -1
  80. package/dist/worker/console/static/assets/{gitGraphDiagram-DS77QQ5N-Du617mp1.js → gitGraphDiagram-DS77QQ5N-DCL6NvKe.js} +1 -1
  81. package/dist/worker/console/static/assets/index-24jp3aBh.js +468 -0
  82. package/dist/worker/console/static/assets/index-CY6y6I8M.css +1 -0
  83. package/dist/worker/console/static/assets/{infoDiagram-6WML65LV-BwmlF-XP.js → infoDiagram-6WML65LV-C0627e-9.js} +1 -1
  84. package/dist/worker/console/static/assets/{ishikawaDiagram-WSZJBQD7-zsGtS59u.js → ishikawaDiagram-WSZJBQD7-C_u3P6Ik.js} +1 -1
  85. package/dist/worker/console/static/assets/{journeyDiagram-NVQOT4AX-DTTPTe3f.js → journeyDiagram-NVQOT4AX-DPDPv9HL.js} +1 -1
  86. package/dist/worker/console/static/assets/{kanban-definition-27J2QSJJ-BkXg9aP-.js → kanban-definition-27J2QSJJ-D3OHdWiO.js} +1 -1
  87. package/dist/worker/console/static/assets/{linear-7U2ue5IE.js → linear-DI88zD7n.js} +1 -1
  88. package/dist/worker/console/static/assets/{mermaid.core-BUuGHmWO.js → mermaid.core-p2l8IrWY.js} +5 -5
  89. package/dist/worker/console/static/assets/{mindmap-definition-FAOFIHXS-7q6fX0Sv.js → mindmap-definition-FAOFIHXS-B1bAX-oS.js} +1 -1
  90. package/dist/worker/console/static/assets/{pegDiagram-VL7TDLO6-CkQPJN55.js → pegDiagram-VL7TDLO6-DwOnWxdD.js} +1 -1
  91. package/dist/worker/console/static/assets/{pieDiagram-7S7Q4E2Y-CCal_tfX.js → pieDiagram-7S7Q4E2Y-xRkTXnJC.js} +1 -1
  92. package/dist/worker/console/static/assets/{quadrantDiagram-CIZ2JOQS-B7bpxyAZ.js → quadrantDiagram-CIZ2JOQS-_9UC5Zio.js} +1 -1
  93. package/dist/worker/console/static/assets/{railroadDiagram-AXF67PYL-CJmww7D-.js → railroadDiagram-AXF67PYL-CgEUirWJ.js} +1 -1
  94. package/dist/worker/console/static/assets/{requirementDiagram-LRYGKXZP-D6ldWJEv.js → requirementDiagram-LRYGKXZP-Czbpwiyz.js} +1 -1
  95. package/dist/worker/console/static/assets/{sankeyDiagram-W5VNT64P-VGh33I9e.js → sankeyDiagram-W5VNT64P-_j7_KiqY.js} +1 -1
  96. package/dist/worker/console/static/assets/{sequenceDiagram-SI44F4Z6-CCkDrIjU.js → sequenceDiagram-SI44F4Z6-BNJa6Hyi.js} +1 -1
  97. package/dist/worker/console/static/assets/{sizeCapture-X5ZJPWSS-NC8f5Otb.js → sizeCapture-X5ZJPWSS-DedpKtOc.js} +1 -1
  98. package/dist/worker/console/static/assets/{stateDiagram-OKZ733FA-_92ezZdF.js → stateDiagram-OKZ733FA-BBvthr7c.js} +1 -1
  99. package/dist/worker/console/static/assets/stateDiagram-v2-UEYNNEHI-BABVQnfM.js +1 -0
  100. package/dist/worker/console/static/assets/{swimlanes-SLNWSIFB-BdUCGtbP.js → swimlanes-SLNWSIFB-Ds7umgEM.js} +2 -2
  101. package/dist/worker/console/static/assets/swimlanesDiagram-ULZ7WXOC-D0qsLaxR.js +8 -0
  102. package/dist/worker/console/static/assets/{timeline-definition-Z64GVDOM-CdD1H8ia.js → timeline-definition-Z64GVDOM-CKa-p1nF.js} +1 -1
  103. package/dist/worker/console/static/assets/{vennDiagram-T6HMQDX7-Dkdk3oFo.js → vennDiagram-T6HMQDX7-LoUNR56o.js} +1 -1
  104. package/dist/worker/console/static/assets/{wardleyDiagram-T6FBY63Y-CKu2uPPY.js → wardleyDiagram-T6FBY63Y-Bqbl6ym7.js} +1 -1
  105. package/dist/worker/console/static/assets/{xychartDiagram-ELKLHX3M-ClqAnuG8.js → xychartDiagram-ELKLHX3M-B8dUg4lf.js} +1 -1
  106. package/dist/worker/console/static/index.html +2 -2
  107. package/dist/worker/console/static-src/operator-chat/active-turn-tail.js +10 -0
  108. package/dist/worker/console/static-src/operator-chat/chat-link.js +94 -0
  109. package/dist/worker/console/static-src/operator-chat/chat-sse-events.js +122 -10
  110. package/dist/worker/console/static-src/operator-chat/compaction-message.js +7 -0
  111. package/dist/worker/console/static-src/operator-chat/pending-user-message.js +27 -15
  112. package/dist/worker/console/static-src/operator-chat/process-label.js +41 -0
  113. package/dist/worker/console/static-src/operator-chat/turn-group-equality.js +13 -0
  114. package/dist/worker/console/static-src/operator-chat/turn-process-disclosure.js +10 -0
  115. package/dist/worker/console/static-src/operator-chat/use-searchable-hidden.js +51 -0
  116. package/dist/worker/console/static-src/operator-chat/useChatSessions.js +44 -24
  117. package/dist/worker/console/static-src/operator-chat/useChatStream.js +18 -2
  118. package/dist/worker/console/static-src/operator-chat/useChatThread.js +41 -8
  119. package/dist/worker/console/static-src/operator-chat/useComposer.js +26 -11
  120. package/dist/worker/console/static-src/operator-chat/user-turn-anchor-equality.js +21 -0
  121. package/dist/worker/console/workspace-context.js +15 -1
  122. package/dist/worker/observe/node-transparency.js +81 -72
  123. package/dist/worker/observe/routes.js +20 -1
  124. package/dist/worker/observe/static/dag-inspector-humanize.js +3 -0
  125. package/dist/worker/observe/static/dom.js +20 -1
  126. package/dist/worker/observe/static/format-pool.d.ts +2 -0
  127. package/dist/worker/observe/static/format-pool.js +6 -0
  128. package/dist/worker/observe/static/format.js +7 -0
  129. package/dist/worker/observe/static/inspect-workspace.js +34 -7
  130. package/dist/worker/observe/static/inspector-submission.js +32 -0
  131. package/dist/worker/observe/static/kpi.js +1 -0
  132. package/dist/worker/observe/static/relations.js +2 -0
  133. package/dist/worker/observe/static/router.js +13 -0
  134. package/dist/worker/observe/static/run-processing.js +2 -0
  135. package/dist/worker/observe/static/shell-chrome.js +36 -3
  136. package/dist/worker/observe/static/state.js +35 -2
  137. package/dist/worker/observe/static/styles.css +263 -39
  138. package/dist/worker/observe/static/task-failure-labels.d.ts +4 -0
  139. package/dist/worker/observe/static/task-failure-labels.js +67 -0
  140. package/dist/worker/observe/static/task-history.js +12 -0
  141. package/dist/worker/observe/static/views/batch.js +6 -13
  142. package/dist/worker/observe/static/views/dag-graph.js +50 -3
  143. package/dist/worker/observe/static/views/dag-inspector.js +742 -268
  144. package/dist/worker/observe/static/views/dag-trajectory.js +3 -0
  145. package/dist/worker/observe/static/views/dag.d.ts +6 -0
  146. package/dist/worker/observe/static/views/dag.js +49 -11
  147. package/dist/worker/observe/static/views/dags.js +2 -0
  148. package/dist/worker/observe/static/views/dashboard.js +21 -12
  149. package/dist/worker/observe/static/views/failures.js +21 -11
  150. package/dist/worker/observe/static/views/feature.js +11 -29
  151. package/dist/worker/observe/static/views/pool.js +37 -28
  152. package/dist/worker/observe/static/views/run.js +48 -5
  153. package/dist/worker/observe/static/views/session-timeline.js +189 -240
  154. package/dist/worker/observe/static/views/task.js +81 -62
  155. package/dist/workflows/dag/budget-enforcement.js +53 -3
  156. package/dist/workflows/dag/frontend-capacity.js +9 -0
  157. package/dist/workflows/dag/frontend-design-policy.js +2 -1
  158. package/dist/workflows/dag/frontend-durable-tools.js +193 -0
  159. package/dist/workflows/dag/frontend-execution-groups.js +24 -0
  160. package/dist/workflows/dag/frontend-implementation-contract.js +13 -0
  161. package/dist/workflows/dag/frontend-input-projection.js +76 -0
  162. package/dist/workflows/dag/frontend-plan-completeness.js +186 -0
  163. package/dist/workflows/dag/frontend-plan-recovery-policy.js +18 -0
  164. package/dist/workflows/dag/frontend-plan-render.js +10 -3
  165. package/dist/workflows/dag/frontend-recovery-controller.js +7 -7
  166. package/dist/workflows/dag/frontend-recovery-lineage.js +13 -0
  167. package/dist/workflows/dag/frontend-recovery-run.js +4 -0
  168. package/dist/workflows/dag/frontend-review-scopes.js +139 -0
  169. package/dist/workflows/dag/frontend-session-budget.js +249 -0
  170. package/dist/workflows/dag/frontend-shadow-dual-write.js +20 -2
  171. package/dist/workflows/dag/frontend-shape-facts.js +12 -2
  172. package/dist/workflows/dag/frontend-shape.js +30 -1
  173. package/dist/workflows/dag/frontend-test-execution-evidence.js +3 -2
  174. package/dist/workflows/dag/frontend-typed-event-store.js +11 -0
  175. package/dist/workflows/dag/init-hybrid.js +16 -10
  176. package/dist/workflows/dag/node-execution.js +38 -155
  177. package/dist/workflows/dag/prompt.js +4 -0
  178. package/dist/workflows/dag/rerun-plan.js +7 -1
  179. package/dist/workflows/dag/runner.js +26 -1
  180. package/dist/workflows/dag/types.js +6 -0
  181. package/docs/operations/README.md +1 -0
  182. package/docs/templates/frontend-design-contract.md +4 -4
  183. package/docs/templates/frontend-implementation-contract.schema.json +34 -2
  184. package/docs/templates/frontend-implementation-dag.json +5 -5
  185. package/package.json +6 -3
  186. package/skills/frontend-contract/SKILL.md +2 -1
  187. package/skills/frontend-contract/references/contract-protocol.md +19 -3
  188. package/skills/frontend-design-review/SKILL.md +12 -11
  189. package/skills/frontend-plan/SKILL.md +9 -2
  190. package/skills/frontend-plan/references/decision-contract.md +18 -5
  191. package/skills/frontend-review/SKILL.md +10 -11
  192. package/skills/frontend-scout/references/scout-evidence.md +4 -0
  193. package/dist/worker/console/static/assets/channel-DAS07MdS.js +0 -1
  194. package/dist/worker/console/static/assets/classDiagram-JCYQIIEL-Cwk-5jiW.js +0 -1
  195. package/dist/worker/console/static/assets/classDiagram-v2-OCEON4UE-Cwk-5jiW.js +0 -1
  196. package/dist/worker/console/static/assets/index-C0O48S_P.js +0 -449
  197. package/dist/worker/console/static/assets/index-CzKf4U8P.css +0 -1
  198. package/dist/worker/console/static/assets/stateDiagram-v2-UEYNNEHI-DyJg5gzW.js +0 -1
  199. package/dist/worker/console/static/assets/swimlanesDiagram-ULZ7WXOC-B1cw_0Uy.js +0 -8
@@ -1,4 +1,4 @@
1
- import { randomBytes } from "node:crypto";
1
+ import { createDecipheriv, randomBytes } from "node:crypto";
2
2
  import { readFile, stat } from "node:fs/promises";
3
3
  import os from "node:os";
4
4
  import path from "node:path";
@@ -10,8 +10,49 @@ export const SDD_SKILL_NAMES = [
10
10
  /** Backward-compatible name for callers that need a stable representative value. */
11
11
  export const SDD_DEFAULT_SKILL_NAME = "SDD-implementation-test-review";
12
12
  export const SDD_TELEMETRY_URL = "https://wizard-ai.paic.com.cn/code_pilot/api/skill-usage-log";
13
- export const SDD_TELEMETRY_SIGN = "52aad0c09e6b46818a11ee702d6fe0ba";
13
+ /** SM4 key hex; also the SDD telemetry `ws-sign` value. */
14
+ export const DEFAULT_AI_MA_PUB_SALT_KEY = "52aad0c09e6b46818a11ee702d6fe0ba";
15
+ export const SDD_TELEMETRY_SIGN = DEFAULT_AI_MA_PUB_SALT_KEY;
16
+ export const AIMAX_AUTH_TOKEN_ENV = "AIMAX_AUTH_TOKEN";
14
17
  export const WIZARD_LOCAL_DEFAULT_USER_AGENT = "Builder/OpenCode ai-sdk/provider-utils/4.0.21 runtime/bun/1.3.11";
18
+ const SM4_V1_PREFIX = "sm4:v1:";
19
+ /** Decode a plaintext ticket or `sm4:v1:` ciphertext. Unknown prefixes and crypto errors fail closed. */
20
+ export function decodeAimaxAuthToken(raw, keyHex = DEFAULT_AI_MA_PUB_SALT_KEY) {
21
+ const candidate = raw.trim();
22
+ if (!candidate)
23
+ return undefined;
24
+ if (!candidate.startsWith("sm4:"))
25
+ return candidate;
26
+ if (!candidate.startsWith(SM4_V1_PREFIX))
27
+ return undefined;
28
+ const hex = candidate.slice(SM4_V1_PREFIX.length);
29
+ if (!hex || hex.length % 2 !== 0 || /[^0-9a-fA-F]/.test(hex))
30
+ return undefined;
31
+ const key = Buffer.from(keyHex.trim(), "hex");
32
+ if (key.length !== 16)
33
+ return undefined;
34
+ try {
35
+ const encrypted = Buffer.from(hex, "hex");
36
+ if (encrypted.length === 0 || encrypted.length % 16 !== 0)
37
+ return undefined;
38
+ const decipher = createDecipheriv("sm4-ecb", key, null);
39
+ decipher.setAutoPadding(true);
40
+ const plain = Buffer.concat([decipher.update(encrypted), decipher.final()])
41
+ .toString("utf8")
42
+ .trim();
43
+ return plain || undefined;
44
+ }
45
+ catch {
46
+ return undefined;
47
+ }
48
+ }
49
+ /** Set or delete `AIMAX_AUTH_TOKEN`. Empty string is treated as absent. */
50
+ export function syncAimaxAuthTokenEnv(env, token) {
51
+ if (token)
52
+ env[AIMAX_AUTH_TOKEN_ENV] = token;
53
+ else
54
+ delete env[AIMAX_AUTH_TOKEN_ENV];
55
+ }
15
56
  function sameAuthFileVersion(left, right) {
16
57
  if (!left.exists || !right.exists)
17
58
  return left.exists === right.exists;
@@ -21,9 +62,22 @@ function sameAuthFileVersion(left, right) {
21
62
  /** Reads ~/.aima-go/auth.json with metadata-based parse caching and fail-closed semantics. */
22
63
  export class AimaxAuthReader {
23
64
  authFile;
65
+ env;
24
66
  cached;
25
- constructor(authFile = path.join(os.homedir(), ".aima-go", "auth.json")) {
67
+ constructor(authFile = path.join(os.homedir(), ".aima-go", "auth.json"), env = process.env) {
26
68
  this.authFile = authFile;
69
+ this.env = env;
70
+ }
71
+ resolveKeyHex() {
72
+ const injected = typeof this.env.AI_MA_PUB_SALT_KEY === "string" ? this.env.AI_MA_PUB_SALT_KEY.trim() : "";
73
+ if (injected)
74
+ return injected;
75
+ const host = process.env.AI_MA_PUB_SALT_KEY?.trim();
76
+ return host || DEFAULT_AI_MA_PUB_SALT_KEY;
77
+ }
78
+ finish(token) {
79
+ syncAimaxAuthTokenEnv(this.env, token);
80
+ return token;
27
81
  }
28
82
  async getToken() {
29
83
  let version;
@@ -34,22 +88,24 @@ export class AimaxAuthReader {
34
88
  }
35
89
  catch {
36
90
  this.cached = { version: { exists: false } };
37
- return undefined;
91
+ return this.finish(undefined);
92
+ }
93
+ if (this.cached && sameAuthFileVersion(this.cached.version, version)) {
94
+ return this.finish(this.cached.token);
38
95
  }
39
- if (this.cached && sameAuthFileVersion(this.cached.version, version))
40
- return this.cached.token;
41
96
  let token;
42
97
  try {
43
98
  const parsed = JSON.parse(await readFile(this.authFile, "utf8"));
44
99
  const candidate = parsed["aimax-auth-token"];
45
- if (typeof candidate === "string" && candidate.trim())
46
- token = candidate;
100
+ if (typeof candidate === "string" && candidate.trim()) {
101
+ token = decodeAimaxAuthToken(candidate, this.resolveKeyHex());
102
+ }
47
103
  }
48
104
  catch {
49
105
  // Malformed or unreadable files are intentionally ineligible.
50
106
  }
51
107
  this.cached = { version, ...(token ? { token } : {}) };
52
- return token;
108
+ return this.finish(token);
53
109
  }
54
110
  async isEligible() {
55
111
  return Boolean(await this.getToken());
@@ -1,5 +1,36 @@
1
1
  import { isBlankChatSession } from "./session-store.js";
2
2
  import { projectDeferredTurnSummaries, projectDeferredTurnSummary, } from "./deferred-turn.js";
3
+ /** Sidebar / global GET /chat/sessions projection. Must include sessionMode. */
4
+ export function projectChatSessionCatalogListItem(entry, active) {
5
+ return {
6
+ sessionId: entry.sessionId,
7
+ ...(entry.workspaceId ? { workspaceId: entry.workspaceId } : {}),
8
+ state: entry.state,
9
+ createdAt: entry.createdAt,
10
+ updatedAt: entry.updatedAt,
11
+ ...(entry.title !== undefined ? { title: entry.title } : {}),
12
+ ...(entry.displayTitle !== undefined
13
+ ? { displayTitle: entry.displayTitle }
14
+ : {}),
15
+ ...(entry.modelProvider !== undefined
16
+ ? { modelProvider: entry.modelProvider }
17
+ : {}),
18
+ ...(entry.modelId !== undefined ? { modelId: entry.modelId } : {}),
19
+ ...(entry.thinkingLevel !== undefined
20
+ ? { thinkingLevel: entry.thinkingLevel }
21
+ : {}),
22
+ sessionMode: entry.sessionMode,
23
+ activeTurnId: active?.turnId,
24
+ turnPhase: active?.abortRequestedAt
25
+ ? "stopping"
26
+ : active
27
+ ? "running"
28
+ : "idle",
29
+ deferredTurn: entry.deferredTurn,
30
+ deferredTurns: entry.deferredTurns,
31
+ isBlank: entry.isBlank && !active,
32
+ };
33
+ }
3
34
  /**
4
35
  * Process-wide Session baseline, mirroring DSH's independent session.list.
5
36
  * Full records stay in their fingerprint-isolated stores; this catalog only
@@ -36,6 +67,7 @@ export class ChatSessionCatalog {
36
67
  deferredTurns: projectDeferredTurnSummaries(record.deferredTurns ?? []),
37
68
  isBlank: isBlankChatSession(record),
38
69
  ...(workspaceId ? { workspaceId } : {}),
70
+ sessionMode: record.sessionMode,
39
71
  });
40
72
  }
41
73
  remove(sessionId) {
@@ -0,0 +1,48 @@
1
+ /**
2
+ * Browser-safe session-mode types and copy.
3
+ *
4
+ * Keep this module free of Node/runtime tool policy so the Console UI
5
+ * bundle can import it without pulling operator registries.
6
+ */
7
+ export const CONSOLE_CHAT_SESSION_MODES = ["workflow", "pi"];
8
+ export const DEFAULT_CONSOLE_CHAT_SESSION_MODE = "workflow";
9
+ export const SESSION_MODE_COPY = {
10
+ workflow: {
11
+ id: "workflow",
12
+ label: "工作流",
13
+ shortLabel: "工作流",
14
+ description: "规划并推进工作流",
15
+ createLabel: "新建工作流会话",
16
+ bannerTitle: "工作流",
17
+ bannerBody: "用自然语言编排 loop-agent / agent-worker 的全部能力。这是 Operator 面:默认具备完整 Pi 工具与受策略约束的 operator action。软约束:大改与高风险变更优先走受治 DAG。",
18
+ landingTitle: "开始一段新的对话",
19
+ landingBody: "用自然语言编排 loop-agent:查询状态、诊断问题、创建与恢复任务。可先点选下方建议,或在输入框描述目标。工作流或 Pi 在输入框上方选择。",
20
+ emptyTitle: "今天想推进什么?",
21
+ emptyBody: "会话已就绪。输入框上方可切换工作区或工作流 / Pi。点选建议快速开场,或直接描述目标。业务写入仍经受治理 DAG。",
22
+ },
23
+ pi: {
24
+ id: "pi",
25
+ label: "Pi",
26
+ shortLabel: "Pi",
27
+ description: "保留压缩与 Explore,直接协作编码",
28
+ createLabel: "新建 Pi 会话",
29
+ bannerTitle: "Pi",
30
+ bannerBody: "保留 Console 压缩与 Explore,直接协作编码。不注入工作流业务指令、业务工具或 Goal 驱动。",
31
+ landingTitle: "开始一段 Pi 协作",
32
+ landingBody: "Pi 模式保留压缩、Explore、认证与 SDD 接入,取消工作流业务注入。适合有人监督的直接编码与调试。",
33
+ emptyTitle: "直接协作编码",
34
+ emptyBody: "会话已就绪。输入框上方可切换工作区或模式。使用 Pi 工具读写仓库;Explore 负责只读深挖。本会话不加载任务 / DAG 工作流工具。",
35
+ },
36
+ };
37
+ /** Slash actions that only exist in workflow sessions. Browser-safe: pure
38
+ * string constants, no runtime/tool policy imports. */
39
+ export const WORKFLOW_EXCLUSIVE_SLASH_ACTIONS = Object.freeze([
40
+ "focus-panel:task",
41
+ "focus-panel:contract",
42
+ "focus-panel:dag",
43
+ "focus:interview",
44
+ "goal",
45
+ ]);
46
+ export function isWorkflowExclusiveSlashAction(action) {
47
+ return WORKFLOW_EXCLUSIVE_SLASH_ACTIONS.includes(action);
48
+ }
@@ -0,0 +1,218 @@
1
+ /**
2
+ * Console Chat session modes (workflow | pi).
3
+ *
4
+ * sessionMode is a durable session identity, independent of per-turn
5
+ * operator | requirement-interview and of UI layout mode. Record is the
6
+ * source of truth; runtime, catalog, list/detail and the browser cache
7
+ * all project this field.
8
+ */
9
+ import { OPERATOR_CHAT_ALLOWED_TOOLS, OPERATOR_CHAT_BUILTIN_CUSTOM_TOOLS, OPERATOR_CHAT_PI_BUILTIN_TOOLS, authorizeOperatorChatTool, isOperatorChatToolDenied, } from "./tools.js";
10
+ import { OPERATOR_CHAT_AGENT_TOOL_NAME } from "./subagents/types.js";
11
+ import { CONSOLE_CHAT_SESSION_MODES, DEFAULT_CONSOLE_CHAT_SESSION_MODE, } from "./session-mode-view.js";
12
+ export { CONSOLE_CHAT_SESSION_MODES, DEFAULT_CONSOLE_CHAT_SESSION_MODE, SESSION_MODE_COPY, } from "./session-mode-view.js";
13
+ export const SESSION_MODE_INVALID_CODE = "INVALID_SESSION_MODE";
14
+ export const SESSION_MODE_UNKNOWN_CODE = "UNKNOWN_SESSION_MODE";
15
+ export const SESSION_MODE_ACTION_DENIED_CODE = "SESSION_MODE_ACTION_DENIED";
16
+ export const SESSION_MODE_IMMUTABLE_CODE = "SESSION_MODE_IMMUTABLE";
17
+ export class InvalidChatSessionModeError extends Error {
18
+ value;
19
+ code = SESSION_MODE_INVALID_CODE;
20
+ constructor(value) {
21
+ super(`sessionMode must be "workflow" or "pi"${value === undefined || value === null || value === ""
22
+ ? ""
23
+ : `; got ${String(value)}`}`);
24
+ this.value = value;
25
+ this.name = "InvalidChatSessionModeError";
26
+ }
27
+ }
28
+ export class UnknownChatSessionModeError extends Error {
29
+ value;
30
+ code = SESSION_MODE_UNKNOWN_CODE;
31
+ constructor(value) {
32
+ super(`chat session record has unknown sessionMode ${JSON.stringify(value)}; refusing to run as workflow`);
33
+ this.value = value;
34
+ this.name = "UnknownChatSessionModeError";
35
+ }
36
+ }
37
+ const MODE_SET = new Set(CONSOLE_CHAT_SESSION_MODES);
38
+ function isSessionMode(value) {
39
+ return typeof value === "string" && MODE_SET.has(value);
40
+ }
41
+ /**
42
+ * Create-path parser. Missing / null / "" → workflow. Explicit illegal
43
+ * values fail closed and must not silently degrade.
44
+ */
45
+ export function parseCreateSessionMode(value) {
46
+ if (value === undefined || value === null || value === "") {
47
+ return DEFAULT_CONSOLE_CHAT_SESSION_MODE;
48
+ }
49
+ if (isSessionMode(value))
50
+ return value;
51
+ throw new InvalidChatSessionModeError(value);
52
+ }
53
+ /**
54
+ * Restore-path parser. Missing field → workflow (stock-data rule, not a
55
+ * compatibility shim). Present but unknown → fail closed.
56
+ */
57
+ export function readStoredSessionMode(value) {
58
+ if (value === undefined || value === null || value === "") {
59
+ return DEFAULT_CONSOLE_CHAT_SESSION_MODE;
60
+ }
61
+ if (isSessionMode(value))
62
+ return value;
63
+ throw new UnknownChatSessionModeError(value);
64
+ }
65
+ export function isWorkflowSessionMode(mode) {
66
+ return mode === "workflow";
67
+ }
68
+ export function isPiSessionMode(mode) {
69
+ return mode === "pi";
70
+ }
71
+ /** Shared Console foundations that both modes keep. Not a native-only prompt. */
72
+ export const PI_CHAT_SYSTEM_PROMPT_BASE = [
73
+ "You are Console Chat in Pi mode: a coding assistant with Pi tools plus Console shared foundations.",
74
+ "Use read/write/edit/bash/grep/find/ls to inspect and change the workspace. apply_patch, full-tools, shell and coding-chat are denied.",
75
+ "Agent (Explore) is a built-in read-only subagent for path-uncertain codebase search. Do not use it for a known single-file read. Prefer safe-read/safe-grep for secret-safe probes.",
76
+ "ask_user_question pauses for a real user answer. todo_write tracks the current work and is restored after compression; it is not a workflow auto-continue signal. The persistent terminal tool is available.",
77
+ "This session keeps Console compression (L0/L1/L2, sift, strict checkpoint) and existing Aimax / SDD access. Do not create tasks, run DAGs, drive Goals, or start requirement interviews from this session.",
78
+ "Obey repository AGENTS.md, skills and extensions when they apply. Choosing Pi mode is not extra write authorization and does not bypass Console access control or output scrubbing.",
79
+ ].join("\n");
80
+ export const CHAT_SAFE_EXPLORE_TOOL_IDS = Object.freeze([
81
+ "safe-read",
82
+ "safe-grep",
83
+ "git-status",
84
+ "git-diff",
85
+ ]);
86
+ export const PI_CHAT_GENERIC_HELPER_TOOLS = Object.freeze([
87
+ "ask_user_question",
88
+ "todo_write",
89
+ ]);
90
+ export const PI_CHAT_WORKFLOW_TOOL_IDS = Object.freeze([
91
+ "get_goal",
92
+ "create_goal",
93
+ "update_goal",
94
+ ]);
95
+ const CHAT_EXTENSION_DENIED_TOOL_IDS = new Set([
96
+ "apply_patch",
97
+ "apply-patch",
98
+ "full-tools",
99
+ "full_tools",
100
+ "coding-chat",
101
+ "coding_chat",
102
+ "shell",
103
+ ].map((name) => name.toLowerCase()));
104
+ const WORKFLOW_OPERATOR_TOOL_IDS = new Set(OPERATOR_CHAT_ALLOWED_TOOLS.map((name) => name.toLowerCase()));
105
+ const PI_GOAL_TOOL_IDS = new Set(PI_CHAT_WORKFLOW_TOOL_IDS.map((name) => name.toLowerCase()));
106
+ export function workflowActiveToolBaseline() {
107
+ return [
108
+ ...OPERATOR_CHAT_ALLOWED_TOOLS,
109
+ ...OPERATOR_CHAT_PI_BUILTIN_TOOLS,
110
+ ...CHAT_SAFE_EXPLORE_TOOL_IDS,
111
+ ...OPERATOR_CHAT_BUILTIN_CUSTOM_TOOLS,
112
+ ];
113
+ }
114
+ export function piActiveToolBaseline() {
115
+ return [
116
+ ...OPERATOR_CHAT_PI_BUILTIN_TOOLS,
117
+ ...CHAT_SAFE_EXPLORE_TOOL_IDS,
118
+ ...OPERATOR_CHAT_BUILTIN_CUSTOM_TOOLS,
119
+ ...PI_CHAT_GENERIC_HELPER_TOOLS,
120
+ ];
121
+ }
122
+ export function chatActiveToolBaseline(sessionMode) {
123
+ return sessionMode === "pi"
124
+ ? piActiveToolBaseline()
125
+ : workflowActiveToolBaseline();
126
+ }
127
+ /**
128
+ * Gate 2 pin: mode baseline plus user/project extension tools. Pi mode must
129
+ * not re-add operator actions or Goal tools via the extras pass.
130
+ */
131
+ export function computeChatActiveToolNames(session, sessionMode) {
132
+ const baseline = chatActiveToolBaseline(sessionMode);
133
+ if (!session?.getAllTools)
134
+ return baseline;
135
+ const baselineLower = new Set(baseline.map((name) => name.toLowerCase()));
136
+ const extras = [];
137
+ for (const tool of session.getAllTools()) {
138
+ const name = tool?.name;
139
+ if (!name || typeof name !== "string")
140
+ continue;
141
+ const lower = name.toLowerCase();
142
+ if (baselineLower.has(lower))
143
+ continue;
144
+ if (CHAT_EXTENSION_DENIED_TOOL_IDS.has(lower))
145
+ continue;
146
+ if (sessionMode === "pi" && WORKFLOW_OPERATOR_TOOL_IDS.has(lower))
147
+ continue;
148
+ if (sessionMode === "pi" && PI_GOAL_TOOL_IDS.has(lower))
149
+ continue;
150
+ extras.push(name);
151
+ }
152
+ return extras.length > 0 ? [...baseline, ...extras] : baseline;
153
+ }
154
+ export function authorizeChatSessionTool(toolId, sessionMode) {
155
+ if (sessionMode === "workflow")
156
+ return authorizeOperatorChatTool(toolId);
157
+ const id = toolId.trim();
158
+ if (!id) {
159
+ return {
160
+ ok: false,
161
+ code: "tool-unknown",
162
+ toolId: id,
163
+ message: "empty tool id is not allowed in Pi mode",
164
+ };
165
+ }
166
+ if (isOperatorChatToolDenied(id)) {
167
+ return {
168
+ ok: false,
169
+ code: "tool-denied",
170
+ toolId: id,
171
+ message: `tool "${id}" is denied in Pi mode (no apply_patch/full-tools/shell/coding-chat)`,
172
+ };
173
+ }
174
+ const lower = id.toLowerCase();
175
+ if (WORKFLOW_OPERATOR_TOOL_IDS.has(lower) || PI_GOAL_TOOL_IDS.has(lower)) {
176
+ return {
177
+ ok: false,
178
+ code: "tool-denied",
179
+ toolId: id,
180
+ message: `tool "${id}" is a workflow action and is not available in Pi mode`,
181
+ };
182
+ }
183
+ const authorized = new Set(piActiveToolBaseline().map((name) => name.toLowerCase()));
184
+ if (authorized.has(lower))
185
+ return { ok: true, toolId: id };
186
+ return {
187
+ ok: false,
188
+ code: "tool-unknown",
189
+ toolId: id,
190
+ message: `tool "${id}" is not registered for Pi mode`,
191
+ };
192
+ }
193
+ export function composeChatSystemPromptParts(input) {
194
+ const base = input.sessionMode === "pi"
195
+ ? PI_CHAT_SYSTEM_PROMPT_BASE
196
+ : input.workflowPrompt;
197
+ const suffix = input.sessionMode === "workflow" ? input.systemPromptSuffix?.trim() : "";
198
+ return suffix ? [base, suffix] : [base];
199
+ }
200
+ export function composeChatSystemPrompt(input) {
201
+ return composeChatSystemPromptParts(input).join("\n\n");
202
+ }
203
+ export const PI_TODO_WRITE_DESCRIPTION = "Record and update a structured task list for the current work. Send the ENTIRE list every call — it REPLACES the previous list (no partial updates, no per-item edits). Before starting multi-step work, add one todo per concrete step. Keep at least one todo `in_progress` while work remains. Mark a todo `completed` immediately when it is done (do not batch completions) and resend the full list as progress advances. Skip the list for simple Q&A, read-only lookups, and single-step tasks. Statuses: `pending` / `in_progress` / `completed`.";
204
+ // Slash gating lives in the browser-safe view module (shortcuts.ts is in the
205
+ // UI bundle); re-export here for Node-side consumers.
206
+ export { WORKFLOW_EXCLUSIVE_SLASH_ACTIONS, isWorkflowExclusiveSlashAction, } from "./session-mode-view.js";
207
+ export function shouldLoadWorkflowBusinessTools(sessionMode) {
208
+ return sessionMode === "workflow";
209
+ }
210
+ export function shouldInjectGoalContinuation(sessionMode) {
211
+ return sessionMode === "workflow";
212
+ }
213
+ export function shouldAcceptOperatorSnapshot(sessionMode) {
214
+ return sessionMode === "workflow";
215
+ }
216
+ export const SESSION_MODE_ACTION_DENIED_MESSAGE = "this action is only available in workflow sessions";
217
+ /** Stable tool name used by tests and catalogs for the Explore subagent. */
218
+ export const PI_CHAT_AGENT_TOOL_NAME = OPERATOR_CHAT_AGENT_TOOL_NAME;
@@ -15,6 +15,7 @@ import { readdir, rm } from "node:fs/promises";
15
15
  import { readJsonIfExists, writeSecureJson, } from "../../../infrastructure/console/app-data.js";
16
16
  import { dispatchOperatorAction } from "../operator-actions.js";
17
17
  import { authorizeOperatorChatTool } from "./tools.js";
18
+ import { authorizeChatSessionTool, DEFAULT_CONSOLE_CHAT_SESSION_MODE, readStoredSessionMode, } from "./session-mode.js";
18
19
  import { projectOperationForChat } from "./chat-event-store.js";
19
20
  import { scrubSecrets } from "./explore-tools.js";
20
21
  import { hashDeferredTurnPayload, parseDeferredTurns, } from "./deferred-turn.js";
@@ -106,6 +107,7 @@ export class ChatSessionStore {
106
107
  ...(typeof raw.workspaceId === "string" && raw.workspaceId
107
108
  ? { workspaceId: raw.workspaceId }
108
109
  : {}),
110
+ sessionMode: readStoredSessionMode(raw.sessionMode),
109
111
  deferredTurns: normalizedDeferredTurns,
110
112
  ...(normalizedDeferredTurns[0] ? { deferredTurn: normalizedDeferredTurns[0] } : {}),
111
113
  deferredQueueRevision: Number.isSafeInteger(raw.deferredQueueRevision) && (raw.deferredQueueRevision ?? 0) >= 0
@@ -143,7 +145,17 @@ export class ChatSessionStore {
143
145
  }
144
146
  const records = await Promise.all(names
145
147
  .filter((name) => name.endsWith(".json"))
146
- .map((name) => this.get(name.slice(0, -".json".length))));
148
+ .map(async (name) => {
149
+ try {
150
+ return await this.get(name.slice(0, -".json".length));
151
+ }
152
+ catch (error) {
153
+ // Skip corrupt records (e.g. unknown sessionMode) but stay
154
+ // diagnosable: silent disappearance is untraceable otherwise.
155
+ process.stderr.write(`[console] chat session record skipped in list: ${name.slice(0, -".json".length)}: ${error instanceof Error ? error.message : String(error)}\n`);
156
+ return undefined;
157
+ }
158
+ }));
147
159
  return records
148
160
  .filter((record) => Boolean(record) && (options?.includeArchived || record.state === "active"))
149
161
  .sort((a, b) => b.updatedAt.localeCompare(a.updatedAt));
@@ -172,6 +184,7 @@ export class ChatSessionStore {
172
184
  updatedAt: now,
173
185
  modelProvider: input.modelProvider,
174
186
  modelId: input.modelId,
187
+ sessionMode: input.sessionMode ?? DEFAULT_CONSOLE_CHAT_SESSION_MODE,
175
188
  messages: [],
176
189
  toolInvocations: [],
177
190
  };
@@ -497,9 +510,10 @@ export class ChatSessionStore {
497
510
  /**
498
511
  * Dispatch a Chat tool invocation into the operator action layer.
499
512
  *
500
- * Gate 3 (per-call): authorizeOperatorChatTool is re-checked here. Even if a
501
- * malicious or drifted session somehow requested a denied tool, this gate
502
- * refuses before any operator action runs (V12 / V15).
513
+ * Gate 3 (per-call): authorizeChatSessionTool is re-checked here with the
514
+ * session mode. Even if a malicious or drifted session somehow requested a
515
+ * denied or workflow-exclusive tool, this gate refuses before any operator
516
+ * action runs (V12 / V15).
503
517
  *
504
518
  * High-risk actions (contractApply / runDag / etc.) are NOT registered as
505
519
  * tools, so they never reach here; but we still deny defensively.
@@ -514,8 +528,10 @@ function redactHumanGateToken(value) {
514
528
  delete clone.humanGateToken;
515
529
  return clone;
516
530
  }
517
- export async function dispatchChatToolCall(ctx, toolName, args, clientRequestId) {
518
- const decision = authorizeOperatorChatTool(toolName);
531
+ export async function dispatchChatToolCall(ctx, toolName, args, clientRequestId, sessionMode) {
532
+ const decision = sessionMode === undefined
533
+ ? authorizeOperatorChatTool(toolName)
534
+ : authorizeChatSessionTool(toolName, sessionMode);
519
535
  if (!decision.ok) {
520
536
  return {
521
537
  ok: false,
@@ -5,6 +5,7 @@
5
5
  * prompt / skill commands are merged via mergeSlashCommands with conflict
6
6
  * priority: operator/web > extension > skill > prompt.
7
7
  */
8
+ import { isWorkflowExclusiveSlashAction } from "./session-mode-view.js";
8
9
  export const SHORTCUTS = [
9
10
  {
10
11
  command: "/task",
@@ -138,7 +139,10 @@ export function mergeSlashCommands(dynamic = [], capabilities = {}) {
138
139
  byName.set(key, { ...item, command: key });
139
140
  }
140
141
  };
142
+ const hideWorkflow = capabilities.sessionMode === "pi";
141
143
  for (const item of SHORTCUTS) {
144
+ if (hideWorkflow && isWorkflowExclusiveSlashAction(item.action))
145
+ continue;
142
146
  upsert({
143
147
  command: item.command,
144
148
  label: item.label,
@@ -148,6 +152,8 @@ export function mergeSlashCommands(dynamic = [], capabilities = {}) {
148
152
  });
149
153
  }
150
154
  for (const item of WEB_SLASH_COMMANDS) {
155
+ if (hideWorkflow && isWorkflowExclusiveSlashAction(item.action))
156
+ continue;
151
157
  upsert({
152
158
  command: item.command,
153
159
  label: item.label,