@gajae-code/coding-agent 0.9.5 → 0.10.0

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 (194) hide show
  1. package/CHANGELOG.md +54 -0
  2. package/dist/types/cli/classify-install-target.d.ts +0 -10
  3. package/dist/types/cli/daemon-cli.d.ts +2 -0
  4. package/dist/types/cli/initial-message.d.ts +1 -1
  5. package/dist/types/cli/malloc-env-guard.d.ts +65 -0
  6. package/dist/types/cli/malloc-env-guard.test.d.ts +1 -0
  7. package/dist/types/cli/notify-cli.d.ts +3 -1
  8. package/dist/types/cli/session-picker.d.ts +4 -3
  9. package/dist/types/cli/update-cli.d.ts +22 -3
  10. package/dist/types/cli.d.ts +4 -0
  11. package/dist/types/commands/daemon.d.ts +6 -2
  12. package/dist/types/commands/launch.d.ts +1 -0
  13. package/dist/types/commands/notify.d.ts +6 -0
  14. package/dist/types/commit/analysis/conventional.d.ts +1 -1
  15. package/dist/types/commit/analysis/summary.d.ts +1 -1
  16. package/dist/types/commit/changelog/generate.d.ts +1 -1
  17. package/dist/types/commit/changelog/index.d.ts +2 -2
  18. package/dist/types/commit/map-reduce/map-phase.d.ts +1 -1
  19. package/dist/types/commit/map-reduce/reduce-phase.d.ts +1 -1
  20. package/dist/types/config/keybindings.d.ts +5 -0
  21. package/dist/types/config/model-profile-activation.d.ts +1 -0
  22. package/dist/types/config/settings-schema.d.ts +47 -7
  23. package/dist/types/coordinator-mcp/model-preset.d.ts +45 -0
  24. package/dist/types/coordinator-mcp/server.d.ts +67 -6
  25. package/dist/types/daemon/control-types.d.ts +10 -0
  26. package/dist/types/daemon/operator-contract.d.ts +47 -0
  27. package/dist/types/defaults/gjc/extensions/grok-cli-vendor/src/models/catalog.d.ts +4 -0
  28. package/dist/types/discovery/helpers.d.ts +1 -1
  29. package/dist/types/discovery/substitute-plugin-root.d.ts +0 -4
  30. package/dist/types/gjc-runtime/launch-tmux.d.ts +26 -7
  31. package/dist/types/gjc-runtime/session-state-sidecar.d.ts +34 -3
  32. package/dist/types/gjc-runtime/tmux-common.d.ts +6 -0
  33. package/dist/types/gjc-runtime/tmux-owner-isolation-cli.d.ts +5 -0
  34. package/dist/types/gjc-runtime/tmux-owner-isolation.d.ts +309 -0
  35. package/dist/types/gjc-runtime/tmux-sessions.d.ts +49 -17
  36. package/dist/types/internal-urls/local-protocol.d.ts +13 -9
  37. package/dist/types/main.d.ts +66 -2
  38. package/dist/types/modes/acp/acp-agent.d.ts +19 -2
  39. package/dist/types/modes/acp/acp-mode.d.ts +12 -0
  40. package/dist/types/modes/components/assistant-message.d.ts +1 -1
  41. package/dist/types/modes/components/custom-editor.d.ts +2 -0
  42. package/dist/types/modes/components/gajae-pet-widget.d.ts +59 -0
  43. package/dist/types/modes/components/hook-selector.d.ts +5 -0
  44. package/dist/types/modes/components/irc-sidebar.d.ts +32 -0
  45. package/dist/types/modes/components/pet-selector.d.ts +11 -0
  46. package/dist/types/modes/components/session-selector.d.ts +22 -9
  47. package/dist/types/modes/components/settings-selector.d.ts +2 -0
  48. package/dist/types/modes/components/tool-execution.d.ts +1 -0
  49. package/dist/types/modes/components/user-message.d.ts +2 -1
  50. package/dist/types/modes/controllers/event-controller.d.ts +4 -0
  51. package/dist/types/modes/controllers/selector-controller.d.ts +1 -0
  52. package/dist/types/modes/interactive-mode.d.ts +24 -2
  53. package/dist/types/modes/irc-observation-ledger.d.ts +22 -0
  54. package/dist/types/modes/shared/agent-wire/deep-interview-gate.d.ts +8 -0
  55. package/dist/types/modes/shared/agent-wire/unattended-run-controller.d.ts +5 -0
  56. package/dist/types/modes/shared/agent-wire/unattended-session.d.ts +45 -0
  57. package/dist/types/modes/shared/agent-wire/workflow-gate-broker.d.ts +42 -2
  58. package/dist/types/modes/theme/defaults/index.d.ts +568 -568
  59. package/dist/types/modes/types.d.ts +28 -2
  60. package/dist/types/modes/utils/abort-message.d.ts +1 -1
  61. package/dist/types/modes/utils/irc-message.d.ts +38 -0
  62. package/dist/types/modes/utils/ui-helpers.d.ts +13 -4
  63. package/dist/types/notifications/config.d.ts +34 -0
  64. package/dist/types/notifications/daemon-paths.d.ts +7 -0
  65. package/dist/types/notifications/index.d.ts +27 -0
  66. package/dist/types/notifications/lifecycle-control-runtime.d.ts +12 -4
  67. package/dist/types/notifications/notification-service.d.ts +144 -0
  68. package/dist/types/notifications/rate-limit-pool.d.ts +27 -9
  69. package/dist/types/notifications/telegram-daemon-control.d.ts +6 -0
  70. package/dist/types/notifications/telegram-daemon.d.ts +130 -3
  71. package/dist/types/notifications/telegram-reference.d.ts +19 -2
  72. package/dist/types/notifications/topic-registry.d.ts +24 -4
  73. package/dist/types/registry/agent-registry.d.ts +2 -0
  74. package/dist/types/rlm/index.d.ts +1 -1
  75. package/dist/types/sdk.d.ts +2 -0
  76. package/dist/types/secrets/obfuscator.d.ts +1 -1
  77. package/dist/types/session/agent-session.d.ts +26 -2
  78. package/dist/types/session/cache-economics.d.ts +79 -0
  79. package/dist/types/session/provider-safety-stop.d.ts +5 -0
  80. package/dist/types/session/session-manager.d.ts +124 -4
  81. package/dist/types/session/session-storage.d.ts +155 -13
  82. package/dist/types/setup/credential-auto-import.d.ts +2 -2
  83. package/dist/types/task/executor.d.ts +3 -0
  84. package/dist/types/task/receipt.d.ts +3 -1
  85. package/dist/types/task/types.d.ts +8 -0
  86. package/dist/types/tools/ask-answer-registry.d.ts +5 -0
  87. package/dist/types/tools/ask.d.ts +25 -1
  88. package/dist/types/tools/bash.d.ts +1 -1
  89. package/dist/types/tools/browser/tab-supervisor.d.ts +6 -0
  90. package/dist/types/tools/index.d.ts +58 -6
  91. package/dist/types/tools/telegram-send.d.ts +7 -0
  92. package/dist/types/utils/external-editor.d.ts +2 -0
  93. package/package.json +9 -9
  94. package/scripts/compile-args.ts +8 -2
  95. package/scripts/g004-tmux-smoke.ts +196 -36
  96. package/src/cli/daemon-cli.ts +19 -29
  97. package/src/cli/malloc-env-guard.test.ts +104 -0
  98. package/src/cli/malloc-env-guard.ts +149 -0
  99. package/src/cli/notify-cli.ts +78 -14
  100. package/src/cli/session-picker.ts +23 -40
  101. package/src/cli/update-cli.ts +56 -37
  102. package/src/cli.ts +50 -10
  103. package/src/commands/daemon.ts +19 -5
  104. package/src/commands/harness.ts +515 -47
  105. package/src/commands/launch.ts +11 -3
  106. package/src/commands/notify.ts +5 -1
  107. package/src/commands/session.ts +6 -1
  108. package/src/config/keybindings.ts +5 -0
  109. package/src/config/model-profile-activation.ts +1 -1
  110. package/src/config/model-profiles.ts +23 -23
  111. package/src/config/settings-schema.ts +41 -1
  112. package/src/coordinator-mcp/model-preset.ts +100 -0
  113. package/src/coordinator-mcp/server.ts +2653 -425
  114. package/src/daemon/control-types.ts +11 -0
  115. package/src/daemon/operator-contract.ts +121 -0
  116. package/src/deep-interview/render-middleware.ts +67 -2
  117. package/src/defaults/gjc/extensions/grok-cli-vendor/src/models/catalog.ts +57 -17
  118. package/src/defaults/gjc/extensions/grok-cli-vendor/src/payload/sanitize.ts +15 -2
  119. package/src/defaults/gjc/extensions/grok-cli-vendor/src/provider/register.ts +5 -1
  120. package/src/gjc-runtime/launch-tmux.ts +702 -135
  121. package/src/gjc-runtime/session-state-sidecar.ts +756 -135
  122. package/src/gjc-runtime/team-runtime.ts +6 -0
  123. package/src/gjc-runtime/tmux-common.ts +26 -7
  124. package/src/gjc-runtime/tmux-gc.ts +52 -9
  125. package/src/gjc-runtime/tmux-owner-isolation-cli.ts +185 -0
  126. package/src/gjc-runtime/tmux-owner-isolation.ts +2060 -0
  127. package/src/gjc-runtime/tmux-sessions.ts +871 -68
  128. package/src/internal-urls/docs-index.generated.ts +9 -8
  129. package/src/internal-urls/local-protocol.ts +29 -10
  130. package/src/main.ts +298 -75
  131. package/src/modes/acp/acp-agent.ts +728 -98
  132. package/src/modes/acp/acp-mode.ts +29 -2
  133. package/src/modes/components/assistant-message.ts +32 -3
  134. package/src/modes/components/bash-execution.ts +43 -13
  135. package/src/modes/components/custom-editor.ts +5 -0
  136. package/src/modes/components/gajae-pet-widget.ts +360 -0
  137. package/src/modes/components/hook-selector.ts +12 -0
  138. package/src/modes/components/irc-sidebar.ts +206 -0
  139. package/src/modes/components/pet-selector.ts +55 -0
  140. package/src/modes/components/session-selector.ts +222 -221
  141. package/src/modes/components/settings-selector.ts +10 -0
  142. package/src/modes/components/tool-execution.ts +47 -6
  143. package/src/modes/components/user-message.ts +26 -9
  144. package/src/modes/controllers/command-controller.ts +28 -2
  145. package/src/modes/controllers/event-controller.ts +159 -36
  146. package/src/modes/controllers/extension-ui-controller.ts +36 -17
  147. package/src/modes/controllers/input-controller.ts +8 -2
  148. package/src/modes/controllers/selector-controller.ts +62 -15
  149. package/src/modes/interactive-mode.ts +183 -7
  150. package/src/modes/irc-observation-ledger.ts +127 -0
  151. package/src/modes/shared/agent-wire/deep-interview-gate.ts +45 -2
  152. package/src/modes/shared/agent-wire/unattended-session.ts +288 -1
  153. package/src/modes/shared/agent-wire/workflow-gate-broker.ts +130 -20
  154. package/src/modes/types.ts +34 -2
  155. package/src/modes/utils/hotkeys-markdown.ts +1 -0
  156. package/src/modes/utils/irc-message.ts +138 -0
  157. package/src/modes/utils/ui-helpers.ts +216 -50
  158. package/src/notifications/config.ts +44 -0
  159. package/src/notifications/daemon-paths.ts +8 -0
  160. package/src/notifications/index.ts +535 -75
  161. package/src/notifications/lifecycle-control-runtime.ts +930 -77
  162. package/src/notifications/notification-service.ts +710 -0
  163. package/src/notifications/rate-limit-pool.ts +46 -12
  164. package/src/notifications/telegram-daemon-cli.ts +2 -0
  165. package/src/notifications/telegram-daemon-control.ts +27 -2
  166. package/src/notifications/telegram-daemon.ts +635 -94
  167. package/src/notifications/telegram-reference.ts +73 -13
  168. package/src/notifications/topic-registry.ts +86 -9
  169. package/src/prompts/system/irc-peer-roster.md +1 -0
  170. package/src/prompts/system/subagent-system-prompt.md +1 -0
  171. package/src/prompts/system/system-prompt.md +1 -0
  172. package/src/prompts/tools/irc.md +1 -1
  173. package/src/registry/agent-registry.ts +3 -0
  174. package/src/sdk.ts +52 -1
  175. package/src/secrets/obfuscator.ts +4 -2
  176. package/src/session/agent-session.ts +396 -145
  177. package/src/session/cache-economics.ts +275 -0
  178. package/src/session/provider-safety-stop.ts +9 -0
  179. package/src/session/session-dump-format.ts +6 -0
  180. package/src/session/session-manager.ts +809 -39
  181. package/src/session/session-storage.ts +582 -38
  182. package/src/slash-commands/builtin-registry.ts +143 -9
  183. package/src/task/executor.ts +12 -3
  184. package/src/task/index.ts +8 -0
  185. package/src/task/receipt.ts +7 -2
  186. package/src/task/types.ts +26 -0
  187. package/src/tools/ask-answer-registry.ts +25 -0
  188. package/src/tools/ask.ts +355 -33
  189. package/src/tools/browser/tab-supervisor.ts +63 -6
  190. package/src/tools/browser.ts +8 -3
  191. package/src/tools/index.ts +81 -6
  192. package/src/tools/sqlite-reader.ts +8 -4
  193. package/src/tui/output-block.ts +18 -6
  194. package/src/utils/external-editor.ts +6 -1
