@selesai/code 0.9.9 → 0.9.11

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 (306) hide show
  1. package/CHANGELOG.md +11 -0
  2. package/dist/cli/args.js +13 -2
  3. package/dist/cli/args.test.js +8 -0
  4. package/dist/cli/credential-print.js +4 -4
  5. package/dist/cli.js +0 -0
  6. package/dist/core/agent-session-auto-handoff.test.js +24 -1
  7. package/dist/core/agent-session.d.ts +11 -4
  8. package/dist/core/agent-session.js +99 -39
  9. package/dist/core/compaction/branch-summarization.js +30 -30
  10. package/dist/core/compaction/compaction.js +81 -81
  11. package/dist/core/compaction/utils.js +2 -2
  12. package/dist/core/defaults.d.ts +1 -0
  13. package/dist/core/defaults.js +9 -0
  14. package/dist/core/export-html/template.css +1066 -1066
  15. package/dist/core/export-html/template.html +55 -55
  16. package/dist/core/export-html/template.js +1864 -1864
  17. package/dist/core/export-html/vendor/highlight.min.js +1212 -1212
  18. package/dist/core/export-html/vendor/marked.min.js +78 -78
  19. package/dist/core/extensions/loader.js +108 -35
  20. package/dist/core/extensions/loader.test.d.ts +1 -0
  21. package/dist/core/extensions/loader.test.js +21 -0
  22. package/dist/core/extensions/types.d.ts +12 -2
  23. package/dist/core/keybindings.d.ts +2 -2
  24. package/dist/core/messages.js +7 -7
  25. package/dist/core/model-resolver.d.ts +1 -0
  26. package/dist/core/model-resolver.js +10 -4
  27. package/dist/core/package-manager.js +4 -4
  28. package/dist/core/sdk.d.ts +5 -5
  29. package/dist/core/sdk.js +16 -4
  30. package/dist/core/settings-manager.d.ts +6 -0
  31. package/dist/core/settings-manager.js +22 -0
  32. package/dist/core/tools/bash.d.ts +18 -1
  33. package/dist/core/tools/bash.js +41 -23
  34. package/dist/core/tools/index.d.ts +4 -1
  35. package/dist/core/tools/index.js +9 -1
  36. package/dist/core/tools/powershell.d.ts +15 -0
  37. package/dist/core/tools/powershell.js +38 -0
  38. package/dist/core/tools/powershell.test.d.ts +1 -0
  39. package/dist/core/tools/powershell.test.js +20 -0
  40. package/dist/extensions/context-compaction-reminder.test.ts +82 -82
  41. package/dist/extensions/context-compaction-reminder.ts +28 -28
  42. package/dist/extensions/copy-turn.test.ts +24 -1
  43. package/dist/extensions/copy-turn.ts +6 -1
  44. package/dist/extensions/handoff-new.test.ts +15 -2
  45. package/dist/extensions/handoff-new.ts +44 -30
  46. package/dist/extensions/pi-intercom/LICENSE +21 -21
  47. package/dist/extensions/pi-intercom/broker/client.test.ts +83 -83
  48. package/dist/extensions/pi-intercom/broker/extension.test.ts +387 -387
  49. package/dist/extensions/pi-intercom/broker/framing.test.ts +114 -114
  50. package/dist/extensions/pi-intercom/broker/paths.test.ts +153 -153
  51. package/dist/extensions/pi-intercom/broker/paths.ts +134 -134
  52. package/dist/extensions/pi-intercom/broker/runtime-claim.test.ts +34 -34
  53. package/dist/extensions/pi-intercom/broker/runtime-claim.ts +21 -21
  54. package/dist/extensions/pi-intercom/cwd.test.ts +40 -40
  55. package/dist/extensions/pi-intercom/cwd.ts +31 -31
  56. package/dist/extensions/pi-intercom/extension-api.ts +44 -44
  57. package/dist/extensions/pi-intercom/format-context.test.ts +31 -31
  58. package/dist/extensions/pi-intercom/format-context.ts +32 -32
  59. package/dist/extensions/pi-intercom/test/overlay-width.test.ts +66 -66
  60. package/dist/extensions/pi-intercom/ui/compose.ts +143 -143
  61. package/dist/extensions/pi-intercom/ui/session-list.ts +166 -166
  62. package/dist/extensions/pi-powerline-footer/bash-mode/shell-session.ts +286 -286
  63. package/dist/extensions/pi-powerline-footer/bash-mode/transcript.ts +108 -108
  64. package/dist/extensions/pi-powerline-footer/separators.ts +57 -57
  65. package/dist/extensions/pi-powerline-footer/tests/session-usage.test.ts +47 -47
  66. package/dist/extensions/pi-powerline-footer/tests/tps.test.ts +39 -39
  67. package/dist/extensions/pi-powerline-footer/theme.example.json +24 -24
  68. package/dist/extensions/pi-powerline-footer/theme.json +12 -12
  69. package/dist/extensions/pi-powerline-footer/tps.ts +345 -345
  70. package/dist/extensions/pi-rewind-hook/README.md +245 -245
  71. package/dist/extensions/pi-rewind-hook/index.ts +1445 -1445
  72. package/dist/extensions/pi-rewind-hook/package.json +29 -29
  73. package/dist/extensions/pi-subagents/install.mjs +0 -0
  74. package/dist/extensions/pi-web-agent/package.json +31 -31
  75. package/dist/extensions/pi-web-agent/src/backends/config.ts +205 -205
  76. package/dist/extensions/pi-web-agent/src/backends/doctor.ts +136 -136
  77. package/dist/extensions/pi-web-agent/src/backends/factory.ts +152 -152
  78. package/dist/extensions/pi-web-agent/src/backends/settings-reader.ts +25 -25
  79. package/dist/extensions/pi-web-agent/src/cache/ttl-cache.ts +28 -28
  80. package/dist/extensions/pi-web-agent/src/changelog-notice.ts +136 -136
  81. package/dist/extensions/pi-web-agent/src/commands/web-agent-config.ts +946 -946
  82. package/dist/extensions/pi-web-agent/src/extension.ts +126 -126
  83. package/dist/extensions/pi-web-agent/src/extract/readability.ts +118 -118
  84. package/dist/extensions/pi-web-agent/src/fetch/browser-resolution.ts +199 -199
  85. package/dist/extensions/pi-web-agent/src/fetch/firecrawl-fetch.ts +100 -100
  86. package/dist/extensions/pi-web-agent/src/fetch/headless-fetch.ts +117 -117
  87. package/dist/extensions/pi-web-agent/src/fetch/http-fetch.ts +67 -67
  88. package/dist/extensions/pi-web-agent/src/orchestration/answer-synthesizer.ts +60 -60
  89. package/dist/extensions/pi-web-agent/src/orchestration/candidate-selector.ts +50 -50
  90. package/dist/extensions/pi-web-agent/src/orchestration/direct-url.ts +52 -52
  91. package/dist/extensions/pi-web-agent/src/orchestration/evidence-quality.ts +105 -105
  92. package/dist/extensions/pi-web-agent/src/orchestration/evidence-ranker.ts +45 -45
  93. package/dist/extensions/pi-web-agent/src/orchestration/index.ts +28 -28
  94. package/dist/extensions/pi-web-agent/src/orchestration/query-planner.ts +47 -47
  95. package/dist/extensions/pi-web-agent/src/orchestration/research-orchestrator.ts +376 -376
  96. package/dist/extensions/pi-web-agent/src/orchestration/research-types.ts +64 -64
  97. package/dist/extensions/pi-web-agent/src/orchestration/research-worker.ts +181 -181
  98. package/dist/extensions/pi-web-agent/src/orchestration/source-profile.ts +101 -101
  99. package/dist/extensions/pi-web-agent/src/orchestration/stop-decider.ts +81 -81
  100. package/dist/extensions/pi-web-agent/src/presentation/config-store.ts +210 -210
  101. package/dist/extensions/pi-web-agent/src/presentation/config.ts +75 -75
  102. package/dist/extensions/pi-web-agent/src/presentation/explore-presentation.ts +61 -61
  103. package/dist/extensions/pi-web-agent/src/presentation/fetch-presentation.ts +54 -54
  104. package/dist/extensions/pi-web-agent/src/presentation/search-presentation.ts +41 -41
  105. package/dist/extensions/pi-web-agent/src/presentation/select-view.ts +20 -20
  106. package/dist/extensions/pi-web-agent/src/presentation/types.ts +63 -63
  107. package/dist/extensions/pi-web-agent/src/search/brave.ts +114 -114
  108. package/dist/extensions/pi-web-agent/src/search/duckduckgo.ts +72 -72
  109. package/dist/extensions/pi-web-agent/src/search/searxng.ts +96 -96
  110. package/dist/extensions/pi-web-agent/src/tools/web-explore.ts +71 -71
  111. package/dist/extensions/pi-web-agent/src/tools/web-fetch-headless.ts +31 -31
  112. package/dist/extensions/pi-web-agent/src/tools/web-fetch.ts +31 -31
  113. package/dist/extensions/pi-web-agent/src/tools/web-search.ts +157 -157
  114. package/dist/extensions/pi-web-agent/src/types.ts +88 -88
  115. package/dist/extensions/ponytail/package.json +8 -8
  116. package/dist/extensions/question/batch.ts +103 -103
  117. package/dist/extensions/question/constants.ts +30 -30
  118. package/dist/extensions/question/helpers.ts +58 -58
  119. package/dist/extensions/question/navigation.ts +14 -14
  120. package/dist/extensions/question/package.json +19 -19
  121. package/dist/extensions/question/schemas.ts +43 -43
  122. package/dist/extensions/question/selection-mode.ts +46 -46
  123. package/dist/extensions/question/shortcuts.ts +44 -44
  124. package/dist/extensions/question/types.ts +132 -132
  125. package/dist/extensions/test-resolve-hook-impl.mjs +6 -6
  126. package/dist/extensions/test-resolve-hook.mjs +6 -6
  127. package/dist/extensions/web-agent-onboarding.ts +222 -222
  128. package/dist/extensions/workflow/package.json +17 -17
  129. package/dist/package-manager-cli.js +71 -71
  130. package/dist/rpc-entry.js +0 -0
  131. package/dist/skills/agent-browser/SKILL.md +52 -52
  132. package/dist/skills/batch-grill-me/SKILL.md +19 -19
  133. package/dist/skills/grill-me/SKILL.md +10 -10
  134. package/dist/skills/handoff/SKILL.md +16 -16
  135. package/dist/skills/handoff-text/SKILL.md +14 -14
  136. package/dist/skills/implanger/SKILL.md +69 -69
  137. package/dist/skills/improve-codebase/REFERENCE.md +78 -78
  138. package/dist/skills/improve-codebase/SKILL.md +178 -178
  139. package/dist/skills/planger/SKILL.md +166 -166
  140. package/dist/skills/ponytail/SKILL.md +116 -116
  141. package/dist/skills/ponytail-audit/SKILL.md +42 -42
  142. package/dist/skills/ponytail-debt/SKILL.md +45 -45
  143. package/dist/skills/ponytail-gain/SKILL.md +51 -51
  144. package/dist/skills/ponytail-help/SKILL.md +70 -70
  145. package/dist/skills/ponytail-review/SKILL.md +58 -58
  146. package/dist/skills/selesai-handoff/SKILL.md +20 -20
  147. package/dist/skills/workflow-creation/SKILL.md +73 -73
  148. package/dist/themes/powerline-footer/theme.json +33 -33
  149. package/dist/utils/shell.d.ts +3 -0
  150. package/dist/utils/shell.js +17 -5
  151. package/docs/compaction.md +396 -396
  152. package/docs/containerization.md +111 -111
  153. package/docs/development.md +71 -71
  154. package/docs/docs.json +164 -164
  155. package/docs/environment-variables.md +86 -86
  156. package/docs/index.md +83 -83
  157. package/docs/json.md +82 -82
  158. package/docs/models.md +502 -502
  159. package/docs/packages.md +227 -227
  160. package/docs/plans/subagent-delegation/phase-0-correctness.md +264 -264
  161. package/docs/plans/subagent-delegation/phase-1-behavioral-contract.md +485 -485
  162. package/docs/plans/subagent-delegation/phase-2-context-controls.md +281 -281
  163. package/docs/plans/subagent-delegation/phase-3-advisory-routing.md +361 -361
  164. package/docs/plans/subagent-delegation/phase-4-optional-enforcement.md +380 -380
  165. package/docs/prompt-templates.md +95 -95
  166. package/docs/providers.md +293 -293
  167. package/docs/sdk.md +1144 -1143
  168. package/docs/security.md +59 -59
  169. package/docs/session-format.md +414 -414
  170. package/docs/sessions.md +145 -145
  171. package/docs/shared-host-extensions.md +109 -109
  172. package/docs/shell-aliases.md +13 -13
  173. package/docs/skills.md +231 -231
  174. package/docs/terminal-setup.md +142 -142
  175. package/docs/termux.md +127 -127
  176. package/docs/themes.md +295 -295
  177. package/docs/tmux.md +63 -63
  178. package/docs/tui.md +927 -927
  179. package/docs/windows.md +17 -17
  180. package/examples/README.md +25 -25
  181. package/examples/extensions/README.md +211 -211
  182. package/examples/extensions/auto-commit-on-exit.ts +49 -49
  183. package/examples/extensions/bash-spawn-hook.ts +30 -30
  184. package/examples/extensions/bookmark.ts +50 -50
  185. package/examples/extensions/border-status-editor.ts +150 -150
  186. package/examples/extensions/built-in-tool-renderer.ts +249 -249
  187. package/examples/extensions/claude-rules.ts +86 -86
  188. package/examples/extensions/commands.ts +72 -72
  189. package/examples/extensions/confirm-destructive.ts +59 -59
  190. package/examples/extensions/custom-compaction.ts +130 -130
  191. package/examples/extensions/custom-footer.ts +64 -64
  192. package/examples/extensions/custom-header.ts +73 -73
  193. package/examples/extensions/custom-provider-anthropic/index.ts +610 -610
  194. package/examples/extensions/custom-provider-anthropic/package-lock.json +24 -24
  195. package/examples/extensions/custom-provider-anthropic/package.json +19 -19
  196. package/examples/extensions/custom-provider-gitlab-duo/index.ts +404 -404
  197. package/examples/extensions/custom-provider-gitlab-duo/package.json +16 -16
  198. package/examples/extensions/custom-provider-gitlab-duo/test.ts +82 -82
  199. package/examples/extensions/dirty-repo-guard.ts +56 -56
  200. package/examples/extensions/doom-overlay/README.md +46 -46
  201. package/examples/extensions/doom-overlay/doom/build/doom.js +21 -21
  202. package/examples/extensions/doom-overlay/doom/build/doom.wasm +0 -0
  203. package/examples/extensions/doom-overlay/doom/build.sh +152 -152
  204. package/examples/extensions/doom-overlay/doom/doomgeneric_pi.c +72 -72
  205. package/examples/extensions/doom-overlay/doom-component.ts +132 -132
  206. package/examples/extensions/doom-overlay/doom-engine.ts +173 -173
  207. package/examples/extensions/doom-overlay/doom-keys.ts +104 -104
  208. package/examples/extensions/doom-overlay/index.ts +74 -74
  209. package/examples/extensions/doom-overlay/wad-finder.ts +51 -51
  210. package/examples/extensions/dynamic-resources/SKILL.md +8 -8
  211. package/examples/extensions/dynamic-resources/dynamic.json +79 -79
  212. package/examples/extensions/dynamic-resources/dynamic.md +5 -5
  213. package/examples/extensions/dynamic-resources/index.ts +15 -15
  214. package/examples/extensions/dynamic-tools.ts +74 -74
  215. package/examples/extensions/event-bus.ts +43 -43
  216. package/examples/extensions/file-trigger.ts +41 -41
  217. package/examples/extensions/git-checkpoint.ts +53 -53
  218. package/examples/extensions/git-merge-and-resolve.ts +115 -115
  219. package/examples/extensions/github-issue-autocomplete.ts +185 -185
  220. package/examples/extensions/gondolin/index.ts +531 -531
  221. package/examples/extensions/gondolin/package-lock.json +185 -185
  222. package/examples/extensions/gondolin/package.json +19 -19
  223. package/examples/extensions/handoff.ts +199 -199
  224. package/examples/extensions/hello.ts +26 -26
  225. package/examples/extensions/hidden-thinking-label.ts +53 -53
  226. package/examples/extensions/inline-bash.ts +94 -94
  227. package/examples/extensions/input-transform-streaming.ts +39 -39
  228. package/examples/extensions/input-transform.ts +43 -43
  229. package/examples/extensions/interactive-shell.ts +196 -196
  230. package/examples/extensions/mac-system-theme.ts +47 -47
  231. package/examples/extensions/message-renderer.ts +59 -59
  232. package/examples/extensions/minimal-mode.ts +426 -426
  233. package/examples/extensions/modal-editor.ts +85 -85
  234. package/examples/extensions/model-status.ts +31 -31
  235. package/examples/extensions/notify.ts +55 -55
  236. package/examples/extensions/overlay-qa-tests.ts +1450 -1450
  237. package/examples/extensions/overlay-test.ts +153 -153
  238. package/examples/extensions/permission-gate.ts +34 -34
  239. package/examples/extensions/pirate.ts +47 -47
  240. package/examples/extensions/plan-mode/README.md +66 -66
  241. package/examples/extensions/plan-mode/index.ts +390 -390
  242. package/examples/extensions/plan-mode/utils.ts +168 -168
  243. package/examples/extensions/preset.ts +436 -436
  244. package/examples/extensions/project-trust.ts +64 -64
  245. package/examples/extensions/prompt-customizer.ts +97 -97
  246. package/examples/extensions/protected-paths.ts +30 -30
  247. package/examples/extensions/provider-payload.ts +18 -18
  248. package/examples/extensions/qna.ts +122 -122
  249. package/examples/extensions/question.ts +285 -285
  250. package/examples/extensions/questionnaire.ts +448 -448
  251. package/examples/extensions/rainbow-editor.ts +88 -88
  252. package/examples/extensions/reload-runtime.ts +37 -37
  253. package/examples/extensions/rpc-demo.ts +118 -118
  254. package/examples/extensions/sandbox/index.ts +321 -321
  255. package/examples/extensions/sandbox/package-lock.json +92 -92
  256. package/examples/extensions/sandbox/package.json +19 -19
  257. package/examples/extensions/send-user-message.ts +97 -97
  258. package/examples/extensions/session-name.ts +27 -27
  259. package/examples/extensions/shutdown-command.ts +63 -63
  260. package/examples/extensions/snake.ts +343 -343
  261. package/examples/extensions/space-invaders.ts +560 -560
  262. package/examples/extensions/ssh.ts +220 -220
  263. package/examples/extensions/status-line.ts +32 -32
  264. package/examples/extensions/structured-output.ts +65 -65
  265. package/examples/extensions/subagent/README.md +175 -175
  266. package/examples/extensions/subagent/agents/planner.md +37 -37
  267. package/examples/extensions/subagent/agents/reviewer.md +35 -35
  268. package/examples/extensions/subagent/agents/scout.md +50 -50
  269. package/examples/extensions/subagent/agents/worker.md +24 -24
  270. package/examples/extensions/subagent/agents.ts +126 -126
  271. package/examples/extensions/subagent/index.ts +1015 -1015
  272. package/examples/extensions/subagent/prompts/implement-and-review.md +10 -10
  273. package/examples/extensions/subagent/prompts/implement.md +10 -10
  274. package/examples/extensions/subagent/prompts/scout-and-plan.md +9 -9
  275. package/examples/extensions/summarize.ts +209 -209
  276. package/examples/extensions/system-prompt-header.ts +17 -17
  277. package/examples/extensions/tic-tac-toe.ts +1008 -1008
  278. package/examples/extensions/timed-confirm.ts +70 -70
  279. package/examples/extensions/titlebar-spinner.ts +58 -58
  280. package/examples/extensions/todo.ts +297 -297
  281. package/examples/extensions/tool-override.ts +144 -144
  282. package/examples/extensions/tools.ts +146 -146
  283. package/examples/extensions/trigger-compact.ts +50 -50
  284. package/examples/extensions/truncated-tool.ts +195 -195
  285. package/examples/extensions/widget-placement.ts +9 -9
  286. package/examples/extensions/with-deps/index.ts +32 -32
  287. package/examples/extensions/with-deps/package-lock.json +31 -31
  288. package/examples/extensions/with-deps/package.json +22 -22
  289. package/examples/extensions/working-indicator.ts +123 -123
  290. package/examples/extensions/working-message-test.ts +25 -25
  291. package/examples/rpc-extension-ui.ts +632 -632
  292. package/examples/sdk/01-minimal.ts +26 -26
  293. package/examples/sdk/02-custom-model.ts +53 -53
  294. package/examples/sdk/03-custom-prompt.ts +75 -75
  295. package/examples/sdk/04-skills.ts +55 -55
  296. package/examples/sdk/05-tools.ts +48 -48
  297. package/examples/sdk/06-extensions.ts +99 -99
  298. package/examples/sdk/07-context-files.ts +47 -47
  299. package/examples/sdk/08-prompt-templates.ts +51 -51
  300. package/examples/sdk/09-api-keys-and-oauth.ts +52 -52
  301. package/examples/sdk/10-settings.ts +53 -53
  302. package/examples/sdk/11-sessions.ts +52 -52
  303. package/examples/sdk/12-full-control.ts +79 -79
  304. package/examples/sdk/13-session-runtime.ts +67 -67
  305. package/examples/sdk/README.md +144 -144
  306. package/package.json +4 -4
