@selesai/code 0.8.6 → 0.8.8

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 (234) hide show
  1. package/CHANGELOG.md +31 -1
  2. package/dist/cli/args.d.ts +1 -0
  3. package/dist/cli/args.js +11 -0
  4. package/dist/cli/args.test.d.ts +1 -0
  5. package/dist/cli/args.test.js +24 -0
  6. package/dist/core/agent-session.d.ts +4 -1
  7. package/dist/core/agent-session.js +18 -7
  8. package/dist/core/experimental.d.ts +4 -0
  9. package/dist/core/experimental.js +4 -0
  10. package/dist/core/extensions/types.d.ts +6 -0
  11. package/dist/core/keybindings.d.ts +24 -0
  12. package/dist/core/model-config.d.ts +5 -0
  13. package/dist/core/model-config.js +1 -0
  14. package/dist/core/project-trust.js +2 -2
  15. package/dist/core/provider-composer.js +17 -4
  16. package/dist/core/sdk.d.ts +5 -3
  17. package/dist/core/sdk.js +2 -1
  18. package/dist/core/session-manager.js +2 -2
  19. package/dist/core/settings-manager.d.ts +8 -0
  20. package/dist/core/settings-manager.js +15 -0
  21. package/dist/core/system-prompt.js +3 -9
  22. package/dist/core/system-prompt.test.js +6 -0
  23. package/dist/core/tools/bash.js +2 -0
  24. package/dist/core/tools/edit.js +2 -0
  25. package/dist/core/tools/find.js +1 -1
  26. package/dist/core/tools/grep.js +1 -1
  27. package/dist/core/tools/index.d.ts +1 -0
  28. package/dist/core/tools/index.js +1 -0
  29. package/dist/core/tools/read.js +2 -0
  30. package/dist/core/tools/schema-prune.d.ts +16 -0
  31. package/dist/core/tools/schema-prune.js +39 -0
  32. package/dist/core/tools/schema-prune.test.d.ts +1 -0
  33. package/dist/core/tools/schema-prune.test.js +111 -0
  34. package/dist/core/tools/write.js +2 -0
  35. package/dist/defaults/settings.json +1 -0
  36. package/dist/extensions/model-prompt-injector/config.json +10 -0
  37. package/dist/extensions/model-prompt-injector/index.test.ts +112 -0
  38. package/dist/extensions/model-prompt-injector/index.ts +151 -0
  39. package/dist/extensions/package.json +1 -0
  40. package/dist/extensions/pi-subagents/CHANGELOG.md +158 -90
  41. package/dist/extensions/pi-subagents/UPSTREAM-V0.50-MAPPING.md +172 -0
  42. package/dist/extensions/pi-subagents/agents/oracle.md +7 -5
  43. package/dist/extensions/pi-subagents/agents/reviewer.md +2 -2
  44. package/dist/extensions/pi-subagents/agents/scout.md +1 -1
  45. package/dist/extensions/pi-subagents/agents/worker.md +1 -1
  46. package/dist/extensions/pi-subagents/docs/configuration.md +78 -19
  47. package/dist/extensions/pi-subagents/docs/extension-api.md +36 -0
  48. package/dist/extensions/pi-subagents/docs/missions.md +5 -3
  49. package/dist/extensions/pi-subagents/docs/models.md +1 -1
  50. package/dist/extensions/pi-subagents/docs/observability.md +42 -2
  51. package/dist/extensions/pi-subagents/docs/tool-reference.md +20 -3
  52. package/dist/extensions/pi-subagents/docs/workflows.md +5 -5
  53. package/dist/extensions/pi-subagents/install.mjs +2 -2
  54. package/dist/extensions/pi-subagents/package-lock.json +1470 -1472
  55. package/dist/extensions/pi-subagents/package.json +1 -1
  56. package/dist/extensions/pi-subagents/skills/pi-subagents/SKILL.md +1 -1
  57. package/dist/extensions/pi-subagents/skills/pi-subagents/references/constraints-and-recipes.md +5 -4
  58. package/dist/extensions/pi-subagents/skills/pi-subagents/references/execution-controls.md +15 -14
  59. package/dist/extensions/pi-subagents/skills/pi-subagents/references/management-authoring-rpc.md +5 -5
  60. package/dist/extensions/pi-subagents/skills/pi-subagents/references/prompting-and-roles.md +46 -26
  61. package/dist/extensions/pi-subagents/src/agents/agent-serializer.ts +2 -0
  62. package/dist/extensions/pi-subagents/src/agents/agents.ts +37 -12
  63. package/dist/extensions/pi-subagents/src/api/external-runs.ts +174 -84
  64. package/dist/extensions/pi-subagents/src/api/preflight.ts +13 -7
  65. package/dist/extensions/pi-subagents/src/extension/config.ts +53 -0
  66. package/dist/extensions/pi-subagents/src/extension/index.ts +67 -13
  67. package/dist/extensions/pi-subagents/src/extension/public-execution.ts +34 -6
  68. package/dist/extensions/pi-subagents/src/extension/rpc.ts +5 -1
  69. package/dist/extensions/pi-subagents/src/extension/schemas.ts +31 -30
  70. package/dist/extensions/pi-subagents/src/extension/tool-description.ts +10 -9
  71. package/dist/extensions/pi-subagents/src/inspectors/herdr/actions.ts +13 -8
  72. package/dist/extensions/pi-subagents/src/inspectors/herdr/inspector-runner.ts +16 -3
  73. package/dist/extensions/pi-subagents/src/inspectors/herdr/project-panes.ts +2 -6
  74. package/dist/extensions/pi-subagents/src/inspectors/herdr/shell-command.ts +16 -0
  75. package/dist/extensions/pi-subagents/src/intercom/intercom-bridge.ts +5 -4
  76. package/dist/extensions/pi-subagents/src/intercom/native-supervisor-channel.ts +19 -42
  77. package/dist/extensions/pi-subagents/src/missions/goal-driver.ts +3 -1
  78. package/dist/extensions/pi-subagents/src/missions/store.ts +8 -3
  79. package/dist/extensions/pi-subagents/src/runs/background/active-async-capacity.ts +82 -25
  80. package/dist/extensions/pi-subagents/src/runs/background/active-run-index.ts +71 -1
  81. package/dist/extensions/pi-subagents/src/runs/background/async-execution.ts +73 -43
  82. package/dist/extensions/pi-subagents/src/runs/background/async-job-tracker.ts +5 -0
  83. package/dist/extensions/pi-subagents/src/runs/background/async-resume.ts +14 -6
  84. package/dist/extensions/pi-subagents/src/runs/background/async-status-snapshot.ts +277 -0
  85. package/dist/extensions/pi-subagents/src/runs/background/async-status.ts +8 -3
  86. package/dist/extensions/pi-subagents/src/runs/background/chain-root-attachment.ts +2 -2
  87. package/dist/extensions/pi-subagents/src/runs/background/completion-replay.ts +11 -1
  88. package/dist/extensions/pi-subagents/src/runs/background/fleet-view.ts +21 -6
  89. package/dist/extensions/pi-subagents/src/runs/background/result-files.ts +437 -0
  90. package/dist/extensions/pi-subagents/src/runs/background/result-watcher.ts +187 -41
  91. package/dist/extensions/pi-subagents/src/runs/background/resume-guidance.ts +27 -7
  92. package/dist/extensions/pi-subagents/src/runs/background/retained-children.ts +76 -19
  93. package/dist/extensions/pi-subagents/src/runs/background/run-id-resolver.ts +30 -24
  94. package/dist/extensions/pi-subagents/src/runs/background/run-status.ts +101 -4
  95. package/dist/extensions/pi-subagents/src/runs/background/scheduled-runs.ts +54 -28
  96. package/dist/extensions/pi-subagents/src/runs/background/stale-run-reconciler.ts +27 -13
  97. package/dist/extensions/pi-subagents/src/runs/background/subagent-runner.ts +298 -33
  98. package/dist/extensions/pi-subagents/src/runs/background/subagent-wait.ts +2 -0
  99. package/dist/extensions/pi-subagents/src/runs/background/wait-completions.ts +5 -2
  100. package/dist/extensions/pi-subagents/src/runs/foreground/async-dismiss-action.ts +2 -1
  101. package/dist/extensions/pi-subagents/src/runs/foreground/chain-execution.ts +16 -0
  102. package/dist/extensions/pi-subagents/src/runs/foreground/execution.ts +219 -15
  103. package/dist/extensions/pi-subagents/src/runs/foreground/prompt-audit.ts +4 -3
  104. package/dist/extensions/pi-subagents/src/runs/foreground/subagent-executor.ts +333 -45
  105. package/dist/extensions/pi-subagents/src/runs/shared/completion-guard.ts +107 -1
  106. package/dist/extensions/pi-subagents/src/runs/shared/external-cli-runner.ts +4 -0
  107. package/dist/extensions/pi-subagents/src/runs/shared/llm-intent-arbiter.ts +39 -23
  108. package/dist/extensions/pi-subagents/src/runs/shared/model-fallback.ts +16 -2
  109. package/dist/extensions/pi-subagents/src/runs/shared/nested-events.ts +66 -62
  110. package/dist/extensions/pi-subagents/src/runs/shared/orca-progress-tabs.ts +376 -0
  111. package/dist/extensions/pi-subagents/src/runs/shared/parallel-utils.ts +2 -0
  112. package/dist/extensions/pi-subagents/src/runs/shared/subagent-control.ts +15 -0
  113. package/dist/extensions/pi-subagents/src/runs/shared/subagent-prompt-runtime.ts +1 -9
  114. package/dist/extensions/pi-subagents/src/runs/shared/subagent-startup-retry.ts +12 -0
  115. package/dist/extensions/pi-subagents/src/runs/shared/tool-timeout.ts +95 -0
  116. package/dist/extensions/pi-subagents/src/shared/agent-stream-options.ts +5 -0
  117. package/dist/extensions/pi-subagents/src/shared/artifacts.ts +0 -4
  118. package/dist/extensions/pi-subagents/src/shared/display-text.ts +50 -0
  119. package/dist/extensions/pi-subagents/src/shared/node-executable.ts +21 -0
  120. package/dist/extensions/pi-subagents/src/shared/types.ts +50 -4
  121. package/dist/extensions/pi-subagents/src/slash/slash-commands.ts +34 -25
  122. package/dist/extensions/pi-subagents/src/slash/slash-live-state.ts +4 -0
  123. package/dist/extensions/pi-subagents/src/tui/fleet-status.ts +160 -45
  124. package/dist/extensions/pi-subagents/src/tui/fleet-transcript.ts +1 -48
  125. package/dist/extensions/pi-subagents/src/tui/fleet.ts +128 -16
  126. package/dist/extensions/pi-subagents/src/tui/render.ts +122 -44
  127. package/dist/extensions/pi-subagents/src/watchdog/permission-arbiter.ts +2 -1
  128. package/dist/extensions/pi-subagents/src/watchdog/review.ts +4 -3
  129. package/dist/extensions/pi-subagents/src/workflows/chat-progress.ts +10 -2
  130. package/dist/extensions/pi-subagents/src/workflows/scripted-workflow.ts +272 -76
  131. package/dist/extensions/pi-subagents/test/fixtures/pi-coding-agent-shim/dist/core/extensions/types.d.ts +2 -0
  132. package/dist/extensions/pi-subagents/test/integration/async-execution.test.ts +2 -2
  133. package/dist/extensions/pi-subagents/test/integration/async-job-tracker.test.ts +68 -9
  134. package/dist/extensions/pi-subagents/test/integration/async-status.test.ts +27 -1
  135. package/dist/extensions/pi-subagents/test/integration/chain-execution.test.ts +1 -1
  136. package/dist/extensions/pi-subagents/test/integration/error-handling.test.ts +49 -0
  137. package/dist/extensions/pi-subagents/test/integration/external-cli-runner.test.ts +1 -0
  138. package/dist/extensions/pi-subagents/test/integration/intercom-result-delivery.test.ts +26 -1
  139. package/dist/extensions/pi-subagents/test/integration/orca-progress-tabs.test.ts +144 -0
  140. package/dist/extensions/pi-subagents/test/integration/render-widget.test.ts +26 -0
  141. package/dist/extensions/pi-subagents/test/integration/result-watcher.test.ts +395 -98
  142. package/dist/extensions/pi-subagents/test/integration/single-execution.test.ts +111 -78
  143. package/dist/extensions/pi-subagents/test/integration/slash-commands.test.ts +49 -1
  144. package/dist/extensions/pi-subagents/test/integration/slash-live-state.test.ts +12 -0
  145. package/dist/extensions/pi-subagents/test/support/node-command.ts +15 -0
  146. package/dist/extensions/pi-subagents/test/unit/active-async-capacity.test.ts +50 -0
  147. package/dist/extensions/pi-subagents/test/unit/agent-frontmatter.test.ts +28 -0
  148. package/dist/extensions/pi-subagents/test/unit/agent-overrides.test.ts +61 -0
  149. package/dist/extensions/pi-subagents/test/unit/agent-stream-options.test.ts +14 -0
  150. package/dist/extensions/pi-subagents/test/unit/async-interrupt-action.test.ts +76 -0
  151. package/dist/extensions/pi-subagents/test/unit/async-resume.test.ts +2 -0
  152. package/dist/extensions/pi-subagents/test/unit/async-status-snapshot.test.ts +162 -0
  153. package/dist/extensions/pi-subagents/test/unit/completion-guard.test.ts +209 -10
  154. package/dist/extensions/pi-subagents/test/unit/completion-replay.test.ts +41 -1
  155. package/dist/extensions/pi-subagents/test/unit/external-runs.test.ts +135 -42
  156. package/dist/extensions/pi-subagents/test/unit/fleet-status.test.ts +252 -1
  157. package/dist/extensions/pi-subagents/test/unit/fleet.test.ts +192 -6
  158. package/dist/extensions/pi-subagents/test/unit/herdr-inspector-bootstrap.test.ts +32 -0
  159. package/dist/extensions/pi-subagents/test/unit/herdr-shell-command.test.ts +59 -0
  160. package/dist/extensions/pi-subagents/test/unit/index-child-registration.test.ts +69 -0
  161. package/dist/extensions/pi-subagents/test/unit/intercom-bridge.test.ts +23 -4
  162. package/dist/extensions/pi-subagents/test/unit/llm-intent-arbiter.test.ts +56 -1
  163. package/dist/extensions/pi-subagents/test/unit/mission-goal-driver.test.ts +67 -3
  164. package/dist/extensions/pi-subagents/test/unit/mission-lifecycle.test.ts +1 -1
  165. package/dist/extensions/pi-subagents/test/unit/mission-store.test.ts +14 -0
  166. package/dist/extensions/pi-subagents/test/unit/model-fallback.test.ts +18 -0
  167. package/dist/extensions/pi-subagents/test/unit/native-supervisor-channel.test.ts +2 -2
  168. package/dist/extensions/pi-subagents/test/unit/nested-events.test.ts +25 -2
  169. package/dist/extensions/pi-subagents/test/unit/node-executable.test.ts +26 -0
  170. package/dist/extensions/pi-subagents/test/unit/notify.test.ts +8 -0
  171. package/dist/extensions/pi-subagents/test/unit/orca-progress-tabs.test.ts +348 -0
  172. package/dist/extensions/pi-subagents/test/unit/package-manifest.test.ts +5 -2
  173. package/dist/extensions/pi-subagents/test/unit/pi-args.test.ts +1 -1
  174. package/dist/extensions/pi-subagents/test/unit/pi-coding-agent-dir.test.ts +34 -0
  175. package/dist/extensions/pi-subagents/test/unit/public-execution.test.ts +6 -1
  176. package/dist/extensions/pi-subagents/test/unit/render-helpers.test.ts +92 -0
  177. package/dist/extensions/pi-subagents/test/unit/result-files.test.ts +175 -0
  178. package/dist/extensions/pi-subagents/test/unit/retained-children.test.ts +127 -17
  179. package/dist/extensions/pi-subagents/test/unit/run-id-resolver.test.ts +44 -0
  180. package/dist/extensions/pi-subagents/test/unit/run-status.test.ts +247 -0
  181. package/dist/extensions/pi-subagents/test/unit/scheduled-runs.test.ts +107 -2
  182. package/dist/extensions/pi-subagents/test/unit/schemas.test.ts +5 -8
  183. package/dist/extensions/pi-subagents/test/unit/scripted-workflow.test.ts +456 -4
  184. package/dist/extensions/pi-subagents/test/unit/stale-run-reconciler.test.ts +128 -0
  185. package/dist/extensions/pi-subagents/test/unit/subagent-control.test.ts +28 -0
  186. package/dist/extensions/pi-subagents/test/unit/subagent-prompt-runtime.test.ts +16 -7
  187. package/dist/extensions/pi-subagents/test/unit/subagent-startup-retry.test.ts +15 -0
  188. package/dist/extensions/pi-subagents/test/unit/subagent-wait.test.ts +79 -15
  189. package/dist/extensions/pi-subagents/test/unit/tool-description.test.ts +12 -12
  190. package/dist/extensions/pi-subagents/test/unit/tool-timeout.test.ts +109 -0
  191. package/dist/extensions/pi-subagents/test/unit/wait-subscriptions.test.ts +34 -0
  192. package/dist/extensions/pi-subagents/test/unit/workflow-chat-progress.test.ts +94 -1
  193. package/dist/extensions/pi-subagents/test/unit/workflow-launch-params.test.ts +42 -2
  194. package/dist/extensions/question/index.ts +21 -6
  195. package/dist/extensions/question/question-list.ts +7 -1
  196. package/dist/extensions/question/row-layout.ts +3 -0
  197. package/dist/extensions/question/tests/exp.test.ts +70 -0
  198. package/dist/extensions/question/tests/exp2.test.ts +59 -0
  199. package/dist/extensions/question/tests/exp3.test.ts +47 -0
  200. package/dist/extensions/question/tests/helpers.test.ts +7 -0
  201. package/dist/extensions/question/tests/question-list.test.ts +140 -0
  202. package/dist/extensions/question/tests/row-layout.test.ts +13 -0
  203. package/dist/extensions/question/tests/selection-mode.test.ts +54 -0
  204. package/dist/extensions/question/tests/zz-ig3.test.ts +20 -0
  205. package/dist/extensions/question/tests/zz-probe.test.ts +29 -0
  206. package/dist/extensions/tokenin-onboarding.ts +1 -1
  207. package/dist/index.d.ts +1 -1
  208. package/dist/main.js +4 -0
  209. package/dist/modes/interactive/components/model-selector.js +2 -1
  210. package/dist/modes/interactive/components/settings-selector.d.ts +3 -1
  211. package/dist/modes/interactive/components/settings-selector.js +10 -0
  212. package/dist/modes/interactive/components/tool-execution.js +10 -1
  213. package/dist/modes/interactive/interactive-mode.d.ts +8 -2
  214. package/dist/modes/interactive/interactive-mode.js +81 -25
  215. package/dist/modes/interactive/model-catalog-refresh.d.ts +6 -0
  216. package/dist/modes/interactive/model-catalog-refresh.js +33 -0
  217. package/dist/modes/interactive/theme/dark.json +2 -0
  218. package/dist/modes/interactive/theme/light.json +2 -0
  219. package/dist/modes/interactive/theme/theme-controller.d.ts +10 -2
  220. package/dist/modes/interactive/theme/theme-controller.js +25 -11
  221. package/dist/modes/interactive/theme/theme-schema.json +9 -1
  222. package/dist/modes/interactive/theme/theme.d.ts +5 -3
  223. package/dist/modes/interactive/theme/theme.js +12 -2
  224. package/dist/skills/pi-subagents/SKILL.md +1 -1
  225. package/dist/skills/pi-subagents/references/constraints-and-recipes.md +5 -4
  226. package/dist/skills/pi-subagents/references/execution-controls.md +15 -14
  227. package/dist/skills/pi-subagents/references/management-authoring-rpc.md +5 -5
  228. package/dist/skills/pi-subagents/references/prompting-and-roles.md +46 -26
  229. package/dist/utils/abort.d.ts +4 -0
  230. package/dist/utils/abort.js +47 -0
  231. package/dist/utils/tools-manager.d.ts +5 -1
  232. package/dist/utils/tools-manager.js +12 -21
  233. package/docs/settings.md +6 -0
  234. package/package.json +6 -6
