@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,162 +0,0 @@
1
- /**
2
- * HTTP routes for the Operator Chat browser panel: one read-only probe
3
- * endpoint the panel uses to explain an iframe refusal (X-Frame-Options /
4
- * CSP frame-ancestors are exactly the signals the browser enforces when it
5
- * refuses to embed a site). The probe is display-only (headers back to the
6
- * caller), restricted to http(s) URLs, with a hard timeout. Local addresses
7
- * are allowed — the panel routinely browses local dev servers.
8
- */
9
- import { embeddabilityOf, extractFrameAncestors, normalizeBrowserUrl, } from "./browser-policy.js";
10
- function workspaceIdOf(req) {
11
- try {
12
- return new URL(req.url ?? "/", "http://localhost").searchParams.get("workspaceId") ?? undefined;
13
- }
14
- catch {
15
- return undefined;
16
- }
17
- }
18
- function sendJson(res, status, body) {
19
- res.writeHead(status, {
20
- "content-type": "application/json; charset=utf-8",
21
- "cache-control": "no-store",
22
- });
23
- res.end(JSON.stringify(body));
24
- }
25
- /** Route dispatcher; returns true when the request was handled. */
26
- export async function handleBrowserRequest(req, res, deps, pathname) {
27
- if (!pathname.startsWith("/api/operator/v1/chat/browser"))
28
- return false;
29
- const method = (req.method ?? "GET").toUpperCase();
30
- const rest = pathname.slice("/api/operator/v1/chat/browser".length);
31
- const parts = rest.split("/").filter(Boolean);
32
- const sub = parts[0] ?? "";
33
- try {
34
- if (method === "GET" && sub === "probe" && parts.length === 1) {
35
- // Fail-closed: the probe needs a workspaceId like every chat API.
36
- if (deps.requireWorkspace) {
37
- const ws = deps.requireWorkspace(req);
38
- if (!ws.ok) {
39
- sendJson(res, 400, {
40
- ok: false,
41
- error: { code: "WORKSPACE_REQUIRED", message: "workspaceId is required" },
42
- });
43
- return true;
44
- }
45
- }
46
- else if (!workspaceIdOf(req)) {
47
- sendJson(res, 400, {
48
- ok: false,
49
- error: { code: "WORKSPACE_REQUIRED", message: "workspaceId is required" },
50
- });
51
- return true;
52
- }
53
- const url = new URL(req.url ?? "/", "http://localhost");
54
- const raw = url.searchParams.get("url") ?? "";
55
- const normalized = normalizeBrowserUrl(raw);
56
- if (normalized.kind !== "ok") {
57
- sendJson(res, 400, {
58
- ok: false,
59
- error: {
60
- code: normalized.kind === "blocked" ? "BAD_SCHEME" : "INVALID_URL",
61
- message: normalized.kind === "blocked"
62
- ? "only http/https urls can be probed"
63
- : "invalid url",
64
- },
65
- });
66
- return true;
67
- }
68
- const parsed = new URL(normalized.url);
69
- const controller = new AbortController();
70
- const timer = setTimeout(() => controller.abort(), 8000);
71
- try {
72
- let response = await fetch(parsed, {
73
- method: "HEAD",
74
- redirect: "follow",
75
- signal: controller.signal,
76
- });
77
- // Some servers answer HEAD with 405/501; retry once as GET
78
- // (the body is discarded — only the headers matter).
79
- if (response.status === 405 || response.status === 501) {
80
- response = await fetch(parsed, {
81
- method: "GET",
82
- redirect: "follow",
83
- signal: controller.signal,
84
- });
85
- }
86
- const csp = response.headers.get("content-security-policy");
87
- const frameAncestors = extractFrameAncestors(csp);
88
- const xFrameOptions = response.headers.get("x-frame-options");
89
- const probe = {
90
- reachable: true,
91
- url: response.url,
92
- status: response.status,
93
- ...(xFrameOptions !== null ? { xFrameOptions } : {}),
94
- ...(frameAncestors !== undefined ? { frameAncestors } : {}),
95
- };
96
- sendJson(res, 200, {
97
- ok: true,
98
- data: { probe, verdict: embeddabilityOf(probe) },
99
- });
100
- return true;
101
- }
102
- catch {
103
- // DNS / TLS / connection / timeout: nothing to judge — the
104
- // client keeps the plain iframe.
105
- sendJson(res, 200, {
106
- ok: true,
107
- data: { probe: { reachable: false }, verdict: "unknown" },
108
- });
109
- return true;
110
- }
111
- finally {
112
- clearTimeout(timer);
113
- }
114
- }
115
- if (method === "GET" && sub === "commands" && parts.length === 1) {
116
- const ws = workspaceIdOf(req);
117
- if (!ws) {
118
- sendJson(res, 400, {
119
- ok: false,
120
- error: { code: "WORKSPACE_REQUIRED", message: "workspaceId is required" },
121
- });
122
- return true;
123
- }
124
- if (deps.requireWorkspace) {
125
- const scope = deps.requireWorkspace(req);
126
- if (!scope.ok) {
127
- sendJson(res, 403, {
128
- ok: false,
129
- error: { code: "WORKSPACE_DENIED", message: "workspace scope mismatch" },
130
- });
131
- return true;
132
- }
133
- }
134
- if (!deps.automation) {
135
- sendJson(res, 200, { ok: true, data: { commands: [] } });
136
- return true;
137
- }
138
- sendJson(res, 200, { ok: true, data: { commands: deps.automation.take() } });
139
- return true;
140
- }
141
- sendJson(res, 404, {
142
- ok: false,
143
- error: { code: "NOT_FOUND", message: `unknown browser route: ${method} ${pathname}` },
144
- });
145
- return true;
146
- }
147
- catch (error) {
148
- if (!res.headersSent) {
149
- sendJson(res, 500, {
150
- ok: false,
151
- error: {
152
- code: "BROWSER_INTERNAL",
153
- message: error instanceof Error ? error.message : String(error),
154
- },
155
- });
156
- }
157
- else {
158
- res.end();
159
- }
160
- return true;
161
- }
162
- }
@@ -1,44 +0,0 @@
1
- /**
2
- * Session-bound ask_user_question custom tool.
3
- * ConsolePiRuntime supplies the sessionId and UserQuestionRegistry.
4
- */
5
- const ASK_USER_QUESTION_DESCRIPTION = "Ask the user concise questions when a confirmation, choice, or missing detail is required before proceeding. " +
6
- "The tool pauses until the user answers. Use it instead of writing questions as ordinary assistant text. " +
7
- "Send one or more questions with stable ids; recommended options should be first and end with (Recommended).";
8
- export async function buildAskUserQuestionTool(options) {
9
- const [{ Type }, { defineTool }] = await Promise.all([
10
- import("typebox"),
11
- import("@earendil-works/pi-coding-agent"),
12
- ]);
13
- return defineTool({
14
- name: "ask_user_question",
15
- label: "Ask user",
16
- description: ASK_USER_QUESTION_DESCRIPTION,
17
- promptSnippet: ASK_USER_QUESTION_DESCRIPTION,
18
- parameters: Type.Object({
19
- questions: Type.Array(Type.Object({
20
- id: Type.String({ description: "Stable question id echoed in the answer." }),
21
- question: Type.String({ description: "Specific user-facing question." }),
22
- header: Type.Optional(Type.String({ description: "Optional short heading." })),
23
- detail: Type.Optional(Type.String({ description: "Optional Markdown context shown below the question." })),
24
- options: Type.Optional(Type.Array(Type.Object({
25
- label: Type.String({ description: "Short user-facing option label." }),
26
- description: Type.Optional(Type.String({ description: "One sentence explaining impact or tradeoff." })),
27
- }, { additionalProperties: false }))),
28
- multi_select: Type.Optional(Type.Boolean({ description: "Allow more than one option." })),
29
- }, { additionalProperties: false }), { minItems: 1, maxItems: 20 }),
30
- }, { additionalProperties: false }),
31
- async execute(toolCallId, params, signal) {
32
- const answer = await options.registry.ask({
33
- sessionId: options.sessionId,
34
- toolCallId,
35
- questions: params.questions,
36
- signal,
37
- });
38
- return {
39
- content: [{ type: "text", text: JSON.stringify(answer) }],
40
- details: answer,
41
- };
42
- },
43
- });
44
- }
@@ -1,89 +0,0 @@
1
- /**
2
- * Session-independent browser tools shared by workflow and Pi chat modes.
3
- * Navigation is visible in the Console sidebar; inspection is server-side and
4
- * bounded to avoid exposing raw credentials or arbitrary page scripts.
5
- */
6
- const BROWSER_TOOLS_DESCRIPTION = "Operate the Console sidebar browser. `browser_navigate` shows a URL in the panel; `browser_search` opens a search URL and returns elements; `browser_inspect` returns title/links/form controls; `browser_act` fills/submits a static GET form or clicks a static link. For natural-language search requests, prefer `browser_search` over navigating to a homepage and simulating its form. It never edits the workspace and cannot execute browser scripts. Dynamic-page and POST-form operations are out of scope.";
7
- export async function buildBrowserTools(options) {
8
- const [{ Type }, { defineTool }] = await Promise.all([
9
- import("typebox"),
10
- import("@earendil-works/pi-coding-agent"),
11
- ]);
12
- const automation = options.automation;
13
- const urlParameter = Type.String({
14
- description: "Absolute http(s) URL. Prefer URLs/element selectors returned by prior browser tools.",
15
- });
16
- async function execute(operation) {
17
- try {
18
- const result = await operation();
19
- return {
20
- content: [{ type: "text", text: JSON.stringify(result) }],
21
- details: result,
22
- };
23
- }
24
- catch (error) {
25
- const payload = {
26
- error: error instanceof Error ? error.message : String(error),
27
- code: error instanceof Error && "code" in error
28
- ? String(error.code)
29
- : "BROWSER_OPERATION_FAILED",
30
- };
31
- return {
32
- content: [{ type: "text", text: JSON.stringify(payload) }],
33
- details: payload,
34
- };
35
- }
36
- }
37
- return [
38
- defineTool({
39
- name: "browser_navigate",
40
- label: "Sidebar browser navigate",
41
- description: BROWSER_TOOLS_DESCRIPTION,
42
- promptSnippet: BROWSER_TOOLS_DESCRIPTION,
43
- parameters: Type.Object({ url: urlParameter }, { additionalProperties: false }),
44
- async execute(_toolCallId, params) {
45
- return execute(() => automation.navigate(params.url, { includeSnapshot: true }));
46
- },
47
- }),
48
- defineTool({
49
- name: "browser_search",
50
- label: "Sidebar browser search",
51
- description: BROWSER_TOOLS_DESCRIPTION,
52
- promptSnippet: BROWSER_TOOLS_DESCRIPTION,
53
- parameters: Type.Object({
54
- query: Type.String({ description: "Search query." }),
55
- engineUrl: Type.Optional(urlParameter),
56
- }, { additionalProperties: false }),
57
- async execute(_toolCallId, params) {
58
- return execute(() => automation.search(params.query, params.engineUrl));
59
- },
60
- }),
61
- defineTool({
62
- name: "browser_inspect",
63
- label: "Sidebar browser inspect",
64
- description: BROWSER_TOOLS_DESCRIPTION,
65
- promptSnippet: BROWSER_TOOLS_DESCRIPTION,
66
- parameters: Type.Object({ url: urlParameter }, { additionalProperties: false }),
67
- async execute(_toolCallId, params) {
68
- return execute(() => automation.inspect(params.url));
69
- },
70
- }),
71
- defineTool({
72
- name: "browser_act",
73
- label: "Sidebar browser act",
74
- description: BROWSER_TOOLS_DESCRIPTION,
75
- promptSnippet: BROWSER_TOOLS_DESCRIPTION,
76
- parameters: Type.Object({
77
- url: urlParameter,
78
- type: Type.Union([Type.Literal("click"), Type.Literal("fill")]),
79
- selector: Type.String({ description: "Selector returned by browser_inspect." }),
80
- value: Type.Optional(Type.String()),
81
- }, { additionalProperties: false }),
82
- async execute(_toolCallId, params) {
83
- return execute(() => automation.act(params.url, params.type === "click"
84
- ? { type: "click", selector: params.selector }
85
- : { type: "fill", selector: params.selector, value: params.value ?? "" }));
86
- },
87
- }),
88
- ];
89
- }
@@ -1,202 +0,0 @@
1
- /**
2
- * Session-less safe explore custom tools (safe-read / safe-grep / git-status /
3
- * git-diff). Execution uses explore-tools.ts path guards and secret scrubbing.
4
- * ConsolePiRuntime owns the sessionless cache.
5
- */
6
- /**
7
- * Build the safe explore custom tools (roadmap M0-A / G16): safe-read,
8
- * safe-grep, gitStatus, gitDiff. These replace the bare SDK bash/read/grep so
9
- * the model can probe the repo WITHOUT write escapes (echo redirect, tee,
10
- * sed -i, node -e) and WITHOUT reading sensitive files (env files, key/pem,
11
- * auth.json, sessions dir) — and every returned byte is secret-scrubbed
12
- * before reaching the model context.
13
- *
14
- * gitStatus/gitDiff use a FIXED argv (typed, no shell) so they cannot be
15
- * turned into an arbitrary-shell vector.
16
- */
17
- export async function buildExploreCustomTools(options) {
18
- const [{ Type }, { defineTool }] = await Promise.all([
19
- import("typebox"),
20
- import("@earendil-works/pi-coding-agent"),
21
- ]);
22
- const { execFileSync } = await import("node:child_process");
23
- const repoRoot = options.repoRoot;
24
- const { safeReadFile, safeGrep, scrubSecrets } = await import("../../explore-tools.js");
25
- function safeGit(args) {
26
- try {
27
- const stdout = execFileSync("git", args, {
28
- cwd: repoRoot,
29
- encoding: "utf8",
30
- // Fixed argv, no shell, bounded output.
31
- maxBuffer: 512 * 1024,
32
- timeout: 10_000,
33
- windowsHide: true,
34
- });
35
- return { ok: true, stdout };
36
- }
37
- catch (e) {
38
- return {
39
- ok: false,
40
- code: "GIT_FAILED",
41
- message: e instanceof Error ? e.message : String(e),
42
- };
43
- }
44
- }
45
- const safeReadTool = defineTool({
46
- name: "safe-read",
47
- label: "safe-read",
48
- description: "Read a repo-relative file with sensitive-file denylist (.env*/*.key/*.pem/.git/**/auth.json/sessions/**) and secret scrubbing. Absolute paths and .. are rejected.",
49
- promptSnippet: "safe-read: read a repo file (safe; secrets scrubbed)",
50
- parameters: Type.Object({
51
- path: Type.String({ description: "repo-relative file path" }),
52
- }, { additionalProperties: false }),
53
- async execute(_toolCallId, params) {
54
- const raw = String(params.path ?? "");
55
- try {
56
- const result = await safeReadFile(repoRoot, raw);
57
- return {
58
- content: [{ type: "text", text: JSON.stringify(result) }],
59
- details: result,
60
- };
61
- }
62
- catch (e) {
63
- const err = e;
64
- return {
65
- content: [
66
- {
67
- type: "text",
68
- text: JSON.stringify({
69
- error: err.message ?? String(e),
70
- code: err.code ?? "READ_FAILED",
71
- }),
72
- },
73
- ],
74
- details: {
75
- error: err.message ?? String(e),
76
- code: err.code ?? "READ_FAILED",
77
- },
78
- };
79
- }
80
- },
81
- });
82
- const safeGrepTool = defineTool({
83
- name: "safe-grep",
84
- label: "safe-grep",
85
- description: "Line search across the repo working tree with sensitive-file denylist and secret scrubbing. pattern is a JS regex source; optional glob filters paths.",
86
- promptSnippet: "safe-grep: search repo files (safe; secrets scrubbed)",
87
- parameters: Type.Object({
88
- pattern: Type.String({ description: "regex source (no shell)" }),
89
- caseInsensitive: Type.Optional(Type.Boolean()),
90
- glob: Type.Optional(Type.String({ description: "optional glob filter e.g. *.ts" })),
91
- }, { additionalProperties: false }),
92
- async execute(_toolCallId, params) {
93
- try {
94
- const result = await safeGrep(repoRoot, String(params.pattern ?? ""), {
95
- caseInsensitive: Boolean(params.caseInsensitive),
96
- glob: params.glob ? String(params.glob) : undefined,
97
- });
98
- return {
99
- content: [{ type: "text", text: JSON.stringify(result) }],
100
- details: result,
101
- };
102
- }
103
- catch (e) {
104
- const err = e;
105
- return {
106
- content: [
107
- {
108
- type: "text",
109
- text: JSON.stringify({
110
- error: err.message ?? String(e),
111
- code: err.code ?? "GREP_FAILED",
112
- }),
113
- },
114
- ],
115
- details: {
116
- error: err.message ?? String(e),
117
- code: err.code ?? "GREP_FAILED",
118
- },
119
- };
120
- }
121
- },
122
- });
123
- const gitStatusTool = defineTool({
124
- name: "git-status",
125
- label: "git-status",
126
- description: "Typed `git status --porcelain` (fixed argv, no shell). Returns scrubbed working-tree status.",
127
- promptSnippet: "git-status: working tree status (read-only)",
128
- parameters: Type.Object({}, { additionalProperties: false }),
129
- async execute() {
130
- const r = safeGit(["status", "--porcelain"]);
131
- if (!r.ok) {
132
- return {
133
- content: [
134
- {
135
- type: "text",
136
- text: JSON.stringify({ error: r.message, code: r.code }),
137
- },
138
- ],
139
- details: { error: r.message, code: r.code },
140
- };
141
- }
142
- const { scrubbed, redactions } = scrubSecrets(r.stdout);
143
- const payload = { status: scrubbed, redactions };
144
- return {
145
- content: [{ type: "text", text: JSON.stringify(payload) }],
146
- details: payload,
147
- };
148
- },
149
- });
150
- const gitDiffTool = defineTool({
151
- name: "git-diff",
152
- label: "git-diff",
153
- description: "Typed `git diff` (fixed argv: --stat or a single -- path; no shell). Returns scrubbed diff. path must be repo-relative and not sensitive.",
154
- promptSnippet: "git-diff: diff (read-only, scrubbed)",
155
- parameters: Type.Object({
156
- path: Type.Optional(Type.String({
157
- description: "optional repo-relative path to diff (default: whole tree --stat)",
158
- })),
159
- }, { additionalProperties: false }),
160
- async execute(_toolCallId, params) {
161
- let rawPath = params.path ? String(params.path) : undefined;
162
- // If a path is supplied, validate it via the read-path guard so git diff
163
- // cannot be aimed at sensitive files (.env* / auth.json / sessions).
164
- if (rawPath) {
165
- const { guardReadPath } = await import("../../explore-tools.js");
166
- const g = await guardReadPath(repoRoot, rawPath);
167
- if (!g.ok) {
168
- return {
169
- content: [
170
- {
171
- type: "text",
172
- text: JSON.stringify({ error: g.message, code: g.code }),
173
- },
174
- ],
175
- details: { error: g.message, code: g.code },
176
- };
177
- }
178
- rawPath = g.repoRelative;
179
- }
180
- const args = rawPath ? ["diff", "--", rawPath] : ["diff", "--stat"];
181
- const r = safeGit(args);
182
- if (!r.ok) {
183
- return {
184
- content: [
185
- {
186
- type: "text",
187
- text: JSON.stringify({ error: r.message, code: r.code }),
188
- },
189
- ],
190
- details: { error: r.message, code: r.code },
191
- };
192
- }
193
- const { scrubbed, redactions } = scrubSecrets(r.stdout);
194
- const payload = { diff: scrubbed, redactions };
195
- return {
196
- content: [{ type: "text", text: JSON.stringify(payload) }],
197
- details: payload,
198
- };
199
- },
200
- });
201
- return [safeReadTool, safeGrepTool, gitStatusTool, gitDiffTool];
202
- }
@@ -1,79 +0,0 @@
1
- /**
2
- * Session-bound Goal tools (shared by workflow and Pi modes since
3
- * 2026-09-10; see exec-plan 2026-09-10-console-chat-goal-for-pi-mode).
4
- * create_goal still requires a consumed model-create grant from the registry.
5
- */
6
- const GET_GOAL_DESCRIPTION = "Read the current session's durable cross-turn Goal, including revision, status, round limit, and whether this Console process is authorized to continue it.";
7
- const CREATE_GOAL_DESCRIPTION = "Create a durable cross-turn Goal only when the user explicitly asks to start or create a Goal. Never silently upgrade an ordinary request. A session may have only one unfinished Goal.";
8
- const UPDATE_GOAL_DESCRIPTION = "Finish or block the current durable Goal using its exact goalId and revision. Set complete only when the objective is genuinely achieved and no required work remains. Set blocked only when safe progress cannot continue; include the blocker.";
9
- export async function buildGoalTools(options) {
10
- const [{ Type }, { defineTool }] = await Promise.all([
11
- import("typebox"),
12
- import("@earendil-works/pi-coding-agent"),
13
- ]);
14
- const textResult = (value) => ({
15
- content: [{ type: "text", text: JSON.stringify(value) }],
16
- details: value,
17
- });
18
- return [
19
- defineTool({
20
- name: "get_goal",
21
- label: "Get goal",
22
- description: GET_GOAL_DESCRIPTION,
23
- promptSnippet: GET_GOAL_DESCRIPTION,
24
- parameters: Type.Object({}, { additionalProperties: false }),
25
- async execute() {
26
- return textResult({ goal: options.registry.get(options.sessionId) });
27
- },
28
- }),
29
- defineTool({
30
- name: "create_goal",
31
- label: "Create goal",
32
- description: CREATE_GOAL_DESCRIPTION,
33
- promptSnippet: CREATE_GOAL_DESCRIPTION,
34
- parameters: Type.Object({
35
- objective: Type.String({
36
- description: "Concrete final objective and completion standard explicitly requested by the user.",
37
- }),
38
- }, { additionalProperties: false }),
39
- async execute(_toolCallId, params) {
40
- if (!options.registry.consumeModelCreateGrant(options.sessionId)) {
41
- return textResult({
42
- ok: false,
43
- code: "GOAL_EXPLICIT_REQUEST_REQUIRED",
44
- message: "create_goal requires an explicit user request to create or start a Goal",
45
- });
46
- }
47
- return textResult(options.registry.create({
48
- sessionId: options.sessionId,
49
- objective: params.objective,
50
- }));
51
- },
52
- }),
53
- defineTool({
54
- name: "update_goal",
55
- label: "Update goal",
56
- description: UPDATE_GOAL_DESCRIPTION,
57
- promptSnippet: UPDATE_GOAL_DESCRIPTION,
58
- parameters: Type.Object({
59
- goalId: Type.String(),
60
- revision: Type.Number({ minimum: 1 }),
61
- status: Type.Union([
62
- Type.Literal("complete"),
63
- Type.Literal("blocked"),
64
- ]),
65
- blocker: Type.Optional(Type.String()),
66
- }, { additionalProperties: false }),
67
- async execute(_toolCallId, params) {
68
- return textResult(options.registry.update({
69
- sessionId: options.sessionId,
70
- goalId: params.goalId,
71
- expectedRevision: params.revision,
72
- phase: params.status,
73
- blocker: params.blocker,
74
- arm: false,
75
- }));
76
- },
77
- }),
78
- ];
79
- }
@@ -1,86 +0,0 @@
1
- /**
2
- * Session-less operator-action custom tools (workflow-mode business tools).
3
- * Definitions and execute() live here; ConsolePiRuntime owns caching and
4
- * composition with session-bound tools.
5
- */
6
- import { authorizeChatSessionTool, DEFAULT_CONSOLE_CHAT_SESSION_MODE, } from "../../session-mode.js";
7
- import { buildModelCallableToolSchemas } from "../../tool-adapter.js";
8
- /**
9
- * Build Pi custom ToolDefinition objects for every whitelisted operator action.
10
- * Each tool's execute() routes into the operator action dispatcher (Gate 3).
11
- * Requires the `typebox` + `defineTool` packages (both bundled with the SDK).
12
- */
13
- export async function buildCustomOperatorTools(options) {
14
- // typebox is a transitive dep of @earendil-works/pi-coding-agent; Node's
15
- // resolver hoists to the SDK's nested copy. defineTool is re-exported by SDK.
16
- const [{ Type }, { defineTool }] = await Promise.all([
17
- import("typebox"),
18
- import("@earendil-works/pi-coding-agent"),
19
- ]);
20
- const schemas = buildModelCallableToolSchemas();
21
- const ctx = options.actionContext;
22
- return schemas.map((schema) => {
23
- // TypeBox schema is built dynamically; cast through unknown to the builder
24
- // since Static<TParams> is structural and cannot be statically inferred here.
25
- const parameters = Type.Object(schema.inputParams.reduce((acc, param) => {
26
- // Carry the registry's param description into the tool schema so
27
- // the model sees parameter semantics, not just names/types.
28
- const desc = param.description?.trim()
29
- ? { description: param.description }
30
- : {};
31
- let t;
32
- switch (param.type) {
33
- case "string":
34
- t = Type.String(desc);
35
- break;
36
- case "boolean":
37
- t = Type.Boolean(desc);
38
- break;
39
- case "number":
40
- t = Type.Number(desc);
41
- break;
42
- case "array":
43
- t = Type.Array(Type.String({}), Object.keys(desc).length ? desc : {});
44
- break;
45
- default:
46
- t = Type.Object({}, { additionalProperties: true });
47
- }
48
- acc[param.name] = param.required ? t : Type.Optional(t);
49
- return acc;
50
- }, {}), { additionalProperties: false });
51
- return defineTool({
52
- name: schema.toolId,
53
- label: schema.toolId,
54
- description: `${schema.description} (kind=${schema.kind}; cli: ${schema.cli})`,
55
- promptSnippet: schema.description,
56
- parameters: parameters,
57
- async execute(toolCallId, params) {
58
- const decision = authorizeChatSessionTool(schema.toolId, options.sessionMode ?? DEFAULT_CONSOLE_CHAT_SESSION_MODE);
59
- if (!decision.ok) {
60
- return {
61
- content: [
62
- {
63
- type: "text",
64
- text: JSON.stringify({
65
- error: decision.message,
66
- code: decision.code,
67
- }),
68
- },
69
- ],
70
- details: { error: decision.message, code: decision.code },
71
- };
72
- }
73
- // Defer require to avoid circular import at module load.
74
- const { dispatchChatToolCall } = await import("../../session-store.js");
75
- const result = await dispatchChatToolCall(ctx, decision.toolId, params, toolCallId, options.sessionMode);
76
- const payload = result.ok
77
- ? result.result
78
- : { error: result.message, code: result.errorCode };
79
- return {
80
- content: [{ type: "text", text: JSON.stringify(payload) }],
81
- details: payload,
82
- };
83
- },
84
- });
85
- });
86
- }