@code-yeongyu/senpi 2026.11.2-3 → 2026.11.3-1

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 (169) hide show
  1. package/CHANGELOG.md +28 -0
  2. package/dist/bundle/chunks/{anthropic-messages-WUPLDYD6.js → anthropic-messages-AFWQB3KN.js} +1 -1
  3. package/dist/bundle/chunks/{args-AOI4NEA6.js → args-O3WS4WCO.js} +1 -1
  4. package/dist/bundle/chunks/{chunk-O4GRBX4R.js → chunk-3WJ2DE2G.js} +1 -1
  5. package/dist/bundle/chunks/{chunk-LMIETUPG.js → chunk-4BF4FLT6.js} +1 -1
  6. package/dist/bundle/chunks/{chunk-T5ZJ2Q4O.js → chunk-4SENPCEA.js} +1 -1
  7. package/dist/bundle/chunks/chunk-5DZD623T.js +448 -0
  8. package/dist/bundle/chunks/{chunk-TXOR5BQL.js → chunk-6BSMXZKQ.js} +1 -1
  9. package/dist/bundle/chunks/{chunk-VRWJJMHO.js → chunk-7565XQAU.js} +1 -1
  10. package/dist/bundle/chunks/{chunk-IWM5QRAE.js → chunk-7KLEFHSU.js} +1 -1
  11. package/dist/bundle/chunks/{chunk-FO56LSUK.js → chunk-BNIZP4OS.js} +1 -1
  12. package/dist/bundle/chunks/{chunk-L3V65XW7.js → chunk-CJWSQ6CK.js} +1 -1
  13. package/dist/bundle/chunks/{chunk-QLTQ3UUI.js → chunk-DAPBNRN5.js} +1 -1
  14. package/dist/bundle/chunks/{chunk-GIY7PGOH.js → chunk-DPBPO5OU.js} +1 -1
  15. package/dist/bundle/chunks/chunk-ESQBKTNG.js +2 -0
  16. package/dist/bundle/chunks/{chunk-N4TSAHRL.js → chunk-EVTTLPIY.js} +1 -1
  17. package/dist/bundle/chunks/{chunk-NYXXKS6D.js → chunk-F4OHTL2K.js} +3 -2
  18. package/dist/bundle/chunks/{chunk-TVMW2SUP.js → chunk-FJ2UCBOA.js} +2 -2
  19. package/dist/bundle/chunks/{chunk-KVPRQ5KN.js → chunk-FLM6GZPT.js} +1 -1
  20. package/dist/bundle/chunks/{chunk-P4AT7SBE.js → chunk-HBCNDC53.js} +1 -1
  21. package/dist/bundle/chunks/chunk-MOH5HOHX.js +2 -0
  22. package/dist/bundle/chunks/{chunk-7FUO655J.js → chunk-MOOFLKLI.js} +1 -1
  23. package/dist/bundle/chunks/{chunk-IHOQR7TU.js → chunk-PX7FF5LE.js} +1 -1
  24. package/dist/bundle/chunks/{chunk-QAM6AXA2.js → chunk-QTQ3ES2S.js} +12 -9
  25. package/dist/bundle/chunks/{chunk-FJSJUVQQ.js → chunk-TOOB6OLG.js} +3 -3
  26. package/dist/bundle/chunks/{chunk-662SCMTH.js → chunk-VPDQ6MOL.js} +1 -1
  27. package/dist/bundle/chunks/{chunk-BW4YXS7X.js → chunk-WCRNJYHO.js} +1 -1
  28. package/dist/bundle/chunks/{chunk-ZSVWKOAJ.js → chunk-ZNLCKKF6.js} +170 -226
  29. package/dist/bundle/chunks/{cli-main-534A3WSC.js → cli-main-XM5FWY3Z.js} +1 -1
  30. package/dist/bundle/chunks/{credential-accounts-OAK2E5O2.js → credential-accounts-YZYSKA7X.js} +1 -1
  31. package/dist/bundle/chunks/{health-write-EB4CPHXN.js → health-write-45CX64T2.js} +1 -1
  32. package/dist/bundle/chunks/{help-fast-path-U2PSNNWO.js → help-fast-path-3EDGRKQM.js} +1 -1
  33. package/dist/bundle/chunks/{host-command-WJIMRBGN.js → host-command-PZ4VYQIW.js} +1 -1
  34. package/dist/bundle/chunks/{host-session-command-PWVPQ2OV.js → host-session-command-OJFARE5Q.js} +1 -1
  35. package/dist/bundle/chunks/{interactive-mode-NPHFDPGH.js → interactive-mode-7JSJVVIS.js} +1 -1
  36. package/dist/bundle/chunks/{login-health-7G2DZVOV.js → login-health-YOPTYRTU.js} +1 -1
  37. package/dist/bundle/chunks/{main-I6FJAFUP.js → main-3YGJ2O4I.js} +1 -1
  38. package/dist/bundle/chunks/{multi-session-host-7E26R5JF.js → multi-session-host-N2RQ7JSZ.js} +4 -4
  39. package/dist/bundle/chunks/openai-chatgpt.js +1 -1
  40. package/dist/bundle/chunks/{openai-codex-responses-VNBMMIL3.js → openai-codex-responses-YTWLG4OL.js} +1 -1
  41. package/dist/bundle/chunks/{openai-completions-JLR32APM.js → openai-completions-TIFDYHZL.js} +1 -1
  42. package/dist/bundle/chunks/{openai-images-LEBNERSM.js → openai-images-OAEMY4RG.js} +1 -1
  43. package/dist/bundle/chunks/{openai-responses-JCDUNMHA.js → openai-responses-L35NIG5Y.js} +1 -1
  44. package/dist/bundle/chunks/{package-manager-cli-CBSDV36M.js → package-manager-cli-JPNA27E5.js} +1 -1
  45. package/dist/bundle/chunks/{role-LP6LVNCY.js → role-45Y7PQFC.js} +1 -1
  46. package/dist/bundle/chunks/{rotation-stream-ZDCNHIBE.js → rotation-stream-WXWJKJZN.js} +1 -1
  47. package/dist/bundle/chunks/{rpc-mode-GBBTN2WP.js → rpc-mode-Z7MN2ZWA.js} +1 -1
  48. package/dist/bundle/chunks/{run-attached-tui-PVLUHHJX.js → run-attached-tui-TI6MELEI.js} +1 -1
  49. package/dist/bundle/chunks/{schedule-command-W45NYTTK.js → schedule-command-OZ5ESMIT.js} +1 -1
  50. package/dist/bundle/chunks/{session-control-endpoint-LFLUNALC.js → session-control-endpoint-5YKBYJOO.js} +1 -1
  51. package/dist/bundle/chunks/{session-picker-OZUINLD7.js → session-picker-CMRV72VA.js} +1 -1
  52. package/dist/bundle/chunks/session-worker.js +324 -376
  53. package/dist/bundle/chunks/{state-store-SZARKD36.js → state-store-Q47AYMRI.js} +1 -1
  54. package/dist/bundle/cli.js +2 -2
  55. package/dist/bundle/index.js +1 -1
  56. package/dist/bundle/rpc-entry.js +1 -1
  57. package/dist/bundle/runtime-manifest.json +1 -1
  58. package/dist/core/agent-session.d.ts +8 -0
  59. package/dist/core/agent-session.js +68 -60
  60. package/dist/core/credential-pool/classify.d.ts +3 -2
  61. package/dist/core/credential-pool/classify.js +10 -3
  62. package/dist/core/dynamic-prompt/build.d.ts +2 -1
  63. package/dist/core/dynamic-prompt/build.js +1 -2
  64. package/dist/core/dynamic-prompt/handoff.d.ts +1 -1
  65. package/dist/core/dynamic-prompt/handoff.js +9 -9
  66. package/dist/core/dynamic-prompt/identity.js +1 -1
  67. package/dist/core/dynamic-prompt/intent-gate.d.ts +1 -1
  68. package/dist/core/dynamic-prompt/intent-gate.js +8 -8
  69. package/dist/core/dynamic-prompt/policies.d.ts +1 -1
  70. package/dist/core/dynamic-prompt/policies.js +5 -7
  71. package/dist/core/dynamic-prompt/style.js +5 -5
  72. package/dist/core/dynamic-prompt/tool-section.d.ts +5 -0
  73. package/dist/core/dynamic-prompt/tool-section.js +8 -6
  74. package/dist/core/dynamic-prompt/verification.d.ts +6 -6
  75. package/dist/core/dynamic-prompt/verification.js +12 -12
  76. package/dist/core/dynamic-prompt/working-task.d.ts +1 -1
  77. package/dist/core/dynamic-prompt/working-task.js +3 -3
  78. package/dist/core/dynamic-prompt/workstation.js +1 -1
  79. package/dist/core/extensions/builtin/anthropic-subscription/session-registry-pump.d.ts +13 -0
  80. package/dist/core/extensions/builtin/anthropic-subscription/session-registry-pump.js +64 -2
  81. package/dist/core/extensions/builtin/anthropic-subscription/session-stream.js +5 -1
  82. package/dist/core/extensions/builtin/anthropic-subscription/session-turn-attempt.d.ts +7 -0
  83. package/dist/core/extensions/builtin/anthropic-subscription/session-turn-attempt.js +28 -1
  84. package/dist/core/extensions/builtin/anthropic-subscription/session-turn-types.d.ts +2 -0
  85. package/dist/core/extensions/builtin/bash-timeout/index.d.ts +1 -1
  86. package/dist/core/extensions/builtin/bash-timeout/index.js +3 -28
  87. package/dist/core/extensions/builtin/bash-timeout/timeout.d.ts +0 -11
  88. package/dist/core/extensions/builtin/bash-timeout/timeout.js +0 -11
  89. package/dist/core/extensions/builtin/imagegen/index.d.ts +0 -1
  90. package/dist/core/extensions/builtin/imagegen/index.js +0 -11
  91. package/dist/core/extensions/builtin/prompt-preset/execution-tooling.d.ts +5 -5
  92. package/dist/core/extensions/builtin/prompt-preset/execution-tooling.js +5 -5
  93. package/dist/core/extensions/builtin/prompt-preset/glm-5.d.ts +1 -1
  94. package/dist/core/extensions/builtin/prompt-preset/glm-5.js +1 -1
  95. package/dist/core/extensions/builtin/terminal/extension.js +8 -1
  96. package/dist/core/extensions/builtin/terminal/notify.js +9 -3
  97. package/dist/core/extensions/builtin/terminal/prompt.d.ts +7 -1
  98. package/dist/core/extensions/builtin/terminal/prompt.js +27 -60
  99. package/dist/core/extensions/builtin/terminal/tools/bash.js +10 -2
  100. package/dist/core/extensions/builtin/todotools/normalize.d.ts +20 -3
  101. package/dist/core/extensions/builtin/todotools/normalize.js +251 -5
  102. package/dist/core/extensions/builtin/todotools/prompt.d.ts +2 -2
  103. package/dist/core/extensions/builtin/todotools/prompt.js +5 -5
  104. package/dist/core/extensions/builtin/todotools/tools/todo.js +9 -8
  105. package/dist/core/extensions/builtin/webfetch/webfetch/tool.js +0 -5
  106. package/dist/core/extensions/builtin/websearch/index.js +9 -4
  107. package/dist/core/extensions/builtin/websearch/websearch/tool.d.ts +2 -0
  108. package/dist/core/extensions/builtin/websearch/websearch/tool.js +3 -1
  109. package/dist/core/model-runtime.js +1 -1
  110. package/dist/core/provider-failure.d.ts +6 -0
  111. package/dist/core/provider-failure.js +6 -2
  112. package/dist/core/retry-fallback/exhaustion.d.ts +18 -0
  113. package/dist/core/retry-fallback/exhaustion.js +20 -0
  114. package/dist/core/system-prompt.js +1 -1
  115. package/dist/core/tools/bash.d.ts +3 -1
  116. package/dist/core/tools/bash.js +14 -4
  117. package/dist/core/tools/edit.d.ts +1 -1
  118. package/dist/core/tools/edit.js +1 -6
  119. package/dist/core/tools/grep/index.js +2 -3
  120. package/dist/core/tools/powershell.d.ts +1 -1
  121. package/dist/core/tools/powershell.js +1 -1
  122. package/dist/core/tools/read.d.ts +1 -1
  123. package/dist/core/tools/read.js +1 -1
  124. package/dist/core/tools/write.d.ts +1 -1
  125. package/dist/core/tools/write.js +1 -1
  126. package/dist/engine-trust/shell-trust.d.ts +36 -0
  127. package/dist/engine-trust/shell-trust.js +44 -0
  128. package/dist/engine-trust/transport-failure.d.ts +12 -0
  129. package/dist/engine-trust/transport-failure.js +48 -0
  130. package/dist/modes/interactive/interactive-mode.js +9 -3
  131. package/dist/modes/print-mode.js +2 -1
  132. package/dist/modes/rpc/compact-catalog-families.d.ts +5 -2
  133. package/dist/modes/rpc/compact-catalog-families.js +5 -2
  134. package/dist/modes/rpc/compact-catalog-registry.d.ts +9 -1
  135. package/dist/modes/rpc/compact-catalog-registry.js +9 -2
  136. package/dist/modes/rpc/compact-recovery-manifest-kinds.d.ts +17 -0
  137. package/dist/modes/rpc/compact-recovery-manifest-kinds.js +21 -0
  138. package/dist/modes/rpc/compact-recovery-manifest-shape.d.ts +7 -0
  139. package/dist/modes/rpc/compact-recovery-manifest.js +11 -3
  140. package/dist/modes/rpc/compact-socket-commands.js +6 -0
  141. package/dist/modes/rpc/connection-handler.js +21 -5
  142. package/dist/modes/rpc/connection-question-bridge.d.ts +3 -1
  143. package/dist/modes/rpc/connection-question-bridge.js +4 -1
  144. package/dist/modes/rpc/connection-roles.d.ts +8 -0
  145. package/dist/modes/rpc/connection-roles.js +18 -0
  146. package/dist/modes/rpc/method-classes-schema-session.d.ts +4 -0
  147. package/dist/modes/rpc/method-classes-schema-session.js +1 -0
  148. package/dist/modes/rpc/method-classes-schema.d.ts +4 -0
  149. package/dist/modes/rpc/protocol-identity.js +2 -0
  150. package/dist/modes/rpc/remote-origin.d.ts +31 -0
  151. package/dist/modes/rpc/remote-origin.js +58 -0
  152. package/dist/modes/rpc/rpc-protocol-info-types.d.ts +8 -0
  153. package/dist/modes/rpc/rpc-question-types.d.ts +7 -0
  154. package/dist/modes/rpc/rpc-question-types.js +0 -3
  155. package/dist/modes/rpc/rpc-session-command-types.d.ts +3 -0
  156. package/dist/modes/rpc/session-registry.js +12 -3
  157. package/dist/modes/rpc/session-worker-client.js +2 -0
  158. package/dist/modes/rpc/session-worker-protocol.d.ts +3 -0
  159. package/dist/modes/rpc/session-worker.js +2 -0
  160. package/docs/engine-socket/fixtures/admission-routes/c-baseline.json +3 -3
  161. package/docs/engine-socket/fixtures/admission-routes/h-legacy.json +1 -1
  162. package/docs/engine-socket/fixtures/admission-routes/i-reset-stream.json +3 -3
  163. package/docs/engine-socket/fixtures/recovery-manifest/index.json +32 -0
  164. package/docs/engine-socket/fixtures/recovery-manifest/one-partial-family.json +118 -0
  165. package/docs/rpc.md +93 -3
  166. package/package.json +6 -6
  167. package/dist/bundle/chunks/chunk-7UC4W2T2.js +0 -2
  168. package/dist/bundle/chunks/chunk-R23WXN4L.js +0 -448
  169. package/dist/bundle/chunks/chunk-W5NLCRB3.js +0 -2