package/CHANGELOG.md CHANGED
@@ -2,7 +2,37 @@
2
2
 
3
3
  All notable changes to `@selesai/code` will be documented in this file.
4
4
 
5
- ## [Unreleased]
5
+ ## [0.8.8] - 2026-08-18
6
+
7
+ ### Added
8
+ - **`--use-theme <name>` CLI flag.** Sets the initial interactive theme for a run; the fullscreen theme controller applies an invocation-level theme before settings load, so the flag wins until you change the theme in `/settings`.
9
+ - **Transcript search highlighting.** The fullscreen TUI now highlights search matches live in the transcript, themeable via new optional `searchMatchBg`/`searchMatchText` colors (falling back to `selectedBg`/`text`).
10
+ - **Fullscreen exit output option.** `/settings` gained a **Fullscreen exit output** entry: exiting fullscreen can print the transcript as before (`"transcript"`) or only a session resume hint (`"resume-hint"`) via the new `fullscreenExitOutput` setting.
11
+ - **`defaultTools` setting.** Seeds the initial built-in tool selection for `createAgentSession`; when set, new sessions start with only the listed tools instead of the `read`/`bash`/`edit`/`write` default.
12
+ - **`sendUserMessage` template expansion.** Extensions can pass `expandPromptTemplates: true` to dispatch extension commands and expand skill commands/prompt templates from a sent user message.
13
+ - **Experimental strict tool sampling.** Under `PI_EXPERIMENTAL=1`, the built-in read/edit/write/bash tools request `json_schema` tool output with `strict: "prefer"`.
14
+
15
+ ### Changed
16
+ - **Managed-tool downloads moved off the startup path.** The TUI mounts and stays responsive while `fd`/`rg` install; download progress and warnings are reported as chat status lines (with an `app.tools.expand` hint) instead of raw `console.log` output, and the interactive startup accepts input (with interrupt/exit/submit feedback) while it completes.
17
+ - **Collapsed large tool output.** Tool components now preview only the first 10 lines with an inline `... (N more lines)` expand hint instead of dumping the whole block.
18
+ - **Shared model-catalog refreshes.** Concurrent interactive all-catalog refreshes reuse one in-flight refresh while keeping each caller's cancellation independent, and refreshes are bounded by a short timeout.
19
+ - **Runtime dependencies updated to Pi 0.84.2.** `@earendil-works/pi-ai`, `@earendil-works/pi-tui`, and `@earendil-works/pi-agent-core` moved to 0.84.2; `openAIResponses` model config gained an optional `supportsAdditionalTools` flag; `exportToHtml` accepts a `themeName` option.
20
+
21
+ ## [0.8.7] - 2026-08-17
22
+
23
+ ### Added
24
+ - **Pi Subagents updated through upstream 0.50.0.** The bundled extension advances through upstream 0.49/0.50 (single-child `{ agent, task }` runs, per-tool-call `toolTimeoutMs` with config/env precedence, `debug.run` inspection, builtin role overrides with `tools: "inherit"`, resumable retained-child listings, indexed async result inboxes) with the Selesai fork layers on top: branding, `.selesai` config routing, `SELESAI_SUBAGENT*` env vars, declarative `chain`/`tasks`/`clarify` modes, workflow auto-relaunch wiring, and same-model retry for transient provider errors.
25
+ - **`model-prompt-injector` extension.** Bundled and registered in the extensions manifest, it injects model-specific prompts into the system prompt when the active model matches a configured rule (provider/model globs, bare id/name patterns, first-match-wins, enabled toggle). Modes: `prepend`, `append`, or `replace`.
26
+ - **Wire-level tool schema pruning.** `pruneToolDescriptions` (default `true`) strips every per-field `description` from tool input schemas before they reach the model, keeping one-line tool descriptions. Stripped schemas are memoized and never mutated; UI/docs definitions keep full descriptions; `keepParameterDescriptions` opts a tool out.
27
+ - **Compact subagent tool description by default.** `toolDescriptionMode` now defaults to `"compact"` (~3.2 KB vs ~6.3 KB per model turn), and a missing/invalid custom description file falls back to compact.
28
+
29
+ ### Changed
30
+ - **Slimmer default system prompt.** The always-on Pi-docs block shrank from 8 lines to 2 (paths only); docs are still read on demand when the user asks about pi.
31
+ - **Bundled defaults** now set `pruneToolDescriptions: true`.
32
+ - **Test coverage.** `src/extensions` (pi-* excluded) now enforces 100% stmt/branch/func/line coverage via vitest thresholds; `safeMaxTokens()` clamps missing/oversized context-window metadata to a sane default.
33
+
34
+ ### Fixed
35
+ - **Subagent prompt-runtime suite passes inside subagent child environments.** The watchdog-lifecycle test now scrubs the steer env vars (`SELESAI_SUBAGENT_STEER_*`) before registering, so the steering inbox's extra `agent_end` handler cannot skew the handler count.
6
36
 
