@bingjiang0611/rotom 0.1.25 → 0.1.26

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 (107) hide show
  1. package/THIRD_PARTY_NOTICES.md +1 -1
  2. package/extensions/observability/index.ts +20 -2
  3. package/extensions/qoder/messages.mjs +1 -1
  4. package/extensions/qoder/provider.mjs +14 -6
  5. package/extensions/qoder/transport.mjs +53 -11
  6. package/extensions/third-party/node_modules/.package-lock.json +6 -6
  7. package/extensions/third-party/node_modules/pi-subagents/README.md +17 -0
  8. package/extensions/third-party/node_modules/pi-subagents/agents/delegate.md +2 -0
  9. package/extensions/third-party/node_modules/pi-subagents/agents/oracle.md +18 -14
  10. package/extensions/third-party/node_modules/pi-subagents/agents/reviewer.md +5 -3
  11. package/extensions/third-party/node_modules/pi-subagents/docs/models.md +1 -1
  12. package/extensions/third-party/node_modules/pi-subagents/docs/tool-reference.md +2 -2
  13. package/extensions/third-party/node_modules/pi-subagents/docs/workflows.md +2 -2
  14. package/extensions/third-party/node_modules/pi-subagents/package.json +1 -1
  15. package/extensions/third-party/node_modules/pi-subagents/prompts/gather-context-and-clarify.md +1 -1
  16. package/extensions/third-party/node_modules/pi-subagents/prompts/parallel-research.md +4 -6
  17. package/extensions/third-party/node_modules/pi-subagents/skills/pi-subagents/references/constraints-and-recipes.md +8 -8
  18. package/extensions/third-party/node_modules/pi-subagents/skills/pi-subagents/references/execution-controls.md +5 -5
  19. package/extensions/third-party/node_modules/pi-subagents/skills/pi-subagents/references/prompting-and-roles.md +7 -8
  20. package/extensions/third-party/node_modules/pi-subagents/src/agents/agents.ts +0 -1
  21. package/extensions/third-party/node_modules/pi-subagents/src/extension/index.ts +9 -2
  22. package/extensions/third-party/node_modules/pi-subagents/src/profiles/profiles.ts +1 -2
  23. package/extensions/third-party/node_modules/pi-subagents/src/runs/background/async-execution.ts +81 -52
  24. package/extensions/third-party/node_modules/pi-subagents/src/runs/background/process-terminal.ts +13 -0
  25. package/extensions/third-party/node_modules/pi-subagents/src/runs/background/stale-run-reconciler.ts +7 -3
  26. package/extensions/third-party/node_modules/sol-pi/UPSTREAM.md +1 -0
  27. package/extensions/third-party/node_modules/sol-pi/package.json +1 -1
  28. package/extensions/third-party/node_modules/sol-pi/src/sol-pi/extensions/evidence-preserving-reducer/index.ts +1 -0
  29. package/extensions/third-party/node_modules/sol-pi/src/sol-pi/extensions/evidence-preserving-reducer/receipt.ts +79 -16
  30. package/extensions/third-party/package-lock.json +8 -8
  31. package/extensions/third-party/package.json +2 -2
  32. package/extensions/third-party/vendor/README.md +12 -12
  33. package/extensions/third-party/vendor/pi-subagents-0.52.1-rotom.10.tgz +0 -0
  34. package/extensions/third-party/vendor/sol-pi-0.1.0-rotom.2.tgz +0 -0
  35. package/package.json +3 -3
  36. package/runtime/pi/fork-build.json +9 -9
  37. package/runtime/pi/node_modules/.package-lock.json +7 -7
  38. package/runtime/pi/node_modules/@earendil-works/pi-agent-core/package.json +1 -1
  39. package/runtime/pi/node_modules/@earendil-works/pi-ai/dist/api/anthropic-messages.d.ts.map +1 -1
  40. package/runtime/pi/node_modules/@earendil-works/pi-ai/dist/api/anthropic-messages.js +2 -1
  41. package/runtime/pi/node_modules/@earendil-works/pi-ai/dist/api/anthropic-messages.js.map +1 -1
  42. package/runtime/pi/node_modules/@earendil-works/pi-ai/dist/utils/error-body.d.ts +8 -0
  43. package/runtime/pi/node_modules/@earendil-works/pi-ai/dist/utils/error-body.d.ts.map +1 -1
  44. package/runtime/pi/node_modules/@earendil-works/pi-ai/dist/utils/error-body.js +37 -1
  45. package/runtime/pi/node_modules/@earendil-works/pi-ai/dist/utils/error-body.js.map +1 -1
  46. package/runtime/pi/node_modules/@earendil-works/pi-ai/dist/utils/retry.d.ts +6 -0
  47. package/runtime/pi/node_modules/@earendil-works/pi-ai/dist/utils/retry.d.ts.map +1 -1
  48. package/runtime/pi/node_modules/@earendil-works/pi-ai/dist/utils/retry.js +34 -0
  49. package/runtime/pi/node_modules/@earendil-works/pi-ai/dist/utils/retry.js.map +1 -1
  50. package/runtime/pi/node_modules/@earendil-works/pi-ai/package.json +1 -1
  51. package/runtime/pi/node_modules/@earendil-works/pi-codemode/package.json +1 -1
  52. package/runtime/pi/node_modules/@earendil-works/pi-coding-agent/dist/bundle/chunks/anthropic-messages-H6BRNJYC.js +6 -0
  53. package/runtime/pi/node_modules/@earendil-works/pi-coding-agent/dist/bundle/chunks/{azure-openai-responses-KZZFKCXW.js → azure-openai-responses-45AJGMB6.js} +1 -1
  54. package/runtime/pi/node_modules/@earendil-works/pi-coding-agent/dist/bundle/chunks/bedrock-converse-stream.js +1 -1
  55. package/runtime/pi/node_modules/@earendil-works/pi-coding-agent/dist/bundle/chunks/{chunk-2CKNKV2I.js → chunk-5MTGRVNE.js} +2 -2
  56. package/runtime/pi/node_modules/@earendil-works/pi-coding-agent/dist/bundle/chunks/{chunk-ITZNWD4K.js → chunk-7OCND3IM.js} +1 -1
  57. package/runtime/pi/node_modules/@earendil-works/pi-coding-agent/dist/bundle/chunks/chunk-CTEAMRDY.js +2 -0
  58. package/runtime/pi/node_modules/@earendil-works/pi-coding-agent/dist/bundle/chunks/{chunk-6NUCYK64.js → chunk-ESL4WJJF.js} +9 -9
  59. package/runtime/pi/node_modules/@earendil-works/pi-coding-agent/dist/bundle/chunks/{chunk-DSV77X2M.js → chunk-MXCOAUPD.js} +1 -1
  60. package/runtime/pi/node_modules/@earendil-works/pi-coding-agent/dist/bundle/chunks/{cloudflare-workers-ai-system-one-UTBL2KOF.js → cloudflare-workers-ai-system-one-IEPXKTM7.js} +1 -1
  61. package/runtime/pi/node_modules/@earendil-works/pi-coding-agent/dist/bundle/chunks/{execute-4WILIDZF.js → execute-ULZNGRYF.js} +1 -1
  62. package/runtime/pi/node_modules/@earendil-works/pi-coding-agent/dist/bundle/chunks/{google-generative-ai-KJOKBJM3.js → google-generative-ai-KXRSXWRQ.js} +1 -1
  63. package/runtime/pi/node_modules/@earendil-works/pi-coding-agent/dist/bundle/chunks/{google-vertex-VCLZ36OB.js → google-vertex-CVLJXJIO.js} +1 -1
  64. package/runtime/pi/node_modules/@earendil-works/pi-coding-agent/dist/bundle/chunks/{llama-cpp-classify-FYN623RH.js → llama-cpp-classify-42ZH3VVO.js} +1 -1
  65. package/runtime/pi/node_modules/@earendil-works/pi-coding-agent/dist/bundle/chunks/{openai-codex-responses-ZYGHVE5B.js → openai-codex-responses-L4P7LV62.js} +1 -1
  66. package/runtime/pi/node_modules/@earendil-works/pi-coding-agent/dist/bundle/chunks/{openai-completions-BGCEXFAB.js → openai-completions-ZIOWDPDJ.js} +1 -1
  67. package/runtime/pi/node_modules/@earendil-works/pi-coding-agent/dist/bundle/chunks/{openai-decisions-WVPMQ4JD.js → openai-decisions-L7N23NC7.js} +1 -1
  68. package/runtime/pi/node_modules/@earendil-works/pi-coding-agent/dist/bundle/chunks/{openai-responses-KCCCXI3B.js → openai-responses-XT6CQ4R7.js} +1 -1
  69. package/runtime/pi/node_modules/@earendil-works/pi-coding-agent/dist/bundle/chunks/{openrouter-images-DUPG5DZO.js → openrouter-images-FQ7HEE4T.js} +1 -1
  70. package/runtime/pi/node_modules/@earendil-works/pi-coding-agent/dist/bundle/chunks/{typesafe-system-one-ZSK3RN4B.js → typesafe-system-one-IH2QHGKL.js} +1 -1
  71. package/runtime/pi/node_modules/@earendil-works/pi-coding-agent/dist/bundle/chunks/{virtual-modules-INPREDLP.js → virtual-modules-YSF6BJRF.js} +1 -1
  72. package/runtime/pi/node_modules/@earendil-works/pi-coding-agent/dist/bundle/cli-runtime.js +1 -1
  73. package/runtime/pi/node_modules/@earendil-works/pi-coding-agent/dist/bundle/index.js +1 -1
  74. package/runtime/pi/node_modules/@earendil-works/pi-coding-agent/dist/bundle/rpc-entry.js +1 -1
  75. package/runtime/pi/node_modules/@earendil-works/pi-coding-agent/dist/core/agent-session.d.ts +5 -0
  76. package/runtime/pi/node_modules/@earendil-works/pi-coding-agent/dist/core/agent-session.d.ts.map +1 -1
  77. package/runtime/pi/node_modules/@earendil-works/pi-coding-agent/dist/core/agent-session.js +56 -27
  78. package/runtime/pi/node_modules/@earendil-works/pi-coding-agent/dist/core/agent-session.js.map +1 -1
  79. package/runtime/pi/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/status-indicator.d.ts +1 -0
  80. package/runtime/pi/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/status-indicator.d.ts.map +1 -1
  81. package/runtime/pi/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/status-indicator.js +4 -1
  82. package/runtime/pi/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/status-indicator.js.map +1 -1
  83. package/runtime/pi/node_modules/@earendil-works/pi-coding-agent/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
  84. package/runtime/pi/node_modules/@earendil-works/pi-coding-agent/dist/modes/rpc/rpc-mode.js +37 -4
  85. package/runtime/pi/node_modules/@earendil-works/pi-coding-agent/dist/modes/rpc/rpc-mode.js.map +1 -1
  86. package/runtime/pi/node_modules/@earendil-works/pi-coding-agent/docs/json.md +6 -0
  87. package/runtime/pi/node_modules/@earendil-works/pi-coding-agent/docs/rpc-extension-ui.md +2 -0
  88. package/runtime/pi/node_modules/@earendil-works/pi-coding-agent/docs/settings.md +3 -1
  89. package/runtime/pi/node_modules/@earendil-works/pi-coding-agent/package.json +1 -1
  90. package/runtime/pi/node_modules/@earendil-works/pi-mcp/package.json +1 -1
  91. package/runtime/pi/node_modules/@earendil-works/pi-telemetry/package.json +1 -1
  92. package/runtime/pi/node_modules/@earendil-works/pi-tui/package.json +1 -1
  93. package/runtime/pi/package-lock.json +7 -7
  94. package/runtime/pi/vendor/earendil-works-pi-agent-core-1.3.0-rotom.2.tgz +0 -0
  95. package/runtime/pi/vendor/earendil-works-pi-ai-1.3.0-rotom.2.tgz +0 -0
  96. package/runtime/pi/vendor/earendil-works-pi-codemode-1.3.0-rotom.2.tgz +0 -0
  97. package/runtime/pi/vendor/earendil-works-pi-coding-agent-1.3.0-rotom.2.tgz +0 -0
  98. package/runtime/pi/vendor/earendil-works-pi-mcp-1.3.0-rotom.2.tgz +0 -0
  99. package/runtime/pi/vendor/earendil-works-pi-telemetry-1.3.0-rotom.2.tgz +0 -0
  100. package/runtime/pi/vendor/earendil-works-pi-tui-1.3.0-rotom.2.tgz +0 -0
  101. package/runtime/product-config.mjs +4 -4
  102. package/extensions/third-party/node_modules/pi-subagents/agents/researcher.md +0 -52
  103. package/extensions/third-party/node_modules/pi-subagents/docs/agents.md +0 -383
  104. package/extensions/third-party/vendor/pi-subagents-0.52.1-rotom.7.tgz +0 -0
  105. package/extensions/third-party/vendor/sol-pi-0.1.0-rotom.1.tgz +0 -0
  106. package/runtime/pi/node_modules/@earendil-works/pi-coding-agent/dist/bundle/chunks/anthropic-messages-UIH6DSZT.js +0 -6
  107. package/runtime/pi/node_modules/@earendil-works/pi-coding-agent/dist/bundle/chunks/chunk-TEPMHNKQ.js +0 -2
