@oh-my-pi/pi-coding-agent 16.2.1 → 16.2.3

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 (187) hide show
  1. package/CHANGELOG.md +72 -0
  2. package/dist/cli.js +3621 -3579
  3. package/dist/types/advisor/__tests__/config.test.d.ts +1 -0
  4. package/dist/types/advisor/advise-tool.d.ts +8 -4
  5. package/dist/types/advisor/config.d.ts +88 -0
  6. package/dist/types/advisor/index.d.ts +1 -0
  7. package/dist/types/advisor/runtime.d.ts +15 -1
  8. package/dist/types/advisor/transcript-recorder.d.ts +13 -2
  9. package/dist/types/advisor/watchdog.d.ts +20 -0
  10. package/dist/types/collab/guest.d.ts +29 -0
  11. package/dist/types/config/model-roles.d.ts +1 -1
  12. package/dist/types/config/settings-schema.d.ts +113 -12
  13. package/dist/types/debug/log-viewer.d.ts +1 -0
  14. package/dist/types/debug/raw-sse.d.ts +1 -0
  15. package/dist/types/discovery/omp-extension-roots.d.ts +3 -3
  16. package/dist/types/edit/hashline/diff.d.ts +0 -11
  17. package/dist/types/edit/index.d.ts +18 -0
  18. package/dist/types/edit/streaming.d.ts +30 -0
  19. package/dist/types/extensibility/custom-tools/types.d.ts +1 -0
  20. package/dist/types/extensibility/shared-events.d.ts +1 -0
  21. package/dist/types/extensibility/tool-event-input.d.ts +7 -0
  22. package/dist/types/extensibility/utils.d.ts +12 -0
  23. package/dist/types/mcp/oauth-discovery.d.ts +0 -11
  24. package/dist/types/mcp/transports/index.d.ts +1 -0
  25. package/dist/types/mcp/transports/sse.d.ts +20 -0
  26. package/dist/types/modes/components/advisor-config.d.ts +59 -0
  27. package/dist/types/modes/components/index.d.ts +1 -0
  28. package/dist/types/modes/components/model-selector.d.ts +9 -1
  29. package/dist/types/modes/components/settings-selector.d.ts +1 -0
  30. package/dist/types/modes/components/status-line/component.d.ts +30 -3
  31. package/dist/types/modes/components/status-line/types.d.ts +13 -1
  32. package/dist/types/modes/controllers/selector-controller.d.ts +1 -0
  33. package/dist/types/modes/interactive-mode.d.ts +10 -4
  34. package/dist/types/modes/skill-command.d.ts +32 -0
  35. package/dist/types/modes/types.d.ts +7 -2
  36. package/dist/types/sdk.d.ts +1 -1
  37. package/dist/types/session/agent-session.d.ts +84 -12
  38. package/dist/types/session/indexed-session-storage.d.ts +7 -1
  39. package/dist/types/session/messages.d.ts +32 -7
  40. package/dist/types/session/messages.test.d.ts +1 -0
  41. package/dist/types/session/session-entries.d.ts +31 -3
  42. package/dist/types/session/session-history-format.d.ts +6 -0
  43. package/dist/types/session/session-loader.d.ts +9 -1
  44. package/dist/types/session/session-manager.d.ts +6 -4
  45. package/dist/types/session/session-storage.d.ts +11 -0
  46. package/dist/types/session/session-title-slot.d.ts +19 -0
  47. package/dist/types/session/settings-stream-fn.d.ts +21 -0
  48. package/dist/types/session/turn-persistence.d.ts +88 -0
  49. package/dist/types/ssh/connection-manager.d.ts +47 -0
  50. package/dist/types/ssh/utils.d.ts +16 -0
  51. package/dist/types/task/executor.d.ts +3 -16
  52. package/dist/types/task/render.d.ts +0 -5
  53. package/dist/types/task/renderer.d.ts +13 -0
  54. package/dist/types/task/types.d.ts +16 -0
  55. package/dist/types/task/yield-assembly.d.ts +28 -0
  56. package/dist/types/tiny/text.d.ts +8 -0
  57. package/dist/types/tools/render-utils.d.ts +2 -0
  58. package/dist/types/tools/review.d.ts +6 -4
  59. package/dist/types/tools/ssh.d.ts +1 -1
  60. package/dist/types/tools/todo.d.ts +6 -0
  61. package/dist/types/tools/yield.d.ts +8 -3
  62. package/dist/types/utils/thinking-display.d.ts +4 -0
  63. package/package.json +12 -12
  64. package/src/advisor/__tests__/advisor.test.ts +438 -10
  65. package/src/advisor/__tests__/config.test.ts +173 -0
  66. package/src/advisor/advise-tool.ts +11 -6
  67. package/src/advisor/config.ts +256 -0
  68. package/src/advisor/index.ts +1 -0
  69. package/src/advisor/runtime.ts +77 -4
  70. package/src/advisor/transcript-recorder.ts +25 -2
  71. package/src/advisor/watchdog.ts +57 -31
  72. package/src/auto-thinking/classifier.ts +2 -2
  73. package/src/autoresearch/index.ts +7 -2
  74. package/src/cli/gc-cli.ts +17 -10
  75. package/src/collab/guest.ts +43 -7
  76. package/src/config/model-registry.ts +80 -18
  77. package/src/config/model-resolver.ts +5 -1
  78. package/src/config/model-roles.ts +3 -3
  79. package/src/config/settings-schema.ts +107 -8
  80. package/src/debug/index.ts +32 -7
  81. package/src/debug/log-viewer.ts +111 -53
  82. package/src/debug/raw-sse.ts +68 -48
  83. package/src/discovery/codex.ts +13 -5
  84. package/src/discovery/omp-extension-roots.ts +38 -13
  85. package/src/edit/hashline/diff.ts +57 -4
  86. package/src/edit/index.ts +21 -0
  87. package/src/edit/streaming.ts +170 -0
  88. package/src/eval/js/shared/local-module-loader.ts +23 -1
  89. package/src/export/html/template.js +13 -7
  90. package/src/extensibility/custom-tools/types.ts +1 -0
  91. package/src/extensibility/extensions/loader.ts +5 -3
  92. package/src/extensibility/extensions/wrapper.ts +9 -3
  93. package/src/extensibility/hooks/loader.ts +3 -3
  94. package/src/extensibility/hooks/tool-wrapper.ts +13 -4
  95. package/src/extensibility/plugins/legacy-pi-bundled-keys.ts +18 -1
  96. package/src/extensibility/plugins/legacy-pi-bundled-registry.ts +59 -2
  97. package/src/extensibility/plugins/manager.ts +76 -5
  98. package/src/extensibility/shared-events.ts +1 -0
  99. package/src/extensibility/tool-event-input.ts +23 -0
  100. package/src/extensibility/utils.ts +74 -0
  101. package/src/internal-urls/docs-index.generated.txt +1 -1
  102. package/src/mcp/client.ts +3 -1
  103. package/src/mcp/manager.ts +12 -5
  104. package/src/mcp/oauth-discovery.ts +5 -29
  105. package/src/mcp/transports/http.ts +3 -1
  106. package/src/mcp/transports/index.ts +1 -0
  107. package/src/mcp/transports/sse.ts +377 -0
  108. package/src/memories/index.ts +15 -6
  109. package/src/mnemopi/backend.ts +2 -2
  110. package/src/modes/acp/acp-agent.ts +1 -1
  111. package/src/modes/components/advisor-config.ts +555 -0
  112. package/src/modes/components/advisor-message.ts +9 -2
  113. package/src/modes/components/agent-hub.ts +9 -4
  114. package/src/modes/components/assistant-message.ts +5 -5
  115. package/src/modes/components/index.ts +2 -0
  116. package/src/modes/components/model-selector.ts +79 -48
  117. package/src/modes/components/settings-selector.ts +1 -0
  118. package/src/modes/components/status-line/component.ts +145 -14
  119. package/src/modes/components/status-line/segments.ts +47 -22
  120. package/src/modes/components/status-line/types.ts +13 -1
  121. package/src/modes/components/tool-execution.ts +47 -6
  122. package/src/modes/controllers/command-controller.ts +23 -2
  123. package/src/modes/controllers/event-controller.ts +114 -11
  124. package/src/modes/controllers/extension-ui-controller.ts +1 -1
  125. package/src/modes/controllers/input-controller.ts +61 -61
  126. package/src/modes/controllers/selector-controller.ts +100 -9
  127. package/src/modes/interactive-mode.ts +65 -10
  128. package/src/modes/print-mode.ts +1 -1
  129. package/src/modes/skill-command.ts +116 -0
  130. package/src/modes/types.ts +7 -2
  131. package/src/modes/utils/transcript-render-helpers.ts +2 -2
  132. package/src/modes/utils/ui-helpers.ts +46 -27
  133. package/src/prompts/agents/reviewer.md +11 -10
  134. package/src/prompts/review-custom-request.md +1 -2
  135. package/src/prompts/review-request.md +1 -2
  136. package/src/prompts/system/interrupted-thinking.md +7 -0
  137. package/src/prompts/system/recap-user.md +9 -0
  138. package/src/prompts/system/subagent-system-prompt.md +8 -5
  139. package/src/prompts/system/subagent-yield-reminder.md +6 -5
  140. package/src/prompts/system/system-prompt.md +0 -1
  141. package/src/prompts/tools/irc.md +2 -2
  142. package/src/prompts/tools/read.md +2 -2
  143. package/src/sdk.ts +40 -50
  144. package/src/session/agent-session.ts +1139 -600
  145. package/src/session/indexed-session-storage.ts +86 -13
  146. package/src/session/messages.test.ts +125 -0
  147. package/src/session/messages.ts +192 -21
  148. package/src/session/redis-session-storage.ts +49 -2
  149. package/src/session/session-entries.ts +39 -2
  150. package/src/session/session-history-format.ts +29 -2
  151. package/src/session/session-listing.ts +54 -24
  152. package/src/session/session-loader.ts +66 -3
  153. package/src/session/session-manager.ts +113 -19
  154. package/src/session/session-persistence.ts +96 -3
  155. package/src/session/session-storage.ts +36 -0
  156. package/src/session/session-title-slot.ts +141 -0
  157. package/src/session/settings-stream-fn.ts +49 -0
  158. package/src/session/sql-session-storage.ts +71 -11
  159. package/src/session/turn-persistence.ts +142 -0
  160. package/src/session/unexpected-stop-classifier.ts +2 -2
  161. package/src/slash-commands/builtin-registry.ts +16 -3
  162. package/src/slash-commands/helpers/mcp.ts +2 -1
  163. package/src/ssh/__tests__/connection-manager-args.test.ts +123 -1
  164. package/src/ssh/__tests__/file-transfer-posix-guard.test.ts +55 -18
  165. package/src/ssh/connection-manager.ts +139 -12
  166. package/src/ssh/file-transfer.ts +23 -18
  167. package/src/ssh/ssh-executor.ts +2 -13
  168. package/src/ssh/utils.ts +19 -0
  169. package/src/task/executor.ts +21 -23
  170. package/src/task/render.ts +162 -20
  171. package/src/task/renderer.ts +14 -0
  172. package/src/task/types.ts +17 -0
  173. package/src/task/yield-assembly.ts +207 -0
  174. package/src/tiny/models.ts +8 -6
  175. package/src/tiny/text.ts +37 -7
  176. package/src/tools/ask.ts +55 -4
  177. package/src/tools/image-gen.ts +2 -1
  178. package/src/tools/render-utils.ts +2 -0
  179. package/src/tools/renderers.ts +8 -2
  180. package/src/tools/review.ts +17 -7
  181. package/src/tools/ssh.ts +8 -4
  182. package/src/tools/todo.ts +17 -1
  183. package/src/tools/tts.ts +2 -1
  184. package/src/tools/yield.ts +140 -31
  185. package/src/utils/thinking-display.ts +15 -0
  186. package/src/utils/title-generator.ts +1 -1
  187. package/src/web/search/providers/tavily.ts +36 -19