7
37
  ## [0.8.6] - 2026-08-15
8
38
 
@@ -37,6 +37,7 @@ export interface Args {
37
37
  promptTemplates?: string[];
38
38
  noPromptTemplates?: boolean;
39
39
  themes?: string[];
40
+ useTheme?: string;
40
41
  noThemes?: boolean;
41
42
  noContextFiles?: boolean;
42
43
  listModels?: string | true;
package/dist/cli/args.js CHANGED
@@ -142,6 +142,16 @@ export function parseArgs(args) {
142
142
  else if (arg === "--no-prompt-templates" || arg === "-np") {
143
143
  result.noPromptTemplates = true;
144
144
  }
145
+ else if (arg === "--use-theme") {
146
+ const themeName = args[i + 1];
147
+ if (themeName === undefined || themeName.startsWith("-")) {
148
+ result.diagnostics.push({ type: "error", message: "--use-theme requires a theme name" });
149
+ }
150
+ else {
151
+ result.useTheme = themeName;
152
+ i++;
153
+ }
154
+ }
145
155
  else if (arg === "--no-themes") {
146
156
  result.noThemes = true;
147
157
  }
@@ -272,6 +282,7 @@ ${chalk.bold("Options:")}
272
282
  --prompt-template <path> Load a prompt template file or directory (can be used multiple times)
273
283
  --no-prompt-templates, -np Disable prompt template discovery and loading
274
284
  --theme <path> Load a theme file or directory (can be used multiple times)
285
+ --use-theme <name[/name]> Set the initial interactive theme for this run
275
286
  --no-themes Disable theme discovery and loading
276
287
  --no-context-files, -nc Disable AGENTS.md and CLAUDE.md discovery and loading
277
288
  --export <file> Export session file to HTML and exit
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,24 @@
1
+ import { describe, expect, test } from "vitest";
2
+ import { parseArgs } from "./args.js";
3
+ describe("parseArgs --use-theme", () => {
4
+ test("parses --use-theme with a theme name", () => {
5
+ const result = parseArgs(["--use-theme", "nord-border", "hello"]);
6
+ expect(result.useTheme).toBe("nord-border");
7
+ expect(result.messages).toEqual(["hello"]);
8
+ });
9
+ test("accepts light/dark slash form", () => {
10
+ const result = parseArgs(["--use-theme", "light/dark"]);
11
+ expect(result.useTheme).toBe("light/dark");
12
+ });
13
+ test("reports an error when --use-theme is missing a theme name", () => {
14
+ const result = parseArgs(["--use-theme"]);
15
+ expect(result.useTheme).toBeUndefined();
16
+ expect(result.diagnostics.some((d) => d.type === "error")).toBe(true);
17
+ });
18
+ test("reports an error when --use-theme precedes a flag", () => {
19
+ const result = parseArgs(["--use-theme", "--no-session"]);
20
+ expect(result.useTheme).toBeUndefined();
21
+ expect(result.noSession).toBe(true);
22
+ expect(result.diagnostics.some((d) => d.type === "error")).toBe(true);
23
+ });
24
+ });
@@ -423,6 +423,7 @@ export declare class AgentSession {
423
423
  */
424
424
  sendUserMessage(content: string | (TextContent | ImageContent)[], options?: {
425
425
  deliverAs?: "steer" | "followUp";
426
+ expandPromptTemplates?: boolean;
426
427
  }): Promise<void>;
427
428
  /**
428
429
  * Clear all queued messages and return them.
@@ -634,7 +635,9 @@ export declare class AgentSession {
634
635
  * @param outputPath Optional output path (defaults to session directory)
635
636
  * @returns Path to exported file
636
637
  */
637
- exportToHtml(outputPath?: string): Promise<string>;
638
+ exportToHtml(outputPath?: string, options?: {
639
+ themeName?: string;
640
+ }): Promise<string>;
638
641
  /**
639
642
  * Export the current session branch to a JSONL file.
640
643
  * Writes the session header followed by all entries on the current branch path.
@@ -35,7 +35,7 @@ import { CURRENT_SESSION_VERSION, getLatestCompactionEntry } from "./session-man
35
35
  import { createSyntheticSourceInfo } from "./source-info.js";
36
36
  import { buildSystemPrompt } from "./system-prompt.js";
37
37
  import { createLocalBashOperations } from "./tools/bash.js";
38
- import { createAllToolDefinitions } from "./tools/index.js";
38
+ import { createAllToolDefinitions, stripToolParameterDescriptions } from "./tools/index.js";
39
39
  import { createToolDefinitionFromAgentTool } from "./tools/tool-definition-wrapper.js";
40
40
  import { addUsageToTotals, createUsageTotals } from "./usage-totals.js";
41
41
  /** Parse consecutive skill blocks at the start of a user message. */
@@ -1133,7 +1133,7 @@ export class AgentSession {
1133
1133
  if (options?.deliverAs === "nextTurn") {
1134
1134
  this._pendingNextTurnMessages.push(appMessage);
1135
1135
  }
1136
- else if (this.isStreaming) {
1136
+ else if (this.isStreaming && options?.triggerTurn !== false) {
1137
1137
  if (options?.deliverAs === "followUp") {
1138
1138
  this.agent.followUp(appMessage);
1139
1139
  }
@@ -1180,9 +1180,9 @@ export class AgentSession {
1180
1180
  if (images.length === 0)
1181
1181
  images = undefined;
1182
1182
  }
1183
- // Use prompt() with expandPromptTemplates: false to skip command handling and template expansion
1183
+ // Use prompt() with expandPromptTemplates to control command handling and template expansion
1184
1184
  await this.prompt(text, {
1185
- expandPromptTemplates: false,
1185
+ expandPromptTemplates: options?.expandPromptTemplates ?? false,
1186
1186
  streamingBehavior: options?.deliverAs,
1187
1187
  images,
1188
1188
  source: "extension",
@@ -2056,6 +2056,18 @@ export class AgentSession {
2056
2056
  toolRegistry.set(tool.name, tool);
2057
2057
  }
2058
2058
  this._toolRegistry = toolRegistry;
2059
+ if (this.settingsManager.getPruneToolDescriptions()) {
2060
+ const keepDescriptions = new Set();
2061
+ for (const [name, entry] of definitionRegistry) {
2062
+ if (entry.definition.keepParameterDescriptions)
2063
+ keepDescriptions.add(name);
2064
+ }
2065
+ for (const [name, tool] of toolRegistry) {
2066
+ if (!keepDescriptions.has(name)) {
2067
+ toolRegistry.set(name, stripToolParameterDescriptions(tool));
2068
+ }
2069
+ }
2070
+ }
2059
2071
  const nextActiveToolNames = (options?.activeToolNames ? [...options.activeToolNames] : [...previousActiveToolNames]).filter((name) => isAllowedTool(name));
2060
2072
  if (allowedToolNames) {
2061
2073
  for (const toolName of this._toolRegistry.keys()) {
@@ -2647,9 +2659,8 @@ export class AgentSession {
2647
2659
  * @param outputPath Optional output path (defaults to session directory)
2648
2660
  * @returns Path to exported file
2649
2661
  */
2650
- async exportToHtml(outputPath) {
2651
- const configuredThemeName = this.settingsManager.getTheme();
2652
- const themeName = configuredThemeName && getThemeByName(configuredThemeName) ? configuredThemeName : undefined;
2662
+ async exportToHtml(outputPath, options = {}) {
2663
+ const themeName = [options.themeName, this.settingsManager.getTheme()].find((candidate) => candidate !== undefined && getThemeByName(candidate) !== undefined);
2653
2664
  // Create tool renderer if we have an extension runner (for custom tool HTML rendering)
2654
2665
  const toolRenderer = createToolHtmlRenderer({
2655
2666
  getToolDefinition: (name) => this.getToolDefinition(name),
@@ -1 +1,5 @@
1
1
  export declare function areExperimentalFeaturesEnabled(): boolean;
2
+ export declare function getExperimentalToolSampling(): {
3
+ readonly type: "json_schema";
4
+ readonly strict: "prefer";
5
+ } | undefined;
@@ -1,3 +1,7 @@
1
+ const PREFER_STRICT_TOOL_SAMPLING = { type: "json_schema", strict: "prefer" };
1
2
  export function areExperimentalFeaturesEnabled() {
2
3
  return process.env.PI_EXPERIMENTAL === "1";
3
4
  }
5
+ export function getExperimentalToolSampling() {
6
+ return areExperimentalFeaturesEnabled() ? PREFER_STRICT_TOOL_SAMPLING : undefined;
7
+ }
@@ -301,6 +301,7 @@ export interface ReplacedSessionContext extends ExtensionCommandContext {
301
301
  }): Promise<void>;
302
302
  sendUserMessage(content: string | (TextContent | ImageContent)[], options?: {
303
303
  deliverAs?: "steer" | "followUp";
304
+ expandPromptTemplates?: boolean;
304
305
  }): Promise<void>;
305
306
  }
306
307
  /** Rendering options for tool results */
@@ -353,6 +354,8 @@ export interface ToolDefinition<TParams extends TSchema = TSchema, TDetails = un
353
354
  promptGuidelines?: string[];
354
355
  /** Parameter schema (TypeBox) */
355
356
  parameters: TParams;
357
+ /** When global pruneToolDescriptions is enabled, keep this tool's per-field parameter descriptions on the wire (already pruned by the tool itself). */
358
+ keepParameterDescriptions?: boolean;
356
359
  /** Optional provider-side constrained sampling request for this tool. Set false to explicitly disable it, equivalent to leaving it undefined. */
357
360
  constrainedSampling?: false | ConstrainedSamplingConfig;
358
361
  /** Controls whether ToolExecutionComponent renders the standard colored shell or the tool renders its own framing. */
@@ -924,9 +927,11 @@ export interface ExtensionAPI {
924
927
  /**
925
928
  * Send a user message to the agent. Always triggers a turn.
926
929
  * When the agent is streaming, use deliverAs to specify how to queue the message.
930
+ * Set expandPromptTemplates to dispatch extension commands and expand skill commands and prompt templates.
927
931
  */
928
932
  sendUserMessage(content: string | (TextContent | ImageContent)[], options?: {
929
933
  deliverAs?: "steer" | "followUp";
934
+ expandPromptTemplates?: boolean;
930
935
  }): void;
931
936
  /** Append a custom entry to the session for state persistence (not sent to LLM). */
932
937
  appendEntry<T = unknown>(customType: string, data?: T): void;
@@ -1122,6 +1127,7 @@ export type SendMessageHandler = <T = unknown>(message: Pick<CustomMessage<T>, "
1122
1127
  }) => void;
1123
1128
  export type SendUserMessageHandler = (content: string | (TextContent | ImageContent)[], options?: {
1124
1129
  deliverAs?: "steer" | "followUp";
1130
+ expandPromptTemplates?: boolean;
1125
1131
  }) => void;
1126
1132
  export type AppendEntryHandler = <T = unknown>(customType: string, data?: T) => void;
1127
1133
  export type SetSessionNameHandler = (name: string) => void;
@@ -197,6 +197,14 @@ export declare const KEYBINDINGS: {
197
197
  readonly defaultKeys: [];
198
198
  readonly description: "Scroll viewport down half a page";
199
199
  };
200
+ readonly "tui.altScreen.lineUp": {
201
+ readonly defaultKeys: [];
202
+ readonly description: "Scroll viewport up one line";
203
+ };
204
+ readonly "tui.altScreen.lineDown": {
205
+ readonly defaultKeys: [];
206
+ readonly description: "Scroll viewport down one line";
207
+ };
200
208
  readonly "tui.altScreen.previousPrompt": {
201
209
  readonly defaultKeys: "ctrl+shift+up";
202
210
  readonly description: "Jump to previous semantic prompt";
@@ -205,6 +213,22 @@ export declare const KEYBINDINGS: {
205
213
  readonly defaultKeys: "ctrl+shift+down";
206
214
  readonly description: "Jump to next semantic prompt";
207
215
  };
216
+ readonly "tui.altScreen.search": {
217
+ readonly defaultKeys: "ctrl+shift+f";
218
+ readonly description: "Search the primary scroll view";
219
+ };
220
+ readonly "tui.altScreen.searchNext": {
221
+ readonly defaultKeys: ["enter", "ctrl+g"];
222
+ readonly description: "Select the next search match";
223
+ };
224
+ readonly "tui.altScreen.searchPrevious": {
225
+ readonly defaultKeys: ["shift+enter", "ctrl+shift+g"];
226
+ readonly description: "Select the previous search match";
227
+ };
228
+ readonly "tui.altScreen.searchClose": {
229
+ readonly defaultKeys: "escape";
230
+ readonly description: "Close transcript search";
231
+ };
208
232
  readonly "tui.altScreen.top": {
209
233
  readonly defaultKeys: "home";
210
234
  readonly description: "Scroll viewport to top";
@@ -98,6 +98,7 @@ declare const ModelDefinitionSchema: Type.TObject<{
98
98
  supportsLongCacheRetention: Type.TOptional<Type.TBoolean>;
99
99
  supportsStrictMode: Type.TOptional<Type.TBoolean>;
100
100
  supportsOpenAIGrammarTools: Type.TOptional<Type.TBoolean>;
101
+ supportsAdditionalTools: Type.TOptional<Type.TBoolean>;
101
102
  supportsToolSearch: Type.TOptional<Type.TBoolean>;
102
103
  }>, Type.TObject<{
103
104
  supportsEagerToolInputStreaming: Type.TOptional<Type.TBoolean>;
@@ -206,6 +207,7 @@ declare const ModelOverrideSchema: Type.TObject<{
206
207
  supportsLongCacheRetention: Type.TOptional<Type.TBoolean>;
207
208
  supportsStrictMode: Type.TOptional<Type.TBoolean>;
208
209
  supportsOpenAIGrammarTools: Type.TOptional<Type.TBoolean>;
210
+ supportsAdditionalTools: Type.TOptional<Type.TBoolean>;
209
211
  supportsToolSearch: Type.TOptional<Type.TBoolean>;
210
212
  }>, Type.TObject<{
211
213
  supportsEagerToolInputStreaming: Type.TOptional<Type.TBoolean>;
@@ -292,6 +294,7 @@ declare const ProviderConfigSchema: Type.TObject<{
292
294
  supportsLongCacheRetention: Type.TOptional<Type.TBoolean>;
293
295
  supportsStrictMode: Type.TOptional<Type.TBoolean>;
294
296
  supportsOpenAIGrammarTools: Type.TOptional<Type.TBoolean>;
297
+ supportsAdditionalTools: Type.TOptional<Type.TBoolean>;
295
298
  supportsToolSearch: Type.TOptional<Type.TBoolean>;
296
299
  }>, Type.TObject<{
297
300
  supportsEagerToolInputStreaming: Type.TOptional<Type.TBoolean>;
@@ -403,6 +406,7 @@ declare const ProviderConfigSchema: Type.TObject<{
403
406
  supportsLongCacheRetention: Type.TOptional<Type.TBoolean>;
404
407
  supportsStrictMode: Type.TOptional<Type.TBoolean>;
405
408
  supportsOpenAIGrammarTools: Type.TOptional<Type.TBoolean>;
409
+ supportsAdditionalTools: Type.TOptional<Type.TBoolean>;
406
410
  supportsToolSearch: Type.TOptional<Type.TBoolean>;
407
411
  }>, Type.TObject<{
408
412
  supportsEagerToolInputStreaming: Type.TOptional<Type.TBoolean>;
@@ -511,6 +515,7 @@ declare const ProviderConfigSchema: Type.TObject<{
511
515
  supportsLongCacheRetention: Type.TOptional<Type.TBoolean>;
512
516
  supportsStrictMode: Type.TOptional<Type.TBoolean>;
513
517
  supportsOpenAIGrammarTools: Type.TOptional<Type.TBoolean>;
518
+ supportsAdditionalTools: Type.TOptional<Type.TBoolean>;
514
519
  supportsToolSearch: Type.TOptional<Type.TBoolean>;
515
520
  }>, Type.TObject<{
516
521
  supportsEagerToolInputStreaming: Type.TOptional<Type.TBoolean>;
@@ -96,6 +96,7 @@ const OpenAIResponsesCompatSchema = Type.Object({
96
96
  supportsLongCacheRetention: Type.Optional(Type.Boolean()),
97
97
  supportsStrictMode: Type.Optional(Type.Boolean()),
98
98
  supportsOpenAIGrammarTools: Type.Optional(Type.Boolean()),
99
+ supportsAdditionalTools: Type.Optional(Type.Boolean()),
99
100
  supportsToolSearch: Type.Optional(Type.Boolean()),
100
101
  });
101
102
  const AnthropicMessagesCompatSchema = Type.Object({
@@ -1,8 +1,8 @@
1
- import { CONFIG_DIR_NAME } from "../config.js";
1
+ import { APP_NAME, CONFIG_DIR_NAME } from "../config.js";
2
2
  import { emitProjectTrustEvent } from "./extensions/runner.js";
3
3
  import { getProjectTrustOptions, hasTrustRequiringProjectResources, } from "./trust-manager.js";
4
4
  function formatProjectTrustPrompt(cwd) {
5
- return `Trust project folder?\n${cwd}\n\nThis allows selesai to load ${CONFIG_DIR_NAME} settings and resources, install missing project packages, and execute project extensions.`;
5
+ return `Trust project folder?\n${cwd}\n\nThis allows ${APP_NAME} to load ${CONFIG_DIR_NAME} settings and resources, install missing project packages, and execute project extensions.`;
6
6
  }
7
7
  async function selectProjectTrustOption(cwd, ctx) {
8
8
  const options = getProjectTrustOptions(cwd, { includeSessionOnly: true });
@@ -2,6 +2,17 @@ import { lazyStream, } from "@earendil-works/pi-ai";
2
2
  import { getApiProvider } from "@earendil-works/pi-ai/compat";
3
3
  import { clearConfigValueCache, getConfigValueEnvVarNames, isCommandConfigValue, isConfigValueConfigured, resolveConfigValueOrThrow, resolveHeadersOrThrow, } from "./resolve-config-value.js";
4
4
  export const clearApiKeyCache = clearConfigValueCache;
5
+ /** Sane default when a model definition omits maxTokens (kept small so providers never reject it). */
6
+ const DEFAULT_MAX_TOKENS = 16384;
7
+ /**
8
+ * Resolve a safe max output token count. Missing or non-positive values fall back
9
+ * (to a sane default or an inherited value); explicit values are never allowed to
10
+ * exceed the model's context window.
11
+ */
12
+ function safeMaxTokens(value, contextWindow, fallback = DEFAULT_MAX_TOKENS) {
13
+ const resolved = typeof value === "number" && value > 0 ? value : fallback;
14
+ return Math.min(resolved, Math.max(contextWindow, 1));
15
+ }
5
16
  function mergeCompat(base, override) {
6
17
  if (!override)
7
18
  return base;
@@ -20,6 +31,7 @@ function mergeCompat(base, override) {
20
31
  return merged;
21
32
  }
22
33
  function applyModelOverride(model, override) {
34
+ const contextWindow = override.contextWindow ?? model.contextWindow;
23
35
  return {
24
36
  ...model,
25
37
  name: override.name ?? model.name,
@@ -37,8 +49,8 @@ function applyModelOverride(model, override) {
37
49
  tiers: override.cost.tiers ?? model.cost.tiers,
38
50
  }
39
51
  : model.cost,
40
- contextWindow: override.contextWindow ?? model.contextWindow,
41
- maxTokens: override.maxTokens ?? model.maxTokens,
52
+ contextWindow,
53
+ maxTokens: safeMaxTokens(override.maxTokens ?? model.maxTokens, contextWindow, model.maxTokens),
42
54
  compat: mergeCompat(model.compat, override.compat),
43
55
  };
44
56
  }
@@ -56,6 +68,7 @@ function modelFromJson(providerId, definition, providerConfig, defaults) {
56
68
  if (definition.maxTokens !== undefined && definition.maxTokens <= 0) {
57
69
  throw new Error(`Provider ${providerId}, model ${definition.id}: invalid maxTokens`);
58
70
  }
71
+ const contextWindow = definition.contextWindow ?? 128000;
59
72
  return {
60
73
  id: definition.id,
61
74
  name: definition.name ?? definition.id,
@@ -66,8 +79,8 @@ function modelFromJson(providerId, definition, providerConfig, defaults) {
66
79
  thinkingLevelMap: definition.thinkingLevelMap,
67
80
  input: (definition.input ?? ["text"]),
68
81
  cost: definition.cost ?? { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
69
- contextWindow: definition.contextWindow ?? 128000,
70
- maxTokens: definition.maxTokens ?? 16384,
82
+ contextWindow,
83
+ maxTokens: safeMaxTokens(definition.maxTokens, contextWindow),
71
84
  headers: undefined,
72
85
  compat: mergeCompat(providerConfig.compat, definition.compat),
73
86
  };
@@ -34,9 +34,11 @@ export interface CreateAgentSessionOptions {
34
34
  /**
35
35
  * Optional allowlist of tool names.
36
36
  *
37
- * When omitted, pi enables the default built-in tools (read, bash, edit, write)
38
- * and leaves extension/custom tools enabled unless `noTools` changes that default.
39
- * When provided, only the listed tool names are enabled.
37
+ * When omitted, pi uses the `defaultTools` setting for the initial built-in
38
+ * selection when configured. Otherwise it enables the default built-in tools
39
+ * (read, bash, edit, write). Extension/custom tools remain enabled unless
40
+ * `noTools` changes that default. When provided, only the listed tool names are
41
+ * enabled.
40
42
  */
41
43
  tools?: string[];
42
44
  /** Optional denylist of tool names to disable. Applies after `tools` when both are provided. */
package/dist/core/sdk.js CHANGED
@@ -130,10 +130,11 @@ export async function createAgentSession(options = {}) {
130
130
  thinkingLevel = clampThinkingLevel(model, thinkingLevel);
131
131
  }
132
132
  const defaultActiveToolNames = ["read", "bash", "edit", "write"];
133
+ const configuredDefaultToolNames = settingsManager.getDefaultTools();
133
134
  const allowedToolNames = options.tools ?? (options.noTools === "all" ? [] : undefined);
134
135
  const excludedToolNames = options.excludeTools;
135
136
  const excludedToolNameSet = excludedToolNames ? new Set(excludedToolNames) : undefined;
136
- const initialActiveToolNames = (options.tools ? [...options.tools] : options.noTools ? [] : defaultActiveToolNames).filter((name) => !excludedToolNameSet?.has(name));
137
+ const initialActiveToolNames = (options.tools ?? (options.noTools ? [] : (configuredDefaultToolNames ?? defaultActiveToolNames))).filter((name) => !excludedToolNameSet?.has(name));
137
138
  let agent;
138
139
  // Create convertToLlm wrapper that filters images if blockImages is enabled (defense-in-depth)
139
140
  const convertToLlmWithBlockImages = (messages) => {
@@ -5,7 +5,7 @@ import { readdir, stat } from "fs/promises";
5
5
  import { join, resolve } from "path";
6
6
  import { createInterface } from "readline";
7
7
  import { StringDecoder } from "string_decoder";
8
- import { getAgentDir as getDefaultAgentDir, getSessionsDir } from "../config.js";
8
+ import { APP_NAME, getAgentDir as getDefaultAgentDir, getSessionsDir } from "../config.js";
9
9
  import { normalizePath, resolvePath } from "../utils/paths.js";
10
10
  import { createBranchSummaryMessage, createCompactionSummaryMessage, createCustomMessage, } from "./messages.js";
11
11
  export const CURRENT_SESSION_VERSION = 3;
@@ -620,7 +620,7 @@ export class SessionManager {
620
620
  if (this.fileEntries.length === 0) {
621
621
  const explicitPath = this.sessionFile;
622
622
  if (statSync(explicitPath).size > 0) {
623
- throw new Error(`Session file is not a valid pi session: ${explicitPath}`);
623
+ throw new Error(`Session file is not a valid ${APP_NAME} session: ${explicitPath}`);
624
624
  }
625
625
  this.newSession();
626
626
  this.sessionFile = explicitPath;
@@ -22,6 +22,7 @@ export interface RetrySettings {
22
22
  provider?: ProviderRetrySettings;
23
23
  }
24
24
  export type TuiMode = RendererTuiMode;
25
+ export type FullscreenExitOutput = "transcript" | "resume-hint";
25
26
  export interface TerminalSettings {
26
27
  showImages?: boolean;
27
28
  imageWidthCells?: number;
@@ -77,6 +78,7 @@ export interface Settings {
77
78
  branchSummary?: BranchSummarySettings;
78
79
  retry?: RetrySettings;
79
80
  hideThinkingBlock?: boolean;
81
+ pruneToolDescriptions?: boolean;
80
82
  showCacheMissNotices?: boolean;
81
83
  externalEditor?: string;
82
84
  shellPath?: string;
@@ -96,6 +98,8 @@ export interface Settings {
96
98
  agents?: string[];
97
99
  terminal?: TerminalSettings;
98
100
  tuiMode?: TuiMode;
101
+ defaultTools?: string[];
102
+ fullscreenExitOutput?: FullscreenExitOutput;
99
103
  fullscreenScrollbar?: ScrollViewScrollbar;
100
104
  images?: ImageSettings;
101
105
  enabledModels?: string[];
@@ -236,6 +240,7 @@ export declare class SettingsManager {
236
240
  };
237
241
  getWebSocketConnectTimeoutMs(): number | undefined;
238
242
  getHideThinkingBlock(): boolean;
243
+ getPruneToolDescriptions(): boolean;
239
244
  getShowCacheMissNotices(): boolean;
240
245
  getExternalEditorCommand(): string;
241
246
  setHideThinkingBlock(hide: boolean): void;
@@ -286,11 +291,14 @@ export declare class SettingsManager {
286
291
  setTuiMode(mode: TuiMode): void;
287
292
  getFullscreenScrollbar(): ScrollViewScrollbar;
288
293
  setFullscreenScrollbar(mode: ScrollViewScrollbar): void;
294
+ getFullscreenExitOutput(): FullscreenExitOutput;
295
+ setFullscreenExitOutput(output: FullscreenExitOutput): void;
289
296
  getImageAutoResize(): boolean;
290
297
  setImageAutoResize(enabled: boolean): void;
291
298
  getBlockImages(): boolean;
292
299
  setBlockImages(blocked: boolean): void;
293
300
  getEnabledModels(): string[] | undefined;
301
+ getDefaultTools(): string[] | undefined;
294
302
  setEnabledModels(patterns: string[] | undefined): void;
295
303
  getDoubleEscapeAction(): "fork" | "tree" | "none";
296
304
  setDoubleEscapeAction(action: "fork" | "tree" | "none"): void;
@@ -598,6 +598,9 @@ export class SettingsManager {
598
598
  getHideThinkingBlock() {
599
599
  return this.settings.hideThinkingBlock ?? false;
600
600
  }
601
+ getPruneToolDescriptions() {
602
+ return this.settings.pruneToolDescriptions ?? true;
603
+ }
601
604
  getShowCacheMissNotices() {
602
605
  return this.settings.showCacheMissNotices ?? false;
603
606
  }
@@ -834,6 +837,14 @@ export class SettingsManager {
834
837
  this.markModified("fullscreenScrollbar");
835
838
  this.save();
836
839
  }
840
+ getFullscreenExitOutput() {
841
+ return this.settings.fullscreenExitOutput === "resume-hint" ? "resume-hint" : "transcript";
842
+ }
843
+ setFullscreenExitOutput(output) {
844
+ this.globalSettings.fullscreenExitOutput = output;
845
+ this.markModified("fullscreenExitOutput");
846
+ this.save();
847
+ }
837
848
  getImageAutoResize() {
838
849
  return this.settings.images?.autoResize ?? true;
839
850
  }
@@ -859,6 +870,10 @@ export class SettingsManager {
859
870
  getEnabledModels() {
860
871
  return this.settings.enabledModels;
861
872
  }
873
+ getDefaultTools() {
874
+ const tools = this.settings.defaultTools;
875
+ return tools ? [...tools] : undefined;
876
+ }
862
877
  setEnabledModels(patterns) {
863
878
  this.globalSettings.enabledModels = patterns;
864
879
  this.markModified("enabledModels");
@@ -51,7 +51,7 @@ export function buildSystemPrompt(options) {
51
51
  if (activeGuidelines.length > 0) {
52
52
  prompt += `\n\nActive tool guidelines:\n${activeGuidelines.map((guideline) => `- ${guideline}`).join("\n")}`;
53
53
  }
54
- prompt += `\nCurrent working directory: ${promptCwd}`;
54
+ prompt += `\nCurrent working directory: ${promptCwd}\n`;
55
55
  return prompt;
56
56
  }
57
57
  // Get absolute paths to documentation and examples
@@ -103,14 +103,8 @@ In addition to the tools above, you may have access to other custom tools depend
103
103
  Guidelines:
104
104
  ${guidelines}
105
105
 
106
- Pi documentation (read only when the user asks about pi itself, its SDK, extensions, themes, skills, or TUI):
107
- - Main documentation: ${readmePath}
108
- - Additional docs: ${docsPath}
109
- - Examples: ${examplesPath} (extensions, custom tools, SDK)
110
- - When reading pi docs or examples, resolve docs/... under Additional docs and examples/... under Examples, not the current working directory
111
- - When asked about: extensions (docs/extensions.md, examples/extensions/), themes (docs/themes.md), skills (docs/skills.md), prompt templates (docs/prompt-templates.md), TUI components (docs/tui.md), keybindings (docs/keybindings.md), SDK integrations (docs/sdk.md), custom providers (docs/custom-provider.md), adding models (docs/models.md), pi packages (docs/packages.md), environment variables (docs/environment-variables.md)
112
- - When working on pi topics, read the docs and examples, and follow .md cross-references before implementing
113
- - Always read pi .md files completely and follow links to related docs (e.g., tui.md for TUI API details)`;
106
+ Pi documentation (read only when the user asks about pi itself, its SDK, extensions, themes, skills, or TUI): main docs ${readmePath}, additional docs ${docsPath}, examples ${examplesPath}.
107
+ When working on pi topics, resolve docs/... and examples/... under those paths (not cwd), read the relevant .md files completely, and follow cross-references before implementing.`;
114
108
  if (appendSection) {
115
109
  prompt += appendSection;
116
110
  }
@@ -12,6 +12,12 @@ describe("buildSystemPrompt", () => {
12
12
  expect(prompt).toMatch(/Guidelines:/);
13
13
  expect(prompt).toContain("Current working directory: /tmp/project");
14
14
  });
15
+ it("keeps the collapsed Pi-docs block without the per-topic filename map", () => {
16
+ const prompt = buildSystemPrompt({ cwd: "/tmp/project" });
17
+ expect(prompt).toContain("Pi documentation");
18
+ expect(prompt).not.toContain("When asked about:");
19
+ expect(prompt).not.toContain("(docs/extensions.md");
20
+ });
15
21
  it("keeps the default tool snippets, skills, and agents XML read-gated", () => {
16
22
  const skill = {
17
23
  name: "test-skill",
@@ -7,6 +7,7 @@ import { keyHint } from "../../modes/interactive/components/keybinding-hints.js"
7
7
  import { truncateToVisualLines } from "../../modes/interactive/components/visual-truncate.js";
8
8
  import { theme } from "../../modes/interactive/theme/theme.js";
9
9
  import { waitForChildProcess } from "../../utils/child-process.js";
10
+ import { getExperimentalToolSampling } from "../experimental.js";
10
11
  import { getShellConfig, getShellEnv, killProcessTree, trackDetachedChildPid, untrackDetachedChildPid, } from "../../utils/shell.js";
11
12
  import { OutputAccumulator } from "./output-accumulator.js";
12
13
  import { getTextOutput, invalidArgText, str } from "./render-utils.js";
@@ -232,6 +233,7 @@ export function createBashToolDefinition(cwd, options) {
232
233
  ? ["Inspect PI_* environment variables for current model and session details."]
233
234
  : undefined,
234
235
  parameters: bashSchema,
236
+ constrainedSampling: getExperimentalToolSampling(),
235
237
  async execute(_toolCallId, { command, timeout }, signal, onUpdate, ctx) {
236
238
  const resolvedCommand = commandPrefix ? `${commandPrefix}\n${command}` : command;
237
239
  const spawnContext = resolveSpawnContext(resolvedCommand, cwd, spawnHook, exposeSessionEnvironment, ctx);
@@ -3,6 +3,7 @@ import { constants } from "fs";
3
3
  import { access as fsAccess, readFile as fsReadFile, writeFile as fsWriteFile } from "fs/promises";
4
4
  import { Type } from "typebox";
5
5
  import { renderDiff } from "../../modes/interactive/components/diff.js";
6
+ import { getExperimentalToolSampling } from "../experimental.js";
6
7
  import { applyEditsToNormalizedContent, computeEditsDiff, detectLineEnding, generateDiffString, generateUnifiedPatch, normalizeToLF, restoreLineEndings, stripBom, } from "./edit-diff.js";
7
8
  import { withFileMutationQueue } from "./file-mutation-queue.js";
8
9
  import { resolveToCwd } from "./path-utils.js";
@@ -169,6 +170,7 @@ export function createEditToolDefinition(cwd, options) {
169
170
  "Keep edits[].oldText as small as possible while still being unique in the file. Do not pad with large unchanged regions.",
170
171
  ],
171
172
  parameters: editSchema,
173
+ constrainedSampling: getExperimentalToolSampling(),
172
174
  renderShell: "self",
173
175
  prepareArguments: prepareEditArguments,
174
176
  async execute(_toolCallId, input, signal, _onUpdate, _ctx) {
@@ -154,7 +154,7 @@ export function createFindToolDefinition(cwd, options) {
154
154
  return;
155
155
  }
156
156
  // Default implementation uses fd.
157
- const fdPath = await ensureTool("fd", true);
157
+ const fdPath = await ensureTool("fd");
158
158
  if (signal?.aborted) {
159
159
  settle(() => reject(new Error("Operation aborted")));
160
160
  return;
@@ -92,7 +92,7 @@ export function createGrepToolDefinition(cwd, options) {
92
92
  };
93
93
  (async () => {
94
94
  try {
95
- const rgPath = await ensureTool("rg", true);
95
+ const rgPath = await ensureTool("rg");
96
96
  if (!rgPath) {
97
97
  settle(() => reject(new Error("ripgrep (rg) is not available and could not be downloaded")));
98
98
  return;
@@ -5,6 +5,7 @@ export { createFindTool, createFindToolDefinition, type FindOperations, type Fin
5
5
  export { createGrepTool, createGrepToolDefinition, type GrepOperations, type GrepToolDetails, type GrepToolInput, type GrepToolOptions, } from "./grep.ts";
6
6
  export { createLsTool, createLsToolDefinition, type LsOperations, type LsToolDetails, type LsToolInput, type LsToolOptions, } from "./ls.ts";
7
7
  export { createReadTool, createReadToolDefinition, type ReadOperations, type ReadToolDetails, type ReadToolInput, type ReadToolOptions, } from "./read.ts";
8
+ export { stripSchemaDescriptions, stripToolParameterDescriptions, } from "./schema-prune.ts";
8
9
  export { DEFAULT_MAX_BYTES, DEFAULT_MAX_LINES, formatSize, type TruncationOptions, type TruncationResult, truncateHead, truncateLine, truncateTail, } from "./truncate.ts";
9
10
  export { createWriteTool, createWriteToolDefinition, type WriteOperations, type WriteToolInput, type WriteToolOptions, } from "./write.ts";
10
11
  import type { AgentTool } from "@earendil-works/pi-agent-core";