@oh-my-pi/pi-coding-agent 17.2.1 → 17.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (114) hide show
  1. package/CHANGELOG.md +47 -0
  2. package/dist/{CHANGELOG-dj46zzrm.md → CHANGELOG-xfpkakrn.md} +47 -0
  3. package/dist/cli.js +3891 -3885
  4. package/dist/types/config/keybindings.d.ts +6 -1
  5. package/dist/types/config/settings-schema.d.ts +16 -5
  6. package/dist/types/edit/hashline/block-resolver.d.ts +5 -5
  7. package/dist/types/edit/hashline/diff.d.ts +4 -4
  8. package/dist/types/eval/executor-base.d.ts +27 -0
  9. package/dist/types/eval/js/context-manager.d.ts +7 -0
  10. package/dist/types/eval/js/executor.d.ts +2 -0
  11. package/dist/types/extensibility/extensions/runner.d.ts +64 -5
  12. package/dist/types/extensibility/extensions/types.d.ts +15 -0
  13. package/dist/types/extensibility/extensions/wrapper.d.ts +1 -1
  14. package/dist/types/extensibility/legacy-pi-coding-agent-shim.d.ts +1 -1
  15. package/dist/types/live/visualizer.d.ts +3 -1
  16. package/dist/types/modes/acp/acp-agent.d.ts +3 -3
  17. package/dist/types/modes/components/keybinding-hints.d.ts +1 -1
  18. package/dist/types/modes/controllers/mcp-command-controller.d.ts +13 -0
  19. package/dist/types/modes/interactive-mode.d.ts +1 -0
  20. package/dist/types/modes/theme/theme.d.ts +1 -1
  21. package/dist/types/modes/types.d.ts +2 -0
  22. package/dist/types/secrets/index.d.ts +22 -0
  23. package/dist/types/secrets/obfuscator.d.ts +1 -1
  24. package/dist/types/session/agent-session-types.d.ts +4 -0
  25. package/dist/types/session/agent-session.d.ts +9 -0
  26. package/dist/types/session/codex-auto-reset.d.ts +182 -64
  27. package/dist/types/session/session-storage.d.ts +5 -2
  28. package/dist/types/session/session-tools.d.ts +2 -1
  29. package/dist/types/session/turn-recovery.d.ts +7 -1
  30. package/dist/types/system-prompt.d.ts +8 -0
  31. package/dist/types/task/executor.d.ts +27 -0
  32. package/dist/types/task/persisted-revive.d.ts +7 -0
  33. package/dist/types/tools/bash-interceptor.d.ts +1 -1
  34. package/dist/types/tools/browser/attach.d.ts +9 -1
  35. package/dist/types/tools/browser/launch.d.ts +20 -1
  36. package/dist/types/tools/browser/registry.d.ts +2 -0
  37. package/dist/types/tools/browser/tab-protocol.d.ts +8 -0
  38. package/dist/types/tools/browser/tab-supervisor.d.ts +1 -0
  39. package/dist/types/tools/browser/tab-worker.d.ts +3 -1
  40. package/dist/types/tools/shell-tokenize.d.ts +11 -0
  41. package/dist/types/utils/image-loading.d.ts +2 -0
  42. package/dist/types/web/search/providers/duckduckgo.d.ts +9 -0
  43. package/dist/types/web/search/types.d.ts +2 -2
  44. package/package.json +12 -12
  45. package/src/commit/agentic/index.ts +2 -1
  46. package/src/commit/pipeline.ts +3 -2
  47. package/src/config/keybindings.ts +6 -1
  48. package/src/config/settings-schema.ts +16 -3
  49. package/src/edit/hashline/block-resolver.ts +5 -5
  50. package/src/edit/hashline/diff.ts +22 -15
  51. package/src/edit/hashline/execute.ts +14 -13
  52. package/src/edit/renderer.ts +3 -3
  53. package/src/eval/executor-base.ts +39 -0
  54. package/src/eval/jl/executor.ts +13 -2
  55. package/src/eval/js/context-manager.ts +97 -14
  56. package/src/eval/js/executor.ts +3 -0
  57. package/src/eval/js/index.ts +1 -0
  58. package/src/eval/py/executor.ts +55 -15
  59. package/src/eval/rb/executor.ts +8 -1
  60. package/src/extensibility/extensions/runner.ts +121 -4
  61. package/src/extensibility/extensions/types.ts +15 -0
  62. package/src/extensibility/extensions/wrapper.ts +19 -2
  63. package/src/extensibility/legacy-pi-coding-agent-shim.ts +5 -5
  64. package/src/live/visualizer.ts +8 -1
  65. package/src/lsp/index.ts +51 -11
  66. package/src/main.ts +3 -0
  67. package/src/modes/acp/acp-agent.ts +16 -5
  68. package/src/modes/components/assistant-message.ts +5 -10
  69. package/src/modes/components/custom-editor.ts +1 -1
  70. package/src/modes/components/keybinding-hints.ts +4 -13
  71. package/src/modes/components/status-line/segments.ts +4 -5
  72. package/src/modes/components/tool-execution.ts +4 -5
  73. package/src/modes/controllers/input-controller.ts +18 -40
  74. package/src/modes/controllers/live-command-controller.ts +1 -0
  75. package/src/modes/controllers/mcp-command-controller.ts +28 -11
  76. package/src/modes/interactive-mode.ts +59 -2
  77. package/src/modes/theme/theme.ts +13 -6
  78. package/src/modes/types.ts +2 -0
  79. package/src/modes/utils/hotkeys-markdown.ts +1 -0
  80. package/src/prompts/system/plan-mode-active.md +5 -5
  81. package/src/sdk.ts +47 -16
  82. package/src/secrets/index.ts +83 -3
  83. package/src/secrets/obfuscator.ts +70 -15
  84. package/src/session/agent-session-types.ts +7 -1
  85. package/src/session/agent-session.ts +393 -112
  86. package/src/session/codex-auto-reset.ts +594 -123
  87. package/src/session/eval-runner.ts +2 -0
  88. package/src/session/messages.ts +1 -1
  89. package/src/session/session-maintenance.ts +48 -1
  90. package/src/session/session-manager.ts +4 -3
  91. package/src/session/session-stats.ts +14 -3
  92. package/src/session/session-storage.ts +47 -15
  93. package/src/session/session-tools.ts +30 -2
  94. package/src/session/turn-recovery.ts +15 -2
  95. package/src/slash-commands/builtin-registry.ts +21 -15
  96. package/src/slash-commands/helpers/reset-usage.ts +2 -0
  97. package/src/system-prompt.ts +13 -1
  98. package/src/task/executor.ts +168 -15
  99. package/src/task/persisted-revive.ts +26 -1
  100. package/src/telemetry-export.ts +8 -4
  101. package/src/tools/bash-interceptor.ts +85 -8
  102. package/src/tools/bash.ts +1 -1
  103. package/src/tools/browser/attach.ts +35 -10
  104. package/src/tools/browser/launch.ts +60 -11
  105. package/src/tools/browser/registry.ts +18 -2
  106. package/src/tools/browser/tab-protocol.ts +8 -0
  107. package/src/tools/browser/tab-supervisor.ts +31 -4
  108. package/src/tools/browser/tab-worker.ts +32 -2
  109. package/src/tools/output-meta.ts +16 -1
  110. package/src/tools/shell-tokenize.ts +101 -0
  111. package/src/utils/image-loading.ts +8 -3
  112. package/src/utils/shell-snapshot.ts +31 -21
  113. package/src/web/search/providers/duckduckgo.ts +183 -15
  114. package/src/web/search/types.ts +6 -1