@@ -0,0 +1,21 @@
1
+ import { describe, expect, test } from "vitest";
2
+ import { createEventBus } from "../event-bus.js";
3
+ import { createExtensionRuntime, loadExtensionFromFactory } from "./loader.js";
4
+ describe("extension factory failure", () => {
5
+ test("discards pending provider and flag state and disables the failed API", async () => {
6
+ const runtime = createExtensionRuntime();
7
+ let capturedApi;
8
+ let calls = 0;
9
+ await expect(loadExtensionFromFactory((pi) => {
10
+ capturedApi = pi;
11
+ pi.events.on("failed-load", () => calls++);
12
+ pi.registerFlag("failed-flag", { type: "boolean", default: true });
13
+ pi.registerProvider("failed-provider", { baseUrl: "https://provider.test", apiKey: "key" });
14
+ throw new Error("factory failed");
15
+ }, process.cwd(), createEventBus(), runtime, "<failing>")).rejects.toThrow("factory failed");
16
+ expect(runtime.flagValues.has("failed-flag")).toBe(false);
17
+ expect(runtime.pendingProviderRegistrations).toEqual([]);
18
+ expect(calls).toBe(0);
19
+ expect(() => capturedApi?.registerFlag("late", { type: "boolean", default: true })).toThrow('Extension "<failing>" failed to load and its API is no longer active.');
20
+ });
21
+ });
@@ -454,7 +454,7 @@ export interface SessionBeforeCompactEvent {
454
454
  willRetry: boolean;
455
455
  signal: AbortSignal;
456
456
  }
