@codeam/shared 2.54.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.
@@ -0,0 +1,1117 @@
1
+ /**
2
+ * Protocol-level types for TUI chrome steps and interactive selectors.
3
+ *
4
+ * Agent-AGNOSTIC: the *shapes* below are part of the chunk-protocol contract
5
+ * between the CLI/IDE clients and the mobile app. The *parsers* that recognize
6
+ * chrome lines and selectors live next to each agent's runtime strategy
7
+ * (e.g. apps/cli/src/agents/claude/parsing.ts) because the glyphs and
8
+ * conventions vary per agent.
9
+ */
10
+ type ChromeToolType = 'read' | 'edit' | 'bash' | 'search' | 'thinking' | 'other';
11
+ interface ChromeStep {
12
+ tool: ChromeToolType;
13
+ label: string;
14
+ detail?: string;
15
+ status: 'running' | 'done';
16
+ }
17
+ interface SelectPrompt {
18
+ question: string;
19
+ options: string[];
20
+ optionDescriptions: string[];
21
+ /** 0-based index of the highlighted item (always 0 for numbered selectors). */
22
+ currentIndex: number;
23
+ }
24
+
25
+ /**
26
+ * Shared wire / lifecycle constants. The values here are bundled
27
+ * into the CLI + VS Code extension at build time via tsup / esbuild
28
+ * and mirrored in `apps/jetbrains-plugin/.../protocol/Constants.kt`
29
+ * since Kotlin can't import an npm package.
30
+ *
31
+ * If you change one of these values, also update the Kotlin mirror.
32
+ */
33
+ /**
34
+ * Discriminated chunk-protocol version sent as the
35
+ * `X-Codeam-Protocol-Version` header on every authed request. The
36
+ * backend uses this to opt into legacy translations or to reject
37
+ * with 426 when the client is too far behind. Bumped in lockstep
38
+ * with chunk-shape changes (e.g. when the `chrome_steps` chunk
39
+ * type is added).
40
+ */
41
+ declare const PROTOCOL_VERSION: "2.0.0";
42
+ /**
43
+ * The VS Code AgentOutputMonitor's loopback HTTP server bound to
44
+ * 127.0.0.1 on this port — the observer JS in the IDE renderer
45
+ * uses it to round-trip captured chat content back into the
46
+ * extension host. The port is intentionally fixed (rather than
47
+ * `listen(0)`) so the observer script can be a static constant
48
+ * rather than dynamically rewriting itself per session.
49
+ *
50
+ * Multi-window collision is solved by listen(0) per-window in the
51
+ * monitor (see #103); this default is still the documented
52
+ * starting port for tooling that needs to probe whether a CodeAgent
53
+ * Mobile session is active locally.
54
+ */
55
+ declare const OBSERVER_BRIDGE_PORT = 47832;
56
+ /**
57
+ * Default plugin → backend heartbeat interval. User-configurable
58
+ * via `codeagent-mobile.heartbeatIntervalMs` on VS Code and
59
+ * `heartbeatIntervalMs` in SettingsService.kt's @State on JetBrains.
60
+ * Mirrors the value the apps/api side uses to flip the paired
61
+ * session to offline.
62
+ */
63
+ declare const HEARTBEAT_INTERVAL_MS_DEFAULT = 30000;
64
+ /**
65
+ * SSE + polling reconnect cap. Vercel's serverless functions close
66
+ * SSE connections after ~25 s by default; the client uses 35 s as
67
+ * its overall socket timeout to leave a beat for graceful close.
68
+ */
69
+ declare const SSE_SOCKET_TIMEOUT_MS = 35000;
70
+
71
+ /**
72
+ * Render raw PTY bytes into an array of screen lines using a simplified
73
+ * virtual terminal. Handles cursor movements (A/B/C/D/G/H), erase (J/K),
74
+ * alternate-screen (?1049h), carriage return, and LF.
75
+ *
76
+ * This is the authoritative implementation used by both codeam-cli (PTY
77
+ * output) and the VS Code extension (shell-integration output) so that
78
+ * the mobile/web client sees identical chunks regardless of surface.
79
+ */
80
+ declare function renderToLines(raw: string): string[];
81
+
82
+ /**
83
+ * The command envelope clients receive from the backend relay — both from
84
+ * the `commands` SSE frames on `/api/commands/pending/stream` and from the
85
+ * `GET /api/commands/pending` polling fallback. One schema, shared, so the
86
+ * VS Code extension (and eventually the CLI) stop blind-casting
87
+ * `Record<string, unknown>` into this shape.
88
+ */
89
+ interface RemoteCommand {
90
+ id: string;
91
+ sessionId: string;
92
+ pluginId: string;
93
+ type: string;
94
+ payload: Record<string, unknown>;
95
+ status: string;
96
+ createdAt: number;
97
+ }
98
+ /**
99
+ * Validate a raw (already JSON-parsed) value into a `RemoteCommand`.
100
+ * Returns `null` — never throws — on a malformed envelope so callers can
101
+ * log-and-skip the single bad command without dropping the whole batch.
102
+ */
103
+ declare function toRemoteCommand(raw: unknown): RemoteCommand | null;
104
+
105
+ interface ModelPricing {
106
+ input: number;
107
+ output: number;
108
+ cacheRead: number;
109
+ cacheWrite: number;
110
+ }
111
+ declare const MODEL_PRICING: Record<string, ModelPricing>;
112
+ declare const MODEL_CONTEXT_WINDOW: Record<string, number>;
113
+ /** True when the model id resolves to a real MODEL_PRICING row (i.e. getPricing
114
+ * will NOT be guessing via the unknown-model fallback). */
115
+ declare function isKnownModel(model: string): boolean;
116
+ /**
117
+ * Resolve pricing by longest matching prefix. Unknown models fall back to
118
+ * claude-sonnet-4 rates — a guess, kept because existing callers do
119
+ * unconditional arithmetic on the result. Callers that need to distinguish
120
+ * real pricing from the fallback must check `isKnownModel(model)` first.
121
+ */
122
+ declare function getPricing(model: string): ModelPricing;
123
+ declare function getContextWindow(model: string | null): number;
124
+
125
+ type AgentId = 'claude' | 'codex' | 'copilot' | 'coderabbit' | 'cursor' | 'aider' | 'gemini';
126
+ type AgentAuthKind = 'oauth_token' | 'api_key' | 'setup_token';
127
+ /**
128
+ * The agent kinds Headroom (the token-compression proxy) can actually
129
+ * wrap/route — the exact subcommands `headroom init --global <kind>`
130
+ * accepts. NOT an alias of {@link AgentId}: cursor / gemini / aider run
131
+ * native (Headroom disabled) because `headroom init` has no recipe that
132
+ * routes them.
133
+ */
134
+ type HeadroomKind = 'claude' | 'codex' | 'copilot';
135
+ interface AgentAuth {
136
+ kind: AgentAuthKind;
137
+ /** API key plain, or JSON serialized for oauth_token. Interpretation depends on the agent. */
138
+ value: string;
139
+ }
140
+ interface AgentModel {
141
+ id: string;
142
+ label: string;
143
+ contextWindow: number;
144
+ pricing?: {
145
+ inputPerM: number;
146
+ outputPerM: number;
147
+ cacheReadPerM?: number;
148
+ cacheCreationPerM?: number;
149
+ };
150
+ }
151
+ interface NormalizedMessage {
152
+ id: string;
153
+ role: 'user' | 'agent' | 'system';
154
+ text: string;
155
+ timestamp: string;
156
+ modelId?: string;
157
+ usage?: {
158
+ input: number;
159
+ output: number;
160
+ cacheRead?: number;
161
+ cacheCreation?: number;
162
+ };
163
+ }
164
+ interface AgentMetadata {
165
+ id: AgentId;
166
+ displayName: string;
167
+ binaryName: string;
168
+ enabled: boolean;
169
+ supportedAuthKinds: AgentAuthKind[];
170
+ preferredAuthKind: AgentAuthKind;
171
+ /**
172
+ * Whether Headroom can wrap/route this agent (claude / codex / copilot
173
+ * only). Canonical truth previously scattered across two prefix-matching
174
+ * predicates: `isHeadroomSupportedAgent` (CLI `host-agent.ts`) and
175
+ * `isHeadroomWrappableAgent` (api-v2 `codespaces/headroom.ts`). When
176
+ * false the agent MUST run native — wrapping an unsupported agent
177
+ * mislaunches it as Claude (the 2026-06 Cursor incident).
178
+ */
179
+ headroomWrappable: boolean;
180
+ /**
181
+ * The `headroom init --global <kind>` subcommand for this agent.
182
+ * Present iff {@link headroomWrappable} is true.
183
+ */
184
+ headroomKind?: HeadroomKind;
185
+ /**
186
+ * Whether the agent runs over ACP (Agent Client Protocol) in the CLI —
187
+ * mirrors which agents have an entry in the CLI's ACP adapter registry
188
+ * (`apps/cli/src/agents/acp/adapters.ts`). `false` ⇒ legacy PTY runtime.
189
+ */
190
+ acp: boolean;
191
+ /**
192
+ * `true` for agents that authorize via the OAuth DEVICE-code flow
193
+ * (Codex, Cursor) rather than the redirect/paste flow (Claude, Gemini).
194
+ * Mirrors the mobile agent catalog (`apps/mobile/src/lib/agentCatalog.ts`).
195
+ */
196
+ deviceFlow?: boolean;
197
+ /**
198
+ * Whether the device-code flow surfaces `userCode` to the user as an
199
+ * "enter this code" string. `true` for Codex (a real human-typed
200
+ * user_code shown on the OpenAI page). `false` for Cursor — there
201
+ * `userCode` is the secret PKCE verifier used only for the poll
202
+ * echo-back; rendering it would leak the secret. Only meaningful when
203
+ * {@link deviceFlow} is `true`.
204
+ */
205
+ showsUserCode?: boolean;
206
+ }
207
+
208
+ declare const AGENT_REGISTRY: Record<AgentId, AgentMetadata>;
209
+ declare function getEnabledAgents(): AgentMetadata[];
210
+ declare function getAgent(id: AgentId): AgentMetadata;
211
+ declare function isKnownAgentId(id: string): id is AgentId;
212
+
213
+ /**
214
+ * Agent identity — the ONE place the public (`LinkedAgentId`) and internal
215
+ * (`AgentId`) id spaces are declared and bridged, plus the ONE alias
216
+ * normalizer every surface funnels through.
217
+ *
218
+ * Canonical values consolidated from (Phase 2, PR-1):
219
+ * - backend `apps/api-v2/src/linked-agents/agent-map.ts`
220
+ * (`PUBLIC_TO_INTERNAL` / `INTERNAL_TO_PUBLIC` / `LinkedAgentId`),
221
+ * - CLI `apps/cli/src/commands/host/agent-provisioning.ts`
222
+ * (`PUBLIC_TO_INTERNAL_AGENT`),
223
+ * - VS Code plugin `apps/vsc-plugin/src/utils/cli-agent-id.ts`
224
+ * (marketplace aliases + `__terminal__:` strip),
225
+ * - CLI `apps/cli/src/commands/start/handlers.ts`
226
+ * (the `claude_code` → `claude` normalization),
227
+ * - mobile `apps/mobile/src/lib/agent-id-map.ts`.
228
+ */
229
+
230
+ /** Sentinel id for the synthetic "CodeAgent Cloud (incluido)" house agent. */
231
+ declare const HOUSE_AGENT_ID = "house-codeagent-cloud";
232
+ /** Internal provider discriminator for the house agent. */
233
+ declare const HOUSE_AGENT_PROVIDER = "codeagent_cloud";
234
+ /** White-label display strings — never mention the backend model. */
235
+ declare const HOUSE_AGENT_NAME = "CodeAgent Cloud";
236
+ declare const HOUSE_AGENT_VENDOR = "CodeAgent";
237
+ declare const HOUSE_AGENT_SUBTITLE = "Included \u2014 no setup";
238
+ /**
239
+ * Public-facing linked-agent ids — the id space the `/api/agents/...`
240
+ * endpoints and the mobile/web surfaces speak. The internal `AgentId`
241
+ * (`'claude' | 'codex' | …`) is what the runtimes / provisioning key on.
242
+ */
243
+ type LinkedAgentId = 'claude_code' | 'codex' | 'cursor' | 'aider' | 'coderabbit' | 'gemini' | typeof HOUSE_AGENT_ID;
244
+ declare const LINKED_AGENT_IDS: readonly LinkedAgentId[];
245
+ declare function isLinkedAgentId(value: string): value is LinkedAgentId;
246
+ /**
247
+ * Every public id → internal `AgentId`.
248
+ *
249
+ * ⚠️ RECONCILED ASYMMETRY — this map is the UNION of what the two sides
250
+ * historically accepted:
251
+ * - The backend's `agent-map.ts` accepts only the `LinkedAgentId` union
252
+ * (incl. the house agent, whose runtime is Claude Code) — no bare
253
+ * `claude`, no `copilot` (there is no public copilot LinkedAgentId).
254
+ * - The CLI's self-hosted `agent-provisioning.ts` additionally accepts
255
+ * bare `'claude'` and `'copilot'` (deploy payloads have carried
256
+ * already-internal ids), but not the house agent.
257
+ * Consumers that must REJECT ids outside their own historical set keep
258
+ * their own guard on top (e.g. `isLinkedAgentId`).
259
+ */
260
+ declare const PUBLIC_TO_INTERNAL: Readonly<Record<LinkedAgentId | 'claude' | 'copilot', AgentId>>;
261
+ /**
262
+ * Internal → public. Partial: `copilot` has no public LinkedAgentId, and
263
+ * `claude` maps back to `claude_code` (never the house agent — that
264
+ * direction is intentionally lossy).
265
+ */
266
+ declare const INTERNAL_TO_PUBLIC: Readonly<Partial<Record<AgentId, LinkedAgentId>>>;
267
+ /** Resolve a public/linked id to the internal `AgentId`, or null. */
268
+ declare function publicToInternal(publicId: string): AgentId | null;
269
+ /** Resolve an internal `AgentId` to its public `LinkedAgentId`, or null. */
270
+ declare function internalToPublic(internal: AgentId): LinkedAgentId | null;
271
+ /** Prefix IDE plugins use for terminal-hosted agent ids. */
272
+ declare const TERMINAL_AGENT_PREFIX = "__terminal__:";
273
+ /**
274
+ * THE agent-id normalizer. Collapses every known spelling of an agent id
275
+ * (registry id, public `claude_code` form, marketplace extension id,
276
+ * `__terminal__:`-prefixed plugin id — case/whitespace tolerant) onto the
277
+ * internal `AgentId`, or `null` when unknown.
278
+ *
279
+ * Deliberately does NOT:
280
+ * - gate on `enabled` (callers that need availability check the
281
+ * registry — see the VS Code wrapper `normalizeCliAgentId`);
282
+ * - map the house agent (that's a runtime substitution, not an alias —
283
+ * use {@link publicToInternal});
284
+ * - fall back to anything. Unknown in → `null` out.
285
+ */
286
+ declare function normalizeAgentId(raw: string): AgentId | null;
287
+ /**
288
+ * The `headroom init --global <kind>` subcommand for an agent id, derived
289
+ * from the registry's `headroomKind` flags — or `null` for unknown or
290
+ * non-wrappable agents (cursor / gemini / aider / anything else).
291
+ *
292
+ * ⚠️ NEVER falls back to `'claude'`. The historical CLI fallback is how
293
+ * the 2026-06 Cursor incident happened: an unsupported agent slipped
294
+ * through, defaulted to `claude`, and `headroom wrap claude` launched
295
+ * Claude Code instead of the user's agent. Callers that genuinely need a
296
+ * default (e.g. picking an init subcommand AFTER the wrappable gate has
297
+ * already passed) apply it themselves — see the CLI's
298
+ * `agentIdToHeadroomKind` wrapper.
299
+ *
300
+ * Matching mirrors the historical predicates on BOTH sides (CLI
301
+ * `isHeadroomSupportedAgent`, api-v2 `isHeadroomWrappableAgent`):
302
+ * case-insensitive, `_`/`-` tolerant, prefix match — so `claude_code`,
303
+ * `Claude-Code`, `codex_cli`, `copilot-cli` all resolve.
304
+ */
305
+ declare function headroomKindFor(agentId: string): HeadroomKind | null;
306
+ /**
307
+ * Registry-derived replacement for the two scattered predicates
308
+ * (`isHeadroomSupportedAgent` in the CLI, `isHeadroomWrappableAgent` in
309
+ * api-v2). Accepts both id spaces (`claude_code` and `claude`).
310
+ */
311
+ declare function isHeadroomWrappable(agentId: string): boolean;
312
+
313
+ /**
314
+ * Wire-shape types for the CLI / IDE-plugin → backend producer endpoints
315
+ * that feed the mobile Files screen and the Pending Review Queue:
316
+ *
317
+ * - `POST /api/files/changed` — register a file change (upsert keyed by
318
+ * `sessionId + filePath` server-side, so re-emitting on every save is
319
+ * safe).
320
+ * - `POST /api/review/hunks` — register an individual hunk for the
321
+ * Pending Review Queue. The "Aggressive" policy this codebase ships
322
+ * with sends one of these per hunk in the diff so the mobile user
323
+ * approves/rejects each one independently.
324
+ *
325
+ * These mirror the backend NestJS DTOs at:
326
+ * apps/api-v2/src/files/dto/report-file-changed.dto.ts
327
+ * apps/api-v2/src/review/dto/create-hunk.dto.ts
328
+ *
329
+ * They are wire-only — no class-validator decorators, no runtime
330
+ * coercion. The producer constructs them in TypeScript and serialises
331
+ * directly to JSON. The backend re-validates on its side.
332
+ */
333
+ type FileChangeStatus = 'modified' | 'added' | 'deleted' | 'renamed';
334
+ type FileReviewStatus = 'modified' | 'awaiting_review' | 'approved' | 'rejected' | 'reviewed';
335
+ /**
336
+ * Body for `POST /api/files/changed`. The producer emits one of these
337
+ * per modified file per session-tick (debounced). The server upserts
338
+ * on `(sessionId, filePath)` so re-emitting on every save is safe.
339
+ *
340
+ * `pluginId` is required by the backend's `PluginAuthGuard` — it's
341
+ * read off the body so the guard can derive the expected HMAC of the
342
+ * `X-Plugin-Auth-Token` header against this exact `(session, plugin)`
343
+ * pair before the controller runs.
344
+ */
345
+ interface FileChangedEvent {
346
+ sessionId: string;
347
+ pluginId: string;
348
+ filePath: string;
349
+ fileStatus: FileChangeStatus;
350
+ linesAdded: number;
351
+ linesRemoved: number;
352
+ hunkCount: number;
353
+ /**
354
+ * Optional. When the producer also emits hunks to `/api/review/hunks`
355
+ * for this file, set this to `'awaiting_review'` so the Files screen
356
+ * renders the pending-review badge. Defaults to `'modified'`
357
+ * server-side when omitted.
358
+ */
359
+ reviewStatus?: FileReviewStatus;
360
+ /**
361
+ * Optional path of the enclosing git repo, relative to the
362
+ * producer's workingDir / workspace folder. Empty string when the
363
+ * producer was launched from inside the repo (single-repo
364
+ * workspace). Lets the UI attribute each row to its sub-repo when
365
+ * the user paired from a multi-repo parent directory (e.g.
366
+ * `~/Documents/codeagent/` containing several sibling repos).
367
+ * Optional for back-compat with older producers — backend
368
+ * defaults to null.
369
+ */
370
+ repoPath?: string;
371
+ /**
372
+ * Optional basename of the enclosing git repo. Provides a short
373
+ * label the UI can render in a chip without parsing `repoPath`.
374
+ * Optional for back-compat.
375
+ */
376
+ repoName?: string;
377
+ }
378
+ type HunkLineType = 'add' | 'remove' | 'context';
379
+ /**
380
+ * One line of a unified diff hunk. `lineNumber` carries the
381
+ * post-change ('+'-side) line numbers from `git diff` so the mobile
382
+ * UI can render the gutter without re-deriving them.
383
+ */
384
+ interface PendingReviewHunkLine {
385
+ type: HunkLineType;
386
+ lineNumber: number;
387
+ text: string;
388
+ }
389
+ /**
390
+ * Body for `POST /api/review/hunks`. One per hunk in the diff.
391
+ *
392
+ * `reasoning` and `sessionLogPreview` are nullable — the v1 chokidar
393
+ * producer doesn't have either (it can't tell agent edits from human
394
+ * edits, and it doesn't read the agent's rationale), so it skips
395
+ * these fields entirely. A future PTY-output-parsing producer can
396
+ * populate them.
397
+ */
398
+ interface PendingReviewHunkEvent {
399
+ sessionId: string;
400
+ pluginId: string;
401
+ filePath: string;
402
+ fileStatus: FileChangeStatus;
403
+ hunkHeader: string;
404
+ lines: PendingReviewHunkLine[];
405
+ linesAdded: number;
406
+ linesRemoved: number;
407
+ reasoning?: string;
408
+ sessionLogPreview?: string[];
409
+ }
410
+ /**
411
+ * One commit in the file's git log (newest first). `sha` is the full
412
+ * 40-char hash; consumers truncate for display. `committedAt` is ISO
413
+ * 8601 in UTC. Mirrors `apps/api-v2/src/review/dto/create-history.dto.ts`
414
+ * `CommitEntryDto`.
415
+ */
416
+ interface CommitEntryWire {
417
+ sha: string;
418
+ authorName: string;
419
+ authorEmail: string;
420
+ committedAt: string;
421
+ subject: string;
422
+ }
423
+ /**
424
+ * Body for `POST /api/review/history`. The producer captures `git log
425
+ * --max-count=N -- <path>` for each touched file at the same point it
426
+ * pushes hunks, then upserts on `(sessionId, repoPath, filePath)`
427
+ * server-side. Re-emitting per save is safe.
428
+ */
429
+ interface FileHistoryEvent {
430
+ sessionId: string;
431
+ pluginId: string;
432
+ filePath: string;
433
+ repoPath?: string;
434
+ repoName?: string;
435
+ commits: CommitEntryWire[];
436
+ }
437
+ /**
438
+ * One line of `git blame`. `lineNumber` is 1-based and matches the
439
+ * post-image (current) file gutter.
440
+ */
441
+ interface BlameLineWire {
442
+ lineNumber: number;
443
+ sha: string;
444
+ authorName: string;
445
+ committedAt: string;
446
+ text: string;
447
+ }
448
+ /**
449
+ * Body for `POST /api/review/blame`. Capped server-side by what the
450
+ * producer chose to emit — large files get truncated by the CLI so a
451
+ * single payload stays under the JSON size limit.
452
+ */
453
+ interface FileBlameEvent {
454
+ sessionId: string;
455
+ pluginId: string;
456
+ filePath: string;
457
+ repoPath?: string;
458
+ repoName?: string;
459
+ lines: BlameLineWire[];
460
+ }
461
+
462
+ /**
463
+ * Wire-shape types for the CLI / IDE-plugin → backend Epic C streaming
464
+ * endpoints. The CLI parses Claude's (or Codex's) PTY output into a
465
+ * stream of discriminated chunks and pushes each one to the backend, so
466
+ * the mobile client can render an in-progress agent turn token-by-token
467
+ * instead of waiting for the entire turn to finalise.
468
+ *
469
+ * - `POST /api/sessions/:id/streaming-chunk` — body is
470
+ * {@link StreamingChunkEvent}. Fires an SSE delta downstream.
471
+ * - `POST /api/sessions/:id/awaiting-answer` — body is
472
+ * {@link AwaitingAnswerEvent}. Pauses the turn on the mobile side
473
+ * and prompts the user for a reply. Stored in Redis with a 5 min TTL.
474
+ * - Answer channel: backend publishes user replies on the Redis
475
+ * channel `session:${sessionId}:answers` with the payload shape
476
+ * {@link AnswerResolvedEvent}. The CLI polls
477
+ * `GET /api/sessions/:id/pending-answer` to drain it (the polling
478
+ * interval is 1.5 s — short enough to feel instant, long enough to
479
+ * stay well under any sane rate limit).
480
+ *
481
+ * These mirror the backend NestJS DTOs at:
482
+ * apps/api-v2/src/sessions/dto/streaming-chunk.dto.ts
483
+ * apps/api-v2/src/sessions/dto/awaiting-answer.dto.ts
484
+ * apps/api-v2/src/sessions/dto/answer-resolved.dto.ts
485
+ *
486
+ * They are wire-only — no class-validator decorators, no runtime
487
+ * coercion. The producer constructs them in TypeScript and serialises
488
+ * directly to JSON. The backend re-validates on its side.
489
+ */
490
+ /**
491
+ * Logical kind of an Epic C streaming chunk.
492
+ *
493
+ * - `text` — agent prose (the conversational reply the user sees).
494
+ * - `thinking` — Claude's "(thinking)" / "+ Puttering…" frame between
495
+ * the prompt and the answer.
496
+ * - `tool_use` — a tool call (Read / Edit / Bash / Search / …) the
497
+ * agent invoked.
498
+ * - `tool_result` — the result body of the prior tool call (typically
499
+ * the `└ …` continuation line in Claude's TUI).
500
+ */
501
+ type StreamingChunkKind = 'text' | 'thinking' | 'tool_use' | 'tool_result';
502
+ /**
503
+ * Body for `POST /api/sessions/:id/streaming-chunk`.
504
+ *
505
+ * `chunkId` is stable across continuation pushes for the same logical
506
+ * chunk (so the backend can splice deltas), and changes when the
507
+ * producer flips `kind` or finalises the chunk. `isFinal: true` marks
508
+ * the last push for this `chunkId`; the next emission opens a fresh
509
+ * chunkId.
510
+ */
511
+ interface StreamingChunkEvent {
512
+ chunkId: string;
513
+ kind: StreamingChunkKind;
514
+ content: string;
515
+ isFinal: boolean;
516
+ }
517
+ /**
518
+ * Body for `POST /api/sessions/:id/awaiting-answer`.
519
+ *
520
+ * `prompt` is the question text the agent rendered (free-form). When
521
+ * the agent presented a multiple-choice selector, `options` is the
522
+ * ordered list of choices the user can pick. `questionId` is the
523
+ * producer-generated UUID the backend echoes back through the answer
524
+ * channel so the CLI can correlate the user's reply with the prompt.
525
+ */
526
+ interface AwaitingAnswerEvent {
527
+ questionId: string;
528
+ prompt: string;
529
+ options?: string[];
530
+ }
531
+ /**
532
+ * Wire shape for the `input_suggestion` output chunk emitted by CLI agents
533
+ * after a turn ends.
534
+ *
535
+ * PTY agents (claude, codex, copilot, aider) emit `content: string` —
536
+ * the detected ghost-text from the agent's input area (backward-compat,
537
+ * one chip on mobile).
538
+ *
539
+ * ACP agents emit `content: string[]` — a static set of chip labels such
540
+ * as `['Continue', 'Yes, go ahead', 'Explain']` (multiple chips on mobile).
541
+ *
542
+ * Consumers MUST normalise:
543
+ * `Array.isArray(content) ? content : [content]`
544
+ */
545
+ interface InputSuggestionChunk {
546
+ type: 'input_suggestion';
547
+ /** Single string (PTY, backward-compat) or array of chip labels (ACP). */
548
+ content: string | string[];
549
+ done: true;
550
+ }
551
+ /**
552
+ * Payload published on the Redis `session:${sessionId}:answers`
553
+ * channel — and also the shape returned by the polling fallback
554
+ * `GET /api/sessions/:id/pending-answer` (wrapped in `{ data: … }` by
555
+ * the backend's standard envelope).
556
+ *
557
+ * For free-form prompts `answer` is the user's typed text. For a
558
+ * selector prompt, the backend forwards the chosen option label as
559
+ * `answer` and additionally sets `optionIndex` (0-based) so the
560
+ * producer can drive arrow-key navigation in a React Ink selector
561
+ * without re-resolving the label.
562
+ */
563
+ interface AnswerResolvedEvent {
564
+ questionId: string;
565
+ answer: string;
566
+ optionIndex?: number;
567
+ }
568
+
569
+ /**
570
+ * Production API base URL for all CodeAgent Mobile clients.
571
+ *
572
+ * History note: prod migrated from Vercel (`https://api.codeagent-mobile.com`)
573
+ * to Cloud Run / api-v2 (`https://api.codeagent-mobile.com`) in 2026-05. The
574
+ * Vercel deployment is now gated by Vercel deployment protection and returns
575
+ * 403 for unauthed traffic — DO NOT fall back to it.
576
+ *
577
+ * Override at runtime with `CODEAM_API_URL` (full URL override) OR set
578
+ * `CODEAM_TEST_MODE=1` to point every client request at the dev
579
+ * preview without having to know its host.
580
+ */
581
+ declare const DEFAULT_API_BASE_URL: "https://api.codeagent-mobile.com";
582
+ /**
583
+ * Dev-preview API base URL. Same Cloud Run service as prod but routed
584
+ * to the `dev` revision (auto-deploys from the `dev` branch in the
585
+ * backend repo). Manual smoke tests + load runs land here.
586
+ */
587
+ declare const DEV_API_BASE_URL: "https://dev-api.codeagent-mobile.com";
588
+ /**
589
+ * Resolve the active API base URL, honoring in priority order:
590
+ *
591
+ * 1. Explicit `CODEAM_API_URL` env var — full URL, takes precedence.
592
+ * 2. `CODEAM_TEST_MODE=1` shortcut — flips to [DEV_API_BASE_URL]
593
+ * without the user having to know the dev host.
594
+ * 3. The `DEFAULT_API_BASE_URL` constant (prod).
595
+ *
596
+ * Used by every CLI service that talks to the backend so one env var
597
+ * flips heartbeats, command relay, chunk uploads, and the pairing
598
+ * flow in lockstep — eliminates the cross-environment misroute where
599
+ * pairing succeeds in dev (shared Redis) but the CLI keeps
600
+ * heartbeating to prod.
601
+ */
602
+ declare function resolveApiBaseUrl(): string;
603
+
604
+ /**
605
+ * Preview wire types (PreviewDetection / PreviewStatus / EnvVar).
606
+ *
607
+ * CANONICAL WIRE OWNER: this file (`@codeam/shared`) owns the wire
608
+ * protocol, per the cross-repo rule. The backend repo keeps hand-synced
609
+ * MIRRORS (`codeagent-mobile/packages/shared/src/types/preview.ts` for
610
+ * mobile/landing, `codeagent-mobile/apps/api-v2/src/common/types/preview.ts`
611
+ * for the backend); a drift-check script at
612
+ * `codeagent-mobile/scripts/check-shared-drift` compares them.
613
+ */
614
+ interface PreviewDetection {
615
+ framework: string;
616
+ command: string;
617
+ args: string[];
618
+ port: number;
619
+ ready_pattern: string;
620
+ env?: Record<string, string>;
621
+ setup_commands?: Array<{
622
+ cmd: string;
623
+ args: string[];
624
+ }>;
625
+ notes?: string;
626
+ }
627
+ type PreviewState = 'idle' | 'detection_pending' | 'detection_ready' | 'starting' | 'running' | 'error';
628
+ type PreviewErrorStage = 'detection' | 'spawn' | 'tunnel' | 'ready_timeout' | 'unsupported';
629
+ interface PreviewStatus {
630
+ state: PreviewState;
631
+ url?: string;
632
+ framework?: string;
633
+ detection?: PreviewDetection;
634
+ error?: {
635
+ stage: PreviewErrorStage;
636
+ message: string;
637
+ };
638
+ }
639
+ /**
640
+ * One environment variable as edited from the app and written to the
641
+ * project `.env`. The wire shape for `env_read` (returns EnvVar[]) and
642
+ * `env_write` (accepts EnvVar[]).
643
+ */
644
+ interface EnvVar {
645
+ key: string;
646
+ value: string;
647
+ }
648
+
649
+ /**
650
+ * Beads wire protocol — the bytes the codeam-cli pushes to the backend's
651
+ * `POST /api/beads/ingest` and that the backend mirrors + fans out over the
652
+ * per-user SSE bus.
653
+ *
654
+ * CANONICAL WIRE OWNER: this file (`@codeam/shared`) owns the wire
655
+ * protocol, per the cross-repo rule. The backend repo keeps hand-synced
656
+ * MIRRORS of these shapes (`codeagent-mobile/packages/shared/src/types/beads.ts`
657
+ * for mobile/landing, `codeagent-mobile/apps/api-v2/src/beads/beads.types.ts`
658
+ * for the backend service); a drift-check script at
659
+ * `codeagent-mobile/scripts/check-shared-drift` compares them. Both the CLI
660
+ * (tsup) and the VS Code extension (esbuild) inline this file at build time.
661
+ *
662
+ * Shape rationale: `BeadsIssueDto` mirrors `bd ready --json` / `bd list --json`
663
+ * output (verified against `@beads/bd@1.0.5`) plus the backend-required
664
+ * `projectKey` scoping field (design decision D7). We do NOT reshape bd's
665
+ * field names — the mirror stores them as-is so a bd schema bump is a
666
+ * one-file change here, not a sprawling rename across the codebase.
667
+ */
668
+ /** bd lifecycle status. bd emits these literals in `--json`. */
669
+ type BeadsIssueStatus = 'open' | 'in_progress' | 'blocked' | 'closed';
670
+ /**
671
+ * Single issue as emitted by `bd ready --json` / `bd list --json`, plus the
672
+ * backend scoping field. The counts are REQUIRED on the wire — the backend's
673
+ * ingest DTO validates them as required ints, so the producer (`bd-adapter`'s
674
+ * `parseIssues`) defaults any count bd omits to 0 rather than dropping the
675
+ * field.
676
+ */
677
+ interface BeadsIssueDto {
678
+ id: string;
679
+ title: string;
680
+ status: BeadsIssueStatus;
681
+ /** 0 = P0 (highest). bd emits an integer; null when unset. */
682
+ priority: number | null;
683
+ /** bug | task | feature | message | … (free-form in bd). */
684
+ issue_type: string;
685
+ /** agent / session id that claimed the issue, when claimed. */
686
+ owner: string | null;
687
+ created_at: string;
688
+ updated_at: string;
689
+ dependency_count: number;
690
+ dependent_count: number;
691
+ comment_count: number;
692
+ /** D7 scoping — normalized git origin (or path-hash fallback). */
693
+ projectKey: string;
694
+ }
695
+ /** bd dependency kind. */
696
+ type BeadsDependencyKind = 'blocks' | 'related' | 'parent-child' | 'discovered-from';
697
+ /**
698
+ * One dependency edge. Rows carry NO per-row `projectKey` — the ingest
699
+ * payload is per-project, so edges are scoped by the payload-level
700
+ * `projectKey` on the backend.
701
+ */
702
+ interface BeadsDependencyDto {
703
+ /** stable id — `${fromId}:${kind}:${toId}` when bd doesn't supply one. */
704
+ id: string;
705
+ fromId: string;
706
+ toId: string;
707
+ kind: BeadsDependencyKind;
708
+ }
709
+ interface BeadsMemoryDto {
710
+ id: string;
711
+ body: string;
712
+ createdAt: string;
713
+ /** null = cross-cutting / personal (not scoped to one project). */
714
+ projectKey: string | null;
715
+ }
716
+ /** `bd status --json` → `summary` block. */
717
+ interface BeadsStatusSummary {
718
+ open_issues: number;
719
+ ready_issues: number;
720
+ blocked_issues: number;
721
+ in_progress_issues: number;
722
+ closed_issues: number;
723
+ total_issues: number;
724
+ }
725
+ /**
726
+ * The delta (or full snapshot) the CLI POSTs to `/api/beads/ingest` whenever
727
+ * `.beads/issues.jsonl` changes. `fullSnapshot: true` tells the backend to
728
+ * prune issues absent from `issues` (station-wins reconciliation).
729
+ */
730
+ interface BeadsIngestPayload {
731
+ sessionId: string;
732
+ pluginId: string;
733
+ /** D7 project key the issues/memories belong to. */
734
+ projectKey: string;
735
+ /** Human-readable label (repo name) for the UI. */
736
+ projectLabel: string;
737
+ /** When true, the backend prunes mirror rows not present in `issues`. */
738
+ fullSnapshot?: boolean;
739
+ issues: BeadsIssueDto[];
740
+ /** Dependency edges between issues. The current watcher ALWAYS sends this
741
+ * (an empty array today — edges aren't computed in the P0 snapshot); the
742
+ * backend DTO nevertheless marks it optional to tolerate older producers.
743
+ * Field name matches the backend (`dependencies`, not `deps`). */
744
+ dependencies: BeadsDependencyDto[];
745
+ memories: BeadsMemoryDto[];
746
+ summary?: BeadsStatusSummary;
747
+ }
748
+ /**
749
+ * A mobile-originated action relayed to the CLI as a pending command
750
+ * (`type: 'beads_action'`). The CLI replays it as a native `bd` command
751
+ * (Task 9) then pushes the resulting state back through ingest.
752
+ *
753
+ * NOTE — this is the backend→CLI COMMAND hop, NOT the mobile→backend
754
+ * request hop. The mobile client POSTs a `BeadsActionRequest`
755
+ * (discriminator `action`, create-title in `title`) to
756
+ * `POST /api/beads/actions`; the backend translates it in
757
+ * `codeagent-mobile/apps/api-v2/src/beads/beads.controller.ts` (+
758
+ * `bd-action.util.ts`) and pushes a `beads_action` command whose payload
759
+ * the CLI decodes in `apps/cli/src/beads/wiring.ts`
760
+ * (`beadsActionFromPayload`) into THIS shape (discriminator `kind`,
761
+ * title/body in `text`, plus `owner`).
762
+ */
763
+ type BeadsActionKind = 'claim' | 'close' | 'create' | 'remember';
764
+ interface BeadsActionCommand {
765
+ kind: BeadsActionKind;
766
+ /** Target issue id — required for `claim` / `close`. */
767
+ issueId?: string;
768
+ /** Free text — `create` title or `remember` body. */
769
+ text?: string;
770
+ /** `close` reason. */
771
+ reason?: string;
772
+ /** Owner to claim as — defaults to the session/agent id when omitted. */
773
+ owner?: string;
774
+ /** Project the action targets (so the right `bd` working context applies). */
775
+ projectKey?: string;
776
+ }
777
+ /** @deprecated Renamed to `BeadsActionCommand` — the old name collided with
778
+ * the backend repo's mobile→backend request type (now `BeadsActionRequest`). */
779
+ type BeadsActionPayload = BeadsActionCommand;
780
+ /** Action verb for `configureBeads` (enable / disable / status). */
781
+ type BeadsConfigureAction = 'enable' | 'disable' | 'status';
782
+ /** Lifecycle state emitted by `configureBeads` on the per-session SSE bus. */
783
+ type BeadsStatusState = 'enabled' | 'disabled' | 'error' | 'provisioning';
784
+ /**
785
+ * Lifecycle of the CLI's Beads provisioning step (spec D10/D13).
786
+ *
787
+ * The CLI's composition-root provisions Beads (`bd init` → start the
788
+ * shared dolt server → enable auto-export → start the watcher) as a
789
+ * parallel, non-fatal concern, decoupled from the agent run. It signals
790
+ * each phase to the backend, which fans it out as a `beads_provisioning`
791
+ * UserEvent so the read-only mobile/web surface can show a lightweight
792
+ * status line ("Provisioning Beads…", "Beads ready", "Beads
793
+ * provisioning failed") — distinct from the data feed (`beads_state_changed`).
794
+ *
795
+ * - `provisioning` — bootstrap started / in flight.
796
+ * - `ready` — Beads is up; the mirror will begin receiving deltas.
797
+ * - `failed` — bootstrap aborted (e.g. bd install failed); the
798
+ * surface explains the agent is running without Beads.
799
+ */
800
+ type BeadsProvisioningStatus = 'provisioning' | 'ready' | 'failed';
801
+ /**
802
+ * Body of `POST /api/beads/provisioning` — the CLI is the producer.
803
+ *
804
+ * `sessionId` + `pluginId` carry the plugin-auth envelope (the CLI has
805
+ * NO user JWT, same as `/ingest`). The backend resolves the userId from
806
+ * the session and publishes `{ type: 'beads_provisioning', status,
807
+ * projectKey }` on the per-user SSE bus.
808
+ *
809
+ * `projectKey` is optional: the home-level `bd init` runs before any
810
+ * repo is resolved, so the first `provisioning` frame may not carry one
811
+ * yet. `detail` is an optional human-readable note (e.g. the failure
812
+ * reason) the surface can render verbatim.
813
+ */
814
+ interface BeadsProvisioningPayload {
815
+ /** Paired session the CLI is pushing from (plugin-auth). */
816
+ sessionId: string;
817
+ /** Plugin id the auth token was minted for (plugin-auth). */
818
+ pluginId: string;
819
+ status: BeadsProvisioningStatus;
820
+ /** Affected project, when the bootstrap has resolved a repo. */
821
+ projectKey?: string;
822
+ /** Optional human-readable note (e.g. failure reason). */
823
+ detail?: string;
824
+ }
825
+ /** Snapshot of the station's Beads add-on state (mirrored to mobile). */
826
+ interface BeadsStatus {
827
+ state: BeadsStatusState;
828
+ running?: boolean;
829
+ bdAvailable?: boolean;
830
+ doltAvailable?: boolean;
831
+ serverUp?: boolean;
832
+ prefix?: string | null;
833
+ error?: string;
834
+ }
835
+ /** One project the mirror has seen — drives the project-list view. */
836
+ interface BeadsProjectDto {
837
+ projectKey: string;
838
+ /** Human repo name for the UI. */
839
+ label: string;
840
+ /** ISO8601 — last time the CLI pushed state for this project. */
841
+ lastSyncedAt: string;
842
+ }
843
+ /**
844
+ * One-shot snapshot returned by `GET /api/beads/me` and embedded in the
845
+ * per-user SSE `snapshot` so reconnects rehydrate. `issuesByProject` is
846
+ * keyed by `projectKey`.
847
+ */
848
+ interface BeadsSnapshotDto {
849
+ projects: BeadsProjectDto[];
850
+ issuesByProject: Record<string, BeadsIssueDto[]>;
851
+ memories: BeadsMemoryDto[];
852
+ /** Aggregate summary across all the user's projects. */
853
+ summary: BeadsStatusSummary;
854
+ }
855
+ /**
856
+ * The user-initiated Beads actions a mobile/web client can request.
857
+ *
858
+ * - `claim` — take ownership of a ready issue (`bd update --status in_progress`).
859
+ * - `close` — close an issue (`bd close`).
860
+ * - `create` — create a new issue (`bd create`).
861
+ * - `remember` — record a persistent memory note (`bd remember`).
862
+ *
863
+ * The backend does NOT mutate the mirror directly — it relays the
864
+ * action as a `bd` command to the user's active paired session, where
865
+ * the CLI runs it natively against the station's `bd` graph. The
866
+ * resulting state change flows back via `POST /api/beads/ingest` and
867
+ * fans out over the per-user SSE bus. The mirror is read-optimised;
868
+ * the station stays the source of truth (station-wins).
869
+ */
870
+ type BeadsActionType = 'claim' | 'close' | 'create' | 'remember';
871
+ /**
872
+ * Body of `POST /api/beads/actions` (JWT-authed mobile/web user).
873
+ *
874
+ * NOTE — this is the mobile→backend REQUEST hop, NOT the backend→CLI
875
+ * command hop (`BeadsActionCommand` above).
876
+ *
877
+ * Field relevance by action:
878
+ * - `claim` — `issueId` required.
879
+ * - `close` — `issueId` required; `reason` optional.
880
+ * - `create` — `title` required; `projectKey` optional (targets a project).
881
+ * - `remember` — `text` required; `projectKey` optional (scopes the memory).
882
+ */
883
+ interface BeadsActionRequest {
884
+ action: BeadsActionType;
885
+ /** Target issue for `claim` / `close`. */
886
+ issueId?: string;
887
+ /** Title for a `create`d issue. */
888
+ title?: string;
889
+ /** Optional human-readable reason for `close`. */
890
+ reason?: string;
891
+ /** Memory body for `remember`. */
892
+ text?: string;
893
+ /** Project scope for `create` / `remember`; defaults to the station's current repo. */
894
+ projectKey?: string;
895
+ }
896
+
897
+ /**
898
+ * Headroom budget configuration and command types.
899
+ * Used by the CLI to enable/disable cost-saving Headroom token compression
900
+ * and track spending against configured budgets.
901
+ *
902
+ * CANONICAL WIRE OWNER: this file (`@codeam/shared`) owns the wire
903
+ * protocol, per the cross-repo rule. The backend repo keeps hand-synced
904
+ * MIRRORS (`codeagent-mobile/packages/shared/src/types/headroom.ts` for
905
+ * mobile/landing, `codeagent-mobile/apps/api-v2/src/common/types/headroom.ts`
906
+ * for the backend); a drift-check script at
907
+ * `codeagent-mobile/scripts/check-shared-drift` compares them.
908
+ */
909
+ type HeadroomBudgetPeriod = 'hourly' | 'daily' | 'monthly';
910
+ /**
911
+ * Command sent via relay to enable/disable/configure Headroom budget settings.
912
+ * The `agentId` field is included because PairedSession has no agentId server-side,
913
+ * so the relay command carries it for the CLI handler to guard on.
914
+ */
915
+ interface HeadroomBudgetCommand {
916
+ budgetEnabled: boolean;
917
+ budgetUsd?: number;
918
+ budgetPeriod?: HeadroomBudgetPeriod;
919
+ agentId?: string;
920
+ }
921
+ /**
922
+ * Budget usage fields appended to the savings payload that the Headroom reporter
923
+ * sends to the backend. Tracks spending in the current budget period.
924
+ */
925
+ interface HeadroomBudgetUsage {
926
+ periodSpendUsd?: number;
927
+ budgetUsd?: number;
928
+ budgetPeriod?: HeadroomBudgetPeriod;
929
+ /** True iff this turn pushed periodSpendUsd to or past budgetUsd. */
930
+ budgetReached?: boolean;
931
+ }
932
+ /**
933
+ * Headroom cost-saving state for a session — carried on the `headroom_status`
934
+ * SSE event and snapshotted by the backend into Redis `headroom:<sessionId>`.
935
+ * Mirrored byte-for-byte in `apps/api-v2/src/common/types/headroom.ts`.
936
+ */
937
+ interface HeadroomStatus {
938
+ state: 'enabled' | 'disabled' | 'error' | 'provisioning';
939
+ running?: boolean;
940
+ agent?: string;
941
+ savings?: number;
942
+ error?: string;
943
+ }
944
+
945
+ /**
946
+ * Headroom provisioning manifest — the SINGLE source of truth for what a
947
+ * Headroom install consists of, rendered by every provisioning surface:
948
+ *
949
+ * - codespace bootstrap (bash composer in the backend repo,
950
+ * `apps/api-v2/src/codespaces/github-ssh.service.ts` — adopts in PR-2),
951
+ * - self-hosted deploy (TS installer, CLI `commands/host-agent.ts`
952
+ * `setupHeadroomForSelfHosted`),
953
+ * - on-demand local sessions ("Session add-ons → Cost-saving", CLI
954
+ * `services/headroom/configure.ts`).
955
+ *
956
+ * Values are DATA-first (arrays/records, plus tiny pure renderers) so both
957
+ * the TS installer and a bash composer can interpolate from them. Renderers
958
+ * are byte-exact with the literals they replaced — guarded by
959
+ * `packages/shared/__tests__/headroom-manifest.test.ts`.
960
+ *
961
+ * ⚠️ The extras matter: `[proxy,code]` pulls the ONNX compression engines
962
+ * (Kompress + tree-sitter CodeCompressor). NEVER add `[ml]` — that's
963
+ * multi-GB PyTorch, and a broken/cold torch wedges every prompt at
964
+ * "Thinking…". The models are pre-downloaded at provision time because the
965
+ * proxy eager-loads with `allow_download=False` and a cold cache defers the
966
+ * ~840 MB download to the first prompt (blowing the agent's ~90 s idle
967
+ * timeout).
968
+ */
969
+ /** Local proxy port the agent's config is routed to. */
970
+ declare const HEADROOM_PROXY_PORT = 8787;
971
+ /**
972
+ * Env that pins the ONNX backend on the proxy process — never imports
973
+ * torch. Spread into the proxy launch env on every surface.
974
+ */
975
+ declare const HEADROOM_BACKEND_ENV: {
976
+ readonly HEADROOM_KOMPRESS_BACKEND: "onnx_cpu";
977
+ };
978
+ /**
979
+ * The proxy's HTTP/server companion packages, installed alongside the
980
+ * `headroom-ai[...]` package. The COMPRESSION ENGINES come from the
981
+ * headroom-ai extras — NOT this list.
982
+ */
983
+ declare const HEADROOM_PIP_COMPANIONS: readonly string[];
984
+ /** The three provisioning surfaces (see module doc). */
985
+ type HeadroomSurface = 'codespace' | 'selfHosted' | 'onDemand';
986
+ /**
987
+ * pip extras per surface. `onDemand` additionally ships `image`
988
+ * (image-compression support, added with the Session add-ons path in
989
+ * codeam-cli@2.49.0); the older codespace/self-hosted install strings
990
+ * remain `[proxy,code]` byte-for-byte.
991
+ */
992
+ declare const HEADROOM_EXTRAS_BY_SURFACE: Readonly<Record<HeadroomSurface, readonly string[]>>;
993
+ /** `headroom-ai[<extras>]` — the pip requirement string. */
994
+ declare function headroomPipPackage(extras: readonly string[]): string;
995
+ /** One HuggingFace repo to pre-warm into the HF cache at provision time. */
996
+ interface HeadroomModelSpec {
997
+ repo: string;
998
+ /** `snapshot_download(..., allow_patterns=[…])` filter. */
999
+ allowPatterns: readonly string[];
1000
+ }
1001
+ /**
1002
+ * The two HF repos Kompress needs. kompress-v2-base is the ONNX model
1003
+ * (skip its .pt/.safetensors torch artifacts); ModernBERT-base is the
1004
+ * TOKENIZER ONLY (skip its model weights).
1005
+ */
1006
+ declare const HEADROOM_MODELS: readonly HeadroomModelSpec[];
1007
+ /** Formatting knob so each surface can stay byte-identical to its
1008
+ * historical literal (the CLI joins patterns with `,`, the codespace
1009
+ * bash composer with `, `). */
1010
+ interface HeadroomPythonRenderOpts {
1011
+ /** Put a space after the commas between allow_patterns entries. */
1012
+ spaceAfterComma?: boolean;
1013
+ }
1014
+ /** Render one `snapshot_download(...)` python line for a model. */
1015
+ declare function headroomSnapshotDownloadLine(model: HeadroomModelSpec, opts?: HeadroomPythonRenderOpts): string;
1016
+ /**
1017
+ * The full model pre-download python snippet (import + one
1018
+ * `snapshot_download` per model), newline-joined — what the surfaces pass
1019
+ * to `python -c` / a heredoc.
1020
+ */
1021
+ declare function headroomModelPredownloadScript(opts?: HeadroomPythonRenderOpts): string;
1022
+
1023
+ /**
1024
+ * Canonical names of the per-user SSE bus events (`/api/users/me/stream`).
1025
+ *
1026
+ * The authoritative list is the `UserEvent` discriminated union in the
1027
+ * backend repo: codeagent-mobile/apps/api-v2/src/user-events/user-events.types.ts.
1028
+ * Every `type:` literal of that union appears here exactly once — when a new
1029
+ * variant lands on the union, add its name here (and in the backend mirror of
1030
+ * this file at codeagent-mobile/packages/shared/src/types/events.ts).
1031
+ *
1032
+ * Producers (CLI event posts, backend `userEvents.publish` calls) and
1033
+ * consumers (the `useUserEventsSSE` hooks' switch cases) should reference
1034
+ * `USER_EVENTS.*` instead of re-typing the string, so a typo becomes a
1035
+ * compile error instead of a silently dropped event.
1036
+ */
1037
+ declare const USER_EVENTS: {
1038
+ readonly PAIRED_SESSION_STATUS: "paired_session_status";
1039
+ readonly PAIRED_SESSION_ADDED: "paired_session_added";
1040
+ readonly PAIRED_SESSION_REMOVED: "paired_session_removed";
1041
+ readonly PAIRED_SESSION_BRANCH_CHANGED: "paired_session_branch_changed";
1042
+ readonly SHARED_WITH_ME_ADDED: "shared_with_me_added";
1043
+ readonly SHARED_WITH_ME_REVOKED: "shared_with_me_revoked";
1044
+ readonly USAGE_CHANGED: "usage_changed";
1045
+ readonly TASK_DONE: "task_done";
1046
+ readonly HUNK_PENDING_REVIEW_ADDED: "hunk_pending_review_added";
1047
+ readonly HUNK_REVIEW_RESOLVED: "hunk_review_resolved";
1048
+ readonly FILE_CHANGED: "file_changed";
1049
+ readonly FILES_BATCH_CHANGED: "files_batch_changed";
1050
+ readonly AGENT_STREAMING_CHUNK: "agent_streaming_chunk";
1051
+ readonly AGENT_AWAITING_ANSWER: "agent_awaiting_answer";
1052
+ readonly AWAITING_INPUT_ADDED: "awaiting_input_added";
1053
+ readonly AGENT_ANSWER_RESOLVED: "agent_answer_resolved";
1054
+ readonly TEMPLATE_ADDED: "template_added";
1055
+ readonly TEMPLATE_REMOVED: "template_removed";
1056
+ readonly TEMPLATE_UPDATED: "template_updated";
1057
+ readonly AGENT_TASK_DISPATCHED: "agent_task_dispatched";
1058
+ readonly AGENT_TASK_COMPLETED: "agent_task_completed";
1059
+ readonly LINKED_AGENT_ADDED: "linked_agent_added";
1060
+ readonly QUOTA_REACHED: "quota_reached";
1061
+ readonly LINKED_AGENT_LINK_FAILED: "linked_agent_link_failed";
1062
+ readonly CODESPACE_AGENT_INSTALLED: "codespace_agent_installed";
1063
+ readonly AGENT_CREDENTIALS_REFRESHED: "agent_credentials_refreshed";
1064
+ readonly CREDENTIAL_INVALID: "credential_invalid";
1065
+ readonly CODESPACE_WAKING: "codespace_waking";
1066
+ readonly CODESPACE_BILLING_BLOCKED: "codespace_billing_blocked";
1067
+ readonly COST_SAVING_UPDATED: "cost_saving_updated";
1068
+ readonly COMMAND_COMPLETED: "command_completed";
1069
+ readonly AI_SUMMARY_PENDING: "ai_summary_pending";
1070
+ readonly AI_SUMMARY_READY: "ai_summary_ready";
1071
+ readonly AI_INSIGHT_PENDING: "ai_insight_pending";
1072
+ readonly AI_INSIGHT_READY: "ai_insight_ready";
1073
+ readonly PUSH_TOKEN_INVALIDATED: "push_token_invalidated";
1074
+ readonly PREVIEW_DETECTION_PENDING: "preview_detection_pending";
1075
+ readonly PREVIEW_DETECTION_READY: "preview_detection_ready";
1076
+ readonly PREVIEW_STARTING: "preview_starting";
1077
+ readonly PREVIEW_READY: "preview_ready";
1078
+ readonly PREVIEW_STOPPED: "preview_stopped";
1079
+ readonly PREVIEW_ERROR: "preview_error";
1080
+ readonly PREVIEW_PROGRESS: "preview_progress";
1081
+ readonly BEADS_STATE_CHANGED: "beads_state_changed";
1082
+ readonly BEADS_PROVISIONING: "beads_provisioning";
1083
+ readonly BEADS_TEAM_MEMORY_CHANGED: "beads_team_memory_changed";
1084
+ readonly AUDIT_EVENT_ADDED: "audit_event_added";
1085
+ readonly SELF_HOSTED_HOST_ADDED: "self_hosted_host_added";
1086
+ readonly SELF_HOSTED_HOST_STATUS: "self_hosted_host_status";
1087
+ readonly SELF_HOSTED_HOST_REMOVED: "self_hosted_host_removed";
1088
+ readonly SELF_HOSTED_HOST_TELEMETRY: "self_hosted_host_telemetry";
1089
+ readonly SELF_HOSTED_HOST_METRICS: "self_hosted_host_metrics";
1090
+ readonly SELF_HOSTED_HOST_SESSIONS: "self_hosted_host_sessions";
1091
+ readonly SELF_HOSTED_DEPLOY_PROGRESS: "self_hosted_deploy_progress";
1092
+ readonly REFERRAL_REWARD_EARNED: "referral_reward_earned";
1093
+ readonly HEADROOM_PROGRESS: "headroom_progress";
1094
+ readonly HEADROOM_STATUS: "headroom_status";
1095
+ readonly BEADS_STATUS: "beads_status";
1096
+ readonly LINKED_AGENT_HEADROOM_BUDGET_UPDATED: "linked_agent_headroom_budget_updated";
1097
+ readonly CLI_UPDATE_AVAILABLE: "cli_update_available";
1098
+ readonly AGENT_INSTALL_PROGRESS: "agent_install_progress";
1099
+ readonly AGENT_INSTALL_FAILED: "agent_install_failed";
1100
+ readonly CLI_UPDATE_PROGRESS: "cli_update_progress";
1101
+ readonly CLI_UPDATE_FAILED: "cli_update_failed";
1102
+ };
1103
+ type UserEventName = (typeof USER_EVENTS)[keyof typeof USER_EVENTS];
1104
+
1105
+ /**
1106
+ * Prompt the CLI sends to the user's linked agent (Claude, Codex, …)
1107
+ * in a headless one-shot to detect how to start the project's dev
1108
+ * server. Same pattern as the AI Insights "summary" prompt — the
1109
+ * agent runs locally with the user's auth, has read access to the
1110
+ * project, and returns a tiny JSON blob the CLI parses.
1111
+ *
1112
+ * Kept here (in `@codeam/shared`) so the CLI build inlines the
1113
+ * exact string at compile time without runtime fetch from the backend.
1114
+ */
1115
+ declare const PREVIEW_DETECT_PROMPT: string;
1116
+
1117
+ export { AGENT_REGISTRY, type AgentAuth, type AgentAuthKind, type AgentId, type AgentMetadata, type AgentModel, type AnswerResolvedEvent, type AwaitingAnswerEvent, type BeadsActionCommand, type BeadsActionKind, type BeadsActionPayload, type BeadsActionRequest, type BeadsActionType, type BeadsConfigureAction, type BeadsDependencyDto, type BeadsDependencyKind, type BeadsIngestPayload, type BeadsIssueDto, type BeadsIssueStatus, type BeadsMemoryDto, type BeadsProjectDto, type BeadsProvisioningPayload, type BeadsProvisioningStatus, type BeadsSnapshotDto, type BeadsStatus, type BeadsStatusState, type BeadsStatusSummary, type BlameLineWire, type ChromeStep, type ChromeToolType, type CommitEntryWire, DEFAULT_API_BASE_URL, DEV_API_BASE_URL, type EnvVar, type FileBlameEvent, type FileChangeStatus, type FileChangedEvent, type FileHistoryEvent, type FileReviewStatus, HEADROOM_BACKEND_ENV, HEADROOM_EXTRAS_BY_SURFACE, HEADROOM_MODELS, HEADROOM_PIP_COMPANIONS, HEADROOM_PROXY_PORT, HEARTBEAT_INTERVAL_MS_DEFAULT, HOUSE_AGENT_ID, HOUSE_AGENT_NAME, HOUSE_AGENT_PROVIDER, HOUSE_AGENT_SUBTITLE, HOUSE_AGENT_VENDOR, type HeadroomBudgetCommand, type HeadroomBudgetPeriod, type HeadroomBudgetUsage, type HeadroomKind, type HeadroomModelSpec, type HeadroomPythonRenderOpts, type HeadroomStatus, type HeadroomSurface, type HunkLineType, INTERNAL_TO_PUBLIC, type InputSuggestionChunk, LINKED_AGENT_IDS, type LinkedAgentId, MODEL_CONTEXT_WINDOW, MODEL_PRICING, type ModelPricing, type NormalizedMessage, OBSERVER_BRIDGE_PORT, PREVIEW_DETECT_PROMPT, PROTOCOL_VERSION, PUBLIC_TO_INTERNAL, type PendingReviewHunkEvent, type PendingReviewHunkLine, type PreviewDetection, type PreviewErrorStage, type PreviewState, type PreviewStatus, type RemoteCommand, SSE_SOCKET_TIMEOUT_MS, type SelectPrompt, type StreamingChunkEvent, type StreamingChunkKind, TERMINAL_AGENT_PREFIX, USER_EVENTS, type UserEventName, getAgent, getContextWindow, getEnabledAgents, getPricing, headroomKindFor, headroomModelPredownloadScript, headroomPipPackage, headroomSnapshotDownloadLine, internalToPublic, isHeadroomWrappable, isKnownAgentId, isKnownModel, isLinkedAgentId, normalizeAgentId, publicToInternal, renderToLines, resolveApiBaseUrl, toRemoteCommand };