@@ -10,3 +10,15 @@ export declare function resolvePath(filePath: string, cwd: string): string;
10
10
  * Create a no-op UI context for headless modes.
11
11
  */
12
12
  export declare function createNoOpUIContext(): HookUIContext;
13
+ /**
14
+ * Raised by {@link withExitGuard} when a guarded callback synchronously
15
+ * attempts to terminate the host process. Callers catch this like any other
16
+ * load-time failure so the extension/hook is skipped with a logged error
17
+ * instead of taking the CLI down with it.
18
+ */
19
+ export declare class ExtensionExitError extends Error {
20
+ readonly alias: string;
21
+ readonly code: number | string | undefined;
22
+ constructor(code: number | string | undefined, alias?: string);
23
+ }
24
+ export declare function withExitGuard<T>(fn: () => Promise<T>): Promise<T>;
@@ -1,9 +1,3 @@
1
- /**
2
- * MCP OAuth Auto-Discovery
3
- *
4
- * Automatically detects OAuth requirements from MCP server responses
5
- * and extracts authentication endpoints.
6
- */
7
1
  import type { FetchImpl } from "@oh-my-pi/pi-ai/types";
8
2
  export interface OAuthEndpoints {
9
3
  authorizationUrl: string;
@@ -21,11 +15,6 @@ export interface AuthDetectionResult {
21
15
  message?: string;
22
16
  }
23
17
  export declare function extractMcpAuthServerUrl(error: Error, serverUrl?: string): string | undefined;
24
- /**
25
- * Detect if an error indicates authentication is required.
26
- * Checks for common auth error patterns.
27
- */
28
- export declare function detectAuthError(error: Error): boolean;
29
18
  /**
30
19
  * Extract OAuth endpoints from error response.
31
20
  * Looks for WWW-Authenticate header format or JSON error bodies.
@@ -2,4 +2,5 @@
2
2
  * MCP transport exports.
3
3
  */
4
4
  export * from "./http";
5
+ export * from "./sse";
5
6
  export * from "./stdio";
@@ -0,0 +1,20 @@
1
+ import type { MCPRequestOptions, MCPSseServerConfig, MCPTransport } from "../../mcp/types";
2
+ /** Legacy MCP HTTP+SSE transport from protocol revision 2024-11-05. */
3
+ export declare class LegacySseTransport implements MCPTransport {
4
+ #private;
5
+ onClose?: () => void;
6
+ onError?: (error: Error) => void;
7
+ onNotification?: (method: string, params: unknown) => void;
8
+ onRequest?: (method: string, params: unknown) => Promise<unknown>;
9
+ /** Called on 401/403 to attempt token refresh. Returns updated headers or null. */
10
+ onAuthError?: () => Promise<Record<string, string> | null>;
11
+ constructor(config: MCPSseServerConfig);
12
+ get connected(): boolean;
13
+ get url(): string;
14
+ connect(): Promise<void>;
15
+ request<T = unknown>(method: string, params?: Record<string, unknown>, options?: MCPRequestOptions): Promise<T>;
16
+ notify(method: string, params?: Record<string, unknown>): Promise<void>;
17
+ close(): Promise<void>;
18
+ }
19
+ /** Create and connect a legacy HTTP+SSE transport. */
20
+ export declare function createSseTransport(config: MCPSseServerConfig): Promise<LegacySseTransport>;
@@ -0,0 +1,59 @@
1
+ /**
2
+ * Fullscreen `/advisor configure` overlay: a mouse- and keyboard-driven editor
3
+ * for the `WATCHDOG.yml` advisor roster at project or user level.
4
+ *
5
+ * It paints the entire alternate screen from row 0 (so SGR mouse rows index
6
+ * directly into the rendered frame) using the shared {@link ./overlay-box} chrome.
7
+ * The list screen is a two-pane split (the `/extensions` idiom): a clickable
8
+ * advisor/action sidebar on the left, and a scrollable preview of the highlighted
9
+ * advisor's model / tools / instructions on the right, filling the free space.
10
+ *
11
+ * Each screen is backed by a proven primitive — {@link SelectList} (list / detail
12
+ * / tools / thinking), {@link Input} (name), {@link ModelSelectorComponent} (the
13
+ * same rich `/model` picker, in direct-select mode), and {@link HookEditorComponent}
14
+ * (multiline instructions; Ctrl+G opens `$EDITOR`). The overlay edits an in-memory
15
+ * {@link WatchdogConfigDoc} and only touches disk + the live advisors via the host
16
+ * `save` callback.
17
+ */
18
+ import type { ThinkingLevel } from "@oh-my-pi/pi-agent-core";
19
+ import type { Model } from "@oh-my-pi/pi-ai";
20
+ import { type Component, type TUI } from "@oh-my-pi/pi-tui";
21
+ import { type AdvisorConfigScope, type WatchdogConfigDoc } from "../../advisor";
22
+ import type { ModelRegistry } from "../../config/model-registry";
23
+ import type { Settings } from "../../config/settings";
24
+ /** Host callbacks: all disk + live-runtime effects flow through these. */
25
+ export interface AdvisorConfigCallbacks {
26
+ /** Load a scope's `WATCHDOG.yml` into an editable doc (empty when absent). */
27
+ loadDoc: (scope: AdvisorConfigScope) => Promise<WatchdogConfigDoc>;
28
+ /** Persist the doc to the scope's file and rebuild the live advisors. */
29
+ save: (scope: AdvisorConfigScope, doc: WatchdogConfigDoc) => Promise<void>;
30
+ /** Tear down the overlay and restore the editor. */
31
+ close: () => void;
32
+ requestRender: () => void;
33
+ /** Surface a transient status/warning line to the user. */
34
+ notify: (message: string) => void;
35
+ }
36
+ export interface AdvisorConfigDeps {
37
+ modelRegistry: ModelRegistry;
38
+ settings: Settings;
39
+ scopedModels: ReadonlyArray<{
40
+ model: Model;
41
+ thinkingLevel?: ThinkingLevel;
42
+ }>;
43
+ availableToolNames: string[];
44
+ /** Formatted advisor-role model shown on the seeded default row (e.g. "anthropic/claude-..."). */
45
+ defaultModelLabel?: string;
46
+ }
47
+ /**
48
+ * Fullscreen advisor-configuration overlay. Implements {@link Component} directly
49
+ * (rather than extending Container) so it owns the whole frame and the mouse
50
+ * geometry needed to make every row clickable.
51
+ */
52
+ export declare class AdvisorConfigOverlayComponent implements Component {
53
+ #private;
54
+ constructor(tui: TUI, deps: AdvisorConfigDeps, scope: AdvisorConfigScope, doc: WatchdogConfigDoc, callbacks: AdvisorConfigCallbacks);
55
+ render(width: number): readonly string[];
56
+ handleInput(data: string): void;
57
+ /** Forward enhanced-paste transports into a multiline instructions editor. */
58
+ pasteText(text: string): void;
59
+ }
@@ -1,3 +1,4 @@
1
+ export * from "./advisor-config";
1
2
  export * from "./assistant-message";
2
3
  export * from "./bash-execution";
3
4
  export * from "./bordered-loader";
@@ -1,5 +1,5 @@
1
1
  import type { Model } from "@oh-my-pi/pi-ai";
2
- import { Container, Input, type TUI } from "@oh-my-pi/pi-tui";
2
+ import { Container, Input, type SgrMouseEvent, type TUI } from "@oh-my-pi/pi-tui";
3
3
  import type { ModelRegistry } from "../../config/model-registry";
4
4
  import type { Settings } from "../../config/settings";
5
5
  import { type ConfiguredThinkingLevel } from "../../thinking";
@@ -19,9 +19,17 @@ export declare class ModelSelectorComponent extends Container {
19
19
  #private;
20
20
  constructor(tui: TUI, _currentModel: Model | undefined, settings: Settings, modelRegistry: ModelRegistry, scopedModels: ReadonlyArray<ScopedModelItem>, onSelect: RoleSelectCallback, onCancel: () => void, options?: {
21
21
  temporaryOnly?: boolean;
22
+ directSelect?: boolean;
23
+ pickerHint?: string;
22
24
  initialSearchInput?: string;
23
25
  currentContextTokens?: number;
24
26
  });
27
+ /**
28
+ * Concatenate children like Container.render, recording where the model list
29
+ * lands so routed mouse events can be hit-tested against it.
30
+ */
31
+ render(width: number): readonly string[];
32
+ routeMouse(event: SgrMouseEvent, line: number, _col: number): void;
25
33
  handleInput(keyData: string): void;
26
34
  getSearchInput(): Input;
27
35
  }
@@ -34,6 +34,7 @@ export interface StatusLinePreviewSettings {
34
34
  separator?: StatusLineSeparatorStyle;
35
35
  sessionAccent?: boolean;
36
36
  transparent?: boolean;
37
+ compactThinkingLevel?: boolean;
37
38
  }
38
39
  export interface SettingsCallbacks {
39
40
  /** Called when any setting value changes */
@@ -14,11 +14,38 @@ export declare class StatusLineComponent implements Component {
14
14
  getEffectiveSettingsForTest(): EffectiveStatusLineSettings;
15
15
  setAutoCompactEnabled(enabled: boolean): void;
16
16
  setSubagentCount(count: number): void;
17
- /** Hub key label shown in the forced running-subagents badge. */
18
- setSubagentHubHint(hint: string | undefined): void;
19
17
  /** Active subagent count as currently displayed (collab state mirroring). */
20
18
  get subagentCount(): number;
21
- setSessionStartTime(time: number): void;
19
+ /**
20
+ * Reset the currently-attached session's active-time accumulators so
21
+ * the `time_spent` segment starts from zero. Called from `/clear`,
22
+ * fresh-session, and joined-collab paths; both the completed
23
+ * accumulator and any in-flight window are dropped, so a reset
24
+ * mid-turn ignores the running window (the matching `markActivityEnd`
25
+ * will see an idle meter and no-op).
26
+ */
27
+ resetActiveTime(): void;
28
+ /**
29
+ * Mark the currently-attached session as having started a unit of
30
+ * active processing. Idempotent: a second start while a window is
31
+ * already open is a no-op, so reentrant `agent_start` events (e.g.
32
+ * nested auto-compaction loops, focus-controller mid-turn attach onto
33
+ * an already-running window) do not double-count.
34
+ */
35
+ markActivityStart(): void;
36
+ /**
37
+ * Close the currently-attached session's open active-processing
38
+ * window, folding its elapsed time into the accumulator. Idempotent
39
+ * when the meter is already idle so callers can fire it on every
40
+ * `agent_end` without guarding.
41
+ */
42
+ markActivityEnd(): void;
43
+ /**
44
+ * Snapshot of total active-processing time for the currently-attached
45
+ * session, including any in-flight window. Exposed for the segment
46
+ * context builder; tests assert against this too.
47
+ */
48
+ getActiveMs(): number;
22
49
  setPlanModeStatus(status: {
23
50
  enabled: boolean;
24
51
  paused: boolean;
@@ -41,6 +41,9 @@ export interface StatusLineSettings {
41
41
  /** Drop the theme's `statusLineBg` fill and powerline caps so the bar
42
42
  * inherits the terminal's default background. */
43
43
  transparent?: boolean;
44
+ /** Replace the model-segment icon with the thinking-level glyph and drop the
45
+ * " · <level>" suffix, so the thinking level reads as a single compact icon. */
46
+ compactThinkingLevel?: boolean;
44
47
  }
45
48
  export type EffectiveStatusLineSettings = Required<Pick<StatusLineSettings, "leftSegments" | "rightSegments" | "separator" | "segmentOptions">> & StatusLineSettings;
46
49
  export type RGB = readonly [number, number, number];
@@ -51,6 +54,8 @@ export interface SegmentContext {
51
54
  activeRepo: ActiveRepoContext | null;
52
55
  width: number;
53
56
  options: StatusLineSegmentOptions;
57
+ /** Render the model segment's thinking level as a compact leading glyph. */
58
+ compactThinkingLevel: boolean;
54
59
  planMode: {
55
60
  enabled: boolean;
56
61
  paused: boolean;
@@ -78,7 +83,14 @@ export interface SegmentContext {
78
83
  contextWindow: number;
79
84
  autoCompactEnabled: boolean;
80
85
  subagentCount: number;
81
- sessionStartTime: number;
86
+ /**
87
+ * Active processing time accumulated this session, in ms — the union of
88
+ * every `agent_start`→`agent_end` window plus the currently-streaming
89
+ * window if the agent is running. Idle wall-clock never contributes, so
90
+ * this is what {@link StatusLineSegmentId.time_spent} renders instead of
91
+ * `Date.now() - sessionStart`.
92
+ */
93
+ activeMs: number;
82
94
  git: {
83
95
  branch: string | null;
84
96
  status: {
@@ -25,6 +25,7 @@ export declare class SelectorController {
25
25
  focus: Component;
26
26
  }): void;
27
27
  showSettingsSelector(): void;
28
+ showAdvisorConfigure(): void;
28
29
  showHistorySearch(): void;
29
30
  /**
30
31
  * Show the Extension Control Center dashboard.
@@ -109,11 +109,16 @@ export declare class InteractiveMode implements InteractiveModeContext {
109
109
  loopLimit: LoopLimitRuntime | undefined;
110
110
  todoPhases: TodoPhase[];
111
111
  hideThinkingBlock: boolean;
112
+ /** Whether the visible session has produced thinking content the user can reveal. */
113
+ get hasDisplayableThinkingContent(): boolean;
114
+ /** Record received reasoning content so Ctrl+T can reveal it even when model metadata says thinking is off. */
115
+ noteDisplayableThinkingContent(message: AgentMessage): boolean;
112
116
  /**
113
- * Effective thinking-block visibility: hidden when the user's setting is on
114
- * OR the session thinking level is "off". Some providers (MiniMax, GLM,
115
- * DeepSeek) return thinking blocks even with reasoning disabled; this
116
- * respects the user's intent when they set thinking to "off" (#626).
117
+ * Effective thinking-block visibility: hidden when the user's setting is on,
118
+ * or while thinking is "off" before the session has actually produced
119
+ * displayable thinking content. Some providers return thinking blocks without
120
+ * advertising reasoning support, so observed content unlocks the visibility
121
+ * toggle.
117
122
  */
118
123
  get effectiveHideThinkingBlock(): boolean;
119
124
  proseOnlyThinking: boolean;
@@ -319,6 +324,7 @@ export declare class InteractiveMode implements InteractiveModeContext {
319
324
  executeCompaction(customInstructionsOrOptions?: string | CompactOptions, isAuto?: boolean): Promise<CompactionOutcome>;
320
325
  openInBrowser(urlOrPath: string): void;
321
326
  showSettingsSelector(): void;
327
+ showAdvisorConfigure(): void;
322
328
  showHistorySearch(): void;
323
329
  showExtensionsDashboard(): void;
324
330
  showAgentsDashboard(): void;
@@ -0,0 +1,32 @@
1
+ import type { ImageContent, TextContent } from "@oh-my-pi/pi-ai";
2
+ import { type CustomMessage, SKILL_PROMPT_MESSAGE_TYPE, type SkillPromptDetails } from "../session/messages";
3
+ import type { InteractiveModeContext } from "./types";
4
+ type SkillCommandHost = Pick<InteractiveModeContext, "skillCommands" | "session" | "showError">;
5
+ type SkillPromptMessage = Pick<CustomMessage<SkillPromptDetails>, "customType" | "content" | "display" | "details" | "attribution"> & {
6
+ customType: typeof SKILL_PROMPT_MESSAGE_TYPE;
7
+ content: string | (TextContent | ImageContent)[];
8
+ display: true;
9
+ details: SkillPromptDetails;
10
+ attribution: "user";
11
+ };
12
+ type SkillPromptOptions = {
13
+ streamingBehavior: "steer" | "followUp";
14
+ queueChipText: string;
15
+ };
16
+ interface InvokeSkillCommandOptions {
17
+ propagateErrors?: boolean;
18
+ queueOnly?: boolean;
19
+ images?: ImageContent[];
20
+ }
21
+ /** Built custom-message payload and delivery options for a `/skill:` command. */
22
+ export interface BuiltSkillCommandPrompt {
23
+ message: SkillPromptMessage;
24
+ options: SkillPromptOptions;
25
+ }
26
+ /** Return true when `text` names a registered `/skill:<name>` command. */
27
+ export declare function isKnownSkillCommand(ctx: SkillCommandHost, text: string): boolean;
28
+ /** Build the user-attributed custom message for a registered `/skill:<name>` command. */
29
+ export declare function buildSkillCommandPrompt(ctx: SkillCommandHost, text: string, streamingBehavior: "steer" | "followUp", images?: ImageContent[]): Promise<BuiltSkillCommandPrompt | undefined>;
30
+ /** Invoke a registered `/skill:<name>` command as a user-attributed custom message. */
31
+ export declare function invokeSkillCommandFromText(ctx: SkillCommandHost, text: string, streamingBehavior: "steer" | "followUp", options?: InvokeSkillCommandOptions): Promise<boolean>;
32
+ export {};
@@ -142,10 +142,14 @@ export interface InteractiveModeContext {
142
142
  hideThinkingBlock: boolean;
143
143
  /**
144
144
  * Effective thinking-block visibility: true when hidden by user setting OR
145
- * thinking level is "off". Read this in render paths instead of
146
- * {@link hideThinkingBlock} so blocks are auto-hidden when thinking is off.
145
+ * thinking level is "off" before the session has produced displayable
146
+ * thinking content.
147
147
  */
148
148
  readonly effectiveHideThinkingBlock: boolean;
149
+ /** Whether this visible session has produced thinking content the user can reveal. */
150
+ readonly hasDisplayableThinkingContent: boolean;
151
+ /** Record a message whose thinking content makes Ctrl+T meaningful even at thinking level "off"; returns true on first observation. */
152
+ noteDisplayableThinkingContent(message: AgentMessage): boolean;
149
153
  proseOnlyThinking: boolean;
150
154
  compactionQueuedMessages: CompactionQueuedMessage[];
151
155
  pendingTools: Map<string, ToolExecutionHandle>;
@@ -316,6 +320,7 @@ export interface InteractiveModeContext {
316
320
  refreshSlashCommandState(cwd?: string): Promise<void>;
317
321
  applyCwdChange(newCwd: string): Promise<void>;
318
322
  showSettingsSelector(): void;
323
+ showAdvisorConfigure(): void;
319
324
  showHistorySearch(): void;
320
325
  showExtensionsDashboard(): void;
321
326
  showAgentsDashboard(): void;
@@ -1,5 +1,5 @@
1
1
  import { type AgentTelemetryConfig, type ThinkingLevel } from "@oh-my-pi/pi-agent-core";
2
- import { type Model } from "@oh-my-pi/pi-ai";
2
+ import type { Model } from "@oh-my-pi/pi-ai";
3
3
  import type { Dialect } from "@oh-my-pi/pi-ai/dialect";
4
4
  import { type Rule } from "./capability/rule";
5
5
  import { ModelRegistry } from "./config/model-registry";
@@ -13,10 +13,11 @@
13
13
  * Modes use this class and add their own I/O layer on top.
14
14
  */
15
15
  import type { InMemorySnapshotStore } from "@oh-my-pi/hashline";
16
- import { Agent, type AgentEvent, type AgentMessage, type AgentState, type AgentTool, ThinkingLevel, type ToolChoiceDirective } from "@oh-my-pi/pi-agent-core";
16
+ import { Agent, type AgentEvent, type AgentMessage, type AgentState, type AgentTool, type StreamFn, ThinkingLevel, type ToolChoiceDirective } from "@oh-my-pi/pi-agent-core";
17
17
  import { type CompactionResult, type ShakeConfig } from "@oh-my-pi/pi-agent-core/compaction";
18
- import type { AssistantMessage, ImageContent, Message, MessageAttribution, Model, ProviderSessionState, ResetCreditAccountStatus, ResetCreditRedeemOutcome, ResetCreditTarget, ServiceTier, SimpleStreamOptions, TextContent, ToolChoice, UsageReport } from "@oh-my-pi/pi-ai";
18
+ import type { AssistantMessage, Context, ImageContent, Message, MessageAttribution, Model, ProviderSessionState, ResetCreditAccountStatus, ResetCreditRedeemOutcome, ResetCreditTarget, ServiceTier, SimpleStreamOptions, TextContent, ToolChoice, UsageReport } from "@oh-my-pi/pi-ai";
19
19
  import { Effort } from "@oh-my-pi/pi-ai";
20
+ import { type AdvisorConfig } from "../advisor";
20
21
  import { type AsyncJob, type AsyncJobDeliveryState, AsyncJobManager } from "../async";
21
22
  import type { Rule } from "../capability/rule";
22
23
  import type { ModelRegistry } from "../config/model-registry";
@@ -72,6 +73,7 @@ export type AgentSessionEvent = AgentEvent | {
72
73
  maxAttempts: number;
73
74
  delayMs: number;
74
75
  errorMessage: string;
76
+ errorId?: number;
75
77
  } | {
76
78
  type: "auto_retry_end";
77
79
  success: boolean;
@@ -160,6 +162,21 @@ export interface AgentSessionConfig {
160
162
  builtInToolNames?: Iterable<string>;
161
163
  /** Current session pre-LLM message transform pipeline */
162
164
  transformContext?: (messages: AgentMessage[], signal?: AbortSignal) => AgentMessage[] | Promise<AgentMessage[]>;
165
+ /**
166
+ * Per-request transform applied after `convertToLlm` and before the
167
+ * provider call. Used for snapcompact, secret obfuscation, and image
168
+ * clamping. When supplied via {@link createAgentSession}, the advisor agent
169
+ * inherits this so its requests undergo the same shaping as the main turn.
170
+ */
171
+ transformProviderContext?: (context: Context, model: Model) => Context | Promise<Context>;
172
+ /**
173
+ * Stream wrapper passed to the advisor agent so its requests apply the
174
+ * session's `providers.openrouterVariant`, `providers.antigravityEndpoint`,
175
+ * `providers.maxInFlightRequests`, and `model.loopGuard.*` settings —
176
+ * keeping OpenRouter sticky-routing / response caching consistent with the
177
+ * main agent. Defaults to plain `streamSimple` when omitted.
178
+ */
179
+ advisorStreamFn?: StreamFn;
163
180
  /** Provider payload hook used by the active session request path */
164
181
  onPayload?: SimpleStreamOptions["onPayload"];
165
182
  /** Provider response hook used by the active session request path */
@@ -231,20 +248,29 @@ export interface AgentSessionConfig {
231
248
  */
232
249
  providerSessionId?: string;
233
250
  /**
234
- * Hard-isolated read-only tools (read/search/find) for the advisor agent,
235
- * pre-built in `createAgentSession` against a distinct `ToolSession` so the
236
- * advisor's reads never share the primary's snapshot/seen-lines/conflict
237
- * caches. Undefined when the advisor is disabled.
251
+ * Full advisor toolset, pre-built in `createAgentSession` against a distinct,
252
+ * advisor-scoped `ToolSession` (its own `-advisor` session/agent id) so the
253
+ * advisor's tool state stays isolated from the primary. The advisor is a full
254
+ * agent; its config `tools` selects a subset (default read/grep/glob). Undefined
255
+ * when the advisor is disabled.
238
256
  */
239
- advisorReadOnlyTools?: AgentTool[];
257
+ advisorTools?: AgentTool[];
240
258
  /** Preloaded watchdog prompt content for the advisor. */
241
259
  advisorWatchdogPrompt?: string;
260
+ /** Preloaded YAML top-level `instructions` shared baseline, kept separate from
261
+ * `advisorWatchdogPrompt` so `/advisor configure` can swap it live. */
262
+ advisorSharedInstructions?: string;
242
263
  /**
243
264
  * Preloaded project context files (AGENTS.md, etc.) rendered as a system-prompt
244
265
  * block for the advisor — the same standing instructions the primary agent
245
266
  * receives, so the reviewer holds the agent to them.
246
267
  */
247
268
  advisorContextPrompt?: string;
269
+ /**
270
+ * Advisors discovered from `WATCHDOG.yml`. Empty/undefined runs a single
271
+ * legacy advisor on the `advisor` role (byte-for-byte the pre-config path).
272
+ */
273
+ advisorConfigs?: AdvisorConfig[];
248
274
  /**
249
275
  * Strip tool descriptions from provider-bound tool specs on side requests
250
276
  * (handoff). Must match the session-start value used to build the system
@@ -340,6 +366,7 @@ export interface SessionStats {
340
366
  tokens: {
341
367
  input: number;
342
368
  output: number;
369
+ reasoning: number;
343
370
  cacheRead: number;
344
371
  cacheWrite: number;
345
372
  total: number;
@@ -357,6 +384,7 @@ export interface AdvisorStats {
357
384
  tokens: {
358
385
  input: number;
359
386
  output: number;
387
+ reasoning: number;
360
388
  cacheRead: number;
361
389
  cacheWrite: number;
362
390
  total: number;
@@ -367,6 +395,18 @@ export interface AdvisorStats {
367
395
  assistant: number;
368
396
  total: number;
369
397
  };
398
+ /** Per-advisor breakdown; one entry per active advisor (single-advisor sessions have one). */
399
+ advisors: PerAdvisorStat[];
400
+ }
401
+ /** One advisor's slice of {@link AdvisorStats}, surfaced for the multi-advisor status panel. */
402
+ export interface PerAdvisorStat {
403
+ name: string;
404
+ model: Model;
405
+ contextWindow: number;
406
+ contextTokens: number;
407
+ tokens: AdvisorStats["tokens"];
408
+ cost: number;
409
+ messages: AdvisorStats["messages"];
370
410
  }
371
411
  export interface FreshSessionResult {
372
412
  previousSessionId: string;
@@ -378,6 +418,7 @@ export type RestoredQueuedMessage = {
378
418
  text: string;
379
419
  images?: ImageContent[];
380
420
  };
421
+ type SessionNameTrigger = "replan";
381
422
  export declare class AgentSession {
382
423
  #private;
383
424
  readonly agent: Agent;
@@ -682,6 +723,7 @@ export declare class AgentSession {
682
723
  prompt(text: string, options?: PromptOptions): Promise<boolean>;
683
724
  promptCustomMessage<T = unknown>(message: Pick<CustomMessage<T>, "customType" | "content" | "display" | "details" | "attribution">, options?: Pick<PromptOptions, "streamingBehavior" | "toolChoice"> & {
684
725
  queueChipText?: string;
726
+ queueOnly?: boolean;
685
727
  }): Promise<void>;
686
728
  /**
687
729
  * Queue a steering message to interrupt the agent mid-run.
@@ -781,7 +823,7 @@ export declare class AgentSession {
781
823
  /**
782
824
  * Set a display name for the current session.
783
825
  */
784
- setSessionName(name: string, source?: "auto" | "user"): Promise<boolean>;
826
+ setSessionName(name: string, source?: "auto" | "user", trigger?: SessionNameTrigger): Promise<boolean>;
785
827
  /**
786
828
  * Fork the current session, creating a new session file with the exact same state.
787
829
  * Copies all entries and artifacts to the new session.
@@ -792,16 +834,22 @@ export declare class AgentSession {
792
834
  /**
793
835
  * Set model directly.
794
836
  * Validates that a credential source is configured (synchronously, without
795
- * refreshing OAuth or running command-backed key programs) and saves to the
796
- * active session. Persists settings only when requested. The concrete key is
797
- * resolved lazily per request, so switching never blocks the event loop.
837
+ * refreshing OAuth or running command-backed key programs). The active
838
+ * session switches by default; when `currentContextTokens` is provided and
839
+ * exceeds the refreshed candidate's context window, the live switch is
840
+ * skipped while role persistence still runs. Returns whether the active
841
+ * model actually switched, computed against the refreshed metadata so
842
+ * dynamic providers (e.g. llama.cpp) honor their post-load contextWindow.
798
843
  * @throws Error if no API key available for the model
799
844
  */
800
845
  setModel(model: Model, role?: string, options?: {
801
846
  selector?: string;
802
847
  thinkingLevel?: ThinkingLevel;
803
848
  persist?: boolean;
804
- }): Promise<void>;
849
+ currentContextTokens?: number;
850
+ }): Promise<{
851
+ switched: boolean;
852
+ }>;
805
853
  /**
806
854
  * Set model temporarily (for this session only).
807
855
  * Validates that a credential source is configured (synchronously, without
@@ -1242,6 +1290,15 @@ export declare class AgentSession {
1242
1290
  * @returns true when the advisor is actively running after the call.
1243
1291
  */
1244
1292
  toggleAdvisorEnabled(): boolean;
1293
+ /**
1294
+ * Replace the live advisor roster from an edited `WATCHDOG.yml` (the `/advisor
1295
+ * configure` save path). Swaps the configs + shared baseline, then rebuilds the
1296
+ * runtimes in place so the change applies without a restart. When the advisor is
1297
+ * disabled the new configs are simply stored for the next enable.
1298
+ *
1299
+ * @returns the number of advisors active after the rebuild.
1300
+ */
1301
+ applyAdvisorConfigs(advisors: AdvisorConfig[], sharedInstructions: string | undefined): number;
1245
1302
  /**
1246
1303
  * Whether the advisor setting is enabled for this session.
1247
1304
  */
@@ -1253,6 +1310,21 @@ export declare class AgentSession {
1253
1310
  * not merely the setting. Drives the status-line badge and `/dump advisor`.
1254
1311
  */
1255
1312
  isAdvisorActive(): boolean;
1313
+ /**
1314
+ * The names of the tools available to advisors this session (the pool a
1315
+ * `/advisor configure` editor lists). The advisor is a full agent, so this is the
1316
+ * full built tool set; a tool whose optional factory returns null (e.g. lsp with
1317
+ * no servers) is absent.
1318
+ */
1319
+ getAdvisorAvailableToolNames(): string[];
1320
+ /**
1321
+ * The live advisor `Agent`, or `undefined` when no advisor runtime is
1322
+ * attached. Surfaced for diagnostics (`/dump advisor` already serializes
1323
+ * its transcript via {@link formatAdvisorHistoryAsText}) and so callers can
1324
+ * verify the advisor inherits the session's provider-shaping options
1325
+ * (`streamFn`, `promptCacheKey`, `providerSessionState`, ...).
1326
+ */
1327
+ getAdvisorAgent(): Agent | undefined;
1256
1328
  /**
1257
1329
  * Return structured advisor stats for the status command and TUI panel.
1258
1330
  */
@@ -1,16 +1,21 @@
1
1
  import type { SessionStorage, SessionStorageStat, SessionStorageWriter } from "./session-storage";
2
+ import { type SessionTitleUpdate } from "./session-title-slot";
2
3
  export interface SessionStorageIndexEntry {
3
4
  path: string;
4
5
  size: number;
5
6
  mtimeMs: number;
7
+ title?: string;
8
+ titleSource?: SessionTitleUpdate["source"];
9
+ titleUpdatedAt?: string;
6
10
  }
7
11
  export interface SessionStorageBackend {
8
12
  init(): Promise<void>;
9
13
  loadIndex(): Promise<Iterable<SessionStorageIndexEntry>>;
10
14
  readFull(path: string): Promise<string | null>;
11
15
  readSlices(path: string, prefixBytes: number, suffixBytes: number): Promise<[string, string]>;
12
- writeFull(path: string, content: string, mtimeMs: number): Promise<void>;
16
+ writeFull(path: string, content: string, mtimeMs: number, title?: SessionTitleUpdate): Promise<void>;
13
17
  append(path: string, line: string, mtimeMs: number): Promise<void>;
18
+ updateSessionTitle(path: string, title: SessionTitleUpdate, mtimeMs: number): Promise<void>;
14
19
  truncate(path: string, mtimeMs: number): Promise<void>;
15
20
  remove(paths: string[]): Promise<void>;
16
21
  move(src: string, dst: string, mtimeMs: number): Promise<void>;
@@ -24,6 +29,7 @@ export declare class IndexedSessionStorage implements SessionStorage {
24
29
  ensureDirSync(_dir: string): void;
25
30
  existsSync(path: string): boolean;
26
31
  writeTextSync(path: string, content: string): void;
32
+ updateSessionTitle(path: string, title: SessionTitleUpdate): Promise<void>;
27
33
  statSync(path: string): SessionStorageStat;
28
34
  listFilesSync(dir: string, pattern: string): string[];
29
35
  exists(path: string): Promise<boolean>;