@oh-my-pi/pi-coding-agent 15.9.5 → 15.10.0

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 (192) hide show
  1. package/CHANGELOG.md +98 -1
  2. package/dist/types/cli/args.d.ts +1 -1
  3. package/dist/types/cli/gallery-cli.d.ts +43 -0
  4. package/dist/types/cli/gallery-fixtures/agentic.d.ts +2 -0
  5. package/dist/types/cli/gallery-fixtures/codeintel.d.ts +3 -0
  6. package/dist/types/cli/gallery-fixtures/edit.d.ts +3 -0
  7. package/dist/types/cli/gallery-fixtures/fs.d.ts +2 -0
  8. package/dist/types/cli/gallery-fixtures/index.d.ts +4 -0
  9. package/dist/types/cli/gallery-fixtures/interaction.d.ts +3 -0
  10. package/dist/types/cli/gallery-fixtures/memory.d.ts +2 -0
  11. package/dist/types/cli/gallery-fixtures/misc.d.ts +3 -0
  12. package/dist/types/cli/gallery-fixtures/search.d.ts +3 -0
  13. package/dist/types/cli/gallery-fixtures/shell.d.ts +3 -0
  14. package/dist/types/cli/gallery-fixtures/types.d.ts +44 -0
  15. package/dist/types/cli/gallery-fixtures/web.d.ts +2 -0
  16. package/dist/types/cli/gallery-screenshot.d.ts +35 -0
  17. package/dist/types/commands/gallery.d.ts +47 -0
  18. package/dist/types/config/keybindings.d.ts +10 -2
  19. package/dist/types/config/model-id-affixes.d.ts +2 -0
  20. package/dist/types/config/model-registry.d.ts +8 -1
  21. package/dist/types/config/settings-schema.d.ts +43 -7
  22. package/dist/types/edit/file-snapshot-store.d.ts +1 -1
  23. package/dist/types/eval/backend.d.ts +6 -6
  24. package/dist/types/eval/bridge-timeout.d.ts +27 -0
  25. package/dist/types/eval/idle-timeout.d.ts +16 -14
  26. package/dist/types/eval/js/executor.d.ts +3 -3
  27. package/dist/types/eval/py/executor.d.ts +2 -2
  28. package/dist/types/eval/py/spawn-options.d.ts +58 -0
  29. package/dist/types/extensibility/plugins/marketplace-auto-update.d.ts +8 -0
  30. package/dist/types/lsp/types.d.ts +10 -0
  31. package/dist/types/main.d.ts +3 -2
  32. package/dist/types/memory-backend/index.d.ts +2 -1
  33. package/dist/types/memory-backend/resolve.d.ts +1 -1
  34. package/dist/types/memory-backend/types.d.ts +1 -1
  35. package/dist/types/modes/components/assistant-message.d.ts +5 -0
  36. package/dist/types/modes/components/copy-selector.d.ts +22 -0
  37. package/dist/types/modes/components/custom-editor.d.ts +2 -1
  38. package/dist/types/modes/components/model-selector.d.ts +1 -0
  39. package/dist/types/modes/components/tool-execution.d.ts +18 -0
  40. package/dist/types/modes/controllers/command-controller.d.ts +0 -1
  41. package/dist/types/modes/controllers/selector-controller.d.ts +2 -1
  42. package/dist/types/modes/index.d.ts +5 -4
  43. package/dist/types/modes/interactive-mode.d.ts +2 -2
  44. package/dist/types/modes/setup-version.d.ts +11 -0
  45. package/dist/types/modes/setup-wizard/index.d.ts +2 -1
  46. package/dist/types/modes/setup-wizard/scenes/web-search.d.ts +2 -1
  47. package/dist/types/modes/types.d.ts +2 -2
  48. package/dist/types/modes/utils/copy-targets.d.ts +53 -0
  49. package/dist/types/sdk.d.ts +1 -1
  50. package/dist/types/task/executor.d.ts +7 -0
  51. package/dist/types/telemetry-export.d.ts +1 -1
  52. package/dist/types/tools/eval-render.d.ts +1 -0
  53. package/dist/types/tools/fetch.d.ts +15 -7
  54. package/dist/types/tools/render-utils.d.ts +33 -0
  55. package/dist/types/tools/renderers.d.ts +16 -2
  56. package/dist/types/tools/search.d.ts +1 -1
  57. package/dist/types/tools/write.d.ts +2 -0
  58. package/dist/types/tui/code-cell.d.ts +6 -0
  59. package/dist/types/tui/output-block.d.ts +11 -0
  60. package/dist/types/web/scrapers/github.d.ts +22 -0
  61. package/dist/types/web/search/providers/perplexity.d.ts +8 -1
  62. package/dist/types/web/search/types.d.ts +1 -1
  63. package/package.json +9 -9
  64. package/scripts/dev-launch +42 -0
  65. package/scripts/dev-launch-preload.ts +19 -0
  66. package/src/autoresearch/dashboard.ts +11 -21
  67. package/src/cli/args.ts +2 -2
  68. package/src/cli/claude-trace-cli.ts +13 -1
  69. package/src/cli/gallery-cli.ts +223 -0
  70. package/src/cli/gallery-fixtures/agentic.ts +292 -0
  71. package/src/cli/gallery-fixtures/codeintel.ts +188 -0
  72. package/src/cli/gallery-fixtures/edit.ts +194 -0
  73. package/src/cli/gallery-fixtures/fs.ts +153 -0
  74. package/src/cli/gallery-fixtures/index.ts +40 -0
  75. package/src/cli/gallery-fixtures/interaction.ts +49 -0
  76. package/src/cli/gallery-fixtures/memory.ts +81 -0
  77. package/src/cli/gallery-fixtures/misc.ts +221 -0
  78. package/src/cli/gallery-fixtures/search.ts +213 -0
  79. package/src/cli/gallery-fixtures/shell.ts +167 -0
  80. package/src/cli/gallery-fixtures/types.ts +41 -0
  81. package/src/cli/gallery-fixtures/web.ts +158 -0
  82. package/src/cli/gallery-screenshot.ts +279 -0
  83. package/src/cli-commands.ts +1 -0
  84. package/src/commands/gallery.ts +52 -0
  85. package/src/commands/launch.ts +1 -1
  86. package/src/config/keybindings.ts +68 -2
  87. package/src/config/model-equivalence.ts +35 -12
  88. package/src/config/model-id-affixes.ts +39 -22
  89. package/src/config/model-registry.ts +16 -16
  90. package/src/config/settings-schema.ts +29 -6
  91. package/src/config/settings.ts +11 -0
  92. package/src/dap/client.ts +14 -16
  93. package/src/debug/raw-sse.ts +18 -4
  94. package/src/edit/file-snapshot-store.ts +1 -1
  95. package/src/edit/index.ts +1 -1
  96. package/src/edit/renderer.ts +43 -55
  97. package/src/edit/streaming.ts +1 -1
  98. package/src/eval/__tests__/agent-bridge.test.ts +102 -58
  99. package/src/eval/__tests__/bridge-timeout.test.ts +64 -0
  100. package/src/eval/__tests__/idle-timeout.test.ts +26 -12
  101. package/src/eval/__tests__/kernel-spawn.test.ts +103 -0
  102. package/src/eval/__tests__/llm-bridge.test.ts +10 -10
  103. package/src/eval/agent-bridge.ts +38 -12
  104. package/src/eval/backend.ts +6 -6
  105. package/src/eval/bridge-timeout.ts +44 -0
  106. package/src/eval/idle-timeout.ts +33 -15
  107. package/src/eval/js/executor.ts +10 -10
  108. package/src/eval/llm-bridge.ts +4 -5
  109. package/src/eval/py/executor.ts +6 -6
  110. package/src/eval/py/kernel.ts +11 -1
  111. package/src/eval/py/spawn-options.ts +126 -0
  112. package/src/export/ttsr.ts +9 -0
  113. package/src/extensibility/extensions/runner.ts +3 -0
  114. package/src/extensibility/plugins/doctor.ts +0 -1
  115. package/src/extensibility/plugins/marketplace-auto-update.ts +49 -0
  116. package/src/goals/tools/goal-tool.ts +2 -2
  117. package/src/internal-urls/docs-index.generated.ts +7 -6
  118. package/src/lsp/client.ts +179 -52
  119. package/src/lsp/index.ts +38 -4
  120. package/src/lsp/render.ts +3 -3
  121. package/src/lsp/types.ts +10 -0
  122. package/src/main.ts +47 -52
  123. package/src/memory-backend/index.ts +13 -1
  124. package/src/memory-backend/resolve.ts +3 -5
  125. package/src/memory-backend/types.ts +1 -1
  126. package/src/modes/components/agent-dashboard.ts +13 -4
  127. package/src/modes/components/assistant-message.ts +22 -1
  128. package/src/modes/components/copy-selector.ts +249 -0
  129. package/src/modes/components/custom-editor.ts +10 -1
  130. package/src/modes/components/extensions/extension-list.ts +17 -8
  131. package/src/modes/components/history-search.ts +19 -11
  132. package/src/modes/components/model-selector.ts +125 -29
  133. package/src/modes/components/oauth-selector.ts +28 -12
  134. package/src/modes/components/session-observer-overlay.ts +13 -15
  135. package/src/modes/components/session-selector.ts +24 -13
  136. package/src/modes/components/status-line.ts +3 -5
  137. package/src/modes/components/tool-execution.ts +83 -24
  138. package/src/modes/components/tree-selector.ts +19 -7
  139. package/src/modes/components/user-message-selector.ts +25 -14
  140. package/src/modes/controllers/command-controller.ts +13 -118
  141. package/src/modes/controllers/event-controller.ts +26 -10
  142. package/src/modes/controllers/input-controller.ts +11 -3
  143. package/src/modes/controllers/selector-controller.ts +40 -3
  144. package/src/modes/index.ts +5 -4
  145. package/src/modes/interactive-mode.ts +21 -7
  146. package/src/modes/setup-version.ts +11 -0
  147. package/src/modes/setup-wizard/index.ts +3 -2
  148. package/src/modes/setup-wizard/scenes/web-search.ts +3 -2
  149. package/src/modes/theme/theme.ts +46 -10
  150. package/src/modes/types.ts +2 -2
  151. package/src/modes/utils/context-usage.ts +10 -6
  152. package/src/modes/utils/copy-targets.ts +254 -0
  153. package/src/modes/utils/hotkeys-markdown.ts +1 -0
  154. package/src/prompts/tools/ast-edit.md +1 -1
  155. package/src/prompts/tools/ast-grep.md +1 -1
  156. package/src/prompts/tools/read.md +1 -1
  157. package/src/prompts/tools/search.md +1 -1
  158. package/src/sdk.ts +21 -23
  159. package/src/session/agent-session.ts +13 -9
  160. package/src/slash-commands/builtin-registry.ts +4 -12
  161. package/src/slash-commands/helpers/usage-report.ts +2 -0
  162. package/src/task/executor.ts +20 -2
  163. package/src/task/render.ts +37 -11
  164. package/src/telemetry-export.ts +25 -7
  165. package/src/tools/bash.ts +18 -8
  166. package/src/tools/browser/render.ts +5 -4
  167. package/src/tools/debug.ts +3 -3
  168. package/src/tools/eval-backends.ts +6 -17
  169. package/src/tools/eval-render.ts +28 -10
  170. package/src/tools/eval.ts +19 -23
  171. package/src/tools/fetch.ts +99 -89
  172. package/src/tools/read.ts +7 -7
  173. package/src/tools/render-utils.ts +63 -3
  174. package/src/tools/renderers.ts +16 -1
  175. package/src/tools/report-tool-issue.ts +1 -1
  176. package/src/tools/search.ts +173 -81
  177. package/src/tools/ssh.ts +21 -8
  178. package/src/tools/todo.ts +20 -7
  179. package/src/tools/write.ts +39 -9
  180. package/src/tui/code-cell.ts +19 -4
  181. package/src/tui/output-block.ts +14 -0
  182. package/src/web/scrapers/github.ts +255 -3
  183. package/src/web/scrapers/youtube.ts +3 -2
  184. package/src/web/search/providers/perplexity.ts +199 -51
  185. package/src/web/search/render.ts +42 -57
  186. package/src/web/search/types.ts +5 -1
  187. package/dist/types/eval/heartbeat.d.ts +0 -45
  188. package/src/eval/__tests__/heartbeat.test.ts +0 -84
  189. package/src/eval/__tests__/shared-executors.test.ts +0 -609
  190. package/src/eval/heartbeat.ts +0 -74
  191. /package/dist/types/eval/__tests__/{heartbeat.test.d.ts → bridge-timeout.test.d.ts} +0 -0
  192. /package/dist/types/eval/__tests__/{shared-executors.test.d.ts → kernel-spawn.test.d.ts} +0 -0
