@oh-my-pi/pi-coding-agent 13.18.0 → 14.0.2

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 (235) hide show
  1. package/CHANGELOG.md +316 -1
  2. package/package.json +86 -24
  3. package/scripts/format-prompts.ts +2 -2
  4. package/src/autoresearch/apply-contract-to-state.ts +24 -0
  5. package/src/autoresearch/contract.ts +0 -44
  6. package/src/autoresearch/dashboard.ts +1 -2
  7. package/src/autoresearch/git.ts +116 -30
  8. package/src/autoresearch/helpers.ts +49 -0
  9. package/src/autoresearch/index.ts +28 -187
  10. package/src/autoresearch/prompt.md +26 -9
  11. package/src/autoresearch/state.ts +0 -6
  12. package/src/autoresearch/tools/init-experiment.ts +202 -117
  13. package/src/autoresearch/tools/log-experiment.ts +123 -178
  14. package/src/autoresearch/tools/run-experiment.ts +48 -10
  15. package/src/autoresearch/types.ts +2 -2
  16. package/src/capability/index.ts +4 -2
  17. package/src/cli/file-processor.ts +3 -3
  18. package/src/cli/grep-cli.ts +8 -8
  19. package/src/cli/grievances-cli.ts +78 -0
  20. package/src/cli/read-cli.ts +67 -0
  21. package/src/cli/setup-cli.ts +4 -4
  22. package/src/cli/update-cli.ts +3 -3
  23. package/src/cli.ts +2 -0
  24. package/src/commands/grep.ts +6 -1
  25. package/src/commands/grievances.ts +20 -0
  26. package/src/commands/read.ts +33 -0
  27. package/src/commit/agentic/agent.ts +5 -8
  28. package/src/commit/agentic/index.ts +22 -26
  29. package/src/commit/agentic/tools/analyze-file.ts +3 -3
  30. package/src/commit/agentic/tools/git-file-diff.ts +3 -6
  31. package/src/commit/agentic/tools/git-hunk.ts +3 -3
  32. package/src/commit/agentic/tools/git-overview.ts +6 -9
  33. package/src/commit/agentic/tools/index.ts +6 -8
  34. package/src/commit/agentic/tools/propose-commit.ts +4 -7
  35. package/src/commit/agentic/tools/recent-commits.ts +3 -3
  36. package/src/commit/agentic/tools/split-commit.ts +4 -4
  37. package/src/commit/agentic/validation.ts +1 -1
  38. package/src/commit/analysis/conventional.ts +4 -4
  39. package/src/commit/analysis/summary.ts +3 -3
  40. package/src/commit/changelog/generate.ts +4 -4
  41. package/src/commit/changelog/index.ts +5 -9
  42. package/src/commit/map-reduce/map-phase.ts +4 -4
  43. package/src/commit/map-reduce/reduce-phase.ts +4 -4
  44. package/src/commit/pipeline.ts +13 -16
  45. package/src/config/keybindings.ts +7 -6
  46. package/src/config/prompt-templates.ts +44 -226
  47. package/src/config/resolve-config-value.ts +4 -2
  48. package/src/config/settings-schema.ts +98 -2
  49. package/src/config/settings.ts +25 -26
  50. package/src/dap/client.ts +674 -0
  51. package/src/dap/config.ts +150 -0
  52. package/src/dap/defaults.json +211 -0
  53. package/src/dap/index.ts +4 -0
  54. package/src/dap/session.ts +1255 -0
  55. package/src/dap/types.ts +600 -0
  56. package/src/debug/log-viewer.ts +3 -2
  57. package/src/discovery/builtin.ts +1 -2
  58. package/src/discovery/codex.ts +2 -2
  59. package/src/discovery/github.ts +2 -1
  60. package/src/discovery/helpers.ts +2 -2
  61. package/src/discovery/opencode.ts +2 -2
  62. package/src/edit/diff.ts +818 -0
  63. package/src/edit/index.ts +309 -0
  64. package/src/edit/line-hash.ts +67 -0
  65. package/src/edit/modes/chunk.ts +454 -0
  66. package/src/{patch → edit/modes}/hashline.ts +741 -361
  67. package/src/{patch/applicator.ts → edit/modes/patch.ts} +420 -117
  68. package/src/{patch/fuzzy.ts → edit/modes/replace.ts} +519 -197
  69. package/src/{patch → edit}/normalize.ts +97 -76
  70. package/src/{patch/shared.ts → edit/renderer.ts} +181 -108
  71. package/src/exec/bash-executor.ts +4 -2
  72. package/src/exec/idle-timeout-watchdog.ts +126 -0
  73. package/src/exec/non-interactive-env.ts +5 -0
  74. package/src/extensibility/custom-commands/bundled/ci-green/index.ts +6 -18
  75. package/src/extensibility/custom-commands/bundled/review/index.ts +45 -43
  76. package/src/extensibility/custom-commands/loader.ts +1 -2
  77. package/src/extensibility/custom-tools/loader.ts +34 -11
  78. package/src/extensibility/custom-tools/types.ts +1 -1
  79. package/src/extensibility/extensions/loader.ts +9 -4
  80. package/src/extensibility/extensions/runner.ts +24 -1
  81. package/src/extensibility/extensions/types.ts +4 -2
  82. package/src/extensibility/hooks/loader.ts +5 -6
  83. package/src/extensibility/hooks/types.ts +2 -2
  84. package/src/extensibility/plugins/doctor.ts +2 -1
  85. package/src/extensibility/plugins/marketplace/fetcher.ts +2 -57
  86. package/src/extensibility/plugins/marketplace/source-resolver.ts +4 -4
  87. package/src/extensibility/slash-commands.ts +3 -7
  88. package/src/index.ts +3 -1
  89. package/src/internal-urls/docs-index.generated.ts +11 -11
  90. package/src/ipy/executor.ts +58 -17
  91. package/src/ipy/gateway-coordinator.ts +6 -4
  92. package/src/ipy/kernel.ts +45 -22
  93. package/src/ipy/runtime.ts +2 -2
  94. package/src/lsp/client.ts +7 -4
  95. package/src/lsp/clients/lsp-linter-client.ts +4 -4
  96. package/src/lsp/config.ts +2 -2
  97. package/src/lsp/defaults.json +688 -154
  98. package/src/lsp/index.ts +234 -45
  99. package/src/lsp/lspmux.ts +2 -2
  100. package/src/lsp/startup-events.ts +13 -0
  101. package/src/lsp/types.ts +12 -1
  102. package/src/lsp/utils.ts +8 -1
  103. package/src/main.ts +125 -47
  104. package/src/memories/index.ts +4 -5
  105. package/src/modes/acp/acp-agent.ts +563 -163
  106. package/src/modes/acp/acp-event-mapper.ts +9 -1
  107. package/src/modes/acp/acp-mode.ts +4 -2
  108. package/src/modes/components/agent-dashboard.ts +3 -4
  109. package/src/modes/components/diff.ts +6 -7
  110. package/src/modes/components/footer.ts +9 -29
  111. package/src/modes/components/hook-editor.ts +3 -3
  112. package/src/modes/components/hook-selector.ts +6 -1
  113. package/src/modes/components/read-tool-group.ts +6 -12
  114. package/src/modes/components/session-observer-overlay.ts +472 -0
  115. package/src/modes/components/settings-defs.ts +24 -0
  116. package/src/modes/components/status-line.ts +15 -61
  117. package/src/modes/components/tool-execution.ts +1 -1
  118. package/src/modes/components/welcome.ts +1 -1
  119. package/src/modes/controllers/btw-controller.ts +2 -2
  120. package/src/modes/controllers/command-controller.ts +4 -2
  121. package/src/modes/controllers/event-controller.ts +59 -2
  122. package/src/modes/controllers/extension-ui-controller.ts +1 -0
  123. package/src/modes/controllers/input-controller.ts +15 -8
  124. package/src/modes/controllers/selector-controller.ts +26 -0
  125. package/src/modes/index.ts +20 -2
  126. package/src/modes/interactive-mode.ts +278 -69
  127. package/src/modes/rpc/host-tools.ts +186 -0
  128. package/src/modes/rpc/rpc-client.ts +178 -13
  129. package/src/modes/rpc/rpc-mode.ts +73 -3
  130. package/src/modes/rpc/rpc-types.ts +53 -1
  131. package/src/modes/session-observer-registry.ts +146 -0
  132. package/src/modes/shared.ts +0 -42
  133. package/src/modes/theme/theme.ts +80 -8
  134. package/src/modes/types.ts +4 -2
  135. package/src/modes/utils/keybinding-matchers.ts +9 -0
  136. package/src/prompts/system/custom-system-prompt.md +5 -0
  137. package/src/prompts/system/system-prompt.md +8 -1
  138. package/src/prompts/tools/chunk-edit.md +219 -0
  139. package/src/prompts/tools/debug.md +43 -0
  140. package/src/prompts/tools/grep.md +3 -0
  141. package/src/prompts/tools/lsp.md +5 -5
  142. package/src/prompts/tools/read-chunk.md +17 -0
  143. package/src/prompts/tools/read.md +19 -5
  144. package/src/sdk.ts +216 -165
  145. package/src/secrets/index.ts +1 -1
  146. package/src/secrets/obfuscator.ts +25 -17
  147. package/src/session/agent-session.ts +381 -286
  148. package/src/session/agent-storage.ts +12 -12
  149. package/src/session/compaction/branch-summarization.ts +3 -3
  150. package/src/session/compaction/compaction.ts +5 -6
  151. package/src/session/compaction/utils.ts +3 -3
  152. package/src/session/history-storage.ts +62 -19
  153. package/src/session/messages.ts +3 -3
  154. package/src/session/session-dump-format.ts +203 -0
  155. package/src/session/session-manager.ts +15 -5
  156. package/src/session/session-storage.ts +4 -2
  157. package/src/session/streaming-output.ts +1 -1
  158. package/src/session/tool-choice-queue.ts +213 -0
  159. package/src/slash-commands/builtin-registry.ts +56 -8
  160. package/src/ssh/connection-manager.ts +2 -2
  161. package/src/ssh/sshfs-mount.ts +5 -5
  162. package/src/stt/downloader.ts +4 -4
  163. package/src/stt/recorder.ts +4 -4
  164. package/src/stt/transcriber.ts +2 -2
  165. package/src/system-prompt.ts +25 -13
  166. package/src/task/agents.ts +5 -6
  167. package/src/task/commands.ts +2 -5
  168. package/src/task/executor.ts +32 -4
  169. package/src/task/index.ts +91 -82
  170. package/src/task/template.ts +2 -2
  171. package/src/task/types.ts +25 -0
  172. package/src/task/worktree.ts +131 -149
  173. package/src/tools/ask.ts +2 -3
  174. package/src/tools/ast-edit.ts +7 -7
  175. package/src/tools/ast-grep.ts +7 -7
  176. package/src/tools/auto-generated-guard.ts +36 -41
  177. package/src/tools/await-tool.ts +2 -2
  178. package/src/tools/bash.ts +5 -23
  179. package/src/tools/browser.ts +4 -5
  180. package/src/tools/calculator.ts +2 -3
  181. package/src/tools/cancel-job.ts +2 -2
  182. package/src/tools/checkpoint.ts +3 -3
  183. package/src/tools/debug.ts +1007 -0
  184. package/src/tools/exit-plan-mode.ts +3 -3
  185. package/src/tools/fetch.ts +67 -3
  186. package/src/tools/find.ts +4 -5
  187. package/src/tools/fs-cache-invalidation.ts +5 -0
  188. package/src/tools/gemini-image.ts +13 -5
  189. package/src/tools/gh.ts +130 -308
  190. package/src/tools/grep.ts +57 -9
  191. package/src/tools/index.ts +44 -22
  192. package/src/tools/inspect-image.ts +4 -4
  193. package/src/tools/output-meta.ts +1 -1
  194. package/src/tools/python.ts +19 -6
  195. package/src/tools/read.ts +211 -146
  196. package/src/tools/render-mermaid.ts +2 -3
  197. package/src/tools/render-utils.ts +20 -6
  198. package/src/tools/renderers.ts +3 -1
  199. package/src/tools/report-tool-issue.ts +80 -0
  200. package/src/tools/resolve.ts +70 -39
  201. package/src/tools/search-tool-bm25.ts +2 -2
  202. package/src/tools/ssh.ts +2 -2
  203. package/src/tools/todo-write.ts +2 -2
  204. package/src/tools/tool-timeouts.ts +1 -0
  205. package/src/tools/write.ts +5 -6
  206. package/src/tui/tree-list.ts +3 -1
  207. package/src/utils/clipboard.ts +80 -0
  208. package/src/utils/commit-message-generator.ts +2 -3
  209. package/src/utils/edit-mode.ts +49 -0
  210. package/src/utils/external-editor.ts +11 -5
  211. package/src/utils/file-display-mode.ts +6 -5
  212. package/src/utils/file-mentions.ts +8 -7
  213. package/src/utils/git.ts +1400 -0
  214. package/src/utils/image-loading.ts +98 -0
  215. package/src/utils/title-generator.ts +2 -3
  216. package/src/utils/tools-manager.ts +6 -6
  217. package/src/web/scrapers/choosealicense.ts +1 -1
  218. package/src/web/search/index.ts +3 -3
  219. package/src/web/search/render.ts +6 -4
  220. package/src/autoresearch/command-initialize.md +0 -34
  221. package/src/commit/git/errors.ts +0 -9
  222. package/src/commit/git/index.ts +0 -210
  223. package/src/commit/git/operations.ts +0 -54
  224. package/src/patch/diff.ts +0 -433
  225. package/src/patch/index.ts +0 -888
  226. package/src/patch/parser.ts +0 -532
  227. package/src/patch/types.ts +0 -292
  228. package/src/prompts/agents/oracle.md +0 -77
  229. package/src/tools/gh-cli.ts +0 -125
  230. package/src/tools/pending-action.ts +0 -49
  231. package/src/utils/child-process.ts +0 -88
  232. package/src/utils/frontmatter.ts +0 -117
  233. package/src/utils/image-input.ts +0 -274
  234. package/src/utils/mime.ts +0 -53
  235. package/src/utils/prompt-format.ts +0 -170
