@oh-my-pi/pi-coding-agent 16.3.2 → 16.3.3

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 (93) hide show
  1. package/CHANGELOG.md +38 -0
  2. package/dist/cli.js +3221 -3208
  3. package/dist/types/cli/update-cli.d.ts +1 -0
  4. package/dist/types/cli/update-cli.test.d.ts +1 -0
  5. package/dist/types/commands/update.d.ts +5 -0
  6. package/dist/types/config/config-file.d.ts +1 -1
  7. package/dist/types/config/settings-schema.d.ts +10 -0
  8. package/dist/types/dap/client.d.ts +9 -1
  9. package/dist/types/edit/file-snapshot-store.d.ts +9 -1
  10. package/dist/types/edit/hashline/execute.d.ts +1 -1
  11. package/dist/types/edit/hashline/params.d.ts +3 -6
  12. package/dist/types/edit/renderer.d.ts +1 -0
  13. package/dist/types/extensibility/plugins/parser.d.ts +2 -1
  14. package/dist/types/hindsight/client.d.ts +15 -11
  15. package/dist/types/hindsight/client.test.d.ts +1 -0
  16. package/dist/types/mcp/smithery-registry.d.ts +1 -0
  17. package/dist/types/mcp/smithery-registry.test.d.ts +1 -0
  18. package/dist/types/modes/components/advisor-message.d.ts +4 -2
  19. package/dist/types/modes/components/tool-execution.d.ts +9 -6
  20. package/dist/types/modes/components/transcript-container.d.ts +1 -0
  21. package/dist/types/modes/theme/theme.d.ts +1 -1
  22. package/dist/types/session/indexed-session-storage.d.ts +2 -2
  23. package/dist/types/session/session-storage.d.ts +31 -3
  24. package/dist/types/ssh/__tests__/connection-manager-timeout.test.d.ts +1 -0
  25. package/dist/types/ssh/__tests__/sshfs-mount.test.d.ts +1 -0
  26. package/dist/types/ssh/connection-manager.d.ts +19 -0
  27. package/dist/types/ssh/sshfs-mount.d.ts +10 -1
  28. package/dist/types/subprocess/worker-client.d.ts +20 -6
  29. package/dist/types/tools/bash.d.ts +27 -0
  30. package/dist/types/tools/renderers.d.ts +13 -0
  31. package/dist/types/tools/ssh.d.ts +2 -0
  32. package/dist/types/utils/fetch-timeout.d.ts +4 -0
  33. package/dist/types/web/search/providers/base.d.ts +1 -0
  34. package/dist/types/web/search/providers/gemini.d.ts +1 -0
  35. package/package.json +12 -12
  36. package/scripts/generate-legacy-pi-bundled-registry.ts +8 -2
  37. package/src/cli/models-cli.ts +19 -0
  38. package/src/cli/update-cli.test.ts +28 -0
  39. package/src/cli/update-cli.ts +35 -8
  40. package/src/commands/update.ts +8 -2
  41. package/src/config/config-file.ts +6 -6
  42. package/src/config/settings-schema.ts +10 -0
  43. package/src/dap/client.ts +134 -36
  44. package/src/edit/file-snapshot-store.ts +12 -1
  45. package/src/edit/hashline/diff.ts +4 -13
  46. package/src/edit/hashline/execute.ts +1 -1
  47. package/src/edit/hashline/params.ts +5 -12
  48. package/src/edit/renderer.ts +4 -2
  49. package/src/edit/streaming.ts +15 -5
  50. package/src/export/html/tool-views.generated.js +2 -2
  51. package/src/extensibility/plugins/installer.ts +12 -3
  52. package/src/extensibility/plugins/manager.ts +32 -8
  53. package/src/extensibility/plugins/parser.ts +7 -5
  54. package/src/extensibility/tool-event-input.ts +1 -1
  55. package/src/hindsight/client.test.ts +33 -0
  56. package/src/hindsight/client.ts +42 -22
  57. package/src/internal-urls/docs-index.generated.txt +1 -1
  58. package/src/main.ts +7 -1
  59. package/src/mcp/oauth-flow.ts +93 -4
  60. package/src/mcp/smithery-auth.ts +3 -0
  61. package/src/mcp/smithery-connect.ts +9 -0
  62. package/src/mcp/smithery-registry.test.ts +51 -0
  63. package/src/mcp/smithery-registry.ts +27 -4
  64. package/src/modes/components/advisor-message.ts +13 -10
  65. package/src/modes/components/status-line/component.ts +11 -4
  66. package/src/modes/components/tool-execution.ts +74 -8
  67. package/src/modes/components/transcript-container.ts +26 -0
  68. package/src/modes/controllers/event-controller.ts +7 -3
  69. package/src/modes/controllers/tool-args-reveal.ts +1 -1
  70. package/src/modes/interactive-mode.ts +1 -0
  71. package/src/modes/rpc/rpc-client.ts +29 -16
  72. package/src/modes/theme/shimmer.ts +49 -15
  73. package/src/modes/theme/theme.ts +7 -0
  74. package/src/session/agent-session.ts +166 -30
  75. package/src/session/indexed-session-storage.ts +40 -3
  76. package/src/session/session-manager.ts +83 -14
  77. package/src/session/session-storage.ts +112 -26
  78. package/src/slash-commands/helpers/usage-report.ts +6 -1
  79. package/src/ssh/__tests__/connection-manager-timeout.test.ts +61 -0
  80. package/src/ssh/__tests__/sshfs-mount.test.ts +13 -0
  81. package/src/ssh/connection-manager.ts +44 -11
  82. package/src/ssh/sshfs-mount.ts +27 -4
  83. package/src/subprocess/worker-client.ts +161 -10
  84. package/src/tools/bash.ts +30 -1
  85. package/src/tools/grep.ts +21 -1
  86. package/src/tools/read.ts +14 -4
  87. package/src/tools/renderers.ts +13 -0
  88. package/src/tools/ssh.ts +8 -0
  89. package/src/utils/clipboard.ts +49 -12
  90. package/src/utils/fetch-timeout.ts +10 -0
  91. package/src/web/search/index.ts +8 -0
  92. package/src/web/search/providers/base.ts +1 -0
  93. package/src/web/search/providers/gemini.ts +23 -6