@@ -40,6 +40,7 @@ interface AppKeybindings {
40
40
  "app.plan.toggle": true;
41
41
  "app.history.search": true;
42
42
  "app.stt.toggle": true;
43
+ "app.live.toggle": true;
43
44
  }
44
45
  export type AppKeybinding = keyof AppKeybindings;
45
46
  declare module "@oh-my-pi/pi-tui" {
@@ -195,7 +196,7 @@ export declare const KEYBINDINGS: {
195
196
  readonly description: "Suspend application";
196
197
  };
197
198
  readonly "app.display.reset": {
198
- readonly defaultKeys: "ctrl+l";
199
+ readonly defaultKeys: "alt+l";
199
200
  readonly description: "Reset terminal display";
200
201
  };
201
202
  readonly "app.thinking.cycle": {
@@ -322,6 +323,10 @@ export declare const KEYBINDINGS: {
322
323
  readonly defaultKeys: [];
323
324
  readonly description: "Toggle speech-to-text (default gesture: hold Space)";
324
325
  };
326
+ readonly "app.live.toggle": {
327
+ readonly defaultKeys: "ctrl+l";
328
+ readonly description: "Start or stop live voice mode (/live)";
329
+ };
325
330
  };
326
331
  /** Controls inherited keybinding lookup when creating a manager for a named profile. */
327
332
  export interface KeybindingsCreateOptions {
@@ -5006,7 +5006,7 @@ export declare const SETTINGS_SCHEMA: {
5006
5006
  } | {
5007
5007
  readonly value: "xai";
5008
5008
  readonly label: "xAI";
5009
- readonly description: "Grok web search via xAI Responses API (requires XAI_API_KEY)";
5009
+ readonly description: "Grok web search via xAI Responses API (uses SuperGrok/X Premium+ OAuth via /login xai-oauth, or XAI_API_KEY)";
5010
5010
  } | {
5011
5011
  readonly value: "zai";
5012
5012
  readonly label: "Z.AI";
@@ -5110,7 +5110,7 @@ export declare const SETTINGS_SCHEMA: {
5110
5110
  } | {
5111
5111
  readonly value: "xai";
5112
5112
  readonly label: "xAI";
5113
- readonly description: "Grok web search via xAI Responses API (requires XAI_API_KEY)";
5113
+ readonly description: "Grok web search via xAI Responses API (uses SuperGrok/X Premium+ OAuth via /login xai-oauth, or XAI_API_KEY)";
5114
5114
  } | {
5115
5115
  readonly value: "zai";
5116
5116
  readonly label: "Z.AI";
@@ -5856,7 +5856,7 @@ export declare const SETTINGS_SCHEMA: {
5856
5856
  readonly tab: "providers";
5857
5857
  readonly group: "Services";
5858
5858
  readonly label: "Codex Auto-Redeem Saved Resets";
5859
- readonly description: "When a turn is blocked by the Codex weekly limit on the active account and no other account is available, run the conservative saved-reset check. unset asks before spending the first eligible reset, yes spends eligible resets without prompting, and no disables the check entirely. Requires retries enabled.";
5859
+ readonly description: "Spend saved Codex rate-limit resets automatically: restore an account blocked by an exhausted 5h or weekly window when a turn is stuck and no other account can take over, and salvage credits that are about to expire. unset asks before the first spend, yes spends without prompting, and no disables both checks.";
5860
5860
  readonly options: readonly [{
5861
5861
  readonly value: "unset";
5862
5862
  readonly label: "Unset";
@@ -5879,7 +5879,7 @@ export declare const SETTINGS_SCHEMA: {
5879
5879
  readonly tab: "providers";
5880
5880
  readonly group: "Services";
5881
5881
  readonly label: "Codex Auto-Redeem Min Block";
5882
- readonly description: "Only auto-redeem when the natural weekly reset is at least this many minutes away (don't spend a ~30-day credit to save a short wait).";
5882
+ readonly description: "Only auto-redeem when the natural unblock — the latest reset among the exhausted 5h/weekly windows — is at least this many minutes away (don't spend a scarce credit to save a short wait). Raise it (e.g. 360) to ignore 5h-only blocks.";
5883
5883
  };
5884
5884
  };
5885
5885
  readonly "codexResets.keepCredits": {
@@ -5889,7 +5889,17 @@ export declare const SETTINGS_SCHEMA: {
5889
5889
  readonly tab: "providers";
5890
5890
  readonly group: "Services";
5891
5891
  readonly label: "Codex Auto-Redeem Reserve";
5892
- readonly description: "Never auto-spend below this many saved resets (0 = the last credit may be spent automatically).";
5892
+ readonly description: "Never auto-spend below this many saved resets (0 = the last credit may be spent automatically). Credits about to expire are exempt — a reserved credit that expires preserves nothing.";
5893
+ };
5894
+ };
5895
+ readonly "codexResets.salvageHorizonHours": {
5896
+ readonly type: "number";
5897
+ readonly default: 12;
5898
+ readonly ui: {
5899
+ readonly tab: "providers";
5900
+ readonly group: "Services";
5901
+ readonly label: "Codex Reset Salvage Horizon";
5902
+ readonly description: "Spend a saved Codex reset automatically when it would otherwise expire within this many hours and either chat window (5h or weekly) has meaningful usage to restore (0 disables expiry salvage).";
5893
5903
  };
5894
5904
  };
5895
5905
  readonly "provider.appendOnlyContext": {
@@ -6319,6 +6329,7 @@ export interface CodexResetsSettings {
6319
6329
  autoRedeem: CodexAutoRedeemMode;
6320
6330
  minBlockedMinutes: number;
6321
6331
  keepCredits: number;
6332
+ salvageHorizonHours: number;
6322
6333
  }
6323
6334
  export interface GcSettings {
6324
6335
  blobs: boolean;
@@ -1,9 +1,9 @@
1
1
  /**
2
- * Tree-sitter-backed {@link BlockResolver} for the hashline block replace
3
- * operator. Bridges the pure hashline seam to the native `blockRangeAt`
4
- * primitive in `@oh-my-pi/pi-natives`, which infers the language from the file
5
- * path and returns the 1-indexed line span of the syntactic block beginning on
6
- * the requested line (or `null` when none can be resolved).
2
+ * Tree-sitter-backed {@link BlockResolver} for the hashline `N*` locator.
3
+ * Bridges the pure hashline seam to the native `blockRangeAt` primitive in
4
+ * `@oh-my-pi/pi-natives`, which infers the language from the file path and
5
+ * returns the 1-indexed line span of the syntactic block beginning on the
6
+ * requested line (or `null` when none can be resolved).
7
7
  */
8
8
  import type { BlockResolver } from "@oh-my-pi/hashline";
9
9
  export declare const nativeBlockResolver: BlockResolver;
@@ -14,10 +14,10 @@ export interface HashlineDiffOptions {
14
14
  skipHashValidation?: boolean;
15
15
  /**
16
16
  * Clipboard register shared across the sections of one patch preview.
17
- * `CUT` in an earlier section feeds `PASTE` in a later one, so the preview
18
- * matches apply. Multi-section previews MUST thread one register through
19
- * sections in patch order; omitted, each section gets a
20
- * private register (same-file cut/paste still previews correctly).
17
+ * `CUT` in an earlier section feeds a register-backed `PUT` in a later one,
18
+ * so the preview matches apply. Multi-section previews MUST thread one
19
+ * register through sections in patch order; omitted, each section gets a
20
+ * private register (same-file cut/put still previews correctly).
21
21
  */
22
22
  clipboard?: Clipboard;
23
23
  }
@@ -90,6 +90,33 @@ export declare function attachSessionOwner(session: {
90
90
  ownerIds: Set<string>;
91
91
  hasFallbackOwner: boolean;
92
92
  }, sessionId: string, ownerId: string | undefined): void;
93
+ /** Owner registry shared by every language's live/starting session records. */
94
+ export interface SessionOwners {
95
+ ownerIds: Set<string>;
96
+ hasFallbackOwner: boolean;
97
+ }
98
+ /**
99
+ * Resolve the session key an owner's eval cell runs on, forking `reset` away
100
+ * from shared kernels.
101
+ *
102
+ * Eval sessions are shared across agents by design (subagents inherit the
103
+ * parent's eval session id), so honoring `reset` on a co-owned kernel would
104
+ * destroy every other agent's state — including cells executing at that
105
+ * moment. When the requester does not exclusively own the live base session,
106
+ * its reset resolves to a deterministic per-owner fork key: the requester
107
+ * starts a fresh private kernel while co-owners keep the shared one. Once
108
+ * forked, the owner keeps resolving to its fork, and per-owner dispose reaps
109
+ * the fork since the requester is its only registered owner.
110
+ */
111
+ export declare function resolveOwnerScopedSessionKey(options: {
112
+ baseKey: string;
113
+ ownerId: string | undefined;
114
+ reset: boolean;
115
+ /** True when a live or starting session exists under `key`. */
116
+ hasSession: (key: string) => boolean;
117
+ /** Owner registry for the session under `key`, when inspectable. */
118
+ getOwners: (key: string) => SessionOwners | undefined;
119
+ }): string;
93
120
  export interface ExecuteWithKernelBaseParams<TOptions extends KernelExecutorBaseOptions, TEnv extends KernelEnvPatch = Record<string, string | null>> {
94
121
  kernel: GenericKernel<TEnv>;
95
122
  code: string;
@@ -18,6 +18,8 @@ export declare function setJsEvalWorkerThreadForTests(enabled: boolean): boolean
18
18
  export declare function executeInVmContext(options: {
19
19
  sessionKey: string;
20
20
  sessionId: string;
21
+ /** Logical owner identifier; scopes `reset` on shared contexts and retained-worker cleanup. */
22
+ ownerId?: string;
21
23
  cwd: string;
22
24
  session: ToolSession;
23
25
  localRoots?: Record<string, string>;
@@ -31,6 +33,11 @@ export declare function executeInVmContext(options: {
31
33
  }>;
32
34
  export declare function resetVmContext(sessionKey: string): Promise<void>;
33
35
  export declare function disposeAllVmContexts(): Promise<void>;
36
+ /**
37
+ * Shut down retained JS contexts owned solely by `ownerId` (e.g. a subagent's
38
+ * private fork); shared contexts just drop the owner registration.
39
+ */
40
+ export declare function disposeVmContextsByOwner(ownerId: string): Promise<void>;
34
41
  /**
35
42
  * Smoke probe: spawn the JS evaluator through the worker-host entry and prove
36
43
  * it answers the `init` handshake in a real isolated subprocess (not the inline
@@ -15,6 +15,8 @@ export interface JsExecutorOptions {
15
15
  onStatus?: (event: JsStatusEvent) => void;
16
16
  signal?: AbortSignal;
17
17
  sessionId: string;
18
+ /** Logical owner identifier; scopes `reset` on shared contexts and retained-worker cleanup. */
19
+ kernelOwnerId?: string;
18
20
  reset?: boolean;
19
21
  sessionFile?: string;
20
22
  artifactPath?: string;
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Extension runner - executes extensions and manages their lifecycle.
3
3
  */
4
- import type { AgentMessage } from "@oh-my-pi/pi-agent-core";
4
+ import type { AgentMessage, AgentTool, AgentToolContext, AgentToolResult, AgentToolUpdateCallback } from "@oh-my-pi/pi-agent-core";
5
5
  import type { CredentialDisabledEvent, ImageContent, Model, ProviderResponseMetadata } from "@oh-my-pi/pi-ai";
6
6
  import type { KeyId } from "@oh-my-pi/pi-tui";
7
7
  import type { ModelRegistry } from "../../config/model-registry.js";
@@ -65,7 +65,6 @@ export declare class ExtensionRunner {
65
65
  #private;
66
66
  private readonly extensions;
67
67
  private readonly runtime;
68
- private readonly cwd;
69
68
  private readonly sessionManager;
70
69
  private readonly modelRegistry;
71
70
  private readonly settings?;
@@ -74,7 +73,51 @@ export declare class ExtensionRunner {
74
73
  markToolCallEmitted(toolCallId: string, toolName: string): void;
75
74
  /** Consumes a {@link markToolCallEmitted} marker; true when the loop already emitted. */
76
75
  consumeToolCallEmitted(toolCallId: string, toolName: string): boolean;
77
- constructor(extensions: Extension[], runtime: ExtensionRuntime, cwd: string, sessionManager: SessionManager, modelRegistry: ModelRegistry, getMemory?: () => MemoryRuntimeContext | undefined, settings?: Settings | undefined, localProtocolOptions?: LocalProtocolOptions | undefined, getAsyncJobSnapshot?: () => AsyncJobSnapshot | null);
76
+ /** Wires the native-tool resolver used by {@link invokeNativeTool}. */
77
+ setNativeToolResolver(resolve: (name: string) => {
78
+ tool: AgentTool;
79
+ makeContext: () => AgentToolContext;
80
+ } | undefined): void;
81
+ /** Whether a native built-in of `name` is available to delegate to. */
82
+ hasNativeTool(name: string): boolean;
83
+ /**
84
+ * Run the native built-in of `name` with `params` and return its result — the delegation target
85
+ * of a same-tool `ctx.invokeTool`. Calls the unwrapped native `execute` directly with the loop's
86
+ * ordinary tool context, so it inherits the caller's already-granted approval (the caller is the
87
+ * same tool) rather than re-running the gate. `depth` guards a wrapper that recurses into itself;
88
+ * it is per call chain (threaded from the caller), not session-global, so concurrent independent
89
+ * delegations do not interfere.
90
+ */
91
+ invokeNativeTool<TDetails = unknown>(name: string, params: Record<string, unknown>, options?: {
92
+ signal?: AbortSignal;
93
+ onUpdate?: AgentToolUpdateCallback<TDetails>;
94
+ depth?: number;
95
+ /**
96
+ * The caller tool's own context. Reused for the native call so metadata the native tool
97
+ * reads — `toolCall` (write/edit LSP batch flushing) and provider metadata /
98
+ * `providerSafetyApproved` (computer) — is preserved. Falls back to a fresh session tool
99
+ * context only when the caller had none.
100
+ */
101
+ callerContext?: AgentToolContext;
102
+ }): Promise<AgentToolResult<TDetails>>;
103
+ constructor(extensions: Extension[], runtime: ExtensionRuntime,
104
+ /** Ignored: `cwd` is always read live via the `cwd` getter below, not cached here. */
105
+ _initialCwd: string, sessionManager: SessionManager, modelRegistry: ModelRegistry, getMemory?: () => MemoryRuntimeContext | undefined, settings?: Settings | undefined, localProtocolOptions?: LocalProtocolOptions | undefined, getAsyncJobSnapshot?: () => AsyncJobSnapshot | null);
106
+ /**
107
+ * Live session directory, not a session-start snapshot: `/move`
108
+ * (`SessionManager.moveTo()`) relocates the owning session by updating
109
+ * `sessionManager`'s own `#cwd`, not a process-global. Reading it here
110
+ * via the getter — instead of caching the constructor-time value in a
111
+ * field — keeps every `ExtensionContext` built below in sync with this
112
+ * session's actual, current directory. Deliberately `sessionManager.getCwd()`
113
+ * rather than `getProjectDir()`: the latter is a single process-wide value
114
+ * that only the interactive TUI's `/move` handler happens to also update
115
+ * (`InteractiveModeContext#applyCwdChange`) — an SDK/ACP host running
116
+ * several concurrent sessions each with their own `cwd` (see
117
+ * `CreateAgentSessionOptions.cwd`) must never have one session's move
118
+ * leak into another's `ctx.cwd` by reading a shared global.
119
+ */
120
+ get cwd(): string;
78
121
  initialize(actions: ExtensionActions, contextActions: ExtensionContextActions, commandContextActions?: ExtensionCommandContextActions, uiContext?: ExtensionUIContext): void;
79
122
  /**
80
123
  * Forward a `credential_disabled` event from `AuthStorage` to extension handlers.
@@ -137,8 +180,24 @@ export declare class ExtensionRunner {
137
180
  path: string;
138
181
  }>;
139
182
  getCommand(name: string): RegisteredCommand | undefined;
140
- /** Creates an extension context, optionally scoped to a provider request model. */
141
- createContext(model?: Model): ExtensionContext;
183
+ /**
184
+ * Creates an extension context, optionally scoped to a provider request model.
185
+ *
186
+ * `delegation` wires the same-tool `ctx.invokeTool` for a re-registered built-in: when `toolName`
187
+ * names an existing native built-in, the context carries an `invokeTool` that runs it (see
188
+ * {@link invokeNativeTool}). The rest inherits the wrapper's own call so a bare
189
+ * `ctx.invokeTool(params)` behaves like the outer call — `context` preserves `toolCall`/provider
190
+ * metadata, `signal`/`onUpdate` default to the wrapper's own channels so aborting the outer tool
191
+ * call stops the native one and native progress still streams, and `depth` bounds recursion per
192
+ * call chain. Explicit options passed to `invokeTool` override the inherited `signal`/`onUpdate`.
193
+ */
194
+ createContext(model?: Model, delegation?: {
195
+ toolName: string;
196
+ depth?: number;
197
+ context?: AgentToolContext;
198
+ signal?: AbortSignal;
199
+ onUpdate?: AgentToolUpdateCallback;
200
+ }): ExtensionContext;
142
201
  /**
143
202
  * Request a graceful shutdown. Called by extension tools and event handlers.
144
203
  */
@@ -325,6 +325,21 @@ export interface ExtensionContext {
325
325
  setTimeout(callback: (...args: unknown[]) => void, ms?: number, ...args: unknown[]): Timer;
326
326
  /** Clear a timer scheduled via {@link setInterval} or {@link setTimeout}. */
327
327
  clearTimer(timer: Timer): void;
328
+ /**
329
+ * Run the NATIVE built-in implementation of the tool this handler re-registered, with `params`,
330
+ * and return its result. Lets a tool that re-registers a built-in (e.g. wrapping `write` to add
331
+ * logging or a policy check) delegate to the original instead of reimplementing it — the native
332
+ * tool performs its own side effects and internal bookkeeping.
333
+ *
334
+ * Delegation is same-tool only: it invokes the built-in of the SAME name as the registering tool,
335
+ * never an arbitrary target, so it cannot escalate past the approval already granted for this
336
+ * call. Present only when a native built-in of that name exists (undefined otherwise, e.g. for a
337
+ * net-new tool that shadows no built-in). Recursion is depth-guarded per call chain.
338
+ */
339
+ invokeTool?<TDetails = unknown>(params: Record<string, unknown>, options?: {
340
+ signal?: AbortSignal;
341
+ onUpdate?: AgentToolUpdateCallback<TDetails>;
342
+ }): Promise<AgentToolResult<TDetails>>;
328
343
  }
329
344
  /**
330
345
  * Extended context for command handlers.
@@ -20,7 +20,7 @@ export declare class RegisteredToolAdapter implements AgentTool<any, any, any> {
20
20
  renderResult?: (result: any, options: any, theme: any, args?: any) => any;
21
21
  readonly loadMode: ToolLoadMode;
22
22
  constructor(registeredTool: RegisteredTool, runner: ExtensionRunner);
23
- execute(toolCallId: string, params: any, signal?: AbortSignal, onUpdate?: AgentToolUpdateCallback<any>, _context?: AgentToolContext): Promise<AgentToolResult<unknown, unknown>>;
23
+ execute(toolCallId: string, params: any, signal?: AbortSignal, onUpdate?: AgentToolUpdateCallback<any>, context?: AgentToolContext): Promise<AgentToolResult<unknown, unknown>>;
24
24
  }
25
25
  /**
26
26
  * Backward-compatible factory function wrapper.
@@ -398,7 +398,7 @@ export { getProjectDir } from "@oh-my-pi/pi-utils";
398
398
  * canonical helper.
399
399
  */
400
400
  export declare function getPackageDir(): string;
401
- export { estimateTokens } from "@oh-my-pi/pi-agent-core/compaction";
401
+ export { compact, estimateTokens } from "@oh-my-pi/pi-agent-core/compaction";
402
402
  export { CONFIG_DIR_NAME } from "@oh-my-pi/pi-utils";
403
403
  export { parseArgs } from "../cli/args.js";
404
404
  export * from "../index.js";
@@ -1,10 +1,12 @@
1
- import { type Component } from "@oh-my-pi/pi-tui";
1
+ import { type Component, type KeyId } from "@oh-my-pi/pi-tui";
2
2
  /** Distinct states of a realtime call connection. */
3
3
  export type LivePhase = "connecting" | "listening" | "working" | "speaking" | "muted" | "error";
4
4
  /** Configuration callbacks for user interactions in the visualizer. */
5
5
  export interface LiveVisualizerOptions {
6
6
  onStop(): void;
7
7
  onToggleMute(): void;
8
+ /** Configured `app.live.toggle` chords that also end the call (Ctrl+L by default). */
9
+ stopKeys?: readonly KeyId[];
8
10
  }
9
11
  /** A compact, fixed-height terminal component for displaying a realtime call. */
10
12
  export declare class LiveVisualizer implements Component {
@@ -23,9 +23,9 @@ type CreateAcpSession = (cwd: string) => Promise<AgentSession>;
23
23
  * symmetric with every other `sessionUpdate` call in this file
24
24
  * (`record.session.sessionId` is always evaluated at emit time).
25
25
  *
26
- * The non-elicitation surface (custom components, editor, theming,
27
- * terminal input) remains stubbed — ACP clients render those themselves
28
- * or not at all. Capability gating respects the client's `initialize`
26
+ * The non-elicitation surface (custom components, theming, terminal
27
+ * input) remains stubbed — ACP clients render those themselves or not
28
+ * at all. Capability gating respects the client's `initialize`
29
29
  * advertisement.
30
30
  */
31
31
  export declare function createAcpExtensionUiContext(connection: AgentSideConnection, getSessionId: () => string, clientCapabilities: ClientCapabilities | undefined): ExtensionUIContext;
@@ -2,7 +2,7 @@
2
2
  * Utilities for formatting keybinding hints in the UI.
3
3
  */
4
4
  import { type Keybinding } from "@oh-my-pi/pi-tui";
5
- import type { AppKeybinding, KeybindingsManager } from "../../config/keybindings.js";
5
+ import { type AppKeybinding, type KeybindingsManager } from "../../config/keybindings.js";
6
6
  /**
7
7
  * Get display string for an editor action.
8
8
  */
@@ -69,4 +69,17 @@ export declare class MCPCommandController {
69
69
  handle(text: string): Promise<void>;
70
70
  /** Reauthorize a server after a tool-level OAuth challenge. */
71
71
  handleMCPAuthChallenge(name: string, challenge: MCPAuthChallenge): Promise<MCPServerConfig | undefined>;
72
+ /**
73
+ * Reconnect every configured MCP server and rebind the session's MCP tools.
74
+ *
75
+ * Disconnects all live connections, rediscovers `.mcp.json` configs, and
76
+ * calls `session.refreshMCPTools(...)` so config edits take effect without a
77
+ * restart. Public because `/reload-plugins` reuses it alongside `/mcp reload`
78
+ * and the config-mutation flows in this controller.
79
+ *
80
+ * Discovery options are derived from settings so the reload honors the same
81
+ * opt-outs as startup — notably `mcp.enableProjectConfig: false`, which must
82
+ * keep project `.mcp.json` servers from being started on reload.
83
+ */
84
+ reloadServers(): Promise<void>;
72
85
  }
@@ -382,6 +382,7 @@ export declare class InteractiveMode implements InteractiveModeContext {
382
382
  handleCtrlC(): void;
383
383
  handleCtrlD(): void;
384
384
  handleCtrlZ(): void;
385
+ resetDisplayAfterAppearanceRefresh(): void;
385
386
  handleDequeue(): void;
386
387
  handleImagePaste(): Promise<boolean>;
387
388
  /** Queue slash-command input behind the active turn. */
@@ -292,7 +292,7 @@ export declare function setAutoThemeMapping(mode: "dark" | "light", themeName: s
292
292
  * The terminal layer queries OSC 11 (background color) and computes luminance;
293
293
  * Mode 2031 notifications trigger re-queries rather than providing the value directly.
294
294
  */
295
- export declare function onTerminalAppearanceChange(mode: "dark" | "light"): void;
295
+ export declare function onTerminalAppearanceChange(mode: "dark" | "light", event?: ThemeChangeEvent): void;
296
296
  export declare function setThemeInstance(themeInstance: Theme): void;
297
297
  /**
298
298
  * Set the symbol preset override, recreating the theme with the new preset.
@@ -375,6 +375,8 @@ export interface InteractiveModeContext {
375
375
  handleCtrlC(): void;
376
376
  handleCtrlD(): void;
377
377
  handleCtrlZ(): void;
378
+ /** Re-query terminal appearance for an explicit display reset, then immediately replay the display. */
379
+ resetDisplayAfterAppearanceRefresh(): void;
378
380
  handleDequeue(): void;
379
381
  handleImagePaste(): Promise<boolean>;
380
382
  /** Queue a message for delivery only after the active agent turn would stop. */
@@ -12,6 +12,14 @@ import { type SecretEntry } from "./obfuscator.js";
12
12
  export declare function getSecretPlaceholderKey(keyDir?: string): Promise<string>;
13
13
  /** Return an existing placeholder key for redaction without creating a new key file. */
14
14
  export declare function getExistingSecretPlaceholderKey(keyDir?: string): Promise<string | undefined>;
15
+ /**
16
+ * Synchronous variant of `getSecretPlaceholderKey` for the lazy key provider
17
+ * `SecretObfuscator` invokes inside its synchronous `obfuscate()` path when a
18
+ * built-in credential-pattern entry first matches session content. Never
19
+ * throws: an unreadable or unwritable key file degrades to a process-ephemeral
20
+ * key (with a warning) instead of breaking the session.
21
+ */
22
+ export declare function getSecretPlaceholderKeySync(keyDir?: string): string;
15
23
  export { deobfuscateSessionContext, deobfuscateToolArguments, obfuscateMessages, obfuscateProviderContext, type SecretEntry, SecretObfuscator, secretEntriesNeedPlaceholderKey, secretEntryNeedsPlaceholderKey, } from "./obfuscator.js";
16
24
  /**
17
25
  * Load secrets from project-local and global secrets.yml files.
@@ -20,3 +28,17 @@ export { deobfuscateSessionContext, deobfuscateToolArguments, obfuscateMessages,
20
28
  export declare function loadSecrets(cwd: string, agentDir: string): Promise<SecretEntry[]>;
21
29
  /** Collect environment variable values that look like secrets. */
22
30
  export declare function collectEnvSecrets(): SecretEntry[];
31
+ /**
32
+ * Built-in entries covering credential-shaped tokens (GitHub/GitLab/OpenAI-style
33
+ * API keys) that are NOT configured via secrets.yml or the environment. Without
34
+ * these, such a token in a tool result falls through to pi-ai's irreversible
35
+ * provider-boundary redaction (`[openai_token_redacted]`); the model then echoes
36
+ * that placeholder into edit-tool `old_text`, which can never match the real
37
+ * bytes on disk (issue #6968). Routing the same shapes through the obfuscator
38
+ * mints reversible keyed placeholders that `deobfuscateToolArguments` restores
39
+ * before tool execution, keeping exact-match edits working while the credential
40
+ * bytes still never reach the provider. Unlike the pi-ai redaction there is no
41
+ * entropy gate here — a false positive only over-obfuscates, which stays
42
+ * transparent because the round trip is lossless.
43
+ */
44
+ export declare function builtinCredentialSecretEntries(): SecretEntry[];
@@ -86,7 +86,7 @@ export declare function secretEntriesNeedPlaceholderKey(entries: SecretEntry[]):
86
86
  export declare function stripPendingSecretPlaceholderSuffix(text: string): string;
87
87
  export declare class SecretObfuscator {
88
88
  #private;
89
- constructor(entries: SecretEntry[], key?: string);
89
+ constructor(entries: SecretEntry[], key?: string | (() => string));
90
90
  hasSecrets(): boolean;
91
91
  /** Obfuscate all secrets in text. Bidirectional placeholders for obfuscate mode, one-way for replace. */
92
92
  obfuscate(text: string, sharedRegexSecretValues?: ReadonlySet<string>): string;
@@ -17,6 +17,7 @@ import type { FileSlashCommand } from "../extensibility/slash-commands.js";
17
17
  import type { SecretObfuscator } from "../secrets/obfuscator.js";
18
18
  import type { ConfiguredThinkingLevel } from "../thinking.js";
19
19
  import type { XdevState } from "../tools/xdev.js";
20
+ import type { CodexAutoRedeemCoordinator } from "./codex-auto-reset.js";
20
21
  import type { SessionManager } from "./session-manager.js";
21
22
  /** Maximum time the interactive shutdown path waits for Mnemopi consolidation. */
22
23
  export declare const SHUTDOWN_CONSOLIDATE_BUDGET_MS = 1500;
@@ -148,6 +149,8 @@ export interface AgentSessionConfig {
148
149
  initialAdvisorCosts?: ReadonlyMap<string, number>;
149
150
  /** Prefer websocket transport for OpenAI Codex requests when supported. */
150
151
  preferWebsockets?: boolean;
152
+ /** Codex saved-reset coordinator; defaults to the process-wide singleton so concurrent sessions can't double-spend. Inject a fresh one in tests. */
153
+ codexResetCoordinator?: CodexAutoRedeemCoordinator;
151
154
  /** Provider payload hook used by the active session request path. */
152
155
  onPayload?: SimpleStreamOptions["onPayload"];
153
156
  /** Provider response hook used by the active session request path. */
@@ -161,6 +164,7 @@ export interface AgentSessionConfig {
161
164
  /** System prompt builder that can consider tool availability. */
162
165
  rebuildSystemPrompt?: (toolNames: string[], tools: Map<string, AgentTool>) => Promise<{
163
166
  systemPrompt: string[];
167
+ xdevCatalogNames?: readonly string[];
164
168
  }>;
165
169
  /** Local calendar date provider used by prompt-cache invalidation. */
166
170
  getLocalCalendarDate?: () => string;
@@ -540,6 +540,13 @@ export declare class AgentSession {
540
540
  get skillWarnings(): readonly SkillWarning[];
541
541
  getTodoPhases(): TodoPhase[];
542
542
  setTodoPhases(phases: TodoPhase[]): void;
543
+ /**
544
+ * Start automatic title generation when the session and input are eligible.
545
+ * Interactive and CLI-bootstrap submissions share this gate so every first
546
+ * user message persists titles with the same environment, signal, and local
547
+ * extension-command policy.
548
+ */
549
+ maybeStartTitleGeneration(firstMessage: string, onStart?: () => void): void;
543
550
  /**
544
551
  * Generate an automatic session title tied to this session's lifecycle.
545
552
  * Input and replan callers share the signal so disposal cancels provider and
@@ -744,6 +751,8 @@ export declare class AgentSession {
744
751
  deliverIrcMessage(msg: IrcMessage, opts?: {
745
752
  expectsReply?: boolean;
746
753
  }): Promise<"injected" | "woken">;
754
+ /** Installs task-executor monitoring around autonomous IRC wake turns. */
755
+ setIrcWakeTurnObserver(observer: ((records: CustomMessage[]) => ((error?: unknown) => void | Promise<void>) | undefined) | undefined): void;
747
756
  /** Emits an IRC relay observation for UI rendering without persisting it. */
748
757
  emitIrcRelayObservation(record: CustomMessage): void;
749
758
  /**