@@ -9,7 +9,6 @@ import {
9
9
  type UsageLimit,
10
10
  type UsageReport,
11
11
  } from "@oh-my-pi/pi-ai";
12
- import { copyToClipboard } from "@oh-my-pi/pi-natives";
13
12
  import { Loader, Markdown, padding, Spacer, Text, visibleWidth } from "@oh-my-pi/pi-tui";
14
13
  import { formatDuration, Snowflake, setProjectDir } from "@oh-my-pi/pi-utils";
15
14
  import { $ } from "bun";
@@ -33,6 +32,7 @@ import { outputMeta } from "../../tools/output-meta";
33
32
  import { resolveToCwd, stripOuterDoubleQuotes } from "../../tools/path-utils";
34
33
  import { replaceTabs } from "../../tools/render-utils";
35
34
  import { getChangelogPath, parseChangelog } from "../../utils/changelog";
35
+ import { copyToClipboard } from "../../utils/clipboard";
36
36
  import { openPath } from "../../utils/open";
37
37
  import { setSessionTerminalTitle } from "../../utils/title-generator";
38
38
 
@@ -396,7 +396,8 @@ export class CommandController {
396
396
  if (this.ctx.lspServers && this.ctx.lspServers.length > 0) {
397
397
  info += `\n${theme.bold("LSP Servers")}\n`;
398
398
  for (const server of this.ctx.lspServers) {
399
- const statusColor = server.status === "ready" ? "success" : "error";
399
+ const statusColor =
400
+ server.status === "ready" ? "success" : server.status === "connecting" ? "warning" : "error";
400
401
  const statusText =
401
402
  server.status === "error" && server.error ? `${server.status}: ${server.error}` : server.status;
402
403
  info += `${theme.fg("dim", `${server.name}:`)} ${theme.fg(statusColor, statusText)} ${theme.fg("dim", `(${server.fileTypes.join(", ")})`)}\n`;
@@ -586,6 +587,7 @@ export class CommandController {
586
587
  }
587
588
  }
588
589
  await this.ctx.session.newSession();
590
+ this.ctx.resetObserverRegistry();
589
591
  setSessionTerminalTitle(this.ctx.sessionManager.getSessionName(), this.ctx.sessionManager.getCwd());
590
592
 
591
593
  this.ctx.statusLine.invalidate();
@@ -1,5 +1,5 @@
1
1
  import { INTENT_FIELD } from "@oh-my-pi/pi-agent-core";
2
- import type { ImageContent } from "@oh-my-pi/pi-ai";
2
+ import type { AssistantMessage, ImageContent } from "@oh-my-pi/pi-ai";
3
3
  import { Loader, TERMINAL, Text } from "@oh-my-pi/pi-tui";
4
4
  import { settings } from "../../config/settings";
5
5
  import { AssistantMessageComponent } from "../../modes/components/assistant-message";
@@ -10,6 +10,7 @@ import { TtsrNotificationComponent } from "../../modes/components/ttsr-notificat
10
10
  import { getSymbolTheme, theme } from "../../modes/theme/theme";
11
11
  import type { InteractiveModeContext, TodoPhase } from "../../modes/types";
12
12
  import type { AgentSessionEvent } from "../../session/agent-session";
13
+ import { calculatePromptTokens } from "../../session/compaction/compaction";
13
14
  import type { ExitPlanModeDetails } from "../../tools";
14
15
 
15
16
  export class EventController {
@@ -21,8 +22,13 @@ export class EventController {
21
22
  #readToolCallArgs = new Map<string, Record<string, unknown>>();
22
23
  #readToolCallAssistantComponents = new Map<string, AssistantMessageComponent>();
23
24
  #lastAssistantComponent: AssistantMessageComponent | undefined = undefined;
25
+ #idleCompactionTimer?: NodeJS.Timeout;
24
26
  constructor(private ctx: InteractiveModeContext) {}
25
27
 
28
+ dispose(): void {
29
+ this.#cancelIdleCompaction();
30
+ }
31
+
26
32
  #resetReadGroup(): void {
27
33
  this.#lastReadGroup = undefined;
28
34
  }
@@ -107,6 +113,7 @@ export class EventController {
107
113
  this.ctx.retryLoader = undefined;
108
114
  this.ctx.statusContainer.clear();
109
115
  }
116
+ this.#cancelIdleCompaction();
110
117
  this.ctx.ensureLoadingAnimation();
111
118
  this.ctx.ui.requestRender();
112
119
  break;
@@ -434,16 +441,19 @@ export class EventController {
434
441
  this.#readToolCallAssistantComponents.clear();
435
442
  this.#lastAssistantComponent = undefined;
436
443
  this.ctx.ui.requestRender();
444
+ this.#scheduleIdleCompaction();
437
445
  this.sendCompletionNotification();
438
446
  break;
439
447
 
440
448
  case "auto_compaction_start": {
449
+ this.#cancelIdleCompaction();
441
450
  this.ctx.autoCompactionEscapeHandler = this.ctx.editor.onEscape;
442
451
  this.ctx.editor.onEscape = () => {
443
452
  this.ctx.session.abortCompaction();
444
453
  };
445
454
  this.ctx.statusContainer.clear();
446
- const reasonText = event.reason === "overflow" ? "Context overflow detected, " : "";
455
+ const reasonText =
456
+ event.reason === "overflow" ? "Context overflow detected, " : event.reason === "idle" ? "Idle " : "";
447
457
  const actionLabel = event.action === "handoff" ? "Auto-handoff" : "Auto context-full maintenance";
448
458
  this.ctx.autoCompactionLoader = new Loader(
449
459
  this.ctx.ui,
@@ -458,6 +468,7 @@ export class EventController {
458
468
  }
459
469
 
460
470
  case "auto_compaction_end": {
471
+ this.#cancelIdleCompaction();
461
472
  if (this.ctx.autoCompactionEscapeHandler) {
462
473
  this.ctx.editor.onEscape = this.ctx.autoCompactionEscapeHandler;
463
474
  this.ctx.autoCompactionEscapeHandler = undefined;
@@ -565,6 +576,52 @@ export class EventController {
565
576
  }
566
577
  }
567
578
 
579
+ #cancelIdleCompaction(): void {
580
+ if (this.#idleCompactionTimer) {
581
+ clearTimeout(this.#idleCompactionTimer);
582
+ this.#idleCompactionTimer = undefined;
583
+ }
584
+ }
585
+
586
+ #scheduleIdleCompaction(): void {
587
+ this.#cancelIdleCompaction();
588
+ // Don't schedule while compaction/handoff is already running — the agent_end from a
589
+ // handoff agent turn still has the old session's bloated token counts, and scheduling
590
+ // here would fire after the session resets, trying to handoff an empty session.
591
+ if (this.ctx.session.isCompacting) return;
592
+
593
+ const idleSettings = settings.getGroup("compaction");
594
+ if (!idleSettings.idleEnabled) return;
595
+
596
+ // Only if input is empty
597
+ if (this.ctx.editor.getText().trim()) return;
598
+
599
+ const threshold = idleSettings.idleThresholdTokens;
600
+ if (threshold <= 0) return;
601
+ if (this.#currentContextTokens() < threshold) return;
602
+
603
+ const timeoutMs = Math.max(60, Math.min(3600, idleSettings.idleTimeoutSeconds)) * 1000;
604
+ this.#idleCompactionTimer = setTimeout(() => {
605
+ this.#idleCompactionTimer = undefined;
606
+ // Re-check conditions before firing. Pruning may have run between arming
607
+ // the timer and now, dropping usage back below the idle threshold.
608
+ if (this.ctx.session.isStreaming) return;
609
+ if (this.ctx.session.isCompacting) return;
610
+ if (this.ctx.editor.getText().trim()) return;
611
+ if (this.#currentContextTokens() < threshold) return;
612
+ void this.ctx.session.runIdleCompaction();
613
+ }, timeoutMs);
614
+ this.#idleCompactionTimer.unref?.();
615
+ }
616
+
617
+ #currentContextTokens(): number {
618
+ const lastAssistant = this.ctx.session.agent.state.messages
619
+ .slice()
620
+ .reverse()
621
+ .find((m): m is AssistantMessage => m.role === "assistant" && m.stopReason !== "aborted");
622
+ return lastAssistant?.usage ? calculatePromptTokens(lastAssistant.usage) : 0;
623
+ }
624
+
568
625
  sendCompletionNotification(): void {
569
626
  if (this.ctx.isBackgrounded === false) return;
570
627
  const notify = settings.get("completion.notify");
@@ -676,6 +676,7 @@ export class ExtensionUiController {
676
676
  finish(undefined);
677
677
  }
678
678
  : undefined,
679
+ onExternalEditor: dialogOptions?.onExternalEditor,
679
680
  helpText: dialogOptions?.helpText,
680
681
  initialIndex: dialogOptions?.initialIndex,
681
682
  timeout: dialogOptions?.timeout,
@@ -1,6 +1,6 @@
1
1
  import * as fs from "node:fs/promises";
2
2
  import { type AgentMessage, ThinkingLevel } from "@oh-my-pi/pi-agent-core";
3
- import { copyToClipboard, readImageFromClipboard, sanitizeText } from "@oh-my-pi/pi-natives";
3
+ import { sanitizeText } from "@oh-my-pi/pi-natives";
4
4
  import type { AutocompleteProvider, SlashCommand } from "@oh-my-pi/pi-tui";
5
5
  import { $env } from "@oh-my-pi/pi-utils";
6
6
  import { settings } from "../../config/settings";
@@ -10,8 +10,9 @@ import type { InteractiveModeContext } from "../../modes/types";
10
10
  import type { AgentSessionEvent } from "../../session/agent-session";
11
11
  import { SKILL_PROMPT_MESSAGE_TYPE, type SkillPromptDetails } from "../../session/messages";
12
12
  import { executeBuiltinSlashCommand } from "../../slash-commands/builtin-registry";
13
+ import { copyToClipboard, readImageFromClipboard } from "../../utils/clipboard";
13
14
  import { getEditorCommand, openInEditor } from "../../utils/external-editor";
14
- import { ensureSupportedImageInput } from "../../utils/image-input";
15
+ import { ensureSupportedImageInput } from "../../utils/image-loading";
15
16
  import { resizeImage } from "../../utils/image-resize";
16
17
  import { generateSessionTitle, setSessionTerminalTitle } from "../../utils/title-generator";
17
18
 
@@ -158,6 +159,9 @@ export class InputController {
158
159
  for (const key of this.ctx.keybindings.getKeys("app.clipboard.copyLine")) {
159
160
  this.ctx.editor.setCustomKeyHandler(key, () => this.handleCopyCurrentLine());
160
161
  }
162
+ for (const key of this.ctx.keybindings.getKeys("app.session.observe")) {
163
+ this.ctx.editor.setCustomKeyHandler(key, () => this.ctx.showSessionObserver());
164
+ }
161
165
 
162
166
  this.ctx.editor.onChange = (text: string) => {
163
167
  const wasBashMode = this.ctx.isBashMode;
@@ -215,14 +219,17 @@ export class InputController {
215
219
  if (!text) return;
216
220
 
217
221
  // Handle built-in slash commands
218
- if (
219
- await executeBuiltinSlashCommand(text, {
220
- ctx: this.ctx,
221
- handleBackgroundCommand: () => this.handleBackgroundCommand(),
222
- })
223
- ) {
222
+ const slashResult = await executeBuiltinSlashCommand(text, {
223
+ ctx: this.ctx,
224
+ handleBackgroundCommand: () => this.handleBackgroundCommand(),
225
+ });
226
+ if (slashResult === true) {
224
227
  return;
225
228
  }
229
+ if (typeof slashResult === "string") {
230
+ // Command handled but returned remaining text to use as prompt
231
+ text = slashResult;
232
+ }
226
233
 
227
234
  // Handle skill commands (/skill:name [args])
228
235
  if (text.startsWith("/skill:")) {
@@ -39,11 +39,13 @@ import { HistorySearchComponent } from "../components/history-search";
39
39
  import { ModelSelectorComponent } from "../components/model-selector";
40
40
  import { OAuthSelectorComponent } from "../components/oauth-selector";
41
41
  import { PluginSelectorComponent } from "../components/plugin-selector";
42
+ import { SessionObserverOverlayComponent } from "../components/session-observer-overlay";
42
43
  import { SessionSelectorComponent } from "../components/session-selector";
43
44
  import { SettingsSelectorComponent } from "../components/settings-selector";
44
45
  import { ToolExecutionComponent } from "../components/tool-execution";
45
46
  import { TreeSelectorComponent } from "../components/tree-selector";
46
47
  import { UserMessageSelectorComponent } from "../components/user-message-selector";
48
+ import type { SessionObserverRegistry } from "../session-observer-registry";
47
49
 
48
50
  const CALLBACK_SERVER_PROVIDERS = new Set<OAuthProvider>([
49
51
  "anthropic",
@@ -962,4 +964,28 @@ export class SelectorController {
962
964
  return { component: selector, focus: selector };
963
965
  });
964
966
  }
967
+
968
+ showSessionObserver(registry: SessionObserverRegistry): void {
969
+ const observeKeys = this.ctx.keybindings.getKeys("app.session.observe");
970
+
971
+ this.showSelector(done => {
972
+ let cleanup: (() => void) | undefined;
973
+
974
+ const selector = new SessionObserverOverlayComponent(
975
+ registry,
976
+ () => {
977
+ cleanup?.();
978
+ done();
979
+ },
980
+ observeKeys,
981
+ );
982
+
983
+ cleanup = registry.onChange(() => {
984
+ selector.refreshFromRegistry();
985
+ this.ctx.ui.requestRender();
986
+ });
987
+
988
+ return { component: selector, focus: selector };
989
+ });
990
+ }
965
991
  }
@@ -7,9 +7,27 @@ import { postmortem } from "@oh-my-pi/pi-utils";
7
7
  export { runAcpMode } from "./acp";
8
8
  export { InteractiveMode, type InteractiveModeOptions } from "./interactive-mode";
9
9
  export { type PrintModeOptions, runPrintMode } from "./print-mode";
10
- export { type ModelInfo, RpcClient, type RpcClientOptions, type RpcEventListener } from "./rpc/rpc-client";
10
+ export {
11
+ defineRpcClientTool,
12
+ type ModelInfo,
13
+ RpcClient,
14
+ type RpcClientCustomTool,
15
+ type RpcClientOptions,
16
+ type RpcClientToolContext,
17
+ type RpcClientToolResult,
18
+ type RpcEventListener,
19
+ } from "./rpc/rpc-client";
11
20
  export { runRpcMode } from "./rpc/rpc-mode";
12
- export type { RpcCommand, RpcResponse, RpcSessionState } from "./rpc/rpc-types";
21
+ export type {
22
+ RpcCommand,
23
+ RpcHostToolCallRequest,
24
+ RpcHostToolCancelRequest,
25
+ RpcHostToolDefinition,
26
+ RpcHostToolResult,
27
+ RpcHostToolUpdate,
28
+ RpcResponse,
29
+ RpcSessionState,
30
+ } from "./rpc/rpc-types";
13
31
 
14
32
  postmortem.register("terminal-restore", () => {
15
33
  emergencyTerminalRestore();