@oh-my-pi/pi-coding-agent 15.10.12 → 15.11.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 (158) hide show
  1. package/CHANGELOG.md +90 -4
  2. package/dist/cli.js +869 -825
  3. package/dist/types/async/index.d.ts +0 -1
  4. package/dist/types/capability/mcp.d.ts +1 -0
  5. package/dist/types/cli/gallery-fixtures/types.d.ts +5 -0
  6. package/dist/types/config/keybindings.d.ts +6 -1
  7. package/dist/types/config/settings-schema.d.ts +66 -34
  8. package/dist/types/export/html/template.generated.d.ts +1 -1
  9. package/dist/types/extensibility/custom-tools/types.d.ts +2 -2
  10. package/dist/types/extensibility/shared-events.d.ts +2 -2
  11. package/dist/types/internal-urls/history-protocol.d.ts +14 -0
  12. package/dist/types/internal-urls/index.d.ts +1 -0
  13. package/dist/types/internal-urls/types.d.ts +1 -1
  14. package/dist/types/irc/bus.d.ts +66 -0
  15. package/dist/types/mcp/oauth-discovery.d.ts +2 -0
  16. package/dist/types/mcp/oauth-flow.d.ts +6 -1
  17. package/dist/types/mcp/transports/stdio.d.ts +1 -0
  18. package/dist/types/mcp/types.d.ts +2 -0
  19. package/dist/types/modes/components/agent-hub.d.ts +30 -0
  20. package/dist/types/modes/components/assistant-message.d.ts +1 -0
  21. package/dist/types/modes/components/compaction-summary-message.d.ts +10 -4
  22. package/dist/types/modes/components/custom-editor.d.ts +2 -0
  23. package/dist/types/modes/components/mcp-add-wizard.d.ts +2 -1
  24. package/dist/types/modes/components/settings-selector.d.ts +1 -0
  25. package/dist/types/modes/components/status-line/types.d.ts +3 -0
  26. package/dist/types/modes/components/tool-execution.d.ts +8 -0
  27. package/dist/types/modes/components/transcript-container.d.ts +3 -2
  28. package/dist/types/modes/components/ttsr-notification.d.ts +5 -1
  29. package/dist/types/modes/components/welcome.d.ts +3 -9
  30. package/dist/types/modes/controllers/selector-controller.d.ts +1 -1
  31. package/dist/types/modes/controllers/tool-args-reveal.d.ts +43 -0
  32. package/dist/types/modes/interactive-mode.d.ts +3 -2
  33. package/dist/types/modes/theme/theme.d.ts +3 -1
  34. package/dist/types/modes/types.d.ts +3 -2
  35. package/dist/types/modes/utils/ui-helpers.d.ts +1 -1
  36. package/dist/types/registry/agent-lifecycle.d.ts +51 -0
  37. package/dist/types/registry/agent-registry.d.ts +16 -5
  38. package/dist/types/session/agent-session.d.ts +35 -30
  39. package/dist/types/session/messages.d.ts +2 -4
  40. package/dist/types/session/session-history-format.d.ts +12 -0
  41. package/dist/types/session/session-manager.d.ts +21 -3
  42. package/dist/types/session/streaming-output.d.ts +23 -0
  43. package/dist/types/task/executor.d.ts +11 -2
  44. package/dist/types/task/index.d.ts +11 -4
  45. package/dist/types/task/output-manager.d.ts +0 -7
  46. package/dist/types/task/repair-args.d.ts +8 -7
  47. package/dist/types/task/types.d.ts +55 -51
  48. package/dist/types/tools/browser/tab-worker.d.ts +3 -1
  49. package/dist/types/tools/find.d.ts +0 -11
  50. package/dist/types/tools/grouped-file-output.d.ts +0 -49
  51. package/dist/types/tools/index.d.ts +1 -3
  52. package/dist/types/tools/irc.d.ts +76 -38
  53. package/dist/types/tools/job.d.ts +7 -1
  54. package/dist/types/tools/render-utils.d.ts +22 -0
  55. package/examples/extensions/with-deps/package.json +1 -0
  56. package/package.json +11 -10
  57. package/scripts/bundle-dist.ts +28 -19
  58. package/src/async/index.ts +0 -1
  59. package/src/capability/mcp.ts +1 -0
  60. package/src/cli/gallery-cli.ts +6 -5
  61. package/src/cli/gallery-fixtures/agentic.ts +230 -115
  62. package/src/cli/gallery-fixtures/types.ts +5 -0
  63. package/src/cli.ts +20 -6
  64. package/src/commit/agentic/tools/analyze-file.ts +38 -19
  65. package/src/config/keybindings.ts +6 -1
  66. package/src/config/mcp-schema.json +4 -0
  67. package/src/config/settings-schema.ts +68 -41
  68. package/src/config/settings.ts +7 -0
  69. package/src/edit/renderer.ts +96 -46
  70. package/src/eval/__tests__/agent-bridge.test.ts +5 -3
  71. package/src/eval/agent-bridge.ts +3 -16
  72. package/src/eval/js/shared/prelude.txt +1 -1
  73. package/src/eval/py/prelude.py +5 -6
  74. package/src/export/html/template.generated.ts +1 -1
  75. package/src/export/html/template.js +44 -14
  76. package/src/extensibility/custom-tools/types.ts +2 -2
  77. package/src/extensibility/shared-events.ts +2 -2
  78. package/src/internal-urls/docs-index.generated.ts +9 -9
  79. package/src/internal-urls/history-protocol.ts +113 -0
  80. package/src/internal-urls/index.ts +1 -0
  81. package/src/internal-urls/router.ts +3 -1
  82. package/src/internal-urls/types.ts +1 -1
  83. package/src/irc/bus.ts +292 -0
  84. package/src/main.ts +8 -60
  85. package/src/mcp/manager.ts +3 -0
  86. package/src/mcp/oauth-discovery.ts +27 -2
  87. package/src/mcp/oauth-flow.ts +47 -1
  88. package/src/mcp/transports/stdio.ts +3 -0
  89. package/src/mcp/types.ts +2 -0
  90. package/src/modes/components/{session-observer-overlay.ts → agent-hub.ts} +586 -367
  91. package/src/modes/components/assistant-message.ts +15 -0
  92. package/src/modes/components/btw-panel.ts +5 -1
  93. package/src/modes/components/compaction-summary-message.ts +68 -32
  94. package/src/modes/components/custom-editor.ts +10 -0
  95. package/src/modes/components/mcp-add-wizard.ts +13 -0
  96. package/src/modes/components/settings-selector.ts +2 -0
  97. package/src/modes/components/status-line/component.ts +22 -12
  98. package/src/modes/components/status-line/types.ts +3 -0
  99. package/src/modes/components/tool-execution.ts +31 -1
  100. package/src/modes/components/transcript-container.ts +99 -18
  101. package/src/modes/components/tree-selector.ts +6 -1
  102. package/src/modes/components/ttsr-notification.ts +72 -30
  103. package/src/modes/components/welcome.ts +9 -33
  104. package/src/modes/controllers/event-controller.ts +93 -4
  105. package/src/modes/controllers/extension-ui-controller.ts +8 -8
  106. package/src/modes/controllers/input-controller.ts +18 -2
  107. package/src/modes/controllers/mcp-command-controller.ts +34 -2
  108. package/src/modes/controllers/selector-controller.ts +25 -17
  109. package/src/modes/controllers/tool-args-reveal.ts +174 -0
  110. package/src/modes/interactive-mode.ts +17 -15
  111. package/src/modes/theme/theme.ts +24 -5
  112. package/src/modes/types.ts +3 -5
  113. package/src/modes/utils/hotkeys-markdown.ts +1 -0
  114. package/src/modes/utils/ui-helpers.ts +51 -49
  115. package/src/prompts/system/irc-incoming.md +3 -4
  116. package/src/prompts/system/orchestrate-notice.md +2 -2
  117. package/src/prompts/system/subagent-system-prompt.md +0 -5
  118. package/src/prompts/system/system-prompt.md +1 -0
  119. package/src/prompts/system/workflow-notice.md +2 -2
  120. package/src/prompts/tools/eval.md +3 -3
  121. package/src/prompts/tools/irc.md +29 -19
  122. package/src/prompts/tools/read.md +2 -2
  123. package/src/prompts/tools/task-summary.md +5 -16
  124. package/src/prompts/tools/task.md +43 -29
  125. package/src/registry/agent-lifecycle.ts +218 -0
  126. package/src/registry/agent-registry.ts +16 -5
  127. package/src/sdk.ts +29 -9
  128. package/src/session/agent-session.ts +268 -241
  129. package/src/session/messages.ts +11 -78
  130. package/src/session/session-history-format.ts +246 -0
  131. package/src/session/session-manager.ts +59 -5
  132. package/src/session/streaming-output.ts +60 -0
  133. package/src/task/executor.ts +855 -466
  134. package/src/task/index.ts +723 -794
  135. package/src/task/output-manager.ts +0 -11
  136. package/src/task/render.ts +142 -66
  137. package/src/task/repair-args.ts +21 -9
  138. package/src/task/types.ts +73 -66
  139. package/src/tools/ask.ts +4 -2
  140. package/src/tools/bash.ts +15 -5
  141. package/src/tools/browser/tab-worker.ts +26 -7
  142. package/src/tools/browser.ts +28 -1
  143. package/src/tools/find.ts +2 -27
  144. package/src/tools/grouped-file-output.ts +1 -118
  145. package/src/tools/index.ts +4 -12
  146. package/src/tools/irc.ts +596 -171
  147. package/src/tools/job.ts +41 -7
  148. package/src/tools/read.ts +57 -1
  149. package/src/tools/render-utils.ts +56 -0
  150. package/src/tools/renderers.ts +2 -0
  151. package/src/tools/resolve.ts +4 -1
  152. package/src/tools/write.ts +65 -47
  153. package/src/web/search/providers/anthropic.ts +29 -4
  154. package/dist/types/async/support.d.ts +0 -2
  155. package/dist/types/modes/components/session-observer-overlay.d.ts +0 -11
  156. package/dist/types/task/simple-mode.d.ts +0 -8
  157. package/src/async/support.ts +0 -5
  158. package/src/task/simple-mode.ts +0 -27
