@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
@@ -0,0 +1,202 @@
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
+ }
@@ -0,0 +1,78 @@
1
+ /**
2
+ * Session-bound Goal tools (workflow-mode only).
3
+ * create_goal still requires a consumed model-create grant from the registry.
4
+ */
5
+ 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.";
6
+ 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.";
7
+ 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.";
8
+ export async function buildGoalTools(options) {
9
+ const [{ Type }, { defineTool }] = await Promise.all([
10
+ import("typebox"),
11
+ import("@earendil-works/pi-coding-agent"),
12
+ ]);
13
+ const textResult = (value) => ({
14
+ content: [{ type: "text", text: JSON.stringify(value) }],
15
+ details: value,
16
+ });
17
+ return [
18
+ defineTool({
19
+ name: "get_goal",
20
+ label: "Get goal",
21
+ description: GET_GOAL_DESCRIPTION,
22
+ promptSnippet: GET_GOAL_DESCRIPTION,
23
+ parameters: Type.Object({}, { additionalProperties: false }),
24
+ async execute() {
25
+ return textResult({ goal: options.registry.get(options.sessionId) });
26
+ },
27
+ }),
28
+ defineTool({
29
+ name: "create_goal",
30
+ label: "Create goal",
31
+ description: CREATE_GOAL_DESCRIPTION,
32
+ promptSnippet: CREATE_GOAL_DESCRIPTION,
33
+ parameters: Type.Object({
34
+ objective: Type.String({
35
+ description: "Concrete final objective and completion standard explicitly requested by the user.",
36
+ }),
37
+ }, { additionalProperties: false }),
38
+ async execute(_toolCallId, params) {
39
+ if (!options.registry.consumeModelCreateGrant(options.sessionId)) {
40
+ return textResult({
41
+ ok: false,
42
+ code: "GOAL_EXPLICIT_REQUEST_REQUIRED",
43
+ message: "create_goal requires an explicit user request to create or start a Goal",
44
+ });
45
+ }
46
+ return textResult(options.registry.create({
47
+ sessionId: options.sessionId,
48
+ objective: params.objective,
49
+ }));
50
+ },
51
+ }),
52
+ defineTool({
53
+ name: "update_goal",
54
+ label: "Update goal",
55
+ description: UPDATE_GOAL_DESCRIPTION,
56
+ promptSnippet: UPDATE_GOAL_DESCRIPTION,
57
+ parameters: Type.Object({
58
+ goalId: Type.String(),
59
+ revision: Type.Number({ minimum: 1 }),
60
+ status: Type.Union([
61
+ Type.Literal("complete"),
62
+ Type.Literal("blocked"),
63
+ ]),
64
+ blocker: Type.Optional(Type.String()),
65
+ }, { additionalProperties: false }),
66
+ async execute(_toolCallId, params) {
67
+ return textResult(options.registry.update({
68
+ sessionId: options.sessionId,
69
+ goalId: params.goalId,
70
+ expectedRevision: params.revision,
71
+ phase: params.status,
72
+ blocker: params.blocker,
73
+ arm: false,
74
+ }));
75
+ },
76
+ }),
77
+ ];
78
+ }
@@ -0,0 +1,86 @@
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
+ }
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Session-bound todo_write custom tool.
3
+ * Description is mode-aware; ConsolePiRuntime owns when to register it.
4
+ */
5
+ import { PI_TODO_WRITE_DESCRIPTION, } from "../../session-mode.js";
6
+ const 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 or DAG state advances. Skip the list for simple Q&A, read-only lookups, and single-step tasks. Use it for multi-step implementation and whenever you prepare, run, or supervise a DAG — call `todo_write` before entering the DAG tool chain. Phrase DAG todos as user-facing phases users can understand, not copies of internal DAG nodes. Statuses: `pending` / `in_progress` / `completed`.";
7
+ export async function buildTodoWriteTool(options) {
8
+ const [{ Type }, { defineTool }] = await Promise.all([
9
+ import("typebox"),
10
+ import("@earendil-works/pi-coding-agent"),
11
+ ]);
12
+ const description = options.sessionMode === "pi"
13
+ ? PI_TODO_WRITE_DESCRIPTION
14
+ : TODO_WRITE_DESCRIPTION;
15
+ return defineTool({
16
+ name: "todo_write",
17
+ label: "Update todo list",
18
+ description,
19
+ promptSnippet: description,
20
+ parameters: Type.Object({
21
+ todos: Type.Array(Type.Object({
22
+ content: Type.String({ description: "Short imperative task description." }),
23
+ status: Type.Union([
24
+ Type.Literal("pending"),
25
+ Type.Literal("in_progress"),
26
+ Type.Literal("completed"),
27
+ ]),
28
+ }, { additionalProperties: false })),
29
+ }, { additionalProperties: false }),
30
+ async execute(toolCallId, params) {
31
+ const result = options.registry.write(options.sessionId, toolCallId, params.todos);
32
+ return {
33
+ content: [{ type: "text", text: JSON.stringify(result) }],
34
+ details: result,
35
+ };
36
+ },
37
+ });
38
+ }
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Live runtime snapshot types and the structured critical-failure error.
3
+ * Projection and inventory collection live in inspection.ts; ConsolePiRuntime
4
+ * remains the owner of live session lookup and preference-cache refresh.
5
+ */
6
+ export const THINKING_LEVELS = [
7
+ "off",
8
+ "minimal",
9
+ "low",
10
+ "medium",
11
+ "high",
12
+ "xhigh",
13
+ "max",
14
+ ];
15
+ /**
16
+ * Structured critical-failure error for snapshot projection (RF-02). Model
17
+ * enumeration or system prompt projection failures throw this so consuming
18
+ * routes can return 503 PI_RUNTIME_UNAVAILABLE instead of a fake-empty 200.
19
+ * Partial ResourceLoader / package-inventory failures are NOT critical — they
20
+ * keep the 200 snapshot and surface as structured diagnostics instead.
21
+ */
22
+ export class RuntimeSnapshotUnavailableError extends Error {
23
+ code = "PI_RUNTIME_UNAVAILABLE";
24
+ constructor(message) {
25
+ super(message);
26
+ this.name = "RuntimeSnapshotUnavailableError";
27
+ }
28
+ }