@oh-my-pi/pi-coding-agent 17.1.2 → 17.1.4

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 (110) hide show
  1. package/CHANGELOG.md +63 -0
  2. package/dist/cli.js +3806 -3798
  3. package/dist/types/cli/__tests__/auth-gateway-catalog.test.d.ts +1 -0
  4. package/dist/types/cli/auth-gateway-cli.d.ts +8 -0
  5. package/dist/types/cli/update-cli.d.ts +41 -0
  6. package/dist/types/cli/usage-cli.d.ts +4 -2
  7. package/dist/types/commands/update.d.ts +1 -0
  8. package/dist/types/config/model-registry.d.ts +19 -0
  9. package/dist/types/config/settings-schema.d.ts +30 -7
  10. package/dist/types/cursor.d.ts +47 -1
  11. package/dist/types/eval/js/process-entry.d.ts +2 -1
  12. package/dist/types/eval/js/worker-core.d.ts +4 -1
  13. package/dist/types/extensibility/extensions/runner.d.ts +1 -0
  14. package/dist/types/extensibility/legacy-pi-ai-shim.d.ts +4 -0
  15. package/dist/types/extensibility/legacy-pi-coding-agent-shim.d.ts +4 -0
  16. package/dist/types/extensibility/legacy-pi-tui-shim.d.ts +15 -7
  17. package/dist/types/extensibility/shared-events.d.ts +2 -0
  18. package/dist/types/modes/components/assistant-message.d.ts +9 -0
  19. package/dist/types/modes/components/custom-editor.d.ts +12 -8
  20. package/dist/types/plan-mode/approved-plan.d.ts +3 -2
  21. package/dist/types/secrets/obfuscator.d.ts +7 -31
  22. package/dist/types/session/agent-session.d.ts +19 -4
  23. package/dist/types/session/prewalk.d.ts +2 -1
  24. package/dist/types/session/session-advisors.d.ts +8 -0
  25. package/dist/types/session/session-metadata.d.ts +29 -0
  26. package/dist/types/session/turn-recovery.d.ts +5 -5
  27. package/dist/types/stt/sherpa-runtime.d.ts +38 -0
  28. package/dist/types/thinking.d.ts +24 -0
  29. package/dist/types/tools/auto-generated-guard.d.ts +5 -2
  30. package/dist/types/tools/bash.d.ts +5 -4
  31. package/dist/types/tools/computer/exposure.d.ts +8 -0
  32. package/dist/types/tools/computer/supervisor.d.ts +1 -1
  33. package/dist/types/tools/computer/worker-entry.d.ts +1 -1
  34. package/dist/types/tools/computer/worker.d.ts +1 -1
  35. package/dist/types/tools/computer.d.ts +6 -0
  36. package/dist/types/tools/memory-render.d.ts +1 -4
  37. package/dist/types/tools/shell-tokenize.d.ts +14 -0
  38. package/dist/types/tools/todo.d.ts +7 -1
  39. package/package.json +12 -12
  40. package/src/advisor/__tests__/advisor.test.ts +80 -10
  41. package/src/advisor/runtime.ts +27 -1
  42. package/src/cli/__tests__/auth-gateway-catalog.test.ts +111 -0
  43. package/src/cli/auth-gateway-cli.ts +63 -16
  44. package/src/cli/config-cli.ts +25 -7
  45. package/src/cli/update-cli.ts +229 -29
  46. package/src/cli/usage-cli.ts +144 -15
  47. package/src/cli.ts +21 -15
  48. package/src/commands/update.ts +6 -0
  49. package/src/config/__tests__/model-registry.test.ts +42 -7
  50. package/src/config/model-registry.ts +67 -4
  51. package/src/config/settings-schema.ts +39 -8
  52. package/src/config/settings.ts +24 -2
  53. package/src/cursor.ts +153 -0
  54. package/src/dap/session.ts +70 -11
  55. package/src/edit/hashline/filesystem.ts +1 -1
  56. package/src/edit/modes/patch.ts +1 -1
  57. package/src/eval/__tests__/js-context-manager.test.ts +9 -1
  58. package/src/eval/__tests__/process-entry-import.test.ts +111 -1
  59. package/src/eval/js/process-entry.ts +9 -5
  60. package/src/eval/js/worker-core.ts +6 -2
  61. package/src/exec/bash-executor.ts +4 -2
  62. package/src/extensibility/extensions/runner.ts +23 -8
  63. package/src/extensibility/legacy-pi-ai-shim.ts +9 -0
  64. package/src/extensibility/legacy-pi-coding-agent-shim.ts +14 -2
  65. package/src/extensibility/legacy-pi-tui-shim.ts +33 -0
  66. package/src/extensibility/shared-events.ts +2 -0
  67. package/src/main.ts +22 -1
  68. package/src/modes/acp/acp-agent.ts +6 -0
  69. package/src/modes/components/assistant-message.ts +88 -11
  70. package/src/modes/components/chat-transcript-builder.ts +2 -0
  71. package/src/modes/components/custom-editor.test.ts +170 -0
  72. package/src/modes/components/custom-editor.ts +79 -29
  73. package/src/modes/components/settings-defs.ts +5 -1
  74. package/src/modes/controllers/event-controller.ts +96 -4
  75. package/src/modes/controllers/selector-controller.ts +14 -0
  76. package/src/modes/interactive-mode.ts +34 -8
  77. package/src/modes/utils/context-usage.ts +19 -2
  78. package/src/modes/utils/interactive-context-helpers.ts +1 -0
  79. package/src/plan-mode/approved-plan.ts +18 -10
  80. package/src/prompts/system/custom-system-prompt.md +1 -1
  81. package/src/prompts/system/system-prompt.md +10 -1
  82. package/src/prompts/tools/ast-edit.md +1 -1
  83. package/src/sdk.ts +4 -0
  84. package/src/secrets/obfuscator.ts +36 -126
  85. package/src/session/agent-session.ts +69 -60
  86. package/src/session/prewalk.ts +8 -3
  87. package/src/session/session-advisors.ts +67 -3
  88. package/src/session/session-metadata.ts +53 -0
  89. package/src/session/session-provider-boundary.ts +0 -1
  90. package/src/session/session-tools.ts +35 -1
  91. package/src/session/stream-guards.ts +1 -1
  92. package/src/session/turn-recovery.ts +36 -19
  93. package/src/slash-commands/builtin-registry.ts +49 -7
  94. package/src/stt/asr-worker.ts +2 -37
  95. package/src/stt/sherpa-runtime.ts +71 -0
  96. package/src/task/executor.ts +6 -5
  97. package/src/thinking.ts +39 -0
  98. package/src/tools/auto-generated-guard.ts +18 -5
  99. package/src/tools/bash.ts +43 -15
  100. package/src/tools/computer/exposure.ts +38 -0
  101. package/src/tools/computer/supervisor.ts +61 -13
  102. package/src/tools/computer/worker-entry.ts +28 -19
  103. package/src/tools/computer/worker.ts +3 -7
  104. package/src/tools/computer.ts +65 -10
  105. package/src/tools/gh-cache-invalidation.ts +2 -82
  106. package/src/tools/memory-render.ts +11 -2
  107. package/src/tools/render-utils.ts +8 -3
  108. package/src/tools/shell-tokenize.ts +83 -0
  109. package/src/tools/todo.ts +44 -17
  110. package/src/tools/write.ts +1 -1