@@ -88,10 +88,10 @@ export type CustomToolSessionEvent = {
88
88
  } | {
89
89
  reason: "auto_compaction_start";
90
90
  trigger: "threshold" | "overflow" | "idle" | "incomplete";
91
- action: "context-full" | "handoff" | "shake";
91
+ action: "context-full" | "handoff" | "shake" | "snapcompact";
92
92
  } | {
93
93
  reason: "auto_compaction_end";
94
- action: "context-full" | "handoff" | "shake";
94
+ action: "context-full" | "handoff" | "shake" | "snapcompact";
95
95
  result: CompactionResult | undefined;
96
96
  aborted: boolean;
97
97
  willRetry: boolean;
@@ -160,12 +160,12 @@ export interface TurnEndEvent {
160
160
  export interface AutoCompactionStartEvent {
161
161
  type: "auto_compaction_start";
162
162
  reason: "threshold" | "overflow" | "idle" | "incomplete";
163
- action: "context-full" | "handoff" | "shake";
163
+ action: "context-full" | "handoff" | "shake" | "snapcompact";
164
164
  }
165
165
  /** Fired when auto-compaction ends */
166
166
  export interface AutoCompactionEndEvent {
167
167
  type: "auto_compaction_end";
168
- action: "context-full" | "handoff" | "shake";
168
+ action: "context-full" | "handoff" | "shake" | "snapcompact";
169
169
  result: CompactionResult | undefined;
170
170
  aborted: boolean;
171
171
  willRetry: boolean;
@@ -0,0 +1,14 @@
1
+ import type { InternalResource, InternalUrl, ProtocolHandler, UrlCompletion } from "./types";
2
+ /**
3
+ * Handler for history:// URLs.
4
+ *
5
+ * Resolves agent ids against the global AgentRegistry, serving transcripts
6
+ * for both live and parked agents.
7
+ */
8
+ export declare class HistoryProtocolHandler implements ProtocolHandler {
9
+ #private;
10
+ readonly scheme = "history";
11
+ readonly immutable = false;
12
+ resolve(url: InternalUrl): Promise<InternalResource>;
13
+ complete(): Promise<UrlCompletion[]>;
14
+ }
@@ -9,6 +9,7 @@
9
9
  */
10
10
  export * from "./agent-protocol";
11
11
  export * from "./artifact-protocol";
12
+ export * from "./history-protocol";
12
13
  export * from "./issue-pr-protocol";
13
14
  export * from "./json-query";
14
15
  export * from "./local-protocol";
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Types for the internal URL routing system.
3
3
  *
4
- * Internal URLs (`agent://`, `artifact://`, `issue://`, `local://`, `mcp://`, `memory://`, `omp://`, `pr://`, `rule://`, `skill://`, and `vault://`) are resolved by tools like read,
4
+ * Internal URLs (`agent://`, `artifact://`, `history://`, `issue://`, `local://`, `mcp://`, `memory://`, `omp://`, `pr://`, `rule://`, `skill://`, and `vault://`) are resolved by tools like read,
5
5
  * providing access to agent outputs and server resources without exposing filesystem paths.
6
6
  */
7
7
  import type { LocalProtocolOptions } from "./local-protocol";
@@ -0,0 +1,66 @@
1
+ /**
2
+ * IrcBus - Process-global mailbox bus for agent-to-agent messaging.
3
+ *
4
+ * Replaces the old auto-reply model: a `send` never blocks on the recipient
5
+ * generating anything. Delivery resolves the recipient via the global
6
+ * AgentRegistry — parked agents are revived through the
7
+ * AgentLifecycleManager, idle agents are woken with a real turn, and busy
8
+ * agents receive the message as a non-interrupting aside at the next step
9
+ * boundary (see AgentSession.deliverIrcMessage). Replies are real turns by
10
+ * the recipient, observed via `wait`.
11
+ */
12
+ import { AgentLifecycleManager } from "../registry/agent-lifecycle";
13
+ import { AgentRegistry } from "../registry/agent-registry";
14
+ export interface IrcMessage {
15
+ id: string;
16
+ /** Sender agent id. */
17
+ from: string;
18
+ /** Recipient agent id (resolved; "all" is expanded by the tool, not stored). */
19
+ to: string;
20
+ body: string;
21
+ ts: number;
22
+ /** Message id being answered. */
23
+ replyTo?: string;
24
+ }
25
+ export interface IrcDeliveryReceipt {
26
+ to: string;
27
+ outcome: "injected" | "woken" | "revived" | "failed";
28
+ error?: string;
29
+ }
30
+ export declare class IrcBus {
31
+ #private;
32
+ static global(): IrcBus;
33
+ /** Reset the global bus. Test-only. */
34
+ static resetGlobalForTests(): void;
35
+ constructor(registry?: AgentRegistry, lifecycle?: AgentLifecycleManager);
36
+ /**
37
+ * Fire-and-forget delivery. Never blocks on the recipient generating
38
+ * anything: the receipt reports how the message reached the recipient
39
+ * (waiter/aside = "injected", idle wake = "woken", park revival =
40
+ * "revived"), not what they did with it.
41
+ *
42
+ * Mailbox semantics: a successfully delivered message never lingers in
43
+ * the recipient's mailbox — injection/wake puts the full body into their
44
+ * context, so buffering it too would double-deliver via a later
45
+ * `wait`/`inbox` and inflate unread counts. Only a failed live hand-off
46
+ * is buffered for the recipient to drain later.
47
+ */
48
+ send(msg: Omit<IrcMessage, "id" | "ts">): Promise<IrcDeliveryReceipt>;
49
+ /**
50
+ * Block until a message for `agentId` (optionally from `filter.from`)
51
+ * arrives; consume + return it. Null on timeout (`timeoutMs <= 0` waits
52
+ * forever). Rejects when `signal` aborts. By default, already-buffered
53
+ * mail satisfies the wait before parking a future waiter; callers that
54
+ * need a strictly future reply can disable that drain.
55
+ */
56
+ wait(agentId: string, filter: {
57
+ from?: string;
58
+ }, timeoutMs: number, signal?: AbortSignal, options?: {
59
+ drainPending?: boolean;
60
+ }): Promise<IrcMessage | null>;
61
+ /** Drain (or peek) pending messages for `agentId`. */
62
+ inbox(agentId: string, opts?: {
63
+ peek?: boolean;
64
+ }): IrcMessage[];
65
+ unreadCount(agentId: string): number;
66
+ }
@@ -10,6 +10,7 @@ export interface OAuthEndpoints {
10
10
  tokenUrl: string;
11
11
  clientId?: string;
12
12
  scopes?: string;
13
+ resource?: string;
13
14
  }
14
15
  export interface AuthDetectionResult {
15
16
  requiresAuth: boolean;
@@ -41,4 +42,5 @@ export declare function analyzeAuthError(error: Error, serverUrl?: string): Auth
41
42
  */
42
43
  export declare function discoverOAuthEndpoints(serverUrl: string, authServerUrl?: string, resourceMetadataUrl?: string, opts?: {
43
44
  fetch?: FetchImpl;
45
+ protectedResource?: string;
44
46
  }): Promise<OAuthEndpoints | null>;
@@ -24,6 +24,8 @@ export interface MCPOAuthConfig {
24
24
  callbackPort?: number;
25
25
  /** Custom callback path (default: /callback or redirectUri pathname) */
26
26
  callbackPath?: string;
27
+ /** MCP resource URI for RFC 8707 resource indicators */
28
+ resource?: string;
27
29
  /** Fetch implementation for token exchange and discovery requests. */
28
30
  fetch?: FetchImpl;
29
31
  }
@@ -49,6 +51,7 @@ export declare class MCPOAuthFlow extends OAuthCallbackFlow {
49
51
  * client id via config.
50
52
  */
51
53
  get registeredClientSecret(): string | undefined;
54
+ get resource(): string | undefined;
52
55
  generateAuthUrl(state: string, redirectUri: string): Promise<{
53
56
  url: string;
54
57
  instructions?: string;
@@ -59,6 +62,8 @@ export declare class MCPOAuthFlow extends OAuthCallbackFlow {
59
62
  * Refresh an MCP OAuth token using the standard refresh_token grant.
60
63
  * Returns updated credentials; preserves the old refresh token if the server doesn't rotate it.
61
64
  */
62
- export declare function refreshMCPOAuthToken(tokenUrl: string, refreshToken: string, clientId?: string, clientSecret?: string, opts?: {
65
+ export declare function refreshMCPOAuthToken(tokenUrl: string, refreshToken: string, clientId?: string, clientSecret?: string, resourceOrOpts?: string | {
66
+ fetch?: FetchImpl;
67
+ }, opts?: {
63
68
  fetch?: FetchImpl;
64
69
  }): Promise<OAuthCredentials>;
@@ -8,6 +8,7 @@ import type { MCPRequestOptions, MCPStdioServerConfig, MCPTransport } from "../.
8
8
  /** Subprocess argv for launching an MCP stdio server. */
9
9
  export interface StdioSpawnCommand {
10
10
  cmd: string[];
11
+ windowsHide?: boolean;
11
12
  }
12
13
  /** Inputs used to resolve platform-specific stdio spawn behavior. */
13
14
  export interface ResolveStdioSpawnOptions {
@@ -40,6 +40,8 @@ export interface MCPAuthConfig {
40
40
  clientId?: string;
41
41
  /** Client secret — persisted for token refresh */
42
42
  clientSecret?: string;
43
+ /** MCP resource URI — persisted for OAuth resource indicators during refresh */
44
+ resource?: string;
43
45
  }
44
46
  /** Base server config with shared options */
45
47
  interface MCPServerConfigBase {
@@ -0,0 +1,30 @@
1
+ import { Container } from "@oh-my-pi/pi-tui";
2
+ import type { KeyId } from "../../config/keybindings";
3
+ import { IrcBus } from "../../irc/bus";
4
+ import { AgentLifecycleManager } from "../../registry/agent-lifecycle";
5
+ import { AgentRegistry } from "../../registry/agent-registry";
6
+ import type { SessionObserverRegistry } from "../session-observer-registry";
7
+ export interface AgentHubDeps {
8
+ /** Progress/status snapshot source (task lifecycle + progress channels). */
9
+ observers: SessionObserverRegistry;
10
+ /** Keys that toggle the hub closed from inside (app.agents.hub + app.session.observe). */
11
+ hubKeys: KeyId[];
12
+ onDone: () => void;
13
+ requestRender: () => void;
14
+ /** Injectable for tests; defaults to the process-global registry. */
15
+ registry?: AgentRegistry;
16
+ /** Injectable for tests; defaults to the process-global lifecycle manager. */
17
+ lifecycle?: AgentLifecycleManager;
18
+ /** Injectable for tests; defaults to the process-global bus. */
19
+ irc?: IrcBus;
20
+ }
21
+ export declare class AgentHubOverlayComponent extends Container {
22
+ #private;
23
+ constructor(deps: AgentHubDeps);
24
+ /** Tear down every subscription and timer. Called by the overlay owner on close. */
25
+ dispose(): void;
26
+ render(width: number): readonly string[];
27
+ handleInput(keyData: string): void;
28
+ /** Open the chat view for an agent id (public for table Enter and tests). */
29
+ openChat(id: string): void;
30
+ }
@@ -19,6 +19,7 @@ export declare class AssistantMessageComponent extends Container {
19
19
  */
20
20
  setErrorPinned(pinned: boolean): void;
21
21
  isTranscriptBlockFinalized(): boolean;
22
+ getTranscriptBlockVersion(): number;
22
23
  markTranscriptBlockFinalized(): void;
23
24
  setToolResultImages(toolCallId: string, images: ImageContent[]): void;
24
25
  setUsageInfo(usage: Usage): void;
@@ -1,13 +1,19 @@
1
- import { Box } from "@oh-my-pi/pi-tui";
1
+ import { type Component } from "@oh-my-pi/pi-tui";
2
2
  import type { CompactionSummaryMessage } from "../../session/messages";
3
3
  /**
4
- * Component that renders a compaction message with collapsed/expanded state.
5
- * Uses same background color as hook messages for visual consistency.
4
+ * Compaction point in the transcript, rendered as a slim horizontal divider:
5
+ *
6
+ * ──────── 📷 compacted · ctrl+o ────────
7
+ *
8
+ * The conversation above the divider stays visible (display transcript keeps
9
+ * full history); only the LLM context was reset. Expanding (ctrl+o) reveals
10
+ * the compaction summary below the divider.
6
11
  */
7
- export declare class CompactionSummaryMessageComponent extends Box {
12
+ export declare class CompactionSummaryMessageComponent implements Component {
8
13
  #private;
9
14
  private readonly message;
10
15
  constructor(message: CompactionSummaryMessage);
11
16
  setExpanded(expanded: boolean): void;
12
17
  invalidate(): void;
18
+ render(width: number): readonly string[];
13
19
  }
@@ -42,6 +42,8 @@ export declare class CustomEditor extends Editor {
42
42
  onDequeue?: () => void;
43
43
  /** Called when Caps Lock is pressed. */
44
44
  onCapsLock?: () => void;
45
+ /** Called when left-arrow is pressed while the editor is empty (cursor necessarily at start). */
46
+ onLeftAtStart?: () => void;
45
47
  setActionKeys(action: ConfigurableEditorAction, keys: KeyId[]): void;
46
48
  /**
47
49
  * Register a custom key handler. Extensions use this for shortcuts.
@@ -16,10 +16,11 @@ export interface MCPAddWizardOAuthResult {
16
16
  credentialId: string;
17
17
  clientId?: string;
18
18
  clientSecret?: string;
19
+ resource?: string;
19
20
  }
20
21
  export declare class MCPAddWizard extends Container {
21
22
  #private;
22
- constructor(onComplete: (name: string, config: MCPServerConfig, scope: Scope) => void, onCancel: () => void, onOAuth?: (authUrl: string, tokenUrl: string, clientId: string, clientSecret: string, scopes: string) => Promise<MCPAddWizardOAuthResult>, onTestConnection?: (config: MCPServerConfig) => Promise<void>, onRender?: () => void, initialName?: string);
23
+ constructor(onComplete: (name: string, config: MCPServerConfig, scope: Scope) => void, onCancel: () => void, onOAuth?: (authUrl: string, tokenUrl: string, clientId: string, clientSecret: string, scopes: string, resource?: string) => Promise<MCPAddWizardOAuthResult>, onTestConnection?: (config: MCPServerConfig) => Promise<void>, onRender?: () => void, initialName?: string);
23
24
  handleInput(keyData: string): void;
24
25
  }
25
26
  export {};
@@ -25,6 +25,7 @@ export interface StatusLinePreviewSettings {
25
25
  rightSegments?: StatusLineSegmentId[];
26
26
  separator?: StatusLineSeparatorStyle;
27
27
  sessionAccent?: boolean;
28
+ transparent?: boolean;
28
29
  }
29
30
  export interface SettingsCallbacks {
30
31
  /** Called when any setting value changes */
@@ -29,6 +29,9 @@ export interface StatusLineSettings {
29
29
  segmentOptions?: StatusLineSegmentOptions;
30
30
  showHookStatus?: boolean;
31
31
  sessionAccent?: boolean;
32
+ /** Drop the theme's `statusLineBg` fill and powerline caps so the bar
33
+ * inherits the terminal's default background. */
34
+ transparent?: boolean;
32
35
  }
33
36
  export type EffectiveStatusLineSettings = Required<Pick<StatusLineSettings, "leftSegments" | "rightSegments" | "separator" | "segmentOptions">> & StatusLineSettings;
34
37
  export type RGB = readonly [number, number, number];
@@ -67,6 +67,14 @@ export declare class ToolExecutionComponent extends Container {
67
67
  * transcript live region.
68
68
  */
69
69
  seal(): void;
70
+ /**
71
+ * Whether this block is a waiting `job` poll (every watched job still
72
+ * running) that has not been sealed. Such a block never finalized, so none
73
+ * of its rows entered native scrollback (the ticking spinner keeps the
74
+ * stable-prefix ratchet at zero) and the whole block can be removed when a
75
+ * follow-up `job` call supersedes it.
76
+ */
77
+ isDisplaceableBlock(): boolean;
70
78
  /**
71
79
  * Stop spinner animation and cleanup resources.
72
80
  */
@@ -1,4 +1,4 @@
1
- import { type Component, Container, type NativeScrollbackLiveRegion, type RenderStablePrefix } from "@oh-my-pi/pi-tui";
1
+ import { type Component, Container, type NativeScrollbackCommittedRows, type NativeScrollbackLiveRegion, type RenderStablePrefix } from "@oh-my-pi/pi-tui";
2
2
  /**
3
3
  * Transcript container that renders every block's current content each frame
4
4
  * and reports the live-region seam (`NativeScrollbackLiveRegion`) that gates
@@ -22,10 +22,11 @@ import { type Component, Container, type NativeScrollbackLiveRegion, type Render
22
22
  * through {@link RenderStablePrefix} so the engine can skip marker scanning,
23
23
  * line preparation, and the committed-prefix audit for those rows.
24
24
  */
25
- export declare class TranscriptContainer extends Container implements NativeScrollbackLiveRegion, RenderStablePrefix {
25
+ export declare class TranscriptContainer extends Container implements NativeScrollbackLiveRegion, NativeScrollbackCommittedRows, RenderStablePrefix {
26
26
  #private;
27
27
  invalidate(): void;
28
28
  clear(): void;
29
+ setNativeScrollbackCommittedRows(rows: number): void;
29
30
  getRenderStablePrefixRows(): number;
30
31
  getNativeScrollbackLiveRegionStart(): number | undefined;
31
32
  getNativeScrollbackCommitSafeEnd(): number | undefined;
@@ -3,11 +3,15 @@ import type { Rule } from "../../capability/rule";
3
3
  /**
4
4
  * Component that renders a TTSR (Time Traveling Stream Rules) notification.
5
5
  * Shows when a rule violation is detected and the stream is being rewound.
6
+ * One block can carry several rules: a single event may match multiple rules,
7
+ * and consecutive notifications merge into the previous block via
8
+ * {@link addRules} while it is still the live transcript tail.
6
9
  */
7
10
  export declare class TtsrNotificationComponent extends Container {
8
11
  #private;
9
- private readonly rules;
10
12
  constructor(rules: Rule[]);
13
+ /** Merge additional rules into this block (deduped by rule name). */
14
+ addRules(rules: Rule[]): void;
11
15
  setExpanded(expanded: boolean): void;
12
16
  isExpanded(): boolean;
13
17
  }
@@ -1,7 +1,7 @@
1
1
  import { type Component } from "@oh-my-pi/pi-tui";
2
2
  /**
3
- * Fixed number of session rows in the welcome box so its height doesn't shift
4
- * between the pre-TUI splash (loading placeholder) and the loaded state.
3
+ * Fixed number of session rows in the welcome box so its height stays stable
4
+ * across recent-session updates.
5
5
  */
6
6
  export declare const WELCOME_SESSION_SLOTS = 4;
7
7
  /**
@@ -29,14 +29,8 @@ export declare class WelcomeComponent implements Component {
29
29
  private providerName;
30
30
  private recentSessions;
31
31
  private lspServers;
32
- constructor(version: string, modelName: string, providerName: string, recentSessions?: RecentSession[] | null, lspServers?: LspServerInfo[]);
32
+ constructor(version: string, modelName: string, providerName: string, recentSessions?: RecentSession[], lspServers?: LspServerInfo[]);
33
33
  invalidate(): void;
34
- /**
35
- * Freeze the logo on the intro animation's first frame. The pre-TUI startup
36
- * splash uses this so the in-TUI intro — which starts at that exact frame —
37
- * picks up seamlessly from the splash's static box.
38
- */
39
- holdIntroFirstFrame(): void;
40
34
  /**
41
35
  * Play a one-shot intro that sweeps the gradient through every phase
42
36
  * before settling on the resting frame. Safe to call multiple times —
@@ -42,5 +42,5 @@ export declare class SelectorController {
42
42
  handleSessionDeleteCommand(): Promise<void>;
43
43
  showOAuthSelector(mode: "login" | "logout", providerId?: string): Promise<void>;
44
44
  showDebugSelector(): Promise<void>;
45
- showSessionObserver(registry: SessionObserverRegistry): void;
45
+ showAgentHub(observers: SessionObserverRegistry): void;
46
46
  }
@@ -0,0 +1,43 @@
1
+ /** Minimal component surface the reveal pushes frames into. */
2
+ type ToolArgsRevealComponent = {
3
+ updateArgs(args: unknown, toolCallId?: string): void;
4
+ };
5
+ type ToolArgsRevealControllerOptions = {
6
+ getSmoothStreaming(): boolean;
7
+ requestRender(): void;
8
+ };
9
+ /**
10
+ * Paces streamed tool-call arguments the same way StreamingRevealController
11
+ * paces assistant text: providers that deliver `partialJson` in large batches
12
+ * (or throttle their partial parses) would otherwise make write/edit/bash
13
+ * streaming previews jump in chunks. Each pending tool call reveals its raw
14
+ * argument stream at the shared 30fps cadence with the same adaptive
15
+ * catch-up step, re-parsing the revealed prefix per frame.
16
+ *
17
+ * Reveal units are UTF-16 code units of the raw stream, not graphemes —
18
+ * the prefix goes through a JSON parser rather than straight to the screen,
19
+ * so only surrogate-pair integrity matters (see {@link clampSliceEnd}).
20
+ */
21
+ export declare class ToolArgsRevealController {
22
+ #private;
23
+ constructor(options: ToolArgsRevealControllerOptions);
24
+ /**
25
+ * Record the latest streamed argument text for a tool call and return the
26
+ * args to render right now. With smoothing disabled the full target passes
27
+ * through in the caller's legacy shape (`{ ...args, __partialJson }`).
28
+ */
29
+ setTarget(id: string, partialJson: string, rawInput: boolean, fullArgs: Record<string, unknown>): Record<string, unknown>;
30
+ /** Attach the component future ticks push frames into. */
31
+ bind(id: string, component: ToolArgsRevealComponent): void;
32
+ /** Final arguments arrived (the JSON closed): drop the reveal so the
33
+ * caller's final-args render wins immediately, mirroring how assistant
34
+ * text snaps to the full message at message_end. */
35
+ finish(id: string): void;
36
+ /** Snap every live entry to its full received stream and clear. Used at
37
+ * message_end (abort/error mid-stream) so sealed components freeze showing
38
+ * everything that arrived rather than a mid-reveal prefix. */
39
+ flushAll(): void;
40
+ /** Clear without pushing (teardown). */
41
+ stop(): void;
42
+ }
43
+ export {};
@@ -100,6 +100,7 @@ export declare class InteractiveMode implements InteractiveModeContext {
100
100
  locallySubmittedUserSignatures: Set<string>;
101
101
  lastSigintTime: number;
102
102
  lastEscapeTime: number;
103
+ lastLeftTapTime: number;
103
104
  shutdownRequested: boolean;
104
105
  hookSelector: HookSelectorComponent | undefined;
105
106
  hookInput: HookInputComponent | undefined;
@@ -210,7 +211,7 @@ export declare class InteractiveMode implements InteractiveModeContext {
210
211
  updateFooter?: boolean;
211
212
  populateHistory?: boolean;
212
213
  }): void;
213
- renderInitialMessages(prebuiltContext?: SessionContext, options?: {
214
+ renderInitialMessages(options?: {
214
215
  preserveExistingChat?: boolean;
215
216
  clearTerminalHistory?: boolean;
216
217
  }): void;
@@ -238,7 +239,7 @@ export declare class InteractiveMode implements InteractiveModeContext {
238
239
  handleMemoryCommand(text: string): Promise<void>;
239
240
  handleSTTToggle(): Promise<void>;
240
241
  showDebugSelector(): Promise<void>;
241
- showSessionObserver(): void;
242
+ showAgentHub(): void;
242
243
  resetObserverRegistry(): void;
243
244
  handleBashCommand(command: string, excludeFromContext?: boolean): Promise<void>;
244
245
  handlePythonCommand(code: string, excludeFromContext?: boolean): Promise<void>;
@@ -6,7 +6,7 @@ export type SymbolPreset = "unicode" | "nerd" | "ascii";
6
6
  /**
7
7
  * All available symbol keys organized by category.
8
8
  */
9
- export type SymbolKey = "status.success" | "status.error" | "status.warning" | "status.info" | "status.pending" | "status.disabled" | "status.enabled" | "status.running" | "status.shadowed" | "status.aborted" | "status.done" | "nav.cursor" | "nav.selected" | "nav.expand" | "nav.collapse" | "nav.back" | "tree.branch" | "tree.last" | "tree.vertical" | "tree.horizontal" | "tree.hook" | "boxRound.topLeft" | "boxRound.topRight" | "boxRound.bottomLeft" | "boxRound.bottomRight" | "boxRound.horizontal" | "boxRound.vertical" | "boxSharp.topLeft" | "boxSharp.topRight" | "boxSharp.bottomLeft" | "boxSharp.bottomRight" | "boxSharp.horizontal" | "boxSharp.vertical" | "boxSharp.cross" | "boxSharp.teeDown" | "boxSharp.teeUp" | "boxSharp.teeRight" | "boxSharp.teeLeft" | "sep.powerline" | "sep.powerlineThin" | "sep.powerlineLeft" | "sep.powerlineRight" | "sep.powerlineThinLeft" | "sep.powerlineThinRight" | "sep.block" | "sep.space" | "sep.asciiLeft" | "sep.asciiRight" | "sep.dot" | "sep.slash" | "sep.pipe" | "icon.model" | "icon.plan" | "icon.goal" | "icon.pause" | "icon.loop" | "icon.folder" | "icon.search" | "icon.scratchFolder" | "icon.file" | "icon.git" | "icon.branch" | "icon.pr" | "icon.tokens" | "icon.context" | "icon.cost" | "icon.time" | "icon.pi" | "icon.agents" | "icon.cache" | "icon.input" | "icon.output" | "icon.host" | "icon.session" | "icon.package" | "icon.warning" | "icon.rewind" | "icon.auto" | "icon.fast" | "icon.extensionSkill" | "icon.extensionTool" | "icon.extensionSlashCommand" | "icon.extensionMcp" | "icon.extensionRule" | "icon.extensionHook" | "icon.extensionPrompt" | "icon.extensionContextFile" | "icon.extensionInstruction" | "icon.mic" | "thinking.minimal" | "thinking.low" | "thinking.medium" | "thinking.high" | "thinking.xhigh" | "thinking.autoPending" | "checkbox.checked" | "checkbox.unchecked" | "radio.selected" | "radio.unselected" | "format.bullet" | "format.dash" | "format.bracketLeft" | "format.bracketRight" | "md.quoteBorder" | "md.hrChar" | "md.bullet" | "md.colorSwatch" | "lang.default" | "lang.typescript" | "lang.javascript" | "lang.python" | "lang.rust" | "lang.go" | "lang.java" | "lang.c" | "lang.cpp" | "lang.csharp" | "lang.ruby" | "lang.php" | "lang.swift" | "lang.kotlin" | "lang.shell" | "lang.html" | "lang.css" | "lang.json" | "lang.yaml" | "lang.markdown" | "lang.sql" | "lang.docker" | "lang.lua" | "lang.text" | "lang.env" | "lang.toml" | "lang.xml" | "lang.ini" | "lang.conf" | "lang.log" | "lang.csv" | "lang.tsv" | "lang.image" | "lang.pdf" | "lang.archive" | "lang.binary" | "tab.appearance" | "tab.model" | "tab.interaction" | "tab.context" | "tab.editing" | "tab.tools" | "tab.memory" | "tab.tasks" | "tab.providers" | "tool.write" | "tool.edit" | "tool.bash" | "tool.ssh" | "tool.lsp" | "tool.gh" | "tool.webSearch" | "tool.exa" | "tool.browser" | "tool.eval" | "tool.debug" | "tool.mcp" | "tool.job" | "tool.task" | "tool.todo" | "tool.memory" | "tool.ask" | "tool.resolve" | "tool.review" | "tool.inspectImage" | "tool.goal";
9
+ export type SymbolKey = "status.success" | "status.error" | "status.warning" | "status.info" | "status.pending" | "status.disabled" | "status.enabled" | "status.running" | "status.shadowed" | "status.aborted" | "status.done" | "nav.cursor" | "nav.selected" | "nav.expand" | "nav.collapse" | "nav.back" | "tree.branch" | "tree.last" | "tree.vertical" | "tree.horizontal" | "tree.hook" | "boxRound.topLeft" | "boxRound.topRight" | "boxRound.bottomLeft" | "boxRound.bottomRight" | "boxRound.horizontal" | "boxRound.vertical" | "boxSharp.topLeft" | "boxSharp.topRight" | "boxSharp.bottomLeft" | "boxSharp.bottomRight" | "boxSharp.horizontal" | "boxSharp.vertical" | "boxSharp.cross" | "boxSharp.teeDown" | "boxSharp.teeUp" | "boxSharp.teeRight" | "boxSharp.teeLeft" | "sep.powerline" | "sep.powerlineThin" | "sep.powerlineLeft" | "sep.powerlineRight" | "sep.powerlineThinLeft" | "sep.powerlineThinRight" | "sep.block" | "sep.space" | "sep.asciiLeft" | "sep.asciiRight" | "sep.dot" | "sep.slash" | "sep.pipe" | "icon.model" | "icon.plan" | "icon.goal" | "icon.pause" | "icon.loop" | "icon.folder" | "icon.search" | "icon.scratchFolder" | "icon.file" | "icon.git" | "icon.branch" | "icon.pr" | "icon.tokens" | "icon.context" | "icon.cost" | "icon.time" | "icon.pi" | "icon.agents" | "icon.job" | "icon.cache" | "icon.input" | "icon.output" | "icon.host" | "icon.session" | "icon.package" | "icon.warning" | "icon.rewind" | "icon.auto" | "icon.fast" | "icon.extensionSkill" | "icon.extensionTool" | "icon.extensionSlashCommand" | "icon.extensionMcp" | "icon.extensionRule" | "icon.extensionHook" | "icon.extensionPrompt" | "icon.extensionContextFile" | "icon.extensionInstruction" | "icon.mic" | "icon.camera" | "thinking.minimal" | "thinking.low" | "thinking.medium" | "thinking.high" | "thinking.xhigh" | "thinking.autoPending" | "checkbox.checked" | "checkbox.unchecked" | "radio.selected" | "radio.unselected" | "format.bullet" | "format.dash" | "format.bracketLeft" | "format.bracketRight" | "md.quoteBorder" | "md.hrChar" | "md.bullet" | "md.colorSwatch" | "lang.default" | "lang.typescript" | "lang.javascript" | "lang.python" | "lang.rust" | "lang.go" | "lang.java" | "lang.c" | "lang.cpp" | "lang.csharp" | "lang.ruby" | "lang.php" | "lang.swift" | "lang.kotlin" | "lang.shell" | "lang.html" | "lang.css" | "lang.json" | "lang.yaml" | "lang.markdown" | "lang.sql" | "lang.docker" | "lang.lua" | "lang.text" | "lang.env" | "lang.toml" | "lang.xml" | "lang.ini" | "lang.conf" | "lang.log" | "lang.csv" | "lang.tsv" | "lang.image" | "lang.pdf" | "lang.archive" | "lang.binary" | "tab.appearance" | "tab.model" | "tab.interaction" | "tab.context" | "tab.editing" | "tab.tools" | "tab.memory" | "tab.tasks" | "tab.providers" | "tool.write" | "tool.edit" | "tool.bash" | "tool.ssh" | "tool.lsp" | "tool.gh" | "tool.webSearch" | "tool.exa" | "tool.browser" | "tool.eval" | "tool.debug" | "tool.mcp" | "tool.job" | "tool.task" | "tool.todo" | "tool.memory" | "tool.ask" | "tool.resolve" | "tool.review" | "tool.inspectImage" | "tool.goal" | "tool.irc";
10
10
  export type SpinnerType = "status" | "activity";
11
11
  export type ThemeColor = "accent" | "border" | "borderAccent" | "borderMuted" | "success" | "error" | "warning" | "muted" | "dim" | "text" | "thinkingText" | "userMessageText" | "customMessageText" | "customMessageLabel" | "toolTitle" | "toolOutput" | "mdHeading" | "mdLink" | "mdLinkUrl" | "mdCode" | "mdCodeBlock" | "mdCodeBlockBorder" | "mdQuote" | "mdQuoteBorder" | "mdHr" | "mdListBullet" | "toolDiffAdded" | "toolDiffRemoved" | "toolDiffContext" | "syntaxComment" | "syntaxKeyword" | "syntaxFunction" | "syntaxVariable" | "syntaxString" | "syntaxNumber" | "syntaxType" | "syntaxOperator" | "syntaxPunctuation" | "thinkingOff" | "thinkingMinimal" | "thinkingLow" | "thinkingMedium" | "thinkingHigh" | "thinkingXhigh" | "bashMode" | "pythonMode" | "statusLineSep" | "statusLineModel" | "statusLinePath" | "statusLineGitClean" | "statusLineGitDirty" | "statusLineContext" | "statusLineSpend" | "statusLineStaged" | "statusLineDirty" | "statusLineUntracked" | "statusLineOutput" | "statusLineCost" | "statusLineSubagents";
12
12
  /** Check if a string is a valid ThemeColor value */
@@ -150,6 +150,7 @@ export declare class Theme {
150
150
  time: string;
151
151
  pi: string;
152
152
  agents: string;
153
+ job: string;
153
154
  cache: string;
154
155
  input: string;
155
156
  output: string;
@@ -170,6 +171,7 @@ export declare class Theme {
170
171
  extensionContextFile: string;
171
172
  extensionInstruction: string;
172
173
  mic: string;
174
+ camera: string;
173
175
  };
174
176
  get thinking(): {
175
177
  minimal: string;
@@ -117,6 +117,7 @@ export interface InteractiveModeContext {
117
117
  locallySubmittedUserSignatures: Set<string>;
118
118
  lastSigintTime: number;
119
119
  lastEscapeTime: number;
120
+ lastLeftTapTime: number;
120
121
  shutdownRequested: boolean;
121
122
  hookSelector: HookSelectorComponent | undefined;
122
123
  hookInput: HookInputComponent | undefined;
@@ -204,7 +205,7 @@ export interface InteractiveModeContext {
204
205
  updateFooter?: boolean;
205
206
  populateHistory?: boolean;
206
207
  }): void;
207
- renderInitialMessages(prebuiltContext?: SessionContext, options?: {
208
+ renderInitialMessages(options?: {
208
209
  preserveExistingChat?: boolean;
209
210
  clearTerminalHistory?: boolean;
210
211
  }): void;
@@ -266,7 +267,7 @@ export interface InteractiveModeContext {
266
267
  showProviderSetup(): Promise<void>;
267
268
  showHookConfirm(title: string, message: string): Promise<boolean>;
268
269
  showDebugSelector(): Promise<void>;
269
- showSessionObserver(): void;
270
+ showAgentHub(): void;
270
271
  resetObserverRegistry(): void;
271
272
  handleCtrlC(): void;
272
273
  handleCtrlD(): void;
@@ -36,7 +36,7 @@ export declare class UiHelpers {
36
36
  updateFooter?: boolean;
37
37
  populateHistory?: boolean;
38
38
  }): void;
39
- renderInitialMessages(prebuiltContext?: SessionContext, options?: RenderInitialMessagesOptions): void;
39
+ renderInitialMessages(options?: RenderInitialMessagesOptions): void;
40
40
  clearEditor(): void;
41
41
  showError(errorMessage: string): void;
42
42
  showWarning(warningMessage: string): void;
@@ -0,0 +1,51 @@
1
+ /**
2
+ * AgentLifecycleManager - Owns the idle → parked → revived lifecycle of
3
+ * adopted subagents.
4
+ *
5
+ * The task executor hands a finished agent over via {@link AgentLifecycleManager.adopt};
6
+ * from then on the manager arms a TTL timer whenever the agent goes `idle`,
7
+ * parks it on expiry (disposes the live session, keeps the AgentRef +
8
+ * sessionFile), and revives it on demand through
9
+ * {@link AgentLifecycleManager.ensureLive}. Only this manager flips
10
+ * `parked` ↔ `idle`.
11
+ */
12
+ import type { AgentSession } from "../session/agent-session";
13
+ import { AgentRegistry } from "./agent-registry";
14
+ export type AgentReviver = () => Promise<AgentSession>;
15
+ export interface AdoptOptions {
16
+ /** TTL before an idle agent is parked. <= 0 disables parking. */
17
+ idleTtlMs: number;
18
+ /** Recreates a live AgentSession from the ref's sessionFile. Absent => not resumable after park (e.g. isolated runs). */
19
+ revive?: AgentReviver;
20
+ }
21
+ export declare class AgentLifecycleManager {
22
+ #private;
23
+ static global(): AgentLifecycleManager;
24
+ /** Reset the global manager. Test-only. */
25
+ static resetGlobalForTests(): void;
26
+ constructor(registry?: AgentRegistry);
27
+ /**
28
+ * Take ownership of a finished subagent. Caller has already set registry
29
+ * status to "idle". Arms the TTL timer (idleTtlMs <= 0 adopts without one).
30
+ */
31
+ adopt(id: string, opts: AdoptOptions): void;
32
+ /** True if the id is adopted (parked or live). */
33
+ has(id: string): boolean;
34
+ /** True while {@link park} is disposing this agent's session (lets dispose hooks distinguish park from teardown). */
35
+ isParking(id: string): boolean;
36
+ /**
37
+ * Dispose the live session, detach it from the registry, and mark the
38
+ * agent `parked`. No-op unless the id is adopted and live.
39
+ */
40
+ park(id: string): Promise<void>;
41
+ /**
42
+ * Return the live session, reviving from the sessionFile if parked.
43
+ * Throws a plain Error if the id is unknown or parked without a reviver.
44
+ * Concurrent calls share one in-flight revive.
45
+ */
46
+ ensureLive(id: string): Promise<AgentSession>;
47
+ /** Hard removal: dispose if live, unregister from registry, drop timers. */
48
+ release(id: string): Promise<void>;
49
+ /** Teardown everything (process exit / main session dispose). */
50
+ dispose(): Promise<void>;
51
+ }
@@ -1,13 +1,23 @@
1
1
  /**
2
- * AgentRegistry - Process-global registry of live AgentSession instances.
2
+ * AgentRegistry - Process-global registry of agents (the main session plus
3
+ * every subagent), keyed by stable id.
3
4
  *
4
- * Tracks every alive agent (the main session plus every subagent) so the
5
- * `irc` tool can address peers by id. Sessions are registered explicitly at
6
- * creation and removed when the owner releases them.
5
+ * Tracks each agent's status and (when live) its AgentSession so peers can be
6
+ * addressed by id (`irc`, `task resume`, `history://`). Sessions are
7
+ * registered explicitly at creation; finished agents stay registered as
8
+ * `idle` (live) or `parked` (session disposed, ref + sessionFile retained for
9
+ * revival) and are only removed on explicit release/teardown.
7
10
  */
8
11
  import type { AgentSession } from "../session/agent-session";
9
12
  export declare const MAIN_AGENT_ID = "Main";
10
- export type AgentStatus = "running" | "idle" | "completed" | "aborted";
13
+ /**
14
+ * - `running`: a turn is in flight.
15
+ * - `idle`: live AgentSession in memory, awaiting work. Finished agents are
16
+ * `idle`, not removed.
17
+ * - `parked`: session disposed; AgentRef + sessionFile retained, revivable.
18
+ * - `aborted`: hard-killed, terminal.
19
+ */
20
+ export type AgentStatus = "running" | "idle" | "parked" | "aborted";
11
21
  export type AgentKind = "main" | "sub";
12
22
  export interface AgentRef {
13
23
  id: string;
@@ -15,6 +25,7 @@ export interface AgentRef {
15
25
  kind: AgentKind;
16
26
  parentId?: string;
17
27
  status: AgentStatus;
28
+ /** Null exactly when parked/aborted. */
18
29
  session: AgentSession | null;
19
30
  sessionFile: string | null;
20
31
  createdAt: number;