@oh-my-pi/pi-coding-agent 17.0.7 → 17.0.9

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 (153) hide show
  1. package/CHANGELOG.md +91 -0
  2. package/dist/cli.js +5025 -4930
  3. package/dist/types/config/__tests__/model-registry.test.d.ts +1 -0
  4. package/dist/types/config/model-registry.d.ts +28 -1
  5. package/dist/types/config/model-resolver.d.ts +5 -1
  6. package/dist/types/config/settings-schema.d.ts +50 -3
  7. package/dist/types/dap/client.d.ts +19 -0
  8. package/dist/types/extensibility/extensions/runner.d.ts +4 -2
  9. package/dist/types/extensibility/extensions/types.d.ts +3 -0
  10. package/dist/types/extensibility/legacy-pi-coding-agent-shim.d.ts +1 -0
  11. package/dist/types/extensibility/legacy-pi-tui-shim.d.ts +10 -0
  12. package/dist/types/extensibility/plugins/legacy-pi-compat.d.ts +1 -1
  13. package/dist/types/extensibility/typebox.d.ts +4 -0
  14. package/dist/types/hindsight/client.d.ts +10 -0
  15. package/dist/types/hindsight/config.d.ts +8 -0
  16. package/dist/types/internal-urls/registry-helpers.d.ts +11 -0
  17. package/dist/types/lsp/client.d.ts +2 -0
  18. package/dist/types/mcp/manager.d.ts +6 -2
  19. package/dist/types/mcp/render.d.ts +2 -2
  20. package/dist/types/mcp/tool-bridge.d.ts +16 -3
  21. package/dist/types/mcp/types.d.ts +6 -0
  22. package/dist/types/mnemopi/state.d.ts +2 -0
  23. package/dist/types/modes/components/oauth-selector.d.ts +8 -0
  24. package/dist/types/modes/components/settings-defs.d.ts +1 -0
  25. package/dist/types/modes/components/user-message.d.ts +25 -1
  26. package/dist/types/modes/controllers/extension-ui-controller.d.ts +8 -0
  27. package/dist/types/modes/controllers/mcp-command-controller.d.ts +3 -0
  28. package/dist/types/modes/interactive-mode.d.ts +7 -1
  29. package/dist/types/modes/rpc/rpc-client.d.ts +10 -1
  30. package/dist/types/modes/rpc/rpc-frame.d.ts +16 -0
  31. package/dist/types/modes/rpc/rpc-messages.d.ts +26 -0
  32. package/dist/types/modes/rpc/rpc-types.d.ts +40 -0
  33. package/dist/types/modes/setup-wizard/scenes/sign-in.d.ts +1 -1
  34. package/dist/types/modes/setup-wizard/scenes/types.d.ts +9 -1
  35. package/dist/types/modes/setup-wizard/scenes/web-search.d.ts +1 -1
  36. package/dist/types/modes/types.d.ts +14 -1
  37. package/dist/types/modes/utils/ui-helpers.d.ts +12 -8
  38. package/dist/types/sdk.d.ts +1 -0
  39. package/dist/types/session/agent-session-error-log.test.d.ts +1 -0
  40. package/dist/types/session/agent-session.d.ts +86 -3
  41. package/dist/types/session/session-loader.d.ts +6 -4
  42. package/dist/types/task/executor.d.ts +10 -0
  43. package/dist/types/task/index.d.ts +1 -0
  44. package/dist/types/task/prewalk.d.ts +3 -0
  45. package/dist/types/task/types.d.ts +14 -0
  46. package/dist/types/tools/ask.d.ts +10 -0
  47. package/dist/types/tools/hub/jobs.d.ts +1 -1
  48. package/dist/types/tools/index.d.ts +3 -0
  49. package/dist/types/tools/report-tool-issue.d.ts +24 -9
  50. package/dist/types/tools/tool-timeouts.d.ts +8 -2
  51. package/dist/types/utils/changelog.d.ts +4 -6
  52. package/dist/types/web/search/providers/firecrawl.d.ts +9 -0
  53. package/dist/types/web/search/types.d.ts +1 -1
  54. package/package.json +13 -13
  55. package/scripts/legacy-pi-virtual-module.ts +1 -1
  56. package/src/cli/grievances-cli.ts +2 -2
  57. package/src/cli/models-cli.ts +37 -17
  58. package/src/cli/update-cli.ts +14 -1
  59. package/src/cli/usage-cli.ts +1 -1
  60. package/src/config/__tests__/model-registry.test.ts +147 -0
  61. package/src/config/model-registry.ts +87 -24
  62. package/src/config/model-resolver.ts +56 -32
  63. package/src/config/settings-schema.ts +46 -3
  64. package/src/config/settings.ts +68 -5
  65. package/src/dap/client.ts +86 -7
  66. package/src/edit/diff.ts +4 -4
  67. package/src/eval/py/prelude.py +5 -5
  68. package/src/export/html/template.js +23 -9
  69. package/src/extensibility/extensions/runner.ts +9 -4
  70. package/src/extensibility/extensions/types.ts +3 -0
  71. package/src/extensibility/legacy-pi-coding-agent-shim.ts +1 -0
  72. package/src/extensibility/legacy-pi-tui-shim.ts +10 -0
  73. package/src/extensibility/plugins/legacy-pi-compat.ts +851 -310
  74. package/src/extensibility/typebox.ts +22 -9
  75. package/src/hindsight/client.test.ts +42 -0
  76. package/src/hindsight/client.ts +40 -3
  77. package/src/hindsight/config.ts +18 -0
  78. package/src/internal-urls/registry-helpers.ts +40 -0
  79. package/src/launch/broker.ts +31 -5
  80. package/src/lsp/client.ts +23 -0
  81. package/src/lsp/clients/biome-client.ts +3 -4
  82. package/src/lsp/index.ts +26 -8
  83. package/src/main.ts +16 -5
  84. package/src/mcp/manager.ts +39 -8
  85. package/src/mcp/render.ts +94 -35
  86. package/src/mcp/tool-bridge.ts +116 -11
  87. package/src/mcp/types.ts +7 -0
  88. package/src/mnemopi/state.ts +70 -3
  89. package/src/modes/components/agent-dashboard.ts +6 -2
  90. package/src/modes/components/agent-hub.ts +26 -9
  91. package/src/modes/components/chat-transcript-builder.ts +13 -2
  92. package/src/modes/components/diff.ts +2 -2
  93. package/src/modes/components/oauth-selector.ts +24 -7
  94. package/src/modes/components/plan-review-overlay.ts +20 -4
  95. package/src/modes/components/settings-defs.ts +5 -2
  96. package/src/modes/components/settings-selector.ts +9 -5
  97. package/src/modes/components/tool-execution.test.ts +63 -2
  98. package/src/modes/components/user-message.ts +100 -1
  99. package/src/modes/controllers/command-controller.ts +36 -12
  100. package/src/modes/controllers/event-controller.ts +4 -1
  101. package/src/modes/controllers/extension-ui-controller.ts +18 -0
  102. package/src/modes/controllers/input-controller.ts +47 -12
  103. package/src/modes/controllers/mcp-command-controller.ts +70 -40
  104. package/src/modes/controllers/selector-controller.ts +82 -6
  105. package/src/modes/interactive-mode.ts +39 -4
  106. package/src/modes/rpc/rpc-client.ts +94 -3
  107. package/src/modes/rpc/rpc-frame.ts +164 -4
  108. package/src/modes/rpc/rpc-messages.ts +127 -0
  109. package/src/modes/rpc/rpc-mode.ts +79 -7
  110. package/src/modes/rpc/rpc-types.ts +34 -2
  111. package/src/modes/setup-wizard/scenes/model.ts +5 -7
  112. package/src/modes/setup-wizard/scenes/providers.ts +3 -2
  113. package/src/modes/setup-wizard/scenes/sign-in.ts +8 -2
  114. package/src/modes/setup-wizard/scenes/theme.ts +13 -3
  115. package/src/modes/setup-wizard/scenes/types.ts +9 -1
  116. package/src/modes/setup-wizard/scenes/web-search.ts +6 -1
  117. package/src/modes/setup-wizard/wizard-overlay.ts +1 -1
  118. package/src/modes/types.ts +16 -3
  119. package/src/modes/utils/ui-helpers.ts +40 -20
  120. package/src/prompts/goals/guided-goal-system.md +24 -3
  121. package/src/prompts/system/workflow-notice.md +1 -1
  122. package/src/prompts/tools/task.md +12 -2
  123. package/src/sdk.ts +179 -51
  124. package/src/session/agent-session-error-log.test.ts +59 -0
  125. package/src/session/agent-session.ts +351 -46
  126. package/src/session/session-context.test.ts +224 -1
  127. package/src/session/session-context.ts +41 -2
  128. package/src/session/session-loader.ts +10 -5
  129. package/src/slash-commands/helpers/usage-report.ts +3 -1
  130. package/src/system-prompt.ts +1 -2
  131. package/src/task/executor.ts +44 -27
  132. package/src/task/index.ts +63 -8
  133. package/src/task/prewalk.ts +6 -0
  134. package/src/task/structured-subagent.ts +3 -1
  135. package/src/task/types.ts +16 -0
  136. package/src/task/worktree.ts +25 -11
  137. package/src/tools/ask.ts +15 -0
  138. package/src/tools/bash.ts +14 -6
  139. package/src/tools/browser.ts +1 -1
  140. package/src/tools/debug.ts +1 -1
  141. package/src/tools/eval.ts +4 -5
  142. package/src/tools/fetch.ts +1 -1
  143. package/src/tools/hub/index.ts +1 -1
  144. package/src/tools/hub/jobs.ts +67 -8
  145. package/src/tools/hub/launch.ts +7 -0
  146. package/src/tools/index.ts +3 -0
  147. package/src/tools/report-tool-issue.ts +79 -28
  148. package/src/tools/tool-timeouts.ts +10 -3
  149. package/src/tools/write.ts +31 -0
  150. package/src/utils/changelog.ts +54 -58
  151. package/src/utils/git.ts +57 -49
  152. package/src/web/search/providers/firecrawl.ts +46 -13
  153. package/src/web/search/types.ts +5 -1