@@ -19,6 +19,7 @@ export interface BinaryReplacementOptions {
19
19
  export declare function parseUpdateArgs(args: string[]): {
20
20
  force: boolean;
21
21
  check: boolean;
22
+ plugins: boolean;
22
23
  } | undefined;
23
24
  type UpdateMethod = "brew" | "mise" | "bun" | "binary";
24
25
  interface UpdateMethodResolutionOptions {
@@ -0,0 +1 @@
1
+ export {};
@@ -15,6 +15,11 @@ export default class Update extends Command {
15
15
  description: string;
16
16
  default: boolean;
17
17
  };
18
+ plugins: import("@oh-my-pi/pi-utils/cli").FlagDescriptor<"boolean"> & {
19
+ char: string;
20
+ description: string;
21
+ default: boolean;
22
+ };
18
23
  };
19
24
  run(): Promise<void>;
20
25
  }
@@ -1,4 +1,4 @@
1
- import type { Type } from "arktype";
1
+ import { type Type } from "arktype";
2
2
  /** Minimal subset of the AJV ConfigSchemaError shape this module actually relies on. */
3
3
  interface ConfigSchemaError {
4
4
  instancePath: string;
@@ -4586,6 +4586,16 @@ export declare const SETTINGS_SCHEMA: {
4586
4586
  readonly description: "Providers that web_search should never use, even as fallbacks";
4587
4587
  };
4588
4588
  };
