@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,220 +0,0 @@
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
- "Sidebar browser tools (browser_navigate/search/inspect/act) drive the visible Browser panel for user-requested web research and static automation; they never edit workspace files or execute page scripts.",
78
- "Goal tools (get_goal / create_goal / update_goal) track the session's durable cross-turn objective. Create a Goal only when the user explicitly asks to start one; iterate in bounded rounds until complete or blocked.",
79
- "This session keeps Console compression (L0/L1/L2, sift, strict checkpoint) and existing Aimax / SDD access. Do not create tasks, run DAGs, or start requirement interviews from this session.",
80
- "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.",
81
- ].join("\n");
82
- export const CHAT_SAFE_EXPLORE_TOOL_IDS = Object.freeze([
83
- "safe-read",
84
- "safe-grep",
85
- "git-status",
86
- "git-diff",
87
- ]);
88
- export const PI_CHAT_GENERIC_HELPER_TOOLS = Object.freeze([
89
- "ask_user_question",
90
- "todo_write",
91
- ]);
92
- /** Durable cross-turn Goal tools. Shared by both session modes since
93
- * 2026-09-10 (exec-plan 2026-09-10-console-chat-goal-for-pi-mode); they are
94
- * NOT workflow business tools and are registered whenever a GoalRegistry
95
- * is present. */
96
- export const GOAL_TOOL_IDS = Object.freeze([
97
- "get_goal",
98
- "create_goal",
99
- "update_goal",
100
- ]);
101
- const CHAT_EXTENSION_DENIED_TOOL_IDS = new Set([
102
- "apply_patch",
103
- "apply-patch",
104
- "full-tools",
105
- "full_tools",
106
- "coding-chat",
107
- "coding_chat",
108
- "shell",
109
- ].map((name) => name.toLowerCase()));
110
- const WORKFLOW_OPERATOR_TOOL_IDS = new Set(OPERATOR_CHAT_ALLOWED_TOOLS.map((name) => name.toLowerCase()));
111
- export function workflowActiveToolBaseline() {
112
- return [
113
- ...OPERATOR_CHAT_ALLOWED_TOOLS,
114
- ...OPERATOR_CHAT_PI_BUILTIN_TOOLS,
115
- ...CHAT_SAFE_EXPLORE_TOOL_IDS,
116
- ...OPERATOR_CHAT_BUILTIN_CUSTOM_TOOLS,
117
- ];
118
- }
119
- export function piActiveToolBaseline() {
120
- return [
121
- ...OPERATOR_CHAT_PI_BUILTIN_TOOLS,
122
- ...CHAT_SAFE_EXPLORE_TOOL_IDS,
123
- ...OPERATOR_CHAT_BUILTIN_CUSTOM_TOOLS,
124
- ...PI_CHAT_GENERIC_HELPER_TOOLS,
125
- ...GOAL_TOOL_IDS,
126
- ];
127
- }
128
- export function chatActiveToolBaseline(sessionMode) {
129
- return sessionMode === "pi"
130
- ? piActiveToolBaseline()
131
- : workflowActiveToolBaseline();
132
- }
133
- /**
134
- * Gate 2 pin: mode baseline plus user/project extension tools. Pi mode must
135
- * not re-add operator actions via the extras pass (Goal tools are shared and
136
- * part of the Pi baseline since 2026-09-10).
137
- */
138
- export function computeChatActiveToolNames(session, sessionMode) {
139
- const baseline = chatActiveToolBaseline(sessionMode);
140
- if (!session?.getAllTools)
141
- return baseline;
142
- const baselineLower = new Set(baseline.map((name) => name.toLowerCase()));
143
- const extras = [];
144
- for (const tool of session.getAllTools()) {
145
- const name = tool?.name;
146
- if (!name || typeof name !== "string")
147
- continue;
148
- const lower = name.toLowerCase();
149
- if (baselineLower.has(lower))
150
- continue;
151
- if (CHAT_EXTENSION_DENIED_TOOL_IDS.has(lower))
152
- continue;
153
- if (sessionMode === "pi" && WORKFLOW_OPERATOR_TOOL_IDS.has(lower))
154
- continue;
155
- extras.push(name);
156
- }
157
- return extras.length > 0 ? [...baseline, ...extras] : baseline;
158
- }
159
- export function authorizeChatSessionTool(toolId, sessionMode) {
160
- if (sessionMode === "workflow")
161
- return authorizeOperatorChatTool(toolId);
162
- const id = toolId.trim();
163
- if (!id) {
164
- return {
165
- ok: false,
166
- code: "tool-unknown",
167
- toolId: id,
168
- message: "empty tool id is not allowed in Pi mode",
169
- };
170
- }
171
- if (isOperatorChatToolDenied(id)) {
172
- return {
173
- ok: false,
174
- code: "tool-denied",
175
- toolId: id,
176
- message: `tool "${id}" is denied in Pi mode (no apply_patch/full-tools/shell/coding-chat)`,
177
- };
178
- }
179
- const lower = id.toLowerCase();
180
- if (WORKFLOW_OPERATOR_TOOL_IDS.has(lower)) {
181
- return {
182
- ok: false,
183
- code: "tool-denied",
184
- toolId: id,
185
- message: `tool "${id}" is a workflow action and is not available in Pi mode`,
186
- };
187
- }
188
- const authorized = new Set(piActiveToolBaseline().map((name) => name.toLowerCase()));
189
- if (authorized.has(lower))
190
- return { ok: true, toolId: id };
191
- return {
192
- ok: false,
193
- code: "tool-unknown",
194
- toolId: id,
195
- message: `tool "${id}" is not registered for Pi mode`,
196
- };
197
- }
198
- export function composeChatSystemPromptParts(input) {
199
- const base = input.sessionMode === "pi"
200
- ? PI_CHAT_SYSTEM_PROMPT_BASE
201
- : input.workflowPrompt;
202
- const suffix = input.sessionMode === "workflow" ? input.systemPromptSuffix?.trim() : "";
203
- return suffix ? [base, suffix] : [base];
204
- }
205
- export function composeChatSystemPrompt(input) {
206
- return composeChatSystemPromptParts(input).join("\n\n");
207
- }
208
- 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`.";
209
- // Slash gating lives in the browser-safe view module (shortcuts.ts is in the
210
- // UI bundle); re-export here for Node-side consumers.
211
- export { WORKFLOW_EXCLUSIVE_SLASH_ACTIONS, isWorkflowExclusiveSlashAction, } from "./session-mode-view.js";
212
- export function shouldLoadWorkflowBusinessTools(sessionMode) {
213
- return sessionMode === "workflow";
214
- }
215
- export function shouldAcceptOperatorSnapshot(sessionMode) {
216
- return sessionMode === "workflow";
217
- }
218
- export const SESSION_MODE_ACTION_DENIED_MESSAGE = "this action is only available in workflow sessions";
219
- /** Stable tool name used by tests and catalogs for the Explore subagent. */
220
- export const PI_CHAT_AGENT_TOOL_NAME = OPERATOR_CHAT_AGENT_TOOL_NAME;
@@ -1,216 +0,0 @@
1
- /**
2
- * Operator Chat — terminal management HTTP API (Console UI side).
3
- *
4
- * Endpoints (all under /api/operator/v1/chat):
5
- * GET /terminals list terminal sessions (all owners)
6
- * POST /terminals spawn { shell, name?, cwd?, ownerSessionId? }
7
- * GET /terminals/:id session info + buffered output
8
- * POST /terminals/:id/input { data } write to the PTY
9
- * POST /terminals/:id/resize { cols, rows }
10
- * POST /terminals/:id/interrupt send Ctrl+C
11
- * POST /terminals/:id/kill stop and await full exit
12
- * GET /terminals/:id/stream SSE: buffered replay + live chunks
13
- *
14
- * Mutating routes require the Console boot token (same gate as other chat
15
- * mutations). The stream is read-only and uses the same origin checks as the
16
- * chat event stream.
17
- */
18
- import { TerminalSessionError, availableShellKinds, } from "./terminal-sessions.js";
19
- function sendJson(res, status, body) {
20
- const payload = JSON.stringify(body);
21
- res.writeHead(status, {
22
- "content-type": "application/json; charset=utf-8",
23
- "cache-control": "no-store",
24
- });
25
- res.end(payload);
26
- }
27
- function mapTerminalError(res, error) {
28
- if (error instanceof TerminalSessionError) {
29
- const status = error.code === "TERMINAL_NOT_FOUND"
30
- ? 404
31
- : error.code === "TERMINAL_EXITED" || error.code === "TERMINAL_SEND_ACTIVE"
32
- ? 409
33
- : 500;
34
- sendJson(res, status, {
35
- ok: false,
36
- error: { code: error.code, message: error.message },
37
- });
38
- return;
39
- }
40
- sendJson(res, 500, {
41
- ok: false,
42
- error: {
43
- code: "TERMINAL_INTERNAL",
44
- message: error instanceof Error ? error.message : String(error),
45
- },
46
- });
47
- }
48
- async function readJsonBody(req, maxBytes = 512 * 1024) {
49
- const chunks = [];
50
- let total = 0;
51
- for await (const chunk of req) {
52
- const buf = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
53
- total += buf.length;
54
- if (total > maxBytes)
55
- throw new Error("request body too large");
56
- chunks.push(buf);
57
- }
58
- if (chunks.length === 0)
59
- return {};
60
- const raw = Buffer.concat(chunks).toString("utf8");
61
- if (!raw.trim())
62
- return {};
63
- return JSON.parse(raw);
64
- }
65
- /** Route dispatcher; returns true when the request was handled. */
66
- export async function handleTerminalRequest(req, res, deps, pathname) {
67
- if (!pathname.startsWith("/api/operator/v1/chat/terminals"))
68
- return false;
69
- const method = (req.method ?? "GET").toUpperCase();
70
- const rest = pathname.slice("/api/operator/v1/chat/terminals".length);
71
- const parts = rest.split("/").filter(Boolean);
72
- try {
73
- // GET /terminals — list (+ available shell kinds for this platform)
74
- if (method === "GET" && parts.length === 0) {
75
- sendJson(res, 200, {
76
- ok: true,
77
- data: {
78
- terminals: deps.terminals.list(),
79
- availableShells: availableShellKinds().kinds,
80
- },
81
- });
82
- return true;
83
- }
84
- // POST /terminals — spawn
85
- if (method === "POST" && parts.length === 0) {
86
- const gate = deps.gateMutation(req);
87
- if (!gate.ok) {
88
- sendJson(res, gate.status, { ok: false, error: { code: gate.code, message: gate.message } });
89
- return true;
90
- }
91
- const body = await readJsonBody(req);
92
- const kinds = availableShellKinds().kinds;
93
- const shell = kinds.includes(body.shell)
94
- ? body.shell
95
- : undefined;
96
- if (!shell) {
97
- sendJson(res, 400, {
98
- ok: false,
99
- error: {
100
- code: "INVALID_INPUT",
101
- message: `shell must be one of: ${kinds.join(", ")} (available on this platform)`,
102
- },
103
- });
104
- return true;
105
- }
106
- const info = deps.terminals.spawn({
107
- ownerSessionId: typeof body.ownerSessionId === "string" && body.ownerSessionId
108
- ? body.ownerSessionId
109
- : "console-ui",
110
- name: typeof body.name === "string" && body.name ? body.name : `${shell}-ui`,
111
- shell: shell,
112
- cwd: typeof body.cwd === "string" && body.cwd
113
- ? body.cwd
114
- : (deps.defaultCwd ?? undefined),
115
- cols: typeof body.cols === "number" ? body.cols : undefined,
116
- rows: typeof body.rows === "number" ? body.rows : undefined,
117
- });
118
- sendJson(res, 201, { ok: true, data: info });
119
- return true;
120
- }
121
- const sessionId = parts[0];
122
- if (!sessionId)
123
- return false;
124
- const sub = parts[1] ?? "";
125
- // GET /terminals/:id — info + buffered output
126
- if (method === "GET" && parts.length === 1) {
127
- const info = deps.terminals.get(sessionId);
128
- const output = deps.terminals.readAll(sessionId);
129
- sendJson(res, 200, { ok: true, data: { ...info, output } });
130
- return true;
131
- }
132
- // GET /terminals/:id/stream — SSE
133
- if (method === "GET" && sub === "stream") {
134
- // Validate existence first (404 before opening the stream).
135
- const info = deps.terminals.get(sessionId);
136
- void info;
137
- res.writeHead(200, {
138
- "content-type": "text/event-stream; charset=utf-8",
139
- "cache-control": "no-cache, no-store",
140
- connection: "keep-alive",
141
- "x-accel-buffering": "no",
142
- });
143
- const writeFrame = (event, data) => {
144
- if (res.writableEnded)
145
- return;
146
- res.write(`event: ${event}\ndata: ${JSON.stringify(data)}\n\n`);
147
- };
148
- const buffered = deps.terminals.readAll(sessionId);
149
- writeFrame("snapshot", {
150
- truncated: buffered.truncated,
151
- totalOutputChars: buffered.totalOutputChars,
152
- text: buffered.text,
153
- info: deps.terminals.get(sessionId),
154
- });
155
- const unsubscribe = deps.terminals.subscribe(sessionId, (chunk) => {
156
- writeFrame("data", { chunk });
157
- });
158
- const heartbeat = setInterval(() => {
159
- if (!res.writableEnded)
160
- res.write(": heartbeat\n\n");
161
- }, 15_000);
162
- res.once("close", () => {
163
- clearInterval(heartbeat);
164
- unsubscribe();
165
- });
166
- return true;
167
- }
168
- // Everything else mutates → gate first.
169
- const gate = deps.gateMutation(req);
170
- if (!gate.ok) {
171
- sendJson(res, gate.status, { ok: false, error: { code: gate.code, message: gate.message } });
172
- return true;
173
- }
174
- if (method === "POST" && sub === "input" && parts.length === 2) {
175
- const body = await readJsonBody(req);
176
- if (typeof body.data !== "string") {
177
- sendJson(res, 400, { ok: false, error: { code: "INVALID_INPUT", message: "data (string) is required" } });
178
- return true;
179
- }
180
- deps.terminals.send(sessionId, body.data);
181
- sendJson(res, 200, { ok: true });
182
- return true;
183
- }
184
- if (method === "POST" && sub === "resize" && parts.length === 2) {
185
- const body = await readJsonBody(req);
186
- const cols = Number(body.cols);
187
- const rows = Number(body.rows);
188
- if (!Number.isInteger(cols) || !Number.isInteger(rows) || cols < 2 || rows < 2 || cols > 500 || rows > 200) {
189
- sendJson(res, 400, { ok: false, error: { code: "INVALID_INPUT", message: "cols and rows (integers 2..500/200) are required" } });
190
- return true;
191
- }
192
- deps.terminals.resize(sessionId, cols, rows);
193
- sendJson(res, 200, { ok: true });
194
- return true;
195
- }
196
- if (method === "POST" && sub === "interrupt" && parts.length === 2) {
197
- deps.terminals.interrupt(sessionId);
198
- sendJson(res, 200, { ok: true });
199
- return true;
200
- }
201
- if (method === "POST" && sub === "kill" && parts.length === 2) {
202
- await deps.terminals.kill(sessionId);
203
- sendJson(res, 200, { ok: true });
204
- return true;
205
- }
206
- sendJson(res, 404, { ok: false, error: { code: "NOT_FOUND", message: `unknown terminal route: ${method} ${pathname}` } });
207
- return true;
208
- }
209
- catch (error) {
210
- if (!res.headersSent)
211
- mapTerminalError(res, error);
212
- else
213
- res.end();
214
- return true;
215
- }
216
- }