457
- /** Fired after context compaction */
457
+ /** Fired after context compaction succeeds */
458
458
  export interface SessionCompactEvent {
459
459
  type: "session_compact";
460
460
  compactionEntry: CompactionEntry;
@@ -464,6 +464,15 @@ export interface SessionCompactEvent {
464
464
  /** True when the aborted turn is retried after this compaction (overflow recovery) */
465
465
  willRetry: boolean;
466
466
  }
467
+ /** Fired after context compaction fails or is aborted. */
468
+ export interface SessionCompactFailedEvent {
469
+ type: "session_compact_failed";
470
+ reason: "manual" | "threshold" | "overflow";
471
+ errorMessage?: string;
472
+ aborted: boolean;
473
+ willRetry: boolean;
474
+ fromExtension: boolean;
475
+ }
467
476
  /** Fired when the session display name changes (e.g. via /name). */
468
477
  export interface SessionInfoChangedEvent {
469
478
  type: "session_info_changed";
@@ -505,7 +514,7 @@ export interface SessionTreeEvent {
505
514
  summaryEntry?: BranchSummaryEntry;
506
515
  fromExtension?: boolean;
507
516
  }
508
- export type SessionEvent = SessionStartEvent | SessionInfoChangedEvent | SessionBeforeSwitchEvent | SessionBeforeForkEvent | SessionBeforeCompactEvent | SessionCompactEvent | SessionShutdownEvent | SessionBeforeTreeEvent | SessionTreeEvent | SessionInfoChangedEvent;
517
+ export type SessionEvent = SessionStartEvent | SessionInfoChangedEvent | SessionBeforeSwitchEvent | SessionBeforeForkEvent | SessionBeforeCompactEvent | SessionCompactEvent | SessionCompactFailedEvent | SessionShutdownEvent | SessionBeforeTreeEvent | SessionTreeEvent | SessionInfoChangedEvent;
509
518
  /** Fired before each LLM call. Can modify messages. */
510
519
  export interface ContextEvent {
511
520
  type: "context";
@@ -874,6 +883,7 @@ export interface ExtensionAPI {
874
883
  on(event: "session_before_fork", handler: ExtensionHandler<SessionBeforeForkEvent, SessionBeforeForkResult>): void;
875
884
  on(event: "session_before_compact", handler: ExtensionHandler<SessionBeforeCompactEvent, SessionBeforeCompactResult>): void;
876
885
  on(event: "session_compact", handler: ExtensionHandler<SessionCompactEvent>): void;
886
+ on(event: "session_compact_failed", handler: ExtensionHandler<SessionCompactFailedEvent>): void;
877
887
  on(event: "session_info_changed", handler: ExtensionHandler<SessionInfoChangedEvent>): void;
878
888
  on(event: "session_shutdown", handler: ExtensionHandler<SessionShutdownEvent>): void;
879
889
  on(event: "session_before_tree", handler: ExtensionHandler<SessionBeforeTreeEvent, SessionBeforeTreeResult>): void;
@@ -206,11 +206,11 @@ export declare const KEYBINDINGS: {
206
206
  readonly description: "Scroll viewport down one line";
207
207
  };
208
208
  readonly "tui.altScreen.previousPrompt": {
209
- readonly defaultKeys: "ctrl+shift+up";
209
+ readonly defaultKeys: ["ctrl+shift+up", "ctrl+up"];
210
210
  readonly description: "Jump to previous semantic prompt";
211
211
  };
212
212
  readonly "tui.altScreen.nextPrompt": {
213
- readonly defaultKeys: "ctrl+shift+down";
213
+ readonly defaultKeys: ["ctrl+shift+down", "ctrl+down"];
214
214
  readonly description: "Jump to next semantic prompt";
215
215
  };
216
216
  readonly "tui.altScreen.search": {
@@ -4,15 +4,15 @@
4
4
  * Extends the base AgentMessage type with coding-agent specific message types,
5
5
  * and provides a transformer to convert them to LLM-compatible messages.
6
6
  */
7
- export const COMPACTION_SUMMARY_PREFIX = `The conversation history before this point was compacted into the following summary:
8
-
9
- <summary>
7
+ export const COMPACTION_SUMMARY_PREFIX = `The conversation history before this point was compacted into the following summary:
8
+
9
+ <summary>
10
10
  `;
11
- export const COMPACTION_SUMMARY_SUFFIX = `
11
+ export const COMPACTION_SUMMARY_SUFFIX = `
12
12
  </summary>`;
13
- export const BRANCH_SUMMARY_PREFIX = `The following is a summary of a branch that this conversation came back from:
14
-
15
- <summary>
13
+ export const BRANCH_SUMMARY_PREFIX = `The following is a summary of a branch that this conversation came back from:
14
+
15
+ <summary>
16
16
  `;
17
17
  export const BRANCH_SUMMARY_SUFFIX = `</summary>`;
18
18
  /**
@@ -110,6 +110,7 @@ export declare function findInitialModel(options: {
110
110
  defaultProvider?: string;
111
111
  defaultModelId?: string;
112
112
  defaultThinkingLevel?: ThinkingLevel;
113
+ modelThinkingLevels?: Record<string, ThinkingLevel>;
113
114
  modelRuntime: ModelRuntime;
114
115
  }): Promise<InitialModelResult>;
115
116
  /**
@@ -440,7 +440,7 @@ export function resolveCliModel(options) {
440
440
  * 5. First available model with valid API key
441
441
  */
442
442
  export async function findInitialModel(options) {
443
- const { cliProvider, cliModel, scopedModels, isContinuing, defaultProvider, defaultModelId, defaultThinkingLevel, modelRuntime, } = options;
443
+ const { cliProvider, cliModel, scopedModels, isContinuing, defaultProvider, defaultModelId, defaultThinkingLevel, modelThinkingLevels, modelRuntime, } = options;
444
444
  let model;
445
445
  let thinkingLevel = DEFAULT_THINKING_LEVEL;
446
446
  // 1. CLI args take priority
@@ -460,9 +460,11 @@ export async function findInitialModel(options) {
460
460
  }
461
461
  // 2. Use first model from scoped models (skip if continuing/resuming)
462
462
  if (scopedModels.length > 0 && !isContinuing) {
463
+ const scopedModel = scopedModels[0];
464
+ const perModel = modelThinkingLevels?.[`${scopedModel.model.provider}/${scopedModel.model.id}`];
463
465
  return {
464
- model: scopedModels[0].model,
465
- thinkingLevel: scopedModels[0].thinkingLevel ?? defaultThinkingLevel ?? DEFAULT_THINKING_LEVEL,
466
+ model: scopedModel.model,
467
+ thinkingLevel: scopedModel.thinkingLevel ?? perModel ?? defaultThinkingLevel ?? DEFAULT_THINKING_LEVEL,
466
468
  fallbackMessage: undefined,
467
469
  };
468
470
  }
@@ -471,7 +473,11 @@ export async function findInitialModel(options) {
471
473
  const found = modelRuntime.getModel(defaultProvider, defaultModelId);
472
474
  if (found && modelRuntime.hasConfiguredAuth(found.provider)) {
473
475
  model = found;
474
- if (defaultThinkingLevel) {
476
+ const perModel = modelThinkingLevels?.[`${defaultProvider}/${defaultModelId}`];
477
+ if (perModel) {
478
+ thinkingLevel = perModel;
479
+ }
480
+ else if (defaultThinkingLevel) {
475
481
  thinkingLevel = defaultThinkingLevel;
476
482
  }
477
483
  return { model, thinkingLevel, fallbackMessage: undefined };
@@ -1973,7 +1973,7 @@ export class DefaultPackageManager {
1973
1973
  // Project extensions from .pi/
1974
1974
  addResources("extensions", collectAutoExtensionEntries(projectDirs.extensions), projectMetadata, projectOverrides.extensions, projectBaseDir);
1975
1975
  // Project skills from .pi/
1976
- addResources("skills", collectAutoSkillEntries(projectDirs.skills, "pi"), projectMetadata, projectOverrides.skills, projectBaseDir, false);
1976
+ addResources("skills", collectAutoSkillEntries(projectDirs.skills, "pi"), projectMetadata, projectOverrides.skills, projectBaseDir);
1977
1977
  }
1978
1978
  // Project skills from .agents/ (each with its own baseDir)
1979
1979
  for (const agentsSkillsDir of projectAgentsSkillDirs) {
@@ -1982,7 +1982,7 @@ export class DefaultPackageManager {
1982
1982
  ...projectMetadata,
1983
1983
  baseDir: agentsBaseDir,
1984
1984
  };
1985
- addResources("skills", collectAutoSkillEntries(agentsSkillsDir, "agents"), agentsMetadata, projectOverrides.skills, agentsBaseDir, false);
1985
+ addResources("skills", collectAutoSkillEntries(agentsSkillsDir, "agents"), agentsMetadata, projectOverrides.skills, agentsBaseDir);
1986
1986
  }
1987
1987
  if (projectTrusted) {
1988
1988
  addResources("prompts", collectAutoPromptEntries(projectDirs.prompts), projectMetadata, projectOverrides.prompts, projectBaseDir);
@@ -2057,14 +2057,14 @@ export class DefaultPackageManager {
2057
2057
  }
2058
2058
  addResources("extensions", piHostKept, { ...userMetadata, baseDir: piHostBaseDir }, userOverrides.extensions, piHostBaseDir);
2059
2059
  // User skills from ~/.selesai/agent/
2060
- addResources("skills", collectAutoSkillEntries(userDirs.skills, "pi"), userMetadata, userOverrides.skills, globalBaseDir, false);
2060
+ addResources("skills", collectAutoSkillEntries(userDirs.skills, "pi"), userMetadata, userOverrides.skills, globalBaseDir);
2061
2061
  // User skills from ~/.agents/ (with its own baseDir)
2062
2062
  const userAgentsBaseDir = dirname(userAgentsSkillsDir);
2063
2063
  const userAgentsMetadata = {
2064
2064
  ...userMetadata,
2065
2065
  baseDir: userAgentsBaseDir,
2066
2066
  };
2067
- addResources("skills", collectAutoSkillEntries(userAgentsSkillsDir, "agents"), userAgentsMetadata, userOverrides.skills, userAgentsBaseDir, false);
2067
+ addResources("skills", collectAutoSkillEntries(userAgentsSkillsDir, "agents"), userAgentsMetadata, userOverrides.skills, userAgentsBaseDir);
2068
2068
  addResources("prompts", collectAutoPromptEntries(userDirs.prompts), userMetadata, userOverrides.prompts, globalBaseDir);
2069
2069
  addResources("themes", collectAutoThemeEntries(userDirs.themes), userMetadata, userOverrides.themes, globalBaseDir);
2070
2070
  return collisions;
@@ -6,7 +6,7 @@ import { ModelRuntime } from "./model-runtime.ts";
6
6
  import type { ResourceLoader } from "./resource-loader.ts";
7
7
  import { SessionManager } from "./session-manager.ts";
8
8
  import { SettingsManager } from "./settings-manager.ts";
9
- import { createBashTool, createCodingTools, createEditTool, createFindTool, createGrepTool, createLsTool, createReadOnlyTools, createReadTool, createWriteTool, withFileMutationQueue } from "./tools/index.ts";
9
+ import { createBashTool, createCodingTools, createEditTool, createFindTool, createGrepTool, createLsTool, createPowerShellTool, createReadOnlyTools, createReadTool, createWriteTool, withFileMutationQueue } from "./tools/index.ts";
10
10
  export interface CreateAgentSessionOptions {
11
11
  /** Working directory for project-local discovery. Default: process.cwd() */
12
12
  cwd?: string;
@@ -36,9 +36,9 @@ export interface CreateAgentSessionOptions {
36
36
  *
37
37
  * When omitted, pi uses the `defaultTools` setting for the initial built-in
38
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.
39
+ * (read, bash, edit, write). Extension/custom tools are inactive by default;
40
+ * `noTools: "builtin"` enables them instead. When provided, only the listed
41
+ * tool names are enabled.
42
42
  */
43
43
  tools?: string[];
44
44
  /** Optional denylist of tool names to disable. Applies after `tools` when both are provided. */
@@ -68,7 +68,7 @@ export type { ExtensionAPI, ExtensionCommandContext, ExtensionContext, Extension
68
68
  export type { PromptTemplate } from "./prompt-templates.ts";
69
69
  export type { Skill } from "./skills.ts";
70
70
  export type { Tool } from "./tools/index.ts";
71
- export { withFileMutationQueue, createCodingTools, createReadOnlyTools, createReadTool, createBashTool, createEditTool, createWriteTool, createGrepTool, createFindTool, createLsTool, };
71
+ export { withFileMutationQueue, createCodingTools, createReadOnlyTools, createReadTool, createBashTool, createPowerShellTool, createEditTool, createWriteTool, createGrepTool, createFindTool, createLsTool, };
72
72
  /**
73
73
  * Create an AgentSession with the specified options.
74
74
  *
package/dist/core/sdk.js CHANGED
@@ -14,7 +14,7 @@ import { DefaultResourceLoader } from "./resource-loader.js";
14
14
  import { getDefaultSessionDir, SessionManager } from "./session-manager.js";
15
15
  import { SettingsManager } from "./settings-manager.js";
16
16
  import { time } from "./timings.js";
17
- import { createBashTool, createCodingTools, createEditTool, createFindTool, createGrepTool, createLsTool, createReadOnlyTools, createReadTool, createWriteTool, withFileMutationQueue, } from "./tools/index.js";
17
+ import { createBashTool, createCodingTools, createEditTool, createFindTool, createGrepTool, createLsTool, createPowerShellTool, createReadOnlyTools, createReadTool, createWriteTool, withFileMutationQueue, } from "./tools/index.js";
18
18
  // Preserve the pre-0.81 fallback for extensions that construct Agent instances
19
19
  // or invoke low-level agent loops without supplying streamFn. Agent core remains
20
20
  // provider-agnostic and does not import pi-ai/compat itself.
@@ -23,7 +23,7 @@ setDefaultStreamFn(streamSimple);
23
23
  export * from "./agent-session-runtime.js";
24
24
  export { withFileMutationQueue,
25
25
  // Tool factories (for custom cwd)
26
- createCodingTools, createReadOnlyTools, createReadTool, createBashTool, createEditTool, createWriteTool, createGrepTool, createFindTool, createLsTool, };
26
+ createCodingTools, createReadOnlyTools, createReadTool, createBashTool, createPowerShellTool, createEditTool, createWriteTool, createGrepTool, createFindTool, createLsTool, };
27
27
  // Helper Functions
28
28
  function getDefaultAgentDir() {
29
29
  return getAgentDir();
@@ -101,6 +101,7 @@ export async function createAgentSession(options = {}) {
101
101
  defaultProvider: settingsManager.getDefaultProvider(),
102
102
  defaultModelId: settingsManager.getDefaultModel(),
103
103
  defaultThinkingLevel: settingsManager.getDefaultThinkingLevel(),
104
+ modelThinkingLevels: settingsManager.getAllModelThinkingLevels(),
104
105
  modelRuntime,
105
106
  });
106
107
  model = result.model;
@@ -118,7 +119,10 @@ export async function createAgentSession(options = {}) {
118
119
  ? existingSession.thinkingLevel
119
120
  : (settingsManager.getDefaultThinkingLevel() ?? DEFAULT_THINKING_LEVEL);
120
121
  }
121
- // Fall back to settings default
122
+ // Fall back to the selected model's override, then settings default
123
+ if (thinkingLevel === undefined && model) {
124
+ thinkingLevel = settingsManager.getModelThinkingLevel(model.provider, model.id);
125
+ }
122
126
  if (thinkingLevel === undefined) {
123
127
  thinkingLevel = settingsManager.getDefaultThinkingLevel() ?? DEFAULT_THINKING_LEVEL;
124
128
  }
@@ -134,7 +138,15 @@ export async function createAgentSession(options = {}) {
134
138
  const allowedToolNames = options.tools ?? (options.noTools === "all" ? [] : undefined);
135
139
  const excludedToolNames = options.excludeTools;
136
140
  const excludedToolNameSet = excludedToolNames ? new Set(excludedToolNames) : undefined;
137
- const initialActiveToolNames = (options.tools ?? (options.noTools ? [] : (configuredDefaultToolNames ?? defaultActiveToolNames))).filter((name) => !excludedToolNameSet?.has(name));
141
+ const initialActiveToolNames = (options.tools ??
142
+ (options.noTools === "builtin"
143
+ ? [
144
+ ...resourceLoader.getExtensions().extensions.flatMap((extension) => Array.from(extension.tools.keys())),
145
+ ...(options.customTools?.map((tool) => tool.name) ?? []),
146
+ ]
147
+ : options.noTools
148
+ ? []
149
+ : (configuredDefaultToolNames ?? defaultActiveToolNames))).filter((name) => !excludedToolNameSet?.has(name));
138
150
  let agent;
139
151
  // Create convertToLlm wrapper that filters images if blockImages is enabled (defense-in-depth)
140
152
  const convertToLlmWithBlockImages = (messages) => {
@@ -72,6 +72,8 @@ export interface Settings {
72
72
  defaultProvider?: string;
73
73
  defaultModel?: string;
74
74
  defaultThinkingLevel?: ThinkingLevel;
75
+ /** Per-model default thinking overrides, keyed by "provider/modelId". */
76
+ modelThinkingLevels?: Record<string, ThinkingLevel>;
75
77
  transport?: TransportSetting;
76
78
  steeringMode?: "all" | "one-at-a-time";
77
79
  followUpMode?: "all" | "one-at-a-time";
@@ -210,6 +212,10 @@ export declare class SettingsManager {
210
212
  setTheme(theme: string): void;
211
213
  getDefaultThinkingLevel(): ThinkingLevel | undefined;
212
214
  setDefaultThinkingLevel(level: ThinkingLevel): void;
215
+ getModelThinkingLevel(provider: string, modelId: string): ThinkingLevel | undefined;
216
+ getAllModelThinkingLevels(): Record<string, ThinkingLevel>;
217
+ setModelThinkingLevel(provider: string, modelId: string, level: ThinkingLevel): void;
218
+ removeModelThinkingLevel(provider: string, modelId: string): void;
213
219
  getTransport(): TransportSetting;
214
220
  setTransport(transport: TransportSetting): void;
215
221
  getCompactionEnabled(): boolean;
@@ -515,6 +515,28 @@ export class SettingsManager {
515
515
  this.markModified("defaultThinkingLevel");
516
516
  this.save();
517
517
  }
518
+ getModelThinkingLevel(provider, modelId) {
519
+ return this.settings.modelThinkingLevels?.[`${provider}/${modelId}`];
520
+ }
521
+ getAllModelThinkingLevels() {
522
+ return { ...(this.settings.modelThinkingLevels ?? {}) };
523
+ }
524
+ setModelThinkingLevel(provider, modelId, level) {
525
+ this.globalSettings.modelThinkingLevels ??= {};
526
+ this.globalSettings.modelThinkingLevels[`${provider}/${modelId}`] = level;
527
+ this.markModified("modelThinkingLevels");
528
+ this.save();
529
+ }
530
+ removeModelThinkingLevel(provider, modelId) {
531
+ if (!this.globalSettings.modelThinkingLevels)
532
+ return;
533
+ delete this.globalSettings.modelThinkingLevels[`${provider}/${modelId}`];
534
+ if (Object.keys(this.globalSettings.modelThinkingLevels).length === 0) {
535
+ delete this.globalSettings.modelThinkingLevels;
536
+ }
537
+ this.markModified("modelThinkingLevels");
538
+ this.save();
539
+ }
518
540
  getTransport() {
519
541
  return this.settings.transport ?? "auto";
520
542
  }
@@ -1,11 +1,16 @@
1
1
  import type { AgentTool } from "@earendil-works/pi-agent-core";
2
2
  import { type Static, Type } from "typebox";
3
+ import { type ShellConfig } from "../../utils/shell.ts";
3
4
  import type { ToolDefinition } from "../extensions/types.ts";
4
5
  import { type TruncationResult } from "./truncate.ts";
5
6
  declare const bashSchema: Type.TObject<{
6
7
  command: Type.TString;
7
8
  timeout: Type.TOptional<Type.TNumber>;
8
9
  }>;
10
+ export declare const bashToolSystemPromptContribution: {
11
+ readonly snippet: "Execute bash commands (ls, grep, find, etc.)";
12
+ readonly guidelines: readonly ["You can inspect PI_* environment variables for current model and session details."];
13
+ };
9
14
  export type BashToolInput = Static<typeof bashSchema>;
10
15
  export interface BashToolDetails {
11
16
  truncation?: TruncationResult;
@@ -32,6 +37,8 @@ export interface BashOperations {
32
37
  exitCode: number | null;
33
38
  }>;
34
39
  }
40
+ /** Shared process execution used by the built-in shell tools. */
41
+ export declare function createLocalShellOperations(shellName: string, resolveShellConfig: () => ShellConfig): BashOperations;
35
42
  /**
36
43
  * Create bash operations using pi's built-in local shell execution backend.
37
44
  *
@@ -59,11 +66,21 @@ export interface BashToolOptions {
59
66
  /** Hook to adjust command, cwd, or env before execution */
60
67
  spawnHook?: BashSpawnHook;
61
68
  }
62
- type BashRenderState = {
69
+ export type BashRenderState = {
63
70
  startedAt: number | undefined;
64
71
  endedAt: number | undefined;
65
72
  interval: NodeJS.Timeout | undefined;
66
73
  };
74
+ export interface ShellToolConfig {
75
+ name: string;
76
+ label: string;
77
+ shellName: string;
78
+ prompt: string;
79
+ promptSnippet: string;
80
+ promptGuidelines?: readonly string[];
81
+ tempFilePrefix: string;
82
+ }
83
+ export declare function createShellToolDefinition(cwd: string, config: ShellToolConfig, options?: BashToolOptions): ToolDefinition<typeof bashSchema, BashToolDetails | undefined, BashRenderState>;
67
84
  export declare function createBashToolDefinition(cwd: string, options?: BashToolOptions): ToolDefinition<typeof bashSchema, BashToolDetails | undefined, BashRenderState>;
68
85
  export declare function createBashTool(cwd: string, options?: BashToolOptions): AgentTool<typeof bashSchema>;
69
86
  export {};
@@ -7,8 +7,8 @@ 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";
11
10
  import { getShellConfig, getShellEnv, killProcessTree, trackDetachedChildPid, untrackDetachedChildPid, } from "../../utils/shell.js";
11
+ import { getExperimentalToolSampling } from "../experimental.js";
12
12
  import { OutputAccumulator } from "./output-accumulator.js";
13
13
  import { getTextOutput, invalidArgText, str } from "./render-utils.js";
14
14
  import { wrapToolDefinition } from "./tool-definition-wrapper.js";
@@ -28,28 +28,27 @@ function resolveTimeoutMs(timeout) {
28
28
  return timeoutMs;
29
29
  }
30
30
  const bashSchema = Type.Object({
31
- command: Type.String({ description: "Bash command to execute" }),
31
+ command: Type.String({ description: "Shell command to execute" }),
32
32
  timeout: Type.Optional(Type.Number({ description: "Timeout in seconds (optional, no default timeout)" })),
33
33
  });
34
- /**
35
- * Create bash operations using pi's built-in local shell execution backend.
36
- *
37
- * This is useful for extensions that intercept user_bash and still want pi's
38
- * standard local shell behavior while wrapping or rewriting commands.
39
- */
40
- export function createLocalBashOperations(options) {
34
+ export const bashToolSystemPromptContribution = {
35
+ snippet: "Execute bash commands (ls, grep, find, etc.)",
36
+ guidelines: ["You can inspect PI_* environment variables for current model and session details."],
37
+ };
38
+ /** Shared process execution used by the built-in shell tools. */
39
+ export function createLocalShellOperations(shellName, resolveShellConfig) {
41
40
  return {
42
41
  exec: async (command, cwd, { onData, signal, timeout, env }) => {
43
42
  const timeoutMs = resolveTimeoutMs(timeout);
44
43
  if (signal?.aborted) {
45
44
  throw new Error("aborted");
46
45
  }
47
- const shellConfig = getShellConfig(options?.shellPath);
46
+ const shellConfig = resolveShellConfig();
48
47
  try {
49
48
  await fsAccess(cwd, constants.F_OK);
50
49
  }
51
50
  catch {
52
- throw new Error(`Working directory does not exist: ${cwd}\nCannot execute bash commands.`);
51
+ throw new Error(`Working directory does not exist: ${cwd}\nCannot execute ${shellName} commands.`);
53
52
  }
54
53
  const commandFromStdin = shellConfig.commandTransport === "stdin";
55
54
  const child = spawn(shellConfig.shell, commandFromStdin ? shellConfig.args : [...shellConfig.args, command], {
@@ -112,6 +111,15 @@ export function createLocalBashOperations(options) {
112
111
  },
113
112
  };
114
113
  }
114
+ /**
115
+ * Create bash operations using pi's built-in local shell execution backend.
116
+ *
117
+ * This is useful for extensions that intercept user_bash and still want pi's
118
+ * standard local shell behavior while wrapping or rewriting commands.
119
+ */
120
+ export function createLocalBashOperations(options) {
121
+ return createLocalShellOperations("bash", () => getShellConfig(options?.shellPath));
122
+ }
115
123
  function resolveSpawnContext(command, cwd, spawnHook, exposeSessionEnvironment, ctx) {
116
124
  const env = { ...getShellEnv() };
117
125
  delete env.PI_SESSION_ID;
@@ -147,12 +155,12 @@ class BashResultRenderComponent extends Container {
147
155
  function formatDuration(ms) {
148
156
  return `${(ms / 1000).toFixed(1)}s`;
149
157
  }
150
- function formatBashCall(args) {
158
+ function formatShellCall(args, prompt) {
151
159
  const command = str(args?.command);
152
160
  const timeout = args?.timeout;
153
161
  const timeoutSuffix = timeout ? theme.fg("muted", ` (timeout ${timeout}s)`) : "";
154
162
  const commandDisplay = command === null ? invalidArgText(theme) : command ? command : theme.fg("toolOutput", "...");
155
- return theme.fg("toolTitle", theme.bold(`$ ${commandDisplay}`)) + timeoutSuffix;
163
+ return theme.fg("toolTitle", theme.bold(`${prompt} ${commandDisplay}`)) + timeoutSuffix;
156
164
  }
157
165
  function rebuildBashResultRenderComponent(component, result, options, showImages, startedAt, endedAt) {
158
166
  const state = component.state;
@@ -219,25 +227,23 @@ function rebuildBashResultRenderComponent(component, result, options, showImages
219
227
  component.addChild(new Text(`\n${theme.fg("muted", `${label} ${formatDuration(endTime - startedAt)}`)}`, 0, 0));
220
228
  }
221
229
  }
222
- export function createBashToolDefinition(cwd, options) {
230
+ export function createShellToolDefinition(cwd, config, options) {
223
231
  const ops = options?.operations ?? createLocalBashOperations({ shellPath: options?.shellPath });
224
232
  const commandPrefix = options?.commandPrefix;
225
233
  const exposeSessionEnvironment = options?.exposeSessionEnvironment ?? true;
226
234
  const spawnHook = options?.spawnHook;
227
235
  return {
228
- name: "bash",
229
- label: "bash",
230
- description: `Execute a bash command in the current working directory. Returns stdout and stderr. Output is truncated to last ${DEFAULT_MAX_LINES} lines or ${DEFAULT_MAX_BYTES / 1024}KB (whichever is hit first). If truncated, full output is saved to a temp file. Optionally provide a timeout in seconds.`,
231
- promptSnippet: "Execute bash commands (ls, grep, find, etc.)",
232
- promptGuidelines: exposeSessionEnvironment
233
- ? ["Inspect PI_* environment variables for current model and session details."]
234
- : undefined,
236
+ name: config.name,
237
+ label: config.label,
238
+ description: `Execute a ${config.shellName} command in the current working directory. Returns stdout and stderr. Output is truncated to last ${DEFAULT_MAX_LINES} lines or ${DEFAULT_MAX_BYTES / 1024}KB (whichever is hit first). If truncated, full output is saved to a temp file. Optionally provide a timeout in seconds.`,
239
+ promptSnippet: config.promptSnippet,
240
+ promptGuidelines: exposeSessionEnvironment && config.promptGuidelines ? [...config.promptGuidelines] : undefined,
235
241
  parameters: bashSchema,
236
242
  constrainedSampling: getExperimentalToolSampling(),
237
243
  async execute(_toolCallId, { command, timeout }, signal, onUpdate, ctx) {
238
244
  const resolvedCommand = commandPrefix ? `${commandPrefix}\n${command}` : command;
239
245
  const spawnContext = resolveSpawnContext(resolvedCommand, cwd, spawnHook, exposeSessionEnvironment, ctx);
240
- const output = new OutputAccumulator({ tempFilePrefix: "pi-bash" });
246
+ const output = new OutputAccumulator({ tempFilePrefix: config.tempFilePrefix });
241
247
  let acceptingOutput = true;
242
248
  let updateTimer;
243
249
  let updateDirty = false;
@@ -358,7 +364,7 @@ export function createBashToolDefinition(cwd, options) {
358
364
  state.endedAt = undefined;
359
365
  }
360
366
  const text = context.lastComponent ?? new Text("", 0, 0);
361
- text.setText(formatBashCall(args));
367
+ text.setText(formatShellCall(args, config.prompt));
362
368
  return text;
363
369
  },
364
370
  renderResult(result, options, _theme, context) {
@@ -380,6 +386,18 @@ export function createBashToolDefinition(cwd, options) {
380
386
  },
381
387
  };
382
388
  }
389
+ const bashToolConfig = {
390
+ name: "bash",
391
+ label: "bash",
392
+ shellName: "bash",
393
+ prompt: "$",
394
+ promptSnippet: bashToolSystemPromptContribution.snippet,
395
+ promptGuidelines: bashToolSystemPromptContribution.guidelines,
396
+ tempFilePrefix: "selesai-bash",
397
+ };
398
+ export function createBashToolDefinition(cwd, options) {
399
+ return createShellToolDefinition(cwd, bashToolConfig, options);
400
+ }
383
401
  export function createBashTool(cwd, options) {
384
402
  const definition = createBashToolDefinition(cwd, options);
385
403
  const tool = wrapToolDefinition(definition);
@@ -1,4 +1,5 @@
1
1
  export { type BashOperations, type BashSpawnContext, type BashSpawnHook, type BashToolDetails, type BashToolInput, type BashToolOptions, createBashTool, createBashToolDefinition, createLocalBashOperations, } from "./bash.ts";
2
+ export { createLocalPowerShellOperations, createPowerShellTool, createPowerShellToolDefinition, type PowerShellOperations, type PowerShellSpawnContext, type PowerShellSpawnHook, type PowerShellToolDetails, type PowerShellToolInput, type PowerShellToolOptions, } from "./powershell.ts";
2
3
  export { createEditTool, createEditToolDefinition, type EditOperations, type EditToolDetails, type EditToolInput, type EditToolOptions, } from "./edit.ts";
3
4
  export { withFileMutationQueue } from "./file-mutation-queue.ts";
4
5
  export { createFindTool, createFindToolDefinition, type FindOperations, type FindToolDetails, type FindToolInput, type FindToolOptions, } from "./find.ts";
@@ -15,15 +16,17 @@ import { type EditToolOptions } from "./edit.ts";
15
16
  import { type FindToolOptions } from "./find.ts";
16
17
  import { type GrepToolOptions } from "./grep.ts";
17
18
  import { type LsToolOptions } from "./ls.ts";
19
+ import { type PowerShellToolOptions } from "./powershell.ts";
18
20
  import { type ReadToolOptions } from "./read.ts";
19
21
  import { type WriteToolOptions } from "./write.ts";
20
22
  export type Tool = AgentTool<any>;
21
23
  export type ToolDef = ToolDefinition<any, any>;
22
- export type ToolName = "read" | "bash" | "edit" | "write" | "grep" | "find" | "ls";
24
+ export type ToolName = "read" | "bash" | "powershell" | "edit" | "write" | "grep" | "find" | "ls";
23
25
  export declare const allToolNames: Set<ToolName>;
24
26
  export interface ToolsOptions {
25
27
  read?: ReadToolOptions;
26
28
  bash?: BashToolOptions;
29
+ powershell?: PowerShellToolOptions;
27
30
  write?: WriteToolOptions;
28
31
  edit?: EditToolOptions;
29
32
  grep?: GrepToolOptions;
@@ -1,4 +1,5 @@
1
1
  export { createBashTool, createBashToolDefinition, createLocalBashOperations, } from "./bash.js";
2
+ export { createLocalPowerShellOperations, createPowerShellTool, createPowerShellToolDefinition, } from "./powershell.js";
2
3
  export { createEditTool, createEditToolDefinition, } from "./edit.js";
3
4
  export { withFileMutationQueue } from "./file-mutation-queue.js";
4
5
  export { createFindTool, createFindToolDefinition, } from "./find.js";
@@ -13,15 +14,18 @@ import { createEditTool, createEditToolDefinition } from "./edit.js";
13
14
  import { createFindTool, createFindToolDefinition } from "./find.js";
14
15
  import { createGrepTool, createGrepToolDefinition } from "./grep.js";
15
16
  import { createLsTool, createLsToolDefinition } from "./ls.js";
17
+ import { createPowerShellTool, createPowerShellToolDefinition } from "./powershell.js";
16
18
  import { createReadTool, createReadToolDefinition } from "./read.js";
17
19
  import { createWriteTool, createWriteToolDefinition } from "./write.js";
18
- export const allToolNames = new Set(["read", "bash", "edit", "write", "grep", "find", "ls"]);
20
+ export const allToolNames = new Set(["read", "bash", "powershell", "edit", "write", "grep", "find", "ls"]);
19
21
  export function createToolDefinition(toolName, cwd, options) {
20
22
  switch (toolName) {
21
23
  case "read":
22
24
  return createReadToolDefinition(cwd, options?.read);
23
25
  case "bash":
24
26
  return createBashToolDefinition(cwd, options?.bash);
27
+ case "powershell":
28
+ return createPowerShellToolDefinition(cwd, options?.powershell);
25
29
  case "edit":
26
30
  return createEditToolDefinition(cwd, options?.edit);
27
31
  case "write":
@@ -42,6 +46,8 @@ export function createTool(toolName, cwd, options) {
42
46
  return createReadTool(cwd, options?.read);
43
47
  case "bash":
44
48
  return createBashTool(cwd, options?.bash);
49
+ case "powershell":
50
+ return createPowerShellTool(cwd, options?.powershell);
45
51
  case "edit":
46
52
  return createEditTool(cwd, options?.edit);
47
53
  case "write":
@@ -76,6 +82,7 @@ export function createAllToolDefinitions(cwd, options) {
76
82
  return {
77
83
  read: createReadToolDefinition(cwd, options?.read),
78
84
  bash: createBashToolDefinition(cwd, options?.bash),
85
+ powershell: createPowerShellToolDefinition(cwd, options?.powershell),
79
86
  edit: createEditToolDefinition(cwd, options?.edit),
80
87
  write: createWriteToolDefinition(cwd, options?.write),
81
88
  grep: createGrepToolDefinition(cwd, options?.grep),
@@ -103,6 +110,7 @@ export function createAllTools(cwd, options) {
103
110
  return {
104
111
  read: createReadTool(cwd, options?.read),
105
112
  bash: createBashTool(cwd, options?.bash),
113
+ powershell: createPowerShellTool(cwd, options?.powershell),
106
114
  edit: createEditTool(cwd, options?.edit),
107
115
  write: createWriteTool(cwd, options?.write),
108
116
  grep: createGrepTool(cwd, options?.grep),
@@ -0,0 +1,15 @@
1
+ import { type BashOperations, type BashSpawnContext, type BashSpawnHook, type BashToolDetails, type BashToolInput, type BashToolOptions, type createBashTool, createShellToolDefinition } from "./bash.ts";
2
+ export declare const powershellToolSystemPromptContribution: {
3
+ readonly snippet: "Execute PowerShell commands";
4
+ readonly guidelines: readonly ["You can inspect PI_* environment variables for current model and session details."];
5
+ };
6
+ export type PowerShellOperations = BashOperations;
7
+ export type PowerShellSpawnContext = BashSpawnContext;
8
+ export type PowerShellSpawnHook = BashSpawnHook;
9
+ export type PowerShellToolDetails = BashToolDetails;
10
+ export type PowerShellToolInput = BashToolInput;
11
+ export interface PowerShellToolOptions extends Pick<BashToolOptions, "operations" | "exposeSessionEnvironment" | "spawnHook"> {
12
+ }
13
+ export declare function createLocalPowerShellOperations(): PowerShellOperations;
14
+ export declare function createPowerShellToolDefinition(cwd: string, options?: PowerShellToolOptions): ReturnType<typeof createShellToolDefinition>;
15
+ export declare function createPowerShellTool(cwd: string, options?: PowerShellToolOptions): ReturnType<typeof createBashTool>;
@@ -0,0 +1,38 @@
1
+ import { getPowerShellConfig } from "../../utils/shell.js";
2
+ import { createLocalShellOperations, createShellToolDefinition, } from "./bash.js";
3
+ import { wrapToolDefinition } from "./tool-definition-wrapper.js";
4
+ const UTF8_OUTPUT_PREFIX = "try { [Console]::OutputEncoding=[System.Text.Encoding]::UTF8 } catch {}\n";
5
+ export const powershellToolSystemPromptContribution = {
6
+ snippet: "Execute PowerShell commands",
7
+ guidelines: ["You can inspect PI_* environment variables for current model and session details."],
8
+ };
9
+ export function createLocalPowerShellOperations() {
10
+ const operations = createLocalShellOperations("PowerShell", getPowerShellConfig);
11
+ return {
12
+ exec: (command, cwd, options) => operations.exec(`${UTF8_OUTPUT_PREFIX}${command}`, cwd, options),
13
+ };
14
+ }
15
+ const powershellToolConfig = {
16
+ name: "powershell",
17
+ label: "powershell",
18
+ shellName: "PowerShell",
19
+ prompt: "PS>",
20
+ promptSnippet: powershellToolSystemPromptContribution.snippet,
21
+ promptGuidelines: powershellToolSystemPromptContribution.guidelines,
22
+ tempFilePrefix: "selesai-powershell",
23
+ };
24
+ export function createPowerShellToolDefinition(cwd, options) {
25
+ return createShellToolDefinition(cwd, powershellToolConfig, {
26
+ ...options,
27
+ operations: options?.operations ?? createLocalPowerShellOperations(),
28
+ });
29
+ }
30
+ export function createPowerShellTool(cwd, options) {
31
+ const definition = createPowerShellToolDefinition(cwd, options);
32
+ const tool = wrapToolDefinition(definition);
33
+ Object.assign(tool, {
34
+ promptSnippet: definition.promptSnippet,
35
+ promptGuidelines: definition.promptGuidelines,
36
+ });
37
+ return tool;
38
+ }