@oh-my-pi/pi-coding-agent 16.3.11 → 16.3.13

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 (113) hide show
  1. package/CHANGELOG.md +65 -0
  2. package/dist/cli.js +3176 -3087
  3. package/dist/types/advisor/runtime.d.ts +11 -0
  4. package/dist/types/config/keybindings.d.ts +9 -4
  5. package/dist/types/config/model-registry.d.ts +4 -0
  6. package/dist/types/config/settings-schema.d.ts +6 -0
  7. package/dist/types/config/settings.d.ts +3 -1
  8. package/dist/types/discovery/helpers.d.ts +9 -0
  9. package/dist/types/exec/bash-executor.d.ts +1 -0
  10. package/dist/types/extensibility/extensions/types.d.ts +11 -2
  11. package/dist/types/extensibility/shared-events.d.ts +2 -2
  12. package/dist/types/internal-urls/__tests__/agent-protocol-nested.test.d.ts +1 -0
  13. package/dist/types/internal-urls/registry-helpers.d.ts +7 -5
  14. package/dist/types/mnemopi/state.d.ts +7 -3
  15. package/dist/types/modes/acp/acp-event-mapper.d.ts +1 -0
  16. package/dist/types/modes/components/model-selector.d.ts +2 -1
  17. package/dist/types/modes/components/read-tool-group.d.ts +1 -0
  18. package/dist/types/modes/github-ref-autocomplete.d.ts +35 -0
  19. package/dist/types/modes/interactive-mode.d.ts +3 -1
  20. package/dist/types/modes/rpc/rpc-client.d.ts +11 -5
  21. package/dist/types/modes/rpc/rpc-mode.d.ts +1 -1
  22. package/dist/types/modes/types.d.ts +3 -1
  23. package/dist/types/modes/utils/context-usage.d.ts +0 -12
  24. package/dist/types/modes/workflow.d.ts +5 -1
  25. package/dist/types/session/agent-session.d.ts +8 -4
  26. package/dist/types/system-prompt.d.ts +1 -1
  27. package/dist/types/tools/bash-interactive.d.ts +1 -1
  28. package/dist/types/tools/bash-skill-urls.d.ts +1 -0
  29. package/dist/types/tools/bash.d.ts +2 -1
  30. package/dist/types/tools/browser/launch.d.ts +1 -0
  31. package/dist/types/tools/grep.d.ts +2 -0
  32. package/dist/types/tools/index.d.ts +4 -0
  33. package/dist/types/tools/path-utils.d.ts +24 -0
  34. package/dist/types/tools/read.d.ts +3 -0
  35. package/dist/types/tools/renderers.d.ts +12 -5
  36. package/dist/types/tools/ssh.d.ts +4 -1
  37. package/dist/types/tools/write.d.ts +1 -0
  38. package/dist/types/utils/local-date.d.ts +2 -0
  39. package/package.json +12 -12
  40. package/src/advisor/__tests__/advisor.test.ts +145 -0
  41. package/src/advisor/runtime.ts +19 -0
  42. package/src/config/api-key-resolver.ts +7 -2
  43. package/src/config/keybindings.ts +62 -10
  44. package/src/config/model-registry.ts +94 -20
  45. package/src/config/settings-schema.ts +11 -1
  46. package/src/config/settings.ts +59 -21
  47. package/src/discovery/builtin.ts +2 -1
  48. package/src/discovery/claude-plugins.ts +167 -46
  49. package/src/discovery/helpers.ts +16 -1
  50. package/src/edit/renderer.ts +20 -6
  51. package/src/eval/js/worker-core.ts +163 -6
  52. package/src/exec/bash-executor.ts +14 -9
  53. package/src/extensibility/extensions/runner.ts +1 -0
  54. package/src/extensibility/extensions/types.ts +13 -2
  55. package/src/extensibility/plugins/legacy-pi-compat.ts +6 -2
  56. package/src/extensibility/plugins/marketplace/fetcher.ts +15 -14
  57. package/src/extensibility/shared-events.ts +2 -2
  58. package/src/internal-urls/__tests__/agent-protocol-nested.test.ts +68 -0
  59. package/src/internal-urls/docs-index.generated.txt +1 -1
  60. package/src/internal-urls/registry-helpers.ts +9 -6
  61. package/src/mnemopi/state.ts +19 -5
  62. package/src/modes/acp/acp-agent.ts +69 -8
  63. package/src/modes/acp/acp-event-mapper.ts +1 -1
  64. package/src/modes/components/model-selector.ts +30 -6
  65. package/src/modes/components/read-tool-group.ts +5 -1
  66. package/src/modes/components/settings-defs.ts +1 -1
  67. package/src/modes/components/status-line/component.ts +14 -2
  68. package/src/modes/components/tool-execution.ts +28 -24
  69. package/src/modes/controllers/command-controller.ts +13 -23
  70. package/src/modes/controllers/event-controller.ts +12 -12
  71. package/src/modes/controllers/extension-ui-controller.test.ts +16 -0
  72. package/src/modes/controllers/extension-ui-controller.ts +7 -35
  73. package/src/modes/controllers/input-controller.ts +23 -57
  74. package/src/modes/controllers/mcp-command-controller.ts +10 -9
  75. package/src/modes/controllers/selector-controller.ts +16 -5
  76. package/src/modes/github-ref-autocomplete.ts +75 -0
  77. package/src/modes/interactive-mode.ts +97 -12
  78. package/src/modes/prompt-action-autocomplete.ts +35 -0
  79. package/src/modes/rpc/rpc-client.ts +42 -13
  80. package/src/modes/rpc/rpc-mode.ts +21 -19
  81. package/src/modes/types.ts +3 -0
  82. package/src/modes/utils/context-usage.ts +58 -5
  83. package/src/modes/utils/hotkeys-markdown.ts +2 -1
  84. package/src/modes/utils/ui-helpers.ts +2 -2
  85. package/src/modes/workflow.ts +14 -8
  86. package/src/prompts/agents/plan.md +0 -1
  87. package/src/prompts/agents/reviewer.md +0 -1
  88. package/src/prompts/system/plan-mode-active.md +5 -2
  89. package/src/prompts/system/system-prompt.md +1 -2
  90. package/src/prompts/system/workflow-notice.md +69 -50
  91. package/src/prompts/tools/bash.md +18 -7
  92. package/src/prompts/tools/grep.md +2 -1
  93. package/src/prompts/tools/memory-edit.md +2 -0
  94. package/src/prompts/tools/read.md +4 -3
  95. package/src/sdk.ts +11 -0
  96. package/src/session/agent-session.ts +136 -19
  97. package/src/system-prompt.ts +3 -2
  98. package/src/tools/bash-interactive.ts +1 -1
  99. package/src/tools/bash-skill-urls.ts +39 -7
  100. package/src/tools/bash.ts +69 -39
  101. package/src/tools/browser/launch.ts +31 -4
  102. package/src/tools/grep.ts +105 -21
  103. package/src/tools/image-gen.ts +1 -1
  104. package/src/tools/index.ts +11 -0
  105. package/src/tools/memory-edit.ts +3 -1
  106. package/src/tools/path-utils.ts +46 -1
  107. package/src/tools/read.ts +135 -57
  108. package/src/tools/renderers.ts +13 -5
  109. package/src/tools/ssh.ts +10 -3
  110. package/src/tools/tts.ts +1 -1
  111. package/src/tools/write.ts +26 -0
  112. package/src/utils/local-date.ts +7 -0
  113. package/src/utils/open.ts +36 -10