@@ -1,3 +1,4 @@
1
+ import { type Api, type Model } from "@oh-my-pi/pi-ai";
1
2
  export type AuthGatewayAction = "serve" | "token" | "status" | "check";
2
3
  export interface AuthGatewayCommandArgs {
3
4
  action: AuthGatewayAction;
@@ -22,5 +23,12 @@ export interface AuthGatewayCommandArgs {
22
23
  };
23
24
  }
24
25
  declare const ACTIONS: readonly AuthGatewayAction[];
26
+ /**
27
+ * Index resolvable models by the request ids clients may send: the
28
+ * provider-qualified `provider/id` (always) and the bare `id` (first-write-wins
29
+ * fallback for legacy clients). Scoped to providers the gateway holds broker
30
+ * credentials for, since only those are routable.
31
+ */
32
+ export declare function indexModelsByRequestId(models: readonly Model<Api>[], providersWithCreds: ReadonlySet<string>): Map<string, Model<Api>>;
25
33
  export declare function runAuthGatewayCommand(cmd: AuthGatewayCommandArgs): Promise<void>;
26
34
  export { ACTIONS as AUTH_GATEWAY_ACTIONS };
@@ -1,3 +1,24 @@
1
+ export interface ReleaseBinaryAsset {
2
+ url: string;
3
+ size: number;
4
+ digest: string;
5
+ }
6
+ type Fetch = (input: string | URL | Request, init?: RequestInit) => Promise<Response>;
7
+ /**
8
+ * Select and validate the binary asset from GitHub release metadata.
9
+ */
10
+ export declare function resolveReleaseBinaryAsset(release: unknown, expectedTag: string, binaryName: string): ReleaseBinaryAsset;
11
+ export interface VerifiedBinaryDownloadOptions {
12
+ url: string;
13
+ targetPath: string;
14
+ expectedSize: number;
15
+ expectedDigest: string;
16
+ fetchImpl?: Fetch;
17
+ }
18
+ /**
19
+ * Download a binary and verify its GitHub-reported size and SHA-256 digest.
20
+ */
21
+ export declare function downloadVerifiedBinary(options: VerifiedBinaryDownloadOptions): Promise<void>;
1
22
  /** Result from running the installed binary and parsing its reported version. */
