@oh-my-pi/pi-coding-agent 14.9.9 → 15.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (230) hide show
  1. package/CHANGELOG.md +123 -0
  2. package/examples/extensions/plan-mode.ts +0 -1
  3. package/package.json +9 -9
  4. package/scripts/build-binary.ts +5 -0
  5. package/scripts/format-prompts.ts +1 -1
  6. package/src/autoresearch/helpers.ts +17 -0
  7. package/src/autoresearch/tools/log-experiment.ts +9 -17
  8. package/src/autoresearch/tools/run-experiment.ts +2 -17
  9. package/src/capability/skill.ts +7 -0
  10. package/src/cli/args.ts +2 -2
  11. package/src/cli/list-models.ts +1 -1
  12. package/src/cli/shell-cli.ts +3 -13
  13. package/src/cli/update-cli.ts +1 -1
  14. package/src/cli.ts +11 -29
  15. package/src/commands/acp.ts +24 -0
  16. package/src/commands/launch.ts +6 -4
  17. package/src/commit/agentic/prompts/system.md +1 -1
  18. package/src/commit/agentic/tools/propose-changelog.ts +8 -1
  19. package/src/commit/analysis/conventional.ts +8 -66
  20. package/src/commit/map-reduce/reduce-phase.ts +6 -65
  21. package/src/commit/pipeline.ts +2 -2
  22. package/src/commit/shared-llm.ts +89 -0
  23. package/src/config/config-file.ts +210 -0
  24. package/src/config/model-equivalence.ts +8 -11
  25. package/src/config/model-registry.ts +13 -2
  26. package/src/config/model-resolver.ts +31 -4
  27. package/src/config/settings-schema.ts +102 -1
  28. package/src/config/settings.ts +1 -1
  29. package/src/config.ts +3 -219
  30. package/src/edit/index.ts +22 -1
  31. package/src/edit/modes/patch.ts +10 -0
  32. package/src/edit/modes/replace.ts +3 -0
  33. package/src/edit/renderer.ts +17 -1
  34. package/src/eval/js/context-manager.ts +1 -1
  35. package/src/eval/js/executor.ts +3 -0
  36. package/src/eval/js/shared/rewrite-imports.ts +122 -50
  37. package/src/eval/js/shared/runtime.ts +31 -4
  38. package/src/eval/js/tool-bridge.ts +43 -21
  39. package/src/eval/py/executor.ts +5 -0
  40. package/src/exa/factory.ts +2 -2
  41. package/src/exa/mcp-client.ts +74 -1
  42. package/src/exec/bash-executor.ts +5 -1
  43. package/src/export/html/template.generated.ts +1 -1
  44. package/src/export/html/template.js +0 -11
  45. package/src/extensibility/extensions/runner.ts +55 -2
  46. package/src/extensibility/extensions/types.ts +98 -221
  47. package/src/extensibility/hooks/types.ts +89 -314
  48. package/src/extensibility/shared-events.ts +343 -0
  49. package/src/extensibility/skills.ts +42 -1
  50. package/src/goals/index.ts +3 -0
  51. package/src/goals/runtime.ts +500 -0
  52. package/src/goals/state.ts +37 -0
  53. package/src/goals/tools/goal-tool.ts +237 -0
  54. package/src/hashline/anchors.ts +2 -2
  55. package/src/hindsight/mental-models.ts +1 -1
  56. package/src/internal-urls/agent-protocol.ts +1 -20
  57. package/src/internal-urls/artifact-protocol.ts +1 -19
  58. package/src/internal-urls/docs-index.generated.ts +9 -10
  59. package/src/internal-urls/index.ts +1 -0
  60. package/src/internal-urls/issue-pr-protocol.ts +577 -0
  61. package/src/internal-urls/registry-helpers.ts +25 -0
  62. package/src/internal-urls/router.ts +6 -3
  63. package/src/internal-urls/types.ts +22 -1
  64. package/src/main.ts +24 -11
  65. package/src/mcp/oauth-flow.ts +20 -0
  66. package/src/modes/acp/acp-agent.ts +412 -71
  67. package/src/modes/acp/acp-client-bridge.ts +152 -0
  68. package/src/modes/acp/acp-event-mapper.ts +180 -15
  69. package/src/modes/acp/terminal-auth.ts +37 -0
  70. package/src/modes/components/assistant-message.ts +14 -8
  71. package/src/modes/components/bash-execution.ts +24 -63
  72. package/src/modes/components/custom-message.ts +14 -40
  73. package/src/modes/components/eval-execution.ts +27 -57
  74. package/src/modes/components/execution-shared.ts +102 -0
  75. package/src/modes/components/hook-message.ts +17 -49
  76. package/src/modes/components/mcp-add-wizard.ts +26 -5
  77. package/src/modes/components/message-frame.ts +88 -0
  78. package/src/modes/components/model-selector.ts +1 -1
  79. package/src/modes/components/read-tool-group.ts +29 -1
  80. package/src/modes/components/session-observer-overlay.ts +6 -2
  81. package/src/modes/components/session-selector.ts +1 -1
  82. package/src/modes/components/status-line/segments.ts +55 -4
  83. package/src/modes/components/status-line/types.ts +4 -0
  84. package/src/modes/components/status-line.ts +28 -10
  85. package/src/modes/components/tool-execution.ts +7 -8
  86. package/src/modes/controllers/command-controller-shared.ts +108 -0
  87. package/src/modes/controllers/command-controller.ts +27 -10
  88. package/src/modes/controllers/event-controller.ts +60 -18
  89. package/src/modes/controllers/extension-ui-controller.ts +8 -2
  90. package/src/modes/controllers/input-controller.ts +85 -39
  91. package/src/modes/controllers/mcp-command-controller.ts +56 -61
  92. package/src/modes/controllers/ssh-command-controller.ts +18 -57
  93. package/src/modes/interactive-mode.ts +675 -39
  94. package/src/modes/print-mode.ts +16 -86
  95. package/src/modes/rpc/rpc-mode.ts +30 -88
  96. package/src/modes/runtime-init.ts +115 -0
  97. package/src/modes/theme/defaults/dark-poimandres.json +2 -0
  98. package/src/modes/theme/defaults/light-poimandres.json +2 -0
  99. package/src/modes/theme/theme.ts +18 -6
  100. package/src/modes/types.ts +20 -5
  101. package/src/modes/utils/context-usage.ts +13 -13
  102. package/src/modes/utils/ui-helpers.ts +25 -6
  103. package/src/plan-mode/approved-plan.ts +35 -1
  104. package/src/prompts/agents/designer.md +5 -5
  105. package/src/prompts/agents/explore.md +7 -7
  106. package/src/prompts/agents/init.md +9 -9
  107. package/src/prompts/agents/librarian.md +14 -14
  108. package/src/prompts/agents/plan.md +4 -4
  109. package/src/prompts/agents/reviewer.md +5 -5
  110. package/src/prompts/agents/task.md +10 -10
  111. package/src/prompts/commands/orchestrate.md +2 -2
  112. package/src/prompts/compaction/branch-summary.md +3 -3
  113. package/src/prompts/compaction/compaction-short-summary.md +7 -7
  114. package/src/prompts/compaction/compaction-summary-context.md +1 -1
  115. package/src/prompts/compaction/compaction-summary.md +5 -5
  116. package/src/prompts/compaction/compaction-turn-prefix.md +3 -3
  117. package/src/prompts/compaction/compaction-update-summary.md +11 -11
  118. package/src/prompts/goals/goal-budget-limit.md +16 -0
  119. package/src/prompts/goals/goal-continuation.md +28 -0
  120. package/src/prompts/goals/goal-mode-active.md +23 -0
  121. package/src/prompts/memories/consolidation.md +2 -2
  122. package/src/prompts/memories/read-path.md +1 -1
  123. package/src/prompts/memories/stage_one_input.md +1 -1
  124. package/src/prompts/memories/stage_one_system.md +5 -5
  125. package/src/prompts/review-request.md +4 -4
  126. package/src/prompts/system/agent-creation-architect.md +17 -17
  127. package/src/prompts/system/agent-creation-user.md +2 -2
  128. package/src/prompts/system/commit-message-system.md +2 -2
  129. package/src/prompts/system/custom-system-prompt.md +2 -2
  130. package/src/prompts/system/eager-todo.md +6 -6
  131. package/src/prompts/system/handoff-document.md +1 -1
  132. package/src/prompts/system/plan-mode-active.md +25 -24
  133. package/src/prompts/system/plan-mode-approved.md +4 -4
  134. package/src/prompts/system/plan-mode-compact-instructions.md +16 -0
  135. package/src/prompts/system/plan-mode-reference.md +2 -2
  136. package/src/prompts/system/plan-mode-subagent.md +8 -8
  137. package/src/prompts/system/plan-mode-tool-decision-reminder.md +3 -3
  138. package/src/prompts/system/project-prompt.md +4 -4
  139. package/src/prompts/system/subagent-system-prompt.md +7 -7
  140. package/src/prompts/system/subagent-yield-reminder.md +4 -4
  141. package/src/prompts/system/system-prompt.md +72 -71
  142. package/src/prompts/system/ttsr-interrupt.md +1 -1
  143. package/src/prompts/tools/apply-patch.md +1 -1
  144. package/src/prompts/tools/ast-edit.md +3 -3
  145. package/src/prompts/tools/ast-grep.md +3 -3
  146. package/src/prompts/tools/bash.md +6 -0
  147. package/src/prompts/tools/browser.md +3 -3
  148. package/src/prompts/tools/checkpoint.md +3 -3
  149. package/src/prompts/tools/find.md +3 -3
  150. package/src/prompts/tools/github.md +2 -5
  151. package/src/prompts/tools/goal.md +13 -0
  152. package/src/prompts/tools/hashline.md +104 -116
  153. package/src/prompts/tools/image-gen.md +3 -3
  154. package/src/prompts/tools/irc.md +1 -1
  155. package/src/prompts/tools/lsp.md +2 -2
  156. package/src/prompts/tools/patch.md +6 -6
  157. package/src/prompts/tools/read.md +8 -7
  158. package/src/prompts/tools/replace.md +5 -5
  159. package/src/prompts/tools/resolve.md +6 -5
  160. package/src/prompts/tools/retain.md +1 -1
  161. package/src/prompts/tools/rewind.md +2 -2
  162. package/src/prompts/tools/search.md +2 -2
  163. package/src/prompts/tools/ssh.md +2 -2
  164. package/src/prompts/tools/task.md +12 -6
  165. package/src/prompts/tools/web-search.md +2 -2
  166. package/src/prompts/tools/write.md +3 -3
  167. package/src/sdk.ts +81 -17
  168. package/src/session/agent-session.ts +656 -125
  169. package/src/session/blob-store.ts +36 -3
  170. package/src/session/client-bridge.ts +81 -0
  171. package/src/session/compaction/errors.ts +31 -0
  172. package/src/session/compaction/index.ts +1 -0
  173. package/src/session/messages.ts +67 -2
  174. package/src/session/session-manager.ts +131 -12
  175. package/src/session/session-storage.ts +33 -15
  176. package/src/session/streaming-output.ts +309 -13
  177. package/src/slash-commands/acp-builtins.ts +46 -0
  178. package/src/slash-commands/builtin-registry.ts +717 -116
  179. package/src/slash-commands/helpers/context-report.ts +39 -0
  180. package/src/slash-commands/helpers/format.ts +23 -0
  181. package/src/slash-commands/helpers/marketplace-manager.ts +25 -0
  182. package/src/slash-commands/helpers/mcp.ts +532 -0
  183. package/src/slash-commands/helpers/parse.ts +85 -0
  184. package/src/slash-commands/helpers/ssh.ts +193 -0
  185. package/src/slash-commands/helpers/todo.ts +279 -0
  186. package/src/slash-commands/helpers/usage-report.ts +91 -0
  187. package/src/slash-commands/types.ts +126 -0
  188. package/src/ssh/ssh-executor.ts +5 -0
  189. package/src/system-prompt.ts +4 -2
  190. package/src/task/executor.ts +27 -10
  191. package/src/task/index.ts +20 -1
  192. package/src/task/render.ts +27 -18
  193. package/src/task/types.ts +4 -0
  194. package/src/tools/ast-edit.ts +21 -120
  195. package/src/tools/ast-grep.ts +21 -119
  196. package/src/tools/bash-interactive.ts +9 -1
  197. package/src/tools/bash.ts +203 -6
  198. package/src/tools/browser/attach.ts +3 -3
  199. package/src/tools/browser/launch.ts +81 -18
  200. package/src/tools/browser/registry.ts +1 -5
  201. package/src/tools/browser/tab-supervisor.ts +51 -14
  202. package/src/tools/conflict-detect.ts +21 -10
  203. package/src/tools/eval.ts +3 -1
  204. package/src/tools/fetch.ts +15 -4
  205. package/src/tools/find.ts +39 -39
  206. package/src/tools/gh-renderer.ts +0 -12
  207. package/src/tools/gh.ts +689 -182
  208. package/src/tools/github-cache.ts +548 -0
  209. package/src/tools/index.ts +25 -11
  210. package/src/tools/inspect-image.ts +3 -10
  211. package/src/tools/output-meta.ts +176 -37
  212. package/src/tools/path-utils.ts +125 -2
  213. package/src/tools/read.ts +605 -239
  214. package/src/tools/render-utils.ts +92 -0
  215. package/src/tools/renderers.ts +2 -0
  216. package/src/tools/resolve.ts +72 -44
  217. package/src/tools/search.ts +120 -186
  218. package/src/tools/write.ts +67 -10
  219. package/src/tui/code-cell.ts +70 -2
  220. package/src/utils/file-mentions.ts +1 -1
  221. package/src/utils/image-loading.ts +7 -3
  222. package/src/utils/image-resize.ts +32 -43
  223. package/src/vim/parser.ts +0 -17
  224. package/src/vim/render.ts +1 -1
  225. package/src/vim/types.ts +1 -1
  226. package/src/web/search/providers/gemini.ts +35 -95
  227. package/src/prompts/tools/exit-plan-mode.md +0 -6
  228. package/src/tools/exit-plan-mode.ts +0 -97
  229. package/src/utils/fuzzy.ts +0 -108
  230. package/src/utils/image-convert.ts +0 -27