4589
+ readonly "providers.webSearchGeminiModel": {
4590
+ readonly type: "string";
4591
+ readonly default: undefined;
4592
+ readonly ui: {
4593
+ readonly tab: "providers";
4594
+ readonly group: "Services";
4595
+ readonly label: "Gemini web_search model";
4596
+ readonly description: "Model ID for Gemini Google Search grounding. Defaults to gemini-2.5-flash.";
4597
+ };
4598
+ };
4589
4599
  readonly "providers.antigravityEndpoint": {
4590
4600
  readonly type: "enum";
4591
4601
  readonly values: readonly ["auto", "production", "sandbox"];
@@ -2,6 +2,14 @@ import type { DapCapabilities, DapClientState, DapEventMessage, DapInitializeArg
2
2
  interface DapSpawnOptions {
3
3
  adapter: DapResolvedAdapter;
4
4
  cwd: string;
5
+ /**
6
+ * Cap on how long the socket-mode helpers wait for the adapter to open its
7
+ * socket (unix) or dial back into our listener (TCP). Exposed for tests;
8
+ * production callers rely on the default.
9
+ *
10
+ * @internal
11
+ */
12
+ socketReadyTimeoutMs?: number;
5
13
  }
6
14
  /** Minimal write interface shared by Bun.FileSink and Bun TCP sockets. */
7
15
  interface DapWriteSink {
@@ -22,7 +30,7 @@ export declare class DapClient {
22
30
  end(): void;
23
31
  };
24
32
  });
25
- static spawn({ adapter, cwd }: DapSpawnOptions): Promise<DapClient>;
33
+ static spawn({ adapter, cwd, socketReadyTimeoutMs }: DapSpawnOptions): Promise<DapClient>;
26
34
  get capabilities(): DapCapabilities | undefined;
27
35
  get lastActivity(): number;
28
36
  isAlive(): boolean;
@@ -59,6 +59,14 @@ export declare function recordSeenLines(session: FileSnapshotStoreOwner, absolut
59
59
  * can reject edits anchored on lines the model never saw. Best-effort: a no-op
60
60
  * when the body has no numbered rows or the snapshot already aged out. `tag`
61
61
  * must be the tag returned when this exact content was recorded.
62
+ *
63
+ * `excludedLines` prunes 1-indexed line numbers whose displayed text was
64
+ * column-truncated (or otherwise not shown in full). A column-clipped row
65
+ * still carries a `NN:` prefix — the parser sees the number and would
66
+ * otherwise mark the line "seen" even though only its prefix ever reached
67
+ * the model. Producers that apply per-line column truncation MUST supply
68
+ * the clipped line set so the patcher's seen-line guard keeps rejecting
69
+ * edits against those lines until a full-width read of them occurs.
62
70
  */
63
- export declare function recordSeenLinesFromBody(session: FileSnapshotStoreOwner, absolutePath: string, tag: string, body: string): void;
71
+ export declare function recordSeenLinesFromBody(session: FileSnapshotStoreOwner, absolutePath: string, tag: string, body: string, excludedLines?: ReadonlySet<number>): void;
64
72
  export {};
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Coding-agent runner that drives the hashline {@link Patcher} on behalf of
3
- * the `edit` tool. Converts a `{input}` tool-call payload into a
3
+ * the `edit` tool. Converts an `{input}` tool-call payload into a
4
4
  * fully-applied patch, wraps the result in the agent's
5
5
  * {@link AgentToolResult} shape, and attaches LSP diagnostics + `outputMeta`
6
6
  * for the renderer.
@@ -1,7 +1,4 @@
1
- export declare const hashlineEditParamsSchema: import("arktype/internal/variants/object.ts").ObjectType<(In: {
2
- input?: string | undefined;
3
- _input?: string | undefined;
4
- }) => import("arktype/internal/attributes.ts").To<{
1
+ export declare const hashlineEditParamsSchema: import("arktype/internal/variants/object.ts").ObjectType<{
5
2
  input: string;
6
- }>, {}>;
7
- export type HashlineParams = Parameters<typeof hashlineEditParamsSchema.assert>[0];
3
+ }, {}>;
4
+ export type HashlineParams = typeof hashlineEditParamsSchema.infer;
@@ -67,6 +67,7 @@ interface EditRenderArgs {
67
67
  newText?: string;
68
68
  patch?: string;
69
69
  input?: string;
70
+ _input?: string;
70
71
  all?: boolean;
71
72
  op?: Operation;
72
73
  rename?: string;
@@ -41,12 +41,13 @@ export declare function parsePluginSpec(spec: string): ParsedPluginSpec;
41
41
  */
42
42
  export declare function formatPluginSpec(spec: ParsedPluginSpec): string;
43
43
  /**
44
- * Extract the base package name without version specifier.
44
+ * Extract the dependency key from an npm package specifier.
45
45
  * Used for path lookups after npm install.
46
46
  *
47
47
  * @example
48
48
  * extractPackageName("lodash@4.17.21") // "lodash"
49
49
  * extractPackageName("@scope/pkg@1.0.0") // "@scope/pkg"
50
50
  * extractPackageName("@scope/pkg") // "@scope/pkg"
51
+ * extractPackageName("npm:lodash") // "lodash"
51
52
  */
52
53
  export declare function extractPackageName(specifier: string): string;
@@ -17,6 +17,10 @@ export interface HindsightApiOptions {
17
17
  apiKey?: string;
18
18
  userAgent?: string;
19
19
  }
20
+ /** Caller cancellation shared by Hindsight request option bags. */
21
+ export interface HindsightRequestOptions {
22
+ signal?: AbortSignal;
23
+ }
20
24
  export interface RecallResult {
21
25
  id?: string;
22
26
  text: string;
@@ -61,7 +65,7 @@ export interface MemoryItemInput {
61
65
  strategy?: string;
62
66
  updateMode?: UpdateMode;
63
67
  }
64
- export interface RetainOptions {
68
+ export interface RetainOptions extends HindsightRequestOptions {
65
69
  timestamp?: Date | string;
66
70
  context?: string;
67
71
  metadata?: Record<string, string>;
@@ -70,42 +74,42 @@ export interface RetainOptions {
70
74
  tags?: string[];
71
75
  updateMode?: UpdateMode;
72
76
  }
73
- export interface RetainBatchOptions {
77
+ export interface RetainBatchOptions extends HindsightRequestOptions {
74
78
  /** Document id applied to every item that doesn't carry its own. */
75
79
  documentId?: string;
76
80
  /** Tags attached to the resulting document(s), not individual items. */
77
81
  documentTags?: string[];
78
82
  async?: boolean;
79
83
  }
80
- export interface RecallOptions {
84
+ export interface RecallOptions extends HindsightRequestOptions {
81
85
  types?: string[];
82
86
  maxTokens?: number;
83
87
  budget?: Budget;
84
88
  tags?: string[];
85
89
  tagsMatch?: TagsMatch;
86
90
  }
87
- export interface ReflectOptions {
91
+ export interface ReflectOptions extends HindsightRequestOptions {
88
92
  context?: string;
89
93
  budget?: Budget;
90
94
  tags?: string[];
91
95
  tagsMatch?: TagsMatch;
92
96
  }
93
- export interface CreateBankOptions {
97
+ export interface CreateBankOptions extends HindsightRequestOptions {
94
98
  reflectMission?: string;
95
99
  retainMission?: string;
96
100
  }
97
- export interface ListMemoriesOptions {
101
+ export interface ListMemoriesOptions extends HindsightRequestOptions {
98
102
  limit?: number;
99
103
  offset?: number;
100
104
  type?: string;
101
105
  q?: string;
102
106
  consolidationState?: ConsolidationState;
103
107
  }
104
- export interface ListDocumentsOptions {
108
+ export interface ListDocumentsOptions extends HindsightRequestOptions {
105
109
  limit?: number;
106
110
  offset?: number;
107
111
  }
108
- export interface UpdateDocumentOptions {
112
+ export interface UpdateDocumentOptions extends HindsightRequestOptions {
109
113
  tags?: string[];
110
114
  }
111
115
  export type MentalModelDetail = "metadata" | "content" | "full";
@@ -137,7 +141,7 @@ export interface MentalModelHistoryEntry {
137
141
  changed_at: string;
138
142
  [key: string]: unknown;
139
143
  }
140
- export interface CreateMentalModelOptions {
144
+ export interface CreateMentalModelOptions extends HindsightRequestOptions {
141
145
  id?: string;
142
146
  tags?: string[];
143
147
  maxTokens?: number;
@@ -151,10 +155,10 @@ export interface RefreshMentalModelResponse {
151
155
  operation_id?: string;
152
156
  [key: string]: unknown;
153
157
  }
154
- export interface ListMentalModelsOptions {
158
+ export interface ListMentalModelsOptions extends HindsightRequestOptions {
155
159
  detail?: MentalModelDetail;
156
160
  }
157
- export interface GetMentalModelOptions {
161
+ export interface GetMentalModelOptions extends HindsightRequestOptions {
158
162
  detail?: MentalModelDetail;
159
163
  }
160
164
  export declare class HindsightError extends Error {
@@ -0,0 +1 @@
1
+ export {};
@@ -41,6 +41,7 @@ export interface SmitherySearchOptions {
41
41
  limit?: number;
42
42
  apiKey?: string;
43
43
  includeSemantic?: boolean;
44
+ signal?: AbortSignal;
44
45
  }
45
46
  export declare class SmitheryRegistryError extends Error {
46
47
  status: number;
@@ -0,0 +1 @@
1
+ export {};
@@ -3,7 +3,9 @@ import type { AdvisorMessageDetails } from "../../advisor";
3
3
  import type { Theme } from "../theme/theme";
4
4
  /**
5
5
  * Display-only transcript card for advisor notes injected into the primary
6
- * session. Mirrors the IRC card's glyph + quote-border conventions so passive
7
- * advice reads as a distinct, non-interrupting aside rather than a user turn.
6
+ * session. Styled as a distinct voice so notes never blend into thinking
7
+ * output (whose `thinkingText` color equals `toolOutput` in most themes):
8
+ * a bold `customMessageLabel` header tag (skill-card convention), a heavy
9
+ * rail tinted per-note severity, and the note body on the default text color.
8
10
  */
9
11
  export declare function createAdvisorMessageCard(details: AdvisorMessageDetails | undefined, getExpanded: () => boolean, uiTheme: Theme): Component;
@@ -33,12 +33,14 @@ export interface ToolExecutionHandle {
33
33
  setArgsComplete(toolCallId?: string): void;
34
34
  setExpanded(expanded: boolean): void;
35
35
  }
36
- /** Drive pending-tool redraws at 30fps for live tool headers and displaceable
37
- * poll blocks. The TUI throttles at the same cadence, and static frames diff to
38
- * a no-op redraw at ~zero cost. */
39
- export declare const SPINNER_RENDER_INTERVAL_MS: number;
40
- /** Advance the spinner glyph at its classic ~12.5fps step, decoupled from the
41
- * render cadence (mirrors `Loader`). */
36
+ /** Redraw live tool blocks at the spinner's glyph-advance rate. Rendering more
37
+ * often produced identical frames the previous 30fps cadence emitted ~2.4
38
+ * paints per glyph step, and although the terminal I/O layer dedupes those, the
39
+ * compose pipeline still ran end-to-end per frame (issue #4353). Matching the
40
+ * render tick to the glyph tick halves the paints during tool execution with no
41
+ * visible change. */
42
+ export declare const SPINNER_RENDER_INTERVAL_MS = 80;
43
+ /** Advance the spinner glyph at its classic ~12.5fps step (mirrors `Loader`). */
42
44
  export declare const SPINNER_GLYPH_ADVANCE_MS = 80;
43
45
  /** Phase-locked spinner glyph index shared by every live tool block so parallel
44
46
  * spinners advance in lockstep instead of each tracking its own start time. */
@@ -121,4 +123,5 @@ export declare class ToolExecutionComponent extends Container implements NativeS
121
123
  setExpanded(expanded: boolean): void;
122
124
  setShowImages(show: boolean): void;
123
125
  invalidate(): void;
126
+ render(width: number): readonly string[];
124
127
  }
@@ -31,6 +31,7 @@ export declare class TranscriptContainer extends Container implements NativeScro
31
31
  getNativeScrollbackLiveRegionStart(): number | undefined;
32
32
  getNativeScrollbackCommitSafeEnd(): number | undefined;
33
33
  getNativeScrollbackSnapshotSafeEnd(): number | undefined;
34
+ getNativeScrollbackOfferSafeEnd(): number | undefined;
34
35
  /**
35
36
  * Whether `component` sits below a still-mutating block — i.e. inside the
36
37
  * live region, where its rows cannot have been committed to native
@@ -6,7 +6,7 @@ export type SymbolPreset = "unicode" | "nerd" | "ascii";
6
6
  /**
7
7
  * All available symbol keys organized by category.
8
8
  */
9
- export type SymbolKey = "status.success" | "status.error" | "status.warning" | "status.info" | "status.pending" | "status.disabled" | "status.enabled" | "status.running" | "status.shadowed" | "status.aborted" | "status.done" | "nav.cursor" | "nav.selected" | "nav.expand" | "nav.collapse" | "nav.back" | "tree.branch" | "tree.last" | "tree.vertical" | "tree.horizontal" | "tree.hook" | "boxRound.topLeft" | "boxRound.topRight" | "boxRound.bottomLeft" | "boxRound.bottomRight" | "boxRound.horizontal" | "boxRound.vertical" | "boxSharp.topLeft" | "boxSharp.topRight" | "boxSharp.bottomLeft" | "boxSharp.bottomRight" | "boxSharp.horizontal" | "boxSharp.vertical" | "boxSharp.cross" | "boxSharp.teeDown" | "boxSharp.teeUp" | "boxSharp.teeRight" | "boxSharp.teeLeft" | "sep.powerline" | "sep.powerlineThin" | "sep.powerlineLeft" | "sep.powerlineRight" | "sep.powerlineThinLeft" | "sep.powerlineThinRight" | "sep.block" | "sep.space" | "sep.asciiLeft" | "sep.asciiRight" | "sep.dot" | "sep.slash" | "sep.pipe" | "icon.model" | "icon.plan" | "icon.goal" | "icon.pause" | "icon.loop" | "icon.folder" | "icon.worktree" | "icon.search" | "icon.scratchFolder" | "icon.file" | "icon.git" | "icon.branch" | "icon.pr" | "icon.tokens" | "icon.context" | "icon.cost" | "icon.time" | "icon.pi" | "icon.ghost" | "icon.agents" | "icon.job" | "icon.cache" | "icon.cacheMiss" | "icon.input" | "icon.output" | "icon.throughput" | "icon.host" | "icon.session" | "icon.package" | "icon.warning" | "icon.rewind" | "icon.auto" | "icon.fast" | "icon.extensionSkill" | "icon.extensionTool" | "icon.extensionSlashCommand" | "icon.extensionMcp" | "icon.extensionRule" | "icon.extensionHook" | "icon.extensionPrompt" | "icon.extensionContextFile" | "icon.extensionInstruction" | "icon.mic" | "icon.camera" | "thinking.minimal" | "thinking.low" | "thinking.medium" | "thinking.high" | "thinking.xhigh" | "thinking.autoPending" | "checkbox.checked" | "checkbox.unchecked" | "radio.selected" | "radio.unselected" | "format.bullet" | "format.dash" | "format.bracketLeft" | "format.bracketRight" | "md.quoteBorder" | "md.hrChar" | "md.bullet" | "md.colorSwatch" | "lang.default" | "lang.typescript" | "lang.javascript" | "lang.python" | "lang.rust" | "lang.go" | "lang.java" | "lang.c" | "lang.cpp" | "lang.csharp" | "lang.ruby" | "lang.julia" | "lang.php" | "lang.swift" | "lang.kotlin" | "lang.shell" | "lang.html" | "lang.css" | "lang.json" | "lang.yaml" | "lang.markdown" | "lang.sql" | "lang.docker" | "lang.lua" | "lang.text" | "lang.env" | "lang.toml" | "lang.xml" | "lang.ini" | "lang.conf" | "lang.log" | "lang.csv" | "lang.tsv" | "lang.image" | "lang.pdf" | "lang.archive" | "lang.binary" | "tab.appearance" | "tab.model" | "tab.interaction" | "tab.context" | "tab.files" | "tab.shell" | "tab.tools" | "tab.memory" | "tab.tasks" | "tab.providers" | "tool.write" | "tool.edit" | "tool.bash" | "tool.ssh" | "tool.lsp" | "tool.gh" | "tool.webSearch" | "tool.exa" | "tool.browser" | "tool.eval" | "tool.debug" | "tool.mcp" | "tool.job" | "tool.task" | "tool.todo" | "tool.memory" | "tool.ask" | "tool.resolve" | "tool.review" | "tool.inspectImage" | "tool.goal" | "tool.irc" | "tool.delete" | "tool.move";
9
+ export type SymbolKey = "status.success" | "status.error" | "status.warning" | "status.info" | "status.pending" | "status.disabled" | "status.enabled" | "status.running" | "status.shadowed" | "status.aborted" | "status.done" | "nav.cursor" | "nav.selected" | "nav.expand" | "nav.collapse" | "nav.back" | "tree.branch" | "tree.last" | "tree.vertical" | "tree.horizontal" | "tree.hook" | "boxRound.topLeft" | "boxRound.topRight" | "boxRound.bottomLeft" | "boxRound.bottomRight" | "boxRound.horizontal" | "boxRound.vertical" | "boxSharp.topLeft" | "boxSharp.topRight" | "boxSharp.bottomLeft" | "boxSharp.bottomRight" | "boxSharp.horizontal" | "boxSharp.vertical" | "boxSharp.cross" | "boxSharp.teeDown" | "boxSharp.teeUp" | "boxSharp.teeRight" | "boxSharp.teeLeft" | "sep.powerline" | "sep.powerlineThin" | "sep.powerlineLeft" | "sep.powerlineRight" | "sep.powerlineThinLeft" | "sep.powerlineThinRight" | "sep.block" | "sep.space" | "sep.asciiLeft" | "sep.asciiRight" | "sep.dot" | "sep.slash" | "sep.pipe" | "icon.model" | "icon.plan" | "icon.goal" | "icon.pause" | "icon.loop" | "icon.folder" | "icon.worktree" | "icon.search" | "icon.scratchFolder" | "icon.file" | "icon.git" | "icon.branch" | "icon.pr" | "icon.tokens" | "icon.context" | "icon.cost" | "icon.time" | "icon.pi" | "icon.ghost" | "icon.agents" | "icon.job" | "icon.cache" | "icon.cacheMiss" | "icon.input" | "icon.output" | "icon.throughput" | "icon.host" | "icon.session" | "icon.package" | "icon.warning" | "icon.rewind" | "icon.auto" | "icon.fast" | "icon.extensionSkill" | "icon.extensionTool" | "icon.extensionSlashCommand" | "icon.extensionMcp" | "icon.extensionRule" | "icon.extensionHook" | "icon.extensionPrompt" | "icon.extensionContextFile" | "icon.extensionInstruction" | "icon.mic" | "icon.camera" | "thinking.minimal" | "thinking.low" | "thinking.medium" | "thinking.high" | "thinking.xhigh" | "thinking.autoPending" | "checkbox.checked" | "checkbox.unchecked" | "radio.selected" | "radio.unselected" | "format.bullet" | "format.dash" | "format.bracketLeft" | "format.bracketRight" | "md.quoteBorder" | "md.hrChar" | "md.bullet" | "md.colorSwatch" | "advisor.rail" | "lang.default" | "lang.typescript" | "lang.javascript" | "lang.python" | "lang.rust" | "lang.go" | "lang.java" | "lang.c" | "lang.cpp" | "lang.csharp" | "lang.ruby" | "lang.julia" | "lang.php" | "lang.swift" | "lang.kotlin" | "lang.shell" | "lang.html" | "lang.css" | "lang.json" | "lang.yaml" | "lang.markdown" | "lang.sql" | "lang.docker" | "lang.lua" | "lang.text" | "lang.env" | "lang.toml" | "lang.xml" | "lang.ini" | "lang.conf" | "lang.log" | "lang.csv" | "lang.tsv" | "lang.image" | "lang.pdf" | "lang.archive" | "lang.binary" | "tab.appearance" | "tab.model" | "tab.interaction" | "tab.context" | "tab.files" | "tab.shell" | "tab.tools" | "tab.memory" | "tab.tasks" | "tab.providers" | "tool.write" | "tool.edit" | "tool.bash" | "tool.ssh" | "tool.lsp" | "tool.gh" | "tool.webSearch" | "tool.exa" | "tool.browser" | "tool.eval" | "tool.debug" | "tool.mcp" | "tool.job" | "tool.task" | "tool.todo" | "tool.memory" | "tool.ask" | "tool.resolve" | "tool.review" | "tool.inspectImage" | "tool.goal" | "tool.irc" | "tool.delete" | "tool.move";
10
10
  export type SpinnerType = "status" | "activity";
11
11
  export type ThemeColor = "accent" | "border" | "borderAccent" | "borderMuted" | "success" | "error" | "warning" | "muted" | "dim" | "text" | "thinkingText" | "userMessageText" | "customMessageText" | "customMessageLabel" | "toolTitle" | "toolOutput" | "mdHeading" | "mdLink" | "mdLinkUrl" | "mdCode" | "mdCodeBlock" | "mdCodeBlockBorder" | "mdQuote" | "mdQuoteBorder" | "mdHr" | "mdListBullet" | "toolDiffAdded" | "toolDiffRemoved" | "toolDiffContext" | "syntaxComment" | "syntaxKeyword" | "syntaxFunction" | "syntaxVariable" | "syntaxString" | "syntaxNumber" | "syntaxType" | "syntaxOperator" | "syntaxPunctuation" | "thinkingOff" | "thinkingMinimal" | "thinkingLow" | "thinkingMedium" | "thinkingHigh" | "thinkingXhigh" | "bashMode" | "pythonMode" | "statusLineSep" | "statusLineModel" | "statusLinePath" | "statusLineGitClean" | "statusLineGitDirty" | "statusLineContext" | "statusLineSpend" | "statusLineStaged" | "statusLineDirty" | "statusLineUntracked" | "statusLineOutput" | "statusLineCost" | "statusLineSubagents";
12
12
  /** Check if a string is a valid ThemeColor value */
@@ -1,4 +1,4 @@
1
- import type { SessionStorage, SessionStorageStat, SessionStorageWriter } from "./session-storage";
1
+ import type { SessionStorage, SessionStorageStat, SessionStorageWriter, WriteTextAtomicOptions } from "./session-storage";
2
2
  import { type SessionTitleUpdate } from "./session-title-slot";
3
3
  export interface SessionStorageIndexEntry {
4
4
  path: string;
@@ -36,7 +36,7 @@ export declare class IndexedSessionStorage implements SessionStorage {
36
36
  readText(path: string): Promise<string>;
37
37
  readTextSlices(path: string, prefixBytes: number, suffixBytes: number): Promise<[string, string]>;
38
38
  writeText(path: string, content: string): Promise<void>;
39
- writeTextAtomic(path: string, content: string): Promise<void>;
39
+ writeTextAtomic(path: string, content: string, options?: WriteTextAtomicOptions): Promise<void>;
40
40
  rename(src: string, dst: string): Promise<void>;
41
41
  unlink(path: string): Promise<void>;
42
42
  deleteSessionWithArtifacts(sessionPath: string): Promise<void>;
@@ -19,6 +19,17 @@ export interface SessionStorageWriter {
19
19
  close(): Promise<void>;
20
20
  getError(): Error | undefined;
21
21
  }
22
+ /**
23
+ * Optional guard applied by {@link SessionStorage.writeTextAtomic}. The
24
+ * backend MUST call `commitGuard()` synchronously immediately before it makes
25
+ * the staged content visible at `path`. If it returns `false`, the staged
26
+ * write is discarded and the target is left untouched. Backends MUST NOT
27
+ * yield between calling the guard and publishing the write, so a concurrent
28
+ * synchronous rewrite that took over cannot be overwritten by a stale body.
29
+ */
30
+ export interface WriteTextAtomicOptions {
31
+ commitGuard?: () => boolean;
32
+ }
22
33
  export interface SessionStorage {
23
34
  ensureDirSync(dir: string): void;
24
35
  existsSync(path: string): boolean;
@@ -38,7 +49,7 @@ export interface SessionStorage {
38
49
  /** Read the requested UTF-8 byte windows from the head and tail of the file. */
39
50
  readTextSlices(path: string, prefixBytes: number, suffixBytes: number): Promise<[string, string]>;
40
51
  writeText(path: string, content: string): Promise<void>;
41
- writeTextAtomic(path: string, content: string): Promise<void>;
52
+ writeTextAtomic(path: string, content: string, options?: WriteTextAtomicOptions): Promise<void>;
42
53
  rename(path: string, nextPath: string): Promise<void>;
43
54
  unlink(path: string): Promise<void>;
44
55
  deleteSessionWithArtifacts(sessionPath: string): Promise<void>;
@@ -46,6 +57,15 @@ export interface SessionStorage {
46
57
  flags?: "a" | "w";
47
58
  onError?: (err: Error) => void;
48
59
  }): SessionStorageWriter;
60
+ /**
61
+ * Wait for every backing write scheduled by this storage to become durably
62
+ * visible. Sync backends (file, memory) return immediately because their
63
+ * writes complete in-body; async backends (Redis/SQL via
64
+ * {@link IndexedSessionStorage}) await their per-path queues so a caller
65
+ * driving a graceful shutdown does not exit while a fire-and-forget
66
+ * `writeTextSync` publish is still on the wire.
67
+ */
68
+ drain(): Promise<void>;
49
69
  }
50
70
  export declare class FileSessionStorage implements SessionStorage {
51
71
  #private;
@@ -59,9 +79,16 @@ export declare class FileSessionStorage implements SessionStorage {
59
79
  readText(path: string): Promise<string>;
60
80
  readTextSlices(path: string, prefixBytes: number, suffixBytes: number): Promise<[string, string]>;
61
81
  writeText(path: string, content: string): Promise<void>;
62
- writeTextAtomic(fpath: string, content: string): Promise<void>;
82
+ writeTextAtomic(fpath: string, content: string, options?: WriteTextAtomicOptions): Promise<void>;
83
+ /**
84
+ * Sync rename hook. Split from `rename` so `writeTextAtomic` can perform its
85
+ * guard-then-publish step without a yield, and so tests can inject
86
+ * Windows-style EPERM at the sync layer used by the atomic path.
87
+ */
88
+ renameSync(source: string, target: string): void;
63
89
  rename(path: string, nextPath: string): Promise<void>;
64
90
  unlink(path: string): Promise<void>;
91
+ drain(): Promise<void>;
65
92
  openWriter(path: string, options?: {
66
93
  flags?: "a" | "w";
67
94
  onError?: (err: Error) => void;
@@ -90,10 +117,11 @@ export declare class MemorySessionStorage implements SessionStorage {
90
117
  readText(path: string): Promise<string>;
91
118
  readTextSlices(path: string, prefixBytes: number, suffixBytes: number): Promise<[string, string]>;
92
119
  writeText(path: string, content: string): Promise<void>;
93
- writeTextAtomic(path: string, content: string): Promise<void>;
120
+ writeTextAtomic(path: string, content: string, options?: WriteTextAtomicOptions): Promise<void>;
94
121
  rename(path: string, nextPath: string): Promise<void>;
95
122
  unlink(path: string): Promise<void>;
96
123
  deleteSessionWithArtifacts(_sessionPath: string): Promise<void>;
124
+ drain(): Promise<void>;
97
125
  openWriter(path: string, options?: {
98
126
  flags?: "a" | "w";
99
127
  onError?: (err: Error) => void;
@@ -0,0 +1 @@
1
+ export {};
@@ -31,6 +31,25 @@ interface SSHArgsOptions {
31
31
  /** When true, omit `-n` so the remote command can read from our piped stdin. */
32
32
  allowStdin?: boolean;
33
33
  }
34
+ declare function runSshSync(args: string[], timeoutMs?: number): Promise<{
35
+ exitCode: number | null;
36
+ stderr: string;
37
+ }>;
38
+ declare function runSshCaptureSync(args: string[], timeoutMs?: number): Promise<{
39
+ exitCode: number | null;
40
+ stdout: string;
41
+ stderr: string;
42
+ }>;
43
+ /**
44
+ * Test-only surface for exercising the pre-command SSH helpers against a
45
+ * fake `ssh` binary with a shortened timeout. External code MUST NOT depend
46
+ * on this — call `ensureConnection` / `ensureHostInfo` instead.
47
+ * @internal
48
+ */
49
+ export declare const _sshHelpersForTests: {
50
+ runSshSync: typeof runSshSync;
51
+ runSshCaptureSync: typeof runSshCaptureSync;
52
+ };
34
53
  /**
35
54
  * Parse a raw cache-file value (or any unknown) into a normalized
36
55
  * {@link SSHHostInfo}, dropping fields that don't pass the per-field guards.
@@ -1,6 +1,15 @@
1
1
  import { type SSHConnectionTarget } from "./connection-manager";
2
+ type MountPointStatReader = (filePath: string) => Promise<{
3
+ dev: number;
4
+ }>;
5
+ interface MountCheckOptions {
6
+ platform?: NodeJS.Platform;
7
+ stat?: MountPointStatReader;
8
+ which?: (command: string) => string | null;
9
+ }
2
10
  export declare function hasSshfs(): boolean;
3
- export declare function isMounted(path: string): Promise<boolean>;
11
+ export declare function isMounted(mountPath: string, options?: MountCheckOptions): Promise<boolean>;
4
12
  export declare function mountRemote(host: SSHConnectionTarget, remotePath?: string): Promise<string | undefined>;
5
13
  export declare function unmountRemote(host: SSHConnectionTarget): Promise<boolean>;
6
14
  export declare function unmountAll(): Promise<void>;
15
+ export {};
@@ -55,7 +55,7 @@ export interface RefCountedWorkerHandle<Inbound, Outbound> extends WorkerHandle<
55
55
  }
56
56
  /** The raw spawned subprocess plus the parent-side fan-out sets. */
57
57
  export interface SpawnedSubprocess<Outbound> {
58
- proc: Subprocess<"ignore", "ignore", "ignore">;
58
+ proc: Subprocess<"ignore", "ignore", number | "ignore">;
59
59
  inbound: Set<(message: Outbound) => void>;
60
60
  errors: Set<(error: Error) => void>;
61
61
  /**
@@ -67,6 +67,14 @@ export interface SpawnedSubprocess<Outbound> {
67
67
  intentionalExit: {
68
68
  value: boolean;
69
69
  };
70
+ /**
71
+ * Resolves when the file-backed stderr capture has drained after worker
72
+ * exit. `onExit` waits on this before surfacing the crash so the exit-error
73
+ * carries the *whole* tail, not whatever happened to be flushed before the
74
+ * exit event fired. Tests can await it deterministically instead of racing
75
+ * wall-clock timers.
76
+ */
77
+ stderrDrained: Promise<void>;
70
78
  }
71
79
  export interface WorkerSpawnCommand {
72
80
  cmd: string[];
@@ -94,11 +102,17 @@ export declare function resolveWorkerSpawnCmd(workerArg: string): WorkerSpawnCom
94
102
  */
95
103
  export declare function workerEnvFromParent(overlay?: Record<string, string>): Record<string, string>;
96
104
  /**
97
- * Spawn an inference worker subprocess and wire its IPC fan-out. The child
98
- * inherits no stdio (native model runtimes may otherwise print progress or
99
- * decoded text and corrupt the chat scrollback) and is `unref`'d outside `bun
100
- * test` so an idle worker never blocks process exit. `exitLabel` prefixes the
101
- * worker-error message surfaced for an unexpected (non-intentional) exit.
105
+ * Spawn an inference worker subprocess and wire its IPC fan-out. Stdio is
106
+ * captured (stderr redirected to a temp file, stdout ignored) so native
107
+ * runtimes can't corrupt the chat scrollback while the crash reason still
108
+ * reaches the parent. The file-backed capture deliberately avoids Bun
109
+ * `ReadableStream` pipes: even an unref'd child with a piped stderr stream can
110
+ * keep the parent event loop alive. After the worker exits, the last
111
+ * {@link STDERR_TAIL_LIMIT_BYTES} are appended to the `onExit` error so
112
+ * `tts/mnemopi/…: worker error` lines carry the actual stack instead of a bare
113
+ * exit code (issue #4324). The child is `unref`'d outside `bun test` so an idle
114
+ * worker never blocks process exit. `exitLabel` prefixes the worker-error
115
+ * message surfaced for an unexpected (non-intentional) exit.
102
116
  */
103
117
  export declare function createWorkerSubprocess<Outbound>(options: {
104
118
  spawnCommand: WorkerSpawnCommand;
@@ -5,6 +5,33 @@ import { type Theme } from "../modes/theme/theme";
5
5
  import type { ToolSession } from ".";
6
6
  import { type OutputMeta } from "./output-meta";
7
7
  export declare const BASH_DEFAULT_PREVIEW_LINES = 10;
8
+ /**
9
+ * Shape a shell command line for an ACP-conformant `terminal/create` request.
10
+ *
11
+ * ACP's `command` field is documented as the executable and `args` as its
12
+ * argv tail (see https://agentclientprotocol.com/protocol/v1/terminals), so a
13
+ * spec-conformant client `spawn(command, args)`s them directly — no implicit
14
+ * shell. A raw `bash` tool line ("git status && echo x | head") therefore has
15
+ * to be wrapped in an explicit shell invocation, otherwise the client tries
16
+ * to spawn the whole line as argv[0] and fails with `ENOENT` for anything
17
+ * containing a space, pipe, `&&`, redirect, or `$(...)`.
18
+ *
19
+ * The wrap reuses the same shell binary + args the local `bash-executor` would
20
+ * pick via `settings.getShellConfig()` — Git Bash / `bash.exe` on Windows,
21
+ * `$SHELL` (bash/zsh) with the `sh` fallback on POSIX — so the ACP path
22
+ * preserves `bash` tool semantics (`$VAR`, `$(...)`, `source`, POSIX quoting,
23
+ * `-l`) instead of dropping to `cmd.exe` on Windows. The agent host's shell
24
+ * path is used as a proxy for the client's, matching the near-universal
25
+ * ACP deployment shape of an editor spawning omp as a co-hosted subprocess.
26
+ */
27
+ export declare function wrapShellLineForClientTerminal(line: string, shellConfig: {
28
+ shell: string;
29
+ args: string[];
30
+ prefix?: string | undefined;
31
+ }): {
32
+ command: string;
33
+ args: string[];
34
+ };
8
35
  /**
9
36
  * Bash patterns flagged as safety critical for approval policy.
10
37
  *
@@ -52,5 +52,18 @@ export type ToolRenderer = {
52
52
  * `options.spinnerFrame`.
53
53
  */
54
54
  animatedPartialResult?: boolean | ((args: unknown) => boolean);
55
+ /**
56
+ * Whether replacing a streamed pending placeholder with the first result
57
+ * requires a full viewport repaint. Use for merged renderers whose pending
58
+ * streamed args may have committed placeholder rows that the result render
59
+ * re-anchors instead of preserving.
60
+ */
61
+ forceFirstResultViewportRepaint?: boolean;
62
+ /**
63
+ * Whether settling a provisional partial result into the final render requires
64
+ * a full viewport repaint. Use when the result renderer changes chrome or
65
+ * frame topology at `options.isPartial: true -> false`.
66
+ */
67
+ forceResultViewportRepaintOnSettle?: boolean;
55
68
  };
56
69
  export declare const toolRenderers: Record<string, ToolRenderer>;
@@ -70,5 +70,7 @@ export declare const sshToolRenderer: {
70
70
  mergeCallAndResult: boolean;
71
71
  provisionalPendingPreview: boolean;
72
72
  provisionalPartialResult: boolean;
73
+ forceFirstResultViewportRepaint: boolean;
74
+ forceResultViewportRepaintOnSettle: boolean;
73
75
  };
74
76
  export {};
@@ -0,0 +1,4 @@
1
+ /** Create an abort signal that fires after a timeout and preserves caller cancellation. */
2
+ export declare function withTimeoutSignal(timeoutMs: number, signal?: AbortSignal): AbortSignal;
3
+ /** Detect a timeout raised by an abortable fetch. */
4
+ export declare function isTimeoutError(error: unknown): boolean;
@@ -51,6 +51,7 @@ export interface SearchParams {
51
51
  */
52
52
  sessionId?: string;
53
53
  antigravityEndpointMode?: "auto" | "production" | "sandbox";
54
+ geminiModel?: string;
54
55
  }
55
56
  /** Base class for web search providers. */
56
57
  export declare abstract class SearchProvider {
@@ -32,6 +32,7 @@ export interface GeminiSearchParams extends GeminiToolParams {
32
32
  sessionId?: string;
33
33
  fetch?: FetchImpl;
34
34
  antigravityEndpointMode?: "auto" | "production" | "sandbox";
35
+ geminiModel?: string;
35
36
  }
36
37
  export declare function buildGeminiRequestTools(params: GeminiToolParams): Array<Record<string, Record<string, unknown>>>;
37
38
  /** First configured Gemini OAuth provider plus its pre-resolved access. */