2
23
  export interface InstalledVersionVerification {
3
24
  ok: boolean;
@@ -27,6 +48,13 @@ interface UpdateMethodResolutionOptions {
27
48
  miseBinDirs?: readonly string[];
28
49
  miseDataDir?: string;
29
50
  npmBinDir?: string;
51
+ /**
52
+ * Whether the resolved omp path is a plain file (the standalone binary)
53
+ * rather than a package-manager symlink. Stops a binary install from being
54
+ * misrouted to npm/bun when the global bin dir overlaps the installer's
55
+ * target directory.
56
+ */
57
+ ompIsRegularFile?: boolean;
30
58
  }
31
59
  export declare function resolveUpdateMethodForTest(ompPath: string, bunBinDir: string | undefined, options?: UpdateMethodResolutionOptions): UpdateMethod;
32
60
  interface BunInstallCachePruneResult {
@@ -44,6 +72,10 @@ interface BunInstallCachePruneResult {
44
72
  */
45
73
  export declare function pruneBunInstallCache(cacheDir: string, packageNames?: Set<string>): Promise<BunInstallCachePruneResult>;
46
74
  export declare function resolveBunGlobalNodeModulesDirFromLocations(globalBinDir: string | undefined, cacheDir: string | undefined): string | undefined;
75
+ /**
76
+ * Run the resolved omp binary and check if it reports the expected version.
77
+ */
78
+ declare function verifyInstalledVersion(expectedVersion: string): Promise<InstalledVersionVerification>;
47
79
  /**
48
80
  * Best-effort removal of binary-update backups left by earlier runs.
49
81
  *
@@ -95,6 +127,15 @@ export declare function buildNpmInstallArgs(expectedVersion: string, nativeTag?:
95
127
  export declare function buildHomebrewUpdateArgs(force: boolean): string[];
96
128
  export declare function buildMiseUpgradeArgs(): string[];
97
129
  export declare function buildMiseForceInstallArgs(expectedVersion: string): string[];
130
+ /**
131
+ * Download a release binary to a target path, replacing an existing file.
132
+ */
133
+ export declare function updateViaBinaryAt(targetPath: string, expectedVersion: string, options?: {
134
+ binaryName?: string;
135
+ fetchImpl?: Fetch;
136
+ githubToken?: string;
137
+ verifyInstalledVersion?: typeof verifyInstalledVersion;
138
+ }): Promise<void>;
98
139
  /**
99
140
  * Run the update command.
100
141
  */
@@ -7,7 +7,7 @@
7
7
  * credentials produced no usage report are listed too, so the output
8
8
  * always covers the full credential pool.
9
9
  */
10
- import { type UsageHistoryEntry, type UsageReport } from "@oh-my-pi/pi-ai";
10
+ import { type DisabledCredentialSummary, type UsageHistoryEntry, type UsageReport } from "@oh-my-pi/pi-ai";
11
11
  export interface UsageCommandArgs {
12
12
  action?: string;
13
13
  json?: boolean;
@@ -29,6 +29,8 @@ export interface UsageAccountIdentity {
29
29
  /** Organization/workspace the credential is scoped to (Anthropic multi-subscription). */
30
30
  orgId?: string;
31
31
  orgName?: string;
32
+ /** Epoch ms of the interactive login that minted the OAuth grant (see `OAuthCredentials.authorizedAt`). */
33
+ authorizedAt?: number;
32
34
  }
33
35
  /**
34
36
  * Minimal-reveal masks for identity strings (`--redact`).
@@ -76,7 +78,7 @@ export declare function computeProviderWindowStats(reports: UsageReport[]): Prov
76
78
  * with a bar, amounts, and reset times; unattributed credentials trail
77
79
  * each provider section as "no usage data" rows.
78
80
  */
79
- export declare function formatUsageBreakdown(reports: UsageReport[], accounts: UsageAccountIdentity[], nowMs: number, redaction?: Map<string, string>): string;
81
+ export declare function formatUsageBreakdown(reports: UsageReport[], accounts: UsageAccountIdentity[], nowMs: number, redaction?: Map<string, string>, disabled?: DisabledCredentialSummary[]): string;
80
82
  /**
81
83
  * Render recorded usage-limit history: per provider, per account, one
82
84
  * peak-per-bucket sparkline per limit window plus latest/peak percentages.
@@ -21,5 +21,6 @@ export default class Update extends Command {
21
21
  default: boolean;
22
22
  };
23
23
  };
24
+ static examples: string[];
24
25
  run(): Promise<void>;
25
26
  }
@@ -55,6 +55,16 @@ export interface ProviderDiscoveryState {
55
55
  models: string[];
56
56
  error?: string;
57
57
  }
58
+ /** Authentication material returned to legacy extensions for one model request. */
59
+ export type ResolvedRequestAuth = {
60
+ ok: true;
61
+ apiKey?: string;
62
+ headers?: Record<string, string>;
63
+ env?: Record<string, string>;
64
+ } | {
65
+ ok: false;
66
+ error: string;
67
+ };
58
68
  /**
59
69
  * Model registry - loads and manages models, resolves API keys via AuthStorage.
60
70
  */
@@ -71,6 +81,13 @@ export declare class ModelRegistry {
71
81
  * `tryLoad()` runs.
72
82
  */
73
83
  constructor(authStorage: AuthStorage, modelsPath?: string, options?: {
84
+ /**
85
+ * Gateway mode: ignore local `models.yml` entirely (provider overrides,
86
+ * config API keys, custom models, custom discovery). A broker-backed
87
+ * gateway serves only bundled + broker-discovered catalog metadata and
88
+ * must never apply client-side credential or routing overrides.
89
+ */
90
+ ignoreLocalModelConfig?: boolean;
74
91
  fetch?: FetchImpl;
75
92
  });
76
93
  /**
@@ -178,6 +195,8 @@ export declare class ModelRegistry {
178
195
  getApiKey(model: Model<Api>, sessionId?: string, options?: {
179
196
  signal?: AbortSignal;
180
197
  }): Promise<string | undefined>;
198
+ /** Resolve request authentication through the historical Pi extension facade. */
199
+ getApiKeyAndHeaders(model: Model<Api>): Promise<ResolvedRequestAuth>;
181
200
  /**
182
201
  * Get API key for a provider (e.g., "openai").
183
202
  *
@@ -85,33 +85,44 @@ export type AnyUiMetadata = UiBase & {
85
85
  secret?: boolean;
86
86
  ordered?: boolean;
87
87
  };
88
- interface BooleanDef {
88
+ /**
89
+ * Marks a setting whose value is a credential.
90
+ *
91
+ * Lives at the top level rather than inside `ui` so it can also describe a
92
+ * setting the settings panel never shows and therefore cannot carry
93
+ * `ui.secret`. Read it through `isCredential`, which is the single accessor
94
+ * both the CLI and the settings panel consult.
95
+ */
96
+ interface CredentialMarker {
97
+ credential?: true;
98
+ }
99
+ interface BooleanDef extends CredentialMarker {
89
100
  type: "boolean";
90
101
  default: boolean | undefined;
91
102
  ui?: UiBoolean;
92
103
  }
93
- interface StringDef {
104
+ interface StringDef extends CredentialMarker {
94
105
  type: "string";
95
106
  default: string | undefined;
96
107
  ui?: UiString;
97
108
  }
98
- interface NumberDef {
109
+ interface NumberDef extends CredentialMarker {
99
110
  type: "number";
100
111
  default: number | undefined;
101
112
  ui?: UiNumber;
102
113
  }
103
- interface EnumDef<T extends readonly string[]> {
114
+ interface EnumDef<T extends readonly string[]> extends CredentialMarker {
104
115
  type: "enum";
105
116
  values: T;
106
117
  default: T[number];
107
118
  ui?: UiEnum<T>;
108
119
  }
109
- interface ArrayDef<T> {
120
+ interface ArrayDef<T> extends CredentialMarker {
110
121
  type: "array";
111
122
  default: T[];
112
123
  ui?: UiArray;
113
124
  }
114
- interface RecordDef<T> {
125
+ interface RecordDef<T> extends CredentialMarker {
115
126
  type: "record";
116
127
  default: Record<string, T>;
117
128
  ui?: UiBase;
@@ -139,6 +150,7 @@ export declare const SETTINGS_SCHEMA: {
139
150
  readonly "auth.broker.token": {
140
151
  readonly type: "string";
141
152
  readonly default: undefined;
153
+ readonly credential: true;
142
154
  };
143
155
  readonly autoResume: {
144
156
  readonly type: "boolean";
@@ -2843,6 +2855,7 @@ export declare const SETTINGS_SCHEMA: {
2843
2855
  };
2844
2856
  readonly "mnemopi.embeddingApiKey": {
2845
2857
  readonly type: "string";
2858
+ readonly credential: true;
2846
2859
  readonly default: undefined;
2847
2860
  readonly ui: {
2848
2861
  readonly tab: "memory";
@@ -2890,6 +2903,7 @@ export declare const SETTINGS_SCHEMA: {
2890
2903
  };
2891
2904
  readonly "mnemopi.llmApiKey": {
2892
2905
  readonly type: "string";
2906
+ readonly credential: true;
2893
2907
  readonly default: undefined;
2894
2908
  readonly ui: {
2895
2909
  readonly tab: "memory";
@@ -2947,6 +2961,7 @@ export declare const SETTINGS_SCHEMA: {
2947
2961
  };
2948
2962
  readonly "hindsight.apiToken": {
2949
2963
  readonly type: "string";
2964
+ readonly credential: true;
2950
2965
  readonly default: undefined;
2951
2966
  readonly ui: {
2952
2967
  readonly tab: "memory";
@@ -2954,7 +2969,6 @@ export declare const SETTINGS_SCHEMA: {
2954
2969
  readonly label: "Hindsight API Token";
2955
2970
  readonly description: "Bearer token for authenticated Hindsight servers";
2956
2971
  readonly condition: "hindsightActive";
2957
- readonly secret: true;
2958
2972
  };
2959
2973
  };
2960
2974
  readonly "hindsight.bankId": {
@@ -5798,6 +5812,7 @@ export declare const SETTINGS_SCHEMA: {
5798
5812
  readonly "searxng.token": {
5799
5813
  readonly type: "string";
5800
5814
  readonly default: undefined;
5815
+ readonly credential: true;
5801
5816
  };
5802
5817
  readonly "searxng.basicUsername": {
5803
5818
  readonly type: "string";
@@ -5806,6 +5821,7 @@ export declare const SETTINGS_SCHEMA: {
5806
5821
  readonly "searxng.basicPassword": {
5807
5822
  readonly type: "string";
5808
5823
  readonly default: undefined;
5824
+ readonly credential: true;
5809
5825
  };
5810
5826
  readonly "searxng.categories": {
5811
5827
  readonly type: "string";
@@ -5866,6 +5882,7 @@ export declare const SETTINGS_SCHEMA: {
5866
5882
  readonly "dev.autoqaPush.token": {
5867
5883
  readonly type: "string";
5868
5884
  readonly default: undefined;
5885
+ readonly credential: true;
5869
5886
  };
5870
5887
  /**
5871
5888
  * User decision on sharing automatic `report_tool_issue` grievances.
@@ -5964,6 +5981,12 @@ export type SettingValue<P extends SettingPath> = Schema[P] extends {
5964
5981
  export declare function getDefault<P extends SettingPath>(path: P): SettingValue<P>;
5965
5982
  /** Check if a path has UI metadata (should appear in settings panel) */
5966
5983
  export declare function hasUi(path: SettingPath): boolean;
5984
+ /**
5985
+ * Whether a setting holds a credential and must never be printed or exported
5986
+ * without an explicit request. Drives both CLI redaction and settings-panel
5987
+ * masking, so the two cannot disagree.
5988
+ */
5989
+ export declare function isCredential(path: SettingPath): boolean;
5967
5990
  /** Get UI metadata for a path (undefined if no UI) */
5968
5991
  export declare function getUi(path: SettingPath): AnyUiMetadata | undefined;
5969
5992
  /** Get all paths for a specific tab */
@@ -1,5 +1,6 @@
1
1
  import type { AgentEvent, AgentTool, AgentToolContext } from "@oh-my-pi/pi-agent-core";
2
- import type { CursorMcpCall, CursorShellStreamCallbacks, CursorExecHandlers as ICursorExecHandlers, ToolResultMessage } from "@oh-my-pi/pi-ai";
2
+ import type { CursorMcpCall, CursorShellStreamCallbacks, CursorTodoSnapshot, CursorExecHandlers as ICursorExecHandlers, ToolResultMessage } from "@oh-my-pi/pi-ai";
3
+ import type { TodoPhase } from "./tools/todo.js";
3
4
  interface CursorExecBridgeOptions {
4
5
  cwd: string;
5
6
  getCwd?: () => string;
@@ -16,6 +17,18 @@ interface CursorExecBridgeOptions {
16
17
  * callers with a restricted tool set (advisors) opt out.
17
18
  */
18
19
  allowNativeDelete?: boolean;
20
+ /**
21
+ * Mirror Cursor's server-owned todo list into local session state. Cursor
22
+ * resolves `update_todos` / `read_todos` remotely, so without this bridge
23
+ * the provider's list and the local `todo` state diverge silently.
24
+ */
25
+ setTodoPhases?: (phases: TodoPhase[]) => void;
26
+ getTodoPhases?: () => TodoPhase[];
27
+ /**
28
+ * Persist the mirrored list to the session branch so it survives reloads.
29
+ * Cursor emits no local `todo` toolResult, so nothing else records it.
30
+ */
31
+ persistTodoPhases?: (phases: TodoPhase[]) => void;
19
32
  }
20
33
  export declare class CursorExecHandlers implements ICursorExecHandlers {
21
34
  private options;
@@ -28,6 +41,39 @@ export declare class CursorExecHandlers implements ICursorExecHandlers {
28
41
  shell(args: Parameters<NonNullable<ICursorExecHandlers["shell"]>>[0]): Promise<ToolResultMessage<unknown>>;
29
42
  shellStream(args: Parameters<NonNullable<ICursorExecHandlers["shellStream"]>>[0], callbacks: CursorShellStreamCallbacks): Promise<ToolResultMessage<unknown>>;
30
43
  diagnostics(args: Parameters<NonNullable<ICursorExecHandlers["diagnostics"]>>[0]): Promise<ToolResultMessage<unknown>>;
44
+ /**
45
+ * Settle a completed native Cursor todo call, mirroring its list when the
46
+ * server supplied an authoritative one.
47
+ *
48
+ * Cursor's snapshot is a flat list, so tasks already known locally keep
49
+ * their phase and only their status is updated; unknown tasks land in a
50
+ * single fallback phase. Statuses come straight from the server snapshot —
51
+ * no local normalization, or an all-pending remote list would gain a
52
+ * phantom in-progress task the remote list does not have.
53
+ *
54
+ * The snapshot is also persisted to the session branch. Every other
55
+ * provider's todo state survives a reload because `todo` runs locally and
56
+ * its `toolResult` (carrying `details.phases`) lands in the branch, which
57
+ * `#syncTodoPhasesFromBranch` replays. Cursor resolves the tool remotely and
58
+ * emits no such result, so without an explicit entry the list is in-memory
59
+ * only and every reload, rewind, compaction, or session switch drops it.
60
+ *
61
+ * This ALWAYS settles the call and returns the result to persist, even when
62
+ * nothing is mirrored. Two reasons it cannot bail out early:
63
+ *
64
+ * - the interactive card leaves `pendingTools` only on a matching
65
+ * `tool_execution_end`, so staying silent leaves it animating forever;
66
+ * - an unpaired `toolCall` is stripped as dangling by `buildSessionContext`,
67
+ * erasing the interaction from every rebuilt transcript.
68
+ *
69
+ * A `null` snapshot means nothing may be mirrored — a server `error`, or a
70
+ * benign refusal: a filtered, truncated, or empty read, or a snapshot the
71
+ * local model cannot represent. Local state is left untouched, and the result
72
+ * carries no `details` (text `"Todo snapshot not mirrored"`): `event-controller`
73
+ * feeds `details.phases` straight into `setTodos`, so echoing the current list
74
+ * back would let a call that changed nothing overwrite live UI state.
75
+ */
76
+ todoSync(snapshot: CursorTodoSnapshot | null, toolCallId: string, error?: string | null): ToolResultMessage;
31
77
  mcp(call: CursorMcpCall): Promise<ToolResultMessage<unknown>>;
32
78
  }
33
79
  export {};
@@ -1,6 +1,7 @@
1
+ import { type RejectionInterceptor } from "./worker-core.js";
1
2
  import type { WorkerInbound, WorkerOutbound } from "./worker-protocol.js";
2
3
  /** Start the JavaScript evaluator inside a subprocess IPC transport. */
3
4
  export declare function startJsEvalProcess(transport: {
4
5
  send(message: WorkerOutbound): void;
5
6
  onMessage(handler: (message: WorkerInbound) => void): () => void;
6
- }): void;
7
+ }, interceptUnhandledRejections: RejectionInterceptor): void;
@@ -1,4 +1,5 @@
1
1
  import type { Transport } from "./worker-protocol.js";
2
+ export type RejectionInterceptor = (handler: (reason: unknown) => boolean) => () => void;
2
3
  export type WorkerCoreOptions = {
3
4
  mode: "isolated";
4
5
  /**
@@ -9,9 +10,11 @@ export type WorkerCoreOptions = {
9
10
  * mutate the host's own cwd on the inline fallback.
10
11
  */
11
12
  chdir?: (cwd: string) => void;
13
+ /** Share the subprocess host's fatal-rejection guard when one is installed. */
14
+ interceptUnhandledRejections?: RejectionInterceptor;
12
15
  } | {
13
16
  mode: "inline";
14
- interceptUnhandledRejections(handler: (reason: unknown) => boolean): () => void;
17
+ interceptUnhandledRejections: RejectionInterceptor;
15
18
  };
16
19
  export declare class WorkerCore {
17
20
  #private;
@@ -86,6 +86,7 @@ export declare class ExtensionRunner {
86
86
  * {@link onError} via {@link emit}'s normal isolation.
87
87
  */
88
88
  emitCredentialDisabled(event: CredentialDisabledEvent): Promise<void>;
89
+ /** Emits a session stop pass that can be cancelled with the active settle signal. */
89
90
  emitSessionStop(event: Omit<SessionStopEvent, "type">): Promise<SessionStopEventResult | undefined>;
90
91
  getUIContext(): ExtensionUIContext;
91
92
  hasUI(): boolean;
@@ -19,6 +19,8 @@
19
19
  * `types.ts` via the `export *` below — pi-ai still exports both as types,
20
20
  * only the runtime `Type` builder and `StringEnum()` helper were removed.
21
21
  */
22
+ import type { Api, Model } from "@oh-my-pi/pi-ai";
23
+ import type { Effort } from "@oh-my-pi/pi-catalog/effort";
22
24
  import { calculateCost, getBundledModel, getBundledModels, getBundledProviders, modelsAreEqual } from "@oh-my-pi/pi-catalog/models";
23
25
  import { type TSchema, Type } from "./typebox.js";
24
26
  export interface StringEnumOptions<T extends string> {
@@ -28,6 +30,8 @@ export interface StringEnumOptions<T extends string> {
28
30
  [key: string]: unknown;
29
31
  }
30
32
  export declare function StringEnum<T extends string | number>(values: readonly T[] | Record<string, T>, options?: StringEnumOptions<any>): TSchema;
33
+ /** Clamp a historical Pi thinking level against OMP's model metadata. */
34
+ export declare function clampThinkingLevel<TApi extends Api>(model: Model<TApi>, level: Effort | "off"): Effort | "off";
31
35
  export * from "@oh-my-pi/pi-ai";
32
36
  /**
33
37
  * Compatibility re-exports for catalog symbols that pi-ai historically exposed
@@ -17,6 +17,7 @@ import type { PromptTemplate } from "../config/prompt-templates.js";
17
17
  import { Settings } from "../config/settings.js";
18
18
  import type { CreateAgentSessionOptions, CreateAgentSessionResult, LoadExtensionsResult } from "../sdk.js";
19
19
  import { EventBus } from "../utils/event-bus.js";
20
+ import { ExtensionRuntime } from "./extensions/loader.js";
20
21
  import type { ExtensionFactory, ToolDefinition } from "./extensions/types.js";
21
22
  import type { Skill } from "./skills.js";
22
23
  export interface BashSpawnContext {
@@ -272,6 +273,8 @@ export interface ResourceLoader {
272
273
  /** @internal — used by the shim's createAgentSession to detect its own loaders. */
273
274
  readonly __ompLegacyPiLoader?: true;
274
275
  }
276
+ /** Create a pre-initialization runtime for legacy extension resource loaders. */
277
+ export declare function createExtensionRuntime(): ExtensionRuntime;
275
278
  export declare class DefaultResourceLoader implements ResourceLoader {
276
279
  #private;
277
280
  readonly __ompLegacyPiLoader: true;
@@ -372,6 +375,7 @@ export { getProjectDir } from "@oh-my-pi/pi-utils";
372
375
  * canonical helper.
373
376
  */
374
377
  export declare function getPackageDir(): string;
378
+ export { estimateTokens } from "@oh-my-pi/pi-agent-core/compaction";
375
379
  export * from "../index.js";
376
380
  export { formatBytes as formatSize } from "../tools/render-utils.js";
377
381
  export { copyToClipboard } from "../utils/clipboard.js";
@@ -1,10 +1,18 @@
1
+ export * from "@oh-my-pi/pi-tui";
2
+ export { decodePrintableKey as decodeKittyPrintable } from "@oh-my-pi/pi-tui";
3
+ /** Report canonical terminal capabilities through the legacy Pi TUI shape. */
4
+ export declare function getCapabilities(): {
5
+ images: "kitty" | "iterm2" | null;
6
+ trueColor: boolean;
7
+ hyperlinks: boolean;
8
+ };
1
9
  /**
2
- * Compatibility shim for legacy extensions importing the package root of
3
- * `@earendil-works/pi-tui` or `@mariozechner/pi-tui`.
10
+ * Delete one Kitty graphics image by id, matching the legacy Pi TUI helper.
4
11
  *
5
- * The historical root exported `decodeKittyPrintable`; the canonical TUI now
6
- * exposes the equivalent, broader `decodePrintableKey` helper. Keep the legacy
7
- * name available without reintroducing it into the canonical package surface.
12
+ * Returns the bare control sequence exactly like upstream Pi: legacy callers
13
+ * (e.g. pi-sprite) apply their own tmux passthrough wrapping, so wrapping here
14
+ * would double-wrap under tmux and the outer terminal would drop the command.
8
15
  */
9
- export * from "@oh-my-pi/pi-tui";
10
- export { decodePrintableKey as decodeKittyPrintable } from "@oh-my-pi/pi-tui";
16
+ export declare function deleteKittyImage(imageId: number): string;
17
+ /** Delete every Kitty graphics image using the legacy Pi TUI bare sequence. */
18
+ export declare function deleteAllKittyImages(): string;
@@ -88,6 +88,8 @@ export interface SessionStopEvent {
88
88
  session_id: string;
89
89
  session_file?: string;
90
90
  stop_hook_active: boolean;
91
+ /** Cancels handler waiting when the active settle pass is aborted. */
92
+ signal: AbortSignal;
91
93
  }
92
94
  /** Preparation data for tree navigation (used by session_before_tree event) */
93
95
  export interface TreePreparation {
@@ -33,6 +33,15 @@ export declare class AssistantMessageComponent extends Container {
33
33
  * pinned in the banner above the editor. Re-renders so the change is visible.
34
34
  */
35
35
  setErrorPinned(pinned: boolean): void;
36
+ /**
37
+ * Expand or collapse the inline turn-ending error block so Ctrl+O
38
+ * (tool-output expansion) can reveal a long provider error's hidden tail.
39
+ * Only re-renders when the current message carries a truncatable error, so
40
+ * toggling expansion across the transcript skips ordinary turns. Works even
41
+ * while the error is pinned in the banner: the inline block is drawn (in full)
42
+ * when expanded so the complete body is reachable without sending a message.
43
+ */
44
+ setExpanded(expanded: boolean): void;
36
45
  isTranscriptBlockFinalized(): boolean;
37
46
  /**
38
47
  * Settled leading rows for mid-stream native-scrollback commits (see
@@ -26,15 +26,21 @@ export declare const SPACE_HOLD_RELEASE_MS = 250;
26
26
  * read directly via `pbpaste`/PowerShell).
27
27
  */
28
28
  export declare function extractPastePathsFromText(text: string): string[] | undefined;
29
- export declare function extractBracketedPastePaths(data: string): string[] | undefined;
30
- export declare function extractBracketedImagePastePaths(data: string): string[] | undefined;
31
29
  /**
32
30
  * Same shape as {@link extractBracketedImagePastePaths} but operates on a
33
31
  * payload that has already been stripped of the `\x1b[200~` / `\x1b[201~`
34
32
  * markers — used by the assembled-paste router in {@link CustomEditor.handleInput}
35
33
  * so split bracketed pastes get the same image-path detection as single-chunk ones.
34
+ *
35
+ * When the segment splitter fails (an unescaped space in a real path breaks
36
+ * its every-segment-is-a-path invariant), falls back to
37
+ * {@link extractWholeTextImagePath}, so a dropped macOS screenshot
38
+ * (`Screenshot 2026-06-25 at 1.23.45 PM.png`) attaches as an image instead of
39
+ * degrading to literal text (#6578).
36
40
  */
37
41
  export declare function extractImagePastePathsFromText(text: string): string[] | undefined;
42
+ export declare function extractBracketedPastePaths(data: string): string[] | undefined;
43
+ export declare function extractBracketedImagePastePaths(data: string): string[] | undefined;
38
44
  export declare function extractBracketedImagePastePath(data: string): string | undefined;
39
45
  /**
40
46
  * Return a single image file path when `text` is exactly one explicit path
@@ -52,12 +58,10 @@ export declare function extractBracketedImagePastePath(data: string): string | u
52
58
  * ambiguous multi-path clipboard text like `/tmp/a.png /tmp/b.png`
53
59
  * still falls through to the text fallback instead of being mis-loaded
54
60
  * as one giant path).
55
- * 2. Whole-text-as-path pass — only reached when the splitter failed
56
- * (every segment must look like an explicit path; an unescaped space in
57
- * a real path breaks that). Restricted to inputs anchored by
58
- * {@link ABSOLUTE_PATH_PREFIX_REGEX} so prose containing a path-shaped
59
- * fragment ("see /tmp/x.png") never hijacks the smart fallback. This
60
- * is what recovers macOS screenshot filenames like
61
+ * 2. {@link extractWholeTextImagePath} — only reached when the splitter
62
+ * failed (every segment must look like an explicit path; an unescaped
63
+ * space in a real path breaks that). This is what recovers macOS
64
+ * screenshot filenames like
61
65
  * `/Users/me/Desktop/Screenshot 2026-06-25 at 1.23.45 PM.png`.
62
66
  */
63
67
  export declare function extractImagePathFromText(text: string): string | undefined;
@@ -63,6 +63,7 @@ export interface ResolvedApprovedPlan {
63
63
  }
64
64
  /** Locate the plan file the agent wrote and finalize its title — without
65
65
  * renaming anything. Tries, in order: the slug derived from `extra.title`
66
- * (`local://<slug>-plan.md`), the plan path from plan-mode state, then a scan
67
- * of recent plan files. Throws a `ToolError` guiding the agent when none exist. */
66
+ * (`local://<slug>-plan.md`), a state plan that the artifact scan can't see,
67
+ * scanned plan files newest-to-oldest, then the state plan path as a final
68
+ * fallback. Throws a `ToolError` guiding the agent when none exist. */
68
69
  export declare function resolveApprovedPlan(input: ResolveApprovedPlanInput): Promise<ResolvedApprovedPlan>;
@@ -88,28 +88,12 @@ export declare class SecretObfuscator {
88
88
  #private;
89
89
  constructor(entries: SecretEntry[], key?: string);
90
90
  hasSecrets(): boolean;
91
- /** Whether stored-session restoration can resolve keyed or legacy placeholders. */
92
- hasStoredSecrets(): boolean;
93
91
  /** Obfuscate all secrets in text. Bidirectional placeholders for obfuscate mode, one-way for replace. */
94
92
  obfuscate(text: string, sharedRegexSecretValues?: ReadonlySet<string>): string;
95
- /**
96
- * Deobfuscate keyed placeholders back to original secrets for LIVE paths
97
- * (provider output, tool-call arguments). Replace-mode is NOT reversed, and
98
- * legacy index-derived aliases are intentionally ignored so a prompt-injected
99
- * model cannot synthesize one to recover a secret.
100
- */
93
+ /** Deobfuscate keyed placeholders for provider output, tool-call arguments, replay, and display. */
101
94
  deobfuscate(text: string): string;
102
- /**
103
- * Deobfuscate stored session content for replay/display. Identical to
104
- * {@link deobfuscate} but additionally honors legacy index-derived aliases so
105
- * sessions persisted before keyed placeholders still resume correctly. Use
106
- * only for trusted on-disk session content, never for live model output.
107
- */
108
- deobfuscateStored(text: string): string;
109
95
  /** Deep-walk an object, deobfuscating string values for LIVE paths (keyed placeholders only). */
110
96
  deobfuscateObject<T>(obj: T): T;
111
- /** Deep-walk stored session content, deobfuscating string values incl. legacy aliases. */
112
- deobfuscateStoredObject<T>(obj: T): T;
113
97
  /** Deep-walk an object, obfuscating all string values. */
114
98
  obfuscateObject<T>(obj: T): T;
115
99
  collectRegexSecretValuesForObfuscation(text: string): Set<string>;
@@ -119,31 +103,23 @@ export declare class SecretObfuscator {
119
103
  * Restore secret placeholders for local display. Only message kinds the model
120
104
  * itself authored from obfuscated context carry placeholders — assistant
121
105
  * content and the LLM-written branch/compaction summaries. User, developer, and
122
- * tool-result messages are persisted with their literal text, so a literal
123
- * `#ABCD#` the operator typed must survive untouched; those roles are never
124
- * walked.
125
- *
126
- * Legacy index-derived aliases (`#XXXX#`) are unkeyed and trivially guessable,
127
- * so a prompt-injected model can plant one in any record it influences. Every
128
- * agent-feeding path (resume, history rewrite, branch switch) therefore restores
129
- * keyed placeholders ONLY (`allowLegacyAliases` false), leaving legacy tokens
130
- * inert; display-only transcripts that are never re-obfuscated opt in via
131
- * `allowLegacyAliases`.
106
+ * tool-result messages are persisted with their literal text, so operator-authored
107
+ * placeholder-shaped text must survive untouched; those roles are never walked.
132
108
  */
133
- export declare function deobfuscateSessionContext(sessionContext: SessionContext, obfuscator: SecretObfuscator | undefined, allowLegacyAliases?: boolean): SessionContext;
134
- export declare function deobfuscateAgentMessages(obfuscator: SecretObfuscator, messages: AgentMessage[], allowLegacyAliases?: boolean): AgentMessage[];
109
+ export declare function deobfuscateSessionContext(sessionContext: SessionContext, obfuscator: SecretObfuscator | undefined): SessionContext;
110
+ export declare function deobfuscateAgentMessages(obfuscator: SecretObfuscator, messages: AgentMessage[]): AgentMessage[];
135
111
  /**
136
112
  * Restore placeholders in assistant content: visible text and tool-call
137
113
  * arguments/intent/rawBlock. Thinking and signatures are opaque
138
114
  * provider-replay/hidden-reasoning data and pass through byte-identical.
139
115
  */
140
- export declare function deobfuscateAssistantContent(obfuscator: SecretObfuscator, content: AssistantMessage["content"], allowLegacyAliases?: boolean): AssistantMessage["content"];
116
+ export declare function deobfuscateAssistantContent(obfuscator: SecretObfuscator, content: AssistantMessage["content"]): AssistantMessage["content"];
141
117
  /**
142
118
  * Restore placeholders inside a tool call's arguments. Arguments are arbitrary
143
119
  * model-authored JSON, so tool-call arguments are the ONLY place a recursive
144
120
  * JSON walk runs.
145
121
  */
146
- export declare function deobfuscateToolArguments(obfuscator: SecretObfuscator, args: Record<string, unknown>, allowLegacyAliases?: boolean): Record<string, unknown>;
122
+ export declare function deobfuscateToolArguments(obfuscator: SecretObfuscator, args: Record<string, unknown>): Record<string, unknown>;
147
123
  /** Redact secrets inside a tool call's arguments (same JSON-walk exception as {@link deobfuscateToolArguments}). */
148
124
  export declare function obfuscateToolArguments(obfuscator: SecretObfuscator, args: Record<string, unknown>, sharedRegexSecretValues?: ReadonlySet<string>): Record<string, unknown>;
149
125
  /**