@@ -1,8 +1,5 @@
1
- import { isAnthropicBashEnabled } from "../anthropic-bash/index.js";
2
- import { isEvalOnlyRouting } from "../eval-only-routing.js";
3
- import { resolveForegroundWindowSeconds } from "../terminal/tools/foreground-window.js";
4
- import { applyBashTimeout, buildBashTimeoutPrompt, resolveBashTimeoutDefaults, } from "./timeout.js";
5
- export { applyBashTimeout, BASH_DEFAULT_TIMEOUT_SECONDS, BASH_MAX_TIMEOUT_SECONDS, buildBashTimeoutPrompt, resolveBashTimeoutDefaults, } from "./timeout.js";
1
+ import { applyBashTimeout, resolveBashTimeoutDefaults } from "./timeout.js";
2
+ export { applyBashTimeout, BASH_DEFAULT_TIMEOUT_SECONDS, resolveBashTimeoutDefaults } from "./timeout.js";
6
3
  export default function bashTimeoutExtension(pi) {
7
4
  const env = typeof process !== "undefined" ? process.env : {};
8
5
  const defaults = resolveBashTimeoutDefaults(env);
@@ -17,28 +14,6 @@ export default function bashTimeoutExtension(pi) {
17
14
  input.timeout = timeout;
18
15
  }
19
16
  });