@@ -1155,16 +1155,6 @@
1155
1155
  return html;
1156
1156
  }
1157
1157
 
1158
- function renderExitPlanMode(name, args, result, ctx) {
1159
- const badges = args.title ? [String(args.title)] : null;
1160
- let html = toolHead('exit_plan_mode', '', badges);
1161
- if (result) {
1162
- const output = ctx.getResultText();
1163
- if (output) html += formatExpandableOutput(output, 8);
1164
- }
1165
- return html;
1166
- }
1167
-
1168
1158
  function renderResolve(name, args, result, ctx) {
1169
1159
  const action = str(args.action) || '?';
1170
1160
  let html = toolHead('resolve', '', [action]);
@@ -1562,7 +1552,6 @@
1562
1552
  inspect_image: renderInspectImage,
1563
1553
  generate_image: renderGenerateImage,
1564
1554
  ask: renderAsk,
1565
- exit_plan_mode: renderExitPlanMode,
1566
1555
  resolve: renderResolve,
1567
1556
  github: renderGh,
1568
1557
  render_mermaid: renderMermaid,
@@ -2,7 +2,7 @@
2
2
  * Extension runner - executes extensions and manages their lifecycle.
3
3
  */
4
4
  import type { AgentMessage } from "@oh-my-pi/pi-agent-core";
5
- import type { ImageContent, Model, ProviderResponseMetadata } from "@oh-my-pi/pi-ai";
5
+ import type { CredentialDisabledEvent, ImageContent, Model, ProviderResponseMetadata } from "@oh-my-pi/pi-ai";
6
6
  import type { KeyId } from "@oh-my-pi/pi-tui";
7
7
  import { logger } from "@oh-my-pi/pi-utils";
8
8
  import type { ModelRegistry } from "../../config/model-registry";
@@ -63,12 +63,14 @@ export type ExtensionErrorListener = (error: ExtensionError) => void;
63
63
  export const EXTENSION_HANDLER_TIMEOUT_MS = 30_000;
64
64
  let extensionHandlerTimeoutMs = EXTENSION_HANDLER_TIMEOUT_MS;
65
65
 
66
- export function __test_setExtensionHandlerTimeoutMs(timeoutMs: number): void {
66
+ export function testSetExtensionHandlerTimeoutMs(timeoutMs: number): void {
67
67
  extensionHandlerTimeoutMs = timeoutMs;
68
68
  }
69
69
 
70
70
  const EXTENSION_HANDLER_TIMEOUT = Symbol("extensionHandlerTimeout");
71
71
 
72
+ const MAX_PENDING_CREDENTIAL_DISABLED = 32;
73
+
72
74
  /**
73
75
  * Events handled by the generic emit() method.
74
76
  * Events with dedicated emitXxx() methods are excluded for stronger type safety.
@@ -185,6 +187,15 @@ export class ExtensionRunner {
185
187
  #reloadHandler: () => Promise<void> = async () => {};
186
188
  #shutdownHandler: ShutdownHandler = () => {};
187
189
  #commandDiagnostics: Array<{ type: string; message: string; path: string }> = [];
190
+ #initialized = false;
191
+ /**
192
+ * Buffer for `credential_disabled` events received via {@link emitCredentialDisabled}
193
+ * before {@link initialize} has run. Drained through {@link emit} once initialize sets
194
+ * up the runtime context, so extension handlers see a populated UI/runtime context
195
+ * rather than the constructor's no-op default. Bounded at
196
+ * {@link MAX_PENDING_CREDENTIAL_DISABLED}; oldest entries are dropped under pressure.
197
+ */
198
+ #pendingCredentialDisabled: CredentialDisabledEvent[] = [];
188
199
 
189
200
  constructor(
190
201
  private readonly extensions: Extension[],
@@ -237,6 +248,48 @@ export class ExtensionRunner {
237
248
  }
238
249
 
239
250
  this.#uiContext = uiContext ?? noOpUIContext;
251
+ this.#initialized = true;
252
+
253
+ // Drain events buffered by emitCredentialDisabled() before initialize ran. The
254
+ // spread adds the `type` discriminator — `event` is the pi-ai shape (no `type`).
255
+ // Deferred by one microtask so callers that register an onError listener
256
+ // synchronously after initialize() see handler errors routed through it.
257
+ const pending = this.#pendingCredentialDisabled.splice(0);
258
+ queueMicrotask(() => {
259
+ for (const event of pending) {
260
+ this.emit({ type: "credential_disabled", ...event }).catch((error: unknown) => {
261
+ logger.warn("credential_disabled handler threw during initialize flush", {
262
+ provider: event.provider,
263
+ error: error instanceof Error ? error.message : String(error),
264
+ });
265
+ });
266
+ }
267
+ });
268
+ }
269
+
270
+ /**
271
+ * Forward a `credential_disabled` event from `AuthStorage` to extension handlers.
272
+ *
273
+ * If {@link initialize} has not yet run, the event is buffered and replayed once
274
+ * initialize wires the runtime/UI context. This matters because mode controllers
275
+ * (interactive, RPC, ACP, print, subagent) call `initialize()` AFTER `createAgentSession`
276
+ * returns, but `AuthStorage` can fire `credential_disabled` during startup model probes
277
+ * inside `createAgentSession()`. Without deferral, extension handlers would observe
278
+ * `hasUI=false`, an unset model, and no-op runtime actions on exactly the headline
279
+ * "OAuth invalid_grant during startup" path the event was designed to surface.
280
+ *
281
+ * Always returns; never throws. Errors from handlers are routed through
282
+ * {@link onError} via {@link emit}'s normal isolation.
283
+ */
284
+ async emitCredentialDisabled(event: CredentialDisabledEvent): Promise<void> {
285
+ if (!this.#initialized) {
286
+ if (this.#pendingCredentialDisabled.length >= MAX_PENDING_CREDENTIAL_DISABLED) {
287
+ this.#pendingCredentialDisabled.shift();
288
+ }
289
+ this.#pendingCredentialDisabled.push(event);
290
+ return;
291
+ }
292
+ await this.emit({ type: "credential_disabled", ...event });
240
293
  }
241
294
 
242
295
  getUIContext(): ExtensionUIContext {
@@ -18,13 +18,11 @@ import type {
18
18
  ProviderResponseMetadata,
19
19
  SimpleStreamOptions,
20
20
  TextContent,
21
- ToolResultMessage,
22
21
  } from "@oh-my-pi/pi-ai";
23
22
  import type { OAuthCredentials, OAuthLoginCallbacks } from "@oh-my-pi/pi-ai/utils/oauth/types";
24
23
  import type * as piCodingAgent from "@oh-my-pi/pi-coding-agent";
25
24
  import type { AutocompleteItem, Component, EditorTheme, KeyId, TUI } from "@oh-my-pi/pi-tui";
26
25
  import type { Static, TSchema } from "@sinclair/typebox";
27
- import type { Rule } from "../../capability/rule";
28
26
  import type { KeybindingsManager } from "../../config/keybindings";
29
27
  import type { ModelRegistry } from "../../config/model-registry";
30
28
  import type { EditToolDetails } from "../../edit";
@@ -33,15 +31,9 @@ import type { BashResult } from "../../exec/bash-executor";
33
31
  import type { ExecOptions, ExecResult } from "../../exec/exec";
34
32
  import type { CustomEditor } from "../../modes/components/custom-editor";
35
33
  import type { Theme } from "../../modes/theme/theme";
36
- import type { CompactionPreparation, CompactionResult } from "../../session/compaction";
34
+ import type { CompactionResult } from "../../session/compaction";
37
35
  import type { CustomMessage } from "../../session/messages";
38
- import type {
39
- BranchSummaryEntry,
40
- CompactionEntry,
41
- ReadonlySessionManager,
42
- SessionEntry,
43
- SessionManager,
44
- } from "../../session/session-manager";
36
+ import type { ReadonlySessionManager, SessionManager } from "../../session/session-manager";
45
37
  import type {
46
38
  BashToolDetails,
47
39
  BashToolInput,
@@ -53,8 +45,40 @@ import type {
53
45
  SearchToolInput,
54
46
  WriteToolInput,
55
47
  } from "../../tools";
56
- import type { TodoItem } from "../../tools/todo-write";
57
48
  import type { EventBus } from "../../utils/event-bus";
49
+ import type {
50
+ AgentEndEvent,
51
+ AgentStartEvent,
52
+ AutoCompactionEndEvent,
53
+ AutoCompactionStartEvent,
54
+ AutoRetryEndEvent,
55
+ AutoRetryStartEvent,
56
+ ContextEvent,
57
+ GoalUpdatedEvent,
58
+ SessionBeforeBranchEvent,
59
+ SessionBeforeBranchResult,
60
+ SessionBeforeCompactEvent,
61
+ SessionBeforeCompactResult,
62
+ SessionBeforeSwitchEvent,
63
+ SessionBeforeSwitchResult,
64
+ SessionBeforeTreeEvent,
65
+ SessionBeforeTreeResult,
66
+ SessionBranchEvent,
67
+ SessionCompactEvent,
68
+ SessionCompactingEvent,
69
+ SessionCompactingResult,
70
+ SessionEvent,
71
+ SessionShutdownEvent,
72
+ SessionStartEvent,
73
+ SessionSwitchEvent,
74
+ SessionTreeEvent,
75
+ TodoReminderEvent,
76
+ ToolCallEventResult,
77
+ ToolResultEventResult,
78
+ TtsrTriggeredEvent,
79
+ TurnEndEvent,
80
+ TurnStartEvent,
81
+ } from "../shared-events";
58
82
  import type { SlashCommandInfo } from "../slash-commands";
59
83
 
60
84
  export type { AppKeybinding, KeybindingsManager } from "../../config/keybindings";
@@ -104,6 +128,11 @@ export type ExtensionWidgetContent = string[] | ExtensionUiComponentFactory | un
104
128
  * UI context for extensions to request interactive UI.
105
129
  * Each mode (interactive, RPC, print) provides its own implementation.
106
130
  */
131
+ // fallow-ignore-next-line code-duplication
132
+ // Parallel to HookUIContext: extensions expose a strictly larger UI surface
133
+ // (custom editor component, header/footer, widgets, theming, terminal input)
134
+ // and may be invoked from event handlers that have already taken the agent
135
+ // loop's lock — hooks intentionally cannot.
107
136
  export interface ExtensionUIContext {
108
137
  /** Show a selector and return the user's choice. */
109
138
  select(title: string, options: string[], dialogOptions?: ExtensionUIDialogOptions): Promise<string | undefined>;
@@ -221,6 +250,11 @@ export interface CompactOptions {
221
250
  /**
222
251
  * Context passed to extension event handlers.
223
252
  */
253
+ // fallow-ignore-next-line code-duplication
254
+ // Parallel to HookContext: extensions expose a strictly larger runtime
255
+ // surface (model registry, system prompt, shutdown, full session manager
256
+ // access). Field overlap is incidental; merging into a base would require
257
+ // hooks to widen their public contract.
224
258
  export interface ExtensionContext {
225
259
  /** UI methods for user interaction */
226
260
  ui: ExtensionUIContext;
@@ -256,6 +290,10 @@ export interface ExtensionContext {
256
290
  * Extended context for command handlers.
257
291
  * Includes session control methods only safe in user-initiated commands.
258
292
  */
293
+ // fallow-ignore-next-line code-duplication
294
+ // Parallel to HookCommandContext: same method names, different invariants —
295
+ // extension commands additionally permit `switchSession` and `reload`,
296
+ // which hooks must not call to avoid deadlocking the agent loop.
259
297
  export interface ExtensionCommandContext extends ExtensionContext {
260
298
  /** Get current context usage for the active model. */
261
299
  getContextUsage(): ContextUsage | undefined;
@@ -373,115 +411,30 @@ export interface ResourcesDiscoverResult {
373
411
  }
374
412
 
375
413
  // ============================================================================
376
- // Session Events
414
+ // Session Events (shared with hooks subsystem)
377
415
  // ============================================================================
378
416
 
379
- /** Fired on initial session load */
380
- export interface SessionStartEvent {
381
- type: "session_start";
382
- }
383
-
384
- /** Fired before switching to another session (can be cancelled) */
385
- export interface SessionBeforeSwitchEvent {
386
- type: "session_before_switch";
387
- reason: "new" | "resume" | "fork";
388
- targetSessionFile?: string;
389
- }
390
-
391
- /** Fired after switching to another session */
392
- export interface SessionSwitchEvent {
393
- type: "session_switch";
394
- reason: "new" | "resume" | "fork";
395
- previousSessionFile: string | undefined;
396
- }
397
-
398
- /** Fired before branching a session (can be cancelled) */
399
- export interface SessionBeforeBranchEvent {
400
- type: "session_before_branch";
401
- entryId: string;
402
- }
403
-
404
- /** Fired after branching a session */
405
- export interface SessionBranchEvent {
406
- type: "session_branch";
407
- previousSessionFile: string | undefined;
408
- }
409
-
410
- /** Fired before context compaction (can be cancelled or customized) */
411
- export interface SessionBeforeCompactEvent {
412
- type: "session_before_compact";
413
- preparation: CompactionPreparation;
414
- branchEntries: SessionEntry[];
415
- customInstructions?: string;
416
- signal: AbortSignal;
417
- }
418
-
419
- /** Fired before compaction summarization to customize prompts/context */
420
- export interface SessionCompactingEvent {
421
- type: "session.compacting";
422
- sessionId: string;
423
- messages: AgentMessage[];
424
- }
425
-
426
- /** Fired after context compaction */
427
- export interface SessionCompactEvent {
428
- type: "session_compact";
429
- compactionEntry: CompactionEntry;
430
- fromExtension: boolean;
431
- }
432
-
433
- /** Fired on process exit */
434
- export interface SessionShutdownEvent {
435
- type: "session_shutdown";
436
- }
437
-
438
- /** Preparation data for tree navigation */
439
- export interface TreePreparation {
440
- targetId: string;
441
- oldLeafId: string | null;
442
- commonAncestorId: string | null;
443
- entriesToSummarize: SessionEntry[];
444
- userWantsSummary: boolean;
445
- }
446
-
447
- /** Fired before navigating in the session tree (can be cancelled) */
448
- export interface SessionBeforeTreeEvent {
449
- type: "session_before_tree";
450
- preparation: TreePreparation;
451
- signal: AbortSignal;
452
- }
453
-
454
- /** Fired after navigating in the session tree */
455
- export interface SessionTreeEvent {
456
- type: "session_tree";
457
- newLeafId: string | null;
458
- oldLeafId: string | null;
459
- summaryEntry?: BranchSummaryEntry;
460
- fromExtension?: boolean;
461
- }
462
-
463
- export type SessionEvent =
464
- | SessionStartEvent
465
- | SessionBeforeSwitchEvent
466
- | SessionSwitchEvent
467
- | SessionBeforeBranchEvent
468
- | SessionBranchEvent
469
- | SessionBeforeCompactEvent
470
- | SessionCompactingEvent
471
- | SessionCompactEvent
472
- | SessionShutdownEvent
473
- | SessionBeforeTreeEvent
474
- | SessionTreeEvent;
417
+ export type {
418
+ SessionBeforeBranchEvent,
419
+ SessionBeforeCompactEvent,
420
+ SessionBeforeSwitchEvent,
421
+ SessionBeforeTreeEvent,
422
+ SessionBranchEvent,
423
+ SessionCompactEvent,
424
+ SessionCompactingEvent,
425
+ SessionEvent,
426
+ SessionShutdownEvent,
427
+ SessionStartEvent,
428
+ SessionSwitchEvent,
429
+ SessionTreeEvent,
430
+ TreePreparation,
431
+ } from "../shared-events";
475
432
 
476
433
  // ============================================================================
477
434
  // Agent Events
478
435
  // ============================================================================
479
436
 
480
- /** Fired before each LLM call. Can modify messages. */
481
- export interface ContextEvent {
482
- type: "context";
483
- messages: AgentMessage[];
484
- }
437
+ export type { ContextEvent } from "../shared-events";
485
438
 
486
439
  /** Fired before a provider request is sent. Can replace the payload. */
487
440
  export interface BeforeProviderRequestEvent {
@@ -502,31 +455,7 @@ export interface BeforeAgentStartEvent {
502
455
  systemPrompt: string[];
503
456
  }
504
457
 
505
- /** Fired when an agent loop starts */
506
- export interface AgentStartEvent {
507
- type: "agent_start";
508
- }
509
-
510
- /** Fired when an agent loop ends */
511
- export interface AgentEndEvent {
512
- type: "agent_end";
513
- messages: AgentMessage[];
514
- }
515
-
516
- /** Fired at the start of each turn */
517
- export interface TurnStartEvent {
518
- type: "turn_start";
519
- turnIndex: number;
520
- timestamp: number;
521
- }
522
-
523
- /** Fired at the end of each turn */
524
- export interface TurnEndEvent {
525
- type: "turn_end";
526
- turnIndex: number;
527
- message: AgentMessage;
528
- toolResults: ToolResultMessage[];
529
- }
458
+ export type { AgentEndEvent, AgentStartEvent, TurnEndEvent, TurnStartEvent } from "../shared-events";
530
459
 
531
460
  /** Fired when a message starts (user, assistant, or toolResult) */
532
461
  export interface MessageStartEvent {
@@ -574,54 +503,22 @@ export interface ToolExecutionEndEvent {
574
503
  isError: boolean;
575
504
  }
576
505
 
577
- /** Fired when auto-compaction starts */
578
- export interface AutoCompactionStartEvent {
579
- type: "auto_compaction_start";
580
- reason: "threshold" | "overflow" | "idle";
581
- action: "context-full" | "handoff";
582
- }
583
-
584
- /** Fired when auto-compaction ends */
585
- export interface AutoCompactionEndEvent {
586
- type: "auto_compaction_end";
587
- action: "context-full" | "handoff";
588
- result: CompactionResult | undefined;
589
- aborted: boolean;
590
- willRetry: boolean;
591
- errorMessage?: string;
592
- /** True when compaction was skipped for a benign reason (no model, no candidates, nothing to compact). */
593
- skipped?: boolean;
594
- }
595
-
596
- /** Fired when auto-retry starts */
597
- export interface AutoRetryStartEvent {
598
- type: "auto_retry_start";
599
- attempt: number;
600
- maxAttempts: number;
601
- delayMs: number;
602
- errorMessage: string;
603
- }
604
-
605
- /** Fired when auto-retry ends */
606
- export interface AutoRetryEndEvent {
607
- type: "auto_retry_end";
608
- success: boolean;
609
- attempt: number;
610
- finalError?: string;
611
- }
506
+ export type {
507
+ AutoCompactionEndEvent,
508
+ AutoCompactionStartEvent,
509
+ AutoRetryEndEvent,
510
+ AutoRetryStartEvent,
511
+ TodoReminderEvent,
512
+ TtsrTriggeredEvent,
513
+ } from "../shared-events";
612
514
 
613
- /** Fired when TTSR rule matching interrupts generation */
614
- export interface TtsrTriggeredEvent {
615
- type: "ttsr_triggered";
616
- rules: Rule[];
617
- }
618
-
619
- /** Fired when todo reminder logic detects unfinished todos */
620
- export interface TodoReminderEvent {
621
- type: "todo_reminder";
622
- todos: TodoItem[];
623
- attempt: number;
624
- maxAttempts: number;
515
+ /** Fired when AuthStorage automatically soft-disables a credential (e.g. OAuth `invalid_grant`). Not fired for user-initiated `remove()` or duplicate-credential dedup. */
516
+ export interface CredentialDisabledEvent {
517
+ type: "credential_disabled";
518
+ /** Provider id whose credential was disabled (e.g. "anthropic"). */
519
+ provider: string;
520
+ /** Verbatim error captured for forensics (truncated upstream). */
521
+ disabledCause: string;
625
522
  }
626
523
 
627
524
  // ============================================================================
@@ -831,6 +728,8 @@ export type ExtensionEvent =
831
728
  | AutoRetryEndEvent
832
729
  | TtsrTriggeredEvent
833
730
  | TodoReminderEvent
731
+ | GoalUpdatedEvent
732
+ | CredentialDisabledEvent
834
733
  | UserBashEvent
835
734
  | UserPythonEvent
836
735
  | InputEvent
@@ -847,10 +746,7 @@ export interface ContextEventResult {
847
746
 
848
747
  export type BeforeProviderRequestEventResult = unknown;
849
748
 
850
- export interface ToolCallEventResult {
851
- block?: boolean;
852
- reason?: string;
853
- }
749
+ export type { ToolCallEventResult } from "../shared-events";
854
750
 
855
751
  /** Result from input event handler */
856
752
  export interface InputEventResult {
@@ -874,11 +770,7 @@ export interface UserPythonEventResult {
874
770
  result?: PythonResult;
875
771
  }
876
772
 
877
- export interface ToolResultEventResult {
878
- content?: (TextContent | ImageContent)[];
879
- details?: unknown;
880
- isError?: boolean;
881
- }
773
+ export type { ToolResultEventResult } from "../shared-events";
882
774
 
883
775
  export interface BeforeAgentStartEventResult {
884
776
  message?: Pick<CustomMessage, "customType" | "content" | "display" | "details" | "attribution">;
@@ -886,33 +778,13 @@ export interface BeforeAgentStartEventResult {
886
778
  systemPrompt?: string[];
887
779
  }
888
780
 
889
- export interface SessionBeforeSwitchResult {
890
- cancel?: boolean;
891
- }
892
-
893
- export interface SessionBeforeBranchResult {
894
- cancel?: boolean;
895
- skipConversationRestore?: boolean;
896
- }
897
-
898
- export interface SessionBeforeCompactResult {
899
- cancel?: boolean;
900
- compaction?: CompactionResult;
901
- }
902
-
903
- export interface SessionCompactingResult {
904
- context?: string[];
905
- prompt?: string;
906
- preserveData?: Record<string, unknown>;
907
- }
908
-
909
- export interface SessionBeforeTreeResult {
910
- cancel?: boolean;
911
- summary?: {
912
- summary: string;
913
- details?: unknown;
914
- };
915
- }
781
+ export type {
782
+ SessionBeforeBranchResult,
783
+ SessionBeforeCompactResult,
784
+ SessionBeforeSwitchResult,
785
+ SessionBeforeTreeResult,
786
+ SessionCompactingResult,
787
+ } from "../shared-events";
916
788
 
917
789
  // ============================================================================
918
790
  // Message Rendering
@@ -932,6 +804,9 @@ export type MessageRenderer<T = unknown> = (
932
804
  // Command Registration
933
805
  // ============================================================================
934
806
 
807
+ // fallow-ignore-next-line code-duplication
808
+ // Parallel to HookAPI's RegisteredCommand: extensions add
809
+ // `getArgumentCompletions` and bind handlers to ExtensionCommandContext.
935
810
  export interface RegisteredCommand {
936
811
  name: string;
937
812
  description?: string;
@@ -1012,6 +887,8 @@ export interface ExtensionAPI {
1012
887
  on(event: "auto_retry_end", handler: ExtensionHandler<AutoRetryEndEvent>): void;
1013
888
  on(event: "ttsr_triggered", handler: ExtensionHandler<TtsrTriggeredEvent>): void;
1014
889
  on(event: "todo_reminder", handler: ExtensionHandler<TodoReminderEvent>): void;
890
+ on(event: "goal_updated", handler: ExtensionHandler<GoalUpdatedEvent>): void;
891
+ on(event: "credential_disabled", handler: ExtensionHandler<CredentialDisabledEvent>): void;
1015
892
  on(event: "input", handler: ExtensionHandler<InputEvent, InputEventResult>): void;
1016
893
  on(event: "tool_call", handler: ExtensionHandler<ToolCallEvent, ToolCallEventResult>): void;
1017
894
  on(event: "tool_result", handler: ExtensionHandler<ToolResultEvent, ToolResultEventResult>): void;