@@ -45,6 +45,17 @@ export interface AdvisorRuntimeHost {
45
45
  * one that routes `advise()` results back to the primary.
46
46
  */
47
47
  beginAdvisorUpdate?(): void;
48
+ /**
49
+ * Called with the error of every failed advisor turn, before the retry sleep
50
+ * or the dropped-after-3 path. Lets the host apply credential-level remedies
51
+ * the advisor loop lacks: the in-stream a/b/c auth retry rotates through
52
+ * sibling credentials within one request but never blocks the LAST failing
53
+ * one — the primary agent's retry pipeline does that via
54
+ * `markUsageLimitReached`, so without this hook the advisor re-picks the
55
+ * same usage-limited account on every retry. Errors thrown here are logged
56
+ * and swallowed.
57
+ */
58
+ onTurnError?(error: unknown): Promise<void> | void;
48
59
  /** Surface a non-recovering advisor failure to the host UI without adding model-visible context. */
49
60
  notifyFailure?(error: unknown): void;
50
61
  }
@@ -323,6 +323,11 @@ export declare const KEYBINDINGS: {
323
323
  readonly description: "Toggle speech-to-text (default gesture: hold Space)";
324
324
  };
325
325
  };
326
+ /** Controls inherited keybinding lookup when creating a manager for a named profile. */
327
+ export interface KeybindingsCreateOptions {
328
+ /** Default-profile agent directory whose keybindings are merged before profile-specific bindings. */
329
+ inheritedAgentDir?: string;
330
+ }
326
331
  declare function migrateKeybindingsConfigFile(agentDir: string): void;
327
332
  /**
328
333
  * Manages all keybindings (app + TUI).
@@ -330,18 +335,18 @@ declare function migrateKeybindingsConfigFile(agentDir: string): void;
330
335
  */