20
- /**
21
- * Native Anthropic bash replaces the PTY `bash` tool and the terminal
22
- * extension steps aside with it, so nothing implements the auto-detach the
23
- * policy would otherwise advertise.
24
- */
25
- const resolveWindow = (ctx) => {
26
- if (isAnthropicBashEnabled() && ctx?.model?.api === "anthropic-messages")
27
- return undefined;
28
- return resolveForegroundWindowSeconds(env);
29
- };
30
- pi.on("before_agent_start", async (event, ctx) => {
31
- // A session with no `bash` tool has nothing this policy can describe. A host that exposes
32
- // only the handler surface (no getAllTools) keeps the policy, as the terminal section does.
33
- if (typeof pi.getAllTools === "function" && !pi.getAllTools().some((tool) => tool.name === "bash")) {
34
- return undefined;
35
- }
36
- const foregroundWindowSeconds = resolveWindow(ctx);
37
- const prompt = buildBashTimeoutPrompt(defaults, {
38
- ...(foregroundWindowSeconds === undefined ? {} : { foregroundWindowSeconds }),
39
- evalOnly: isEvalOnlyRouting(pi),
40
- });
41
- return { systemPrompt: `${event.systemPrompt}${prompt}` };
42
- }, { previewSafe: true });
17
+ // The timeout facts reach the model through the terminal section (senpi#5335); this extension adds no prompt text.
43
18
  }
44
19
  //# sourceMappingURL=index.js.map
@@ -12,16 +12,5 @@ export interface BashToolInputLike {
12
12
  [key: string]: unknown;
13
13
  }
14
14
  export declare function applyBashTimeout<TInput extends BashToolInputLike>(input: TInput, defaults: BashTimeoutDefaults): TInput;
15
- export interface BashTimeoutPromptOptions {
16
- /**
17
- * `undefined` when no PTY bash tool is live (native Anthropic bash replaces
18
- * it). Nothing implements auto-detach then, so the policy must not promise
19
- * it — a prompt that describes impossible behavior is worse than a silent one.
20
- */
21
- readonly foregroundWindowSeconds?: number;
22
- /** True when the session routes shell tools through eval cells, so the call shape must be `tool.bash(`. */
23
- readonly evalOnly?: boolean;
24
- }
25
- export declare function buildBashTimeoutPrompt(defaults: BashTimeoutDefaults, options?: BashTimeoutPromptOptions): string;
26
15
  export {};
27
16
  //# sourceMappingURL=timeout.d.ts.map
@@ -22,15 +22,4 @@ export function applyBashTimeout(input, defaults) {
22
22
  }
23
23
  return input;
24
24
  }
