indusagi-coding-agent 0.2.8 → 0.2.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (219) hide show
  1. package/package.json +2 -1
  2. package/src/_decls/entry.ts +18 -0
  3. package/src/_decls/guardrails.ts +35 -0
  4. package/src/_decls/index.ts +26 -0
  5. package/src/addons/contract.ts +236 -0
  6. package/src/addons/dispatch/event-dispatcher.ts +164 -0
  7. package/src/addons/dispatch/index.ts +25 -0
  8. package/src/addons/dispatch/tool-interceptor.ts +208 -0
  9. package/src/addons/host.ts +225 -0
  10. package/src/addons/index.ts +112 -0
  11. package/src/addons/manifest.ts +158 -0
  12. package/src/addons/sandbox.ts +170 -0
  13. package/src/addons/surface.ts +78 -0
  14. package/src/boot/auth-vault.ts +195 -0
  15. package/src/boot/boot.ts +138 -0
  16. package/src/boot/contract.ts +238 -0
  17. package/src/boot/heap.ts +59 -0
  18. package/src/boot/index.ts +28 -0
  19. package/src/boot/invocation.ts +93 -0
  20. package/src/boot/runners/addon-wiring.ts +153 -0
  21. package/src/boot/runners/checkpoint.ts +169 -0
  22. package/src/boot/runners/delegate-runner.ts +294 -0
  23. package/src/boot/runners/index.ts +13 -0
  24. package/src/boot/runners/link-runner.ts +45 -0
  25. package/src/boot/runners/memdir.ts +168 -0
  26. package/src/boot/runners/oneshot-runner.ts +58 -0
  27. package/src/boot/runners/read-state.ts +90 -0
  28. package/src/boot/runners/registry.ts +42 -0
  29. package/src/boot/runners/repl-runner.ts +143 -0
  30. package/src/boot/runners/server-mode.ts +121 -0
  31. package/src/boot/runners/session.ts +641 -0
  32. package/src/boot/server-token.ts +148 -0
  33. package/src/boot/stages.ts +167 -0
  34. package/src/boot/upgrade/apply.ts +94 -0
  35. package/src/boot/upgrade/index.ts +13 -0
  36. package/src/boot/upgrade/upgrades.ts +289 -0
  37. package/src/briefing/compose.ts +150 -0
  38. package/src/briefing/context-docs.ts +19 -0
  39. package/src/briefing/contract.ts +717 -0
  40. package/src/briefing/index.ts +31 -0
  41. package/src/briefing/macros.ts +97 -0
  42. package/src/briefing/skills.ts +47 -0
  43. package/src/capability-deck/bridge-ledger/index.ts +27 -0
  44. package/src/capability-deck/bridge-ledger/key.ts +67 -0
  45. package/src/capability-deck/bridge-ledger/ledger.ts +131 -0
  46. package/src/capability-deck/bridge-ledger/network.ts +117 -0
  47. package/src/capability-deck/builtin-bridge.ts +312 -0
  48. package/src/capability-deck/cards/bg-process-card.ts +335 -0
  49. package/src/capability-deck/cards/index.ts +115 -0
  50. package/src/capability-deck/cards/memory-card.ts +146 -0
  51. package/src/capability-deck/cards/plan-file.ts +97 -0
  52. package/src/capability-deck/cards/plan-tools.ts +185 -0
  53. package/src/capability-deck/cards/saas-card.ts +183 -0
  54. package/src/capability-deck/cards/task-card.ts +207 -0
  55. package/src/capability-deck/cards/todo-card.ts +168 -0
  56. package/src/capability-deck/cards/workflow-card.ts +247 -0
  57. package/src/capability-deck/contract.ts +388 -0
  58. package/src/capability-deck/index.ts +48 -0
  59. package/src/capability-deck/manifest.ts +109 -0
  60. package/src/capability-deck/provision.ts +169 -0
  61. package/src/channels/contract.ts +191 -0
  62. package/src/channels/framer.ts +50 -0
  63. package/src/channels/index.ts +101 -0
  64. package/src/channels/link/dialog.ts +129 -0
  65. package/src/channels/link/driver.ts +190 -0
  66. package/src/channels/link/index.ts +34 -0
  67. package/src/channels/link/server.ts +134 -0
  68. package/src/channels/oneshot.ts +90 -0
  69. package/src/channels/ops.ts +65 -0
  70. package/src/channels/session-ops.ts +81 -0
  71. package/src/conductor/bash-guard.ts +599 -0
  72. package/src/conductor/catalog/catalog.ts +116 -0
  73. package/src/conductor/catalog/index.ts +8 -0
  74. package/src/conductor/catalog/matcher.ts +134 -0
  75. package/src/conductor/conductor.ts +234 -0
  76. package/src/conductor/contract.ts +842 -0
  77. package/src/conductor/diagnostics.ts +227 -0
  78. package/src/conductor/index.ts +33 -0
  79. package/src/conductor/permissions.ts +588 -0
  80. package/src/conductor/quota-error.ts +49 -0
  81. package/src/conductor/signal-hub/hub.ts +46 -0
  82. package/src/conductor/signal-hub/index.ts +2 -0
  83. package/src/conductor/signal-hub/translate.test.ts +81 -0
  84. package/src/conductor/signal-hub/translate.ts +74 -0
  85. package/src/conductor/skill-parse/index.ts +2 -0
  86. package/src/conductor/skill-parse/parse.ts +108 -0
  87. package/src/conductor/transcript-store/index.ts +22 -0
  88. package/src/conductor/transcript-store/serialize.ts +116 -0
  89. package/src/conductor/transcript-store/store.ts +205 -0
  90. package/src/console/auth-status.ts +56 -0
  91. package/src/console/components/AgentsView.ts +165 -0
  92. package/src/console/components/BackgroundAgents.ts +155 -0
  93. package/src/console/components/Banner.ts +334 -0
  94. package/src/console/components/Composer.ts +94 -0
  95. package/src/console/components/StatusBar.ts +49 -0
  96. package/src/console/components/TerminalConsole.ts +1090 -0
  97. package/src/console/components/WorkingIndicator.ts +98 -0
  98. package/src/console/components/banner-sweep.ts +24 -0
  99. package/src/console/components/welcome.ts +74 -0
  100. package/src/console/contract.ts +630 -0
  101. package/src/console/index.ts +34 -0
  102. package/src/console/input/complete.ts +127 -0
  103. package/src/console/input/dir-reader.ts +34 -0
  104. package/src/console/input/index.ts +23 -0
  105. package/src/console/input/keymap.ts +159 -0
  106. package/src/console/input/paste.ts +104 -0
  107. package/src/console/mount.ts +56 -0
  108. package/src/console/overlays/approval-queue.ts +57 -0
  109. package/src/console/overlays/approval.ts +130 -0
  110. package/src/console/overlays/auth.ts +342 -0
  111. package/src/console/overlays/boards.ts +308 -0
  112. package/src/console/overlays/host.ts +36 -0
  113. package/src/console/overlays/index.ts +26 -0
  114. package/src/console/overlays/pickers.ts +258 -0
  115. package/src/console/overlays/sessions.ts +190 -0
  116. package/src/console/reducer.ts +182 -0
  117. package/src/console/slash/builtins.ts +81 -0
  118. package/src/console/slash/commands/dynamic.ts +83 -0
  119. package/src/console/slash/commands/integrations.ts +695 -0
  120. package/src/console/slash/commands/shared.ts +75 -0
  121. package/src/console/slash/commands/transcript.ts +263 -0
  122. package/src/console/slash/commands/workbench.ts +246 -0
  123. package/src/console/slash/index.ts +15 -0
  124. package/src/console/slash/registry.ts +70 -0
  125. package/src/console/slash/resolve.ts +63 -0
  126. package/src/console/startup.ts +209 -0
  127. package/src/console/theme/adapter.ts +45 -0
  128. package/src/console/theme/index.ts +7 -0
  129. package/src/console/theme/palette.ts +68 -0
  130. package/src/console/theme/resolve.ts +39 -0
  131. package/src/console/theme/tokens.ts +71 -0
  132. package/src/entry.ts +55 -0
  133. package/src/guardrails.ts +37 -0
  134. package/src/index.ts +18 -0
  135. package/src/insight/channel.ts +88 -0
  136. package/src/insight/contract.ts +185 -0
  137. package/src/insight/index.ts +110 -0
  138. package/src/insight/recorder.ts +213 -0
  139. package/src/insight/redaction.ts +157 -0
  140. package/src/insight/replay.ts +158 -0
  141. package/src/insight/sampling.ts +70 -0
  142. package/src/insight/serialize.ts +50 -0
  143. package/src/insight/sinks/console.ts +64 -0
  144. package/src/insight/sinks/file.ts +40 -0
  145. package/src/insight/sinks/index.ts +24 -0
  146. package/src/insight/sinks/stream.ts +54 -0
  147. package/src/integrations/sarvam/attach.ts +239 -0
  148. package/src/integrations/sarvam/config.ts +156 -0
  149. package/src/integrations/sarvam/index.ts +25 -0
  150. package/src/integrations/sarvam/sarvam.test.ts +60 -0
  151. package/src/integrations/sarvam/types.ts +27 -0
  152. package/src/integrations/zoho/attach.ts +342 -0
  153. package/src/integrations/zoho/config.ts +125 -0
  154. package/src/integrations/zoho/index.ts +27 -0
  155. package/src/integrations/zoho/types.ts +21 -0
  156. package/src/integrations/zoho/zoho.test.ts +50 -0
  157. package/src/kit/clipboard-image.ts +107 -0
  158. package/src/kit/external-editor.ts +48 -0
  159. package/src/kit/image.ts +59 -0
  160. package/src/kit/index.ts +51 -0
  161. package/src/kit/shell.ts +19 -0
  162. package/src/kit/tool-fetch.ts +85 -0
  163. package/src/launch/catalog.ts +148 -0
  164. package/src/launch/contract.ts +187 -0
  165. package/src/launch/credentials.ts +625 -0
  166. package/src/launch/index.ts +98 -0
  167. package/src/launch/invocation/attachments.ts +179 -0
  168. package/src/launch/invocation/flags.ts +196 -0
  169. package/src/launch/invocation/index.ts +25 -0
  170. package/src/launch/invocation/read.ts +260 -0
  171. package/src/launch/invocation/usage.ts +67 -0
  172. package/src/launch/login.ts +324 -0
  173. package/src/launch/oauth.test.ts +18 -0
  174. package/src/launch/oauth.ts +203 -0
  175. package/src/launch/packages.ts +194 -0
  176. package/src/launch/pickers.ts +189 -0
  177. package/src/runtime-bridge/bridges/_drive.ts +96 -0
  178. package/src/runtime-bridge/bridges/builtins.ts +68 -0
  179. package/src/runtime-bridge/bridges/claude-cli.ts +123 -0
  180. package/src/runtime-bridge/bridges/codex-cli.ts +142 -0
  181. package/src/runtime-bridge/bridges/index.ts +33 -0
  182. package/src/runtime-bridge/bridges/indusagi-cli.ts +155 -0
  183. package/src/runtime-bridge/broker.ts +227 -0
  184. package/src/runtime-bridge/contract.ts +122 -0
  185. package/src/runtime-bridge/index.ts +79 -0
  186. package/src/runtime-bridge/sink.ts +180 -0
  187. package/src/sessions/contract.ts +81 -0
  188. package/src/sessions/index.ts +13 -0
  189. package/src/sessions/library.ts +229 -0
  190. package/src/settings/contract.ts +114 -0
  191. package/src/settings/index.ts +32 -0
  192. package/src/settings/manager.ts +117 -0
  193. package/src/transcript-export/index.ts +45 -0
  194. package/src/transcript-export/publish.ts +260 -0
  195. package/src/transcript-export/sgr.ts +315 -0
  196. package/src/transcript-export/template.ts +272 -0
  197. package/src/transcript-export/theme-bridge.ts +150 -0
  198. package/src/window-budget/budget/estimate.ts +135 -0
  199. package/src/window-budget/budget/gate.ts +33 -0
  200. package/src/window-budget/budget/index.ts +16 -0
  201. package/src/window-budget/budget/slice.ts +56 -0
  202. package/src/window-budget/condenser.ts +58 -0
  203. package/src/window-budget/contract.ts +184 -0
  204. package/src/window-budget/index.ts +19 -0
  205. package/src/window-budget/microcompact.ts +95 -0
  206. package/src/window-budget/rehydrate.ts +136 -0
  207. package/src/window-budget/summarize/condense.ts +103 -0
  208. package/src/window-budget/summarize/index.ts +14 -0
  209. package/src/window-budget/summarize/prompt.ts +149 -0
  210. package/src/workflow-engine/agent-runner.ts +181 -0
  211. package/src/workflow-engine/display.ts +224 -0
  212. package/src/workflow-engine/engine.ts +294 -0
  213. package/src/workflow-engine/index.ts +23 -0
  214. package/src/workflow-engine/parse.ts +172 -0
  215. package/src/workflow-engine/structured-output.ts +35 -0
  216. package/src/workspace/brand.ts +29 -0
  217. package/src/workspace/index.ts +18 -0
  218. package/src/workspace/locator.ts +103 -0
  219. package/src/workspace/runtime-detect.ts +64 -0