@@ -48,7 +48,7 @@ subagent({
48
48
 
49
49
  ```typescript
50
50
  subagent({
51
- workflowScript: `return runs.run("oracle-check", { agent: "oracle", task: "Review my current direction and challenge assumptions.", context: "fork" })`
51
+ workflowScript: `return runs.run("continue-thread", { agent: "delegate", task: "Continue the investigation from the current conversation state.", context: "fork" })`
52
52
  })
53
53
  ```
54
54
 
@@ -86,7 +86,7 @@ Completed workflow children from this parent session stay addressable as retaine
86
86
 
87
87
  ### Async/background
88
88
 
89
- Prefer async mode for every subagent launch. Set `async: true` no matter the task unless the parent must block until completion. This applies to scouts, researchers, workers, reviewers, validators, oracle checks, one-off delegates, final review gates, backlog gates, and scripted workflows. Keep the write path single-threaded even when the run is async.
89
+ Prefer async mode for every subagent launch. Set `async: true` no matter the task unless the parent must block until completion. This applies to scouts, workers, reviewers, validators, oracle checks, one-off delegates, final review gates, backlog gates, and scripted workflows. Keep the write path single-threaded even when the run is async.
90
90
 
91
91
  Use `async:false` only when the parent must block until completion. Async mode still shows progress. Do not use `async:false` because a task is short, because it is the last gate, because no other work is ready, because the user asked to finish the overall job, or because blocking is convenient.
92
92
 
@@ -358,7 +358,7 @@ worktree, first confirm dependencies were linked, installed, or provisioned by
358
358
 
359
359
  ### Oracle consultation loop
360
360
 
361
- For plan, design, or architecture advice that asks to ask, consult, discuss with, or come to agreement with `oracle`, start with one forked oracle run. Read its result. If it challenges the direction or leaves a material tradeoff, resume that same completed child once with a focused follow-up, then synthesize the parent decision. `resume` returns a new run id, but continues the same oracle session and inherited context. Do not force a second round for an explicit one-shot request, a trivial question, or a fully settled first answer.
361
+ For plan, design, or architecture advice that asks to ask, consult, discuss with, or come to agreement with `oracle`, start with one fresh oracle run whose task is a decision brief: goal and acceptance criteria, decisions already made and why, hard constraints, the proposed move, the files that matter, and the specific question. Read its result. If it challenges the direction or leaves a material tradeoff, resume that same completed child once with a focused follow-up, then synthesize the parent decision. `resume` returns a new run id, but continues the same oracle session. Do not force a second round for an explicit one-shot request, a trivial question, or a fully settled first answer.
362
362
 
363
363
  ```typescript
364
364
  const first = await runs.run("oracle-consult", { agent: "oracle", task: "Review this plan and identify the strongest unresolved tradeoff." });
@@ -368,14 +368,14 @@ const final = await runs.run("oracle-consult-follow-up", { resume: first.runId,
368
368
  The parent remains the final decision-maker. Oracle advice does not approve a direction or start implementation.
369
369
 
370
370
  The intended oracle loop is:
371
- 1. the main agent forks to `oracle`
371
+ 1. the main agent writes a decision brief and launches `oracle` with fresh context
372
372
  2. `oracle` reviews direction, drift, assumptions, and risks
373
373
  3. `oracle` can coordinate back through `contact_supervisor` when the bridge injects it
374
374
  4. the main agent decides what direction to approve
375
375
  5. only then should `worker` implement
376
376
 
377
377
  ```typescript
378
- // Advisory review in a branched thread. Oracle defaults to forked context.
378
+ // Advisory review from a parent-written decision brief. Oracle defaults to fresh context.
379
379
  subagent({
380
380
  workflowScript: `return runs.run("oracle-check", { agent: "oracle", task: "Review my current direction, challenge assumptions, and propose the best next move." })`
381
381
  })
@@ -9,7 +9,7 @@ Parent extensions may register a session-scoped, out-of-band ceiling through `pi
9
9
  ## When to Use
10
10
 
11
11
  - **Complex work orchestration**: use Fable mode as the default parent-agent loop for complex work. Complex means the task has multiple moving parts, unclear acceptance, cross-cutting code, meaningful user-visible impact, expensive or irreversible validation, broad review surface, or the user asks for orchestration. Lightweight one-off delegation can stay lightweight.
12
- - **Advisory review**: use fresh-context `reviewer` agents for adversarial code review, or fork to `oracle` when inherited decisions and drift matter
12
+ - **Advisory review**: use fresh-context `reviewer` agents for adversarial code review, or give `oracle` a written decision brief when prior decisions and drift matter
13
13
  - **Implementation handoff**: have `oracle` advise, then `worker` implement only after an approved direction
14
14
  - **Recon and planning**: use `scout`, then write a plan when needed
15
15
  - **Parallel exploration**: run multiple non-conflicting tasks concurrently
@@ -41,7 +41,7 @@ you are guiding a human through an interactive flow.
41
41
  Packaged prompt shortcuts are also available for repeatable workflows. Treat them as reusable orchestration recipes, not just human slash commands. When the user asks for one of these shapes, or when the workflow clearly fits, apply the same pattern directly with `subagent(...)` and other tools:
42
42
  - `/parallel-review` — fresh-context reviewers with distinct review angles, then synthesis
43
43
  - `/review-loop` — parent-orchestrated worker, fresh-reviewer, and fix-worker cycles until clean or capped
44
- - `/parallel-research` — combine `researcher` and `scout` for external evidence plus local code context
44
+ - `/parallel-research` — combine parallel `scout` lanes for local code context with external evidence the parent gathers
45
45
  - `/gather-context-and-clarify` — scout/research first, then ask the user clarifying questions with `interview`
46
46
  - `/parallel-cleanup` — two fresh-context reviewers (deslop + verbosity passes) for an adversarial cleanup review of the current diff
47
47
 
@@ -87,13 +87,13 @@ As a conservative orchestration policy, do not pass `turnBudget` or a hard `tool
87
87
 
88
88
  ### Parallel research technique
89
89
 
90
- Use this when the question needs both external evidence and local implications. Combine `researcher` for official docs, specs, ecosystem behavior, recent changes, benchmarks, and primary sources with `scout` for repository files, patterns, constraints, tests, and likely integration points. Give each child a distinct angle: external evidence, local code context, and practical tradeoffs. Ask for source links or file ranges, confidence level, gaps, and decision implications. Do not ask these children to edit unless implementation was explicitly requested.
90
+ Use this when the question needs both external evidence and local implications. The parent gathers official docs, specs, ecosystem behavior, recent changes, benchmarks, and primary sources itself (there is no builtin web-research agent) and uses `scout` for repository files, patterns, constraints, tests, and likely integration points. Give each child a distinct angle: external evidence, local code context, and practical tradeoffs. Ask for source links or file ranges, confidence level, gaps, and decision implications. Do not ask these children to edit unless implementation was explicitly requested.
91
91
 
92
92
 
93
93
 
94
94
  ### Gather-context-and-clarify technique
95
95
 
96
- Use this at the start of non-trivial work. Launch `scout` for local context and `researcher` only when external docs, recent sources, ecosystem context, or primary evidence would materially improve understanding. Ask children for concise findings plus remaining clarification questions. Then synthesize what is known and use `interview` to ask the unresolved questions needed for shared understanding before planning or implementing.
96
+ Use this at the start of non-trivial work. Launch `scout` for local context, and gather external docs, recent sources, ecosystem context, or primary evidence in the parent only when they would materially improve understanding. Ask children for concise findings plus remaining clarification questions. Then synthesize what is known and use `interview` to ask the unresolved questions needed for shared understanding before planning or implementing.
97
97
 
98
98
  ### Parallel cleanup technique
99
99
 
@@ -157,10 +157,9 @@ and user/project agents override builtins with the same name.
157
157
  |-------|---------|-------|------------------------|
158
158
  | `scout` | Fast codebase recon | inherits default | Writes `context.md` handoff material |
159
159
  | `worker` | Implementation and approved oracle handoffs | inherits default | Single-writer implementation with decision escalation |
160
- | `reviewer` | Review specialist | inherits default | Default recipes are review-only; tools include edit/write when a fix pass is explicit |
161
- | `researcher` | Web research brief generator | inherits default | Writes `research.md` |
160
+ | `reviewer` | Review specialist | inherits default | Review-only; `bash` limited by prompt to read-only inspection and existing checks |
162
161
  | `delegate` | Lightweight generic delegate | inherits default | No fixed output; generic delegated work |
163
- | `oracle` | Decision-consistency advisory review | inherits default | Advisory review, intercom coordination |
162
+ | `oracle` | Decision-consistency advisory review | inherits default | Read-only; fresh context from a parent-written decision brief |
164
163
  | `advisor` | Claude Code-compatible alias for `oracle` | inherits default | Same advisory role as `oracle` |
165
164
 
166
165
  Builtin `worker` and `delegate` use strict tool allowlists and do not inherit ambient parent extension tools. To give a child an extension tool, name it in `tools` and load its provider via `extensions`, a path-like `tools` entry, or `subagentOnlyExtensions`. Custom agents without an `extensions` field follow `subagents.defaultExtensions` when set.
@@ -206,7 +205,7 @@ A strong subagent prompt usually includes:
206
205
 
207
206
  Give each role useful discovery anchors. Name source roots, filenames, symbols, types, methods, and paths for scouts. Give workers context files, plans, task paths, and named source seams before asking them to search. Give reviewers changed files, contracts, and any exhaustive-verification target. Tell oracle whether current source behavior, product/policy documents, plans, or inherited decisions are the evidence that matters.
208
207
 
209
- Avoid carrying over old prompt habits that over-specify every step. Use `must`, `always`, and `never` for real invariants; for judgment calls, give decision rules. For example, tell a reviewer to inspect the staged diff directly and report only evidence-backed findings, rather than prescribing every file or command. Tell a researcher the retrieval budget: start with broad targeted searches, fetch only the strongest sources, search again only when a required fact is missing, then stop.
208
+ Avoid carrying over old prompt habits that over-specify every step. Use `must`, `always`, and `never` for real invariants; for judgment calls, give decision rules. For example, tell a reviewer to inspect the staged diff directly and report only evidence-backed findings, rather than prescribing every file or command.
210
209
 
211
210
  For implementation handoffs, name the approved scope and success criteria more clearly than the process. Good prompts say what to change, what not to change, where the evidence lives, how to validate, and when to escalate. They should not ask the child to create another subagent plan or continue the parent conversation.
212
211
 
@@ -39,7 +39,6 @@ export const BUILTIN_AGENT_NAMES = [
39
39
  "advisor",
40
40
  "delegate",
41
41
  "oracle",
42
- "researcher",
43
42
  "reviewer",
44
43
  "scout",
45
44
  "worker",
@@ -47,6 +47,7 @@ import { resolveWaitToolConfig } from "../runs/background/subagent-wait.ts";
47
47
  import { registerWaitTool } from "../runs/background/wait-tool.ts";
48
48
  import { createWaitSubscriptionManager } from "../runs/background/wait-subscriptions.ts";
49
49
  import { drainOutstandingWork } from "../runs/background/auto-drain.ts";
50
+ import { asyncRunnerDrain } from "../runs/background/async-execution.ts";
50
51
  import registerSubagentNotify, { parseSubagentNotifyContent, type SubagentNotifyDetails } from "../runs/background/notify.ts";
51
52
  import { formatSteeringNotice, handleSubagentSteeringNotice, SUBAGENT_STEERING_MESSAGE_TYPE, type SubagentSteeringMessageDetails } from "./steering-notices.ts";
52
53
  import { SUBAGENT_CHILD_ENV, SUBAGENT_PARENT_SESSION_ENV } from "../runs/shared/pi-args.ts";
@@ -950,7 +951,13 @@ export default function registerSubagentExtension(pi: ExtensionAPI): void {
950
951
  });
951
952
 
952
953
  pi.on("session_shutdown", async () => {
953
- runtimeEntry.cleanup();
954
- await herdrStatusBridge.flush();
954
+ try {
955
+ // Quit, reload and replacement retire this runtime's authority. Persist
956
+ // child close evidence before disposing the original observers.
957
+ await asyncRunnerDrain(pi).drain();
958
+ } finally {
959
+ runtimeEntry.cleanup();
960
+ await herdrStatusBridge.flush();
961
+ }
955
962
  });
956
963
  }
@@ -261,7 +261,7 @@ function qualityTierToRoleTier(quality: QualityTier, cost: CostTier): Recommende
261
261
 
262
262
  function agentsForRoleTier(roleTier: RecommendedRoleTier): BuiltinAgentName[] {
263
263
  if (roleTier === "cheap") return ["scout", "delegate"];
264
- if (roleTier === "medium") return ["researcher", "reviewer"];
264
+ if (roleTier === "medium") return ["reviewer"];
265
265
  return ["worker", "reviewer", "oracle"];
266
266
  }
267
267
 
@@ -407,7 +407,6 @@ function buildProfileFile(kind: ProfileKind, models: { cheap: string; medium: st
407
407
  agentOverrides: {
408
408
  scout: { model: models.cheap },
409
409
  delegate: { model: models.cheap },
410
- researcher: { model: models.medium },
411
410
  worker: { model: models.strong },
412
411
  reviewer: { model: models.strong },
413
412
  oracle: { model: models.strong },
@@ -67,7 +67,9 @@ import { validateToolBudgetConfig } from "../shared/tool-budget.ts";
67
67
  import { usageBudgetState } from "../shared/usage-budget.ts";
68
68
  import type { ImportedAsyncRoot } from "./chain-root-attachment.ts";
69
69
  import type { SessionLeaseRequest } from "../shared/session-lease.ts";
70
- import { finalizeProcessTerminal, readProcessTerminal } from "./process-terminal.ts";
70
+ import { finalizeProcessTerminal, readProcessTerminal, registerRunnerCloseObserver } from "./process-terminal.ts";
71
+ import { createRunnerDrain } from "./runner-drain.ts";
72
+
71
73
  import type { ActiveAsyncCapacityHandle } from "./active-async-capacity.ts";
72
74
  import { assertExecutionStoreScope, scopedSessionRoot, assertScopedSessionPath } from "../../shared/execution-store.ts";
73
75
  import { OWNED_EXECUTION_SCOPE, type OwnedExecutionRequest, type OwnedWorkflowParent } from "./owned-execution.ts";
@@ -76,6 +78,17 @@ import { assertAgentAllowedByCapabilityCeiling, decodeSubagentCapabilityCeiling,
76
78
  import { agentDefinitionDigest, launchBindingDigest } from "../../shared/launch-contract.ts";
77
79
  import { resolvePermissionRules, type PermissionConfig } from "../shared/permissions.ts";
78
80
 
81
+ // Each runtime owns live ChildProcess handles, never historical PIDs.
82
+ const runtimeRunnerDrains = new WeakMap<object, ReturnType<typeof createRunnerDrain>>();
83
+ export function asyncRunnerDrain(owner: object): ReturnType<typeof createRunnerDrain> {
84
+ let drain = runtimeRunnerDrains.get(owner);
85
+ if (!drain) {
86
+ drain = createRunnerDrain();
87
+ runtimeRunnerDrains.set(owner, drain);
88
+ }
89
+ return drain;
90
+ }
91
+
79
92
  const require = createRequire(import.meta.url);
80
93
  const piPackageRoot = resolvePiPackageRoot();
81
94
 
@@ -487,7 +500,8 @@ interface SpawnRunnerResult {
487
500
  startupDidNotProceed?: boolean;
488
501
  }
489
502
 
490
- function spawnRunner(cfg: object, suffix: string, cwd: string, onProcessTerminal?: (proof: unknown) => void): SpawnRunnerResult {
503
+ function spawnRunner(cfg: object, suffix: string, cwd: string, drain: ReturnType<typeof createRunnerDrain>, onProcessTerminal?: (proof: unknown) => void): SpawnRunnerResult {
504
+ drain.assertOpen();
491
505
  if (!jitiCliPath) {
492
506
  return { error: "upstream jiti for TypeScript execution could not be found; ensure package dependencies are installed" };
493
507
  }
@@ -546,62 +560,75 @@ function spawnRunner(cfg: object, suffix: string, cwd: string, onProcessTerminal
546
560
  proc.on("error", (error) => {
547
561
  console.error(`[pi-subagents] async spawn failed: ${error.message}`);
548
562
  });
563
+ const releaseCloseObserver = typeof launchAsyncDir === "string" && typeof launchRunId === "string"
564
+ ? registerRunnerCloseObserver(launchAsyncDir, launchRunId, runnerProcessInstanceId) : undefined;
565
+ const observedClose = drain.track(() => {
566
+ // Awaiting a Promise alone cannot keep Node alive after RPC stdin closes.
567
+ proc.ref();
568
+ if (proc.exitCode === null && proc.signalCode === null) proc.kill("SIGTERM");
569
+ });
549
570
  proc.once("close", (exitCode, signal) => {
550
- const launch = launchConfig as { asyncDir?: unknown; id?: unknown; nestedRoute?: NestedRouteInfo; nestedSelf?: { parentRunId: string; parentStepIndex?: number; depth: number; path?: Array<{ runId: string; stepIndex?: number; agent?: string }> } };
551
- const asyncDir = launch.asyncDir;
552
- const runId = launch.id;
553
- if (typeof asyncDir !== "string" || typeof runId !== "string") return;
554
- finalizeProcessTerminal(asyncDir, runId, {
555
- processInstanceId: runnerProcessInstanceId,
556
- closeObservedAt: Date.now(),
557
- exitCode,
558
- signal,
559
- });
560
- const persisted = readProcessTerminal(asyncDir, { runId, runnerProcessInstanceId });
561
- if (!persisted) return;
562
- if (launch.nestedRoute && launch.nestedSelf) {
563
- try {
564
- let status: import("../../shared/types.ts").AsyncStatus;
571
+ try {
572
+ const launch = launchConfig as { asyncDir?: unknown; id?: unknown; nestedRoute?: NestedRouteInfo; nestedSelf?: { parentRunId: string; parentStepIndex?: number; depth: number; path?: Array<{ runId: string; stepIndex?: number; agent?: string }> } };
573
+ const asyncDir = launch.asyncDir;
574
+ const runId = launch.id;
575
+ if (typeof asyncDir !== "string" || typeof runId !== "string") return;
576
+ finalizeProcessTerminal(asyncDir, runId, {
577
+ processInstanceId: runnerProcessInstanceId,
578
+ closeObservedAt: Date.now(),
579
+ exitCode,
580
+ signal,
581
+ });
582
+ const persisted = readProcessTerminal(asyncDir, { runId, runnerProcessInstanceId });
583
+ if (!persisted) return;
584
+ if (launch.nestedRoute && launch.nestedSelf) {
565
585
  try {
566
- status = JSON.parse(fs.readFileSync(path.join(asyncDir, "status.json"), "utf-8")) as import("../../shared/types.ts").AsyncStatus;
567
- status.processTerminal = persisted;
568
- } catch {
569
- status = {
570
- runId,
571
- mode: "single",
572
- state: persisted.state === "observed" ? "complete" : "failed",
573
- startedAt: persisted.observedAt ?? Date.now(),
574
- lastUpdate: Date.now(),
575
- processTerminal: persisted,
576
- };
577
- }
578
- writeNestedEvent(launch.nestedRoute, {
579
- type: "subagent.nested.completed",
580
- ts: Date.now(),
581
- parentRunId: launch.nestedSelf.parentRunId,
582
- parentStepIndex: launch.nestedSelf.parentStepIndex,
583
- child: nestedSummaryFromAsyncStatus(status, asyncDir, {
584
- id: runId,
586
+ let status: import("../../shared/types.ts").AsyncStatus;
587
+ try {
588
+ status = JSON.parse(fs.readFileSync(path.join(asyncDir, "status.json"), "utf-8")) as import("../../shared/types.ts").AsyncStatus;
589
+ status.processTerminal = persisted;
590
+ } catch {
591
+ status = {
592
+ runId,
593
+ mode: "single",
594
+ state: persisted.state === "observed" ? "complete" : "failed",
595
+ startedAt: persisted.observedAt ?? Date.now(),
596
+ lastUpdate: Date.now(),
597
+ processTerminal: persisted,
598
+ };
599
+ }
600
+ writeNestedEvent(launch.nestedRoute, {
601
+ type: "subagent.nested.completed",
602
+ ts: Date.now(),
585
603
  parentRunId: launch.nestedSelf.parentRunId,
586
604
  parentStepIndex: launch.nestedSelf.parentStepIndex,
587
- depth: launch.nestedSelf.depth,
588
- path: launch.nestedSelf.path,
589
- mode: status.mode,
590
- ts: Date.now(),
591
- }),
592
- });
605
+ child: nestedSummaryFromAsyncStatus(status, asyncDir, {
606
+ id: runId,
607
+ parentRunId: launch.nestedSelf.parentRunId,
608
+ parentStepIndex: launch.nestedSelf.parentStepIndex,
609
+ depth: launch.nestedSelf.depth,
610
+ path: launch.nestedSelf.path,
611
+ mode: status.mode,
612
+ ts: Date.now(),
613
+ }),
614
+ });
615
+ } catch (error) {
616
+ console.error("Failed to emit final nested process-terminal status:", error);
617
+ }
618
+ }
619
+ try {
620
+ onProcessTerminal?.(persisted);
593
621
  } catch (error) {
594
- console.error("Failed to emit final nested process-terminal status:", error);
622
+ // The close proof is already durable. Reload/disposal can retire the
623
+ // originating Pi API before this late advisory wake; never redirect it
624
+ // to a new session or claim a receipt. Recovery must read the record.
625
+ if (!(error instanceof Error)
626
+ || !/extension ctx is stale|stale after session replacement or reload/i.test(error.message)) throw error;
595
627
  }
596
- }
597
- try {
598
- onProcessTerminal?.(persisted);
599
- } catch (error) {
600
- // The close proof is already durable. Reload/disposal can retire the
601
- // originating Pi API before this late advisory wake; never redirect it
602
- // to a new session or claim a receipt. Recovery must read the record.
603
- if (!(error instanceof Error)
604
- || !/extension ctx is stale|stale after session replacement or reload/i.test(error.message)) throw error;
628
+ } finally {
629
+ // Finalization (including honest unknown) precedes runtime teardown.
630
+ releaseCloseObserver?.();
631
+ observedClose();
605
632
  }
606
633
  });
607
634
  if (typeof proc.pid !== "number") {
@@ -1202,6 +1229,7 @@ export function executeAsyncChain(
1202
1229
  },
1203
1230
  id,
1204
1231
  runnerCwd,
1232
+ asyncRunnerDrain(ctx.pi),
1205
1233
  (proof) => ctx.pi.events.emit(SUBAGENT_PROCESS_TERMINAL_EVENT, proof),
1206
1234
  );
1207
1235
  } catch (error) {
@@ -1684,6 +1712,7 @@ export function executeAsyncSingle(
1684
1712
  },
1685
1713
  id,
1686
1714
  runnerCwd,
1715
+ asyncRunnerDrain(ctx.pi),
1687
1716
  (proof) => ctx.pi.events.emit(SUBAGENT_PROCESS_TERMINAL_EVENT, proof),
1688
1717
  );
1689
1718
  } catch (error) {
@@ -13,6 +13,19 @@ import { canonicalSessionId, inspectSessionLease } from "../shared/session-lease
13
13
  import { releaseActiveRunIndex } from "./active-run-index.ts";
14
14
  import { validOwnedExecution, projectOwnedClosure, type OwnedExecutionV2 } from "./owned-execution.ts";
15
15
 
16
+ // Process-local liveness of the original observer, not evidence of exit. A new
17
+ // parent cannot reconstruct this registration from disk or a numeric PID.
18
+ const runnerCloseObservers = new Set<string>();
19
+ const observerKey = (asyncDir: string, runId: string, instanceId: string) => JSON.stringify([path.resolve(asyncDir), runId, instanceId]);
20
+ export function registerRunnerCloseObserver(asyncDir: string, runId: string, instanceId: string): () => void {
21
+ const key = observerKey(asyncDir, runId, instanceId);
22
+ runnerCloseObservers.add(key);
23
+ return () => { runnerCloseObservers.delete(key); };
24
+ }
25
+ export function hasRunnerCloseObserver(asyncDir: string, runId: string, instanceId: string): boolean {
26
+ return runnerCloseObservers.has(observerKey(asyncDir, runId, instanceId));
27
+ }
28
+
16
29
  export interface ProcessTerminalCandidate {
17
30
  version: 1;
18
31
  runId: string;
@@ -7,6 +7,7 @@ import { readStatus } from "../../shared/utils.ts";
7
7
  import { DIRS, type AsyncParallelGroupStatus, type AsyncStatus, type NestedRunSummary, type SubagentRunMode } from "../../shared/types.ts";
8
8
  import { resolveEffectiveThinking } from "../../shared/model-info.ts";
9
9
  import { normalizeParallelGroups } from "./parallel-groups.ts";
10
+ import { hasRunnerCloseObserver } from "./process-terminal.ts";
10
11
  import { nestedSummaryFromAsyncStatus, projectNestedEvents, resolveNestedAsyncDir, writeNestedEvent, type NestedRoute } from "../shared/nested-events.ts";
11
12
 
12
13
  export type PidLiveness = "alive" | "dead" | "unknown";
@@ -141,7 +142,7 @@ function childState(overallState: ResultRepairData["state"], child: ResultChildO
141
142
  return overallState;
142
143
  }
143
144
 
144
- function terminalStatusFromResult(status: AsyncStatus, resultPath: string, now: number): AsyncStatus | undefined {
145
+ function terminalStatusFromResult(status: AsyncStatus, resultPath: string, now: number, asyncDir: string): AsyncStatus | undefined {
145
146
  const repair = readResultRepairData(resultPath);
146
147
  if (!repair) return undefined;
147
148
  const steps = (status.steps ?? []).map((step, index) => {
@@ -168,7 +169,10 @@ function terminalStatusFromResult(status: AsyncStatus, resultPath: string, now:
168
169
  const terminalStatus: AsyncStatus = {
169
170
  ...status,
170
171
  state: repair.state,
171
- ...(status.lifecycleArtifactVersion === 3 && (!status.processTerminal || status.processTerminal.state === "pending") ? {
172
+ ...(status.lifecycleArtifactVersion === 3 && (!status.processTerminal || status.processTerminal.state === "pending")
173
+ // A result can precede the launching parent's native close callback.
174
+ // Retain pending for that actual observer; this never proves exit.
175
+ && !(status.processTerminal?.state === "pending" && hasRunnerCloseObserver(asyncDir, status.runId, status.processTerminal.runnerProcessInstanceId)) ? {
172
176
  processTerminal: { version: 1 as const, state: "unknown" as const, runId: status.runId, runnerProcessInstanceId: "observer-unavailable", reason: "observer-unavailable" as const },
173
177
  } : {}),
174
178
  ...(repair.state === "stopped" ? { stopped: true } : {}),
@@ -379,7 +383,7 @@ export function reconcileAsyncRun(asyncDir: string, options: ReconcileAsyncRunOp
379
383
  : regularFileExists(resultPath) ? resultPath : undefined;
380
384
  if (existingResultPath) {
381
385
  const terminalStatus = effectiveStatus.state === "running" || effectiveStatus.state === "queued"
382
- ? terminalStatusFromResult(effectiveStatus, existingResultPath, now)
386
+ ? terminalStatusFromResult(effectiveStatus, existingResultPath, now, asyncDir)
383
387
  : undefined;
384
388
  if (terminalStatus) {
385
389
  writeAtomicJson(path.join(asyncDir, "status.json"), terminalStatus);
@@ -14,6 +14,7 @@
14
14
  ## rotom changes
15
15
 
16
16
  - `0.1.0-rotom.1`: the Evidence-Preserving Reducer records each returned reducer response (applied or rejected) as a Pi `usage` entry of kind `sol_pi_reducer`, attributed to the reducer provider/model with the provider-reported usage unchanged. Pi's footer, session stats, usage breakdown and Goal budgets then include the reducer spend. It uses `pi.appendUsage`, which the rotom Pi fork exposes from `1.3.0-rotom.2`; on Pi releases without it (upstream Pi) only the SoL-Pi journal entry is written, as before. Calls that throw before a response (timeout, unavailable model, missing auth) record no usage. Files: `evidence-preserving-reducer/{provider,journal,index}.ts`, `tests/helpers.ts`, `tests/evidence-preserving-reducer.test.ts`.
17
+ - `0.1.0-rotom.2`: an `unverifiable-quote` fallback journal entry now carries a `quoteDiagnostic` for the first rejected evidence item: `cause` (`invalid-kind`, `not-a-string`, `empty`, `too-long` or `not-in-source`), its index and the evidence count, the quote length and SHA-256, and for `not-in-source` the longest leading part found in the log with its line, plus whether the quote would match after removing ANSI escapes or collapsing whitespace. It never stores quote or log text. Acceptance is unchanged: a receipt is still rejected unless every quote appears byte for byte. Files: `evidence-preserving-reducer/{receipt,index}.ts`, `tests/evidence-preserving-reducer.test.ts`.
17
18
 
18
19
  ## How rotom uses it
19
20
 
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sol-pi",
3
- "version": "0.1.0-rotom.1",
3
+ "version": "0.1.0-rotom.2",
4
4
  "description": "rotom-maintained build of SoL-Pi: context and tool-efficiency extensions for Pi",
5
5
  "type": "module",
6
6
  "private": true,
@@ -131,6 +131,7 @@ export async function reduceToolResult(
131
131
  toolCallId: event.toolCallId,
132
132
  sourceSha256: archive.hash,
133
133
  reason: checked.reason,
134
+ quoteDiagnostic: checked.quoteDiagnostic,
134
135
  usage: provider.usage,
135
136
  });
136
137
  return undefined;
@@ -30,9 +30,30 @@ export interface ValidatedReceipt {
30
30
  readonly evidence: readonly VerifiedEvidence[];
31
31
  }
32
32
 
33
+ export type QuoteRejection = "invalid-kind" | "not-a-string" | "empty" | "too-long" | "not-in-source";
34
+
35
+ /**
36
+ * Why one evidence item was rejected, without its text: the journal may only
37
+ * hold digests, sizes and line numbers, never log or model content.
38
+ */
39
+ export interface QuoteDiagnostic {
40
+ readonly cause: QuoteRejection;
41
+ readonly evidenceIndex: number;
42
+ readonly evidenceCount: number;
43
+ readonly quoteChars?: number;
44
+ readonly quoteSha256?: string;
45
+ /** Longest leading part of the quote found in the log, and its line. */
46
+ readonly matchedPrefixChars?: number;
47
+ readonly matchedPrefixLine?: number;
48
+ /** Whether the quote would match after removing ANSI escapes from the log. */
49
+ readonly matchesWithoutAnsi?: boolean;
50
+ /** Whether the quote would match after collapsing whitespace runs in both. */
51
+ readonly matchesWithCollapsedWhitespace?: boolean;
52
+ }
53
+
33
54
  export type ReceiptValidation =
34
55
  | { readonly ok: true; readonly value: ValidatedReceipt }
35
- | { readonly ok: false; readonly reason: string };
56
+ | { readonly ok: false; readonly reason: string; readonly quoteDiagnostic?: QuoteDiagnostic };
36
57
 
37
58
  export function reducerInstructions(): string {
38
59
  return [
@@ -74,6 +95,50 @@ function lineNumberOf(body: string, quote: string): number | undefined {
74
95
  return line;
75
96
  }
76
97
 
98
+ const ALLOWED_KINDS = new Set<EvidenceKind>(["fatal", "failure", "warning", "target", "summary"]);
99
+ const ANSI_ESCAPE = /\u001b\[[0-9;?]*[ -/]*[@-~]/gu;
100
+
101
+ function collapseWhitespace(value: string): string {
102
+ return value.replace(/\s+/gu, " ").trim();
103
+ }
104
+
105
+ function quoteRejection(kind: unknown, quote: unknown, body: string): QuoteRejection | undefined {
106
+ if (typeof kind !== "string" || !ALLOWED_KINDS.has(kind as EvidenceKind)) return "invalid-kind";
107
+ if (typeof quote !== "string") return "not-a-string";
108
+ if (quote.length < 1) return "empty";
109
+ if (quote.length > MAX_QUOTE_CHARS) return "too-long";
110
+ if (!body.includes(quote)) return "not-in-source";
111
+ return undefined;
112
+ }
113
+
114
+ function quoteDiagnostic(
115
+ cause: QuoteRejection,
116
+ quote: unknown,
117
+ body: string,
118
+ evidenceIndex: number,
119
+ evidenceCount: number,
120
+ ): QuoteDiagnostic {
121
+ const base = { cause, evidenceIndex, evidenceCount };
122
+ if (typeof quote !== "string") return base;
123
+ const sized = { ...base, quoteChars: quote.length, quoteSha256: sha256(quote) };
124
+ if (cause !== "not-in-source") return sized;
125
+ // Prefix presence is monotonic, so a binary search finds the longest one.
126
+ let found = 0;
127
+ let missing = quote.length;
128
+ while (missing - found > 1) {
129
+ const middle = Math.floor((found + missing) / 2);
130
+ if (body.includes(quote.slice(0, middle))) found = middle;
131
+ else missing = middle;
132
+ }
133
+ return {
134
+ ...sized,
135
+ matchedPrefixChars: found,
136
+ matchedPrefixLine: found > 0 ? lineNumberOf(body, quote.slice(0, found)) : undefined,
137
+ matchesWithoutAnsi: body.replace(ANSI_ESCAPE, "").includes(quote),
138
+ matchesWithCollapsedWhitespace: collapseWhitespace(body).includes(collapseWhitespace(quote)),
139
+ };
140
+ }
141
+
77
142
  /**
78
143
  * Accept a receipt only when every claim in it can be checked against the
79
144
  * archived log: right schema, right source hash, status that matches the
@@ -104,31 +169,29 @@ export function validateReceipt(
104
169
  ) {
105
170
  return { ok: false, reason: "schema-mismatch" };
106
171
  }
107
- const allowedKinds = new Set<EvidenceKind>(["fatal", "failure", "warning", "target", "summary"]);
108
172
  const evidence: VerifiedEvidence[] = [];
109
173
  const seen = new Set<string>();
110
- for (const item of evidenceValue) {
174
+ for (const [index, item] of evidenceValue.entries()) {
111
175
  const kind = recordValue(item, "kind");
112
176
  const quote = recordValue(item, "quote");
113
- if (
114
- typeof kind !== "string" ||
115
- !allowedKinds.has(kind as EvidenceKind) ||
116
- typeof quote !== "string" ||
117
- quote.length < 1 ||
118
- quote.length > MAX_QUOTE_CHARS ||
119
- !body.includes(quote)
120
- ) {
121
- return { ok: false, reason: "unverifiable-quote" };
177
+ const rejection = quoteRejection(kind, quote, body);
178
+ if (rejection !== undefined) {
179
+ return {
180
+ ok: false,
181
+ reason: "unverifiable-quote",
182
+ quoteDiagnostic: quoteDiagnostic(rejection, quote, body, index, evidenceValue.length),
183
+ };
122
184
  }
123
185
  const evidenceKind = kind as EvidenceKind;
124
- const key = `${evidenceKind}\0${quote}`;
186
+ const evidenceQuote = quote as string;
187
+ const key = `${evidenceKind}\0${evidenceQuote}`;
125
188
  if (seen.has(key)) continue;
126
189
  seen.add(key);
127
190
  evidence.push({
128
191
  kind: evidenceKind,
129
- line: lineNumberOf(body, quote),
130
- quote,
131
- quoteSha256: sha256(quote),
192
+ line: lineNumberOf(body, evidenceQuote),
193
+ quote: evidenceQuote,
194
+ quoteSha256: sha256(evidenceQuote),
132
195
  });
133
196
  }
134
197
  // A failing log that reads as a failure must carry failure evidence, or the
@@ -10,8 +10,8 @@
10
10
  "@juicesharp/rpiv-ask-user-question": "2.6.2",
11
11
  "@narumitw/pi-goal": "0.54.4-rotom.8",
12
12
  "pi-context-view": "0.7.1",
13
- "pi-subagents": "0.52.1-rotom.7",
14
- "sol-pi": "0.1.0-rotom.1"
13
+ "pi-subagents": "0.52.1-rotom.10",
14
+ "sol-pi": "0.1.0-rotom.2"
15
15
  }
16
16
  },
17
17
  "node_modules/@injaneity/pi-computer-use": {
@@ -142,9 +142,9 @@
142
142
  }
143
143
  },
144
144
  "node_modules/pi-subagents": {
145
- "version": "0.52.1-rotom.7",
146
- "resolved": "file:vendor/pi-subagents-0.52.1-rotom.7.tgz",
147
- "integrity": "sha512-6hbdcuDAqFSsYxlGzVptP1vbQc+x6Zxu4VAtSQVke6ZZWn+T+MWGvaLV06qATmCWo2bVfj0CNjJb8egQj96FPg==",
145
+ "version": "0.52.1-rotom.10",
146
+ "resolved": "file:vendor/pi-subagents-0.52.1-rotom.10.tgz",
147
+ "integrity": "sha512-5mXSC3zXponiWE+NP16rJ4zo1j1mHS04bbFO+fOc31RVVHA8rKvZ3nvemDOHT9qCBqINAiRcXJuhpZCNNNeoHg==",
148
148
  "license": "MIT",
149
149
  "dependencies": {
150
150
  "acorn": "8.18.0",
@@ -177,9 +177,9 @@
177
177
  }
178
178
  },
179
179
  "node_modules/sol-pi": {
180
- "version": "0.1.0-rotom.1",
181
- "resolved": "file:vendor/sol-pi-0.1.0-rotom.1.tgz",
182
- "integrity": "sha512-t4h2lPg0ktcA4oyiBwKJur13Noc5pfYUhV5lXkRuoPV3CQ/Bf1oYil8zIgz8rBB5vMrYXUn6zRhDQg+S/VljAw==",
180
+ "version": "0.1.0-rotom.2",
181
+ "resolved": "file:vendor/sol-pi-0.1.0-rotom.2.tgz",
182
+ "integrity": "sha512-9SOaxYtxnfbnU+IByPpz8dmk95eDsGs4dvi1sq9i2g3VrGxIok0sGatlhPLhiOUgETWZyRBtRHULCm+yZiOu2g==",
183
183
  "license": "MIT",
184
184
  "engines": {
185
185
  "node": ">=22.19.0"
@@ -7,7 +7,7 @@
7
7
  "@juicesharp/rpiv-ask-user-question": "2.6.2",
8
8
  "@narumitw/pi-goal": "0.54.4-rotom.8",
9
9
  "pi-context-view": "0.7.1",
10
- "pi-subagents": "0.52.1-rotom.7",
11
- "sol-pi": "0.1.0-rotom.1"
10
+ "pi-subagents": "0.52.1-rotom.10",
11
+ "sol-pi": "0.1.0-rotom.2"
12
12
  }
13
13
  }