@oh-my-pi/pi-coding-agent 16.5.0 → 16.5.1

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 (121) hide show
  1. package/CHANGELOG.md +26 -0
  2. package/dist/cli.js +3336 -3318
  3. package/dist/types/advisor/advise-tool.d.ts +12 -1
  4. package/dist/types/advisor/runtime.d.ts +41 -1
  5. package/dist/types/cli/args.d.ts +2 -0
  6. package/dist/types/cli/update-cli.d.ts +4 -1
  7. package/dist/types/cli/usage-cli.d.ts +3 -0
  8. package/dist/types/cli/usage-error.d.ts +4 -0
  9. package/dist/types/config/api-key-resolver.d.ts +2 -2
  10. package/dist/types/config/model-registry.d.ts +3 -3
  11. package/dist/types/config/model-resolver.d.ts +8 -1
  12. package/dist/types/config/models-config.d.ts +1 -1
  13. package/dist/types/eval/__tests__/process-entry-import.test.d.ts +1 -0
  14. package/dist/types/eval/bridge-timeout.d.ts +9 -1
  15. package/dist/types/eval/js/context-manager.d.ts +5 -3
  16. package/dist/types/eval/js/process-entry.d.ts +6 -0
  17. package/dist/types/eval/js/worker-core.d.ts +15 -1
  18. package/dist/types/eval/py/spawn-options.d.ts +10 -0
  19. package/dist/types/eval/py/tool-bridge.d.ts +1 -0
  20. package/dist/types/extensibility/custom-tools/types.d.ts +3 -0
  21. package/dist/types/extensibility/extensions/runner.d.ts +3 -1
  22. package/dist/types/extensibility/extensions/types.d.ts +3 -0
  23. package/dist/types/internal-urls/memory-protocol.d.ts +6 -7
  24. package/dist/types/main.d.ts +1 -0
  25. package/dist/types/modes/components/transcript-container.d.ts +3 -2
  26. package/dist/types/modes/magic-keyword-boundary.d.ts +9 -0
  27. package/dist/types/modes/orchestrate.d.ts +1 -1
  28. package/dist/types/modes/rpc/host-tools.d.ts +2 -0
  29. package/dist/types/modes/rpc/rpc-mode.d.ts +26 -6
  30. package/dist/types/modes/ultrathink.d.ts +1 -1
  31. package/dist/types/modes/utils/transcript-render-helpers.d.ts +12 -0
  32. package/dist/types/modes/workflow.d.ts +1 -1
  33. package/dist/types/session/agent-session.d.ts +6 -0
  34. package/dist/types/session/exit-diagnostics.d.ts +11 -0
  35. package/dist/types/slash-commands/helpers/active-oauth-account.d.ts +11 -0
  36. package/dist/types/subprocess/worker-client.d.ts +6 -0
  37. package/dist/types/tools/bash-skill-urls.d.ts +1 -0
  38. package/dist/types/web/search/provider.d.ts +10 -3
  39. package/dist/types/web/search/providers/codex.d.ts +5 -4
  40. package/package.json +12 -12
  41. package/src/advisor/__tests__/advisor.test.ts +830 -42
  42. package/src/advisor/advise-tool.ts +17 -1
  43. package/src/advisor/runtime.ts +288 -67
  44. package/src/autolearn/controller.ts +15 -3
  45. package/src/cli/args.ts +12 -0
  46. package/src/cli/auth-broker-cli.ts +30 -11
  47. package/src/cli/auth-gateway-cli.ts +5 -1
  48. package/src/cli/dry-balance-cli.ts +14 -4
  49. package/src/cli/flag-tables.ts +21 -7
  50. package/src/cli/update-cli.ts +62 -11
  51. package/src/cli/usage-cli.ts +58 -5
  52. package/src/cli/usage-error.ts +7 -0
  53. package/src/cli.ts +23 -1
  54. package/src/commands/acp.ts +11 -2
  55. package/src/commands/launch.ts +12 -3
  56. package/src/commands/token.ts +3 -1
  57. package/src/config/api-key-resolver.ts +12 -3
  58. package/src/config/config-file.ts +30 -12
  59. package/src/config/model-registry.ts +7 -7
  60. package/src/config/model-resolver.ts +21 -7
  61. package/src/config/models-config.ts +1 -1
  62. package/src/eval/__tests__/agent-bridge.test.ts +19 -14
  63. package/src/eval/__tests__/bridge-timeout.test.ts +106 -0
  64. package/src/eval/__tests__/js-context-manager.test.ts +158 -1
  65. package/src/eval/__tests__/kernel-spawn.test.ts +12 -0
  66. package/src/eval/__tests__/process-entry-import.test.ts +27 -0
  67. package/src/eval/agent-bridge.ts +121 -116
  68. package/src/eval/bridge-timeout.ts +20 -2
  69. package/src/eval/executor-base.ts +85 -7
  70. package/src/eval/jl/kernel.ts +2 -1
  71. package/src/eval/js/context-manager.ts +109 -32
  72. package/src/eval/js/process-entry.ts +27 -0
  73. package/src/eval/js/shared/runtime.ts +1 -1
  74. package/src/eval/js/worker-core.ts +70 -9
  75. package/src/eval/js/worker-entry.ts +1 -1
  76. package/src/eval/py/kernel.ts +2 -1
  77. package/src/eval/py/spawn-options.ts +13 -0
  78. package/src/eval/py/tool-bridge.ts +13 -14
  79. package/src/eval/rb/kernel.ts +2 -1
  80. package/src/extensibility/custom-tools/types.ts +3 -0
  81. package/src/extensibility/extensions/runner.ts +3 -0
  82. package/src/extensibility/extensions/types.ts +3 -0
  83. package/src/extensibility/plugins/manager.ts +21 -0
  84. package/src/internal-urls/memory-protocol.ts +13 -9
  85. package/src/lsp/client.ts +7 -1
  86. package/src/main.ts +29 -0
  87. package/src/mcp/tool-bridge.ts +57 -6
  88. package/src/modes/components/chat-transcript-builder.ts +22 -1
  89. package/src/modes/components/status-line/component.ts +10 -1
  90. package/src/modes/components/transcript-container.ts +110 -7
  91. package/src/modes/controllers/command-controller.ts +12 -4
  92. package/src/modes/controllers/event-controller.ts +80 -15
  93. package/src/modes/controllers/selector-controller.ts +15 -3
  94. package/src/modes/magic-keyword-boundary.ts +23 -0
  95. package/src/modes/orchestrate.ts +6 -5
  96. package/src/modes/print-mode.ts +9 -0
  97. package/src/modes/rpc/host-tools.ts +15 -0
  98. package/src/modes/rpc/rpc-mode.ts +123 -48
  99. package/src/modes/ultrathink.ts +6 -5
  100. package/src/modes/utils/transcript-render-helpers.ts +54 -0
  101. package/src/modes/utils/ui-helpers.ts +27 -1
  102. package/src/modes/workflow.ts +6 -5
  103. package/src/prompts/advisor/system.md +1 -0
  104. package/src/sdk.ts +33 -3
  105. package/src/session/agent-session.ts +239 -17
  106. package/src/session/exit-diagnostics.ts +108 -0
  107. package/src/session/streaming-output.ts +40 -12
  108. package/src/slash-commands/helpers/active-oauth-account.ts +22 -2
  109. package/src/slash-commands/helpers/logout.ts +23 -3
  110. package/src/slash-commands/helpers/usage-report.ts +14 -2
  111. package/src/subprocess/worker-client.ts +9 -2
  112. package/src/task/executor.ts +8 -0
  113. package/src/task/render.test.ts +36 -0
  114. package/src/task/render.ts +55 -43
  115. package/src/tools/bash-skill-urls.ts +4 -1
  116. package/src/tools/bash.ts +1 -0
  117. package/src/tools/write.ts +82 -9
  118. package/src/tools/yield.ts +29 -1
  119. package/src/web/search/index.ts +39 -22
  120. package/src/web/search/provider.ts +33 -16
  121. package/src/web/search/providers/codex.ts +68 -21