@@ -1,27 +1,29 @@
1
1
  /**
2
- * Inactivity watchdog for eval cells.
2
+ * Watchdog for eval cell work.
3
3
  *
4
- * A cell's `timeout` is treated as an *idle* budget rather than a hard
5
- * wall-clock deadline: the watchdog aborts {@link signal} (with a
6
- * `TimeoutError` reason, matching `AbortSignal.timeout`) only once `idleMs`
7
- * elapses with no {@link bump}. Every progress signal re-arms it, so a
8
- * long-running fanout that keeps reporting progress (e.g. `agent()` status
9
- * updates, `log()`/`phase()`) never trips the timeout, while a genuinely
10
- * stalled cell still gets interrupted.
4
+ * A cell's `timeout` bounds time while the Python kernel or JS VM is in control.
5
+ * Host-side bridge calls can {@link pause} the watchdog so delegated
6
+ * `agent()`/`parallel()`/`llm()` work is ignored completely, then {@link resume}
7
+ * starts a fresh timeout window once the runtime gets control back.
11
8
  *
12
- * The timer self-reschedules instead of being torn down and recreated on every
13
- * bump, so a high-frequency stream of bumps (sub-second agent progress) costs
14
- * one timestamp write per event rather than churning a timer each time.
9
+ * The active timer self-reschedules instead of being torn down on every
10
+ * activity event, so frequent activity costs one timestamp write per event.
11
+ * Pause is reference-counted because `parallel()` can have multiple bridge calls
12
+ * in flight at once.
15
13
  */