@@ -1,10 +1,10 @@
1
- import type { AgentMessage } from "@gajae-code/agent-core";
1
+ import { type AgentMessage } from "@gajae-code/agent-core";
2
2
  import type { ImageContent, Message, MessageAttribution, ServiceTier, TextContent } from "@gajae-code/ai";
3
3
  import type { TtsrInjectionRecord } from "../export/ttsr";
4
4
  import { ArtifactManager } from "./artifacts";
5
5
  import { type BlobPutResult, BlobStore } from "./blob-store";
6
6
  import { type BashExecutionMessage, type CustomMessage, type FileMentionMessage, type HookMessage, type PythonExecutionMessage } from "./messages";
7
- import type { SessionStorage } from "./session-storage";
7
+ import type { SessionStorage, SessionStorageStat, VerifiedSessionDeleteResult, VerifiedSessionDeleteTarget } from "./session-storage";
8
8
  export declare const CURRENT_SESSION_VERSION = 3;
9
9
  export interface SessionHeader {
10
10
  type: "session";
@@ -73,6 +73,13 @@ export interface SessionMessageEntry extends SessionEntryBase {
73
73
  * metadata (not a message field) so strict message types stay intact. */
74
74
  evictedContent?: EvictedContentMarker;
75
75
  }
76
+ export declare function associateSessionMessageEntryId(message: AgentMessage, entryId: string): void;
77
+ export declare function getSessionMessageEntryId(message: AgentMessage): string | undefined;
78
+ export declare function associateSessionMessageObservationId(message: AgentMessage, observationId: string): string;
79
+ export declare function getSessionMessageObservationId(message: AgentMessage): string | undefined;
80
+ export declare function associateSessionMessageViewportAnchorId(message: AgentMessage, anchorId: string): void;
81
+ export declare function getSessionMessageViewportAnchorId(message: AgentMessage): string | undefined;
82
+ export declare function transferSessionMessageIdentity(source: AgentMessage[], target: AgentMessage[]): void;
76
83
  export interface ThinkingLevelChangeEntry extends SessionEntryBase {
77
84
  type: "thinking_level_change";
78
85
  thinkingLevel?: string | null;
@@ -230,6 +237,40 @@ export interface SessionContext {
230
237
  /** Mode-specific data from the last mode_change entry */
231
238
  modeData?: Record<string, unknown>;
232
239
  }
240
+ /** Immutable fingerprint captured during read-only resume inspection. */
241
+ export interface ResumeSessionIdentity {
242
+ canonicalPath: string;
243
+ sessionId: string;
244
+ dev: bigint;
245
+ ino: bigint;
246
+ size: number;
247
+ mtimeMs: number;
248
+ mtimeNs: bigint;
249
+ sha256: string;
250
+ }
251
+ export interface ResumeTailResumable {
252
+ kind: "resumable";
253
+ identity: ResumeSessionIdentity;
254
+ }
255
+ export interface ResumeTailTerminal {
256
+ kind: "terminal";
257
+ identity: ResumeSessionIdentity;
258
+ }
259
+ export interface ResumeTailError {
260
+ kind: "error";
261
+ reason: "missing" | "malformed" | "unstable" | "read-failed";
262
+ }
263
+ export type ResumeTailInspection = ResumeTailResumable | ResumeTailTerminal | ResumeTailError;
264
+ export interface StrictSessionOpenSuccess {
265
+ kind: "opened";
266
+ manager: SessionManager;
267
+ }
268
+ export interface StrictSessionOpenFailure {
269
+ kind: "error";
270
+ reason: ResumeTailError["reason"] | "identity-mismatch";
271
+ }
272
+ /** Result of opening an inspected session without create-or-rewrite fallback. */
273
+ export type StrictSessionOpenResult = StrictSessionOpenSuccess | StrictSessionOpenFailure;
233
274
  export interface SessionInfo {
234
275
  path: string;
235
276
  id: string;
@@ -246,6 +287,47 @@ export interface SessionInfo {
246
287
  firstMessage: string;
247
288
  allMessagesText: string;
248
289
  }
290
+ /** Kind of failure surfaced by strict scoped inventory. Any failure grants zero authority. */
291
+ export type StrictInventoryFailureKind = "root" | "scan" | "lstat" | "read" | "parse" | "stat" | "header" | "cwd" | "containment" | "identity";
292
+ /** Sanitized strict-inventory failure. Never carries raw file content. */
293
+ export interface StrictInventoryFailure {
294
+ kind: StrictInventoryFailureKind;
295
+ message: string;
296
+ path?: string;
297
+ }
298
+ /** One exact-identity candidate suitable for ACP authorization binding. */
299
+ export interface StrictInventoryCandidate {
300
+ /** Canonical absolute transcript path. */
301
+ path: string;
302
+ /** Session id parsed from the header. */
303
+ id: string;
304
+ /** Canonical cwd parsed from the header. */
305
+ cwd: string;
306
+ /** Descriptor-bound transcript identity (dev, ino, ...). */
307
+ identity: SessionStorageStat;
308
+ }
309
+ /**
310
+ * Strict inventory result. `complete` carries the full validated candidate set;
311
+ * `failure` carries every sanitized failure and grants zero page/cursor/authority.
312
+ * A failure result is never reduced to a partial candidate set.
313
+ */
314
+ export type StrictInventoryResult = {
315
+ kind: "complete";
316
+ candidates: StrictInventoryCandidate[];
317
+ } | {
318
+ kind: "failure";
319
+ failures: StrictInventoryFailure[];
320
+ };
321
+ /** Certainty-aware close outcome for strict ACP disposal. */
322
+ export type SessionManagerCloseOutcome = {
323
+ kind: "closed";
324
+ } | {
325
+ kind: "close_failed_retryable";
326
+ error: Error;
327
+ } | {
328
+ kind: "close_unknown";
329
+ error: Error;
330
+ };
249
331
  export type ReadonlySessionManager = Pick<SessionManager, "getCwd" | "getSessionDir" | "getSessionId" | "getSessionFile" | "getSessionName" | "getArtifactsDir" | "getArtifactManager" | "allocateArtifactPath" | "saveArtifact" | "getArtifactPath" | "getLeafId" | "getLeafEntry" | "getEntry" | "getLabel" | "getBranch" | "getHeader" | "getEntries" | "getTree" | "getUsageStatistics" | "putBlob">;
250
332
  /** Exported for testing */
251
333
  export declare function migrateSessionEntries(entries: FileEntry[]): void;
@@ -257,7 +339,7 @@ export declare function getLatestCompactionEntry(entries: SessionEntry[]): Compa
257
339
  * If leafId is provided, walks from that entry to root.
258
340
  * Handles compaction and branch summaries along the path.
259
341
  */
260
- export declare function buildSessionContext(entries: SessionEntry[], leafId?: string | null, byId?: Map<string, SessionEntry>): SessionContext;
342
+ export declare function buildSessionContext(entries: SessionEntry[], leafId?: string | null, byId?: Map<string, SessionEntry>, sessionIdentityNamespace?: string): SessionContext;
261
343
  /** Exported for testing */
262
344
  export declare function loadEntriesFromFile(filePath: string, storage?: SessionStorage): Promise<FileEntry[]>;
263
345
  declare class RecentSessionInfo {
@@ -386,6 +468,15 @@ export declare class SessionManager {
386
468
  flush(): Promise<void>;
387
469
  /** Close the persistent writer after flushing all pending data. */
388
470
  close(): Promise<void>;
471
+ /** Flush while open, then strictly close; retryable close skips the invalid second flush. */
472
+ flushAndCloseStrict(): Promise<SessionManagerCloseOutcome>;
473
+ /**
474
+ * Strictly flush and close the persist writer, returning the certainty-aware close
475
+ * outcome without manufacturing success. The existing {@link close} path is
476
+ * preserved for best-effort callers; this seam lets strict ACP disposal prove
477
+ * writer closure before any destructive operation.
478
+ */
479
+ closeStrict(): Promise<SessionManagerCloseOutcome>;
389
480
  getCwd(): string;
390
481
  /** Get usage statistics across all assistant messages in the session. */
391
482
  getUsageStatistics(): UsageStatistics;
@@ -515,7 +606,7 @@ export declare class SessionManager {
515
606
  * @param attribution Who initiated this message for billing/attribution semantics
516
607
  * @returns Entry id
517
608
  */
518
- appendCustomMessageEntry<T = unknown>(customType: string, content: string | (TextContent | ImageContent)[], display: boolean, details?: T, attribution?: MessageAttribution): string;
609
+ appendCustomMessageEntry<T = unknown>(customType: string, content: string | (TextContent | ImageContent)[], display: boolean, details?: T, attribution?: MessageAttribution, observationId?: string): string;
519
610
  /**
520
611
  * Append an MCP tool selection entry recording the discovery-selected MCP tools.
521
612
  * @param selectedToolNames MCP tool names selected for this branch
@@ -639,6 +730,18 @@ export declare class SessionManager {
639
730
  * @param sessionDir Optional session directory for /new or /branch. If omitted, derives from file's parent.
640
731
  */
641
732
  static open(filePath: string, sessionDir?: string, storage?: SessionStorage): Promise<SessionManager>;
733
+ /**
734
+ * List sessions for the resume picker without recovery or other maintenance writes.
735
+ */
736
+ static listForResumePickerReadOnly(cwd: string, sessionDir?: string, storage?: SessionStorage): Promise<SessionInfo[]>;
737
+ /** Inspect a selected session without acquiring write-capable ownership. */
738
+ static inspectSessionTailReadOnly(filePath: string, storage?: SessionStorage): Promise<ResumeTailInspection>;
739
+ /**
740
+ * Main startup code MUST retain the consented inspection identity and branch on
741
+ * the returned discriminant; an error result never creates, rewrites, or adopts
742
+ * the selected path. Breadcrumb ownership begins only after `kind: "opened"`.
743
+ */
744
+ static openExistingStrict(identity: ResumeSessionIdentity, sessionDir?: string, storage?: SessionStorage): Promise<StrictSessionOpenResult>;
642
745
  /**
643
746
  * Continue the most recent session, or create new if none.
644
747
  * @param cwd Working directory
@@ -657,5 +760,22 @@ export declare class SessionManager {
657
760
  * List all sessions across all project directories.
658
761
  */
659
762
  static listAll(storage?: SessionStorage): Promise<SessionInfo[]>;
763
+ /**
764
+ * Strict raw scoped inventory for ACP authorization. Enumerates the scoped
765
+ * session directory without suppressing any root/scan/lstat/read/parse/stat/
766
+ * header/cwd/containment/identity failure. A failure result carries every
767
+ * sanitized failure and grants zero authority — it is never reduced to a
768
+ * partial candidate set. Display/global {@link list} behavior is unaffected.
769
+ */
770
+ static inventorySessionsStrict(cwd: string, options?: {
771
+ sessionDir?: string;
772
+ storage?: SessionStorage;
773
+ }): StrictInventoryResult;
774
+ /**
775
+ * Propagate the storage-layer verified hard delete bound to exact identity evidence.
776
+ * Never performs ID lookup or first-match selection; the caller supplies the exact
777
+ * authorization target captured from a complete strict inventory.
778
+ */
779
+ deleteSessionVerified(target: VerifiedSessionDeleteTarget): Promise<VerifiedSessionDeleteResult>;
660
780
  }
661
781
  export {};
@@ -1,7 +1,53 @@
1
1
  export interface SessionStorageStat {
2
+ dev: bigint;
3
+ ino: bigint;
2
4
  size: number;
3
5
  mtimeMs: number;
6
+ mtimeNs: bigint;
4
7
  mtime: Date;
8
+ isFile: boolean;
9
+ }
10
+ /** Exact bytes and identity captured from one opened regular-file descriptor. */
11
+ export interface SessionStorageSnapshot {
12
+ bytes: Uint8Array;
13
+ stat: SessionStorageStat;
14
+ }
15
+ /**
16
+ * Four-state writer close lifecycle. Only a successful underlying close confirms
17
+ * `closed`. A failure certified to have happened BEFORE the OS close was dispatched
18
+ * is `close_failed_retryable` (ownership of the numeric fd is still proven, so a
19
+ * later retry/finalizer close is safe). Any exception from an actually dispatched
20
+ * close call is terminal `close_unknown`: the numeric fd cannot be safely retried
21
+ * or finalizer-closed, and the writer blocks strict deletion.
22
+ */
23
+ export type SessionStorageWriterCloseState = "open" | "close_failed_retryable" | "close_unknown" | "closed";
24
+ /**
25
+ * Thrown by a {@link SessionStorageWriterCloseAdapter} to certify that a close
26
+ * failure occurred BEFORE the real OS close (`fs.closeSync`-equivalent) was ever
27
+ * dispatched. Because no OS close ran, the numeric fd is still owned and a retry
28
+ * is safe. Any other thrown value is treated as a dispatched close failure
29
+ * (`close_unknown`) and forbids retry/finalizer close of that fd.
30
+ */
31
+ export declare class SessionStorageWriterRetryableCloseError extends Error {
32
+ readonly name = "SessionStorageWriterRetryableCloseError";
33
+ constructor(message?: string, options?: ErrorOptions);
34
+ }
35
+ /**
36
+ * Injectable dispatcher for the numeric-fd OS close. The default implementation
37
+ * calls `fs.closeSync(fd)`. Tests inject adapters that throw
38
+ * {@link SessionStorageWriterRetryableCloseError} to certify a pre-dispatch
39
+ * failure, or that call the real close and throw to simulate a dispatched
40
+ * failure (`close_unknown`).
41
+ */
42
+ export interface SessionStorageWriterCloseAdapter {
43
+ close(fd: number): void;
44
+ }
45
+ /** Options for opening a {@link SessionStorageWriter}. */
46
+ export interface SessionStorageWriterOpenOptions {
47
+ flags?: "a" | "w";
48
+ onError?: (err: Error) => void;
49
+ /** Injectable OS-close dispatcher; defaults to `fs.closeSync`. */
50
+ closeAdapter?: SessionStorageWriterCloseAdapter;
5
51
  }
6
52
  export interface SessionStorageWriter {
7
53
  writeLine(line: string): Promise<void>;
@@ -16,15 +62,35 @@ export interface SessionStorageWriter {
16
62
  flush(): Promise<void>;
17
63
  fsync(): Promise<void>;
18
64
  close(): Promise<void>;
65
+ /**
66
+ * Synchronously close the underlying descriptor. The certainty-aware close
67
+ * state is updated synchronously and any close failure throws before this
68
+ * returns, so sync callers (atomic rewrite) can observe a close failure
69
+ * before proceeding to rename. Mirrors {@link close} semantics exactly.
70
+ */
71
+ closeSync(): void;
19
72
  getError(): Error | undefined;
73
+ /** Current certainty-aware close lifecycle state. */
74
+ getCloseState(): SessionStorageWriterCloseState;
75
+ /** Stored error for non-success close states (`close_failed_retryable`/`close_unknown`). */
76
+ getCloseError(): Error | undefined;
20
77
  }
21
78
  export interface SessionStorage {
22
79
  ensureDirSync(dir: string): void;
23
80
  existsSync(path: string): boolean;
24
81
  writeTextSync(path: string, content: string): void;
25
82
  readTextSync(path: string): string;
83
+ /** Exact on-disk bytes for strict read-only session inspection. */
84
+ readBytesSync?(path: string): Uint8Array;
85
+ /** Exact bytes and descriptor-bound identity captured from one opened regular file. */
86
+ readSnapshotSync?(path: string): SessionStorageSnapshot;
26
87
  statSync(path: string): SessionStorageStat;
27
88
  listFilesSync(dir: string, pattern: string): string[];
89
+ /**
90
+ * Strict directory scan that never suppresses scan/root errors. Used by strict
91
+ * authorization inventory; the forgiving {@link listFilesSync} stays display-only.
92
+ */
93
+ listFilesStrictSync?(dir: string, pattern: string): string[];
28
94
  exists(path: string): Promise<boolean>;
29
95
  readText(path: string): Promise<string>;
30
96
  readTextPrefix(path: string, maxBytes: number): Promise<string>;
@@ -34,18 +100,90 @@ export interface SessionStorage {
34
100
  unlink(path: string): Promise<void>;
35
101
  unlinkSync(path: string): void;
36
102
  deleteSessionWithArtifacts(sessionPath: string): Promise<void>;
37
- openWriter(path: string, options?: {
38
- flags?: "a" | "w";
39
- onError?: (err: Error) => void;
40
- }): SessionStorageWriter;
103
+ /**
104
+ * Verified hard delete bound to exact identity evidence. Removes the verified
105
+ * artifact directory first, revalidates, and unlinks the transcript last. Returns
106
+ * typed partial-cleanup evidence for exact-identity retry; never returns success
107
+ * for a partial deletion.
108
+ */
109
+ deleteSessionVerified?(target: VerifiedSessionDeleteTarget): Promise<VerifiedSessionDeleteResult>;
110
+ openWriter(path: string, options?: SessionStorageWriterOpenOptions): SessionStorageWriter;
41
111
  }
112
+ /** Exact (dev, ino) identity fields used for ACP authorization binding. */
113
+ export interface SessionStorageFileIdentity {
114
+ dev: bigint;
115
+ ino: bigint;
116
+ }
117
+ /** Kind of verification failure surfaced by {@link deleteSessionVerified}. */
118
+ export type VerifiedDeleteFailureKind = "containment" | "symlink" | "stat" | "identity" | "header" | "cwd" | "artifacts";
119
+ /**
120
+ * Thrown by {@link deleteSessionVerified} when canonical containment, transcript
121
+ * non-symlink/identity, header id/cwd, parent identity, or artifact identity
122
+ * verification fails. These are visible, sanitized failures: they never mutate
123
+ * the transcript or artifacts and grant zero authority.
124
+ */
125
+ export declare class SessionDeleteVerificationError extends Error {
126
+ readonly kind: VerifiedDeleteFailureKind;
127
+ constructor(kind: VerifiedDeleteFailureKind, message: string, options?: ErrorOptions);
128
+ }
129
+ /**
130
+ * Exact identity evidence a verified hard delete binds to. All fields are captured
131
+ * at authorization time; delete revalidates each one before any mutation. Retry
132
+ * after a partial cleanup supplies the recorded artifact identity via
133
+ * {@link expectedArtifactsIdentity}.
134
+ */
135
+ export interface VerifiedSessionDeleteTarget {
136
+ /** Canonical sessions root; the transcript must be contained within it. */
137
+ sessionsRoot: string;
138
+ /** Canonical transcript path (absolute `*.jsonl`). */
139
+ transcriptPath: string;
140
+ /** Expected session id parsed from the header. */
141
+ sessionId: string;
142
+ /** Expected canonical cwd parsed from the header. */
143
+ cwd: string;
144
+ /** Expected transcript file `(dev, ino)` captured at authorization. */
145
+ transcriptIdentity: SessionStorageFileIdentity;
146
+ /**
147
+ * For retry after an `artifacts` `cleanup_pending`: the recorded artifact
148
+ * directory identity to re-accept. A replacement/different artifact directory
149
+ * fails closed. Omit on first attempt or to accept recorded absence.
150
+ */
151
+ expectedArtifactsIdentity?: SessionStorageFileIdentity;
152
+ }
153
+ /**
154
+ * Outcome of a verified hard delete. Artifact removal happens first; only after
155
+ * revalidation is the transcript unlinked last. A partial deletion returns
156
+ * `cleanup_pending` with exact evidence for same-connection retry — never
157
+ * `deleted` and never `{}`.
158
+ */
159
+ export type VerifiedSessionDeleteResult = {
160
+ kind: "deleted";
161
+ } | {
162
+ kind: "cleanup_pending";
163
+ phase: "artifacts";
164
+ error: Error;
165
+ /** Artifact directory identity at failure time; undefined when absent. */
166
+ artifactsIdentity: SessionStorageFileIdentity | undefined;
167
+ /** Transcript identity (unchanged) for retry binding. */
168
+ transcriptIdentity: SessionStorageFileIdentity;
169
+ } | {
170
+ kind: "cleanup_pending";
171
+ phase: "transcript";
172
+ error: Error;
173
+ /** Transcript identity at failure time for retry binding. */
174
+ transcriptIdentity: SessionStorageFileIdentity;
175
+ };
42
176
  export declare class FileSessionStorage implements SessionStorage {
177
+ #private;
43
178
  ensureDirSync(dir: string): void;
44
179
  existsSync(path: string): boolean;
45
180
  writeTextSync(fpath: string, content: string): void;
46
181
  readTextSync(fpath: string): string;
182
+ readBytesSync(fpath: string): Uint8Array;
183
+ readSnapshotSync(fpath: string): SessionStorageSnapshot;
47
184
  statSync(path: string): SessionStorageStat;
48
185
  listFilesSync(dir: string, pattern: string): string[];
186
+ listFilesStrictSync(dir: string, pattern: string): string[];
49
187
  exists(path: string): Promise<boolean>;
50
188
  readText(path: string): Promise<string>;
51
189
  readTextPrefix(path: string, maxBytes: number): Promise<string>;
@@ -54,15 +192,18 @@ export declare class FileSessionStorage implements SessionStorage {
54
192
  renameSync(path: string, nextPath: string): void;
55
193
  unlink(path: string): Promise<void>;
56
194
  unlinkSync(path: string): void;
57
- openWriter(path: string, options?: {
58
- flags?: "a" | "w";
59
- onError?: (err: Error) => void;
60
- }): SessionStorageWriter;
195
+ openWriter(path: string, options?: SessionStorageWriterOpenOptions): SessionStorageWriter;
61
196
  /**
62
197
  * Delete a session file and its artifacts directory.
63
198
  * Artifacts are stored in a sibling directory with the same name minus .jsonl extension.
64
199
  */
65
200
  deleteSessionWithArtifacts(sessionPath: string): Promise<void>;
201
+ /**
202
+ * Verified hard delete bound to exact identity evidence. Artifact directory first,
203
+ * revalidate, transcript last. Partial deletion returns typed cleanup_pending
204
+ * evidence; identity/symlink/containment/header/cwd mismatch throws.
205
+ */
206
+ deleteSessionVerified(target: VerifiedSessionDeleteTarget): Promise<VerifiedSessionDeleteResult>;
66
207
  }
67
208
  export declare class MemorySessionStorage implements SessionStorage {
68
209
  #private;
@@ -70,8 +211,11 @@ export declare class MemorySessionStorage implements SessionStorage {
70
211
  existsSync(path: string): boolean;
71
212
  writeTextSync(path: string, content: string): void;
72
213
  readTextSync(path: string): string;
214
+ readBytesSync(path: string): Uint8Array;
215
+ readSnapshotSync(path: string): SessionStorageSnapshot;
73
216
  statSync(path: string): SessionStorageStat;
74
217
  listFilesSync(dir: string, pattern: string): string[];
218
+ listFilesStrictSync(dir: string, pattern: string): string[];
75
219
  exists(path: string): Promise<boolean>;
76
220
  readText(path: string): Promise<string>;
77
221
  readTextPrefix(path: string, maxBytes: number): Promise<string>;
@@ -80,9 +224,7 @@ export declare class MemorySessionStorage implements SessionStorage {
80
224
  renameSync(path: string, nextPath: string): void;
81
225
  unlink(path: string): Promise<void>;
82
226
  unlinkSync(path: string): void;
83
- deleteSessionWithArtifacts(_sessionPath: string): Promise<void>;
84
- openWriter(path: string, options?: {
85
- flags?: "a" | "w";
86
- onError?: (err: Error) => void;
87
- }): SessionStorageWriter;
227
+ deleteSessionWithArtifacts(sessionPath: string): Promise<void>;
228
+ deleteSessionVerified(target: VerifiedSessionDeleteTarget): Promise<VerifiedSessionDeleteResult>;
229
+ openWriter(path: string, options?: SessionStorageWriterOpenOptions): SessionStorageWriter;
88
230
  }
@@ -45,7 +45,7 @@ export interface CredentialAutoImportOptions {
45
45
  trigger: CredentialAutoImportTrigger;
46
46
  sourceLabel?: CredentialAutoImportSourceLabel;
47
47
  }
48
- export declare function runExternalCredentialAutoImport({ authStorage, discover, discoveryOptions }: CredentialAutoImportOptions): Promise<CredentialAutoImportResult>;
48
+ export declare function runExternalCredentialAutoImport({ authStorage, discover, discoveryOptions, }: CredentialAutoImportOptions): Promise<CredentialAutoImportResult>;
49
49
  export declare function buildCredentialAutoImportNotice(result: Pick<CredentialAutoImportResult, "imported">): string | undefined;
50
50
  export declare function formatCredentialAutoImportResult(result: CredentialAutoImportResult): string[];
51
51
  export interface CredentialImportMarkerStore {
@@ -60,4 +60,4 @@ export interface StartupCredentialAutoImportOptions {
60
60
  agentDir?: string;
61
61
  markerStore?: CredentialImportMarkerStore;
62
62
  }
63
- export declare function runStartupCredentialAutoImportIfNeeded({ authStorage: activeAuthStorage, modelRegistry: activeModelRegistry, discover, version, agentDir, markerStore }: StartupCredentialAutoImportOptions): Promise<string | undefined>;
63
+ export declare function runStartupCredentialAutoImportIfNeeded({ authStorage: activeAuthStorage, modelRegistry: activeModelRegistry, discover, version, agentDir, markerStore, }: StartupCredentialAutoImportOptions): Promise<string | undefined>;
@@ -11,6 +11,7 @@ import { Settings } from "../config/settings";
11
11
  import { type Skill } from "../extensibility/skills";
12
12
  import type { HindsightSessionState } from "../hindsight/state";
13
13
  import type { LocalProtocolOptions } from "../internal-urls";
14
+ import { AgentRegistry } from "../registry/agent-registry";
14
15
  import type { ForkContextSeed } from "../session/agent-session";
15
16
  import type { ArtifactManager } from "../session/artifacts";
16
17
  import type { AuthStorage } from "../session/auth-storage";
@@ -61,6 +62,8 @@ export interface ExecutorOptions {
61
62
  authStorage?: AuthStorage;
62
63
  modelRegistry?: ModelRegistry;
63
64
  settings?: Settings;
65
+ /** Parent session's registry; shared by child sessions for IRC routing and roster visibility. */
66
+ agentRegistry?: AgentRegistry;
64
67
  /**
65
68
  * Live service-tier intent of the parent session (`AgentSession.serviceTier`),
66
69
  * used as the inherited tier when `task.serviceTier === "inherit"`. Passing the
@@ -1,4 +1,4 @@
1
- import type { SingleResult, TaskToolDetails } from "./types";
1
+ import { type SingleResult, type TaskToolDetails } from "./types";
2
2
  export interface TaskRoi {
3
3
  tokens: number;
4
4
  contextTokens?: number;
@@ -31,6 +31,7 @@ export interface TaskResultReceipt {
31
31
  modelSubstitutionWarning?: SingleResult["modelSubstitutionWarning"];
32
32
  usage?: SingleResult["usage"];
33
33
  cost?: number;
34
+ usageCostBreakdownComplete?: true;
34
35
  branchName?: string;
35
36
  retryFailure?: {
36
37
  attempt: number;
@@ -77,6 +78,7 @@ export interface RawTaskToolDetails {
77
78
  results: SingleResult[];
78
79
  totalDurationMs: number;
79
80
  usage?: TaskToolDetails["usage"];
81
+ usageCostBreakdownComplete?: TaskToolDetails["usageCostBreakdownComplete"];
80
82
  async?: TaskToolDetails["async"];
81
83
  forkContextClonedTokens?: number;
82
84
  roiSummary?: TaskToolDetails["roiSummary"];
@@ -387,6 +387,8 @@ export interface SingleResult {
387
387
  paused?: boolean;
388
388
  /** Aggregated usage from the subprocess, accumulated incrementally from message_end events. */
389
389
  usage?: Usage;
390
+ /** True only when every usage-contributing assistant supplied a complete, non-negative raw cost breakdown. */
391
+ usageCostBreakdownComplete?: true;
390
392
  /** Output path for the task result */
391
393
  outputPath?: string;
392
394
  /** Patch path for isolated worktree output */
@@ -430,6 +432,10 @@ export interface SingleResult {
430
432
  reasons: string[];
431
433
  };
432
434
  }
435
+ /** True only for complete, factual five-bucket cost accounting. */
436
+ export declare function hasCompleteUsageCostBreakdown(usage: unknown): boolean;
437
+ /** True only when every usage-contributing result has explicit, complete cost provenance. */
438
+ export declare function hasCompleteAggregateUsageCostBreakdown(results: readonly Pick<SingleResult, "usage" | "usageCostBreakdownComplete">[]): boolean;
433
439
  /** Tool details for TUI rendering */
434
440
  export interface TaskToolDetails {
435
441
  projectAgentsDir: string | null;
@@ -437,6 +443,8 @@ export interface TaskToolDetails {
437
443
  totalDurationMs: number;
438
444
  /** Aggregated usage across all subagents. */
439
445
  usage?: Usage;
446
+ /** True only when every usage-contributing subagent supplied a complete raw cost breakdown. */
447
+ usageCostBreakdownComplete?: true;
440
448
  /** Aggregate cloned tokens copied into fork-context seeds across subagents. */
441
449
  forkContextClonedTokens?: number;
442
450
  roiSummary?: {
@@ -6,8 +6,13 @@
6
6
  * through the extension/runner/controller wiring. A session has at most one
7
7
  * source; registering returns a disposer.
8
8
  */
9
+ import type { WorkflowGateEmitter } from "../modes/shared/agent-wire/unattended-session";
9
10
  import type { AskAnswerSource } from "./index";
10
11
  /** Register `source` for `sessionId`. Returns a disposer that clears it. */
11
12
  export declare function registerAskAnswerSource(sessionId: string, source: AskAnswerSource): () => void;
12
13
  /** The answer source for `sessionId`, if one is registered. */
13
14
  export declare function getAskAnswerSource(sessionId: string): AskAnswerSource | undefined;
15
+ /** Publish a session's current workflow-gate emitter after mode initialization. */
16
+ export declare function notifyWorkflowGateEmitterChanged(sessionId: string, emitter: WorkflowGateEmitter | undefined): void;
17
+ /** Observe workflow-gate emitter installation even when it occurs after session_start. */
18
+ export declare function registerWorkflowGateEmitterListener(sessionId: string, listener: (emitter: WorkflowGateEmitter | undefined) => void): () => void;
@@ -19,7 +19,7 @@ import { type Component } from "@gajae-code/tui";
19
19
  import * as z from "zod/v4";
20
20
  import type { RenderResultOptions } from "../extensibility/custom-tools/types";
21
21
  import { type Theme } from "../modes/theme/theme";
22
- import type { ToolSession } from ".";
22
+ import type { AskRemoteControl, AskRemoteInteraction, AskSettlement, AskSettlementResult, ToolSession } from ".";
23
23
  export declare const askSchema: z.ZodObject<{
24
24
  questions: z.ZodArray<z.ZodObject<{
25
25
  id: z.ZodString;
@@ -71,6 +71,30 @@ export interface AskToolDetails {
71
71
  /** Multi-part question mode */
72
72
  results?: QuestionResult[];
73
73
  }
74
+ /** The only remote navigation control; labels are presentation, never protocol. */
75
+ export declare function askRemoteControls(input: {
76
+ multi: boolean;
77
+ questionIndex: number;
78
+ questionCount: number;
79
+ selectedCount: number;
80
+ hasNonWhitespaceCustom: boolean;
81
+ }): readonly AskRemoteControl[];
82
+ /** Classify remote input without looking at option labels used for controls. */
83
+ export declare function classifyAskRemoteInteraction(input: {
84
+ interaction: AskRemoteInteraction;
85
+ options: readonly string[];
86
+ controls: readonly AskRemoteControl[];
87
+ multi: boolean;
88
+ selectedCount: number;
89
+ customInput?: string;
90
+ clarification?: boolean;
91
+ }): AskSettlement;
92
+ /** A one-shot local receipt used to normalize legacy string answer sources. */
93
+ export declare function legacyAskReceipt(value: string): {
94
+ source: "remote";
95
+ interaction: AskRemoteInteraction;
96
+ settle(settlement: AskSettlement): Promise<AskSettlementResult>;
97
+ };
74
98
  type AskParams = AskToolInput;
75
99
  /**
76
100
  * Ask tool for interactive user prompting during execution.
@@ -86,7 +86,7 @@ export declare class BashTool implements AgentTool<BashToolSchema, BashToolDetai
86
86
  label: string;
87
87
  commandCwd: string;
88
88
  }>;
89
- execute(_toolCallId: string, { command: rawCommand, env: rawEnv, timeout: rawTimeout, cwd, async: asyncRequested, pty }: BashToolInput, signal?: AbortSignal, onUpdate?: AgentToolUpdateCallback<BashToolDetails>, ctx?: AgentToolContext): Promise<AgentToolResult<BashToolDetails>>;
89
+ execute(_toolCallId: string, { command: rawCommand, env: rawEnv, timeout: rawTimeout, cwd, async: asyncRequested, pty, }: BashToolInput, signal?: AbortSignal, onUpdate?: AgentToolUpdateCallback<BashToolDetails>, ctx?: AgentToolContext): Promise<AgentToolResult<BashToolDetails>>;
90
90
  }
91
91
  export interface BashRenderArgs {
92
92
  command?: string;
@@ -60,6 +60,12 @@ export interface RunInTabOptions {
60
60
  }
61
61
  export interface ReleaseTabOptions {
62
62
  kill?: boolean;
63
+ /**
64
+ * Absolute end-to-end deadline (`Date.now()`-based, ms) for the whole teardown chain.
65
+ * Shared across a `releaseAllTabs` loop so close/close-all honors ONE aggregate budget.
66
+ * Omitted (the GC/session-teardown callers) keeps the original unbounded behavior.
67
+ */
68
+ deadlineAt?: number;
63
69
  }
64
70
  export declare function getTab(name: string): TabSession | undefined;
65
71
  /** Read-only, GC-facing projection of a live tab. Never exposes the mutable `tabs` map. */
@@ -70,16 +70,68 @@ export type ContextFileEntry = {
70
70
  };
71
71
  export type { DiscoverableMCPTool } from "../runtime-mcp/discoverable-tool-metadata";
72
72
  export type { DiscoverableTool, DiscoverableToolSearchIndex, DiscoverableToolSearchResult, DiscoverableToolSource, } from "../tool-discovery/tool-index";
73
+ /** A typed remote action available to an ask answer source. */
74
+ export type AskRemoteControlId = "navigation_forward";
75
+ export interface AskRemoteControl {
76
+ id: AskRemoteControlId;
77
+ kind: "navigation";
78
+ label: "Next" | "Done";
79
+ enabled: boolean;
80
+ }
81
+ export interface AskAnswerRequest {
82
+ question: string;
83
+ options: string[];
84
+ interaction: "selector" | "custom_editor" | "clarification_editor";
85
+ controls: readonly AskRemoteControl[];
86
+ }
87
+ export type AskRemoteInteraction = {
88
+ kind: "value";
89
+ value: string;
90
+ } | {
91
+ kind: "control";
92
+ controlId: AskRemoteControlId;
93
+ };
94
+ export type AskSettlement = {
95
+ kind: "commit";
96
+ } | {
97
+ kind: "resolve_without_commit";
98
+ reason: "toggle" | "other_transition" | "clarification_transition" | "clarification_submitted" | "empty_navigation" | "back_navigation" | "cancelled" | "aborted" | "timed_out" | "exception" | "shutdown";
99
+ } | {
100
+ kind: "invalid";
101
+ reason: "invalid_option" | "invalid_control" | "invalid_structured_answer" | "empty_custom" | "empty_clarification";
102
+ };
103
+ export type AskSelectedAckOutcome = {
104
+ status: "delivered";
105
+ messageId: number;
106
+ } | {
107
+ status: "failed";
108
+ reason: "unsupported" | "no_participant" | "ambiguous_participant" | "route_missing" | "expired" | "cancelled" | "telegram_rejected" | "session_closed";
109
+ } | {
110
+ status: "unknown";
111
+ reason: "transport_ambiguous" | "origin_disconnected" | "host_timeout" | "shutdown";
112
+ };
113
+ export type AskSettlementResult = {
114
+ kind: "committed";
115
+ ack: AskSelectedAckOutcome;
116
+ } | {
117
+ kind: "resolved_without_commit";
118
+ } | {
119
+ kind: "invalid_closed";
120
+ };
121
+ export interface AskRemoteReceipt {
122
+ source: "remote";
123
+ interaction: AskRemoteInteraction;
124
+ settle(value: AskSettlement): Promise<AskSettlementResult>;
125
+ }
126
+ export type AskAnswerSourceResult = AskRemoteReceipt | string | undefined;
73
127
  /**
74
- * Source of remote answers for interactive asks (e.g. a Telegram reply routed
75
- * through the notifications SDK). Lets a pending ask resolve without RPC mode.
128
+ * Source of remote answers. `awaitAnswer` remains the legacy wire for existing
129
+ * integrations; typed sources opt into `awaitAnswerRequest`. This keeps an old
130
+ * string-only source from accidentally acquiring acknowledgement authority.
76
131
  */
77
132
  export interface AskAnswerSource {
78
- /**
79
- * Race a remote answer against the local UI for one question. Resolves with the
80
- * chosen option label or free-text answer, or `undefined` to defer to local UI.
81
- */
82
133
  awaitAnswer(question: string, options: string[], signal?: AbortSignal): Promise<string | undefined>;
134
+ awaitAnswerRequest?(request: AskAnswerRequest, signal?: AbortSignal): Promise<AskAnswerSourceResult>;
83
135
  }
84
136
  /** Session context for tool factories */
85
137
  export interface ToolSession {