25
- export function buildBashTimeoutPrompt(defaults, options = {}) {
26
- const { foregroundWindowSeconds, evalOnly = false } = options;
27
- const subject = evalOnly
28
- ? "Shell commands run from an eval cell as `tool.bash({ command, timeout })`; its `timeout` parameter"
29
- : "The `bash` tool's `timeout` parameter";
30
- const minutes = (seconds) => (seconds % 60 === 0 ? `${seconds / 60} min` : `${seconds}s`);
31
- const detachRules = foregroundWindowSeconds === undefined
32
- ? ""
33
- : `\n- Foreground blocking stops at the ~${foregroundWindowSeconds}s window. A command still running then auto-detaches alive to a background session with a \`bash_id\` and keeps running until it exits or hits the kill deadline; the session tools in the terminal section steer or stop it.`;
34
- return `\n## Bash Tool Timeout Policy\n\n${subject} is the process kill deadline, not how long you wait for output: the command is killed when it reaches the deadline.\n\n- Default timeout: ${defaults.defaultSeconds}s (${minutes(defaults.defaultSeconds)}). Applied automatically when you do not set \`timeout\`.\n- Recommended maximum timeout: ${defaults.maxSeconds}s (${minutes(defaults.maxSeconds)}). Explicit \`timeout\` values are preserved because different hosts may use different timeout units.${detachRules}`;
35
- }
36
25
  //# sourceMappingURL=timeout.js.map
@@ -1,5 +1,4 @@
1
1
  import type { ExtensionAPI } from "../../types.ts";
2
- export declare const IMAGE_GEN_SECTION = "\n## Image Generation\n\nWhen image generation tooling is present, read the gpt-image-gen skill before generating.\nUse the image generation tool currently available in this session.\n";
3
2
  export declare function registerImageGenExtension(pi: ExtensionAPI, baseDir?: string): void;
4
3
  export default function imageGenExtension(pi: ExtensionAPI): void;
5
4
  //# sourceMappingURL=index.d.ts.map
@@ -7,12 +7,6 @@ import { imageGenRegistryOverride } from "./state.js";
7
7
  import { generateImageTool } from "./tool.js";
8
8
  const IMAGEGEN_BASE_DIR = dirname(fileURLToPath(import.meta.url));
9
9
  let loggedMissingSkill = false;
10
- export const IMAGE_GEN_SECTION = `
11
- ## Image Generation
12
-
13
- When image generation tooling is present, read the gpt-image-gen skill before generating.
14
- Use the image generation tool currently available in this session.
15
- `;
16
10
  async function isImageGenActive(ctx) {
17
11
  const auth = await resolveImageGenAuth({ modelRegistry: imageGenRegistryOverride() ?? ctx.modelRegistry });
18
12
  return auth.kind !== "none";
@@ -54,11 +48,6 @@ export function registerImageGenExtension(pi, baseDir = IMAGEGEN_BASE_DIR) {
54
48
  const skillPath = await bundledSkillPath(baseDir);
55
49
  return skillPath === undefined ? undefined : { skillPaths: [skillPath] };
56
50
  });
57
- pi.on("before_agent_start", async (event, ctx) => {
58
- if (!(await isImageGenActive(ctx)))
59
- return undefined;
60
- return { systemPrompt: `${event.systemPrompt}\n${IMAGE_GEN_SECTION}` };
61
- }, { previewSafe: true });
62
51
  }