@@ -44,7 +44,7 @@ interface ProviderOverride {
44
44
  * See `xiaomi-tp-discovery-merge.test.ts` and the `refresh()` baseUrl-override
45
45
  * regression in `model-registry.test.ts`.
46
46
  */
47
- export declare function mergeDiscoveredModel<TApi extends Api>(model: Model<TApi>, existing: Model<Api> | undefined, providerOverride?: Pick<ProviderOverride, "baseUrl" | "headers" | "remoteCompaction" | "transport">): Model<TApi>;
47
+ export declare function mergeDiscoveredModel<TApi extends Api>(model: Model<TApi>, existing: Model<Api> | undefined, providerOverride?: Pick<ProviderOverride, "baseUrl" | "compat" | "headers" | "remoteCompaction" | "transport">): Model<TApi>;
48
48
  export type ProviderDiscoveryStatus = "idle" | "ok" | "empty" | "cached" | "unavailable" | "unauthenticated";
49
49
  export interface ProviderDiscoveryState {
50
50
  provider: string;
@@ -78,6 +78,23 @@ export declare class ModelRegistry {
78
78
  */
79
79
  refresh(strategy?: ModelRefreshStrategy): Promise<void>;
80
80
  refreshInBackground(strategy?: ModelRefreshStrategy): void;
81
+ /**
82
+ * Wait for any in-flight background model discovery to settle.
83
+ *
84
+ * Background discovery started by {@link refreshInBackground} is
85
+ * fire-and-forget; RPC consumers (e.g. `get_available_models`,
86
+ * `set_model`) and deferred `--model` resolution that read the registry
87
+ * immediately after session creation can otherwise observe a partial
88
+ * catalog before discovery-backed providers have populated `#models`.
89
+ * Awaiting the tracked promise ensures the response reflects every
90
+ * configured provider once the initial background refresh resolves.
91
+ *
92
+ * No-op when no refresh is in flight (`#backgroundRefresh` cleared in the
93
+ * `finally` of `refreshInBackground` on completion). Resolves immediately
94
+ * in that case so already-warm sessions are unaffected. Discovery errors
95
+ * remain swallowed by `refreshInBackground`'s existing `.catch`.
96
+ */
97
+ awaitBackgroundRefresh(): Promise<void>;
81
98
  refreshProvider(providerId: string, strategy?: ModelRefreshStrategy): Promise<void>;
82
99
  /**
83
100
  * Refresh dynamic metadata that can appear only after a local model loads.
@@ -132,6 +149,16 @@ export declare class ModelRegistry {
132
149
  */
133
150
  hasCommandBackedApiKey(provider: string): boolean;
134
151
  getDiscoverableProviders(): string[];
152
+ /**
153
+ * Whether `providerId` is known to the registry: it has at least one live
154
+ * model, or it is configured for dynamic discovery (models.yml `discovery:`
155
+ * or a runtime extension provider) and is not disabled. Discovery-only
156
+ * providers can hold zero models at startup — cached rows never persist
157
+ * live auth headers (#5780), so a provider whose discovered models all
158
+ * carry config headers (`authHeader: true`) only materializes models after
159
+ * the online refresh completes.
160
+ */
161
+ hasProvider(providerId: string): boolean;
135
162
  getProviderDiscoveryState(provider: string): ProviderDiscoveryState | undefined;
136
163
  /**
137
164
  * Find a model by provider and ID.
@@ -265,8 +265,10 @@ export declare function resolveAllowedModels(modelRegistry: Pick<ModelRegistry,
265
265
  export declare function filterAvailableModelsByEnabledPatterns(available: Model<Api>[], patterns: readonly string[], settings?: Settings): Model<Api>[];
266
266
  export interface ResolveCliModelResult {
267
267
  model: Model<Api> | undefined;
268
- /** configuredPatterns is the full configured fallback chain when the selector resolves through a role. */
268
+ /** configuredPatterns contains the role's ordered primary candidates. */
269
269
  configuredPatterns?: string[];
270
+ /** configuredRole identifies the role expanded into configuredPatterns. */
271
+ configuredRole?: string;
270
272
  /** configuredPatternIndex identifies the configured role pattern that matched an available model. */
271
273
  configuredPatternIndex?: number;
272
274
  selector?: string;
@@ -283,6 +285,8 @@ export declare function resolveCliModel(options: {
283
285
  cliProvider?: string;
284
286
  cliModel?: string;
285
287
  modelRegistry: CliModelRegistry;
288
+ /** Authenticated models to prefer for unqualified selectors; omit to preserve catalog-order behavior. */
289
+ availableModels?: Model<Api>[];
286
290
  settings?: Settings;
287
291
  preferences?: ModelMatchPreferences;
288
292
  }): ResolveCliModelResult;
@@ -62,6 +62,8 @@ interface UiNumber extends UiBase {
62
62
  options?: ReadonlyArray<SubmenuOption>;
63
63
  }
64
64
  interface UiString extends UiBase {
65
+ /** Mask the value in both the settings row and text editor. */
66
+ secret?: boolean;
65
67
  /**
66
68
  * Submenu options.
67
69
  * - Array → submenu with these choices.
@@ -73,6 +75,7 @@ interface UiString extends UiBase {
73
75
  /** Wide ui shape exposed to consumers that walk the schema generically. */
74
76
  export type AnyUiMetadata = UiBase & {
75
77
  options?: ReadonlyArray<SubmenuOption> | "runtime";
78
+ secret?: boolean;
76
79
  };
77
80
  interface BooleanDef {
78
81
  type: "boolean";
@@ -2839,6 +2842,14 @@ export declare const SETTINGS_SCHEMA: {
2839
2842
  readonly "hindsight.apiToken": {
2840
2843
  readonly type: "string";
2841
2844
  readonly default: undefined;
2845
+ readonly ui: {
2846
+ readonly tab: "memory";
2847
+ readonly group: "Hindsight";
2848
+ readonly label: "Hindsight API Token";
2849
+ readonly description: "Bearer token for authenticated Hindsight servers";
2850
+ readonly condition: "hindsightActive";
2851
+ readonly secret: true;
2852
+ };
2842
2853
  };
2843
2854
  readonly "hindsight.bankId": {
2844
2855
  readonly type: "string";
@@ -2968,6 +2979,22 @@ export declare const SETTINGS_SCHEMA: {
2968
2979
  readonly type: "boolean";
2969
2980
  readonly default: false;
2970
2981
  };
2982
+ readonly "hindsight.requestTimeoutMs": {
2983
+ readonly type: "number";
2984
+ readonly default: 30000;
2985
+ };
2986
+ readonly "hindsight.reflectTimeoutMs": {
2987
+ readonly type: "number";
2988
+ readonly default: 120000;
2989
+ };
2990
+ readonly "hindsight.recallTimeoutMs": {
2991
+ readonly type: "number";
2992
+ readonly default: 30000;
2993
+ };
2994
+ readonly "hindsight.retainTimeoutMs": {
2995
+ readonly type: "number";
2996
+ readonly default: 60000;
2997
+ };
2971
2998
  readonly "hindsight.mentalModelsEnabled": {
2972
2999
  readonly type: "boolean";
2973
3000
  readonly default: true;
@@ -4034,6 +4061,16 @@ export declare const SETTINGS_SCHEMA: {
4034
4061
  readonly description: "Load .mcp.json/mcp.json from project root";
4035
4062
  };
4036
4063
  };
4064
+ readonly "mcp.renderMarkdownResults": {
4065
+ readonly type: "boolean";
4066
+ readonly default: true;
4067
+ readonly ui: {
4068
+ readonly tab: "tools";
4069
+ readonly group: "Discovery & MCP";
4070
+ readonly label: "MCP Markdown Results";
4071
+ readonly description: "Render non-JSON MCP text results as Markdown in the transcript";
4072
+ };
4073
+ };
4037
4074
  readonly "mcp.notifications": {
4038
4075
  readonly type: "boolean";
4039
4076
  readonly default: false;
@@ -4167,6 +4204,16 @@ export declare const SETTINGS_SCHEMA: {
4167
4204
  }];
4168
4205
  };
4169
4206
  };
4207
+ readonly "task.isolation.apply": {
4208
+ readonly type: "boolean";
4209
+ readonly default: true;
4210
+ readonly ui: {
4211
+ readonly tab: "tasks";
4212
+ readonly group: "Isolation";
4213
+ readonly label: "Apply Isolated Changes";
4214
+ readonly description: "Automatically apply successful isolated task changes to the parent checkout; disable to retain patch or branch artifacts";
4215
+ };
4216
+ };
4170
4217
  readonly "task.isolation.merge": {
4171
4218
  readonly type: "enum";
4172
4219
  readonly values: readonly ["patch", "branch"];
@@ -4632,7 +4679,7 @@ export declare const SETTINGS_SCHEMA: {
4632
4679
  }, {
4633
4680
  readonly value: "firecrawl";
4634
4681
  readonly label: "Firecrawl";
4635
- readonly description: "Requires FIRECRAWL_API_KEY";
4682
+ readonly description: "Uses Firecrawl API when FIRECRAWL_API_KEY is set; falls back to keyless mode";
4636
4683
  }, {
4637
4684
  readonly value: "brave";
4638
4685
  readonly label: "Brave";
@@ -5470,12 +5517,12 @@ export declare const SETTINGS_SCHEMA: {
5470
5517
  };
5471
5518
  readonly "dev.autoqa": {
5472
5519
  readonly type: "boolean";
5473
- readonly default: false;
5520
+ readonly default: true;
5474
5521
  readonly ui: {
5475
5522
  readonly tab: "tools";
5476
5523
  readonly group: "Developer";
5477
5524
  readonly label: "Auto QA";
5478
- readonly description: "Enable automated tool issue reporting (report_tool_issue) for all agents";
5525
+ readonly description: "Automated tool issue reporting (xd://report_issue). On by default; the first report asks for consent, and denying it disables reporting until re-enabled explicitly";
5479
5526
  };
5480
5527
  };
5481
5528
  readonly "dev.autoqaPush.endpoint": {
@@ -53,4 +53,23 @@ export declare class DapClient {
53
53
  sendResponse(request: DapRequestMessage, success: boolean, body?: unknown, message?: string): Promise<void>;
54
54
  dispose(): Promise<void>;
55
55
  }
56
+ /**
57
+ * Give the adapter a chance to announce it is listening on `port` before the
58
+ * first connect. vscode-js-debug prints `Debug server listening at HOST:PORT`
59
+ * to stdout from inside its `listen()` callback; waiting for the port to appear
60
+ * there means we only connect once the child genuinely owns the reserved port,
61
+ * which closes the WSL2-mirrored ghost-accept window (issue #6055) at its root.
62
+ *
63
+ * Best-effort: resolves on the banner, on process exit, or on timeout — the
64
+ * subsequent connect loop and `proc.exitCode` checks surface real failures, so
65
+ * an adapter that never prints a banner still proceeds (just without the gate).
66
+ * Also drains stdout for the wait's duration: in tcp mode the DAP protocol
67
+ * flows over the socket, so nothing else consumes the adapter's stdout.
68
+ *
69
+ * Exported so tests can drive the gate deterministically with a synthetic stdout.
70
+ */
71
+ export declare function waitForTcpServerListening(proc: {
72
+ stdout: ReadableStream<Uint8Array>;
73
+ exitCode: number | null;
74
+ }, port: number, timeoutMs: number): Promise<void>;
56
75
  export {};
@@ -54,8 +54,10 @@ export type SwitchSessionHandler = (sessionPath: string) => Promise<{
54
54
  }>;
55
55
  export type ShutdownHandler = () => void;
56
56
  /**
57
- * Helper function to emit session_shutdown event to extensions.
58
- * Returns true if the event was emitted, false if there were no handlers.
57
+ * Emit `session_shutdown` and clear timers owned by an extension runner.
58
+ *
59
+ * Returns whether any shutdown handlers were present. Timer cleanup runs even
60
+ * when a handler fails so extension background work cannot outlive its host.
59
61
  */
60
62
  export declare function emitSessionShutdownEvent(extensionRunner: ExtensionRunner | undefined): Promise<boolean>;
61
63
  export declare class ExtensionRunner {
@@ -398,6 +398,9 @@ export interface ToolDefinition<TParams extends TSchema = TSchema, TDetails = un
398
398
  /** Tool approval tier. Defaults to `"exec"` when omitted.
399
399
  * `"read"`: read-only operations. `"write"`: mutations. `"exec"`: code execution. */
400
400
  approval?: ToolApproval;
401
+ /** Structured-output strict grammar opt-in/out. `false` is meaningful: OpenAI-family
402
+ * serializers preserve an explicit `strict: false` on the wire (#4336/#4340). */
403
+ strict?: boolean;
401
404
  /** MCP server name for discovery/search metadata when this tool fronts an MCP server. */
402
405
  mcpServerName?: string;
403
406
  /** Original MCP tool name for discovery/search metadata. */
@@ -371,4 +371,5 @@ export { getProjectDir } from "@oh-my-pi/pi-utils";
371
371
  export declare function getPackageDir(): string;
372
372
  export * from "../index.js";
373
373
  export { formatBytes as formatSize } from "../tools/render-utils.js";
374
+ export { copyToClipboard } from "../utils/clipboard.js";
374
375
  export { Type } from "./typebox.js";
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Compatibility shim for legacy extensions importing the package root of
3
+ * `@earendil-works/pi-tui` or `@mariozechner/pi-tui`.
4
+ *
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.
8
+ */
9
+ export * from "@oh-my-pi/pi-tui";
10
+ export { decodePrintableKey as decodeKittyPrintable } from "@oh-my-pi/pi-tui";
@@ -57,7 +57,7 @@ export declare function __validateLegacyPiPackageRootOverrides(candidates: Recor
57
57
  */
58
58
  export declare function __buildLegacyPiPackageRootOverrides(isCompiled: boolean, bundledModuleKeys?: Iterable<string>): Record<string, string>;
59
59
  /** Test seam for compiled-binary legacy extension source rewriting. */
60
- export declare function __rewriteLegacyExtensionSourceForTests(source: string, importerPath: string, mtimeTag?: string | null): Promise<string>;
60
+ export declare function __rewriteLegacyExtensionSourceForTests(source: string, importerPath: string, mtimeTag?: string | null, resolvedImportMtimeTag?: string | null): Promise<string>;
61
61
  /**
62
62
  * Load a legacy Pi extension module from its real on-disk location.
63
63
  *
@@ -33,6 +33,8 @@ export type TOptional<_E extends ArkSchema> = ArkSchema;
33
33
  export type TUnion<_T extends readonly ArkSchema[] = readonly ArkSchema[]> = ArkSchema;
34
34
  export type TEnum<_T extends readonly (string | number)[] = readonly (string | number)[]> = ArkSchema;
35
35
  export type TRecord<_K extends ArkSchema, _V extends ArkSchema> = ArkSchema;
36
+ /** TypeBox-compatible wrapper for raw JSON Schema documents. */
37
+ export type TUnsafe<_T = unknown> = ArkSchema;
36
38
  declare const VALIDATION_FAILURE: unique symbol;
37
39
  interface ValidationFailure {
38
40
  message: string;
@@ -126,6 +128,7 @@ export declare const Type: {
126
128
  readonly Null: typeof tNull;
127
129
  readonly Any: typeof tAny;
128
130
  readonly Unknown: typeof tUnknown;
131
+ readonly Unsafe: <T = unknown>(jsonSchema?: Record<string, unknown>) => TUnsafe<T>;
129
132
  readonly Never: typeof tNever;
130
133
  readonly Literal: typeof tLiteral;
131
134
  readonly Union: typeof tUnion;
@@ -155,6 +158,7 @@ declare const _default: {
155
158
  readonly Null: typeof tNull;
156
159
  readonly Any: typeof tAny;
157
160
  readonly Unknown: typeof tUnknown;
161
+ readonly Unsafe: <T = unknown>(jsonSchema?: Record<string, unknown>) => TUnsafe<T>;
158
162
  readonly Never: typeof tNever;
159
163
  readonly Literal: typeof tLiteral;
160
164
  readonly Union: typeof tUnion;
@@ -12,10 +12,20 @@ export type Budget = "low" | "mid" | "high" | string;
12
12
  export type TagsMatch = "any" | "all" | "any_strict" | "all_strict";
13
13
  export type UpdateMode = "replace" | "append";
14
14
  export type ConsolidationState = "failed" | "pending" | "done";
15
+ /** Per-operation request deadlines (ms). Each falls back to a built-in default. */
16
+ export interface HindsightTimeouts {
17
+ /** Default deadline for ops without a specific override. */
18
+ request?: number;
19
+ reflect?: number;
20
+ recall?: number;
21
+ retain?: number;
22
+ }
15
23
  export interface HindsightApiOptions {
16
24
  baseUrl: string;
17
25
  apiKey?: string;
18
26
  userAgent?: string;
27
+ /** Per-op deadlines; unset entries fall back to built-in defaults. */
28
+ timeouts?: HindsightTimeouts;
19
29
  }
20
30
  /** Caller cancellation shared by Hindsight request option bags. */
21
31
  export interface HindsightRequestOptions {
@@ -32,6 +32,14 @@ export interface HindsightConfig {
32
32
  recallMaxQueryChars: number;
33
33
  recallPromptPreamble: string;
34
34
  debug: boolean;
35
+ /** Default per-request client deadline (ms) for ops without a specific override. */
36
+ requestTimeoutMs: number;
37
+ /** Client deadline (ms) for reflect (agentic synthesis; costlier than a metadata fetch). */
38
+ reflectTimeoutMs: number;
39
+ /** Client deadline (ms) for recall. */
40
+ recallTimeoutMs: number;
41
+ /** Client deadline (ms) for retain / retainBatch. */
42
+ retainTimeoutMs: number;
35
43
  mentalModelsEnabled: boolean;
36
44
  mentalModelAutoSeed: boolean;
37
45
  mentalModelRefreshIntervalMs: number;
@@ -31,3 +31,14 @@ export declare function artifactsDirsFromRegistry(): string[];
31
31
  * multiple dirs, the first hit wins (registry dirs are scanned first).
32
32
  */
33
33
  export declare function sessionFilesFromDisk(): Promise<Map<string, string>>;
34
+ /**
35
+ * Availability half of the `history://` resolution semantics: true when a
36
+ * transcript for `agentId` can be served from a registered ref's live session
37
+ * or retained session file, or from an on-disk `.jsonl` under a known
38
+ * artifacts dir. Hint surfaces use this so they only advertise
39
+ * `history://<agentId>` links that `HistoryProtocolHandler` can actually
40
+ * resolve. A retained sessionFile path is verified on disk before it counts,
41
+ * and probing never throws: a stale path or unreadable artifacts subtree
42
+ * reads as unavailable instead of disturbing the caller's delivery path.
43
+ */
44
+ export declare function hasResolvableTranscript(agentId: string): Promise<boolean>;
@@ -30,6 +30,8 @@ export declare const WARMUP_TIMEOUT_MS = 5000;
30
30
  * timeout/cancel instead of falling back to the internal 30s default.
31
31
  */
32
32
  export declare function getOrCreateClient(config: ServerConfig, cwd: string, initTimeoutMs?: number, signal?: AbortSignal): Promise<LspClient>;
33
+ /** Return an active or already-starting client without starting a language server. */
34
+ export declare function getActiveOrPendingClient(config: ServerConfig, cwd: string, signal?: AbortSignal): Promise<LspClient | undefined>;
33
35
  /**
34
36
  * Ensure a file is opened in the LSP client.
35
37
  * Sends didOpen notification if the file is not already tracked.
@@ -5,7 +5,7 @@ import { type AuthStorage } from "../session/auth-storage.js";
5
5
  import type { McpConnectionStatusEvent } from "./startup-events.js";
6
6
  import type { MCPToolDetails } from "./tool-bridge.js";
7
7
  import type { MCPToolCache } from "./tool-cache.js";
8
- import type { MCPGetPromptResult, MCPPrompt, MCPRequestOptions, MCPResource, MCPResourceReadResult, MCPResourceTemplate, MCPServerConfig, MCPServerConnection } from "./types.js";
8
+ import type { MCPAuthChallenge, MCPGetPromptResult, MCPPrompt, MCPRequestOptions, MCPResource, MCPResourceReadResult, MCPResourceTemplate, MCPServerConfig, MCPServerConnection } from "./types.js";
9
9
  /**
10
10
  * Stable, total ordering on MCP tools by name.
11
11
  *
@@ -42,6 +42,8 @@ export interface MCPDiscoverOptions {
42
42
  /** Called when MCP server connection state changes. */
43
43
  onStatus?: (event: McpConnectionStatusEvent) => void;
44
44
  }
45
+ /** Handles an MCP `WWW-Authenticate` challenge and returns refreshed config. */
46
+ export type MCPAuthHandler = (serverName: string, challenge: MCPAuthChallenge) => Promise<MCPServerConfig | undefined>;
45
47
  /**
46
48
  * MCP Server Manager.
47
49
  *
@@ -79,6 +81,8 @@ export declare class MCPManager {
79
81
  * Set the auth storage for resolving OAuth credentials.
80
82
  */
81
83
  setAuthStorage(authStorage: AuthStorage): void;
84
+ /** Set the callback used to complete OAuth after a tool-level auth challenge. */
85
+ setAuthHandler(handler: MCPAuthHandler | undefined): void;
82
86
  /**
83
87
  * Discover and connect to all MCP servers from .mcp.json files.
84
88
  * Returns tools and any connection errors.
@@ -149,7 +153,6 @@ export declare class MCPManager {
149
153
  * the same server share one reconnection attempt. Returns the new
150
154
  * connection, or `null` if reconnection failed or the per-server crash
151
155
  * burst limit (see {@link RECONNECT_BURST_LIMIT}) is exceeded.
152
- *
153
156
  * @param options.manual - When `true`, resets the crash-burst window so a
154
157
  * user-driven retry (e.g. `/mcp reconnect`) is never blocked by an
155
158
  * earlier storm. Defaults to `false`; the transport `onClose` callback
@@ -157,6 +160,7 @@ export declare class MCPManager {
157
160
  */
158
161
  reconnectServer(name: string, options?: {
159
162
  manual?: boolean;
163
+ authChallenge?: MCPAuthChallenge;
160
164
  }): Promise<MCPServerConnection | null>;
161
165
  /**
162
166
  * Refresh tools from a specific server.
@@ -4,9 +4,9 @@
4
4
  * Provides structured display of MCP tool calls and results,
5
5
  * showing args and output in JSON tree format similar to task tool.
6
6
  */
7
- import type { Component } from "@oh-my-pi/pi-tui";
7
+ import { type Component } from "@oh-my-pi/pi-tui";
8
8
  import type { RenderResultOptions } from "../extensibility/custom-tools/types.js";
9
- import type { Theme } from "../modes/theme/theme.js";
9
+ import { type Theme } from "../modes/theme/theme.js";
10
10
  import type { MCPToolDetails } from "./tool-bridge.js";
11
11
  /**
12
12
  * Render MCP tool call.
@@ -9,9 +9,11 @@ import type { SourceMeta } from "../capability/types.js";
9
9
  import type { CustomTool, CustomToolContext, CustomToolResult, RenderResultOptions } from "../extensibility/custom-tools/types.js";
10
10
  import type { Theme } from "../modes/theme/theme.js";
11
11
  import type { OutputMeta } from "../tools/output-meta.js";
12
- import type { MCPContent, MCPServerConnection, MCPToolDefinition } from "./types.js";
13
- /** Reconnect callback: tears down stale connection, returns new one or null. */
14
- export type MCPReconnect = () => Promise<MCPServerConnection | null>;
12
+ import type { MCPAuthChallenge, MCPContent, MCPServerConnection, MCPToolDefinition } from "./types.js";
13
+ /** Reconnect callback: tears down a stale connection, optionally authorizing first. */
14
+ export type MCPReconnect = (options?: {
15
+ authChallenge?: MCPAuthChallenge;
16
+ }) => Promise<MCPServerConnection | null>;
15
17
  export declare function isRetriableConnectionError(error: unknown): boolean;
16
18
  /** Details included in MCP tool results for rendering */
17
19
  export interface MCPToolDetails {
@@ -23,6 +25,8 @@ export interface MCPToolDetails {
23
25
  isError?: boolean;
24
26
  /** Raw content from MCP response */
25
27
  rawContent?: MCPContent[];
28
+ /** Structured metadata from the MCP response */
29
+ mcpMeta?: Record<string, unknown>;
26
30
  /** Provider ID (e.g., "claude", "mcp-json") */
27
31
  provider?: string;
28
32
  /** Provider display name (e.g., "Claude Code", "MCP Config") */
@@ -59,6 +63,13 @@ export declare class MCPTool implements CustomTool<TSchema, MCPToolDetails> {
59
63
  readonly approval: "write";
60
64
  /** Render completed MCP calls with the result header replacing the pending call header. */
61
65
  readonly mergeCallAndResult = true;
66
+ /**
67
+ * MCP-backed tools opt out of strict structured-output grammar. The server
68
+ * owns validation, and strict mode makes OpenAI-family models over-fill
69
+ * mutually exclusive optional fields (#4336/#4340). Serializers preserve an
70
+ * explicit `false`; an omitted flag would leave nothing to preserve.
71
+ */
72
+ readonly strict: false;
62
73
  /** Create MCPTool instances for all tools from an MCP server connection */
63
74
  static fromTools(connection: MCPServerConnection, tools: MCPToolDefinition[], reconnect?: MCPReconnect): MCPTool[];
64
75
  constructor(connection: MCPServerConnection, tool: MCPToolDefinition, reconnect?: MCPReconnect | undefined);
@@ -86,6 +97,8 @@ export declare class DeferredMCPTool implements CustomTool<TSchema, MCPToolDetai
86
97
  readonly approval: "write";
87
98
  /** Render completed MCP calls with the result header replacing the pending call header. */
88
99
  readonly mergeCallAndResult = true;
100
+ /** See {@link MCPTool.strict}: MCP servers own validation, so stay non-strict. */
101
+ readonly strict: false;
89
102
  /** Create DeferredMCPTool instances for all tools from an MCP server */
90
103
  static fromTools(serverName: string, tools: MCPToolDefinition[], getConnection: () => Promise<MCPServerConnection>, source?: SourceMeta, reconnect?: MCPReconnect): DeferredMCPTool[];
91
104
  constructor(serverName: string, tool: MCPToolDefinition, getConnection: () => Promise<MCPServerConnection>, source?: SourceMeta, reconnect?: MCPReconnect | undefined);
@@ -175,10 +175,16 @@ export interface MCPResourceContent {
175
175
  };
176
176
  }
177
177
  export type MCPContent = MCPTextContent | MCPImageContent | MCPResourceContent;
178
+ /** Structured authentication challenge returned in a tool result. */
179
+ export interface MCPAuthChallenge {
180
+ /** Values from `_meta["mcp/www_authenticate"]`. */
181
+ readonly wwwAuthenticate: readonly string[];
182
+ }
178
183
  /** tools/call response */
179
184
  export interface MCPToolCallResult {
180
185
  content: MCPContent[];
181
186
  isError?: boolean;
187
+ _meta?: Record<string, unknown>;
182
188
  }
183
189
  export interface MCPRequestOptions {
184
190
  /** Abort signal (e.g. Escape-to-interrupt) */
@@ -74,6 +74,7 @@ export interface MnemopiSessionStateOptions {
74
74
  hasRecalledForFirstTurn?: boolean;
75
75
  }
76
76
  export declare class MnemopiSessionState {
77
+ #private;
77
78
  sessionId: string;
78
79
  readonly config: MnemopiBackendConfig;
79
80
  readonly session: AgentSession;
@@ -124,6 +125,7 @@ export declare class MnemopiSessionState {
124
125
  content: string;
125
126
  }>, sourceId: string, options?: {
126
127
  extract?: boolean;
128
+ retainedThroughUserTurn?: number;
127
129
  }): Promise<void>;
128
130
  attachSessionListeners(): void;
129
131
  maybeRecallOnAgentStart(): Promise<void>;
@@ -10,6 +10,14 @@ export declare class OAuthSelectorComponent extends Container {
10
10
  requestRender?: () => void;
11
11
  });
12
12
  stopValidation(): void;
13
+ /**
14
+ * Fit the selector into `lines` rendered rows by shrinking the visible list
15
+ * window (the window is centered on the selection, so the selected row is
16
+ * always visible at any height). Prefers keeping the full chrome — borders,
17
+ * spacers, title, search status — but sacrifices the trailing spacer/border
18
+ * (clipped by the host) before dropping below three visible rows.
19
+ */
20
+ setMaxHeight(lines: number): void;
13
21
  handleInput(keyData: string): void;
14
22
  /** Move the selection one step for a wheel notch (clamped, no wrap). */
15
23
  handleWheel(delta: -1 | 1): void;
@@ -40,6 +40,7 @@ export interface SubmenuSettingDef extends BaseSettingDef {
40
40
  }
41
41
  export interface TextInputSettingDef extends BaseSettingDef {
42
42
  type: "text";
43
+ secret: boolean;
43
44
  }
44
45
  export interface ProviderLimitsSettingDef extends BaseSettingDef {
45
46
  type: "providerLimits";
@@ -1,4 +1,4 @@
1
- import { Container } from "@oh-my-pi/pi-tui";
1
+ import { type Component, Container } from "@oh-my-pi/pi-tui";
2
2
  /**
3
3
  * Component that renders a user message
4
4
  */
@@ -7,3 +7,27 @@ export declare class UserMessageComponent extends Container {
7
7
  constructor(text: string, synthetic?: boolean, imageLinks?: readonly (string | undefined)[]);
8
8
  render(width: number): readonly string[];
9
9
  }
10
+ /**
11
+ * Collapsed placeholder for a synthetic (agent-attributed) user input in the
12
+ * file/remote-backed transcript viewer — chiefly the advisor's `Session update`
13
+ * replay dumps, which can each be hundreds of KiB of Markdown and, on cold open,
14
+ * blocked the TUI for tens of seconds while every historical body was laid out
15
+ * before the viewport clip (issue #6308).
16
+ *
17
+ * Collapsed by default: renders one dim summary row (label · size · line count ·
18
+ * expand hint) and builds NO Markdown. The heavy {@link UserMessageComponent} is
19
+ * constructed lazily only when expanded via `ctrl+o`, so blocks above the
20
+ * viewport never pay layout cost until the reader asks to see them. The raw
21
+ * observability data stays intact in `__advisor.jsonl`.
22
+ */
23
+ export declare class CollapsedSyntheticMessageComponent implements Component {
24
+ #private;
25
+ private readonly text;
26
+ private readonly imageLinks?;
27
+ constructor(text: string, imageLinks?: readonly (string | undefined)[] | undefined);
28
+ /** ctrl+o toggle: reveal/hide the full Markdown body. */
29
+ setExpanded(expanded: boolean): void;
30
+ invalidate(): void;
31
+ dispose(): void;
32
+ render(width: number): readonly string[];
33
+ }
@@ -12,6 +12,14 @@ export declare class ExtensionUiController {
12
12
  * Initialize the hook system with TUI-based UI context.
13
13
  */
14
14
  initHooksAndCustomTools(): Promise<void>;
15
+ /**
16
+ * The `ExtensionUIContext` built in `initHooksAndCustomTools()` — the same
17
+ * picker/dialog primitives passed as `context.ui` for every live tool
18
+ * call. `/tree` `ask` re-answer (issue #5642) reuses this to drive a
19
+ * standalone `AskTool.execute()` call outside a normal agent turn.
20
+ * `undefined` before hooks have initialized.
21
+ */
22
+ getToolUIContext(): ExtensionUIContext | undefined;
15
23
  setHookWidget(key: string, content: ExtensionWidgetContent, options?: ExtensionWidgetOptions): void;
16
24
  initializeHookRunner(uiContext: ExtensionUIContext, _hasUI: boolean): void;
17
25
  /**
@@ -1,4 +1,5 @@
1
1
  import { type Component } from "@oh-my-pi/pi-tui";
2
+ import type { MCPAuthChallenge, MCPServerConfig } from "../../mcp/types.js";
2
3
  import type { InteractiveModeContext } from "../types.js";
3
4
  /**
4
5
  * Renders the MCP OAuth fallback URL. Always shows the full authorization URL
@@ -41,4 +42,6 @@ export declare class MCPCommandController {
41
42
  * Handle /mcp command and route to subcommands
42
43
  */
43
44
  handle(text: string): Promise<void>;
45
+ /** Reauthorize a server after a tool-level OAuth challenge. */
46
+ handleMCPAuthChallenge(name: string, challenge: MCPAuthChallenge): Promise<MCPServerConfig | undefined>;
44
47
  }
@@ -128,6 +128,7 @@ export declare class InteractiveMode implements InteractiveModeContext {
128
128
  proseOnlyThinking: boolean;
129
129
  compactionQueuedMessages: CompactionQueuedMessage[];
130
130
  pendingTools: Map<string, ToolExecutionHandle>;
131
+ transcriptMessageComponents: WeakMap<AgentMessage, Component>;
131
132
  pendingBashComponents: BashExecutionComponent[];
132
133
  bashComponent: BashExecutionComponent | undefined;
133
134
  pendingPythonComponents: EvalExecutionComponent[];
@@ -228,7 +229,9 @@ export declare class InteractiveMode implements InteractiveModeContext {
228
229
  syncRunningSubagentBadge(options?: {
229
230
  requestRender?: boolean;
230
231
  }): void;
231
- rebuildChatFromMessages(): void;
232
+ rebuildChatFromMessages(options?: {
233
+ reuseSettledComponents?: boolean;
234
+ }): void;
232
235
  /**
233
236
  * Render the ctrl+p model-role cycle chip track into its own anchored
234
237
  * container (just above the editor), mirroring the todo HUD: the container is
@@ -301,10 +304,12 @@ export declare class InteractiveMode implements InteractiveModeContext {
301
304
  addMessageToChat(message: AgentMessage, options?: {
302
305
  populateHistory?: boolean;
303
306
  imageLinks?: readonly (string | undefined)[];
307
+ reuseSettledComponent?: boolean;
304
308
  }): Component[];
305
309
  renderSessionContext(sessionContext: SessionContext, options?: {
306
310
  updateFooter?: boolean;
307
311
  populateHistory?: boolean;
312
+ reuseSettledComponents?: boolean;
308
313
  }): void;
309
314
  renderInitialMessages(options?: {
310
315
  preserveExistingChat?: boolean;
@@ -399,6 +404,7 @@ export declare class InteractiveMode implements InteractiveModeContext {
399
404
  openExternalEditor(): void;
400
405
  registerExtensionShortcuts(): void;
401
406
  initHooksAndCustomTools(): Promise<void>;
407
+ getToolUIContext(): ExtensionUIContext | undefined;
402
408
  emitCustomToolSessionEvent(reason: "start" | "switch" | "branch" | "tree" | "shutdown", previousSessionFile?: string): Promise<void>;
403
409
  setHookWidget(key: string, content: ExtensionWidgetContent, options?: ExtensionWidgetOptions): void;
404
410
  setHookStatus(key: string, text: string | undefined): void;