@@ -0,0 +1,842 @@
1
+ // @ts-nocheck
2
+ // Type declarations recovered from dist/types (no runtime body)
3
+ /**
4
+ * Conductor contract — the FROZEN type surface of Phase 2 (agent runtime core).
5
+ *
6
+ * This module is the single typed seam between the coding-agent *product* (the
7
+ * UI/channels that drive a session) and the framework `Agent` (the raw LLM
8
+ * conversation loop, published by `indusagi/agent`). It declares *only* shapes
9
+ * plus two tiny inert helpers — no behavior, no I/O, no orchestration. Every
10
+ * later conductor module (the signal hub, the transcript store, the model
11
+ * catalog/matcher, the credential vault, the conductor factory, and the
12
+ * `SessionConductor` itself) is written against the names declared here, so the
13
+ * file is intentionally small, append-mostly, and stable.
14
+ *
15
+ * Design stance:
16
+ * - The conductor *wraps* the framework `Agent`. The framework emits a
17
+ * fine-grained `AgentEvent` stream for its own loop; the conductor consumes
18
+ * that internally and **re-emits a distinct, product-level
19
+ * {@link SessionSignal} stream** to consumers. The two are deliberately not
20
+ * the same union: `SessionSignal` is the stable surface the app renders,
21
+ * free to evolve independently of the framework's loop events.
22
+ * - Faults are **typed discriminated values** ({@link ConductorFault}), never
23
+ * string sentinels. A consumer switches on `fault.kind`, not on substring
24
+ * matching of a message.
25
+ * - Persistence uses a **fresh on-disk vocabulary** ({@link TranscriptEntry},
26
+ * {@link SessionHead}, {@link TRANSCRIPT_SCHEMA}). The node is a `parent`-linked
27
+ * tree, the version is a namespaced string, and the field names are the
28
+ * conductor's own — not the framework's session-manager schema.
29
+ * - State is exposed as an **immutable snapshot** ({@link ConductorState});
30
+ * consumers read it, they never mutate it.
31
+ *
32
+ * Framework anchors (all from the `indusagi` package — the sibling rebuilt
33
+ * framework this app targets):
34
+ * - `AgentMessage`, `ThinkingLevel`, `AgentTool` ← `indusagi/agent`
35
+ * - `Model`, `Usage`, `KnownProvider` ← `indusagi/ai`
36
+ *
37
+ * The conductor never re-declares these; it composes them.
38
+ */
39
+ import type { AgentMessage, AgentTool, CanUseToolFn, ThinkingLevel } from "indusagi/agent";
40
+ import type { KnownProvider, Model, Usage } from "indusagi/ai";
41
+ import type { PermissionMode } from "../settings.js";
42
+ import type { ApprovalResolver } from "./permissions.js";
43
+ /** Re-exported framework vocabulary that conductor consumers routinely need. */
44
+ export type { AgentMessage, AgentTool, CanUseToolFn, ThinkingLevel, Model, Usage, KnownProvider };
45
+ /** Re-exported permission vocabulary, so conductor consumers get it in one import. */
46
+ export type { PermissionMode, ApprovalResolver };
47
+ /**
48
+ * The closed set of failure categories the conductor can surface.
49
+ *
50
+ * Each is a distinct recovery story, so the kind is a discriminant — not a
51
+ * free-form string:
52
+ * - `model` — the LLM call itself failed (transport, provider, decode).
53
+ * - `tool` — a tool invocation threw or returned a hard error.
54
+ * - `persistence` — writing/reading the on-disk transcript failed.
55
+ * - `aborted` — the caller cancelled the in-flight turn via {@link SessionConductor.abort}.
56
+ * - `overflow` — the context window was exceeded and could not be condensed.
57
+ */
58
+ export type FaultKind = "model" | "tool" | "persistence" | "aborted" | "overflow";
59
+ /**
60
+ * A typed, discriminated failure value emitted on the {@link SessionSignal}
61
+ * stream and attached to faulted states.
62
+ *
63
+ * The `kind` selects the category; `message` is a human-readable summary; the
64
+ * optional `cause` carries the underlying error (or any structured detail) for
65
+ * logging without forcing consumers to parse the message string.
66
+ */
67
+ export interface ConductorFault {
68
+ /** Failure category — the discriminant consumers switch on. */
69
+ readonly kind: FaultKind;
70
+ /** Human-readable, single-line summary of what went wrong. */
71
+ readonly message: string;
72
+ /** Underlying error or structured detail, if any. */
73
+ readonly cause?: unknown;
74
+ }
75
+ /**
76
+ * Construct a {@link ConductorFault}. The single sanctioned way to mint a fault,
77
+ * so the shape stays uniform across every producer.
78
+ *
79
+ * @param kind the failure category
80
+ * @param message a human-readable, single-line summary
81
+ * @param cause optional underlying error or structured detail
82
+ */
83
+ export function conductorFault(kind: FaultKind, message: string, cause?: unknown): ConductorFault {
84
+ return cause === undefined ? { kind, message } : { kind, message, cause };
85
+ }
86
+ /**
87
+ * The product-level event stream the conductor emits to its consumers (the
88
+ * interactive UI, the print/JSON mode, the JSON-RPC link).
89
+ *
90
+ * This is the conductor's **re-emitted surface** — distinct from the framework
91
+ * `AgentEvent` union. The conductor subscribes to the raw framework loop,
92
+ * layers persistence / auto-condense / fault handling on top, and projects the
93
+ * result down to this small, stable set of discriminated signals. Consumers
94
+ * switch on `kind` and never see a framework loop event directly.
95
+ *
96
+ * - `prompt` — the user's turn was committed to the conversation; `text`
97
+ * is the submitted prompt. Emitted the instant the turn is
98
+ * accepted (before the model replies) so a UI can echo the
99
+ * user message immediately rather than waiting for the first
100
+ * assistant token.
101
+ * - `text` — a chunk of assistant answer text streamed in.
102
+ * - `thinking` — a chunk of reasoning/thinking text streamed in.
103
+ * - `tool_start`— a tool invocation began (correlate by `id`).
104
+ * - `tool_update`— a running tool emitted partial progress (correlate by `id`);
105
+ * `name` is the tool name and `details` is the tool's own typed
106
+ * partial-result detail (e.g. the live `◆ Workflow` snapshot).
107
+ * - `tool_end` — a tool invocation finished (`ok` = no error).
108
+ * - `turn_end` — the assistant turn settled; `usage` reports token spend.
109
+ * - `persisted` — the latest node was committed to the transcript (`entryId`).
110
+ * - `compacted` — the transcript WAS condensed (emitted on completion, not at
111
+ * the start). `manual` marks a user-driven `/compact` — a view may then
112
+ * reset its visible transcript — versus mid-turn auto-compaction, where the
113
+ * display must keep the in-flight exchange on screen.
114
+ * - `fault` — a typed {@link ConductorFault} occurred. `transient` marks a
115
+ * fault surfaced purely as an in-turn notice (e.g. a fallback-model swap on
116
+ * provider overload) — the turn keeps running, so a consumer must NOT treat
117
+ * it as the turn's end (must not clear a busy/in-flight indicator on it).
118
+ * - `queue` — the pending-input queue changed; `count` is its new depth.
119
+ * - `idle` — the conductor has no in-flight work and is ready for input.
120
+ */
121
+ export type SessionSignal = {
122
+ readonly kind: "prompt";
123
+ readonly text: string;
124
+ } | {
125
+ readonly kind: "text";
126
+ readonly delta: string;
127
+ } | {
128
+ readonly kind: "thinking";
129
+ readonly delta: string;
130
+ } | {
131
+ readonly kind: "tool_start";
132
+ readonly id: string;
133
+ readonly name: string;
134
+ } | {
135
+ readonly kind: "tool_update";
136
+ readonly id: string;
137
+ readonly name: string;
138
+ readonly details: unknown;
139
+ } | {
140
+ readonly kind: "tool_end";
141
+ readonly id: string;
142
+ readonly ok: boolean;
143
+ } | {
144
+ readonly kind: "turn_end";
145
+ readonly usage: Usage;
146
+ } | {
147
+ readonly kind: "persisted";
148
+ readonly entryId: string;
149
+ } | {
150
+ readonly kind: "compacted";
151
+ readonly manual?: boolean;
152
+ } | {
153
+ readonly kind: "fault";
154
+ readonly fault: ConductorFault;
155
+ readonly transient?: boolean;
156
+ } | {
157
+ readonly kind: "queue";
158
+ readonly count: number;
159
+ } | {
160
+ readonly kind: "idle";
161
+ };
162
+ /** The discriminant literals of {@link SessionSignal}, for filtering/logging. */
163
+ export type SignalKind = SessionSignal["kind"];
164
+ /** Extract a single member of {@link SessionSignal} by its `kind`. */
165
+ export type SignalOf<K extends SignalKind> = Extract<SessionSignal, {
166
+ kind: K;
167
+ }>;
168
+ /** A subscriber callback registered with {@link SessionConductor.subscribe}. */
169
+ export type SignalHandler = (signal: SessionSignal) => void;
170
+ /**
171
+ * The on-disk transcript schema namespace + version.
172
+ *
173
+ * A namespaced string (not a bare integer) so the format is self-describing and
174
+ * can evolve without colliding with any other versioned artifact in the app.
175
+ * This is deliberately the conductor's own vocabulary.
176
+ */
177
+ export const TRANSCRIPT_SCHEMA = "indus/transcript@1" as const;
178
+ /** The literal type of {@link TRANSCRIPT_SCHEMA}. */
179
+ export type TranscriptSchema = typeof TRANSCRIPT_SCHEMA;
180
+ /**
181
+ * The conversational role a {@link TranscriptEntry} node carries.
182
+ *
183
+ * Spans both the LLM-facing turns (`user`/`assistant`/`tool`) and the
184
+ * conductor's own bookkeeping nodes (`system` seed, `condense` markers, and
185
+ * `note` for app-injected context). Kept open at the product layer so the
186
+ * transcript can hold more than the framework's message roles.
187
+ */
188
+ export type TranscriptRole = "user" | "assistant" | "tool" | "system" | "condense" | "note";
189
+ /**
190
+ * A single node in the on-disk transcript tree.
191
+ *
192
+ * The transcript is an append-only **tree**: every node names its `parent`
193
+ * (a root has `parent: null`), and the active leaf is tracked separately in
194
+ * {@link SessionHead}. Branching is moving the head to an earlier node; the next
195
+ * append becomes that node's child. `content` holds the framework
196
+ * {@link AgentMessage} payload so the node round-trips back into the agent loop;
197
+ * `meta` carries optional, non-LLM annotations (labels, condense bookkeeping,
198
+ * model/reasoning markers).
199
+ *
200
+ * Field names are the conductor's own (`parent`, `createdAt`, `meta`) — not the
201
+ * framework's persistence schema.
202
+ */
203
+ export interface TranscriptEntry {
204
+ /** Stable unique node id (e.g. a ULID). */
205
+ readonly id: string;
206
+ /** Parent node id, or `null` for the transcript root. */
207
+ readonly parent: string | null;
208
+ /** Conversational role of this node. */
209
+ readonly role: TranscriptRole;
210
+ /** The framework message payload this node persists. */
211
+ readonly content: AgentMessage;
212
+ /** ISO-8601 creation timestamp. */
213
+ readonly createdAt: string;
214
+ /** Optional, non-LLM annotations keyed by name. */
215
+ readonly meta?: Readonly<Record<string, unknown>>;
216
+ }
217
+ /**
218
+ * The head record of a persisted transcript: which session, and where its
219
+ * active leaf currently points.
220
+ *
221
+ * The `leaf` is the id of the most recently appended (or branched-to) node;
222
+ * walking `parent` links from `leaf` to a root reconstructs the active branch.
223
+ * `null` means an empty transcript (no nodes yet).
224
+ */
225
+ export interface SessionHead {
226
+ /** Stable identifier of the session this transcript belongs to. */
227
+ readonly sessionId: string;
228
+ /** Id of the active leaf node, or `null` for an empty transcript. */
229
+ readonly leaf: string | null;
230
+ /**
231
+ * Cumulative session usage (tokens + cost) persisted alongside the head so
232
+ * resume can restore the running total instead of seeding zero. Optional and
233
+ * absent on legacy transcripts; the store rewrites the head line on every
234
+ * flush, keeping this current with the live tally.
235
+ */
236
+ readonly usage?: Usage;
237
+ }
238
+ /**
239
+ * A lightweight, resolved reference to one model card in the catalog.
240
+ *
241
+ * This is the *display/identity* projection of a framework {@link Model} — the
242
+ * minimum a UI needs to list, label, and select a model without holding the
243
+ * full model object. The matcher produces these; the conductor resolves the
244
+ * chosen one back to a full `Model` when it configures the agent.
245
+ */
246
+ export interface ModelCardRef {
247
+ /** Canonical `"provider/modelId"` identifier (the catalog key). */
248
+ readonly id: string;
249
+ /** Owning provider. */
250
+ readonly provider: KnownProvider | string;
251
+ /** Provider-scoped model id (e.g. `"claude-sonnet-4"`). */
252
+ readonly modelId: string;
253
+ /** Human-readable display name. */
254
+ readonly name: string;
255
+ /** Whether this model exposes a reasoning/thinking budget. */
256
+ readonly reasoning: boolean;
257
+ }
258
+ /**
259
+ * A query against the model catalog/matcher.
260
+ *
261
+ * Resolution is a prioritized candidate pipeline: an explicit `provider`+`modelId`
262
+ * pins a single card; otherwise `pattern` is matched (exact id, `provider/`
263
+ * prefix, then glob/fuzzy) and narrowed by the optional capability filters.
264
+ * All fields are optional so an empty query means "the default candidate".
265
+ */
266
+ export interface MatchQuery {
267
+ /** Free-form selector: an id, an alias, or a glob pattern. */
268
+ readonly pattern?: string;
269
+ /** Restrict candidates to this provider. */
270
+ readonly provider?: KnownProvider | string;
271
+ /** Pin a specific provider-scoped model id (used with {@link provider}). */
272
+ readonly modelId?: string;
273
+ /** Require reasoning/thinking support. */
274
+ readonly reasoning?: boolean;
275
+ /** Require image input support. */
276
+ readonly supportsImageInput?: boolean;
277
+ }
278
+ /**
279
+ * The coarse lifecycle phase of the conductor at a point in time.
280
+ *
281
+ * - `idle` — assembled and ready; no turn in flight.
282
+ * - `streaming` — an assistant turn is producing text/thinking.
283
+ * - `tooling` — a tool invocation is executing mid-turn.
284
+ * - `condensing` — the transcript is being condensed to fit the window.
285
+ * - `faulted` — the last turn ended in a {@link ConductorFault}.
286
+ */
287
+ export type ConductorPhase = "idle" | "streaming" | "tooling" | "condensing" | "faulted";
288
+ /**
289
+ * An immutable snapshot of the conductor's observable state.
290
+ *
291
+ * Returned by {@link SessionConductor.snapshot} and resolved by
292
+ * {@link SessionConductor.submit}. It is a value, not a live view: every field
293
+ * is read-only and the object reflects the instant it was taken. Re-read with a
294
+ * fresh `snapshot()` to observe later changes.
295
+ */
296
+ export interface ConductorState {
297
+ /** Coarse lifecycle phase at snapshot time. */
298
+ readonly phase: ConductorPhase;
299
+ /** The active transcript head (session id + current leaf). */
300
+ readonly head: SessionHead;
301
+ /** Cumulative token/cost spend across the session so far. */
302
+ readonly usage: Usage;
303
+ /**
304
+ * Tokens occupying the model's context window as of the most recent turn —
305
+ * the last assistant turn's reported usage, NOT the cumulative session spend.
306
+ * This is what the footer's `ctx:%` divides by the context window;
307
+ * {@link usage}.totalTokens grows unbounded across turns and would inflate it.
308
+ */
309
+ readonly contextTokens: number;
310
+ /** Canonical id of the model currently bound to the session. */
311
+ readonly modelId: string;
312
+ /** The fault from the most recent turn, when {@link phase} is `"faulted"`. */
313
+ readonly fault?: ConductorFault;
314
+ }
315
+ /**
316
+ * How a queued input rejoins the conversation once the active turn settles.
317
+ *
318
+ * - `steer` — interrupt-style input meant to redirect the agent; drained
319
+ * ahead of plain follow-ups.
320
+ * - `followUp` — input that simply waits its turn after the current one ends.
321
+ *
322
+ * The conductor enqueues input under one of these modes when {@link SessionConductor.submit}
323
+ * is called while a turn is in flight, then drains the queue in order.
324
+ */
325
+ export type QueueMode = "steer" | "followUp";
326
+ /**
327
+ * One entry in the conductor's pending-input queue: the {@link QueueMode} it was
328
+ * filed under and the raw user `text`. Surfaced by
329
+ * {@link SessionConductor.pendingInputs} so a UI can render what is waiting.
330
+ */
331
+ export interface QueuedInput {
332
+ /** How this input will rejoin the conversation when drained. */
333
+ readonly mode: QueueMode;
334
+ /** The raw user message text held for a later turn. */
335
+ readonly text: string;
336
+ }
337
+ /**
338
+ * A point-in-time tally of the active session: message counts by role, tool
339
+ * activity, cumulative token spend, and total cost. Computed by
340
+ * {@link SessionConductor.stats} from the live message list plus the running
341
+ * usage carried on {@link ConductorState}.
342
+ */
343
+ export interface SessionStats {
344
+ /** Identifier of the session these figures describe. */
345
+ readonly sessionId: string;
346
+ /** Number of user-role messages in the active branch. */
347
+ readonly userMessages: number;
348
+ /** Number of assistant-role messages in the active branch. */
349
+ readonly assistantMessages: number;
350
+ /** Number of tool invocations the assistant issued. */
351
+ readonly toolCalls: number;
352
+ /** Number of tool-result messages produced in reply. */
353
+ readonly toolResults: number;
354
+ /** Total message count across all roles. */
355
+ readonly totalMessages: number;
356
+ /** Cumulative token spend, broken out by category and totalled. */
357
+ readonly tokens: {
358
+ readonly input: number;
359
+ readonly output: number;
360
+ readonly cacheRead: number;
361
+ readonly cacheWrite: number;
362
+ readonly total: number;
363
+ };
364
+ /** Cumulative monetary cost of the session so far. */
365
+ readonly cost: number;
366
+ }
367
+ /** Options for {@link SessionConductor.executeBash}. */
368
+ export interface ExecuteBashOptions {
369
+ /**
370
+ * When `true`, the command's output is *not* recorded as a transcript note,
371
+ * so it never re-enters the agent's context. Defaults to `false`.
372
+ */
373
+ readonly excludeFromContext?: boolean;
374
+ }
375
+ /** The settled result of {@link SessionConductor.executeBash}. */
376
+ export interface BashOutcome {
377
+ /** Combined stdout + stderr of the command. */
378
+ readonly output: string;
379
+ /** Process exit code (`0` on success; non-zero, or `1` on a thrown error). */
380
+ readonly exitCode: number;
381
+ }
382
+ /**
383
+ * The minimal file-checkpoint surface the conductor drives for rewind (#24).
384
+ *
385
+ * The product mints a concrete `CheckpointStore` (in `boot/runners/checkpoint.ts`),
386
+ * injects it into the deck's `ctx.framework` bag under the `'checkpoint'` key so
387
+ * the framework's write/edit tools record pre-mutation file content against the
388
+ * active transcript node, and ALSO hands it to the conductor as this port. The
389
+ * conductor pins the active node id as its head advances ({@link setActiveNodeId})
390
+ * so a turn's edits key to the node that was active before the turn, and exposes
391
+ * {@link restore}/{@link hasSnapshot} so the tree picker can roll the working tree
392
+ * back when navigating to an earlier node.
393
+ *
394
+ * Declared as a tiny structural port (not the concrete store) so the conductor
395
+ * stays free of any boot-layer import — the product's store satisfies it by shape.
396
+ */
397
+ export interface CheckpointPort {
398
+ /**
399
+ * Pin the transcript node subsequent file snapshots are filed under. Called by
400
+ * the conductor as its head advances (at turn start) so a turn's edits key to
401
+ * the node active before the turn ran.
402
+ *
403
+ * @param id the active transcript node id, or `null` to fall back to the root
404
+ */
405
+ setActiveNodeId(id: string | null): void;
406
+ /** Whether a node has ANY recorded file snapshot (the picker's restore gate). */
407
+ hasSnapshot(nodeId: string): boolean;
408
+ /**
409
+ * Roll the working tree back to a node's recorded state, rewriting each tracked
410
+ * file to its pre-mutation content (deleting files recorded as absent). A safe
411
+ * no-op when the node has no snapshot.
412
+ *
413
+ * @param nodeId the transcript node whose file state to restore to
414
+ * @returns the absolute paths that were written or deleted
415
+ */
416
+ restore(nodeId: string): string[];
417
+ }
418
+ /**
419
+ * Options that configure a {@link SessionConductor} at assembly time.
420
+ *
421
+ * Only {@link modelId} is required; everything else has a sensible default
422
+ * resolved by the conductor factory. The shape is intentionally small — richer
423
+ * wiring (MCP, memory, provider routing) is attached by the factory, not passed
424
+ * through this surface.
425
+ */
426
+ export interface SessionConductorOptions {
427
+ /** Canonical id of the model to bind the session to. */
428
+ readonly modelId: string;
429
+ /** Initial system prompt seeding the conversation. */
430
+ readonly system?: string;
431
+ /** Tools made available to the agent for this session. */
432
+ readonly tools?: AgentTool[];
433
+ /** Initial reasoning effort for models that support it. */
434
+ readonly thinking?: ThinkingLevel;
435
+ /**
436
+ * Canonical id of a model to fall back to when the bound model is overloaded
437
+ * (HTTP 529 / "overloaded") mid-turn (`--fallback-model`). When set, an
438
+ * overload that exhausts the transient-retry budget swaps to this model once
439
+ * per turn and retries instead of surfacing a terminal fault. Absent disables
440
+ * the swap entirely (behavior-preserving default).
441
+ */
442
+ readonly fallbackModelId?: string;
443
+ /**
444
+ * Per-provider indus-gateway base URLs ("server mode"), keyed by provider slug
445
+ * (e.g. `{ minimax: "http://host/gateway/minimax", sarvam: "…/gateway/sarvam" }`).
446
+ * Set by the session runner for every gateway-eligible provider the user has no
447
+ * local key for but holds a valid server token. At EVERY model bind (including a
448
+ * runtime `/model` switch) the conductor looks up the BOUND model's provider in
449
+ * this map and, when present, binds a CLONE of the framework model with its
450
+ * `baseUrl` swapped to that URL — so any server-tier model routes through the
451
+ * quota-enforcing server while the session token (via {@link getApiKey})
452
+ * authenticates it. A provider absent from the map keeps the direct path.
453
+ */
454
+ readonly gatewayBaseUrls?: Record<string, string>;
455
+ /** Working directory the session is scoped to (defaults to process cwd). */
456
+ readonly workspace?: string;
457
+ /**
458
+ * Directory to persist the transcript into. When set, the conductor backs its
459
+ * {@link TranscriptStore} with a filesystem backend rooted here (one
460
+ * `<sessionId>.ndjson` per session) so the conversation survives the process
461
+ * and can be resumed. Absent (or when a `store` dep is injected) keeps the
462
+ * default in-memory store — nothing is written to disk.
463
+ */
464
+ readonly sessionsDir?: string;
465
+ /** Condense the transcript automatically when it nears the window (default on). */
466
+ readonly autoCompact?: boolean;
467
+ /**
468
+ * Resolve the credential for a provider on each call. Threaded to the framework
469
+ * `Agent`, which calls it per request so short-lived OAuth access tokens (e.g.
470
+ * `openai-codex`) can be refreshed and providers with no env-var mapping still
471
+ * authenticate. Returning `undefined` lets the framework fall back to its own
472
+ * environment lookup. May be sync or async.
473
+ */
474
+ readonly getApiKey?: (provider: string) => Promise<string | undefined> | string | undefined;
475
+ /**
476
+ * The hard per-tool permission gate, threaded straight to the framework `Agent`.
477
+ * The framework awaits it on the validated arguments immediately before each
478
+ * tool runs and either proceeds (optionally with substituted input) or
479
+ * short-circuits to an `isError` tool result.
480
+ *
481
+ * Supplied as a **factory** `(currentMode, requestApproval?) => CanUseToolFn`:
482
+ * the conductor calls it once with a getter onto its OWN live permission mode,
483
+ * so the gate it returns reads `permissionMode()` live — a
484
+ * {@link SessionConductor.setPermissionMode} retargets later tool calls with no
485
+ * agent rebuild. (A caller that does not care about the live mode can simply
486
+ * ignore the getter and close over a fixed gate.)
487
+ *
488
+ * The OPTIONAL second argument is a stable {@link ApprovalResolver} delegate the
489
+ * conductor owns: it forwards to whatever resolver was installed via
490
+ * {@link SessionConductor.setApprovalResolver} at call time (and denies when none
491
+ * is installed). An interactive front-end can therefore wire its approval overlay
492
+ * AFTER the conductor (and its gate) are built — the factory just closes over the
493
+ * delegate. A factory that ignores it keeps today's behavior.
494
+ *
495
+ * Optional everywhere: omit it and the framework allows every tool (today's
496
+ * allow-all behavior).
497
+ */
498
+ readonly canUseTool?: (currentMode: () => PermissionMode, requestApproval?: ApprovalResolver) => CanUseToolFn;
499
+ /**
500
+ * The permission mode the session opens in. Seeds {@link SessionConductor.permissionMode};
501
+ * defaults to `"default"` when absent. The mode is consulted live by the
502
+ * {@link canUseTool} gate, so a later {@link SessionConductor.setPermissionMode}
503
+ * changes subsequent tool calls without rebuilding the gate.
504
+ */
505
+ readonly permissionMode?: PermissionMode;
506
+ /**
507
+ * Directory the approved plan-mode plan is persisted into. When the model calls
508
+ * `exit_plan_mode` and the user approves leaving plan mode, the conductor writes
509
+ * the plan as a slug-named markdown file under `<plansDir>/plans/`. Absent keeps
510
+ * the handshake (mode flip + context injection) but skips the disk write —
511
+ * tests and headless probes can run the round-trip without a filesystem.
512
+ */
513
+ readonly plansDir?: string;
514
+ /**
515
+ * The per-session file-checkpoint store for rewind (#24), or `undefined` to run
516
+ * without code checkpointing. When present, the conductor pins the active
517
+ * transcript node on it (the head leaf at turn start) so a turn's file edits key
518
+ * to the node that was active before the turn, and {@link SessionConductor.restoreCode}
519
+ * delegates to it so the tree picker can revert the working tree.
520
+ */
521
+ readonly checkpoint?: CheckpointPort;
522
+ }
523
+ /**
524
+ * What a manual {@link SessionConductor.condense} run amounted to — the honest
525
+ * completion vocabulary `/compact` reports from (see the method doc).
526
+ */
527
+ export type CondenseOutcome = "condensed" | "nothing" | "cancelled" | "failed" | "busy";
528
+ /**
529
+ * The conductor of a single coding-agent session.
530
+ *
531
+ * It owns the framework `Agent`, threads persistence and auto-condense through
532
+ * the turn loop, and exposes a small product API: submit input, subscribe to
533
+ * the {@link SessionSignal} stream, abort the in-flight turn, read an immutable
534
+ * {@link ConductorState} snapshot, resume a persisted session, and optionally
535
+ * rotate the active model. This is the surface all three run modes drive.
536
+ */
537
+ export interface SessionConductor {
538
+ /**
539
+ * Submit user input as a new turn and run the agent to settle.
540
+ *
541
+ * Streams {@link SessionSignal}s to subscribers as the turn progresses and
542
+ * resolves to the immutable {@link ConductorState} once the turn settles
543
+ * (success or fault).
544
+ *
545
+ * When a turn is already in flight the input is **not** dropped: it is handed
546
+ * to {@link enqueue} and run automatically as a later turn once the current one
547
+ * settles. In that case `submit` resolves immediately with the current
548
+ * snapshot rather than waiting for the queued turn.
549
+ *
550
+ * @param input the user message text for this turn
551
+ */
552
+ submit(input: string): Promise<ConductorState>;
553
+ /**
554
+ * Queue an input to run as a future turn. Used directly, or reached via
555
+ * {@link submit} when the conductor is busy. Queued items drain in order after
556
+ * the active turn settles, each running as its own turn. Emits a
557
+ * `{ kind: "queue" }` signal so a UI can reflect the new depth.
558
+ *
559
+ * @param input the user message text to hold for a later turn
560
+ * @param mode how it rejoins the conversation when drained (default `"followUp"`)
561
+ */
562
+ enqueue(input: string, mode?: QueueMode): void;
563
+ /** How many inputs are currently waiting in the pending-input queue. */
564
+ pendingCount(): number;
565
+ /** A read-only view of the queued inputs, oldest first. */
566
+ pendingInputs(): readonly QueuedInput[];
567
+ /** Discard every queued input. Emits a `{ kind: "queue" }` signal. */
568
+ clearQueue(): void;
569
+ /**
570
+ * Promote the NEWEST queued input to run immediately: the in-flight turn (if
571
+ * any) is aborted — its work stops — while the rest of the queue is kept, and
572
+ * the promoted input runs as the very next turn. The user-facing "run my new
573
+ * message NOW" affordance for a long/stuck turn (issue #19), distinct from
574
+ * {@link abort} (which stops everything and clears the queue). Returns `false`
575
+ * when no input is queued.
576
+ */
577
+ steerNow(): boolean;
578
+ /**
579
+ * Remove and return the text of the most-recently queued input, or `undefined`
580
+ * when the queue is empty. Lets a UI pop the last entry back into its prompt.
581
+ */
582
+ dequeueLast(): string | undefined;
583
+ /**
584
+ * The live transcript messages for the active branch.
585
+ *
586
+ * A read-through onto the wrapped agent's running message list — what the
587
+ * interactive UI renders as the conversation. The returned array is the
588
+ * current contents at call time; re-read to observe later turns.
589
+ */
590
+ messages(): readonly AgentMessage[];
591
+ /**
592
+ * The full framework {@link Model} object currently bound to the session, or
593
+ * `undefined` when none could be resolved. Tracks the active selection across
594
+ * {@link selectModel}/{@link cycleModel} changes.
595
+ */
596
+ model(): Model<any> | undefined;
597
+ /** Whether a turn is currently in flight (guards re-entrant submit). */
598
+ isBusy(): boolean;
599
+ /**
600
+ * The model catalog entries a picker lists, best-first. Derived from the
601
+ * configured model matcher; returns `[]` when no matcher is wired in.
602
+ */
603
+ availableModels(): ModelCardRef[];
604
+ /**
605
+ * Bind a model by canonical id for subsequent turns. The companion of
606
+ * {@link cycleModel}; both route through the same selection path.
607
+ *
608
+ * @param id canonical id of the model to switch to
609
+ */
610
+ selectModel(id: string): void;
611
+ /**
612
+ * Replace the server-tier gateway routing map and immediately re-bind the
613
+ * currently selected model against it (without changing which model is
614
+ * selected). Lets an interactive mid-session sign-in (see `/login` ->
615
+ * "Indus Server") take effect right away: the gateway base-url map is
616
+ * otherwise frozen at conductor construction, so a login that happens after
617
+ * boot would silently never route the bound model through the gateway even
618
+ * though the per-request key resolver already started vending the fresh
619
+ * session token as the provider key.
620
+ *
621
+ * @param map provider id -> gateway base URL, as produced by
622
+ * `resolveServerGatewayUrls` for the current vault/token state
623
+ */
624
+ updateGatewayBaseUrls(map: Record<string, string>): void;
625
+ /**
626
+ * Replace the agent's tool deck for subsequent turns.
627
+ *
628
+ * Used by `/mcp` to inject the tools of freshly-connected MCP servers into the
629
+ * live session (and to drop them again on disconnect). The conductor merges the
630
+ * passed list with its own seed deck (the built-in tools the session was
631
+ * assembled with), so callers pass only the *extra* tools to add — never the
632
+ * built-ins, which are preserved automatically. Pass `[]` to clear the extras
633
+ * and fall back to the seed deck alone.
634
+ *
635
+ * @param tools the additional tools to layer over the seed deck
636
+ */
637
+ registerTools(tools: AgentTool[]): void;
638
+ /**
639
+ * Manually run the transcript-condense path (`/compact`) and report what
640
+ * happened, so the caller can give honest feedback instead of announcing
641
+ * "condensed" regardless:
642
+ * - `"condensed"` — the branch shrank and was rebound (emits `compacted`).
643
+ * - `"nothing"` — nothing older to fold (single-turn session, or already
644
+ * compacted); the transcript is untouched.
645
+ * - `"cancelled"` — {@link cancelCondense} fired mid-run; the digest was
646
+ * discarded and the transcript is untouched.
647
+ * - `"failed"` — the condense hook threw; a typed fault was emitted.
648
+ * - `"busy"` — a turn is in flight; compact after it settles (or abort
649
+ * it first).
650
+ * While the condense runs, {@link submit} queues instead of racing it, and the
651
+ * queue drains once the condense settles.
652
+ */
653
+ condense(): Promise<CondenseOutcome>;
654
+ /**
655
+ * Cancel an in-flight manual {@link condense} (the `/compact` Esc affordance).
656
+ * The summarizer's result is discarded and the transcript stays untouched; a
657
+ * no-op when no manual condense is running.
658
+ */
659
+ cancelCondense(): void;
660
+ /**
661
+ * Branch the transcript from a prior node. A new branch is opened whose parent
662
+ * is `entryId`; the agent's message list is rebound to that branch's root→leaf
663
+ * path. The conductor's head advances onto the chosen node.
664
+ *
665
+ * @param entryId the transcript node to branch from
666
+ */
667
+ fork(entryId: string): Promise<void>;
668
+ /**
669
+ * Move the active leaf to `nodeId`, rebuild that branch's root→leaf path, and
670
+ * rebind the agent's message list to it. Used to walk between existing
671
+ * branches without forking a new one.
672
+ *
673
+ * @param nodeId the transcript node to make the active leaf
674
+ */
675
+ navigateTree(nodeId: string): Promise<void>;
676
+ /**
677
+ * Roll the working tree back to a transcript node's file-checkpoint state
678
+ * (rewind, #24). Reverts every file the node tracked to its pre-mutation content
679
+ * (deleting files that were absent at that point). Additive and code-only: it
680
+ * does NOT move the conversation head — pair it with {@link navigateTree}/{@link fork}
681
+ * for a combined "restore code and conversation". A safe no-op when no checkpoint
682
+ * store is wired or the node has no recorded snapshot.
683
+ *
684
+ * @param nodeId the transcript node whose file state to restore to
685
+ * @returns the absolute paths that were restored (written or deleted)
686
+ */
687
+ restoreCode(nodeId: string): Promise<string[]>;
688
+ /**
689
+ * Whether the tree picker should offer "restore code" for a node — i.e. whether
690
+ * the node has any recorded file-checkpoint snapshot. `false` when no checkpoint
691
+ * store is wired or the node never mutated files, so the picker's restore option
692
+ * is a safe no-op there.
693
+ *
694
+ * @param nodeId the transcript node to test
695
+ */
696
+ codeRestoreInfo(nodeId: string): Promise<{
697
+ readonly canRestore: boolean;
698
+ }>;
699
+ /**
700
+ * Run a shell command in the session workspace, returning its combined
701
+ * stdout+stderr and exit code. Unless `opts.excludeFromContext` is set, the
702
+ * output is recorded as a transcript note so it re-enters the agent's context.
703
+ * Never throws: a spawn/exec failure resolves to a non-zero {@link BashOutcome}.
704
+ *
705
+ * @param command the shell command to execute
706
+ * @param opts execution options
707
+ */
708
+ executeBash(command: string, opts?: ExecuteBashOptions): Promise<BashOutcome>;
709
+ /** A point-in-time {@link SessionStats} tally for the active session. */
710
+ stats(): SessionStats;
711
+ /**
712
+ * Render the session's cumulative cost + token usage as a human-readable,
713
+ * multi-line report. Drives the `/cost` slash command without the caller
714
+ * having to format the {@link SessionStats} figures itself.
715
+ */
716
+ costReport(): string;
717
+ /** The reasoning effort currently applied to the session. */
718
+ thinkingLevel(): ThinkingLevel;
719
+ /**
720
+ * Set the reasoning effort for subsequent turns. Applied to the agent when it
721
+ * exposes a setter; otherwise stored and applied on the next model bind.
722
+ *
723
+ * @param level the reasoning effort to apply
724
+ */
725
+ setThinkingLevel(level: ThinkingLevel): void;
726
+ /**
727
+ * Advance the reasoning effort to the next level in the cycle, applying it, and
728
+ * return the newly-selected level.
729
+ */
730
+ cycleThinkingLevel(): ThinkingLevel;
731
+ /**
732
+ * The permission mode currently in effect. The live `canUseTool` gate reads
733
+ * this on every tool call, so the value reflects the most recent
734
+ * {@link setPermissionMode}.
735
+ */
736
+ permissionMode(): PermissionMode;
737
+ /**
738
+ * Switch the permission mode for subsequent tool calls. The gate consults the
739
+ * mode live (via a getter), so this takes effect on the next tool call with no
740
+ * agent rebuild. A no-op-equivalent when no gate was wired (the conductor still
741
+ * tracks the mode for the UI).
742
+ *
743
+ * @param mode the permission mode to apply
744
+ */
745
+ setPermissionMode(mode: PermissionMode): void;
746
+ /**
747
+ * Install (or clear) the host approval resolver an `ask` decision routes to.
748
+ *
749
+ * The `canUseTool` gate consults a STABLE delegate the conductor owns; this
750
+ * method swaps the resolver behind that delegate, so an interactive front-end
751
+ * can wire its approval overlay AFTER the conductor (and its gate) are built —
752
+ * the exact post-mount install the React console needs. Passing `undefined`
753
+ * clears it (an `ask` then deterministically denies, the non-interactive
754
+ * default). A no-op-equivalent when no gate was wired; the resolver is simply
755
+ * never consulted.
756
+ *
757
+ * @param resolver the resolver to consult on an `ask`, or `undefined` to clear
758
+ */
759
+ setApprovalResolver(resolver: ApprovalResolver | undefined): void;
760
+ /**
761
+ * Toggle plan mode on or off.
762
+ *
763
+ * Entering plan mode (`true`) captures the current mode as the pre-plan mode and
764
+ * switches to `"plan"` (read-only — the gate blocks every mutating tool).
765
+ * Leaving (`false`) restores the captured pre-plan mode (or `"default"` when none
766
+ * was captured). Idempotent: toggling on while already in plan mode is a no-op,
767
+ * and toggling off when not in plan mode restores/keeps `"default"`. Drives the
768
+ * `/plan` command and the Shift+Tab toggle, and is the same path the conductor's
769
+ * own `enter_plan_mode` / approved `exit_plan_mode` handshake uses.
770
+ *
771
+ * @param on `true` to enter plan mode, `false` to leave it
772
+ * @returns the permission mode in effect after the toggle
773
+ */
774
+ togglePlanMode(on: boolean): PermissionMode;
775
+ /**
776
+ * Advance the permission mode to the NEXT mode in the fixed cycle and return the
777
+ * new mode. The order is `default → acceptEdits → plan → bypass → (wrap)
778
+ * default`; the `"bypassPermissions"` alias is folded to `"bypass"` when reading
779
+ * the current mode so the cycle is stable.
780
+ *
781
+ * Built on top of {@link setPermissionMode}, so the live `canUseTool` gate (which
782
+ * reads {@link permissionMode} on every call) picks the new mode up immediately
783
+ * with no agent rebuild. Plan bookkeeping is preserved: ENTERING `"plan"` captures
784
+ * the pre-plan mode exactly as {@link togglePlanMode} does, so a later round-trip
785
+ * restores the prior mode; LEAVING `"plan"` (cycling `plan → bypass`) is a plain
786
+ * mode change — it does NOT run the `exit_plan_mode` approval handshake, since a
787
+ * manual cycle is not a plan exit. Drives the Shift+Tab cycle; {@link togglePlanMode}
788
+ * remains the path `/plan` uses.
789
+ *
790
+ * @returns the permission mode in effect after the advance
791
+ */
792
+ cyclePermissionMode(): PermissionMode;
793
+ /**
794
+ * The mode captured when plan mode was last entered, restored on exit — or
795
+ * `undefined` when not currently in (or paused from) plan mode. Exposed so a UI
796
+ * (and the round-trip tests) can observe the Enter/Exit pairing.
797
+ */
798
+ prePlanMode(): PermissionMode | undefined;
799
+ /** The human-readable session name, or `undefined` when none is set. */
800
+ sessionName(): string | undefined;
801
+ /**
802
+ * Assign a human-readable name to the session.
803
+ *
804
+ * @param name the display name to store
805
+ */
806
+ setSessionName(name: string): void;
807
+ /**
808
+ * Register a handler for the {@link SessionSignal} stream.
809
+ *
810
+ * @param handler invoked for every emitted signal
811
+ * @returns an unsubscribe function that removes the handler
812
+ */
813
+ subscribe(handler: SignalHandler): () => void;
814
+ /** Cancel the in-flight turn, if any; emits an `aborted` fault signal. */
815
+ abort(): void;
816
+ /** Read an immutable snapshot of the current {@link ConductorState}. */
817
+ snapshot(): ConductorState;
818
+ /**
819
+ * Restore a previously persisted session, replacing the current transcript
820
+ * and rebinding the agent to the restored model/leaf.
821
+ *
822
+ * @param sessionId the persisted session to resume
823
+ */
824
+ resume(sessionId: string): Promise<void>;
825
+ /**
826
+ * Abandon the current conversation and start a fresh, empty session.
827
+ *
828
+ * Drops the agent's message history, opens a new session id (so later turns
829
+ * persist separately, leaving the prior transcript intact on disk), zeroes the
830
+ * usage tally, clears the pending-input queue and session name, and settles to
831
+ * `idle`. Emits an `idle` signal so a subscribed UI re-renders the now-empty
832
+ * conversation. This is what `/clear` (and `/new`) drive.
833
+ */
834
+ newSession(): Promise<void>;
835
+ /**
836
+ * Rotate the active model for subsequent turns. Optional: not every assembly
837
+ * supports mid-session model changes.
838
+ *
839
+ * @param id canonical id of the model to switch to
840
+ */
841
+ cycleModel?(id: string): void;
842
+ }