63
52
  export default function imageGenExtension(pi) {
64
53
  registerImageGenExtension(pi);
@@ -10,28 +10,28 @@ export declare const EXECUTION_TOOLING_RULES: readonly [{
10
10
  readonly id: "eval-routing-decision";
11
11
  readonly concern: "code-cell-routing";
12
12
  readonly directive: {
13
- readonly claude: "Sort a multi-call step before you write it: independent reads, searches, symbol lookups, and probes go into ONE `eval` cell together via `parallel(thunks)` - an extra read-only call in that wave is nearly free, a stale assumption costs the turn - while edits, side-effecting commands, deploys, approvals, and any call whose input is a result you have not seen yet run one at a time, each observed before the next.";
13
+ readonly claude: "Sort each multi-call step first: independent reads/searches/symbol lookups/probes -> ONE `eval` cell via `parallel(thunks)`. Edits, side effects, deploys, approvals, any call fed by an unseen result -> one at a time, observe each before next.";
14
14
  readonly kimi: "Sort a multi-call step before you write it: put independent reads, searches, symbol lookups, and probes into one `eval` cell together with `parallel(thunks)`, and run edits, side-effecting commands, deploys, approvals, and any call that depends on a result you have not seen yet one at a time, looking at each result before the next.";
15
15
  };
16
16
  }, {
17
17
  readonly id: "eval-evidence-return";
18
18
  readonly concern: "code-cell-routing";
19
19
  readonly directive: {
20
- readonly claude: "Name the state a cell should produce before running it; when it returns, COMPARE the returned evidence with that state, and for a cell that changed something also check that nothing changed beyond it. A result that hides a failed item or a truncated tail is not evidence.";
21
- readonly kimi: "Name the state a cell should produce before running it; when it returns, compare the returned evidence with that state, and for a cell that changed something also check that nothing changed beyond it. A result that hides a failed item or a truncated tail is not evidence.";
20
+ readonly claude: "Name expected state before running a cell; on return COMPARE evidence to it; for a mutating cell also confirm nothing changed beyond it.";
21
+ readonly kimi: "Name the state a cell should produce before running it; when it returns, compare the returned evidence with that state, and for a cell that changed something also check that nothing changed beyond it.";
22
22
  };
23
23
  }, {
24
24
  readonly id: "perceived-state-loop";
25
25
  readonly concern: "code-cell-routing";
26
26
  readonly directive: {
27
- readonly claude: "When the result must be SEEN rather than read - a page, a component, an image, a 3D scene, a layout - make one change, render or screenshot it, look, then make the next; check a 3D scene from several angles and a page at desktop and mobile widths. Compare what you see with the reference or the stated intent, and ask only where two readings of that intent diverge.";
27
+ readonly claude: "Result must be SEEN (page, component, image, 3D scene, layout): one change -> render/screenshot -> look -> next. 3D: several angles. Page: desktop + mobile widths. Compare to reference or stated intent; ask only where two readings of intent diverge.";
28
28
  readonly kimi: "When the result must be seen rather than read - a page, a component, an image, a 3D scene, a layout - make one change, render or screenshot it, look, then make the next; check a 3D scene from several angles and a page at desktop and mobile widths. Compare what you see with the reference or the stated intent, and ask only where two readings of that intent diverge.";
29
29
  };
30
30
  }, {
31
31
  readonly id: "eval-stay-direct";
32
32
  readonly concern: "code-cell-routing";
33
33
  readonly directive: {
34
- readonly claude: "Call a tool directly only when one call is enough, the result decides the next call, semantic judgment sits between calls, or the action needs approval.";
34
+ readonly claude: "Direct tool call only when: one call suffices, result decides next call, semantic judgment sits between calls, or action needs approval.";
35
35
  readonly kimi: "Use a direct tool call when one call is enough, when each result decides the next call, or when the action needs approval - then stop deliberating and make it.";
36
36
  };
37
37
  }];
@@ -29,7 +29,7 @@ export const EXECUTION_TOOLING_RULES = [
29
29
  id: "eval-routing-decision",
30
30
  concern: "code-cell-routing",
31
31
  directive: {
32
- claude: "Sort a multi-call step before you write it: independent reads, searches, symbol lookups, and probes go into ONE `eval` cell together via `parallel(thunks)` - an extra read-only call in that wave is nearly free, a stale assumption costs the turn - while edits, side-effecting commands, deploys, approvals, and any call whose input is a result you have not seen yet run one at a time, each observed before the next.",
32
+ claude: "Sort each multi-call step first: independent reads/searches/symbol lookups/probes -> ONE `eval` cell via `parallel(thunks)`. Edits, side effects, deploys, approvals, any call fed by an unseen result -> one at a time, observe each before next.",
33
33
  kimi: "Sort a multi-call step before you write it: put independent reads, searches, symbol lookups, and probes into one `eval` cell together with `parallel(thunks)`, and run edits, side-effecting commands, deploys, approvals, and any call that depends on a result you have not seen yet one at a time, looking at each result before the next.",
34
34
  },
35
35
  },
@@ -37,15 +37,15 @@ export const EXECUTION_TOOLING_RULES = [
37
37
  id: "eval-evidence-return",
38
38
  concern: "code-cell-routing",
39
39
  directive: {
40
- claude: "Name the state a cell should produce before running it; when it returns, COMPARE the returned evidence with that state, and for a cell that changed something also check that nothing changed beyond it. A result that hides a failed item or a truncated tail is not evidence.",
41
- kimi: "Name the state a cell should produce before running it; when it returns, compare the returned evidence with that state, and for a cell that changed something also check that nothing changed beyond it. A result that hides a failed item or a truncated tail is not evidence.",
40
+ claude: "Name expected state before running a cell; on return COMPARE evidence to it; for a mutating cell also confirm nothing changed beyond it.",
41
+ kimi: "Name the state a cell should produce before running it; when it returns, compare the returned evidence with that state, and for a cell that changed something also check that nothing changed beyond it.",
42
42
  },
43
43
  },
44
44
  {
45
45
  id: "perceived-state-loop",
46
46
  concern: "code-cell-routing",
47
47
  directive: {
48
- claude: "When the result must be SEEN rather than read - a page, a component, an image, a 3D scene, a layout - make one change, render or screenshot it, look, then make the next; check a 3D scene from several angles and a page at desktop and mobile widths. Compare what you see with the reference or the stated intent, and ask only where two readings of that intent diverge.",
48
+ claude: "Result must be SEEN (page, component, image, 3D scene, layout): one change -> render/screenshot -> look -> next. 3D: several angles. Page: desktop + mobile widths. Compare to reference or stated intent; ask only where two readings of intent diverge.",
49
49
  kimi: "When the result must be seen rather than read - a page, a component, an image, a 3D scene, a layout - make one change, render or screenshot it, look, then make the next; check a 3D scene from several angles and a page at desktop and mobile widths. Compare what you see with the reference or the stated intent, and ask only where two readings of that intent diverge.",
50
50
  },
51
51
  },
@@ -53,7 +53,7 @@ export const EXECUTION_TOOLING_RULES = [
53
53
  id: "eval-stay-direct",
54
54
  concern: "code-cell-routing",
55
55
  directive: {
56
- claude: "Call a tool directly only when one call is enough, the result decides the next call, semantic judgment sits between calls, or the action needs approval.",
56
+ claude: "Direct tool call only when: one call suffices, result decides next call, semantic judgment sits between calls, or action needs approval.",
57
57
  kimi: "Use a direct tool call when one call is enough, when each result decides the next call, or when the action needs approval - then stop deliberating and make it.",
58
58
  },
59
59
  },
@@ -1,4 +1,4 @@
1
1
  import { type BuildDynamicSystemPromptOptions } from "../../../dynamic-prompt/build.ts";
2
- export declare const GLM5_TUNING = "A cheap tool call beats long internal debate: when reading, running, or searching can settle a question, do that and reason over the result. Work in short act-inspect-verify loops so an early mistake surfaces before later steps build on it; when only the user can settle a question, ask through ask_user_question when it is available (waitForAnswer true when the next step depends on the answer).";
2
+ export declare const GLM5_TUNING = "Cheap tool call beats long internal debate: reading/running/searching can settle it -> do that, reason over result. Short act-inspect-verify loops so early mistakes surface before later steps build on them. Only the user can settle it -> ask_user_question when available.";
3
3
  export declare function buildGlm5Prompt(options: BuildDynamicSystemPromptOptions): string;
4
4
  //# sourceMappingURL=glm-5.d.ts.map
@@ -1,6 +1,6 @@
1
1
  import { buildDynamicSystemPrompt } from "../../../dynamic-prompt/build.js";
2
2
  import { buildExecutionToolingSection } from "./execution-tooling.js";
3
- export const GLM5_TUNING = "A cheap tool call beats long internal debate: when reading, running, or searching can settle a question, do that and reason over the result. Work in short act-inspect-verify loops so an early mistake surfaces before later steps build on it; when only the user can settle a question, ask through ask_user_question when it is available (waitForAnswer true when the next step depends on the answer).";
3
+ export const GLM5_TUNING = "Cheap tool call beats long internal debate: reading/running/searching can settle it -> do that, reason over result. Short act-inspect-verify loops so early mistakes surface before later steps build on them. Only the user can settle it -> ask_user_question when available.";
4
4
  export function buildGlm5Prompt(options) {
5
5
  return buildDynamicSystemPrompt({
6
6
  ...options,
@@ -2,6 +2,7 @@ import { join } from "node:path";
2
2
  import { encodedSessionId } from "../../../session-sidecar-store.js";
3
3
  import { SettingsManager } from "../../../settings-manager.js";
4
4
  import { isAnthropicBashEnabled } from "../anthropic-bash/index.js";
5
+ import { resolveBashTimeoutDefaults } from "../bash-timeout/timeout.js";
5
6
  import { isEvalOnlyRouting } from "../eval-only-routing.js";
6
7
  import { buildToolContext, bundleSinks, createBundle, sessionKeyOf, } from "./extension-state.js";
7
8
  import { currentLeaseToken, releaseTerminalLease, retireLeaseToken } from "./manifest-lease.js";
@@ -24,6 +25,7 @@ import { createBashOutputTool } from "./tools/bash-output.js";
24
25
  import { createBashResizeTool } from "./tools/bash-resize.js";
25
26
  import { TERMINAL_CHILD_JOB_KINDS, terminalChildJob } from "./tools/child-placement.js";
26
27
  import { createKillBashTool } from "./tools/kill-bash.js";
28
+ import { resolveForegroundWindowSeconds } from "./tools/foreground-window.js";
27
29
  import { bindTerminalManifestWriter, createMonitorTool } from "./tools/monitor.js";
28
30
  /**
29
31
  * Only paced (persistent command) watches of a session with a durable state dir get an overflow file.
@@ -218,7 +220,12 @@ export function registerTerminalExtension(pi) {
218
220
  });
219
221
  pi.on("before_agent_start", async (event) => {
220
222
  return {
221
- systemPrompt: `${event.systemPrompt}\n${buildTerminalPromptSection({ evalOnly: isEvalOnlyRouting(pi), ptyBash: !state.steppedAside })}`,
223
+ systemPrompt: `${event.systemPrompt}\n${buildTerminalPromptSection({
224
+ evalOnly: isEvalOnlyRouting(pi),
225
+ ptyBash: !state.steppedAside,
226
+ foregroundWindowSeconds: resolveForegroundWindowSeconds(process.env),
227
+ defaultTimeoutSeconds: resolveBashTimeoutDefaults(process.env).defaultSeconds,
228
+ })}`,
222
229
  };
223
230
  }, { previewSafe: true });
224
231
  pi.on("session_shutdown", async (event, ctx) => {
@@ -1,3 +1,4 @@
1
+ import { annotateShellTrust } from "../../../../engine-trust/shell-trust.js";
1
2
  import { withTerminalContext } from "./context-lifetime.js";
2
3
  import { sanitizeTerminalOutput } from "./output-format.js";
3
4
  import { describeExit } from "./tools/spawn.js";
@@ -26,7 +27,7 @@ export function getTerminalNotificationDelivery(deps, customType = TERMINAL_NOTI
26
27
  }),
27
28
  };
28
29
  }
29
- function buildNotice(id, runtime) {
30
+ function buildNotice(id, runtime, trustText) {
30
31
  const status = describeExit(runtime) ?? "exited";
31
32
  const code = runtime.exitResult?.exitCode;
32
33
  const codeText = code === null || code === undefined ? "" : ` (exit code ${code})`;
@@ -40,7 +41,8 @@ function buildNotice(id, runtime) {
40
41
  : "";
41
42
  tailSection = `\nFinal output:\n${shown}${note}`;
42
43
  }
43
- return `<system-reminder>Background terminal session ${id} finished: ${status}${codeText}.${tailSection}</system-reminder>`;
44
+ const trustSection = trustText === undefined ? "" : `\n${trustText}`;
45
+ return `<system-reminder>Background terminal session ${id} finished: ${status}${codeText}.${tailSection}${trustSection}</system-reminder>`;
44
46
  }
45
47
  /**
46
48
  * Notifies an interactive agent once when a background session completes.
@@ -68,7 +70,11 @@ export class TerminalNotifier {
68
70
  if (!delivery)
69
71
  return;
70
72
  this.notified.add(id);
71
- delivery.send(buildNotice(id, runtime));
73
+ const annotation = annotateShellTrust({
74
+ exitCode: runtime.exitResult?.exitCode ?? null,
75
+ output: runtime.fullOutput(),
76
+ });
77
+ delivery.send(buildNotice(id, runtime, annotation?.text), annotation === undefined ? undefined : { details: { trust: annotation.trust } });
72
78
  }
73
79
  }
74
80
  //# sourceMappingURL=notify.js.map
@@ -3,6 +3,10 @@ export interface TerminalPromptOptions {
3
3
  readonly evalOnly: boolean;
4
4
  /** Native bash replaces PTY bash, but monitor and its terminal companions remain available. */
5
5
  readonly ptyBash?: boolean;
6
+ /** Seconds a foreground `bash` call blocks before it auto-detaches (`PI_BASH_FOREGROUND_SECONDS`). */
7
+ readonly foregroundWindowSeconds?: number;
8
+ /** `timeout` applied when a `bash` call sets none (`PI_BASH_DEFAULT_TIMEOUT_SECONDS`). */
9
+ readonly defaultTimeoutSeconds?: number;
6
10
  }
7
11
  /**
8
12
  * System-prompt guidance for the persistent-terminal tool suite (CC-close, snake_case).
@@ -11,7 +15,9 @@ export interface TerminalPromptOptions {
11
15
  * `eval` tool, so their call shapes are rendered per branch: a hardcoded direct shape
12
16
  * would teach a call the model cannot make. The steering companions
13
17
  * (`bash_output`/`bash_input`/`bash_resize`/`kill_bash`) stay callable by name in both; `bash_input` and
14
- * `bash_resize` are search-exposed and activate on that first call (senpi#4446).
18
+ * `bash_resize` are search-exposed and activate on that first call (senpi#4446). This section is also
19
+ * the one home of the bash timeout facts (kill deadline, default, foreground auto-detach); the separate
20
+ * timeout policy section folded into it (senpi#5335).
15
21
  */
16
22
  export declare function buildTerminalPromptSection(options: TerminalPromptOptions): string;
17
23
  //# sourceMappingURL=prompt.d.ts.map
@@ -1,3 +1,5 @@
1
+ import { BASH_DEFAULT_TIMEOUT_SECONDS } from "../bash-timeout/timeout.js";
2
+ import { DEFAULT_FOREGROUND_WINDOW_SECONDS } from "./tools/foreground-window.js";
1
3
  /**
2
4
  * System-prompt guidance for the persistent-terminal tool suite (CC-close, snake_case).
3
5
  *
@@ -5,74 +7,39 @@
5
7
  * `eval` tool, so their call shapes are rendered per branch: a hardcoded direct shape
6
8
  * would teach a call the model cannot make. The steering companions
7
9
  * (`bash_output`/`bash_input`/`bash_resize`/`kill_bash`) stay callable by name in both; `bash_input` and
8
- * `bash_resize` are search-exposed and activate on that first call (senpi#4446).
10
+ * `bash_resize` are search-exposed and activate on that first call (senpi#4446). This section is also
11
+ * the one home of the bash timeout facts (kill deadline, default, foreground auto-detach); the separate
12
+ * timeout policy section folded into it (senpi#5335).
9
13
  */
10
14
  export function buildTerminalPromptSection(options) {
15
+ const ptyBash = options.ptyBash !== false;
11
16
  const bash = options.evalOnly ? "tool.bash" : "bash";
12
17
  const monitor = options.evalOnly ? "tool.monitor" : "monitor";
13
- const bashGuidance = options.ptyBash === false
18
+ const window = options.foregroundWindowSeconds ?? DEFAULT_FOREGROUND_WINDOW_SECONDS;
19
+ const defaultTimeout = options.defaultTimeoutSeconds ?? BASH_DEFAULT_TIMEOUT_SECONDS;
20
+ const evalOnlyReach = !options.evalOnly
14
21
  ? ""
15
- : `The \`bash\` tool is PTY-backed. For long-running or interactive work, do NOT use tmux or
16
- manual \`&\` backgrounding; use the built-in session tools:
17
-
18
- - \`${bash}({ command, run_in_background: true })\` starts a persistent session and returns a
19
- \`bash_id\` immediately. Foreground calls still block and return output; their \`timeout\`
20
- (seconds) is a kill deadline. Background sessions ignore \`timeout\` and live until they
21
- exit or you call \`kill_bash\`. Backgrounding is not a session: a plain \`&\` job dies with the
22
- call's PTY hangup (native backend), \`nohup\` at best leaves an untracked orphan (no \`bash_id\`,
23
- no log) that the call's timeout still group-kills; only \`run_in_background\` creates a
24
- session that outlives the call.
25
- `;
22
+ : ptyBash
23
+ ? '`bash`, `monitor`: eval-only, call as `tool.bash({ command })` / `tool.monitor(...)`; params via `tool_schema("bash")` / `tool_schema("monitor")`. '
24
+ : '`monitor`: eval-only, call as `tool.monitor(...)`; params via `tool_schema("monitor")`. ';
25
+ const bashGuidance = ptyBash
26
+ ? `\`bash\` = PTY. Never tmux, plain \`&\`, or \`nohup\` (PTY hangup or call timeout kills them). Only \`${bash}({ command, run_in_background: true })\` -> session outliving the call, returns \`bash_id\`. Foreground call blocks ~${window}s then auto-detaches alive to background. \`timeout\` (seconds, default ${defaultTimeout}) = process kill deadline, not output wait; background sessions ignore it.`
27
+ : "";
28
+ const opening = `${evalOnlyReach}${bashGuidance}`.trimEnd();
29
+ const longerJob = ptyBash
30
+ ? "longer job: `run_in_background` + watch only"
31
+ : "longer job: `persistent: true` + stop via `kill_bash`";
26
32
  return `
27
33
  ## Persistent terminal sessions
28
34
 
29
- ${bashGuidance}- \`bash_output({ bash_id, filter, view })\` peeks at a session without blocking: new output
30
- since the last read, the status line, or a rendered full-screen snapshot of TUIs via
31
- \`view: "screen"\`. Completion arrives as a notification carrying the exit code and output
32
- tail: peeking is for steering, never for waiting.
33
- - For observable state (CI checks, builds, log patterns, deploys, files or other sessions),
34
- register \`${monitor}\` and keep working instead of foreground sleeping/polling or repeatedly
35
- calling \`bash_output\`. Sleep loops belong inside the monitor command.
36
- - \`${monitor}\` subscribes you to a change. Pass exactly one source (\`command\`, \`path\` or
37
- \`target\`; one branch per call, never two):
38
- - \`${monitor}({ description, command, filter?, timeout_ms?, persistent? })\` watches a command:
39
- newline-terminated PTY output lines (stderr included) matching \`filter\` arrive as injected
40
- events while you keep working; command exit always delivers a summary. \`timeout_ms\` is
41
- that watch's own deadline: it KILLS the watched command when it fires (the summary says
42
- \`killed at deadline\`); ${options.ptyBash === false
43
- ? "for longer jobs, set `persistent: true` and stop with `kill_bash`."
44
- : "for longer jobs, start with `run_in_background` and only watch them."} One-shot gate: wait
45
- inside the command and print one sentinel (\`until <cond>; do sleep 1; done;
46
- printf 'READY\\n'\`) with \`filter: "^READY$"\`. Stream: \`tail -n 0 -F <log> | grep --line-buffered <pat>\`
47
- with \`persistent: true\`. Filter noise at the
48
- source and stop with \`kill_bash\`. Persistent command watches are re-run after a restart with
49
- \`SENPI_MONITOR_RESTORED=1\`; keep any baseline in \`$SENPI_MONITOR_STATE_DIR\` so a move during
50
- downtime (at most \`$SENPI_MONITOR_DOWNTIME_MS\` ms) is still reported:
51
- \`b="$SENPI_MONITOR_STATE_DIR/base"; p=$(cat "$b" 2>/dev/null || git rev-parse origin/main | tee "$b"); while sleep 30; do git fetch -q || true; n=$(git rev-parse origin/main); [ "$n" != "$p" ] && { echo "MOVED $p..$n"; p=$n; echo "$p" > "$b"; }; done\`.
52
- A watch whose command exits is not restarted, so keep failures inside the loop non-fatal.
53
- - \`${monitor}({ description, path, event?, persistent? })\` natively watches one regular file and
54
- fires once: prefer it over a shell poll loop. \`"create"\` (the default) fires only when the file
55
- appears after registration, so watch an already-existing file with \`"modify"\`; registration needs
56
- the parent directory to exist already, so poll with a \`command\` when the run creates that
57
- directory too. This branch takes no \`filter\`.
58
- - \`${monitor}({ type: "rpc", target, description, events?, exclude?, filter?, persistent? })\` watches other
59
- sessions over every RPC host and terminal: \`target: "children"\` (sessions you spawned, including
60
- later ones), \`"all"\`, or one session id, path or \`st_\` task id. The result lists each matched
61
- session as it is now; then each status change (\`rpc <label> status running -> idle ...\`) and
62
- effect receipt arrives as an event. \`events: "all"\` adds their content, streaming collapsed to one
63
- line per 2 s; \`exclude\` drops kinds. Watching never attaches to a session.
64
- A standing watch is marked \`persistent: true\`: it has no deadline, survives a session restart
65
- (the file is rescanned and any change missed while detached reported), expires 7 days after
66
- creation, has no per-session cap unless the \`terminal.maxDurableMonitors\` setting sets one,
67
- and is accounted for in one restart-report line on session start.
68
- Identical updates are deduped; repeated monitor-only wakes pause the noisy monitor(s) that
69
- caused them, not all monitors. Completion still wakes the session, and
70
- \`${monitor}({ action: "rearm", bash_id })\` resumes one while \`${monitor}({ action: "rearm" })\`
71
- resumes all paused monitors; real user input also resumes paused monitors.
72
- - \`bash_input({ bash_id, input, keys, submit })\` sends stdin or named keys (e.g.
73
- \`["ctrl+c"]\`, \`["enter"]\`) to steer a REPL or interrupt a process.
74
- - \`bash_resize({ bash_id, cols, rows })\` resizes the PTY so full-screen programs reflow.
75
- - \`kill_bash({ bash_id })\` (or \`{ all: true }\`) tears the session tree down with no orphans.
35
+ ${opening ? `${opening}\n\n` : ""}- \`bash_output({ bash_id, filter, view })\`: non-blocking peek (new output / status line / \`view: "screen"\` for TUI). Completion = notification with exit code + tail. Peek to steer, never to wait.
36
+ - Waiting on observable state (CI, build, log pattern, deploy, file, other session): register \`${monitor}\`, keep working. No sleep/poll in cells, no repeated \`bash_output\`; sleep loops live inside monitor command. Exactly one source per call:
37
+ - \`${monitor}({ description, command, filter?, timeout_ms?, persistent? })\`: lines matching \`filter\` -> events; exit -> summary. \`timeout_ms\` KILLS watched command; ${longerJob}. One-shot gate: \`until <cond>; do sleep 1; done; printf 'READY\\n'\` + \`filter: "^READY$"\`. Stream: \`tail -n 0 -F <log> | grep --line-buffered <pat>\` + \`persistent: true\`. Filter noise at source; stop via \`kill_bash\`.
38
+ - \`${monitor}({ description, path, event?, persistent? })\`: one regular file, parent dir must exist, fires once, no \`filter\`. \`"create"\` (default) fires only for a file that appears after registration; existing file -> \`event: "modify"\`; run creates the dir too -> \`command\` poll.
39
+ - \`${monitor}({ type: "rpc", target, description, events?, exclude?, filter?, persistent? })\`: \`target\` = \`"children"\` / \`"all"\` / one session id, path, \`st_\` id. Status changes + effect receipts -> events; \`events: "all"\` adds content; \`exclude\` drops kinds.
40
+ - \`persistent: true\`: no deadline, survives restart (command re-run with \`SENPI_MONITOR_RESTORED=1\`, file rescanned), expires 7 days. Baseline in \`$SENPI_MONITOR_STATE_DIR\` so a move during downtime (<= \`$SENPI_MONITOR_DOWNTIME_MS\` ms) still reported. Loop failures non-fatal: exited watch not restarted.
41
+ - Repeated monitor-only wakes pause that noisy monitor only. \`${monitor}({ action: "rearm", bash_id })\` resumes one; \`${monitor}({ action: "rearm" })\` all. Completion and real user input also resume.
42
+ - \`bash_input({ bash_id, input, keys, submit })\`: stdin or keys (\`["ctrl+c"]\`, \`["enter"]\`). \`bash_resize({ bash_id, cols, rows })\`: reflow TUI. \`kill_bash({ bash_id })\` / \`{ all: true }\`: tear down session tree.
76
43
  `;
77
44
  }
78
45
  //# sourceMappingURL=prompt.js.map
@@ -1,4 +1,5 @@
1
1
  import { Type } from "typebox";
2
+ import { annotateShellTrust } from "../../../../../engine-trust/shell-trust.js";
2
3
  import { formatTerminalToolOutput } from "../output-format.js";
3
4
  import { BACKGROUND_START_GRACE_MS, DEFAULT_COLS, DEFAULT_ROWS, FOREGROUND_ENV_OVERRIDES, KILLED_SESSION_EXIT_GRACE_MS, TERMINAL_BASH_TOOL, } from "../shared.js";
4
5
  import { errorResult, noticedResult, textResult, } from "./context.js";
@@ -317,7 +318,14 @@ async function runForeground(ctx, input, cols, rows, signal, cwd, onUpdate, exec
317
318
  }
318
319
  const status = describeExit(runtime);
319
320
  if (exit && exit.exitCode !== 0 && exit.exitCode !== null) {
320
- return errorResult(`${output ? `${output}\n\n` : ""}Command exited with code ${exit.exitCode}`);
321
+ const text = `${output ? `${output}\n\n` : ""}Command exited with code ${exit.exitCode}`;
322
+ const annotation = annotateShellTrust({ exitCode: exit.exitCode, output: runtime.fullOutput() });
323
+ if (annotation === undefined)
324
+ return errorResult(text);
325
+ return textResult(annotation.text === undefined ? text : `${text}\n\n${annotation.text}`, {
326
+ details: { trust: annotation.trust },
327
+ isError: true,
328
+ });
321
329
  }
322
330
  return noticedResult(output || "(no output)", [formatted.marker], {
323
331
  details: {
@@ -357,7 +365,7 @@ export function createPtyBashTool(ctx) {
357
365
  label: "bash",
358
366
  description: "Execute a shell command in a persistent PTY-backed session. Set run_in_background:true for long-lived or interactive sessions; steer them with bash_input, snapshot with bash_output, tear down with kill_bash. To wait on observable state (a build finishing, a server coming up, a log line), never run sleep or poll loops: subscribe with the monitor tool instead. Foreground blocking stops at the ~60s window and a still-running command auto-detaches to a live background session; `timeout` is the process kill deadline in seconds.",
359
367
  promptSnippet: "Run shell commands; run_in_background:true for long-lived/interactive PTY sessions",
360
- promptGuidelines: ["You can inspect PI_* environment variables for current model and session details."],
368
+ promptGuidelines: ["PI_* env vars = current model + session details."],
361
369
  parameters: ptyBashSchema,
362
370
  async execute(_toolCallId, input, signal, onUpdate, execCtx) {
363
371
  const cols = resolveDimension(input.cols, ctx.defaultCols || DEFAULT_COLS);
@@ -1,10 +1,27 @@
1
- import type { TodoOpEntry, TodoPhase } from "./todo-types.ts";
1
+ import { type TodoOpEntry, type TodoPhase } from "./todo-types.ts";
2
2
  export type TodoNormalization = {
3
3
  entry?: TodoOpEntry;
4
4
  corrections: string[];
5
5
  error?: string;
6
6
  };
7
- /** The todo tool's `prepareArguments`: returns the arguments with `list` unwrapped to its canonical shape. */
8
- export declare function prepareTodoArguments(args: unknown): unknown;
7
+ /**
8
+ * The todo tool's `prepareArguments`: rewrites near-canonical shapes (senpi#5148 wrappers,
9
+ * senpi#5332 list/op corrections) to the canonical one before schema validation. Any call a
10
+ * rule does not correct is returned as the SAME reference, and a correction that would leave
11
+ * `list` empty is abandoned entirely so the malformed call still fails validation instead of
12
+ * clearing the todo list. A caller-sent `TODO_PREPARED_CORRECTIONS_KEY` is never trusted
13
+ * (senpi#5332): it is dropped on a copy before any rule runs, and when that removal is the
14
+ * only change the stripped copy is returned instead of the same reference.
15
+ */
16
+ export declare function prepareTodoArguments(input: unknown): unknown;
17
+ /**
18
+ * Splits the prepare-time correction notices off prepared arguments (see
19
+ * `TODO_PREPARED_CORRECTIONS_KEY`): the arguments without the reserved key, plus the notices
20
+ * to prepend to `normalizeTodoParams`'s own corrections.
21
+ */
22
+ export declare function splitPreparedCorrections(args: Record<string, unknown>): {
23
+ args: Record<string, unknown>;
24
+ corrections: string[];
25
+ };
9
26
  export declare function normalizeTodoParams(raw: Record<string, unknown>, currentPhases: readonly TodoPhase[]): TodoNormalization;
10
27
  //# sourceMappingURL=normalize.d.ts.map