16
14
  export declare class IdleTimeout {
17
15
  #private;
18
16
  constructor(idleMs: number);
19
- /** Aborts with a `TimeoutError` reason once the inactivity budget is exhausted. */
17
+ /** Aborts with a `TimeoutError` reason once the active timeout window is exhausted. */
20
18
  get signal(): AbortSignal;
21
- /** Configured inactivity budget in milliseconds. */
19
+ /** Configured active timeout window in milliseconds. */
22
20
  get idleMs(): number;
23
- /** Record activity, pushing the inactivity deadline forward by `idleMs`. */
21
+ /** Record runtime activity, pushing the active deadline forward by `idleMs`. */
24
22
  bump(): void;
23
+ /** Suspend timeout accounting while control is delegated to host-side work. */
24
+ pause(): void;
25
+ /** Resume timeout accounting with a fresh timeout window. */
26
+ resume(): void;
25
27
  /** Stop the watchdog. Safe to call multiple times. */
26
28
  dispose(): void;
27
29
  [Symbol.dispose](): void;
@@ -6,9 +6,9 @@ export interface JsExecutorOptions {
6
6
  timeoutMs?: number;
7
7
  deadlineMs?: number;
8
8
  /**
9
- * Inactivity budget (ms). Used for worker cold-start headroom and
10
- * timeout-annotation text when the caller drives cancellation via an
11
- * idle-aware `signal` instead of `deadlineMs`/`timeoutMs`. Never arms a timer.
9
+ * Runtime-work budget (ms). Used for worker cold-start headroom and
10
+ * timeout-annotation text when the caller drives cancellation via the eval
11
+ * watchdog `signal` instead of `deadlineMs`/`timeoutMs`. Never arms a timer.
12
12
  */
13
13
  idleTimeoutMs?: number;
14
14
  onChunk?: (chunk: string) => Promise<void> | void;
@@ -10,8 +10,8 @@ export interface PythonExecutorOptions {
10
10
  /** Absolute wall-clock deadline in milliseconds since epoch */
11
11
  deadlineMs?: number;
12
12
  /**
13
- * Inactivity budget (ms). Used only for timeout-annotation text when the
14
- * caller drives cancellation via an idle-aware `signal` instead of a
13
+ * Runtime-work budget (ms). Used only for timeout-annotation text when the
14
+ * caller drives cancellation via the eval watchdog `signal` instead of a
15
15
  * wall-clock `deadlineMs`/`timeoutMs`. Does not arm a timer.
16
16
  */
17
17
  idleTimeoutMs?: number;
@@ -0,0 +1,58 @@
1
+ /**
2
+ * Decide whether the long-lived Python kernel subprocess should be spawned
3
+ * with `windowsHide: true`.
4
+ *
5
+ * On Windows, Bun maps `windowsHide: true` to the `CREATE_NO_WINDOW` flag,
6
+ * which detaches the child from any inherited console. The Python kernel
7
+ * runs user code that imports NumPy/pandas; those native extensions
8
+ * (`numpy/_core/_multiarray_umath.pyd` + bundled OpenBLAS/SLEEF thread-pool
9
+ * init) can deadlock inside `LoadLibraryExW` when no console is attached,
10
+ * and a console-less child cannot receive SIGINT via
11
+ * `GenerateConsoleCtrlEvent` (the recovery path the host relies on). See
12
+ * issue #1960.
13
+ *
14
+ * So on Windows we hide only when the host itself has no console to share.
15
+ * In any launch where a console is attached — even one with every stdio
16
+ * stream redirected — the kernel inherits the parent's console, matching
17
+ * `python.exe` invoked from `cmd.exe`, which keeps native imports and
18
+ * SIGINT recovery working.
19
+ *
20
+ * Short-lived helper subprocesses elsewhere in the codebase (LSP probes,
21
+ * git, plugin installs) keep `windowsHide: true` because they don't load
22
+ * complex native modules and the brief console flash would be user-visible
23
+ * noise.
24
+ */
25
+ export declare function shouldHideKernelWindow(opts: {
26
+ platform: NodeJS.Platform;
27
+ hostHasInheritableConsole: boolean;
28
+ }): boolean;
29
+ /**
30
+ * TTY-based fallback used when the Win32 console probe is unavailable.
31
+ *
32
+ * Returns `true` if any of stdin/stdout/stderr is currently a TTY. This
33
+ * correctly detects the common interactive launches and the partial-
34
+ * redirection cases (`omp -p > out.txt`, `< in.txt`, `2> err.log`) where at
35
+ * least one stream stays bound to the terminal. The all-stdio-redirected
36
+ * case (`< in > out 2> err` from a console) is the reason we prefer the
37
+ * Win32 probe over this fallback whenever possible.
38
+ */
39
+ export declare function consoleAttachedViaTTY(opts: {
40
+ stdinIsTTY: boolean;
41
+ stdoutIsTTY: boolean;
42
+ stderrIsTTY: boolean;
43
+ }): boolean;
44
+ /** Reset the cached Win32 probe result. Test-only; not part of the public surface. */
45
+ export declare function __resetWindowsConsoleProbeCache(): void;
46
+ /**
47
+ * Whether the host process owns a console its children can inherit.
48
+ *
49
+ * - On Windows, the authoritative signal is `GetConsoleWindow()`. It returns
50
+ * a non-NULL HWND whenever the process has a console attached, regardless
51
+ * of how the standard streams are redirected — so an `omp -p ... < in.txt
52
+ * > out.txt 2> err.log` launched from a real Windows Terminal session is
53
+ * correctly classified as console-attached and the kernel keeps its
54
+ * inheritable console.
55
+ * - On any other platform, or if the FFI probe fails, fall back to the
56
+ * TTY-OR heuristic. That still catches the common interactive cases.
57
+ */
58
+ export declare function hostHasInheritableConsole(): boolean;
@@ -0,0 +1,8 @@
1
+ type MarketplaceAutoUpdateMode = "off" | "notify" | "auto";
2
+ interface MarketplaceAutoUpdateOptions {
3
+ autoUpdate: MarketplaceAutoUpdateMode;
4
+ resolveActiveProjectRegistryPath: (cwd: string) => Promise<string | null>;
5
+ clearPluginRootsCache: () => void;
6
+ }
7
+ export declare function scheduleMarketplaceAutoUpdate(options: MarketplaceAutoUpdateOptions): void;
8
+ export {};
@@ -222,6 +222,16 @@ export interface ServerConfig {
222
222
  disabled?: boolean;
223
223
  /** Per-server warmup timeout in milliseconds. Overrides the global WARMUP_TIMEOUT_MS for this server during startup. */
224
224
  warmupTimeoutMs?: number;
225
+ /**
226
+ * Per-server overrides for rust-analyzer workspace-ready polling. When omitted, the module
227
+ * defaults are used. Primarily a tuning/test seam to bound the multi-second settle window.
228
+ */
229
+ workspaceReadyTimings?: {
230
+ timeoutMs?: number;
231
+ pollMs?: number;
232
+ settleMs?: number;
233
+ statusRequestTimeoutMs?: number;
234
+ };
225
235
  capabilities?: ServerCapabilities;
226
236
  /** If true, this is a linter/formatter server (e.g., Biome) - used only for diagnostics/actions, not type intelligence */
227
237
  isLinter?: boolean;
@@ -7,12 +7,13 @@
7
7
  import type { Args } from "./cli/args";
8
8
  import { ModelRegistry } from "./config/model-registry";
9
9
  import { Settings } from "./config/settings";
10
- import { InteractiveMode, runAcpMode } from "./modes";
10
+ import { InteractiveMode } from "./modes/interactive-mode";
11
11
  import type { SubmittedUserInput } from "./modes/types";
12
12
  import { type CreateAgentSessionOptions, type CreateAgentSessionResult, createAgentSession, discoverAuthStorage } from "./sdk";
13
13
  import type { AgentSession } from "./session/agent-session";
14
14
  import type { AuthStorage } from "./session/auth-storage";
15
15
  import { type SessionInfo, SessionManager } from "./session/session-manager";
16
+ type RunAcpMode = (createSession: AcpSessionFactory) => Promise<never>;
16
17
  export interface InteractiveModeNotify {
17
18
  kind: "warn" | "error" | "info";
18
19
  message: string;
@@ -47,7 +48,7 @@ export declare function createSessionManager(parsed: Args, cwd: string, activeSe
47
48
  interface RunRootCommandDependencies {
48
49
  createAgentSession?: typeof createAgentSession;
49
50
  discoverAuthStorage?: typeof discoverAuthStorage;
50
- runAcpMode?: typeof runAcpMode;
51
+ runAcpMode?: RunAcpMode;
51
52
  settings?: Settings;
52
53
  forceSetupWizard?: boolean;
53
54
  }
@@ -1,4 +1,5 @@
1
- export * from "../mnemopi";
1
+ export type { MnemopiBackendConfig, MnemopiLlmMode, MnemopiProviderOptions, MnemopiScoping, } from "../mnemopi/config";
2
+ export type { MnemopiMemoryEditOperation, MnemopiMemoryEditOptions, MnemopiMemoryEditResult, MnemopiSessionState, MnemopiSessionStateOptions, } from "../mnemopi/state";
2
3
  export * from "./local-backend";
3
4
  export * from "./off-backend";
4
5
  export * from "./resolve";
@@ -13,4 +13,4 @@ import type { MemoryBackend } from "./types";
13
13
  * `memories.enabled` remains accepted only as a legacy migration input. Once
14
14
  * a config is loaded, `memory.backend` is the sole runtime selector.
15
15
  */
16
- export declare function resolveMemoryBackend(settings: Settings): MemoryBackend;
16
+ export declare function resolveMemoryBackend(settings: Settings): Promise<MemoryBackend>;
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Memory backend abstraction.
3
3
  *
4
- * Backends are mutually exclusive — `resolveMemoryBackend(settings)` returns
4
+ * Backends are mutually exclusive — `await resolveMemoryBackend(settings)` resolves
5
5
  * exactly one. Implementations MUST be self-contained: they own the per-session
6
6
  * state they create in `start()` and tear it down on `clear()`.
7
7
  */
@@ -13,6 +13,11 @@ export declare class AssistantMessageComponent extends Container {
13
13
  constructor(message?: AssistantMessage, hideThinkingBlock?: boolean, onImageUpdate?: (() => void) | undefined, thinkingRenderers?: readonly AssistantThinkingRenderer[], imageBudget?: ImageBudget | undefined);
14
14
  invalidate(): void;
15
15
  setHideThinkingBlock(hide: boolean): void;
16
+ /**
17
+ * Toggle suppression of the inline `Error: …` line while the same error is
18
+ * pinned in the banner above the editor. Re-renders so the change is visible.
19
+ */
20
+ setErrorPinned(pinned: boolean): void;
16
21
  isTranscriptBlockFinalized(): boolean;
17
22
  /**
18
23
  * Assistant text/thinking streams in append-only: earlier rendered rows never
@@ -0,0 +1,22 @@
1
+ import { type Component } from "@oh-my-pi/pi-tui";
2
+ import type { CopyTarget } from "../utils/copy-targets";
3
+ export interface CopySelectorCallbacks {
4
+ /** A copy target was chosen — copy its `content`. */
5
+ onPick: (target: CopyTarget) => void;
6
+ /** The picker was dismissed. */
7
+ onCancel: () => void;
8
+ }
9
+ /**
10
+ * Fullscreen `/copy` picker rendered as a `/tree`-style tree inside one
11
+ * outlined box: a title, the tree of copy targets (recent assistant messages
12
+ * with their code blocks nested beneath), a live preview of the highlighted
13
+ * node, and a keybinding footer. Every node copies its `content` on Enter.
14
+ */
15
+ export declare class CopySelectorComponent implements Component {
16
+ #private;
17
+ private readonly callbacks;
18
+ constructor(roots: CopyTarget[], callbacks: CopySelectorCallbacks);
19
+ invalidate(): void;
20
+ handleInput(keyData: string): void;
21
+ render(width: number): string[];
22
+ }
@@ -1,6 +1,6 @@
1
1
  import { Editor, type KeyId } from "@oh-my-pi/pi-tui";
2
2
  import type { AppKeybinding } from "../../config/keybindings";
3
- type ConfigurableEditorAction = Extract<AppKeybinding, "app.interrupt" | "app.clear" | "app.exit" | "app.suspend" | "app.thinking.cycle" | "app.model.cycleForward" | "app.model.cycleBackward" | "app.model.select" | "app.model.selectTemporary" | "app.tools.expand" | "app.thinking.toggle" | "app.editor.external" | "app.history.search" | "app.message.dequeue" | "app.clipboard.pasteImage" | "app.clipboard.pasteTextRaw" | "app.clipboard.copyPrompt">;
3
+ type ConfigurableEditorAction = Extract<AppKeybinding, "app.interrupt" | "app.clear" | "app.exit" | "app.suspend" | "app.display.reset" | "app.thinking.cycle" | "app.model.cycleForward" | "app.model.cycleBackward" | "app.model.select" | "app.model.selectTemporary" | "app.tools.expand" | "app.thinking.toggle" | "app.editor.external" | "app.history.search" | "app.message.dequeue" | "app.clipboard.pasteImage" | "app.clipboard.pasteTextRaw" | "app.clipboard.copyPrompt">;
4
4
  /**
5
5
  * Custom editor that handles configurable app-level shortcuts for coding-agent.
6
6
  */
@@ -14,6 +14,7 @@ export declare class CustomEditor extends Editor {
14
14
  onEscape?: () => void;
15
15
  onClear?: () => void;
16
16
  onExit?: () => void;
17
+ onDisplayReset?: () => void;
17
18
  onCycleThinkingLevel?: () => void;
18
19
  onCycleModelForward?: () => void;
19
20
  onCycleModelBackward?: () => void;
@@ -20,6 +20,7 @@ export declare class ModelSelectorComponent extends Container {
20
20
  constructor(tui: TUI, _currentModel: Model | undefined, settings: Settings, modelRegistry: ModelRegistry, scopedModels: ReadonlyArray<ScopedModelItem>, onSelect: RoleSelectCallback, onCancel: () => void, options?: {
21
21
  temporaryOnly?: boolean;
22
22
  initialSearchInput?: string;
23
+ currentContextTokens?: number;
23
24
  });
24
25
  handleInput(keyData: string): void;
25
26
  getSearchInput(): Input;
@@ -61,6 +61,24 @@ export declare class ToolExecutionComponent extends Container {
61
61
  * past, or an explicit {@link seal} flips it to `true`.
62
62
  */
63
63
  isTranscriptBlockFinalized(): boolean;
64
+ /**
65
+ * While a tool's preview is still streaming, a block whose preview is
66
+ * append-only (rows only grow at the bottom, never re-layout) lets the
67
+ * renderer commit the scrolled-off head of an over-tall preview to native
68
+ * scrollback instead of dropping it — the same anti-yank path a streaming
69
+ * assistant reply uses (see {@link TranscriptContainer} +
70
+ * `NativeScrollbackLiveRegion`). Covers both phases: a pre-result call preview
71
+ * (a `write` whose content streams in) and a partial-result preview that
72
+ * streams output below fixed input (an `eval`/`bash` whose stdout grows under
73
+ * its code cell). Gated on {@link isTranscriptBlockFinalized} so the boundary
74
+ * closes the instant the block reaches a terminal state — a final result that
75
+ * may collapse to a compact view, a backgrounded async tool, or a seal — and
76
+ * the renderer decides whether its current preview shape qualifies via
77
+ * `isStreamingPreviewAppendOnly` (typically: only the expanded full view,
78
+ * which is top-anchored; the collapsed tail window re-layouts but is bounded
79
+ * so it never overflows anyway).
80
+ */
81
+ isTranscriptBlockAppendOnly(): boolean;
64
82
  /**
65
83
  * Mark the tool terminal even though no result arrived (the turn aborted or
66
84
  * abandoned it) and stop animating, so it can freeze and stops pinning the
@@ -13,7 +13,6 @@ export declare class CommandController {
13
13
  handleDumpCommand(): void;
14
14
  handleDebugTranscriptCommand(): Promise<void>;
15
15
  handleShareCommand(): Promise<void>;
16
- handleCopyCommand(sub?: string): void;
17
16
  handleSessionCommand(): Promise<void>;
18
17
  handleJobsCommand(): Promise<void>;
19
18
  handleUsageCommand(reports?: UsageReport[] | null): Promise<void>;
@@ -35,11 +35,12 @@ export declare class SelectorController {
35
35
  }): void;
36
36
  showPluginSelector(mode?: "install" | "uninstall"): Promise<void>;
37
37
  showUserMessageSelector(): void;
38
+ showCopySelector(): void;
38
39
  showTreeSelector(): void;
39
40
  showSessionSelector(): Promise<void>;
40
41
  handleResumeSession(sessionPath: string): Promise<void>;
41
42
  handleSessionDeleteCommand(): Promise<void>;
42
43
  showOAuthSelector(mode: "login" | "logout", providerId?: string): Promise<void>;
43
- showDebugSelector(): void;
44
+ showDebugSelector(): Promise<void>;
44
45
  showSessionObserver(registry: SessionObserverRegistry): void;
45
46
  }
@@ -1,9 +1,10 @@
1
1
  /**
2
- * Run modes for the coding agent.
2
+ * Interactive mode and embeddable RPC client exports for the coding agent.
3
+ *
4
+ * Branch-specific runners live in their concrete modules so importing this
5
+ * barrel does not pull print, RPC server, or ACP server mode into the normal
6
+ * TUI graph.
3
7
  */
4
- export { runAcpMode } from "./acp";
5
8
  export { InteractiveMode, type InteractiveModeOptions } from "./interactive-mode";
6
- export { type PrintModeOptions, runPrintMode } from "./print-mode";
7
9
  export { defineRpcClientTool, type ModelInfo, RpcClient, type RpcClientCustomTool, type RpcClientOptions, type RpcClientToolContext, type RpcClientToolResult, type RpcEventListener, } from "./rpc/rpc-client";
8
- export { runRpcMode } from "./rpc/rpc-mode";
9
10
  export type { RpcCommand, RpcHostToolCallRequest, RpcHostToolCancelRequest, RpcHostToolDefinition, RpcHostToolResult, RpcHostToolUpdate, RpcResponse, RpcSessionState, } from "./rpc/rpc-types";
@@ -199,7 +199,6 @@ export declare class InteractiveMode implements InteractiveModeContext {
199
199
  handleDumpCommand(): void;
200
200
  handleDebugTranscriptCommand(): Promise<void>;
201
201
  handleShareCommand(): Promise<void>;
202
- handleCopyCommand(sub?: string): void;
203
202
  handleTodoCommand(args: string): Promise<void>;
204
203
  handleSessionCommand(): Promise<void>;
205
204
  handleJobsCommand(): Promise<void>;
@@ -215,7 +214,7 @@ export declare class InteractiveMode implements InteractiveModeContext {
215
214
  handleRenameCommand(title: string): Promise<void>;
216
215
  handleMemoryCommand(text: string): Promise<void>;
217
216
  handleSTTToggle(): Promise<void>;
218
- showDebugSelector(): void;
217
+ showDebugSelector(): Promise<void>;
219
218
  showSessionObserver(): void;
220
219
  resetObserverRegistry(): void;
221
220
  handleBashCommand(command: string, excludeFromContext?: boolean): Promise<void>;
@@ -236,6 +235,7 @@ export declare class InteractiveMode implements InteractiveModeContext {
236
235
  }): void;
237
236
  showPluginSelector(mode?: "install" | "uninstall"): void;
238
237
  showUserMessageSelector(): void;
238
+ showCopySelector(): void;
239
239
  showTreeSelector(): void;
240
240
  showSessionSelector(): void;
241
241
  handleResumeSession(sessionPath: string): Promise<void>;
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Setup version the wizard advances a fresh install to. Bump it whenever a new
3
+ * setup scene lands (or an existing scene raises its `minVersion`).
4
+ *
5
+ * Kept in its own dependency-free module so the cold-launch gate in `main.ts`
6
+ * can answer "is the stored setup version stale?" without statically importing
7
+ * the full wizard — every scene (sign-in/OAuth, web search, theme previews) plus
8
+ * the overlay component and their TUI deps. MUST equal `max(scene.minVersion)`
9
+ * across `ALL_SCENES`; the `setup-wizard` barrel and test suite guard it.
10
+ */
11
+ export declare const CURRENT_SETUP_VERSION = 1;
@@ -1,9 +1,10 @@
1
1
  import type { Settings } from "../../config/settings";
2
+ import { CURRENT_SETUP_VERSION } from "../setup-version";
2
3
  import type { InteractiveModeContext } from "../types";
3
4
  import type { SetupScene } from "./scenes/types";
4
5
  export type { SetupScene, SetupSceneController, SetupSceneHost, SetupSceneResult } from "./scenes/types";
6
+ export { CURRENT_SETUP_VERSION };
5
7
  export declare const ALL_SCENES: readonly [SetupScene, SetupScene, SetupScene];
6
- export declare const CURRENT_SETUP_VERSION: number;
7
8
  export interface SetupSceneSelectionOptions {
8
9
  resuming?: boolean;
9
10
  isTTY?: boolean;
@@ -2,7 +2,8 @@ import type { SetupSceneHost, SetupTab } from "./types";
2
2
  /**
3
3
  * "Web search" panel: picks the provider the web_search tool should prefer and
4
4
  * reports whether the highlighted provider is ready to use given current
5
- * credentials (env keys or OAuth sign-ins from the Sign in tab).
5
+ * credentials (env keys or OAuth sign-ins from the Sign in tab) or an
6
+ * unauthenticated fallback.
6
7
  */
7
8
  export declare class WebSearchTab implements SetupTab {
8
9
  #private;
@@ -197,7 +197,6 @@ export interface InteractiveModeContext {
197
197
  toggleTodoExpansion(): void;
198
198
  handleExportCommand(text: string): Promise<void>;
199
199
  handleShareCommand(): Promise<void>;
200
- handleCopyCommand(sub?: string): void;
201
200
  handleTodoCommand(args: string): Promise<void>;
202
201
  handleSessionCommand(): Promise<void>;
203
202
  handleJobsCommand(): Promise<void>;
@@ -235,13 +234,14 @@ export interface InteractiveModeContext {
235
234
  }): void;
236
235
  showPluginSelector(mode?: "install" | "uninstall"): void;
237
236
  showUserMessageSelector(): void;
237
+ showCopySelector(): void;
238
238
  showTreeSelector(): void;
239
239
  showSessionSelector(): void;
240
240
  handleResumeSession(sessionPath: string): Promise<void>;
241
241
  handleSessionDeleteCommand(): Promise<void>;
242
242
  showOAuthSelector(mode: "login" | "logout", providerId?: string): Promise<void>;
243
243
  showHookConfirm(title: string, message: string): Promise<boolean>;
244
- showDebugSelector(): void;
244
+ showDebugSelector(): Promise<void>;
245
245
  showSessionObserver(): void;
246
246
  resetObserverRegistry(): void;
247
247
  handleCtrlC(): void;
@@ -0,0 +1,53 @@
1
+ import type { AgentMessage } from "@oh-my-pi/pi-agent-core";
2
+ /** A fenced code block extracted from assistant markdown. */
3
+ export interface CodeBlock {
4
+ /** Info string after the opening fence (language id), trimmed. */
5
+ lang: string;
6
+ /** Block body with the trailing newline stripped. */
7
+ code: string;
8
+ }
9
+ /** A runnable command found in the transcript. */
10
+ export interface LastCommand {
11
+ kind: "bash" | "eval";
12
+ code: string;
13
+ /** Highlight language: "bash" for bash, "python"/"javascript" for eval. */
14
+ language: string;
15
+ }
16
+ /**
17
+ * A node in the `/copy` picker tree. Leaves carry `content` (placed on the
18
+ * clipboard) plus `copyMessage` (the status shown afterwards); groups carry
19
+ * `children` to drill into.
20
+ */
21
+ export interface CopyTarget {
22
+ /** Stable identifier (e.g. "msg:1", "msg:1:code:0", "msg:1:all", "cmd:1"). */
23
+ id: string;
24
+ label: string;
25
+ /** Dim annotation: line/block counts, language, or tool name. */
26
+ hint?: string;
27
+ /** Full text rendered in the preview pane. */
28
+ preview: string;
29
+ /** Highlight language for code/command previews (undefined = plain/markdown). */
30
+ language?: string;
31
+ /** Leaf: text copied to the clipboard. */
32
+ content?: string;
33
+ /** Leaf: status message shown after copying. */
34
+ copyMessage?: string;
35
+ /** Group: nested targets to drill into. */
36
+ children?: CopyTarget[];
37
+ }
38
+ /** Minimal session surface needed to assemble copy targets (eases testing). */
39
+ export interface CopySource {
40
+ readonly messages: readonly AgentMessage[];
41
+ getLastVisibleHandoffText(): string | undefined;
42
+ }
43
+ /** Extract fenced code blocks from assistant markdown, in document order. */
44
+ export declare function extractCodeBlocks(text: string): CodeBlock[];
45
+ /** Walk the transcript backwards for the most recent bash command or eval code. */
46
+ export declare function extractLastCommand(messages: readonly AgentMessage[]): LastCommand | undefined;
47
+ /**
48
+ * Assemble the unified `/copy` target tree: recent assistant messages
49
+ * (most recent first, each drillable into its code blocks), runnable command
50
+ * targets interleaved after the assistant message that issued them, and a
51
+ * fresh-handoff fallback when no assistant message exists yet.
52
+ */
53
+ export declare function buildCopyTargets(source: CopySource): CopyTarget[];
@@ -13,7 +13,7 @@ import { type FileSlashCommand } from "./extensibility/slash-commands";
13
13
  import type { HindsightSessionState } from "./hindsight/state";
14
14
  import { type LocalProtocolOptions } from "./internal-urls";
15
15
  import { MCPManager, type MCPToolsLoadResult } from "./mcp";
16
- import { type MnemopiSessionState } from "./mnemopi/state";
16
+ import type { MnemopiSessionState } from "./mnemopi/state";
17
17
  import { AgentRegistry } from "./registry/agent-registry";
18
18
  import { AgentSession } from "./session/agent-session";
19
19
  import { AuthStorage } from "./session/auth-storage";
@@ -48,6 +48,13 @@ export interface ExecutorOptions {
48
48
  outputSchema?: unknown;
49
49
  /** Parent task recursion depth (0 = top-level, 1 = first child, etc.) */
50
50
  taskDepth?: number;
51
+ /**
52
+ * Override the `task.maxRuntimeMs` wall-clock cap for this run. When provided
53
+ * it wins over the settings value; `0` disables the per-subagent wall-clock
54
+ * limit entirely. Used by the eval `agent()` bridge, whose parent cell
55
+ * watchdog is already suspended for the call's duration.
56
+ */
57
+ maxRuntimeMs?: number;
51
58
  enableLsp?: boolean;
52
59
  signal?: AbortSignal;
53
60
  onProgress?: (progress: AgentProgress) => void;
@@ -10,7 +10,7 @@ export declare function isTelemetryExportEnabled(): boolean;
10
10
  * the OTEL kill-switches are engaged), so it is safe to call unconditionally at
11
11
  * startup.
12
12
  */
13
- export declare function initTelemetryExport(): void;
13
+ export declare function initTelemetryExport(): Promise<void>;
14
14
  /**
15
15
  * Flush any buffered spans to the exporter. No-op when export is disabled.
16
16
  * Hosts embedding the agent can call this at natural boundaries (e.g. the end
@@ -46,6 +46,7 @@ export declare const evalToolRenderer: {
46
46
  }, options: RenderResultOptions & {
47
47
  renderContext?: EvalRenderContext;
48
48
  }, uiTheme: Theme, _args?: EvalRenderArgs): Component;
49
+ isStreamingPreviewAppendOnly(_args: EvalRenderArgs, _options: RenderResultOptions, result?: unknown): boolean;
49
50
  mergeCallAndResult: boolean;
50
51
  inline: boolean;
51
52
  };
@@ -17,14 +17,22 @@ export interface ParsedReadUrlTarget {
17
17
  ranges?: readonly LineRange[];
18
18
  }
19
19
  export declare function parseReadUrlTarget(readPath: string): ParsedReadUrlTarget | null;
20
+ /** Reader backends for {@link renderHtmlToText}, in default priority order. */
21
+ export type FetchProvider = "native" | "trafilatura" | "lynx" | "parallel" | "jina";
20
22
  /**
21
- * Render HTML to markdown using Parallel, jina, trafilatura, lynx, then the
22
- * in-process native converter. The overall `timeout` budget bounds the call,
23
- * but remote reader requests are additionally capped at `REMOTE_READER_MAX_MS`
24
- * so that a hung remote endpoint cannot prevent local fallbacks from running.
25
- * Only a real `userSignal` cancellation aborts the chain remote per-attempt
26
- * timeouts and the overall reader-mode timeout still allow later renderers
27
- * (especially the purely-local native converter) to be tried.
23
+ * Render HTML to markdown by trying reader backends in priority order: native
24
+ * (in-process), trafilatura, lynx, Parallel, then Jina. The `providers.fetch`
25
+ * setting picks the order `auto` uses the default above; any specific backend
26
+ * is tried first, then the remaining backends as fallbacks. Every backend's
27
+ * output must clear the same quality gate (>100 non-whitespace chars and not
28
+ * {@link isLowQualityOutput}) before it is accepted, otherwise the next backend
29
+ * is tried.
30
+ *
31
+ * The overall `timeout` budget bounds the whole call; remote backends (Parallel,
32
+ * Jina) are additionally capped at `REMOTE_READER_MAX_MS` so a hung endpoint
33
+ * cannot starve later renderers — especially the purely-local native converter,
34
+ * which always works on already-loaded HTML. Only a real `userSignal`
35
+ * cancellation aborts the chain (#1449).
28
36
  */
29
37
  export declare function renderHtmlToText(url: string, html: string, timeout: number, settings: Settings, userSignal: AbortSignal | undefined, storage: AgentStorage | null): Promise<{
30
38
  content: string;
@@ -76,8 +76,41 @@ export declare function formatBadge(label: string, color: ToolUIColor, theme: Th
76
76
  * Uses consistent wording pattern.
77
77
  */
78
78
  export declare function formatMoreItems(remaining: number, itemType: string): string;
79
+ /**
80
+ * Maximum rows a tool's streaming/pending *call* preview may render before it is
81
+ * capped. This is intentionally conservative: the preview still sits inside a
82
+ * transcript that already consumed some viewport rows, and tool blocks carry
83
+ * extra chrome (status/header/border/"more lines"), so a "reasonable" raw code
84
+ * or command preview like 10-12 lines can still overflow and strand its top
85
+ * while the block is volatile. Keeping the live call window short avoids that
86
+ * across terminals without turning the transcript into an interactive scroller.
87
+ */
88
+ export declare const CALL_PREVIEW_MAX_LINES = 6;
89
+ /**
90
+ * Cap a pre-rendered pending/call preview to a bounded window. When truncated,
91
+ * show both the head and the live tail so the user can still see what the tool
92
+ * is currently writing while the volatile block stays short enough not to strand
93
+ * its top above the viewport. `Ctrl+O` widens the bounded window, but does not
94
+ * fully uncap live tool previews for the same reason.
95
+ *
96
+ * `prefix` (raw, e.g. a dim tree gutter) is prepended to the summary line so
97
+ * nested previews stay aligned.
98
+ */
99
+ export declare function capPreviewLines(lines: string[], theme: Theme, options?: {
100
+ max?: number;
101
+ expanded?: boolean;
102
+ prefix?: string;
103
+ }): string[];
79
104
  export declare function formatMeta(meta: string[], theme: Theme): string;
80
105
  export declare function formatErrorMessage(message: string | undefined, theme: Theme): string;
106
+ /**
107
+ * Error message rendered as a subordinate detail line beneath a status header
108
+ * that already carries the error icon (e.g. `✘ Write: <path>`). The header's
109
+ * icon already signals failure, so this omits the redundant error symbol and
110
+ * "Error:" prefix that `formatErrorMessage` adds for standalone single-line
111
+ * errors, indenting two columns to sit under the header title instead.
112
+ */
113
+ export declare function formatErrorDetail(message: string | undefined, theme: Theme): string;
81
114
  export declare function formatEmptyMessage(message: string, theme: Theme): string;
82
115
  export type CodeFrameMarker = "" | " " | "*" | "+" | "-" | ">";
83
116
  export declare function formatCodeFrameLine(marker: CodeFrameMarker, lineNumber: string | number, content: string, lineNumberWidth: number): string;
@@ -6,7 +6,7 @@
6
6
  import type { Component } from "@oh-my-pi/pi-tui";
7
7
  import type { RenderResultOptions } from "../extensibility/custom-tools/types";
8
8
  import type { Theme } from "../modes/theme/theme";
9
- type ToolRenderer = {
9
+ export type ToolRenderer = {
10
10
  renderCall: (args: unknown, options: RenderResultOptions, theme: Theme) => Component;
11
11
  renderResult: (result: {
12
12
  content: Array<{
@@ -19,8 +19,22 @@ type ToolRenderer = {
19
19
  renderContext?: Record<string, unknown>;
20
20
  }, theme: Theme, args?: unknown) => Component;
21
21
  mergeCallAndResult?: boolean;
22
+ /**
23
+ * While a tool's preview is still streaming, report whether the
24
+ * currently-rendered preview is append-only: its rows only grow at the bottom
25
+ * and never re-layout above the bottom live region (a full, top-anchored
26
+ * content/code preview). The transcript reports this up to the TUI so a
27
+ * streaming preview taller than the viewport commits its scrolled-off head to
28
+ * native scrollback instead of dropping it (see
29
+ * `ToolExecutionComponent.isTranscriptBlockAppendOnly`). `result` is the
30
+ * latest (possibly partial) tool result, or `undefined` before one exists —
31
+ * `eval`/`bash` use its presence to defer committing until the streamed input
32
+ * (code) has finalized. Omit (or return `false`) for previews that slide a
33
+ * tail window or later collapse to a compact result — committing their head
34
+ * would strand stale rows.
35
+ */
36
+ isStreamingPreviewAppendOnly?: (args: unknown, options: RenderResultOptions, result?: unknown) => boolean;
22
37
  /** Render without background box, inline in the response flow */
23
38
  inline?: boolean;
24
39
  };
25
40
  export declare const toolRenderers: Record<string, ToolRenderer>;
26
- export {};