@@ -36,6 +36,13 @@ export declare function formatAdvisorBatchContent(notes: readonly AdvisorNote[])
36
36
  * and `blocker` interrupt; a plain `nit` queues.
37
37
  */
38
38
  export declare function isInterruptingSeverity(severity: AdvisorSeverity | undefined): boolean;
39
+ /**
40
+ * Append a staleness caveat to an advisor note when newer primary turns arrived
41
+ * after the reviewed transcript window (i.e. `hasFreshBacklog` is true on the
42
+ * advisor runtime at delivery time). Pure function — no session coupling — so it
43
+ * can be unit-tested in isolation and called from `AgentSession#routeAdvice`.
44
+ */
45
+ export declare function annotateForStaleness(note: string, hasFreshBacklog: boolean): string;
39
46
  /** How an advisor note is routed to the primary. */
40
47
  export type AdvisorDeliveryChannel = "aside" | "steer" | "preserve";
41
48
  /** Half-open turn-count fence for the post-interrupt cooldown. */
@@ -51,6 +58,9 @@ export declare function isAdvisorInterruptImmuneTurnActive(opts: {
51
58
  * - An interrupting `concern`/`blocker` is normally steered into the agent: into
52
59
  * the live turn while one is streaming, or (when idle) a triggered turn so the
53
60
  * advice is acted on immediately.
61
+ * - If the primary tail is already a terminal text answer and there is no queued
62
+ * work, late interrupting advice is preserved as a visible card instead of
63
+ * waking the primary to restate completion.
54
64
  * - After a deliberate user interrupt (`autoResumeSuppressed`) the advisor must
55
65
  * not auto-resume the stopped run. While the agent is idle — or still tearing
56
66
  * the interrupted turn down (`aborting`) — the note is preserved as a visible
@@ -60,13 +70,14 @@ export declare function isAdvisorInterruptImmuneTurnActive(opts: {
60
70
  * run instead strands it (it never reaches the running agent) and the withheld
61
71
  * notes dump as one burst at the next user prompt — the bug this guards.
62
72
  * - During the post-interrupt immune-turn window, further `concern`/`blocker`
63
- * notes are downgraded to asides; suppression preservation still wins.
73
+ * notes are downgraded to asides; preservation still wins.
64
74
  */
65
75
  export declare function resolveAdvisorDeliveryChannel(opts: {
66
76
  severity: AdvisorSeverity | undefined;
67
77
  autoResumeSuppressed: boolean;
68
78
  streaming: boolean;
69
79
  aborting: boolean;
80
+ terminalAnswerNoQueuedWork?: boolean;
70
81
  interruptImmuneTurnActive?: boolean;
71
82
  }): AdvisorDeliveryChannel;
72
83
  /**
@@ -1,4 +1,5 @@
1
1
  import type { AgentMessage } from "@oh-my-pi/pi-agent-core";
2
+ import type { AssistantMessage } from "@oh-my-pi/pi-ai";
2
3
  import { type SecretObfuscator } from "../secrets/obfuscator.js";
3
4
  /**
4
5
  * Minimal slice of `Agent` the runtime drives — satisfied by pi-agent-core
@@ -59,6 +60,24 @@ export interface AdvisorRuntimeHost {
59
60
  /** Surface a non-recovering advisor failure to the host UI without adding model-visible context. */
60
61
  notifyFailure?(error: unknown): void;
61
62
  }
63
+ /** Signals that an advisor response was discarded before it could become model-visible context. */
64
+ export declare class AdvisorOutputQuarantinedError extends Error {
65
+ constructor(message: string);
66
+ }
67
+ /**
68
+ * Replaces an advisor assistant turn that requested unavailable tools or generated
69
+ * output-only destructive directives with a sanitized error before dispatch.
70
+ *
71
+ * The agent loop records assistant turns before dispatching tools. Without this
72
+ * pre-dispatch rewrite, an advisor hallucination can leave unrelated text in the
73
+ * advisor transcript even though the action itself never executes.
74
+ */
75
+ export declare function quarantineAdvisorUnsafeOutput(message: AssistantMessage, availableToolNames: ReadonlySet<string>, sourceText?: string): string | undefined;
76
+ /**
77
+ * Builds the provenance text used to decide whether hazardous advisor output was
78
+ * generated by the advisor or came from model-visible primary/tool context.
79
+ */
80
+ export declare function buildAdvisorQuarantineSourceText(currentInput: string, messages: readonly AgentMessage[]): string;
62
81
  export declare class AdvisorRuntime {
63
82
  #private;
64
83
  private readonly agent;
@@ -67,7 +86,28 @@ export declare class AdvisorRuntime {
67
86
  disposed: boolean;
68
87
  constructor(agent: AdvisorAgent, host: AdvisorRuntimeHost, retryDelayMs?: number);
69
88
  get backlog(): number;
70
- onTurnEnd(messages?: AgentMessage[]): void;
89
+ /**
90
+ * True when `#pending` is non-empty while the drain loop is busy — i.e., newer
91
+ * primary turns arrived after the current batch's transcript window was fixed
92
+ * but before the advisor model finished processing it. The delivery path uses
93
+ * this to annotate advice that was generated without seeing those newer turns.
94
+ * Can be true during `agent.prompt()`, a `maintainContext` await, or a retry
95
+ * sleep — any time `#drain` is busy and a concurrent `onTurnEnd` pushed.
96
+ */
97
+ get hasFreshBacklog(): boolean;
98
+ /**
99
+ * Called after each primary turn ends. Renders the incremental delta and
100
+ * queues it for the advisor model.
101
+ *
102
+ * @param messages - Live primary transcript snapshot (defaults to `snapshotMessages()`).
103
+ * @param opts.willContinue - When `true` the primary is mid-turn (more tool-call
104
+ * steps will follow). The rendered heading is tagged `[in progress]` so the
105
+ * advisor knows to withhold critique on partial work. The flag is carried on
106
+ * the delta and forwarded to the reprime path so it is never silently dropped.
107
+ */
108
+ onTurnEnd(messages?: AgentMessage[], opts?: {
109
+ willContinue?: boolean;
110
+ }): void;
71
111
  waitForCatchup(maxMs: number, threshold: number, signal?: AbortSignal): Promise<void>;
72
112
  dispose(): void;
73
113
  /**
@@ -79,5 +79,7 @@ export declare function parseArgs(inputArgs: string[], extensionFlags?: Map<stri
79
79
  * process (issue #2459).
80
80
  */
81
81
  export declare function reportUnrecognizedFlags(args: Pick<Args, "unrecognizedFlags">, write?: (text: string) => void): boolean;
82
+ /** Emit a clean CLI usage error without an internal stack trace. */
83
+ export declare function reportCliUsageError(error: unknown, write?: (text: string) => void): boolean;
82
84
  export declare function getExtraHelpText(): string;
83
85
  export declare function printHelp(): void;
@@ -21,11 +21,12 @@ export declare function parseUpdateArgs(args: string[]): {
21
21
  check: boolean;
22
22
  plugins: boolean;
23
23
  } | undefined;
24
- type UpdateMethod = "brew" | "mise" | "bun" | "binary";
24
+ type UpdateMethod = "brew" | "mise" | "bun" | "npm" | "binary";
25
25
  interface UpdateMethodResolutionOptions {
26
26
  homebrewPrefix?: string;
27
27
  miseBinDirs?: readonly string[];
28
28
  miseDataDir?: string;
29
+ npmBinDir?: string;
29
30
  }
30
31
  export declare function resolveUpdateMethodForTest(ompPath: string, bunBinDir: string | undefined, options?: UpdateMethodResolutionOptions): UpdateMethod;
31
32
  interface BunInstallCachePruneResult {
@@ -89,6 +90,8 @@ export declare function replaceBinaryForUpdate(options: BinaryReplacementOptions
89
90
  * See #1824.
90
91
  */
91
92
  export declare function buildBunInstallArgs(expectedVersion: string, nativeTag?: string): string[];
93
+ /** Build the npm argv used to update npm-managed global installs. */
94
+ export declare function buildNpmInstallArgs(expectedVersion: string, nativeTag?: string): string[];
92
95
  export declare function buildHomebrewUpdateArgs(force: boolean): string[];
93
96
  export declare function buildMiseUpgradeArgs(): string[];
94
97
  export declare function buildMiseForceInstallArgs(expectedVersion: string): string[];
@@ -26,6 +26,9 @@ export interface UsageAccountIdentity {
26
26
  accountId?: string;
27
27
  projectId?: string;
28
28
  enterpriseUrl?: string;
29
+ /** Organization/workspace the credential is scoped to (Anthropic multi-subscription). */
30
+ orgId?: string;
31
+ orgName?: string;
29
32
  }
30
33
  /**
31
34
  * Minimal-reveal masks for identity strings (`--redact`).
@@ -0,0 +1,4 @@
1
+ /** Command-line input error that should be rendered without a stack trace. */
2
+ export declare class CliUsageError extends Error {
3
+ constructor(message: string);
4
+ }
@@ -1,4 +1,4 @@
1
- import type { Api, ApiKeyResolver, AuthStorage, Model } from "@oh-my-pi/pi-ai";
1
+ import { type Api, type ApiKeyResolver, type AuthStorage, type Model } from "@oh-my-pi/pi-ai";
2
2
  /** Model slice accepted by the model-form `resolver(model, sessionId)` overload. */
3
3
  export type ApiKeyResolverModel = Pick<Model<Api>, "provider" | "baseUrl" | "id">;
4
4
  export interface ApiKeyResolverOptions {
@@ -25,7 +25,7 @@ export interface ApiKeyResolverRegistry {
25
25
  /**
26
26
  * Build an {@link ApiKeyResolver} implementing the central a/b/c auth-retry
27
27
  * policy: initial → resolve; step (b) → force-refresh same account; step (c)
28
- * → rotate to a sibling credential, then re-resolve.
28
+ * → rotate to a sibling and re-resolve, unless quota exhaustion has no sibling.
29
29
  *
30
30
  * Two call forms: `resolver(provider, options?)` for provider-scoped keys,
31
31
  * and `resolver(model, sessionId?)` which derives `baseUrl`/`modelId` from
@@ -74,7 +74,7 @@ export declare class ModelRegistry {
74
74
  fetch?: FetchImpl;
75
75
  });
76
76
  /**
77
- * Reload models from disk (built-in + custom from models.json).
77
+ * Reload models from disk (built-in + custom config).
78
78
  */
79
79
  refresh(strategy?: ModelRefreshStrategy): Promise<void>;
80
80
  refreshInBackground(strategy?: ModelRefreshStrategy): void;
@@ -94,12 +94,12 @@ export declare class ModelRegistry {
94
94
  */
95
95
  refreshRuntimeProviders(strategy?: ModelRefreshStrategy): Promise<void>;
96
96
  /**
97
- * Get any error from loading models.json (undefined if no error).
97
+ * Get any error from loading custom models config (undefined if no error).
98
98
  */
99
99
  getError(): ConfigError | undefined;
100
100
  /**
101
101
  * Get all models (built-in + custom).
102
- * If models.json had errors, returns only built-in models.
102
+ * If custom config had errors, returns only built-in models.
103
103
  */
104
104
  getAll(): Model<Api>[];
105
105
  /**
@@ -144,6 +144,7 @@ export declare function resolveModelOverride(modelPatterns: string[], modelRegis
144
144
  model?: Model<Api>;
145
145
  thinkingLevel?: ConfiguredThinkingLevel;
146
146
  explicitThinkingLevel: boolean;
147
+ warning?: string;
147
148
  };
148
149
  /**
149
150
  * Resolve a list of override patterns to the first matching model, with an
@@ -156,6 +157,11 @@ export declare function resolveModelOverride(modelPatterns: string[], modelRegis
156
157
  * `modelRoles.task` pointing at an unqualified id whose only available
157
158
  * provider variant has no configured credentials — see #985).
158
159
  *
160
+ * `sessionId` is forwarded to `getApiKey` so that session-sticky OAuth
161
+ * credentials resolve correctly during the pre-flight auth check. Without it,
162
+ * providers with multiple OAuth accounts may return `undefined` even though
163
+ * the credential is usable once the subagent session starts — see #5325.
164
+ *
159
165
  * Keyless-by-design providers (llama.cpp, ollama, lm-studio) advertise the
160
166
  * `kNoAuth` sentinel from `getApiKey` to signal that they do not require
161
167
  * credentials. Those are treated as authenticated here so an explicitly
@@ -166,11 +172,12 @@ export declare function resolveModelOverride(modelPatterns: string[], modelRegis
166
172
  * primary resolution unchanged so the existing error path still surfaces
167
173
  * a meaningful failure downstream.
168
174
  */
169
- export declare function resolveModelOverrideWithAuthFallback(modelPatterns: string[], parentActiveModelPattern: string | undefined, modelRegistry: ModelLookupRegistry & Pick<ModelRegistry, "getApiKey">, settings?: Settings): Promise<{
175
+ export declare function resolveModelOverrideWithAuthFallback(modelPatterns: string[], parentActiveModelPattern: string | undefined, modelRegistry: ModelLookupRegistry & Pick<ModelRegistry, "getApiKey">, settings?: Settings, sessionId?: string): Promise<{
170
176
  model?: Model<Api>;
171
177
  thinkingLevel?: ConfiguredThinkingLevel;
172
178
  explicitThinkingLevel: boolean;
173
179
  authFallbackUsed: boolean;
180
+ warning?: string;
174
181
  }>;
175
182
  /**
176
183
  * Resolve a list of role patterns to the first matching model.
@@ -1,5 +1,5 @@
1
1
  /**
2
- * models.json config file handle and provider configuration validation.
2
+ * Custom model/provider config file handle and validation.
3
3
  */
4
4
  import type { Api, ModelSpec } from "@oh-my-pi/pi-ai/types";
5
5
  import { ConfigFile } from "./config-file.js";
@@ -20,8 +20,16 @@ export declare const EVAL_TIMEOUT_PAUSE_OP = "timeout-pause";
20
20
  export declare const EVAL_TIMEOUT_RESUME_OP = "timeout-resume";
21
21
  /** Whether a status event is pure eval-timeout control and should not render. */
22
22
  export declare function isEvalTimeoutControlEvent(event: JsStatusEvent): boolean;
23
+ /** Optional behavior for a timeout pause around a host bridge call. */
24
+ export interface BridgeTimeoutPauseOptions {
25
+ /**
26
+ * Marks the pause as an `agent()` call whose already-started work must finish
27
+ * before an external eval abort reaches the kernel.
28
+ */
29
+ deferExternalAbort?: boolean;
30
+ }
23
31
  /**
24
32
  * Run {@link operation} while suspending the eval watchdog through
25
33
  * {@link emitStatus}. A no-op wrapper when no status sink is wired.
26
34
  */
27
- export declare function withBridgeTimeoutPause<T>(emitStatus: ((event: JsStatusEvent) => void) | undefined, operation: () => Promise<T>): Promise<T>;
35
+ export declare function withBridgeTimeoutPause<T>(emitStatus: ((event: JsStatusEvent) => void) | undefined, operation: () => Promise<T>, options?: BridgeTimeoutPauseOptions): Promise<T>;
@@ -13,6 +13,8 @@ export interface VmRunState {
13
13
  * {@link WORKER_CLOSE_TIMEOUT_MS}; never call this outside tests.
14
14
  */
15
15
  export declare function setWorkerCloseTimeoutMsForTests(ms: number): number;
16
+ /** Test-only seam for the legacy Worker lifecycle mocks. */
17
+ export declare function setJsEvalWorkerThreadForTests(enabled: boolean): boolean;
16
18
  export declare function executeInVmContext(options: {
17
19
  sessionKey: string;
18
20
  sessionId: string;
@@ -30,9 +32,9 @@ export declare function executeInVmContext(options: {
30
32
  export declare function resetVmContext(sessionKey: string): Promise<void>;
31
33
  export declare function disposeAllVmContexts(): Promise<void>;
32
34
  /**
33
- * Smoke probe: spawn the JS eval worker through the worker-host entry and prove
34
- * it answers the `init` handshake on a real worker thread (not the inline
35
- * fallback). Catches the silent worker-load and init-message-drop regressions
35
+ * Smoke probe: spawn the JS evaluator through the worker-host entry and prove
36
+ * it answers the `init` handshake in a real isolated subprocess (not the inline
37
+ * fallback). Catches silent process-load and init-message regressions
36
38
  * that otherwise strand every cell on the init timeout in a distribution build —
37
39
  * the failure mode that motivated `installWorkerInbox`. Wired into
38
40
  * `omp --smoke-test` so binary / source / tarball installs all exercise it.
@@ -0,0 +1,6 @@
1
+ import type { WorkerInbound, WorkerOutbound } from "./worker-protocol.js";
2
+ /** Start the JavaScript evaluator inside a subprocess IPC transport. */
3
+ export declare function startJsEvalProcess(transport: {
4
+ send(message: WorkerOutbound): void;
5
+ onMessage(handler: (message: WorkerInbound) => void): () => void;
6
+ }): void;
@@ -1,6 +1,20 @@
1
1
  import type { Transport } from "./worker-protocol.js";
2
+ export type WorkerCoreOptions = {
3
+ mode: "isolated";
4
+ /**
5
+ * Mirror the session cwd onto the real process cwd so cell code using
6
+ * `process.cwd()`, relative paths, or child processes without an explicit
7
+ * `cwd` resolves against the project. Only the dedicated subprocess may
8
+ * pass this: `process.chdir` is unavailable in Worker threads and would
9
+ * mutate the host's own cwd on the inline fallback.
10
+ */
11
+ chdir?: (cwd: string) => void;
12
+ } | {
13
+ mode: "inline";
14
+ interceptUnhandledRejections(handler: (reason: unknown) => boolean): () => void;
15
+ };
2
16
  export declare class WorkerCore {
3
17
  #private;
4
- constructor(transport: Transport);
18
+ constructor(transport: Transport, options: WorkerCoreOptions);
5
19
  dispose(): void;
6
20
  }
@@ -26,6 +26,16 @@ export declare function shouldHideKernelWindow(opts: {
26
26
  platform: NodeJS.Platform;
27
27
  hostHasInheritableConsole: boolean;
28
28
  }): boolean;
29
+ /**
30
+ * Keep eval kernels outside the host's POSIX terminal session.
31
+ *
32
+ * User code can start an interactive shell which calls `tcsetpgrp(3)`. If the
33
+ * kernel shares OMP's session, that shell can replace OMP as the controlling
34
+ * terminal's foreground process group and the host is then stopped by SIGTTIN
35
+ * on its next stdin read. Bun implements `detached: true` with `setsid(2)` on
36
+ * POSIX, making the kernel a session leader with no controlling terminal.
37
+ */
38
+ export declare function shouldDetachKernel(platform: NodeJS.Platform): boolean;
29
39
  /**
30
40
  * TTY-based fallback used when the Win32 console probe is unavailable.
31
41
  *
@@ -4,6 +4,7 @@ export interface PyToolBridgeEntry {
4
4
  toolSession: ToolSession;
5
5
  signal?: AbortSignal;
6
6
  emitStatus?: (event: JsStatusEvent) => void;
7
+ abortRequested?: () => boolean;
7
8
  }
8
9
  export interface PyToolBridgeInfo {
9
10
  url: string;
@@ -17,6 +17,7 @@ import type { Settings } from "../../config/settings.js";
17
17
  import type { ExecOptions, ExecResult } from "../../exec/exec.js";
18
18
  import type { HookUIContext } from "../../extensibility/hooks/types.js";
19
19
  import type * as PiCodingAgent from "../../index.js";
20
+ import type { LocalProtocolOptions } from "../../internal-urls/local-protocol.js";
20
21
  import type { Theme } from "../../modes/theme/theme.js";
21
22
  import type { ReadonlySessionManager } from "../../session/session-manager.js";
22
23
  import type { TodoItem } from "../../tools/todo.js";
@@ -84,6 +85,8 @@ export interface CustomToolContext {
84
85
  settings?: Settings;
85
86
  /** Fetch implementation for outbound HTTP; defaults to global fetch when omitted. */
86
87
  fetch?: FetchImpl;
88
+ /** Calling session's `local://` root mapping for tools that bridge out of the OMP process. */
89
+ localProtocolOptions?: LocalProtocolOptions;
87
90
  /** Whether to auto-approve all destructive tool operations (--auto-approve CLI flag) */
88
91
  autoApprove?: boolean;
89
92
  }
@@ -6,6 +6,7 @@ import type { CredentialDisabledEvent, ImageContent, Model, ProviderResponseMeta
6
6
  import type { KeyId } from "@oh-my-pi/pi-tui";
7
7
  import type { ModelRegistry } from "../../config/model-registry.js";
8
8
  import type { Settings } from "../../config/settings.js";
9
+ import type { LocalProtocolOptions } from "../../internal-urls/local-protocol.js";
9
10
  import type { MemoryRuntimeContext } from "../../memory-backend/index.js";
10
11
  import type { SessionManager } from "../../session/session-manager.js";
11
12
  import type { BranchHandler, NavigateTreeHandler, NewSessionHandler } from "../session-handler-types.js";
@@ -65,7 +66,8 @@ export declare class ExtensionRunner {
65
66
  private readonly sessionManager;
66
67
  private readonly modelRegistry;
67
68
  private readonly settings?;
68
- constructor(extensions: Extension[], runtime: ExtensionRuntime, cwd: string, sessionManager: SessionManager, modelRegistry: ModelRegistry, getMemory?: () => MemoryRuntimeContext | undefined, settings?: Settings | undefined);
69
+ private readonly localProtocolOptions?;
70
+ constructor(extensions: Extension[], runtime: ExtensionRuntime, cwd: string, sessionManager: SessionManager, modelRegistry: ModelRegistry, getMemory?: () => MemoryRuntimeContext | undefined, settings?: Settings | undefined, localProtocolOptions?: LocalProtocolOptions | undefined);
69
71
  initialize(actions: ExtensionActions, contextActions: ExtensionContextActions, commandContextActions?: ExtensionCommandContextActions, uiContext?: ExtensionUIContext): void;
70
72
  /**
71
73
  * Forward a `credential_disabled` event from `AuthStorage` to extension handlers.
@@ -22,6 +22,7 @@ import type { PythonResult } from "../../eval/py/executor.js";
22
22
  import type { BashResult } from "../../exec/bash-executor.js";
23
23
  import type { ExecOptions, ExecResult } from "../../exec/exec.js";
24
24
  import type * as PiCodingAgent from "../../index.js";
25
+ import type { LocalProtocolOptions } from "../../internal-urls/local-protocol.js";
25
26
  import type { MemoryRuntimeContext } from "../../memory-backend/index.js";
26
27
  import type { CustomEditor } from "../../modes/components/custom-editor.js";
27
28
  import type { Theme } from "../../modes/theme/theme.js";
@@ -285,6 +286,8 @@ export interface ExtensionContext {
285
286
  sessionManager: ReadonlySessionManager;
286
287
  /** Model registry for API key resolution */
287
288
  modelRegistry: ModelRegistry;
289
+ /** Calling session's `local://` root mapping for external tool bridges. */
290
+ localProtocolOptions?: LocalProtocolOptions;
288
291
  /** Current model (may be undefined) */
289
292
  model: Model | undefined;
290
293
  /** Read-only model query facade: list / current / resolve / family. */
@@ -1,4 +1,4 @@
1
- import type { InternalResource, InternalUrl, ProtocolHandler, UrlCompletion } from "./types.js";
1
+ import type { InternalResource, InternalUrl, ProtocolHandler, ResolveContext, UrlCompletion } from "./types.js";
2
2
  /**
3
3
  * Snapshot of memory roots for every registered session, deduped.
4
4
  * Each session has its own cwd (possibly a worktree), so subagents and main
@@ -11,14 +11,13 @@ export declare function memoryRootsFromRegistry(): string[];
11
11
  export declare function resolveMemoryUrlToPath(url: InternalUrl, memoryRoot: string): string;
12
12
  /**
13
13
  * Protocol handler for memory:// URLs.
14
- *
15
- * Walks every active session's memory root. Worktree-based subagents have
16
- * their own root; first one containing the file wins. Parent and subagent
17
- * sharing a cwd see the same file regardless of order.
14
+ * Resolves file-backed roots against the calling session cwd when provided.
15
+ * Contextless callers fall back to the live-session registry for legacy
16
+ * cross-session lookups.
18
17
  */
19
18
  export declare class MemoryProtocolHandler implements ProtocolHandler {
20
19
  readonly scheme = "memory";
21
20
  readonly immutable = true;
22
- resolve(url: InternalUrl): Promise<InternalResource>;
23
- complete(): Promise<UrlCompletion[]>;
21
+ resolve(url: InternalUrl, context?: ResolveContext): Promise<InternalResource>;
22
+ complete(_query?: string, context?: ResolveContext): Promise<UrlCompletion[]>;
24
23
  }
@@ -53,6 +53,7 @@ export declare class SessionResolutionError extends Error {
53
53
  readonly hint?: string;
54
54
  constructor(message: string, hint?: string);
55
55
  }
56
+ export declare function normalizeContinueSessionArgs(parsed: Args, rawArgs?: readonly string[]): void;
56
57
  /** Resolves CLI session flags into an existing, forked, in-memory, or cancelled session manager. */
57
58
  export declare function createSessionManager(parsed: Args, cwd: string, activeSettings?: Settings, askToForkSession?: SessionPrompt, askToMoveSession?: SessionPrompt): Promise<SessionManager | undefined>;
58
59
  /** Apply resolved CLI/discovered prompt files without bypassing system prompt templates. */
@@ -1,4 +1,4 @@
1
- import { type Component, Container, type NativeScrollbackCommittedRows, type NativeScrollbackLiveRegion, type RenderStablePrefix, type ViewportTailProvider } from "@oh-my-pi/pi-tui";
1
+ import { type Component, Container, type NativeScrollbackCommittedRows, type NativeScrollbackLiveRegion, type NativeScrollbackReplay, type RenderStablePrefix, type ViewportTailProvider } from "@oh-my-pi/pi-tui";
2
2
  /**
3
3
  * Transcript container that renders every block's current content each frame
4
4
  * and reports the native-scrollback exactness boundary
@@ -24,11 +24,12 @@ import { type Component, Container, type NativeScrollbackCommittedRows, type Nat
24
24
  * through {@link RenderStablePrefix} so the engine can skip marker scanning,
25
25
  * line preparation, and the committed-prefix audit for those rows.
26
26
  */
27
- export declare class TranscriptContainer extends Container implements NativeScrollbackLiveRegion, NativeScrollbackCommittedRows, RenderStablePrefix, ViewportTailProvider {
27
+ export declare class TranscriptContainer extends Container implements NativeScrollbackLiveRegion, NativeScrollbackCommittedRows, NativeScrollbackReplay, RenderStablePrefix, ViewportTailProvider {
28
28
  #private;
29
29
  invalidate(): void;
30
30
  clear(): void;
31
31
  setNativeScrollbackCommittedRows(rows: number): void;
32
+ prepareNativeScrollbackReplay(): void;
32
33
  getRenderStablePrefixRows(): number;
33
34
  getNativeScrollbackLiveRegionStart(): number | undefined;
34
35
  /**
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Build a case-sensitive magic-keyword matcher for prose punctuation boundaries.
3
+ *
4
+ * Sentence punctuation and quotes may touch the keyword, but letters, digits,
5
+ * underscores, slashes, backslashes, hyphens, file-extension dots, symbol
6
+ * references (`foo::keyword`), and immediate call parentheses (`keyword()`)
7
+ * keep the occurrence embedded in code rather than prose.
8
+ */
9
+ export declare function magicKeywordRegex(keyword: string, flags?: string): RegExp;
@@ -3,7 +3,7 @@ import { type KeywordHighlighter } from "./gradient-highlight.js";
3
3
  export declare const ORCHESTRATE_NOTICE: string;
4
4
  /**
5
5
  * Whether `text` contains the standalone keyword "orchestrate" (lowercase,
6
- * whitespace-delimited) in prose — never inside a code block, inline code span,
6
+ * prose-delimited) in prose — never inside a code block, inline code span,
7
7
  * or XML/HTML section.
8
8
  */
9
9
  export declare function containsOrchestrate(text: string): boolean;
@@ -12,5 +12,7 @@ export declare class RpcHostToolBridge {
12
12
  handleUpdate(frame: RpcHostToolUpdate): boolean;
13
13
  requestExecution(definition: RpcHostToolDefinition, toolCallId: string, args: Record<string, unknown>, signal?: AbortSignal, onUpdate?: AgentToolUpdateCallback<unknown>): Promise<AgentToolResult<unknown>>;
14
14
  rejectAllPending(message: string): void;
15
+ /** Reject active and future host tool requests after the RPC client disconnects. */
16
+ close(message: string): void;
15
17
  }
16
18
  export {};
@@ -8,6 +8,13 @@ export type PendingExtensionRequest = {
8
8
  resolve: (response: RpcExtensionUIResponse) => void;
9
9
  reject: (error: Error) => void;
10
10
  };
11
+ /** Pending extension UI request map that can fail closed when the RPC client disconnects. */
12
+ export declare class RpcPendingExtensionRequests extends Map<string, PendingExtensionRequest> {
13
+ #private;
14
+ set(id: string, request: PendingExtensionRequest): this;
15
+ /** Reject every active and future extension UI request. */
16
+ rejectAll(message: string): void;
17
+ }
11
18
  type RpcOutput = (obj: RpcResponse | RpcExtensionUIRequest | RpcHostToolCallRequest | RpcHostToolCancelRequest | RpcHostUriRequest | RpcHostUriCancelRequest | object) => void;
12
19
  export type RpcSessionChangeCommand = Extract<RpcCommand, {
13
20
  type: "new_session";
@@ -84,15 +91,16 @@ export interface RpcInputFrameDeps {
84
91
  onHostToolUpdate: (frame: RpcHostToolUpdate) => void;
85
92
  onHostUriResult: (frame: RpcHostUriResult) => void;
86
93
  }
94
+ /** Dispatch side-channel frames that must overtake the serialized command queue. */
95
+ export declare function dispatchRpcControlFrame(parsed: unknown, deps: RpcInputFrameDeps): boolean;
87
96
  /**
88
97
  * Dispatch a single parsed frame from the RPC input stream.
89
98
  *
90
- * Bash commands are dispatched in the background so the caller (the stdin loop
91
- * in {@link runRpcMode}) can keep reading subsequent frames while a shell
92
- * command is still running. This lets a client send `abort_bash` (or any other
93
- * command) while a long-running `bash` is in flight. Response correlation is
94
- * preserved via each command's `id`; ordering across concurrent commands is
95
- * not guaranteed and clients MUST match on `id`.
99
+ * Bash commands are dispatched in the background so the caller can keep reading
100
+ * subsequent frames while a shell command is still running. This lets a client
101
+ * send `abort_bash` while a long-running `bash` is in flight. Response
102
+ * correlation is preserved via each command's `id`; ordering across concurrent
103
+ * commands is not guaranteed and clients MUST match on `id`.
96
104
  *
97
105
  * @returns `undefined` when the frame was routed to a side-channel handler
98
106
  * (extension UI response, host tool/URI frames) or dispatched in the
@@ -101,6 +109,18 @@ export interface RpcInputFrameDeps {
101
109
  * on non-`bash` commands propagate; the caller is expected to wrap them.
102
110
  */
103
111
  export declare function dispatchRpcInputFrame(parsed: unknown, deps: RpcInputFrameDeps): Promise<void> | undefined;
112
+ /** Serializes ordinary RPC commands while allowing control frames to dispatch immediately. */
113
+ export declare class RpcInputDispatcher {
114
+ #private;
115
+ constructor(options: {
116
+ deps: RpcInputFrameDeps;
117
+ afterSerialCommand?: () => Promise<void>;
118
+ });
119
+ /** Accept a parsed input frame without blocking the stdin reader. */
120
+ dispatch(parsed: unknown): void;
121
+ /** Await every accepted serial command, including commands queued before EOF. */
122
+ drain(): Promise<void>;
123
+ }
104
124
  /**
105
125
  * Coordinates deferred shutdown with in-flight background input tasks.
106
126
  *
@@ -3,7 +3,7 @@ import { type KeywordHighlighter } from "./gradient-highlight.js";
3
3
  export declare const ULTRATHINK_NOTICE: string;
4
4
  /**
5
5
  * Whether `text` contains the standalone keyword "ultrathink" (lowercase,
6
- * whitespace-delimited) in prose — never inside a code block, inline code span,
6
+ * prose-delimited) in prose — never inside a code block, inline code span,
7
7
  * or XML/HTML section.
8
8
  */
9
9
  export declare function containsUltrathink(text: string): boolean;
@@ -38,6 +38,18 @@ export declare function buildFileMentionBlock(files: FileMentionMessage["files"]
38
38
  * canonicalization) — i.e. content that closes the current read-tool run.
39
39
  */
40
40
  export declare function assistantHasVisibleContent(message: AssistantAgentMessage): boolean;
41
+ /**
42
+ * Split mixed assistant turns into visible text before tool execution and
43
+ * visible text segments that must render immediately after the preceding tool.
44
+ * Cursor can return intro text, tool calls, progress text, and the final answer
45
+ * in one assistant message; keeping every text block in the leading assistant
46
+ * block buries post-tool text above tool results in the transcript.
47
+ */
48
+ export declare function splitAssistantMessageToolTimeline(message: AssistantAgentMessage): {
49
+ beforeTools: AssistantAgentMessage;
50
+ afterToolCalls: ReadonlyMap<string, AssistantAgentMessage>;
51
+ hasToolCalls: boolean;
52
+ };
41
53
  /**
42
54
  * Normalize raw tool-call arguments to a plain record, collapsing non-object or
43
55
  * array values to an empty object.
@@ -7,7 +7,7 @@ export declare function renderWorkflowNotice({ taskBatch }: {
7
7
  }): string;
8
8
  /**
9
9
  * Whether `text` contains the standalone keyword "workflowz"
10
- * (lowercase, whitespace-delimited) in prose — never inside a code block, inline
10
+ * (lowercase, prose-delimited) in prose — never inside a code block, inline
11
11
  * code span, or XML/HTML section.
12
12
  */
13
13
  export declare function containsWorkflow(text: string): boolean;
@@ -811,6 +811,11 @@ export declare class AgentSession {
811
811
  * from role configuration (e.g., "anthropic/claude-sonnet-4-5:xhigh").
812
812
  */
813
813
  resolveRoleModelWithThinking(role: string): ResolvedModelRoleValue;
814
+ /**
815
+ * Resolve the explicit thinking suffix that should apply when a temporary
816
+ * picker selects a model already assigned to a configured role.
817
+ */
818
+ resolveTemporaryModelThinkingLevel(model: Model): ConfiguredThinkingLevel | undefined;
814
819
  get promptTemplates(): ReadonlyArray<PromptTemplate>;
815
820
  /** Replace file-based slash commands used for prompt expansion. */
816
821
  setSlashCommands(slashCommands: FileSlashCommand[]): void;
@@ -872,6 +877,7 @@ export declare class AgentSession {
872
877
  triggerTurn?: boolean;
873
878
  deliverAs?: "steer" | "followUp" | "nextTurn";
874
879
  queueChipText?: string;
880
+ acceptTerminalEmptyStop?: boolean;
875
881
  }): Promise<boolean>;
876
882
  /**
877
883
  * Send a user message through the prompt flow.
@@ -1,3 +1,4 @@
1
+ import type { AssistantMessage } from "@oh-my-pi/pi-ai";
1
2
  import type { SessionEntry } from "./session-entries.js";
2
3
  export declare const TOOL_EXECUTION_START_CUSTOM_TYPE = "tool_execution_start";
3
4
  export declare const SESSION_EXIT_CUSTOM_TYPE = "session_exit";
@@ -35,6 +36,16 @@ export interface SessionExitData {
35
36
  recordedAt: string;
36
37
  pendingToolCalls?: PendingToolCallDiagnostic[];
37
38
  }
39
+ export interface AssistantModelMetadata {
40
+ api: AssistantMessage["api"];
41
+ provider: string;
42
+ model: string;
43
+ }
44
+ /**
45
+ * createInterruptedTurnAbortMessage returns a terminal assistant record when
46
+ * the latest persisted process exit follows a non-terminal conversation tail.
47
+ */
48
+ export declare function createInterruptedTurnAbortMessage(entries: readonly SessionEntry[], fallbackModel?: AssistantModelMetadata): AssistantMessage | undefined;
38
49
  /**
39
50
  * Project full tool-call arguments down to the fields the pending-tool-call
40
51
  * resume warning actually renders (`command`/`path`), truncated. Returns