331
336
  export declare class KeybindingsManager extends TuiKeybindingsManager {
332
337
  #private;
333
- constructor(userBindings?: KeybindingsConfig, configPath?: string);
338
+ constructor(userBindings?: KeybindingsConfig, configPath?: string, inheritedConfigPath?: string);
334
339
  /**
335
- * Create from config file at agentDir/keybindings.yml.
340
+ * Create from config files at agentDir/keybindings.yml and the default profile.
336
341
  * Legacy keybindings.json is migrated to keybindings.yml on load.
337
342
  */
338
- static create(agentDir?: string): KeybindingsManager;
343
+ static create(agentDir?: string, options?: KeybindingsCreateOptions): KeybindingsManager;
339
344
  /**
340
345
  * Create an in-memory keybindings manager without file persistence.
341
346
  */
342
347
  static inMemory(userBindings?: KeybindingsConfig): KeybindingsManager;
343
348
  /**
344
- * Reload keybindings from the config file.
349
+ * Reload keybindings from the config files.
345
350
  */
346
351
  reload(): void;
347
352
  setUserBindings(userBindings: KeybindingsConfig): void;
@@ -189,6 +189,10 @@ export declare class ModelRegistry {
189
189
  * Check if a model selector is currently suppressed due to rate limits.
190
190
  */
191
191
  isSelectorSuppressed(selector: string): boolean;
192
+ /**
193
+ * Clear the cooldown suppression for one selector after an explicit user selection.
194
+ */
195
+ clearSuppressedSelector(selector: string): void;
192
196
  /**
193
197
  * Clear all cooldown suppressions recorded via {@link suppressSelector}.
194
198
  * Used to reset retry-fallback cooldown state without a full {@link refresh}.
@@ -1380,6 +1380,12 @@ export declare const SETTINGS_SCHEMA: {
1380
1380
  readonly "retry.fallbackChains": {
1381
1381
  readonly type: "record";
1382
1382
  readonly default: Record<string, string[]>;
1383
+ readonly ui: {
1384
+ readonly tab: "model";
1385
+ readonly group: "Retry & Fallback";
1386
+ readonly label: "Retry Fallback Chains";
1387
+ readonly description: 'JSON object mapping model roles to ordered fallback model selectors, e.g. {"default":["openai/gpt-4o-mini"]}.';
1388
+ };
1383
1389
  };
1384
1390
  readonly "retry.fallbackRevertPolicy": {
1385
1391
  readonly type: "enum";
@@ -24,7 +24,7 @@ export interface RawSettings {
24
24
  export interface SettingsOptions {
25
25
  /** Current working directory for project settings discovery */
26
26
  cwd?: string;
27
- /** Agent directory for config.yml storage */
27
+ /** Agent directory for config.yml/config.yaml storage */
28
28
  agentDir?: string;
29
29
  /** Don't persist to disk (for tests) */
30
30
  inMemory?: boolean;
@@ -152,6 +152,8 @@ export declare class Settings {
152
152
  * can register independently without overwriting each other.
153
153
  */
154
154
  export declare const onAppendOnlyModeChanged: (cb: (value: string) => void) => () => void;
155
+ /** Subscribe to model role changes. Returns an unsubscribe function. */
156
+ export declare const onModelRolesChanged: (cb: () => void) => () => void;
155
157
  /**
156
158
  * Subscribe to session-accent setting changes.
157
159
  * Returns an unsubscribe function. Callers should re-read settings in the callback.
@@ -122,6 +122,15 @@ export interface ScanSkillsFromDirOptions {
122
122
  providerId: string;
123
123
  level: "user" | "project";
124
124
  requireDescription?: boolean;
125
+ /**
126
+ * When true, treat a `SKILL.md` sitting directly under `dir` as a single skill in addition to
127
+ * scanning `<dir>/<name>/SKILL.md` children. Matches the Claude plugin manifest convention
128
+ * that lets a skill path point at a directory containing `SKILL.md` directly (e.g.
129
+ * `"skills": ["./"]`), where the frontmatter `name` determines the invocation name and the
130
+ * directory basename is the fallback. Default `false` preserves the strict child-scan
131
+ * semantic every non-Claude provider relies on.
132
+ */
133
+ includeSelf?: boolean;
125
134
  }
126
135
  export declare function compareSkillOrder(aName: string, aPath: string, bName: string, bPath: string): number;
127
136
  export declare function scanSkillsFromDir(_ctx: LoadContext, options: ScanSkillsFromDirOptions): Promise<LoadResult<Skill>>;
@@ -2,6 +2,7 @@ import { type MinimizerOptions } from "@oh-my-pi/pi-natives";
2
2
  import { type ShellMinimizerSettings } from "../config/settings.js";
3
3
  export interface BashExecutorOptions {
4
4
  cwd?: string;
5
+ /** Milliseconds before aborting the command; 0 disables the executor deadline. */
5
6
  timeout?: number;
6
7
  onChunk?: (chunk: string) => void;
7
8
  chunkThrottleMs?: number;
@@ -11,7 +11,7 @@ import type { AgentMessage, AgentToolResult, AgentToolUpdateCallback, ThinkingLe
11
11
  import type { CompactionResult } from "@oh-my-pi/pi-agent-core/compaction";
12
12
  import type { Api, AssistantMessageEvent, AssistantMessageEventStream, Context, ImageContent, Model, ModelSpec, ProviderResponseMetadata, SimpleStreamOptions, Static, TextContent, TSchema } from "@oh-my-pi/pi-ai";
13
13
  import type { OAuthCredentials, OAuthLoginCallbacks } from "@oh-my-pi/pi-ai/oauth/types";
14
- import type { AutocompleteItem, Component, EditorTheme, KeyId, TUI } from "@oh-my-pi/pi-tui";
14
+ import type { AutocompleteItem, AutocompleteProvider, Component, EditorTheme, KeyId, TUI } from "@oh-my-pi/pi-tui";
15
15
  import type { logger as PiLogger } from "@oh-my-pi/pi-utils";
16
16
  import type { Type as arktype } from "arktype";
17
17
  import type * as zod from "zod/v4";
@@ -89,6 +89,8 @@ export type ExtensionUiComponent = Component & {
89
89
  };
90
90
  export type ExtensionUiComponentFactory = (tui: TUI, theme: Theme) => ExtensionUiComponent;
91
91
  export type ExtensionWidgetContent = string[] | ExtensionUiComponentFactory | undefined;
92
+ /** Wrap the current autocomplete provider with additional behavior (pi-compatible). */
93
+ export type AutocompleteProviderFactory = (current: AutocompleteProvider) => AutocompleteProvider;
92
94
  /**
93
95
  * UI context for extensions to request interactive UI.
94
96
  * Each mode (interactive, RPC, print) provides its own implementation.
@@ -135,6 +137,13 @@ export interface ExtensionUIContext {
135
137
  editor(title: string, prefill?: string, dialogOptions?: ExtensionUIDialogOptions, editorOptions?: {
136
138
  promptStyle?: boolean;
137
139
  }): Promise<string | undefined>;
140
+ /**
141
+ * Stack additional autocomplete behavior on top of the built-in provider
142
+ * (pi-compatible). Interactive mode rebuilds the editor's provider through
143
+ * every registered factory, in registration order; headless modes (print,
144
+ * RPC, ACP, subagents) accept and ignore the factory.
145
+ */
146
+ addAutocompleteProvider(factory: AutocompleteProviderFactory): void;
138
147
  /**
139
148
  * Set a custom editor component via factory function, or `undefined` to restore the default editor.
140
149
  *
@@ -707,7 +716,7 @@ export interface ExtensionAPI {
707
716
  triggerTurn?: boolean;
708
717
  deliverAs?: "steer" | "followUp" | "nextTurn";
709
718
  }): void;
710
- /** Send a user message to the agent, or queue it when deliverAs is set. */
719
+ /** Send a user prompt: idle starts a turn; streaming queues as steer unless deliverAs is set. */
711
720
  sendUserMessage(content: string | (TextContent | ImageContent)[], options?: {
712
721
  deliverAs?: "steer" | "followUp";
713
722
  }): void;
@@ -27,7 +27,7 @@ export interface SessionStartEvent {
27
27
  export interface SessionBeforeSwitchEvent {
28
28
  type: "session_before_switch";
29
29
  /** Reason for the switch */
30
- reason: "new" | "resume" | "fork";
30
+ reason: "new" | "resume" | "fork" | "handoff";
31
31
  /** Session file we're switching to (only for "resume") */
32
32
  targetSessionFile?: string;
33
33
  }
@@ -35,7 +35,7 @@ export interface SessionBeforeSwitchEvent {
35
35
  export interface SessionSwitchEvent {
36
36
  type: "session_switch";
37
37
  /** Reason for the switch */
38
- reason: "new" | "resume" | "fork";
38
+ reason: "new" | "resume" | "fork" | "handoff";
39
39
  /** Session file we came from */
40
40
  previousSessionFile: string | undefined;
41
41
  }
@@ -3,10 +3,12 @@ export declare function resetRegisteredArtifactDirsForTests(): void;
3
3
  /**
4
4
  * Snapshot of artifacts dirs for every registered session, deduped.
5
5
  *
6
- * Prefers `sessionManager.getArtifactsDir()` because subagents adopt their
7
- * parent's `ArtifactManager` and report the parent's dir there; dedup then
8
- * collapses parent + N subagents (the whole agent tree) to one entry. Falls
9
- * back to the raw session file (with the `.jsonl` suffix stripped) when no
10
- * live session reference is attached.
6
+ * Collects TWO candidate dirs per ref, because a subagent reads from its
7
+ * adopted (root-wide) `ArtifactManager.dir` but its own children are written
8
+ * one level deeper, under `sessionFile.slice(0, -6)` (`task/index.ts`). A
9
+ * depth-2+ subagent's output therefore lives in the write-time dir, not the
10
+ * adopted one, so `agent://` must scan both or it 404s a live nested peer.
11
+ * `addDir` dedup collapses the depth-0 case (both formulas agree) back to a
12
+ * single entry.
11
13
  */
12
14
  export declare function artifactsDirsFromRegistry(): string[];
@@ -33,10 +33,14 @@ export interface MnemopiMemoryEditOptions {
33
33
  replacementId?: string;
34
34
  }
35
35
  export interface MnemopiMemoryEditResult {
36
- status: "updated" | "deleted" | "invalidated" | "not_found";
36
+ status: "updated" | "deleted" | "invalidated" | "not_found" | "not_editable";
37
37
  bank?: string;
38
- store?: "working" | "episodic";
38
+ store?: MnemopiMemoryStore;
39
39
  }
40
+ /** Which mnemopi table a resolved memory id lives in. `fact` rows are
41
+ * read-only projections of fact extraction (issue #4725): resolvable for
42
+ * reads, never editable. */
43
+ export type MnemopiMemoryStore = "working" | "episodic" | "fact";
40
44
  /**
41
45
  * Full-row lookup result produced by {@link MnemopiSessionState.getScopedMemory}.
42
46
  * Mirrors the shape stored in mnemopi's working/episodic tables, tagged with
@@ -45,7 +49,7 @@ export interface MnemopiMemoryEditResult {
45
49
  */
46
50
  export interface MnemopiScopedMemoryHit {
47
51
  bank: string;
48
- store: "working" | "episodic";
52
+ store: MnemopiMemoryStore;
49
53
  row: {
50
54
  id: string;
51
55
  content: string;
@@ -30,4 +30,5 @@ export declare function buildToolCallStartUpdate(input: {
30
30
  export declare function normalizeReplayToolArguments(value: unknown): {
31
31
  args: unknown;
32
32
  };
33
+ export declare function extractAssistantMessageText(value: unknown): string;
33
34
  export {};
@@ -7,7 +7,8 @@ interface ScopedModelItem {
7
7
  model: Model;
8
8
  thinkingLevel?: string;
9
9
  }
10
- type RoleSelectCallback = (model: Model, role: string | null, thinkingLevel?: ConfiguredThinkingLevel, selector?: string) => void;
10
+ type ModelSelectorAction = "modelRole" | "retryFallback";
11
+ type RoleSelectCallback = (model: Model, role: string | null, thinkingLevel?: ConfiguredThinkingLevel, selector?: string, action?: ModelSelectorAction) => void;
11
12
  /**
12
13
  * Component that renders a model selector with provider tabs and context menu.
13
14
  * - Tab/Arrow Left/Right: Switch between provider tabs
@@ -6,6 +6,7 @@ export declare function readArgsTargetInternalUrl(args: unknown): boolean;
6
6
  type ReadRenderArgs = {
7
7
  path?: string;
8
8
  file_path?: string;
9
+ selector?: string;
9
10
  sel?: string;
10
11
  };
11
12
  type ReadToolGroupOptions = {
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Autocomplete for GitHub issue/PR references typed as `#<number>` (e.g. `#3164`).
3
+ *
4
+ * Mirrors the `@` file-reference and `scheme://` internal-url conventions: the
5
+ * token is rewritten to an internal URL (`pr://3164` or `issue://3164`) plus a
6
+ * trailing space, and the existing tool-mediated pipeline (the `read` tool →
7
+ * InternalUrlRouter → `gh`) resolves it from the session cwd's git remote.
8
+ *
9
+ * No network at suggestion time — candidates are generated locally. GitHub
10
+ * shares the issue/PR number space and there is no cheap way to tell which a
11
+ * given number is while typing, so both a PR and an Issue candidate are offered
12
+ * by default. Naming the type first (`pr #3164` / `issue #3164`) constrains the
13
+ * candidates to that kind. Anything that is not a standalone `#<number>` token
14
+ * keeps falling through to the existing prompt-action menu.
15
+ */
16
+ import type { AutocompleteItem } from "@oh-my-pi/pi-tui";
17
+ export interface GithubRefContext {
18
+ /** Text to replace on accept: `#3164`, or `pr #3164` when a qualifier precedes it. */
19
+ prefix: string;
20
+ /** Type the user named (`pr`/`pull` → `pr`, `issue` → `issue`), or null to offer both. */
21
+ qualifier: "pr" | "issue" | null;
22
+ /** The numeric reference, e.g. `3164`. */
23
+ number: string;
24
+ }
25
+ export declare function getGithubRefContext(textBeforeCursor: string): GithubRefContext | null;
26
+ /**
27
+ * Suggestions for a `#<number>` token. Both kinds are offered unless the user
28
+ * named a type (`pr #3164` / `issue #3164`), in which case only that kind is
29
+ * offered. Returns `null` when the text before the cursor is not a standalone
30
+ * `#<number>` token.
31
+ */
32
+ export declare function getGithubRefSuggestions(textBeforeCursor: string): {
33
+ items: AutocompleteItem[];
34
+ prefix: string;
35
+ } | null;
@@ -7,7 +7,7 @@ import type { CollabGuestLink } from "../collab/guest.js";
7
7
  import type { CollabHost } from "../collab/host.js";
8
8
  import { KeybindingsManager } from "../config/keybindings.js";
9
9
  import { Settings } from "../config/settings.js";
10
- import type { ExtensionUIContext, ExtensionUIDialogOptions, ExtensionUISelectItem, ExtensionWidgetContent, ExtensionWidgetOptions } from "../extensibility/extensions/index.js";
10
+ import type { AutocompleteProviderFactory, ExtensionUIContext, ExtensionUIDialogOptions, ExtensionUISelectItem, ExtensionWidgetContent, ExtensionWidgetOptions } from "../extensibility/extensions/index.js";
11
11
  import type { CompactOptions } from "../extensibility/extensions/types.js";
12
12
  import type { Skill } from "../extensibility/skills.js";
13
13
  import type { MCPManager } from "../mcp/index.js";
@@ -180,6 +180,8 @@ export declare class InteractiveMode implements InteractiveModeContext {
180
180
  refreshTitleSystemPrompt(cwd?: string): Promise<void>;
181
181
  /** Reload slash commands and autocomplete for the provided working directory. */
182
182
  refreshSlashCommandState(cwd?: string): Promise<void>;
183
+ /** Stack extension autocomplete behavior on top of the built-in editor provider (#4919). */
184
+ addAutocompleteProvider(factory: AutocompleteProviderFactory): void;
183
185
  /**
184
186
  * Re-point the process and every cwd-derived cache at `newCwd` after the
185
187
  * active session's working directory changed (`/move` relocation or resuming
@@ -269,17 +269,23 @@ export declare class RpcClient {
269
269
  /**
270
270
  * Trigger OAuth login for the given provider.
271
271
  * The server will emit an `open_url` extension_ui_request for the auth URL.
272
+ * Providers that require pasted-code completion may then emit an `input`
273
+ * extension_ui_request; pass `onManualCodeInput` to satisfy it.
272
274
  * Resolves when login completes or rejects on failure.
273
275
  *
274
276
  * @param onOpenUrl Called when the server emits the auth URL. The host must
275
- * open `url` in a browser for the callback-server OAuth flow to complete.
276
- * When the flow's callback server hosts a `/launch` redirect, `launchUrl`
277
- * is a short loopback URL that 302s to `url` — hosts SHOULD surface it as
278
- * the truncation-safe copy target so terminal viewport clipping cannot
279
- * corrupt trailing OAuth query parameters (e.g. `code_challenge_method=S256`).
277
+ * open `url` in a browser. When the flow's callback server hosts a
278
+ * `/launch` redirect, `launchUrl` is a short loopback URL that 302s to
279
+ * `url` — hosts SHOULD surface it as the truncation-safe copy target so
280
+ * terminal viewport clipping cannot corrupt trailing OAuth query
281
+ * parameters (e.g. `code_challenge_method=S256`).
280
282
  */
281
283
  login(providerId: string, options?: {
282
284
  onOpenUrl?: (url: string, instructions?: string, launchUrl?: string) => void;
285
+ onManualCodeInput?: (prompt: {
286
+ title: string;
287
+ placeholder?: string;
288
+ }) => string | Promise<string>;
283
289
  }): Promise<{
284
290
  providerId: string;
285
291
  }>;
@@ -38,7 +38,7 @@ export type RpcSkillCommandSession = Pick<AgentSession, "promptCustomMessage" |
38
38
  export type RpcSkillCommandResult = {
39
39
  agentInvoked: true;
40
40
  };
41
- export declare function tryRunRpcSkillCommand(session: RpcSkillCommandSession, text: string): Promise<RpcSkillCommandResult | false>;
41
+ export declare function tryRunRpcSkillCommand(session: RpcSkillCommandSession, text: string, streamingBehavior?: "steer" | "followUp"): Promise<RpcSkillCommandResult | false>;
42
42
  export declare function reportLocalOnlyPromptResult(input: {
43
43
  id: string | undefined;
44
44
  prompt: Promise<boolean>;
@@ -6,7 +6,7 @@ import type { CollabGuestLink } from "../collab/guest.js";
6
6
  import type { CollabHost } from "../collab/host.js";
7
7
  import type { KeybindingsManager } from "../config/keybindings.js";
8
8
  import type { Settings } from "../config/settings.js";
9
- import type { ExtensionUIContext, ExtensionUIDialogOptions, ExtensionUISelectItem, ExtensionWidgetContent, ExtensionWidgetOptions } from "../extensibility/extensions/index.js";
9
+ import type { AutocompleteProviderFactory, ExtensionUIContext, ExtensionUIDialogOptions, ExtensionUISelectItem, ExtensionWidgetContent, ExtensionWidgetOptions } from "../extensibility/extensions/index.js";
10
10
  import type { CompactOptions } from "../extensibility/extensions/types.js";
11
11
  import type { Skill } from "../extensibility/skills.js";
12
12
  import type { MCPManager } from "../mcp/index.js";
@@ -195,6 +195,8 @@ export interface InteractiveModeContext {
195
195
  checkShutdownRequested(): Promise<void>;
196
196
  setToolUIContext(uiContext: ExtensionUIContext, hasUI: boolean): void;
197
197
  initializeHookRunner(uiContext: ExtensionUIContext, hasUI: boolean): void;
198
+ /** Stack extension autocomplete behavior on top of the built-in editor provider. */
199
+ addAutocompleteProvider(factory: AutocompleteProviderFactory): void;
198
200
  setEditorComponent(factory: ((tui: TUI, theme: EditorTheme, keybindings: KeybindingsManager) => CustomEditor) | undefined): void;
199
201
  /**
200
202
  * Mount transcript content and repaint once. The single sink for "show this in
@@ -24,18 +24,6 @@ export interface ContextBreakdown {
24
24
  }
25
25
  export declare function estimateSkillsTokens(skills: readonly Skill[]): number;
26
26
  export declare function estimateToolSchemaTokens(tools: ReadonlyArray<Pick<Tool, "name" | "description" | "parameters">>): number;
27
- /**
28
- * Compute just the NON-MESSAGE token total: system prompt (with its skills
29
- * section subtracted, since skills are tokenized separately) + system context
30
- * (the rest of the system-prompt array) + tools + skills.
31
- *
32
- * Exposed so callers like `StatusLineComponent` can cache the non-message
33
- * total separately from the message total. Non-message inputs (skills,
34
- * tools, system prompt) change rarely; the message list grows on every
35
- * streaming turn. Splitting the two lets the caller refresh each on its own
36
- * cadence — non-message recomputed only when the inputs identity changes,
37
- * messages walked incrementally as new entries append.
38
- */
39
27
  export declare function computeNonMessageTokens(session: AgentSession): number;
40
28
  /**
41
29
  * Shared helper for the four non-message token totals used by
@@ -1,6 +1,10 @@
1
1
  import { type KeywordHighlighter } from "./gradient-highlight.js";
2
- /** Hidden system notice appended after a user message that mentions "workflowz". */
2
+ /** WORKFLOW_NOTICE is the default hidden notice for sessions with batched task calls enabled. */
3
3
  export declare const WORKFLOW_NOTICE: string;
4
+ /** renderWorkflowNotice renders the workflow notice for the active task schema. */
5
+ export declare function renderWorkflowNotice({ taskBatch }: {
6
+ taskBatch: boolean;
7
+ }): string;
4
8
  /**
5
9
  * Whether `text` contains the standalone keyword "workflowz"
6
10
  * (lowercase, whitespace-delimited) in prose — never inside a code block, inline
@@ -184,6 +184,8 @@ export interface AgentSessionConfig {
184
184
  toolRegistry?: Map<string, AgentTool>;
185
185
  /** Tool names whose current registry entry is still the built-in implementation. */
186
186
  builtInToolNames?: Iterable<string>;
187
+ /** Update tool-session predicates that render guidance from the live active tool set. */
188
+ setActiveToolNames?: (names: Iterable<string>) => void;
187
189
  /** Current session pre-LLM message transform pipeline */
188
190
  transformContext?: (messages: AgentMessage[], signal?: AbortSignal) => AgentMessage[] | Promise<AgentMessage[]>;
189
191
  /**
@@ -224,6 +226,8 @@ export interface AgentSessionConfig {
224
226
  rebuildSystemPrompt?: (toolNames: string[], tools: Map<string, AgentTool>) => Promise<{
225
227
  systemPrompt: string[];
226
228
  }>;
229
+ /** Local calendar date provider used by prompt-cache invalidation. Defaults to the host local date. */
230
+ getLocalCalendarDate?: () => string;
227
231
  /** Rebuild the SSH tool from current capability discovery results. */
228
232
  reloadSshTool?: () => Promise<AgentTool | null>;
229
233
  requestedToolNames?: ReadonlySet<string>;
@@ -366,6 +370,7 @@ export interface HandoffResult {
366
370
  export interface SessionHandoffOptions {
367
371
  autoTriggered?: boolean;
368
372
  signal?: AbortSignal;
373
+ onSwitchCancelled?: () => void;
369
374
  }
370
375
  /** Result from cycleModel() */
371
376
  export interface ModelCycleResult {
@@ -809,11 +814,10 @@ export declare class AgentSession {
809
814
  queueChipText?: string;
810
815
  }): Promise<boolean>;
811
816
  /**
812
- * Send a user message to the agent.
813
- * When deliverAs is set, queue the message instead of starting a new turn.
817
+ * Send a user message through the prompt flow.
814
818
  *
815
- * @param content User message content (string or content array)
816
- * @param options.deliverAs Delivery mode: "steer" or "followUp"
819
+ * Omitted `deliverAs` starts a turn when idle and queues as a steer while streaming.
820
+ * Explicit `deliverAs` queues without starting a turn in either state.
817
821
  */
818
822
  sendUserMessage(content: string | (TextContent | ImageContent)[], options?: {
819
823
  deliverAs?: "steer" | "followUp";
@@ -35,7 +35,7 @@ export declare function loadProjectContextFiles(options?: LoadContextFilesOption
35
35
  * Project-level SYSTEM.md overrides user-level SYSTEM.md.
36
36
  */
37
37
  export declare function loadSystemPromptFiles(options?: LoadContextFilesOptions): Promise<string | null>;
38
- export declare const DEFAULT_SYSTEM_PROMPT_TOOL_NAMES: readonly ["read", "bash", "eval", "edit", "write"];
38
+ export declare const DEFAULT_SYSTEM_PROMPT_TOOL_NAMES: readonly ["read", "bash", "edit", "write"];
39
39
  export interface SystemPromptToolMetadata {
40
40
  label: string;
41
41
  description: string;
@@ -8,7 +8,7 @@ export interface BashInteractiveResult extends OutputSummary {
8
8
  export declare function runInteractiveBashPty(ui: NonNullable<AgentToolContext["ui"]>, options: {
9
9
  command: string;
10
10
  cwd: string;
11
- timeoutMs: number;
11
+ timeoutMs?: number;
12
12
  signal?: AbortSignal;
13
13
  env?: Record<string, string>;
14
14
  artifactPath?: string;
@@ -25,6 +25,7 @@ export declare function resolveSkillUrlToPath(url: string, skills: readonly Skil
25
25
  export declare function expandSkillUrls(command: string, skills: readonly Skill[]): string;
26
26
  /**
27
27
  * Expand supported internal URLs in a bash command string to shell-escaped absolute paths.
28
+ * Unresolvable URLs and literal mentions inside larger quoted text are left unchanged.
28
29
  * Supported schemes: skill://, agent://, artifact://, memory://, rule://, local://
29
30
  */
30
31
  export declare function expandInternalUrls(command: string, options: InternalUrlExpansionOptions): Promise<string>;
@@ -72,6 +72,7 @@ export interface BashToolDetails {
72
72
  meta?: OutputMeta;
73
73
  timeoutSeconds?: number;
74
74
  requestedTimeoutSeconds?: number;
75
+ timeoutDisabled?: boolean;
75
76
  wallTimeMs?: number;
76
77
  /** Exit code of a command that ran to completion but failed (non-zero). */
77
78
  exitCode?: number;
@@ -97,7 +98,7 @@ export declare class BashTool implements AgentTool<typeof bashSchemaBase | typeo
97
98
  readonly formatApprovalDetails: (args: unknown) => string[];
98
99
  readonly label = "Bash";
99
100
  readonly loadMode = "essential";
100
- readonly description: string;
101
+ get description(): string;
101
102
  readonly parameters: BashToolSchema;
102
103
  readonly concurrency: (args: Partial<BashToolInput>) => "shared" | "exclusive";
103
104
  readonly strict = true;
@@ -60,6 +60,7 @@ export declare function applyStealthPatches(browser: Browser, page: Page, state:
60
60
  browserSession: CDPSession | null;
61
61
  override: UserAgentOverride | null;
62
62
  }): Promise<void>;
63
+ export declare function stealthIgnoreDefaultArgsForTest(executablePath: string | undefined): string[];
63
64
  export declare function targetSupportsUserAgentOverrideForTest(target: Target): boolean;
64
65
  export declare function configureUserAgentTargetsForTest(browser: Browser, state: {
65
66
  browserSession: CDPSession | null;
@@ -8,6 +8,7 @@ import type { OutputMeta } from "./output-meta.js";
8
8
  declare const searchSchema: import("arktype/internal/variants/object.ts").ObjectType<{
9
9
  pattern: string;
10
10
  path?: string | undefined;
11
+ selector?: string | undefined;
11
12
  case?: boolean | undefined;
12
13
  gitignore?: boolean | undefined;
13
14
  skip?: number | null | undefined;
@@ -66,6 +67,7 @@ export declare class GrepTool implements AgentTool<typeof searchSchema, GrepTool
66
67
  readonly parameters: import("arktype/internal/variants/object.ts").ObjectType<{
67
68
  pattern: string;
68
69
  path?: string | undefined;
70
+ selector?: string | undefined;
69
71
  case?: boolean | undefined;
70
72
  gitignore?: boolean | undefined;
71
73
  skip?: number | null | undefined;
@@ -172,6 +172,10 @@ export interface ToolSession {
172
172
  getAgentId?: () => string | null;
173
173
  /** Look up a registered tool by name (used by the eval js backend's tool bridge). */
174
174
  getToolByName?: (name: string) => AgentTool | undefined;
175
+ /** Return whether a built-in tool is active in this turn's tool set. */
176
+ isToolActive?: (name: string) => boolean;
177
+ /** Update the active built-in tool predicate when a session changes tools mid-run. */
178
+ setActiveToolNames?: (names: Iterable<string>) => void;
175
179
  /** Agent registry for IRC routing across live sessions. */
176
180
  agentRegistry?: AgentRegistry;
177
181
  /** Get artifacts directory for artifact:// URLs */
@@ -36,6 +36,30 @@ export declare function splitPathAndSel(rawPath: string): {
36
36
  path: string;
37
37
  sel?: string;
38
38
  };
39
+ /**
40
+ * Three-way probe for whether the exact filesystem entry named by `filePath`
41
+ * exists. `stat` (used earlier) failed for reasons other than "no such file"
42
+ * (dangling symlink, `EACCES` on a parent, transient I/O), and each of those
43
+ * silently reinterpreted a real literal path such as `test:1-2` as `test`
44
+ * plus selector `1-2` (issue #4618). `lstat` inspects the entry itself, so a
45
+ * dangling symlink is still detected as present; ambiguous errors resolve to
46
+ * `"unknown"` so callers keep the raw path instead of guessing.
47
+ */
48
+ export declare function probeLiteralPathExists(filePath: string, cwd: string): Promise<"exists" | "missing" | "unknown">;
49
+ /**
50
+ * Async sibling of {@link splitPathAndSel} that prefers a literal filesystem
51
+ * path over selector interpretation. Filenames whose tail matches the selector
52
+ * grammar (e.g. `test:1-2`, `log:raw`) are legal on POSIX; without this the
53
+ * strict splitter peels the tail and both `read` and `grep` refuse to open the
54
+ * real file (issue #4618). The literal wins on a confirmed `lstat`, and also
55
+ * on `"unknown"` (`EACCES` on a parent, transient I/O), so an unreachable
56
+ * literal is never silently reinterpreted as `path + selector`. Only a
57
+ * definitive `ENOENT`/`ENOTDIR` falls back to the strict split.
58
+ */
59
+ export declare function splitPathAndSelPreferringLiteral(rawPath: string, cwd: string): Promise<{
60
+ path: string;
61
+ sel?: string;
62
+ }>;
39
63
  /**
40
64
  * Variant of {@link splitPathAndSel} for internal URLs (`scheme://...`).
41
65
  *
@@ -7,6 +7,7 @@ import { type TruncationResult } from "../session/streaming-output.js";
7
7
  import { type OutputMeta } from "./output-meta.js";
8
8
  declare const readSchema: import("arktype/internal/variants/object.ts").ObjectType<{
9
9
  path: string;
10
+ selector?: string | undefined;
10
11
  }, {}>;
11
12
  export type ReadToolInput = typeof readSchema.infer;
12
13
  export interface ReadToolDetails {
@@ -59,6 +60,7 @@ export declare class ReadTool implements AgentTool<typeof readSchema, ReadToolDe
59
60
  readonly description: string;
60
61
  readonly parameters: import("arktype/internal/variants/object.ts").ObjectType<{
61
62
  path: string;
63
+ selector?: string | undefined;
62
64
  }, {}>;
63
65
  readonly strict = true;
64
66
  constructor(session: ToolSession);
@@ -67,6 +69,7 @@ export declare class ReadTool implements AgentTool<typeof readSchema, ReadToolDe
67
69
  interface ReadRenderArgs {
68
70
  path?: unknown;
69
71
  file_path?: unknown;
72
+ selector?: unknown;
70
73
  sel?: string;
71
74
  offset?: number;
72
75
  limit?: number;
@@ -6,6 +6,14 @@
6
6
  import type { Component } from "@oh-my-pi/pi-tui";
7
7
  import type { RenderResultOptions } from "../extensibility/custom-tools/types.js";
8
8
  import type { Theme } from "../modes/theme/theme.js";
9
+ /**
10
+ * Per-renderer opt-in for a full viewport replay when the first result
11
+ * replaces a painted pending-call render. A predicate receives the painted
12
+ * call args and render options so the repaint stays scoped to the pending
13
+ * shapes that actually re-anchor (an over-eager replay wipes native
14
+ * scrollback on direct terminals).
15
+ */
16
+ export type FirstResultViewportRepaint = boolean | ((args: unknown, options: RenderResultOptions) => boolean);
9
17
  export type ToolRenderer = {
10
18
  renderCall: (args: unknown, options: RenderResultOptions, theme: Theme) => Component;
11
19
  renderResult: (result: {
@@ -33,12 +41,11 @@ export type ToolRenderer = {
33
41
  */
34
42
  animatedPartialResult?: boolean | ((args: unknown) => boolean);
35
43
  /**
36
- * Whether replacing a streamed pending placeholder with the first result
37
- * requires a full viewport repaint. Use for merged renderers whose pending
38
- * streamed args may have committed placeholder rows that the result render
39
- * re-anchors instead of preserving.
44
+ * Whether replacing a pending call render with the first result requires a
45
+ * full viewport repaint. Use for merged renderers whose pending rows can be
46
+ * re-anchored instead of preserved by the result render.
40
47
  */
41
- forceFirstResultViewportRepaint?: boolean;
48
+ forceFirstResultViewportRepaint?: FirstResultViewportRepaint;
42
49
  /**
43
50
  * Whether settling a provisional partial result into the final render requires
44
51
  * a full viewport repaint. Use when the result renderer changes chrome or