@codeam/shared 2.60.45 → 2.60.47
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.
- package/dist/index.d.mts +76 -1
- package/dist/index.d.ts +76 -1
- package/dist/index.js +55 -0
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +51 -0
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -319,6 +319,78 @@ declare function headroomKindFor(agentId: string): HeadroomKind | null;
|
|
|
319
319
|
*/
|
|
320
320
|
declare function isHeadroomWrappable(agentId: string): boolean;
|
|
321
321
|
|
|
322
|
+
/**
|
|
323
|
+
* Agent Toolkits — integration wire types.
|
|
324
|
+
* Spec: docs/superpowers/specs/2026-07-10-agent-toolkits-integrations-design.md
|
|
325
|
+
*
|
|
326
|
+
* Decision rule for the delivery rails: if the agent already masters a
|
|
327
|
+
* ubiquitous CLI for the tool → `cliEnv`; otherwise → `mcp`. A tool may
|
|
328
|
+
* declare both.
|
|
329
|
+
*/
|
|
330
|
+
type IntegrationId = 'jira';
|
|
331
|
+
type IntegrationAuthKind = 'oauth_redirect' | 'oauth_device' | 'api_key';
|
|
332
|
+
type IntegrationHealth = 'ok' | 'expired' | 'revoked';
|
|
333
|
+
/** stdio MCP server spec, executed as DATA by the CLI shim (`codeam mcp-run <id>`). */
|
|
334
|
+
interface IntegrationMcpDelivery {
|
|
335
|
+
command: string;
|
|
336
|
+
args: string[];
|
|
337
|
+
/** env var name → credential field (`accessToken` | `cloudId` | …). Env only, never argv. */
|
|
338
|
+
envMapping: Record<string, string>;
|
|
339
|
+
/** Static, non-credential env the server needs to boot (e.g. mode flags).
|
|
340
|
+
* Merged into the child env BENEATH the credential envMapping. Never secrets. */
|
|
341
|
+
staticEnv?: Record<string, string>;
|
|
342
|
+
}
|
|
343
|
+
interface IntegrationDelivery {
|
|
344
|
+
mcp?: IntegrationMcpDelivery;
|
|
345
|
+
/** env var name → credential field, merged into agent child spawns. No MVP consumer. */
|
|
346
|
+
cliEnv?: Record<string, string>;
|
|
347
|
+
}
|
|
348
|
+
interface IntegrationDefinition {
|
|
349
|
+
id: IntegrationId;
|
|
350
|
+
name: string;
|
|
351
|
+
icon: string;
|
|
352
|
+
enabled: boolean;
|
|
353
|
+
auth: {
|
|
354
|
+
kind: IntegrationAuthKind;
|
|
355
|
+
scopes?: string[];
|
|
356
|
+
};
|
|
357
|
+
delivery: IntegrationDelivery;
|
|
358
|
+
}
|
|
359
|
+
/** What a deploy writes to `~/.codeam/integrations.json` — manifests, never secrets. */
|
|
360
|
+
interface IntegrationsManifestEntry {
|
|
361
|
+
id: IntegrationId;
|
|
362
|
+
delivery: IntegrationDelivery;
|
|
363
|
+
}
|
|
364
|
+
interface IntegrationsManifest {
|
|
365
|
+
integrations: IntegrationsManifestEntry[];
|
|
366
|
+
}
|
|
367
|
+
/** `GET /api/integrations` row: registry definition merged with the user's link state. */
|
|
368
|
+
interface IntegrationStatus {
|
|
369
|
+
id: IntegrationId;
|
|
370
|
+
linked: boolean;
|
|
371
|
+
health?: IntegrationHealth;
|
|
372
|
+
siteUrl?: string;
|
|
373
|
+
accountEmail?: string;
|
|
374
|
+
linkedAt?: string;
|
|
375
|
+
}
|
|
376
|
+
/** `POST /api/plugin/integrations/:id/token` response — ~1 h access token, never a refresh token. */
|
|
377
|
+
interface BrokeredIntegrationToken {
|
|
378
|
+
accessToken: string;
|
|
379
|
+
expiresAt: string;
|
|
380
|
+
cloudId?: string;
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
/**
|
|
384
|
+
* The single source of truth for supported integrations. Adding one =
|
|
385
|
+
* 1 entry here + 1 backend OAuth provider + icon. The `delivery` spec is
|
|
386
|
+
* resolved into deploy manifests and executed as data by the CLI, so a new
|
|
387
|
+
* MCP integration with no special logic needs no CLI release.
|
|
388
|
+
*/
|
|
389
|
+
declare const INTEGRATION_REGISTRY: Record<IntegrationId, IntegrationDefinition>;
|
|
390
|
+
declare function getEnabledIntegrations(): IntegrationDefinition[];
|
|
391
|
+
declare function getIntegration(id: IntegrationId): IntegrationDefinition;
|
|
392
|
+
declare function isKnownIntegrationId(id: string): id is IntegrationId;
|
|
393
|
+
|
|
322
394
|
/**
|
|
323
395
|
* Wire-shape types for the CLI / IDE-plugin → backend producer endpoints
|
|
324
396
|
* that feed the mobile Files screen and the Pending Review Queue:
|
|
@@ -1118,6 +1190,9 @@ declare const USER_EVENTS: {
|
|
|
1118
1190
|
readonly CLI_UPDATE_PROGRESS: "cli_update_progress";
|
|
1119
1191
|
readonly CLI_UPDATE_FAILED: "cli_update_failed";
|
|
1120
1192
|
readonly BATON_STATE: "baton_state";
|
|
1193
|
+
readonly INTEGRATION_LINKED: "integration_linked";
|
|
1194
|
+
readonly INTEGRATION_UNLINKED: "integration_unlinked";
|
|
1195
|
+
readonly INTEGRATION_CREDENTIAL_INVALID: "integration_credential_invalid";
|
|
1121
1196
|
readonly CODERABBIT_PROGRESS: "coderabbit_progress";
|
|
1122
1197
|
readonly CODERABBIT_STATUS: "coderabbit_status";
|
|
1123
1198
|
readonly CODERABBIT_REVIEW: "coderabbit_review";
|
|
@@ -1136,4 +1211,4 @@ type UserEventName = (typeof USER_EVENTS)[keyof typeof USER_EVENTS];
|
|
|
1136
1211
|
*/
|
|
1137
1212
|
declare const PREVIEW_DETECT_PROMPT: string;
|
|
1138
1213
|
|
|
1139
|
-
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 HeadroomStep, 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, UNKNOWN_MODEL_PRICING, USER_EVENTS, type UserEventName, getAgent, getContextWindow, getEnabledAgents, getPricing, headroomKindFor, headroomModelPredownloadScript, headroomPipPackage, headroomSnapshotDownloadLine, internalToPublic, isHeadroomWrappable, isKnownAgentId, isKnownModel, isLinkedAgentId, normalizeAgentId, publicToInternal, renderToLines, resolveApiBaseUrl, toRemoteCommand };
|
|
1214
|
+
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 BrokeredIntegrationToken, 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 HeadroomStep, type HeadroomSurface, type HunkLineType, INTEGRATION_REGISTRY, INTERNAL_TO_PUBLIC, type InputSuggestionChunk, type IntegrationAuthKind, type IntegrationDefinition, type IntegrationDelivery, type IntegrationHealth, type IntegrationId, type IntegrationMcpDelivery, type IntegrationStatus, type IntegrationsManifest, type IntegrationsManifestEntry, 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, UNKNOWN_MODEL_PRICING, USER_EVENTS, type UserEventName, getAgent, getContextWindow, getEnabledAgents, getEnabledIntegrations, getIntegration, getPricing, headroomKindFor, headroomModelPredownloadScript, headroomPipPackage, headroomSnapshotDownloadLine, internalToPublic, isHeadroomWrappable, isKnownAgentId, isKnownIntegrationId, isKnownModel, isLinkedAgentId, normalizeAgentId, publicToInternal, renderToLines, resolveApiBaseUrl, toRemoteCommand };
|
package/dist/index.d.ts
CHANGED
|
@@ -319,6 +319,78 @@ declare function headroomKindFor(agentId: string): HeadroomKind | null;
|
|
|
319
319
|
*/
|
|
320
320
|
declare function isHeadroomWrappable(agentId: string): boolean;
|
|
321
321
|
|
|
322
|
+
/**
|
|
323
|
+
* Agent Toolkits — integration wire types.
|
|
324
|
+
* Spec: docs/superpowers/specs/2026-07-10-agent-toolkits-integrations-design.md
|
|
325
|
+
*
|
|
326
|
+
* Decision rule for the delivery rails: if the agent already masters a
|
|
327
|
+
* ubiquitous CLI for the tool → `cliEnv`; otherwise → `mcp`. A tool may
|
|
328
|
+
* declare both.
|
|
329
|
+
*/
|
|
330
|
+
type IntegrationId = 'jira';
|
|
331
|
+
type IntegrationAuthKind = 'oauth_redirect' | 'oauth_device' | 'api_key';
|
|
332
|
+
type IntegrationHealth = 'ok' | 'expired' | 'revoked';
|
|
333
|
+
/** stdio MCP server spec, executed as DATA by the CLI shim (`codeam mcp-run <id>`). */
|
|
334
|
+
interface IntegrationMcpDelivery {
|
|
335
|
+
command: string;
|
|
336
|
+
args: string[];
|
|
337
|
+
/** env var name → credential field (`accessToken` | `cloudId` | …). Env only, never argv. */
|
|
338
|
+
envMapping: Record<string, string>;
|
|
339
|
+
/** Static, non-credential env the server needs to boot (e.g. mode flags).
|
|
340
|
+
* Merged into the child env BENEATH the credential envMapping. Never secrets. */
|
|
341
|
+
staticEnv?: Record<string, string>;
|
|
342
|
+
}
|
|
343
|
+
interface IntegrationDelivery {
|
|
344
|
+
mcp?: IntegrationMcpDelivery;
|
|
345
|
+
/** env var name → credential field, merged into agent child spawns. No MVP consumer. */
|
|
346
|
+
cliEnv?: Record<string, string>;
|
|
347
|
+
}
|
|
348
|
+
interface IntegrationDefinition {
|
|
349
|
+
id: IntegrationId;
|
|
350
|
+
name: string;
|
|
351
|
+
icon: string;
|
|
352
|
+
enabled: boolean;
|
|
353
|
+
auth: {
|
|
354
|
+
kind: IntegrationAuthKind;
|
|
355
|
+
scopes?: string[];
|
|
356
|
+
};
|
|
357
|
+
delivery: IntegrationDelivery;
|
|
358
|
+
}
|
|
359
|
+
/** What a deploy writes to `~/.codeam/integrations.json` — manifests, never secrets. */
|
|
360
|
+
interface IntegrationsManifestEntry {
|
|
361
|
+
id: IntegrationId;
|
|
362
|
+
delivery: IntegrationDelivery;
|
|
363
|
+
}
|
|
364
|
+
interface IntegrationsManifest {
|
|
365
|
+
integrations: IntegrationsManifestEntry[];
|
|
366
|
+
}
|
|
367
|
+
/** `GET /api/integrations` row: registry definition merged with the user's link state. */
|
|
368
|
+
interface IntegrationStatus {
|
|
369
|
+
id: IntegrationId;
|
|
370
|
+
linked: boolean;
|
|
371
|
+
health?: IntegrationHealth;
|
|
372
|
+
siteUrl?: string;
|
|
373
|
+
accountEmail?: string;
|
|
374
|
+
linkedAt?: string;
|
|
375
|
+
}
|
|
376
|
+
/** `POST /api/plugin/integrations/:id/token` response — ~1 h access token, never a refresh token. */
|
|
377
|
+
interface BrokeredIntegrationToken {
|
|
378
|
+
accessToken: string;
|
|
379
|
+
expiresAt: string;
|
|
380
|
+
cloudId?: string;
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
/**
|
|
384
|
+
* The single source of truth for supported integrations. Adding one =
|
|
385
|
+
* 1 entry here + 1 backend OAuth provider + icon. The `delivery` spec is
|
|
386
|
+
* resolved into deploy manifests and executed as data by the CLI, so a new
|
|
387
|
+
* MCP integration with no special logic needs no CLI release.
|
|
388
|
+
*/
|
|
389
|
+
declare const INTEGRATION_REGISTRY: Record<IntegrationId, IntegrationDefinition>;
|
|
390
|
+
declare function getEnabledIntegrations(): IntegrationDefinition[];
|
|
391
|
+
declare function getIntegration(id: IntegrationId): IntegrationDefinition;
|
|
392
|
+
declare function isKnownIntegrationId(id: string): id is IntegrationId;
|
|
393
|
+
|
|
322
394
|
/**
|
|
323
395
|
* Wire-shape types for the CLI / IDE-plugin → backend producer endpoints
|
|
324
396
|
* that feed the mobile Files screen and the Pending Review Queue:
|
|
@@ -1118,6 +1190,9 @@ declare const USER_EVENTS: {
|
|
|
1118
1190
|
readonly CLI_UPDATE_PROGRESS: "cli_update_progress";
|
|
1119
1191
|
readonly CLI_UPDATE_FAILED: "cli_update_failed";
|
|
1120
1192
|
readonly BATON_STATE: "baton_state";
|
|
1193
|
+
readonly INTEGRATION_LINKED: "integration_linked";
|
|
1194
|
+
readonly INTEGRATION_UNLINKED: "integration_unlinked";
|
|
1195
|
+
readonly INTEGRATION_CREDENTIAL_INVALID: "integration_credential_invalid";
|
|
1121
1196
|
readonly CODERABBIT_PROGRESS: "coderabbit_progress";
|
|
1122
1197
|
readonly CODERABBIT_STATUS: "coderabbit_status";
|
|
1123
1198
|
readonly CODERABBIT_REVIEW: "coderabbit_review";
|
|
@@ -1136,4 +1211,4 @@ type UserEventName = (typeof USER_EVENTS)[keyof typeof USER_EVENTS];
|
|
|
1136
1211
|
*/
|
|
1137
1212
|
declare const PREVIEW_DETECT_PROMPT: string;
|
|
1138
1213
|
|
|
1139
|
-
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 HeadroomStep, 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, UNKNOWN_MODEL_PRICING, USER_EVENTS, type UserEventName, getAgent, getContextWindow, getEnabledAgents, getPricing, headroomKindFor, headroomModelPredownloadScript, headroomPipPackage, headroomSnapshotDownloadLine, internalToPublic, isHeadroomWrappable, isKnownAgentId, isKnownModel, isLinkedAgentId, normalizeAgentId, publicToInternal, renderToLines, resolveApiBaseUrl, toRemoteCommand };
|
|
1214
|
+
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 BrokeredIntegrationToken, 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 HeadroomStep, type HeadroomSurface, type HunkLineType, INTEGRATION_REGISTRY, INTERNAL_TO_PUBLIC, type InputSuggestionChunk, type IntegrationAuthKind, type IntegrationDefinition, type IntegrationDelivery, type IntegrationHealth, type IntegrationId, type IntegrationMcpDelivery, type IntegrationStatus, type IntegrationsManifest, type IntegrationsManifestEntry, 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, UNKNOWN_MODEL_PRICING, USER_EVENTS, type UserEventName, getAgent, getContextWindow, getEnabledAgents, getEnabledIntegrations, getIntegration, getPricing, headroomKindFor, headroomModelPredownloadScript, headroomPipPackage, headroomSnapshotDownloadLine, internalToPublic, isHeadroomWrappable, isKnownAgentId, isKnownIntegrationId, isKnownModel, isLinkedAgentId, normalizeAgentId, publicToInternal, renderToLines, resolveApiBaseUrl, toRemoteCommand };
|
package/dist/index.js
CHANGED
|
@@ -34,6 +34,7 @@ __export(index_exports, {
|
|
|
34
34
|
HOUSE_AGENT_PROVIDER: () => HOUSE_AGENT_PROVIDER,
|
|
35
35
|
HOUSE_AGENT_SUBTITLE: () => HOUSE_AGENT_SUBTITLE,
|
|
36
36
|
HOUSE_AGENT_VENDOR: () => HOUSE_AGENT_VENDOR,
|
|
37
|
+
INTEGRATION_REGISTRY: () => INTEGRATION_REGISTRY,
|
|
37
38
|
INTERNAL_TO_PUBLIC: () => INTERNAL_TO_PUBLIC,
|
|
38
39
|
LINKED_AGENT_IDS: () => LINKED_AGENT_IDS,
|
|
39
40
|
MODEL_CONTEXT_WINDOW: () => MODEL_CONTEXT_WINDOW,
|
|
@@ -49,6 +50,8 @@ __export(index_exports, {
|
|
|
49
50
|
getAgent: () => getAgent,
|
|
50
51
|
getContextWindow: () => getContextWindow,
|
|
51
52
|
getEnabledAgents: () => getEnabledAgents,
|
|
53
|
+
getEnabledIntegrations: () => getEnabledIntegrations,
|
|
54
|
+
getIntegration: () => getIntegration,
|
|
52
55
|
getPricing: () => getPricing,
|
|
53
56
|
headroomKindFor: () => headroomKindFor,
|
|
54
57
|
headroomModelPredownloadScript: () => headroomModelPredownloadScript,
|
|
@@ -57,6 +60,7 @@ __export(index_exports, {
|
|
|
57
60
|
internalToPublic: () => internalToPublic,
|
|
58
61
|
isHeadroomWrappable: () => isHeadroomWrappable,
|
|
59
62
|
isKnownAgentId: () => isKnownAgentId,
|
|
63
|
+
isKnownIntegrationId: () => isKnownIntegrationId,
|
|
60
64
|
isKnownModel: () => isKnownModel,
|
|
61
65
|
isLinkedAgentId: () => isLinkedAgentId,
|
|
62
66
|
normalizeAgentId: () => normalizeAgentId,
|
|
@@ -517,6 +521,50 @@ function isHeadroomWrappable(agentId) {
|
|
|
517
521
|
return headroomKindFor(agentId) !== null;
|
|
518
522
|
}
|
|
519
523
|
|
|
524
|
+
// src/integrations/registry.ts
|
|
525
|
+
var INTEGRATION_REGISTRY = {
|
|
526
|
+
jira: {
|
|
527
|
+
id: "jira",
|
|
528
|
+
name: "Jira",
|
|
529
|
+
icon: "jira",
|
|
530
|
+
enabled: true,
|
|
531
|
+
auth: {
|
|
532
|
+
kind: "oauth_redirect",
|
|
533
|
+
scopes: ["read:jira-work", "write:jira-work", "offline_access"]
|
|
534
|
+
},
|
|
535
|
+
delivery: {
|
|
536
|
+
mcp: {
|
|
537
|
+
// mcp-atlassian in BYO-token mode (headless; credentials via env only).
|
|
538
|
+
// Version PINNED to the exact release verified headless by Plan 2's
|
|
539
|
+
// Docker integration test (apps/cli mcp-shim.int.test.ts).
|
|
540
|
+
command: "uvx",
|
|
541
|
+
args: ["mcp-atlassian==0.22.1"],
|
|
542
|
+
envMapping: {
|
|
543
|
+
ATLASSIAN_OAUTH_ACCESS_TOKEN: "accessToken",
|
|
544
|
+
ATLASSIAN_OAUTH_CLOUD_ID: "cloudId"
|
|
545
|
+
},
|
|
546
|
+
// Without ATLASSIAN_OAUTH_ENABLE=true, JiraConfig.from_env() raises
|
|
547
|
+
// "Missing required JIRA_URL" (swallowed at server startup) and the
|
|
548
|
+
// server silently registers ZERO Jira tools. The flag activates
|
|
549
|
+
// mcp-atlassian's "minimal OAuth config for user-provided tokens"
|
|
550
|
+
// mode — the BYO-token path the broker feeds. Static + non-secret.
|
|
551
|
+
staticEnv: { ATLASSIAN_OAUTH_ENABLE: "true" }
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
}
|
|
555
|
+
};
|
|
556
|
+
function getEnabledIntegrations() {
|
|
557
|
+
return Object.values(INTEGRATION_REGISTRY).filter((m) => m.enabled);
|
|
558
|
+
}
|
|
559
|
+
function getIntegration(id) {
|
|
560
|
+
const meta = INTEGRATION_REGISTRY[id];
|
|
561
|
+
if (!meta) throw new Error(`Unknown integration id: ${id}`);
|
|
562
|
+
return meta;
|
|
563
|
+
}
|
|
564
|
+
function isKnownIntegrationId(id) {
|
|
565
|
+
return id in INTEGRATION_REGISTRY;
|
|
566
|
+
}
|
|
567
|
+
|
|
520
568
|
// src/api-url.ts
|
|
521
569
|
var DEFAULT_API_BASE_URL = "https://api.codeagent-mobile.com";
|
|
522
570
|
var DEV_API_BASE_URL = "https://dev-api.codeagent-mobile.com";
|
|
@@ -638,6 +686,9 @@ var USER_EVENTS = {
|
|
|
638
686
|
CLI_UPDATE_PROGRESS: "cli_update_progress",
|
|
639
687
|
CLI_UPDATE_FAILED: "cli_update_failed",
|
|
640
688
|
BATON_STATE: "baton_state",
|
|
689
|
+
INTEGRATION_LINKED: "integration_linked",
|
|
690
|
+
INTEGRATION_UNLINKED: "integration_unlinked",
|
|
691
|
+
INTEGRATION_CREDENTIAL_INVALID: "integration_credential_invalid",
|
|
641
692
|
// CodeRabbit reviewer — the CLI posts these to /api/coderabbit/events; the
|
|
642
693
|
// backend re-publishes them on the per-user SSE bus (mirrored in repo A).
|
|
643
694
|
CODERABBIT_PROGRESS: "coderabbit_progress",
|
|
@@ -707,6 +758,7 @@ OUTPUT JSON ONLY. NO MARKDOWN. NO COMMENTARY.
|
|
|
707
758
|
HOUSE_AGENT_PROVIDER,
|
|
708
759
|
HOUSE_AGENT_SUBTITLE,
|
|
709
760
|
HOUSE_AGENT_VENDOR,
|
|
761
|
+
INTEGRATION_REGISTRY,
|
|
710
762
|
INTERNAL_TO_PUBLIC,
|
|
711
763
|
LINKED_AGENT_IDS,
|
|
712
764
|
MODEL_CONTEXT_WINDOW,
|
|
@@ -722,6 +774,8 @@ OUTPUT JSON ONLY. NO MARKDOWN. NO COMMENTARY.
|
|
|
722
774
|
getAgent,
|
|
723
775
|
getContextWindow,
|
|
724
776
|
getEnabledAgents,
|
|
777
|
+
getEnabledIntegrations,
|
|
778
|
+
getIntegration,
|
|
725
779
|
getPricing,
|
|
726
780
|
headroomKindFor,
|
|
727
781
|
headroomModelPredownloadScript,
|
|
@@ -730,6 +784,7 @@ OUTPUT JSON ONLY. NO MARKDOWN. NO COMMENTARY.
|
|
|
730
784
|
internalToPublic,
|
|
731
785
|
isHeadroomWrappable,
|
|
732
786
|
isKnownAgentId,
|
|
787
|
+
isKnownIntegrationId,
|
|
733
788
|
isKnownModel,
|
|
734
789
|
isLinkedAgentId,
|
|
735
790
|
normalizeAgentId,
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/protocol/constants.ts","../src/protocol/renderToLines.ts","../src/protocol/remote-command.ts","../src/models/pricing.ts","../src/agents/registry.ts","../src/agents/identity.ts","../src/api-url.ts","../src/headroom/manifest.ts","../src/types/events.ts","../src/preview-prompts.ts"],"sourcesContent":["export * from './protocol/chrome-types';\nexport * from './protocol/constants';\nexport * from './protocol/renderToLines';\nexport * from './protocol/remote-command';\nexport * from './models/pricing';\nexport * from './agents';\nexport * from './types/file-change';\nexport * from './types/streaming';\nexport * from './api-url';\nexport * from './types/preview';\nexport * from './types/beads';\nexport * from './types/headroom';\nexport * from './headroom/manifest';\nexport * from './types/events';\nexport * from './preview-prompts';\n","/**\n * Shared wire / lifecycle constants. The values here are bundled\n * into the CLI + VS Code extension at build time via tsup / esbuild\n * and mirrored in `apps/jetbrains-plugin/.../protocol/Constants.kt`\n * since Kotlin can't import an npm package.\n *\n * If you change one of these values, also update the Kotlin mirror.\n */\n\n/**\n * Discriminated chunk-protocol version sent as the\n * `X-Codeam-Protocol-Version` header on every authed request. The\n * backend uses this to opt into legacy translations or to reject\n * with 426 when the client is too far behind. Bumped in lockstep\n * with chunk-shape changes (e.g. when the `chrome_steps` chunk\n * type is added).\n */\nexport const PROTOCOL_VERSION = '2.0.0' as const;\n\n/**\n * The VS Code AgentOutputMonitor's loopback HTTP server bound to\n * 127.0.0.1 on this port — the observer JS in the IDE renderer\n * uses it to round-trip captured chat content back into the\n * extension host. The port is intentionally fixed (rather than\n * `listen(0)`) so the observer script can be a static constant\n * rather than dynamically rewriting itself per session.\n *\n * Multi-window collision is solved by listen(0) per-window in the\n * monitor (see #103); this default is still the documented\n * starting port for tooling that needs to probe whether a CodeAgent\n * Mobile session is active locally.\n */\nexport const OBSERVER_BRIDGE_PORT = 47832;\n\n/**\n * Default plugin → backend heartbeat interval. User-configurable\n * via `codeagent-mobile.heartbeatIntervalMs` on VS Code and\n * `heartbeatIntervalMs` in SettingsService.kt's @State on JetBrains.\n * Mirrors the value the apps/api side uses to flip the paired\n * session to offline.\n */\nexport const HEARTBEAT_INTERVAL_MS_DEFAULT = 30_000;\n\n/**\n * SSE + polling reconnect cap. Vercel's serverless functions close\n * SSE connections after ~25 s by default; the client uses 35 s as\n * its overall socket timeout to leave a beat for graceful close.\n */\nexport const SSE_SOCKET_TIMEOUT_MS = 35_000;\n","/**\n * Render raw PTY bytes into an array of screen lines using a simplified\n * virtual terminal. Handles cursor movements (A/B/C/D/G/H), erase (J/K),\n * alternate-screen (?1049h), carriage return, and LF.\n *\n * This is the authoritative implementation used by both codeam-cli (PTY\n * output) and the VS Code extension (shell-integration output) so that\n * the mobile/web client sees identical chunks regardless of surface.\n */\nexport function renderToLines(raw: string): string[] {\n const screen: string[] = [''];\n let row = 0;\n let col = 0;\n\n function ensureRow(): void {\n while (screen.length <= row) screen.push('');\n }\n\n function writeChar(ch: string): void {\n ensureRow();\n if (col < screen[row].length) {\n screen[row] = screen[row].slice(0, col) + ch + screen[row].slice(col + 1);\n } else {\n while (screen[row].length < col) screen[row] += ' ';\n screen[row] += ch;\n }\n col++;\n }\n\n let i = 0;\n while (i < raw.length) {\n const ch = raw[i];\n\n if (ch === '\\x1B') {\n i++;\n if (i >= raw.length) break;\n\n if (raw[i] === '[') {\n i++;\n let param = '';\n while (i < raw.length && !/[@-~]/.test(raw[i])) param += raw[i++];\n const cmd = raw[i] ?? '';\n const n = parseInt(param) || 1;\n\n if (cmd === 'A') { row = Math.max(0, row - n); }\n else if (cmd === 'B') { row += n; ensureRow(); }\n else if (cmd === 'C') { col += n; }\n else if (cmd === 'D') { col = Math.max(0, col - n); }\n else if (cmd === 'G') { col = Math.max(0, n - 1); }\n else if (cmd === 'H' || cmd === 'f') {\n const p = param.split(';');\n row = Math.max(0, (parseInt(p[0] ?? '1') || 1) - 1);\n col = Math.max(0, (parseInt(p[1] ?? '1') || 1) - 1);\n ensureRow();\n } else if (cmd === 'J') {\n if (param === '2' || param === '3') {\n screen.length = 1; screen[0] = ''; row = 0; col = 0;\n } else if (param === '1') {\n for (let r = 0; r < row; r++) screen[r] = '';\n screen[row] = ' '.repeat(col) + screen[row].slice(col);\n } else {\n screen[row] = screen[row].slice(0, col);\n screen.splice(row + 1);\n }\n } else if (cmd === 'K') {\n ensureRow();\n if (param === '' || param === '0') screen[row] = screen[row].slice(0, col);\n else if (param === '1') screen[row] = ' '.repeat(col) + screen[row].slice(col);\n else if (param === '2') screen[row] = '';\n } else if (cmd === 'h' && (param === '?1049' || param === '?47')) {\n screen.length = 1; screen[0] = ''; row = 0; col = 0;\n } else if (cmd === 'l' && (param === '?1049' || param === '?47')) {\n screen.length = 1; screen[0] = ''; row = 0; col = 0;\n }\n } else if (raw[i] === ']') {\n i++;\n while (i < raw.length) {\n if (raw[i] === '\\x07') break;\n if (raw[i] === '\\x1B' && i + 1 < raw.length && raw[i + 1] === '\\\\') { i++; break; }\n i++;\n }\n }\n } else if (ch === '\\r') {\n if (i + 1 < raw.length && raw[i + 1] === '\\n') {\n row++; col = 0; ensureRow(); i++;\n } else {\n col = 0;\n }\n } else if (ch === '\\n') {\n row++; col = 0; ensureRow();\n } else if (ch >= ' ' || ch === '\\t') {\n writeChar(ch);\n }\n\n i++;\n }\n\n return screen;\n}\n","import { z } from 'zod';\n\n/**\n * The command envelope clients receive from the backend relay — both from\n * the `commands` SSE frames on `/api/commands/pending/stream` and from the\n * `GET /api/commands/pending` polling fallback. One schema, shared, so the\n * VS Code extension (and eventually the CLI) stop blind-casting\n * `Record<string, unknown>` into this shape.\n */\nexport interface RemoteCommand {\n id: string;\n sessionId: string;\n pluginId: string;\n type: string;\n payload: Record<string, unknown>;\n status: string;\n createdAt: number;\n}\n\nconst remoteCommandSchema = z.object({\n id: z.string(),\n sessionId: z.string(),\n pluginId: z.string(),\n type: z.string(),\n // The backend may omit `payload` (or send null) for payload-less commands;\n // clients have always normalized that to `{}` — keep that behavior here.\n payload: z.record(z.string(), z.unknown()).nullish(),\n status: z.string(),\n createdAt: z.number(),\n});\n\n/**\n * Validate a raw (already JSON-parsed) value into a `RemoteCommand`.\n * Returns `null` — never throws — on a malformed envelope so callers can\n * log-and-skip the single bad command without dropping the whole batch.\n */\nexport function toRemoteCommand(raw: unknown): RemoteCommand | null {\n const parsed = remoteCommandSchema.safeParse(raw);\n if (!parsed.success) return null;\n const { payload, ...rest } = parsed.data;\n return { ...rest, payload: payload ?? {} };\n}\n","export interface ModelPricing {\n input: number;\n output: number;\n cacheRead: number;\n cacheWrite: number;\n}\n\nexport const MODEL_PRICING: Record<string, ModelPricing> = {\n // ── Anthropic / Claude ────────────────────────────────────\n // The 4.x rows below cover the model ids actually emitted by the CLI\n // (apps/cli/src/agents/claude/runtime.ts listModels) and the JetBrains\n // fallback catalog (RemoteCommandRouter.kt). Prices are copied from the\n // same-family base rows (claude-opus-4 / claude-sonnet-4 /\n // claude-3-5-haiku) until distinct published rates land.\n 'claude-opus-4-7': { input: 15, output: 75, cacheRead: 1.50, cacheWrite: 18.75 },\n 'claude-opus-4-6': { input: 15, output: 75, cacheRead: 1.50, cacheWrite: 18.75 },\n 'claude-sonnet-4-6': { input: 3, output: 15, cacheRead: 0.30, cacheWrite: 3.75 },\n // Haiku-tier prices copied from claude-3-5-haiku (closest same-tier\n // sibling in this table) — previously this id matched NO row and was\n // silently billed at sonnet rates via the unknown-model fallback.\n 'claude-haiku-4-5': { input: 0.80, output: 4, cacheRead: 0.08, cacheWrite: 1 },\n 'claude-sonnet-4': { input: 3, output: 15, cacheRead: 0.30, cacheWrite: 3.75 },\n 'claude-opus-4': { input: 15, output: 75, cacheRead: 1.50, cacheWrite: 18.75 },\n 'claude-3-5-sonnet': { input: 3, output: 15, cacheRead: 0.30, cacheWrite: 3.75 },\n 'claude-3-5-haiku': { input: 0.80, output: 4, cacheRead: 0.08, cacheWrite: 1 },\n 'claude-3-haiku': { input: 0.25, output: 1.25, cacheRead: 0.03, cacheWrite: 0.30 },\n\n // ── Codex / OpenAI ────────────────────────────────────────\n // GPT-5.x rows are derived from OpenAI's published GPT-5 family rates\n // (standard tier: $1.25/1M in, $10/1M out, cached input at ~10% of input;\n // mini tier: $0.25/1M in, $2/1M out). OpenAI has no separate cache-WRITE\n // premium, so cacheWrite mirrors the input rate. Replace with the exact\n // per-version numbers from developers.openai.com/pricing when published —\n // these were the ZERO placeholders that rendered Codex sessions as $0.\n 'gpt-5.5': { input: 1.25, output: 10, cacheRead: 0.125, cacheWrite: 1.25 },\n 'gpt-5.4': { input: 1.25, output: 10, cacheRead: 0.125, cacheWrite: 1.25 },\n 'gpt-5.4-mini': { input: 0.25, output: 2, cacheRead: 0.025, cacheWrite: 0.25 },\n 'gpt-5.3-codex': { input: 1.25, output: 10, cacheRead: 0.125, cacheWrite: 1.25 },\n 'gpt-5.2': { input: 1.25, output: 10, cacheRead: 0.125, cacheWrite: 1.25 },\n 'codex-auto-review': { input: 1.25, output: 10, cacheRead: 0.125, cacheWrite: 1.25 },\n};\n\nexport const MODEL_CONTEXT_WINDOW: Record<string, number> = {\n // ── Anthropic / Claude ────────────────────────────────────\n 'claude-opus-4-7': 1_000_000,\n 'claude-opus-4-6': 1_000_000,\n 'claude-sonnet-4-6': 1_000_000,\n 'claude-haiku-4-5': 200_000,\n 'claude-opus-4': 1_000_000,\n 'claude-sonnet-4': 1_000_000,\n 'claude-3-5-sonnet': 200_000,\n 'claude-3-5-haiku': 200_000,\n 'claude-3-haiku': 200_000,\n\n // ── Codex / OpenAI ────────────────────────────────────────\n 'gpt-5.5': 272_000,\n 'gpt-5.4': 272_000,\n 'gpt-5.4-mini': 272_000,\n 'gpt-5.3-codex': 272_000,\n 'gpt-5.2': 272_000,\n 'codex-auto-review': 272_000,\n};\n\nconst DEFAULT_CONTEXT_WINDOW = 200_000;\n\n/**\n * Longest-prefix lookup. The tables key by model-family prefix; a model id\n * like `claude-opus-4-7` must resolve to its own row, not be shadowed by the\n * shorter `claude-opus-4` — so the match is by prefix LENGTH, never by the\n * table's insertion order.\n */\nfunction longestPrefixMatch<T>(table: Record<string, T>, model: string): T | undefined {\n let best: T | undefined;\n let bestLen = -1;\n for (const [prefix, value] of Object.entries(table)) {\n if (prefix.length > bestLen && model.startsWith(prefix)) {\n best = value;\n bestLen = prefix.length;\n }\n }\n return best;\n}\n\n/** True when the model id resolves to a real MODEL_PRICING row (i.e. getPricing\n * will NOT be guessing via the unknown-model fallback). */\nexport function isKnownModel(model: string): boolean {\n return longestPrefixMatch(MODEL_PRICING, model) !== undefined;\n}\n\n/**\n * Flagged default for an unpriced model id. All-zero so an unknown model is\n * VISIBLY unpriced ($0) rather than silently MISPRICED at some other family's\n * rates (the old sonnet-4 fallback billed unknown ids — including a haiku id\n * that matched no row — at sonnet rates). `getPricing` returns this object for\n * unknown ids so callers that do unconditional arithmetic still work; callers\n * that must distinguish real pricing from the default check `isKnownModel`.\n */\nexport const UNKNOWN_MODEL_PRICING: ModelPricing = {\n input: 0,\n output: 0,\n cacheRead: 0,\n cacheWrite: 0,\n};\n\n/**\n * Resolve pricing by longest matching prefix. Unknown models resolve to the\n * flagged {@link UNKNOWN_MODEL_PRICING} default (all-zero, i.e. visibly\n * unpriced) instead of guessing at another model's rates. Callers that need to\n * distinguish real pricing from the default must check `isKnownModel(model)`.\n */\nexport function getPricing(model: string): ModelPricing {\n return longestPrefixMatch(MODEL_PRICING, model) ?? UNKNOWN_MODEL_PRICING;\n}\n\nexport function getContextWindow(model: string | null): number {\n if (!model) return DEFAULT_CONTEXT_WINDOW;\n return longestPrefixMatch(MODEL_CONTEXT_WINDOW, model) ?? DEFAULT_CONTEXT_WINDOW;\n}\n","import type { AgentId, AgentMetadata } from './types';\n\nexport const AGENT_REGISTRY: Record<AgentId, AgentMetadata> = {\n claude: {\n id: 'claude',\n displayName: 'Claude Code',\n binaryName: 'claude',\n enabled: true,\n // Mirrors the backend registry (codeagent-mobile\n // apps/api-v2/src/codespaces/agent.ts — authoritative for auth\n // capabilities). `setup_token` is the bare `sk-ant-oat01-…` from\n // `claude setup-token` → delivered via CLAUDE_CODE_OAUTH_TOKEN.\n supportedAuthKinds: ['setup_token', 'oauth_token', 'api_key'],\n preferredAuthKind: 'setup_token',\n headroomWrappable: true,\n headroomKind: 'claude',\n // npm adapter `@agentclientprotocol/claude-agent-acp`.\n acp: true,\n },\n codex: {\n id: 'codex',\n displayName: 'Codex CLI',\n binaryName: 'codex',\n enabled: true,\n supportedAuthKinds: ['oauth_token', 'api_key'],\n preferredAuthKind: 'oauth_token',\n headroomWrappable: true,\n headroomKind: 'codex',\n // npm adapter `@agentclientprotocol/codex-acp`.\n acp: true,\n // OAuth device-code flow; the user_code on the OpenAI page IS a real\n // human-typed code — surfaces render it (with a copy affordance).\n deviceFlow: true,\n showsUserCode: true,\n },\n copilot: {\n id: 'copilot',\n displayName: 'GitHub Copilot CLI',\n binaryName: 'gh',\n enabled: false,\n supportedAuthKinds: ['oauth_token'],\n preferredAuthKind: 'oauth_token',\n // `headroom init --global copilot` exists even though the agent is\n // still disabled here (no runtime builder yet).\n headroomWrappable: true,\n headroomKind: 'copilot',\n acp: false,\n },\n coderabbit: {\n id: 'coderabbit',\n displayName: 'CodeRabbit',\n binaryName: 'coderabbit',\n enabled: true,\n // CodeRabbit links via a CLI-driven LOOPBACK OAuth (`coderabbit auth\n // login --agent`): the CLI captures the token and hands it to the vault\n // through `linkFromCli` (method:'oauth'), same as the terminal handoff.\n // `oauth_token` is preferred; a real API key is still accepted as a\n // fallback. There is no backend PKCE provider — the loopback runs on the\n // user's own machine, so linking is always CLI-mediated.\n supportedAuthKinds: ['oauth_token', 'api_key'],\n preferredAuthKind: 'oauth_token',\n headroomWrappable: false,\n // Legacy PTY runtime — no ACP adapter registered.\n acp: false,\n },\n cursor: {\n id: 'cursor',\n displayName: 'Cursor Agent',\n binaryName: 'cursor-agent',\n enabled: true,\n // Backend registry is authoritative: since the Cursor OAuth\n // device-flow shipped, new links are oauth_token only (the login\n // blob written to ~/.config/cursor/auth.json). Legacy vaulted\n // api_key rows may still exist server-side, but the link surface\n // no longer offers api_key.\n supportedAuthKinds: ['oauth_token'],\n preferredAuthKind: 'oauth_token',\n // `headroom wrap cursor` is \"manual/print-only\" (IDE settings; the\n // headless cursor-agent CLI has no base-URL override) — runs native.\n headroomWrappable: false,\n // Native ACP server: `cursor-agent acp`.\n acp: true,\n // Reverse-engineered device/poll flow; `userCode` is the secret PKCE\n // verifier echoed back on poll — NEVER human-facing.\n deviceFlow: true,\n showsUserCode: false,\n },\n aider: {\n id: 'aider',\n displayName: 'Aider',\n binaryName: 'aider',\n enabled: true,\n // Aider is OAuth-less — auth is via ANTHROPIC_API_KEY / OPENAI_API_KEY\n // / etc. env vars or `~/.aider.conf.yml`. The link flow surfaces\n // this via the existing --api-key escape hatch in commands/link.ts.\n supportedAuthKinds: ['api_key'],\n preferredAuthKind: 'api_key',\n headroomWrappable: false,\n // Legacy PTY runtime — no ACP adapter registered.\n acp: false,\n },\n gemini: {\n id: 'gemini',\n displayName: 'Gemini CLI',\n binaryName: 'gemini',\n enabled: true,\n // OAuth via `gemini auth login` (captured by `codeam link gemini`\n // from ~/.gemini/oauth_creds.json) AND GEMINI_API_KEY are both\n // accepted by the backend's GeminiProvisioningStrategy and propagated\n // into codespace deploys.\n supportedAuthKinds: ['oauth_token', 'api_key'],\n preferredAuthKind: 'oauth_token',\n // Not listed by `headroom wrap --help` — runs native.\n headroomWrappable: false,\n // Native ACP server: `gemini --skip-trust --acp`.\n acp: true,\n },\n kimi: {\n id: 'kimi',\n displayName: 'Kimi Code',\n binaryName: 'kimi',\n enabled: true,\n // API key (KIMI_API_KEY, + optional KIMI_BASE_URL) is the shipping auth —\n // fully documented, no reverse-engineering. OAuth `/login` (login-state at\n // ~/.kimi-code/credentials/<name>.json, base https://api.kimi.com/coding/)\n // is declared so it can land later without a wire change, but capturing\n // that blob server-side is a separate reverse-engineering spike (phase 2).\n supportedAuthKinds: ['api_key', 'oauth_token'],\n preferredAuthKind: 'api_key',\n // Moonshot's `kimi` is not listed by `headroom wrap --help` — runs native.\n headroomWrappable: false,\n // Native ACP server: `kimi acp` (stdio JSON-RPC, answers `initialize`).\n acp: true,\n },\n};\n\nexport function getEnabledAgents(): AgentMetadata[] {\n return Object.values(AGENT_REGISTRY).filter(m => m.enabled);\n}\n\nexport function getAgent(id: AgentId): AgentMetadata {\n const meta = AGENT_REGISTRY[id];\n if (!meta) throw new Error(`Unknown agent id: ${id}`);\n return meta;\n}\n\nexport function isKnownAgentId(id: string): id is AgentId {\n return id in AGENT_REGISTRY;\n}\n","/**\n * Agent identity — the ONE place the public (`LinkedAgentId`) and internal\n * (`AgentId`) id spaces are declared and bridged, plus the ONE alias\n * normalizer every surface funnels through.\n *\n * Canonical values consolidated from (Phase 2, PR-1):\n * - backend `apps/api-v2/src/linked-agents/agent-map.ts`\n * (`PUBLIC_TO_INTERNAL` / `INTERNAL_TO_PUBLIC` / `LinkedAgentId`),\n * - CLI `apps/cli/src/commands/host/agent-provisioning.ts`\n * (`PUBLIC_TO_INTERNAL_AGENT`),\n * - VS Code plugin `apps/vsc-plugin/src/utils/cli-agent-id.ts`\n * (marketplace aliases + `__terminal__:` strip),\n * - CLI `apps/cli/src/commands/start/handlers.ts`\n * (the `claude_code` → `claude` normalization),\n * - mobile `apps/mobile/src/lib/agent-id-map.ts`.\n */\n\nimport type { AgentId, HeadroomKind } from './types';\nimport { AGENT_REGISTRY, isKnownAgentId } from './registry';\n\n// ─── House agent constants ───────────────────────────────────────────────────\n// Byte-identical mirrors of the backend repo's canonical\n// `codeagent-mobile/packages/shared/src/constants/house-agent.ts` (which the\n// api-v2 additionally hand-mirrors in `common/constants/house-agent.ts`).\n// PR-3 replaces those copies with re-exports of THESE.\n\n/** Sentinel id for the synthetic \"CodeAgent Cloud (incluido)\" house agent. */\nexport const HOUSE_AGENT_ID = 'house-codeagent-cloud';\n\n/** Internal provider discriminator for the house agent. */\nexport const HOUSE_AGENT_PROVIDER = 'codeagent_cloud';\n\n/** White-label display strings — never mention the backend model. */\nexport const HOUSE_AGENT_NAME = 'CodeAgent Cloud';\nexport const HOUSE_AGENT_VENDOR = 'CodeAgent';\nexport const HOUSE_AGENT_SUBTITLE = 'Included — no setup';\n\n// ─── Public (LinkedAgent) id space ───────────────────────────────────────────\n\n/**\n * Public-facing linked-agent ids — the id space the `/api/agents/...`\n * endpoints and the mobile/web surfaces speak. The internal `AgentId`\n * (`'claude' | 'codex' | …`) is what the runtimes / provisioning key on.\n */\nexport type LinkedAgentId =\n | 'claude_code'\n | 'codex'\n | 'cursor'\n | 'aider'\n | 'coderabbit'\n | 'gemini'\n | 'kimi'\n | typeof HOUSE_AGENT_ID;\n\nexport const LINKED_AGENT_IDS: readonly LinkedAgentId[] = [\n 'claude_code',\n 'codex',\n 'cursor',\n 'aider',\n 'coderabbit',\n 'gemini',\n 'kimi',\n HOUSE_AGENT_ID,\n];\n\nexport function isLinkedAgentId(value: string): value is LinkedAgentId {\n return (LINKED_AGENT_IDS as readonly string[]).includes(value);\n}\n\n/**\n * Every public id → internal `AgentId`.\n *\n * ⚠️ RECONCILED ASYMMETRY — this map is the UNION of what the two sides\n * historically accepted:\n * - The backend's `agent-map.ts` accepts only the `LinkedAgentId` union\n * (incl. the house agent, whose runtime is Claude Code) — no bare\n * `claude`, no `copilot` (there is no public copilot LinkedAgentId).\n * - The CLI's self-hosted `agent-provisioning.ts` additionally accepts\n * bare `'claude'` and `'copilot'` (deploy payloads have carried\n * already-internal ids), but not the house agent.\n * Consumers that must REJECT ids outside their own historical set keep\n * their own guard on top (e.g. `isLinkedAgentId`).\n */\nexport const PUBLIC_TO_INTERNAL: Readonly<\n Record<LinkedAgentId | 'claude' | 'copilot', AgentId>\n> = {\n claude_code: 'claude',\n // CLI-side extra: self-hosted deploy payloads may carry the internal id.\n claude: 'claude',\n codex: 'codex',\n // CLI-side extra: copilot has no public LinkedAgentId (backend doesn't\n // expose it) but the self-hosted path accepts it.\n copilot: 'copilot',\n cursor: 'cursor',\n aider: 'aider',\n coderabbit: 'coderabbit',\n gemini: 'gemini',\n kimi: 'kimi',\n // The house agent runs Claude Code under the hood (pointed at the\n // MiniMax proxy). Its internal runtime is therefore `claude`.\n [HOUSE_AGENT_ID]: 'claude',\n};\n\n/**\n * Internal → public. Partial: `copilot` has no public LinkedAgentId, and\n * `claude` maps back to `claude_code` (never the house agent — that\n * direction is intentionally lossy).\n */\nexport const INTERNAL_TO_PUBLIC: Readonly<Partial<Record<AgentId, LinkedAgentId>>> = {\n claude: 'claude_code',\n codex: 'codex',\n cursor: 'cursor',\n aider: 'aider',\n coderabbit: 'coderabbit',\n gemini: 'gemini',\n kimi: 'kimi',\n};\n\nfunction isPublicToInternalKey(v: string): v is LinkedAgentId | 'claude' | 'copilot' {\n // Not Object.hasOwn — the VS Code plugin's tsconfig lib predates ES2022.\n return Object.prototype.hasOwnProperty.call(PUBLIC_TO_INTERNAL, v);\n}\n\n/** Resolve a public/linked id to the internal `AgentId`, or null. */\nexport function publicToInternal(publicId: string): AgentId | null {\n return isPublicToInternalKey(publicId) ? PUBLIC_TO_INTERNAL[publicId] : null;\n}\n\n/** Resolve an internal `AgentId` to its public `LinkedAgentId`, or null. */\nexport function internalToPublic(internal: AgentId): LinkedAgentId | null {\n return INTERNAL_TO_PUBLIC[internal] ?? null;\n}\n\n// ─── Alias normalization ─────────────────────────────────────────────────────\n\n/** Prefix IDE plugins use for terminal-hosted agent ids. */\nexport const TERMINAL_AGENT_PREFIX = '__terminal__:';\n\n/**\n * Known aliases → internal `AgentId`. Union of every alias set that used\n * to live scattered across the surfaces: the public `claude_code` id, the\n * VS Code / Open VSX marketplace extension ids, and JetBrains plugin ids.\n */\nconst AGENT_ID_ALIASES: Readonly<Record<string, AgentId>> = {\n claude_code: 'claude',\n 'claude-code': 'claude',\n 'anthropic.claude-code': 'claude',\n 'anthropics.claude': 'claude',\n 'anthropic.claude-ce': 'claude',\n 'anthropic.claude': 'claude',\n 'com.anthropic.claudecode': 'claude',\n 'com.anthropic.claude': 'claude',\n 'openai.chatgpt': 'codex',\n 'coderabbitai.coderabbit-vscode': 'coderabbit',\n};\n\n/**\n * THE agent-id normalizer. Collapses every known spelling of an agent id\n * (registry id, public `claude_code` form, marketplace extension id,\n * `__terminal__:`-prefixed plugin id — case/whitespace tolerant) onto the\n * internal `AgentId`, or `null` when unknown.\n *\n * Deliberately does NOT:\n * - gate on `enabled` (callers that need availability check the\n * registry — see the VS Code wrapper `normalizeCliAgentId`);\n * - map the house agent (that's a runtime substitution, not an alias —\n * use {@link publicToInternal});\n * - fall back to anything. Unknown in → `null` out.\n */\nexport function normalizeAgentId(raw: string): AgentId | null {\n const value = (raw ?? '').trim().toLowerCase();\n if (!value) return null;\n\n if (isKnownAgentId(value)) return value;\n\n const unprefixed = value.startsWith(TERMINAL_AGENT_PREFIX)\n ? value.slice(TERMINAL_AGENT_PREFIX.length)\n : value;\n if (isKnownAgentId(unprefixed)) return unprefixed;\n\n return AGENT_ID_ALIASES[unprefixed] ?? null;\n}\n\n// ─── Headroom kind derivation ────────────────────────────────────────────────\n\n/**\n * The `headroom init --global <kind>` subcommand for an agent id, derived\n * from the registry's `headroomKind` flags — or `null` for unknown or\n * non-wrappable agents (cursor / gemini / aider / anything else).\n *\n * ⚠️ NEVER falls back to `'claude'`. The historical CLI fallback is how\n * the 2026-06 Cursor incident happened: an unsupported agent slipped\n * through, defaulted to `claude`, and `headroom wrap claude` launched\n * Claude Code instead of the user's agent. Callers that genuinely need a\n * default (e.g. picking an init subcommand AFTER the wrappable gate has\n * already passed) apply it themselves — see the CLI's\n * `agentIdToHeadroomKind` wrapper.\n *\n * Matching mirrors the historical predicates on BOTH sides (CLI\n * `isHeadroomSupportedAgent`, api-v2 `isHeadroomWrappableAgent`):\n * case-insensitive, `_`/`-` tolerant, prefix match — so `claude_code`,\n * `Claude-Code`, `codex_cli`, `copilot-cli` all resolve.\n */\nexport function headroomKindFor(agentId: string): HeadroomKind | null {\n const normalized = (agentId ?? '').toLowerCase().replace(/[_-]/g, '');\n if (!normalized) return null;\n for (const meta of Object.values(AGENT_REGISTRY)) {\n if (meta.headroomKind !== undefined && normalized.startsWith(meta.id)) {\n return meta.headroomKind;\n }\n }\n return null;\n}\n\n/**\n * Registry-derived replacement for the two scattered predicates\n * (`isHeadroomSupportedAgent` in the CLI, `isHeadroomWrappableAgent` in\n * api-v2). Accepts both id spaces (`claude_code` and `claude`).\n */\nexport function isHeadroomWrappable(agentId: string): boolean {\n return headroomKindFor(agentId) !== null;\n}\n","/**\n * Production API base URL for all CodeAgent Mobile clients.\n *\n * History note: prod migrated from Vercel (`https://api.codeagent-mobile.com`)\n * to Cloud Run / api-v2 (`https://api.codeagent-mobile.com`) in 2026-05. The\n * Vercel deployment is now gated by Vercel deployment protection and returns\n * 403 for unauthed traffic — DO NOT fall back to it.\n *\n * Override at runtime with `CODEAM_API_URL` (full URL override) OR set\n * `CODEAM_TEST_MODE=1` to point every client request at the dev\n * preview without having to know its host.\n */\nexport const DEFAULT_API_BASE_URL = 'https://api.codeagent-mobile.com' as const;\n\n/**\n * Dev-preview API base URL. Same Cloud Run service as prod but routed\n * to the `dev` revision (auto-deploys from the `dev` branch in the\n * backend repo). Manual smoke tests + load runs land here.\n */\nexport const DEV_API_BASE_URL = 'https://dev-api.codeagent-mobile.com' as const;\n\n/**\n * Resolve the active API base URL, honoring in priority order:\n *\n * 1. Explicit `CODEAM_API_URL` env var — full URL, takes precedence.\n * 2. `CODEAM_TEST_MODE=1` shortcut — flips to [DEV_API_BASE_URL]\n * without the user having to know the dev host.\n * 3. The `DEFAULT_API_BASE_URL` constant (prod).\n *\n * Used by every CLI service that talks to the backend so one env var\n * flips heartbeats, command relay, chunk uploads, and the pairing\n * flow in lockstep — eliminates the cross-environment misroute where\n * pairing succeeds in dev (shared Redis) but the CLI keeps\n * heartbeating to prod.\n */\nexport function resolveApiBaseUrl(): string {\n // Guard against non-Node runtimes (browser bundles import this\n // module). `process` is undefined there; treat as prod default.\n // `@codeam/shared` deliberately avoids depending on `@types/node`\n // so its types stay consumable from the mobile RN bundle too, so we\n // reach for the env via a structural cast rather than NodeJS.ProcessEnv.\n const env = (globalThis as { process?: { env?: Record<string, string | undefined> } }).process?.env;\n const explicit = env?.CODEAM_API_URL?.trim();\n if (explicit) return explicit;\n const testFlag = env?.CODEAM_TEST_MODE?.trim();\n if (testFlag === '1' || testFlag?.toLowerCase() === 'true') return DEV_API_BASE_URL;\n return DEFAULT_API_BASE_URL;\n}\n","/**\n * Headroom provisioning manifest — the SINGLE source of truth for what a\n * Headroom install consists of, rendered by every provisioning surface:\n *\n * - codespace bootstrap (bash composer in the backend repo,\n * `apps/api-v2/src/codespaces/github-ssh.service.ts` — adopts in PR-2),\n * - self-hosted deploy (TS installer, CLI `commands/host-agent.ts`\n * `setupHeadroomForSelfHosted`),\n * - on-demand local sessions (\"Session add-ons → Cost-saving\", CLI\n * `services/headroom/configure.ts`).\n *\n * Values are DATA-first (arrays/records, plus tiny pure renderers) so both\n * the TS installer and a bash composer can interpolate from them. Renderers\n * are byte-exact with the literals they replaced — guarded by\n * `packages/shared/__tests__/headroom-manifest.test.ts`.\n *\n * ⚠️ The extras matter: `[proxy,code]` pulls the ONNX compression engines\n * (Kompress + tree-sitter CodeCompressor). NEVER add `[ml]` — that's\n * multi-GB PyTorch, and a broken/cold torch wedges every prompt at\n * \"Thinking…\". The models are pre-downloaded at provision time because the\n * proxy eager-loads with `allow_download=False` and a cold cache defers the\n * ~840 MB download to the first prompt (blowing the agent's ~90 s idle\n * timeout).\n */\n\n/** Local proxy port the agent's config is routed to. */\nexport const HEADROOM_PROXY_PORT = 8787;\n\n/**\n * Env that pins the ONNX backend on the proxy process — never imports\n * torch. Spread into the proxy launch env on every surface.\n */\nexport const HEADROOM_BACKEND_ENV = {\n HEADROOM_KOMPRESS_BACKEND: 'onnx_cpu',\n} as const;\n\n/**\n * The proxy's HTTP/server companion packages, installed alongside the\n * `headroom-ai[...]` package. The COMPRESSION ENGINES come from the\n * headroom-ai extras — NOT this list.\n */\nexport const HEADROOM_PIP_COMPANIONS: readonly string[] = [\n 'fastapi',\n 'uvicorn',\n 'httpx[http2]',\n 'websockets',\n 'zstandard',\n];\n\n/** The three provisioning surfaces (see module doc). */\nexport type HeadroomSurface = 'codespace' | 'selfHosted' | 'onDemand';\n\n/**\n * pip extras per surface. `onDemand` additionally ships `image`\n * (image-compression support, added with the Session add-ons path in\n * codeam-cli@2.49.0); the older codespace/self-hosted install strings\n * remain `[proxy,code]` byte-for-byte.\n */\nexport const HEADROOM_EXTRAS_BY_SURFACE: Readonly<Record<HeadroomSurface, readonly string[]>> = {\n codespace: ['proxy', 'code'],\n selfHosted: ['proxy', 'code'],\n onDemand: ['proxy', 'code', 'image'],\n};\n\n/** `headroom-ai[<extras>]` — the pip requirement string. */\nexport function headroomPipPackage(extras: readonly string[]): string {\n return `headroom-ai[${extras.join(',')}]`;\n}\n\n/** One HuggingFace repo to pre-warm into the HF cache at provision time. */\nexport interface HeadroomModelSpec {\n repo: string;\n /** `snapshot_download(..., allow_patterns=[…])` filter. */\n allowPatterns: readonly string[];\n}\n\n/**\n * The two HF repos Kompress needs. kompress-v2-base is the ONNX model\n * (skip its .pt/.safetensors torch artifacts); ModernBERT-base is the\n * TOKENIZER ONLY (skip its model weights).\n */\nexport const HEADROOM_MODELS: readonly HeadroomModelSpec[] = [\n {\n repo: 'chopratejas/kompress-v2-base',\n allowPatterns: ['*.json', 'onnx/*.onnx', 'kompress-int8-wo.onnx'],\n },\n {\n repo: 'answerdotai/ModernBERT-base',\n allowPatterns: ['*.json', 'tokenizer*', '*.txt', 'vocab*', 'merges*'],\n },\n];\n\n/** Formatting knob so each surface can stay byte-identical to its\n * historical literal (the CLI joins patterns with `,`, the codespace\n * bash composer with `, `). */\nexport interface HeadroomPythonRenderOpts {\n /** Put a space after the commas between allow_patterns entries. */\n spaceAfterComma?: boolean;\n}\n\n/** Render one `snapshot_download(...)` python line for a model. */\nexport function headroomSnapshotDownloadLine(\n model: HeadroomModelSpec,\n opts: HeadroomPythonRenderOpts = {},\n): string {\n const sep = opts.spaceAfterComma ? ', ' : ',';\n const patterns = model.allowPatterns.map((p) => `\"${p}\"`).join(sep);\n return `snapshot_download(\"${model.repo}\", allow_patterns=[${patterns}])`;\n}\n\n/**\n * The full model pre-download python snippet (import + one\n * `snapshot_download` per model), newline-joined — what the surfaces pass\n * to `python -c` / a heredoc.\n */\nexport function headroomModelPredownloadScript(opts: HeadroomPythonRenderOpts = {}): string {\n return [\n 'from huggingface_hub import snapshot_download',\n ...HEADROOM_MODELS.map((m) => headroomSnapshotDownloadLine(m, opts)),\n ].join('\\n');\n}\n","/**\n * Canonical names of the per-user SSE bus events (`/api/users/me/stream`).\n *\n * The authoritative list is the `UserEvent` discriminated union in the\n * backend repo: codeagent-mobile/apps/api-v2/src/user-events/user-events.types.ts.\n * Every `type:` literal of that union appears here exactly once — when a new\n * variant lands on the union, add its name here (and in the backend mirror of\n * this file at codeagent-mobile/packages/shared/src/types/events.ts).\n *\n * Producers (CLI event posts, backend `userEvents.publish` calls) and\n * consumers (the `useUserEventsSSE` hooks' switch cases) should reference\n * `USER_EVENTS.*` instead of re-typing the string, so a typo becomes a\n * compile error instead of a silently dropped event.\n */\nexport const USER_EVENTS = {\n PAIRED_SESSION_STATUS: 'paired_session_status',\n PAIRED_SESSION_ADDED: 'paired_session_added',\n PAIRED_SESSION_REMOVED: 'paired_session_removed',\n PAIRED_SESSION_BRANCH_CHANGED: 'paired_session_branch_changed',\n SHARED_WITH_ME_ADDED: 'shared_with_me_added',\n SHARED_WITH_ME_REVOKED: 'shared_with_me_revoked',\n USAGE_CHANGED: 'usage_changed',\n TASK_DONE: 'task_done',\n HUNK_PENDING_REVIEW_ADDED: 'hunk_pending_review_added',\n HUNK_REVIEW_RESOLVED: 'hunk_review_resolved',\n FILE_CHANGED: 'file_changed',\n FILES_BATCH_CHANGED: 'files_batch_changed',\n AGENT_STREAMING_CHUNK: 'agent_streaming_chunk',\n AGENT_AWAITING_ANSWER: 'agent_awaiting_answer',\n AWAITING_INPUT_ADDED: 'awaiting_input_added',\n AGENT_ANSWER_RESOLVED: 'agent_answer_resolved',\n TEMPLATE_ADDED: 'template_added',\n TEMPLATE_REMOVED: 'template_removed',\n TEMPLATE_UPDATED: 'template_updated',\n AGENT_TASK_DISPATCHED: 'agent_task_dispatched',\n AGENT_TASK_COMPLETED: 'agent_task_completed',\n LINKED_AGENT_ADDED: 'linked_agent_added',\n QUOTA_REACHED: 'quota_reached',\n LINKED_AGENT_LINK_FAILED: 'linked_agent_link_failed',\n CODESPACE_AGENT_INSTALLED: 'codespace_agent_installed',\n AGENT_CREDENTIALS_REFRESHED: 'agent_credentials_refreshed',\n CREDENTIAL_INVALID: 'credential_invalid',\n CODESPACE_WAKING: 'codespace_waking',\n CODESPACE_BILLING_BLOCKED: 'codespace_billing_blocked',\n COST_SAVING_UPDATED: 'cost_saving_updated',\n COMMAND_COMPLETED: 'command_completed',\n AI_SUMMARY_PENDING: 'ai_summary_pending',\n AI_SUMMARY_READY: 'ai_summary_ready',\n AI_INSIGHT_PENDING: 'ai_insight_pending',\n AI_INSIGHT_READY: 'ai_insight_ready',\n PUSH_TOKEN_INVALIDATED: 'push_token_invalidated',\n PREVIEW_DETECTION_PENDING: 'preview_detection_pending',\n PREVIEW_DETECTION_READY: 'preview_detection_ready',\n PREVIEW_STARTING: 'preview_starting',\n PREVIEW_READY: 'preview_ready',\n PREVIEW_STOPPED: 'preview_stopped',\n PREVIEW_ERROR: 'preview_error',\n PREVIEW_PROGRESS: 'preview_progress',\n BEADS_STATE_CHANGED: 'beads_state_changed',\n BEADS_PROVISIONING: 'beads_provisioning',\n BEADS_TEAM_MEMORY_CHANGED: 'beads_team_memory_changed',\n AUDIT_EVENT_ADDED: 'audit_event_added',\n SELF_HOSTED_HOST_ADDED: 'self_hosted_host_added',\n SELF_HOSTED_HOST_STATUS: 'self_hosted_host_status',\n SELF_HOSTED_HOST_REMOVED: 'self_hosted_host_removed',\n SELF_HOSTED_HOST_TELEMETRY: 'self_hosted_host_telemetry',\n SELF_HOSTED_HOST_METRICS: 'self_hosted_host_metrics',\n SELF_HOSTED_HOST_SESSIONS: 'self_hosted_host_sessions',\n SELF_HOSTED_DEPLOY_PROGRESS: 'self_hosted_deploy_progress',\n REFERRAL_REWARD_EARNED: 'referral_reward_earned',\n HEADROOM_PROGRESS: 'headroom_progress',\n HEADROOM_STATUS: 'headroom_status',\n BEADS_STATUS: 'beads_status',\n LINKED_AGENT_HEADROOM_BUDGET_UPDATED: 'linked_agent_headroom_budget_updated',\n CLI_UPDATE_AVAILABLE: 'cli_update_available',\n AGENT_INSTALL_PROGRESS: 'agent_install_progress',\n AGENT_INSTALL_FAILED: 'agent_install_failed',\n CLI_UPDATE_PROGRESS: 'cli_update_progress',\n CLI_UPDATE_FAILED: 'cli_update_failed',\n BATON_STATE: 'baton_state',\n // CodeRabbit reviewer — the CLI posts these to /api/coderabbit/events; the\n // backend re-publishes them on the per-user SSE bus (mirrored in repo A).\n CODERABBIT_PROGRESS: 'coderabbit_progress',\n CODERABBIT_STATUS: 'coderabbit_status',\n CODERABBIT_REVIEW: 'coderabbit_review',\n} as const;\n\nexport type UserEventName = (typeof USER_EVENTS)[keyof typeof USER_EVENTS];\n","/**\n * Prompt the CLI sends to the user's linked agent (Claude, Codex, …)\n * in a headless one-shot to detect how to start the project's dev\n * server. Same pattern as the AI Insights \"summary\" prompt — the\n * agent runs locally with the user's auth, has read access to the\n * project, and returns a tiny JSON blob the CLI parses.\n *\n * Kept here (in `@codeam/shared`) so the CLI build inlines the\n * exact string at compile time without runtime fetch from the backend.\n */\nexport const PREVIEW_DETECT_PROMPT = `\nAnalyze the project in the current working directory and return how to start\nits development server for in-app preview.\n\nRead package.json, Procfile, Dockerfile, docker-compose.yml, manage.py, app.json,\nmix.exs, Cargo.toml, go.mod, requirements.txt, Gemfile, and any other framework\nmarkers you find at depth <= 2.\n\nReturn ONLY a JSON object on stdout (no prose, no markdown fences):\n\n{\n \"framework\": \"<name, or 'unsupported'>\",\n \"command\": \"<executable>\",\n \"args\": [\"...\"],\n \"port\": <number>,\n \"ready_pattern\": \"<regex matching the server-ready stdout line>\",\n \"env\": { \"HOST\": \"0.0.0.0\" },\n \"setup_commands\": [{ \"cmd\": \"<executable>\", \"args\": [\"...\"] }],\n \"notes\": \"<one-line caveat or null>\"\n}\n\nRules:\n- Pick the script the developer would run locally to see the app (typically \"dev\", \"start\", \"serve\").\n- Prefer binding to 0.0.0.0 — most frameworks default to localhost which the tunnel cannot reach.\n- For Expo: framework=\"Expo\", command=\"npx\", args=[\"expo\",\"start\",\"--tunnel\"], port=8081, notes=\"Scan QR with Expo Go\".\n- If no dev server applies (CLI library, lambda, batch script): {\"framework\":\"unsupported\",\"notes\":\"<reason>\"}.\n\nCRITICAL — setup_commands:\n- DO NOT include an install command (npm install, pnpm install, yarn install,\n yarn, bun install) in setup_commands. A lockfile-aware pre-flight installer\n runs BEFORE setup_commands and picks the correct package manager from the\n lockfile present (pnpm-lock.yaml -> pnpm, yarn.lock -> yarn, bun.lockb -> bun,\n else npm). Emitting an install here either duplicates that work or, worse,\n uses the WRONG package manager on top of node_modules just populated by the\n pre-flight, which crashes (e.g. npm errors with \"Cannot read properties of\n null (reading 'matches')\" when run over pnpm's .pnpm/ layout).\n- ONLY include setup_commands for genuinely non-install work the project needs\n before its dev server can boot: prisma generate, codegen, prebuild scripts,\n database migrations against a local SQLite, etc.\n- Each setup_commands entry MUST be an object {\"cmd\": \"...\", \"args\": [\"...\"]} —\n e.g. {\"cmd\": \"npx\", \"args\": [\"prisma\", \"generate\"]}. NOT a bare string.\n- For most projects, setup_commands should be an empty array [].\n\nOUTPUT JSON ONLY. NO MARKDOWN. NO COMMENTARY.\n`.trim();\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/protocol/constants.ts","../src/protocol/renderToLines.ts","../src/protocol/remote-command.ts","../src/models/pricing.ts","../src/agents/registry.ts","../src/agents/identity.ts","../src/integrations/registry.ts","../src/api-url.ts","../src/headroom/manifest.ts","../src/types/events.ts","../src/preview-prompts.ts"],"sourcesContent":["export * from './protocol/chrome-types';\nexport * from './protocol/constants';\nexport * from './protocol/renderToLines';\nexport * from './protocol/remote-command';\nexport * from './models/pricing';\nexport * from './agents';\nexport * from './integrations';\nexport * from './types/file-change';\nexport * from './types/streaming';\nexport * from './api-url';\nexport * from './types/preview';\nexport * from './types/beads';\nexport * from './types/headroom';\nexport * from './headroom/manifest';\nexport * from './types/events';\nexport * from './preview-prompts';\n","/**\n * Shared wire / lifecycle constants. The values here are bundled\n * into the CLI + VS Code extension at build time via tsup / esbuild\n * and mirrored in `apps/jetbrains-plugin/.../protocol/Constants.kt`\n * since Kotlin can't import an npm package.\n *\n * If you change one of these values, also update the Kotlin mirror.\n */\n\n/**\n * Discriminated chunk-protocol version sent as the\n * `X-Codeam-Protocol-Version` header on every authed request. The\n * backend uses this to opt into legacy translations or to reject\n * with 426 when the client is too far behind. Bumped in lockstep\n * with chunk-shape changes (e.g. when the `chrome_steps` chunk\n * type is added).\n */\nexport const PROTOCOL_VERSION = '2.0.0' as const;\n\n/**\n * The VS Code AgentOutputMonitor's loopback HTTP server bound to\n * 127.0.0.1 on this port — the observer JS in the IDE renderer\n * uses it to round-trip captured chat content back into the\n * extension host. The port is intentionally fixed (rather than\n * `listen(0)`) so the observer script can be a static constant\n * rather than dynamically rewriting itself per session.\n *\n * Multi-window collision is solved by listen(0) per-window in the\n * monitor (see #103); this default is still the documented\n * starting port for tooling that needs to probe whether a CodeAgent\n * Mobile session is active locally.\n */\nexport const OBSERVER_BRIDGE_PORT = 47832;\n\n/**\n * Default plugin → backend heartbeat interval. User-configurable\n * via `codeagent-mobile.heartbeatIntervalMs` on VS Code and\n * `heartbeatIntervalMs` in SettingsService.kt's @State on JetBrains.\n * Mirrors the value the apps/api side uses to flip the paired\n * session to offline.\n */\nexport const HEARTBEAT_INTERVAL_MS_DEFAULT = 30_000;\n\n/**\n * SSE + polling reconnect cap. Vercel's serverless functions close\n * SSE connections after ~25 s by default; the client uses 35 s as\n * its overall socket timeout to leave a beat for graceful close.\n */\nexport const SSE_SOCKET_TIMEOUT_MS = 35_000;\n","/**\n * Render raw PTY bytes into an array of screen lines using a simplified\n * virtual terminal. Handles cursor movements (A/B/C/D/G/H), erase (J/K),\n * alternate-screen (?1049h), carriage return, and LF.\n *\n * This is the authoritative implementation used by both codeam-cli (PTY\n * output) and the VS Code extension (shell-integration output) so that\n * the mobile/web client sees identical chunks regardless of surface.\n */\nexport function renderToLines(raw: string): string[] {\n const screen: string[] = [''];\n let row = 0;\n let col = 0;\n\n function ensureRow(): void {\n while (screen.length <= row) screen.push('');\n }\n\n function writeChar(ch: string): void {\n ensureRow();\n if (col < screen[row].length) {\n screen[row] = screen[row].slice(0, col) + ch + screen[row].slice(col + 1);\n } else {\n while (screen[row].length < col) screen[row] += ' ';\n screen[row] += ch;\n }\n col++;\n }\n\n let i = 0;\n while (i < raw.length) {\n const ch = raw[i];\n\n if (ch === '\\x1B') {\n i++;\n if (i >= raw.length) break;\n\n if (raw[i] === '[') {\n i++;\n let param = '';\n while (i < raw.length && !/[@-~]/.test(raw[i])) param += raw[i++];\n const cmd = raw[i] ?? '';\n const n = parseInt(param) || 1;\n\n if (cmd === 'A') { row = Math.max(0, row - n); }\n else if (cmd === 'B') { row += n; ensureRow(); }\n else if (cmd === 'C') { col += n; }\n else if (cmd === 'D') { col = Math.max(0, col - n); }\n else if (cmd === 'G') { col = Math.max(0, n - 1); }\n else if (cmd === 'H' || cmd === 'f') {\n const p = param.split(';');\n row = Math.max(0, (parseInt(p[0] ?? '1') || 1) - 1);\n col = Math.max(0, (parseInt(p[1] ?? '1') || 1) - 1);\n ensureRow();\n } else if (cmd === 'J') {\n if (param === '2' || param === '3') {\n screen.length = 1; screen[0] = ''; row = 0; col = 0;\n } else if (param === '1') {\n for (let r = 0; r < row; r++) screen[r] = '';\n screen[row] = ' '.repeat(col) + screen[row].slice(col);\n } else {\n screen[row] = screen[row].slice(0, col);\n screen.splice(row + 1);\n }\n } else if (cmd === 'K') {\n ensureRow();\n if (param === '' || param === '0') screen[row] = screen[row].slice(0, col);\n else if (param === '1') screen[row] = ' '.repeat(col) + screen[row].slice(col);\n else if (param === '2') screen[row] = '';\n } else if (cmd === 'h' && (param === '?1049' || param === '?47')) {\n screen.length = 1; screen[0] = ''; row = 0; col = 0;\n } else if (cmd === 'l' && (param === '?1049' || param === '?47')) {\n screen.length = 1; screen[0] = ''; row = 0; col = 0;\n }\n } else if (raw[i] === ']') {\n i++;\n while (i < raw.length) {\n if (raw[i] === '\\x07') break;\n if (raw[i] === '\\x1B' && i + 1 < raw.length && raw[i + 1] === '\\\\') { i++; break; }\n i++;\n }\n }\n } else if (ch === '\\r') {\n if (i + 1 < raw.length && raw[i + 1] === '\\n') {\n row++; col = 0; ensureRow(); i++;\n } else {\n col = 0;\n }\n } else if (ch === '\\n') {\n row++; col = 0; ensureRow();\n } else if (ch >= ' ' || ch === '\\t') {\n writeChar(ch);\n }\n\n i++;\n }\n\n return screen;\n}\n","import { z } from 'zod';\n\n/**\n * The command envelope clients receive from the backend relay — both from\n * the `commands` SSE frames on `/api/commands/pending/stream` and from the\n * `GET /api/commands/pending` polling fallback. One schema, shared, so the\n * VS Code extension (and eventually the CLI) stop blind-casting\n * `Record<string, unknown>` into this shape.\n */\nexport interface RemoteCommand {\n id: string;\n sessionId: string;\n pluginId: string;\n type: string;\n payload: Record<string, unknown>;\n status: string;\n createdAt: number;\n}\n\nconst remoteCommandSchema = z.object({\n id: z.string(),\n sessionId: z.string(),\n pluginId: z.string(),\n type: z.string(),\n // The backend may omit `payload` (or send null) for payload-less commands;\n // clients have always normalized that to `{}` — keep that behavior here.\n payload: z.record(z.string(), z.unknown()).nullish(),\n status: z.string(),\n createdAt: z.number(),\n});\n\n/**\n * Validate a raw (already JSON-parsed) value into a `RemoteCommand`.\n * Returns `null` — never throws — on a malformed envelope so callers can\n * log-and-skip the single bad command without dropping the whole batch.\n */\nexport function toRemoteCommand(raw: unknown): RemoteCommand | null {\n const parsed = remoteCommandSchema.safeParse(raw);\n if (!parsed.success) return null;\n const { payload, ...rest } = parsed.data;\n return { ...rest, payload: payload ?? {} };\n}\n","export interface ModelPricing {\n input: number;\n output: number;\n cacheRead: number;\n cacheWrite: number;\n}\n\nexport const MODEL_PRICING: Record<string, ModelPricing> = {\n // ── Anthropic / Claude ────────────────────────────────────\n // The 4.x rows below cover the model ids actually emitted by the CLI\n // (apps/cli/src/agents/claude/runtime.ts listModels) and the JetBrains\n // fallback catalog (RemoteCommandRouter.kt). Prices are copied from the\n // same-family base rows (claude-opus-4 / claude-sonnet-4 /\n // claude-3-5-haiku) until distinct published rates land.\n 'claude-opus-4-7': { input: 15, output: 75, cacheRead: 1.50, cacheWrite: 18.75 },\n 'claude-opus-4-6': { input: 15, output: 75, cacheRead: 1.50, cacheWrite: 18.75 },\n 'claude-sonnet-4-6': { input: 3, output: 15, cacheRead: 0.30, cacheWrite: 3.75 },\n // Haiku-tier prices copied from claude-3-5-haiku (closest same-tier\n // sibling in this table) — previously this id matched NO row and was\n // silently billed at sonnet rates via the unknown-model fallback.\n 'claude-haiku-4-5': { input: 0.80, output: 4, cacheRead: 0.08, cacheWrite: 1 },\n 'claude-sonnet-4': { input: 3, output: 15, cacheRead: 0.30, cacheWrite: 3.75 },\n 'claude-opus-4': { input: 15, output: 75, cacheRead: 1.50, cacheWrite: 18.75 },\n 'claude-3-5-sonnet': { input: 3, output: 15, cacheRead: 0.30, cacheWrite: 3.75 },\n 'claude-3-5-haiku': { input: 0.80, output: 4, cacheRead: 0.08, cacheWrite: 1 },\n 'claude-3-haiku': { input: 0.25, output: 1.25, cacheRead: 0.03, cacheWrite: 0.30 },\n\n // ── Codex / OpenAI ────────────────────────────────────────\n // GPT-5.x rows are derived from OpenAI's published GPT-5 family rates\n // (standard tier: $1.25/1M in, $10/1M out, cached input at ~10% of input;\n // mini tier: $0.25/1M in, $2/1M out). OpenAI has no separate cache-WRITE\n // premium, so cacheWrite mirrors the input rate. Replace with the exact\n // per-version numbers from developers.openai.com/pricing when published —\n // these were the ZERO placeholders that rendered Codex sessions as $0.\n 'gpt-5.5': { input: 1.25, output: 10, cacheRead: 0.125, cacheWrite: 1.25 },\n 'gpt-5.4': { input: 1.25, output: 10, cacheRead: 0.125, cacheWrite: 1.25 },\n 'gpt-5.4-mini': { input: 0.25, output: 2, cacheRead: 0.025, cacheWrite: 0.25 },\n 'gpt-5.3-codex': { input: 1.25, output: 10, cacheRead: 0.125, cacheWrite: 1.25 },\n 'gpt-5.2': { input: 1.25, output: 10, cacheRead: 0.125, cacheWrite: 1.25 },\n 'codex-auto-review': { input: 1.25, output: 10, cacheRead: 0.125, cacheWrite: 1.25 },\n};\n\nexport const MODEL_CONTEXT_WINDOW: Record<string, number> = {\n // ── Anthropic / Claude ────────────────────────────────────\n 'claude-opus-4-7': 1_000_000,\n 'claude-opus-4-6': 1_000_000,\n 'claude-sonnet-4-6': 1_000_000,\n 'claude-haiku-4-5': 200_000,\n 'claude-opus-4': 1_000_000,\n 'claude-sonnet-4': 1_000_000,\n 'claude-3-5-sonnet': 200_000,\n 'claude-3-5-haiku': 200_000,\n 'claude-3-haiku': 200_000,\n\n // ── Codex / OpenAI ────────────────────────────────────────\n 'gpt-5.5': 272_000,\n 'gpt-5.4': 272_000,\n 'gpt-5.4-mini': 272_000,\n 'gpt-5.3-codex': 272_000,\n 'gpt-5.2': 272_000,\n 'codex-auto-review': 272_000,\n};\n\nconst DEFAULT_CONTEXT_WINDOW = 200_000;\n\n/**\n * Longest-prefix lookup. The tables key by model-family prefix; a model id\n * like `claude-opus-4-7` must resolve to its own row, not be shadowed by the\n * shorter `claude-opus-4` — so the match is by prefix LENGTH, never by the\n * table's insertion order.\n */\nfunction longestPrefixMatch<T>(table: Record<string, T>, model: string): T | undefined {\n let best: T | undefined;\n let bestLen = -1;\n for (const [prefix, value] of Object.entries(table)) {\n if (prefix.length > bestLen && model.startsWith(prefix)) {\n best = value;\n bestLen = prefix.length;\n }\n }\n return best;\n}\n\n/** True when the model id resolves to a real MODEL_PRICING row (i.e. getPricing\n * will NOT be guessing via the unknown-model fallback). */\nexport function isKnownModel(model: string): boolean {\n return longestPrefixMatch(MODEL_PRICING, model) !== undefined;\n}\n\n/**\n * Flagged default for an unpriced model id. All-zero so an unknown model is\n * VISIBLY unpriced ($0) rather than silently MISPRICED at some other family's\n * rates (the old sonnet-4 fallback billed unknown ids — including a haiku id\n * that matched no row — at sonnet rates). `getPricing` returns this object for\n * unknown ids so callers that do unconditional arithmetic still work; callers\n * that must distinguish real pricing from the default check `isKnownModel`.\n */\nexport const UNKNOWN_MODEL_PRICING: ModelPricing = {\n input: 0,\n output: 0,\n cacheRead: 0,\n cacheWrite: 0,\n};\n\n/**\n * Resolve pricing by longest matching prefix. Unknown models resolve to the\n * flagged {@link UNKNOWN_MODEL_PRICING} default (all-zero, i.e. visibly\n * unpriced) instead of guessing at another model's rates. Callers that need to\n * distinguish real pricing from the default must check `isKnownModel(model)`.\n */\nexport function getPricing(model: string): ModelPricing {\n return longestPrefixMatch(MODEL_PRICING, model) ?? UNKNOWN_MODEL_PRICING;\n}\n\nexport function getContextWindow(model: string | null): number {\n if (!model) return DEFAULT_CONTEXT_WINDOW;\n return longestPrefixMatch(MODEL_CONTEXT_WINDOW, model) ?? DEFAULT_CONTEXT_WINDOW;\n}\n","import type { AgentId, AgentMetadata } from './types';\n\nexport const AGENT_REGISTRY: Record<AgentId, AgentMetadata> = {\n claude: {\n id: 'claude',\n displayName: 'Claude Code',\n binaryName: 'claude',\n enabled: true,\n // Mirrors the backend registry (codeagent-mobile\n // apps/api-v2/src/codespaces/agent.ts — authoritative for auth\n // capabilities). `setup_token` is the bare `sk-ant-oat01-…` from\n // `claude setup-token` → delivered via CLAUDE_CODE_OAUTH_TOKEN.\n supportedAuthKinds: ['setup_token', 'oauth_token', 'api_key'],\n preferredAuthKind: 'setup_token',\n headroomWrappable: true,\n headroomKind: 'claude',\n // npm adapter `@agentclientprotocol/claude-agent-acp`.\n acp: true,\n },\n codex: {\n id: 'codex',\n displayName: 'Codex CLI',\n binaryName: 'codex',\n enabled: true,\n supportedAuthKinds: ['oauth_token', 'api_key'],\n preferredAuthKind: 'oauth_token',\n headroomWrappable: true,\n headroomKind: 'codex',\n // npm adapter `@agentclientprotocol/codex-acp`.\n acp: true,\n // OAuth device-code flow; the user_code on the OpenAI page IS a real\n // human-typed code — surfaces render it (with a copy affordance).\n deviceFlow: true,\n showsUserCode: true,\n },\n copilot: {\n id: 'copilot',\n displayName: 'GitHub Copilot CLI',\n binaryName: 'gh',\n enabled: false,\n supportedAuthKinds: ['oauth_token'],\n preferredAuthKind: 'oauth_token',\n // `headroom init --global copilot` exists even though the agent is\n // still disabled here (no runtime builder yet).\n headroomWrappable: true,\n headroomKind: 'copilot',\n acp: false,\n },\n coderabbit: {\n id: 'coderabbit',\n displayName: 'CodeRabbit',\n binaryName: 'coderabbit',\n enabled: true,\n // CodeRabbit links via a CLI-driven LOOPBACK OAuth (`coderabbit auth\n // login --agent`): the CLI captures the token and hands it to the vault\n // through `linkFromCli` (method:'oauth'), same as the terminal handoff.\n // `oauth_token` is preferred; a real API key is still accepted as a\n // fallback. There is no backend PKCE provider — the loopback runs on the\n // user's own machine, so linking is always CLI-mediated.\n supportedAuthKinds: ['oauth_token', 'api_key'],\n preferredAuthKind: 'oauth_token',\n headroomWrappable: false,\n // Legacy PTY runtime — no ACP adapter registered.\n acp: false,\n },\n cursor: {\n id: 'cursor',\n displayName: 'Cursor Agent',\n binaryName: 'cursor-agent',\n enabled: true,\n // Backend registry is authoritative: since the Cursor OAuth\n // device-flow shipped, new links are oauth_token only (the login\n // blob written to ~/.config/cursor/auth.json). Legacy vaulted\n // api_key rows may still exist server-side, but the link surface\n // no longer offers api_key.\n supportedAuthKinds: ['oauth_token'],\n preferredAuthKind: 'oauth_token',\n // `headroom wrap cursor` is \"manual/print-only\" (IDE settings; the\n // headless cursor-agent CLI has no base-URL override) — runs native.\n headroomWrappable: false,\n // Native ACP server: `cursor-agent acp`.\n acp: true,\n // Reverse-engineered device/poll flow; `userCode` is the secret PKCE\n // verifier echoed back on poll — NEVER human-facing.\n deviceFlow: true,\n showsUserCode: false,\n },\n aider: {\n id: 'aider',\n displayName: 'Aider',\n binaryName: 'aider',\n enabled: true,\n // Aider is OAuth-less — auth is via ANTHROPIC_API_KEY / OPENAI_API_KEY\n // / etc. env vars or `~/.aider.conf.yml`. The link flow surfaces\n // this via the existing --api-key escape hatch in commands/link.ts.\n supportedAuthKinds: ['api_key'],\n preferredAuthKind: 'api_key',\n headroomWrappable: false,\n // Legacy PTY runtime — no ACP adapter registered.\n acp: false,\n },\n gemini: {\n id: 'gemini',\n displayName: 'Gemini CLI',\n binaryName: 'gemini',\n enabled: true,\n // OAuth via `gemini auth login` (captured by `codeam link gemini`\n // from ~/.gemini/oauth_creds.json) AND GEMINI_API_KEY are both\n // accepted by the backend's GeminiProvisioningStrategy and propagated\n // into codespace deploys.\n supportedAuthKinds: ['oauth_token', 'api_key'],\n preferredAuthKind: 'oauth_token',\n // Not listed by `headroom wrap --help` — runs native.\n headroomWrappable: false,\n // Native ACP server: `gemini --skip-trust --acp`.\n acp: true,\n },\n kimi: {\n id: 'kimi',\n displayName: 'Kimi Code',\n binaryName: 'kimi',\n enabled: true,\n // API key (KIMI_API_KEY, + optional KIMI_BASE_URL) is the shipping auth —\n // fully documented, no reverse-engineering. OAuth `/login` (login-state at\n // ~/.kimi-code/credentials/<name>.json, base https://api.kimi.com/coding/)\n // is declared so it can land later without a wire change, but capturing\n // that blob server-side is a separate reverse-engineering spike (phase 2).\n supportedAuthKinds: ['api_key', 'oauth_token'],\n preferredAuthKind: 'api_key',\n // Moonshot's `kimi` is not listed by `headroom wrap --help` — runs native.\n headroomWrappable: false,\n // Native ACP server: `kimi acp` (stdio JSON-RPC, answers `initialize`).\n acp: true,\n },\n};\n\nexport function getEnabledAgents(): AgentMetadata[] {\n return Object.values(AGENT_REGISTRY).filter(m => m.enabled);\n}\n\nexport function getAgent(id: AgentId): AgentMetadata {\n const meta = AGENT_REGISTRY[id];\n if (!meta) throw new Error(`Unknown agent id: ${id}`);\n return meta;\n}\n\nexport function isKnownAgentId(id: string): id is AgentId {\n return id in AGENT_REGISTRY;\n}\n","/**\n * Agent identity — the ONE place the public (`LinkedAgentId`) and internal\n * (`AgentId`) id spaces are declared and bridged, plus the ONE alias\n * normalizer every surface funnels through.\n *\n * Canonical values consolidated from (Phase 2, PR-1):\n * - backend `apps/api-v2/src/linked-agents/agent-map.ts`\n * (`PUBLIC_TO_INTERNAL` / `INTERNAL_TO_PUBLIC` / `LinkedAgentId`),\n * - CLI `apps/cli/src/commands/host/agent-provisioning.ts`\n * (`PUBLIC_TO_INTERNAL_AGENT`),\n * - VS Code plugin `apps/vsc-plugin/src/utils/cli-agent-id.ts`\n * (marketplace aliases + `__terminal__:` strip),\n * - CLI `apps/cli/src/commands/start/handlers.ts`\n * (the `claude_code` → `claude` normalization),\n * - mobile `apps/mobile/src/lib/agent-id-map.ts`.\n */\n\nimport type { AgentId, HeadroomKind } from './types';\nimport { AGENT_REGISTRY, isKnownAgentId } from './registry';\n\n// ─── House agent constants ───────────────────────────────────────────────────\n// Byte-identical mirrors of the backend repo's canonical\n// `codeagent-mobile/packages/shared/src/constants/house-agent.ts` (which the\n// api-v2 additionally hand-mirrors in `common/constants/house-agent.ts`).\n// PR-3 replaces those copies with re-exports of THESE.\n\n/** Sentinel id for the synthetic \"CodeAgent Cloud (incluido)\" house agent. */\nexport const HOUSE_AGENT_ID = 'house-codeagent-cloud';\n\n/** Internal provider discriminator for the house agent. */\nexport const HOUSE_AGENT_PROVIDER = 'codeagent_cloud';\n\n/** White-label display strings — never mention the backend model. */\nexport const HOUSE_AGENT_NAME = 'CodeAgent Cloud';\nexport const HOUSE_AGENT_VENDOR = 'CodeAgent';\nexport const HOUSE_AGENT_SUBTITLE = 'Included — no setup';\n\n// ─── Public (LinkedAgent) id space ───────────────────────────────────────────\n\n/**\n * Public-facing linked-agent ids — the id space the `/api/agents/...`\n * endpoints and the mobile/web surfaces speak. The internal `AgentId`\n * (`'claude' | 'codex' | …`) is what the runtimes / provisioning key on.\n */\nexport type LinkedAgentId =\n | 'claude_code'\n | 'codex'\n | 'cursor'\n | 'aider'\n | 'coderabbit'\n | 'gemini'\n | 'kimi'\n | typeof HOUSE_AGENT_ID;\n\nexport const LINKED_AGENT_IDS: readonly LinkedAgentId[] = [\n 'claude_code',\n 'codex',\n 'cursor',\n 'aider',\n 'coderabbit',\n 'gemini',\n 'kimi',\n HOUSE_AGENT_ID,\n];\n\nexport function isLinkedAgentId(value: string): value is LinkedAgentId {\n return (LINKED_AGENT_IDS as readonly string[]).includes(value);\n}\n\n/**\n * Every public id → internal `AgentId`.\n *\n * ⚠️ RECONCILED ASYMMETRY — this map is the UNION of what the two sides\n * historically accepted:\n * - The backend's `agent-map.ts` accepts only the `LinkedAgentId` union\n * (incl. the house agent, whose runtime is Claude Code) — no bare\n * `claude`, no `copilot` (there is no public copilot LinkedAgentId).\n * - The CLI's self-hosted `agent-provisioning.ts` additionally accepts\n * bare `'claude'` and `'copilot'` (deploy payloads have carried\n * already-internal ids), but not the house agent.\n * Consumers that must REJECT ids outside their own historical set keep\n * their own guard on top (e.g. `isLinkedAgentId`).\n */\nexport const PUBLIC_TO_INTERNAL: Readonly<\n Record<LinkedAgentId | 'claude' | 'copilot', AgentId>\n> = {\n claude_code: 'claude',\n // CLI-side extra: self-hosted deploy payloads may carry the internal id.\n claude: 'claude',\n codex: 'codex',\n // CLI-side extra: copilot has no public LinkedAgentId (backend doesn't\n // expose it) but the self-hosted path accepts it.\n copilot: 'copilot',\n cursor: 'cursor',\n aider: 'aider',\n coderabbit: 'coderabbit',\n gemini: 'gemini',\n kimi: 'kimi',\n // The house agent runs Claude Code under the hood (pointed at the\n // MiniMax proxy). Its internal runtime is therefore `claude`.\n [HOUSE_AGENT_ID]: 'claude',\n};\n\n/**\n * Internal → public. Partial: `copilot` has no public LinkedAgentId, and\n * `claude` maps back to `claude_code` (never the house agent — that\n * direction is intentionally lossy).\n */\nexport const INTERNAL_TO_PUBLIC: Readonly<Partial<Record<AgentId, LinkedAgentId>>> = {\n claude: 'claude_code',\n codex: 'codex',\n cursor: 'cursor',\n aider: 'aider',\n coderabbit: 'coderabbit',\n gemini: 'gemini',\n kimi: 'kimi',\n};\n\nfunction isPublicToInternalKey(v: string): v is LinkedAgentId | 'claude' | 'copilot' {\n // Not Object.hasOwn — the VS Code plugin's tsconfig lib predates ES2022.\n return Object.prototype.hasOwnProperty.call(PUBLIC_TO_INTERNAL, v);\n}\n\n/** Resolve a public/linked id to the internal `AgentId`, or null. */\nexport function publicToInternal(publicId: string): AgentId | null {\n return isPublicToInternalKey(publicId) ? PUBLIC_TO_INTERNAL[publicId] : null;\n}\n\n/** Resolve an internal `AgentId` to its public `LinkedAgentId`, or null. */\nexport function internalToPublic(internal: AgentId): LinkedAgentId | null {\n return INTERNAL_TO_PUBLIC[internal] ?? null;\n}\n\n// ─── Alias normalization ─────────────────────────────────────────────────────\n\n/** Prefix IDE plugins use for terminal-hosted agent ids. */\nexport const TERMINAL_AGENT_PREFIX = '__terminal__:';\n\n/**\n * Known aliases → internal `AgentId`. Union of every alias set that used\n * to live scattered across the surfaces: the public `claude_code` id, the\n * VS Code / Open VSX marketplace extension ids, and JetBrains plugin ids.\n */\nconst AGENT_ID_ALIASES: Readonly<Record<string, AgentId>> = {\n claude_code: 'claude',\n 'claude-code': 'claude',\n 'anthropic.claude-code': 'claude',\n 'anthropics.claude': 'claude',\n 'anthropic.claude-ce': 'claude',\n 'anthropic.claude': 'claude',\n 'com.anthropic.claudecode': 'claude',\n 'com.anthropic.claude': 'claude',\n 'openai.chatgpt': 'codex',\n 'coderabbitai.coderabbit-vscode': 'coderabbit',\n};\n\n/**\n * THE agent-id normalizer. Collapses every known spelling of an agent id\n * (registry id, public `claude_code` form, marketplace extension id,\n * `__terminal__:`-prefixed plugin id — case/whitespace tolerant) onto the\n * internal `AgentId`, or `null` when unknown.\n *\n * Deliberately does NOT:\n * - gate on `enabled` (callers that need availability check the\n * registry — see the VS Code wrapper `normalizeCliAgentId`);\n * - map the house agent (that's a runtime substitution, not an alias —\n * use {@link publicToInternal});\n * - fall back to anything. Unknown in → `null` out.\n */\nexport function normalizeAgentId(raw: string): AgentId | null {\n const value = (raw ?? '').trim().toLowerCase();\n if (!value) return null;\n\n if (isKnownAgentId(value)) return value;\n\n const unprefixed = value.startsWith(TERMINAL_AGENT_PREFIX)\n ? value.slice(TERMINAL_AGENT_PREFIX.length)\n : value;\n if (isKnownAgentId(unprefixed)) return unprefixed;\n\n return AGENT_ID_ALIASES[unprefixed] ?? null;\n}\n\n// ─── Headroom kind derivation ────────────────────────────────────────────────\n\n/**\n * The `headroom init --global <kind>` subcommand for an agent id, derived\n * from the registry's `headroomKind` flags — or `null` for unknown or\n * non-wrappable agents (cursor / gemini / aider / anything else).\n *\n * ⚠️ NEVER falls back to `'claude'`. The historical CLI fallback is how\n * the 2026-06 Cursor incident happened: an unsupported agent slipped\n * through, defaulted to `claude`, and `headroom wrap claude` launched\n * Claude Code instead of the user's agent. Callers that genuinely need a\n * default (e.g. picking an init subcommand AFTER the wrappable gate has\n * already passed) apply it themselves — see the CLI's\n * `agentIdToHeadroomKind` wrapper.\n *\n * Matching mirrors the historical predicates on BOTH sides (CLI\n * `isHeadroomSupportedAgent`, api-v2 `isHeadroomWrappableAgent`):\n * case-insensitive, `_`/`-` tolerant, prefix match — so `claude_code`,\n * `Claude-Code`, `codex_cli`, `copilot-cli` all resolve.\n */\nexport function headroomKindFor(agentId: string): HeadroomKind | null {\n const normalized = (agentId ?? '').toLowerCase().replace(/[_-]/g, '');\n if (!normalized) return null;\n for (const meta of Object.values(AGENT_REGISTRY)) {\n if (meta.headroomKind !== undefined && normalized.startsWith(meta.id)) {\n return meta.headroomKind;\n }\n }\n return null;\n}\n\n/**\n * Registry-derived replacement for the two scattered predicates\n * (`isHeadroomSupportedAgent` in the CLI, `isHeadroomWrappableAgent` in\n * api-v2). Accepts both id spaces (`claude_code` and `claude`).\n */\nexport function isHeadroomWrappable(agentId: string): boolean {\n return headroomKindFor(agentId) !== null;\n}\n","import type { IntegrationDefinition, IntegrationId } from './types';\n\n/**\n * The single source of truth for supported integrations. Adding one =\n * 1 entry here + 1 backend OAuth provider + icon. The `delivery` spec is\n * resolved into deploy manifests and executed as data by the CLI, so a new\n * MCP integration with no special logic needs no CLI release.\n */\nexport const INTEGRATION_REGISTRY: Record<IntegrationId, IntegrationDefinition> = {\n jira: {\n id: 'jira',\n name: 'Jira',\n icon: 'jira',\n enabled: true,\n auth: {\n kind: 'oauth_redirect',\n scopes: ['read:jira-work', 'write:jira-work', 'offline_access'],\n },\n delivery: {\n mcp: {\n // mcp-atlassian in BYO-token mode (headless; credentials via env only).\n // Version PINNED to the exact release verified headless by Plan 2's\n // Docker integration test (apps/cli mcp-shim.int.test.ts).\n command: 'uvx',\n args: ['mcp-atlassian==0.22.1'],\n envMapping: {\n ATLASSIAN_OAUTH_ACCESS_TOKEN: 'accessToken',\n ATLASSIAN_OAUTH_CLOUD_ID: 'cloudId',\n },\n // Without ATLASSIAN_OAUTH_ENABLE=true, JiraConfig.from_env() raises\n // \"Missing required JIRA_URL\" (swallowed at server startup) and the\n // server silently registers ZERO Jira tools. The flag activates\n // mcp-atlassian's \"minimal OAuth config for user-provided tokens\"\n // mode — the BYO-token path the broker feeds. Static + non-secret.\n staticEnv: { ATLASSIAN_OAUTH_ENABLE: 'true' },\n },\n },\n },\n};\n\nexport function getEnabledIntegrations(): IntegrationDefinition[] {\n return Object.values(INTEGRATION_REGISTRY).filter((m) => m.enabled);\n}\n\nexport function getIntegration(id: IntegrationId): IntegrationDefinition {\n const meta = INTEGRATION_REGISTRY[id];\n if (!meta) throw new Error(`Unknown integration id: ${id}`);\n return meta;\n}\n\nexport function isKnownIntegrationId(id: string): id is IntegrationId {\n return id in INTEGRATION_REGISTRY;\n}\n","/**\n * Production API base URL for all CodeAgent Mobile clients.\n *\n * History note: prod migrated from Vercel (`https://api.codeagent-mobile.com`)\n * to Cloud Run / api-v2 (`https://api.codeagent-mobile.com`) in 2026-05. The\n * Vercel deployment is now gated by Vercel deployment protection and returns\n * 403 for unauthed traffic — DO NOT fall back to it.\n *\n * Override at runtime with `CODEAM_API_URL` (full URL override) OR set\n * `CODEAM_TEST_MODE=1` to point every client request at the dev\n * preview without having to know its host.\n */\nexport const DEFAULT_API_BASE_URL = 'https://api.codeagent-mobile.com' as const;\n\n/**\n * Dev-preview API base URL. Same Cloud Run service as prod but routed\n * to the `dev` revision (auto-deploys from the `dev` branch in the\n * backend repo). Manual smoke tests + load runs land here.\n */\nexport const DEV_API_BASE_URL = 'https://dev-api.codeagent-mobile.com' as const;\n\n/**\n * Resolve the active API base URL, honoring in priority order:\n *\n * 1. Explicit `CODEAM_API_URL` env var — full URL, takes precedence.\n * 2. `CODEAM_TEST_MODE=1` shortcut — flips to [DEV_API_BASE_URL]\n * without the user having to know the dev host.\n * 3. The `DEFAULT_API_BASE_URL` constant (prod).\n *\n * Used by every CLI service that talks to the backend so one env var\n * flips heartbeats, command relay, chunk uploads, and the pairing\n * flow in lockstep — eliminates the cross-environment misroute where\n * pairing succeeds in dev (shared Redis) but the CLI keeps\n * heartbeating to prod.\n */\nexport function resolveApiBaseUrl(): string {\n // Guard against non-Node runtimes (browser bundles import this\n // module). `process` is undefined there; treat as prod default.\n // `@codeam/shared` deliberately avoids depending on `@types/node`\n // so its types stay consumable from the mobile RN bundle too, so we\n // reach for the env via a structural cast rather than NodeJS.ProcessEnv.\n const env = (globalThis as { process?: { env?: Record<string, string | undefined> } }).process?.env;\n const explicit = env?.CODEAM_API_URL?.trim();\n if (explicit) return explicit;\n const testFlag = env?.CODEAM_TEST_MODE?.trim();\n if (testFlag === '1' || testFlag?.toLowerCase() === 'true') return DEV_API_BASE_URL;\n return DEFAULT_API_BASE_URL;\n}\n","/**\n * Headroom provisioning manifest — the SINGLE source of truth for what a\n * Headroom install consists of, rendered by every provisioning surface:\n *\n * - codespace bootstrap (bash composer in the backend repo,\n * `apps/api-v2/src/codespaces/github-ssh.service.ts` — adopts in PR-2),\n * - self-hosted deploy (TS installer, CLI `commands/host-agent.ts`\n * `setupHeadroomForSelfHosted`),\n * - on-demand local sessions (\"Session add-ons → Cost-saving\", CLI\n * `services/headroom/configure.ts`).\n *\n * Values are DATA-first (arrays/records, plus tiny pure renderers) so both\n * the TS installer and a bash composer can interpolate from them. Renderers\n * are byte-exact with the literals they replaced — guarded by\n * `packages/shared/__tests__/headroom-manifest.test.ts`.\n *\n * ⚠️ The extras matter: `[proxy,code]` pulls the ONNX compression engines\n * (Kompress + tree-sitter CodeCompressor). NEVER add `[ml]` — that's\n * multi-GB PyTorch, and a broken/cold torch wedges every prompt at\n * \"Thinking…\". The models are pre-downloaded at provision time because the\n * proxy eager-loads with `allow_download=False` and a cold cache defers the\n * ~840 MB download to the first prompt (blowing the agent's ~90 s idle\n * timeout).\n */\n\n/** Local proxy port the agent's config is routed to. */\nexport const HEADROOM_PROXY_PORT = 8787;\n\n/**\n * Env that pins the ONNX backend on the proxy process — never imports\n * torch. Spread into the proxy launch env on every surface.\n */\nexport const HEADROOM_BACKEND_ENV = {\n HEADROOM_KOMPRESS_BACKEND: 'onnx_cpu',\n} as const;\n\n/**\n * The proxy's HTTP/server companion packages, installed alongside the\n * `headroom-ai[...]` package. The COMPRESSION ENGINES come from the\n * headroom-ai extras — NOT this list.\n */\nexport const HEADROOM_PIP_COMPANIONS: readonly string[] = [\n 'fastapi',\n 'uvicorn',\n 'httpx[http2]',\n 'websockets',\n 'zstandard',\n];\n\n/** The three provisioning surfaces (see module doc). */\nexport type HeadroomSurface = 'codespace' | 'selfHosted' | 'onDemand';\n\n/**\n * pip extras per surface. `onDemand` additionally ships `image`\n * (image-compression support, added with the Session add-ons path in\n * codeam-cli@2.49.0); the older codespace/self-hosted install strings\n * remain `[proxy,code]` byte-for-byte.\n */\nexport const HEADROOM_EXTRAS_BY_SURFACE: Readonly<Record<HeadroomSurface, readonly string[]>> = {\n codespace: ['proxy', 'code'],\n selfHosted: ['proxy', 'code'],\n onDemand: ['proxy', 'code', 'image'],\n};\n\n/** `headroom-ai[<extras>]` — the pip requirement string. */\nexport function headroomPipPackage(extras: readonly string[]): string {\n return `headroom-ai[${extras.join(',')}]`;\n}\n\n/** One HuggingFace repo to pre-warm into the HF cache at provision time. */\nexport interface HeadroomModelSpec {\n repo: string;\n /** `snapshot_download(..., allow_patterns=[…])` filter. */\n allowPatterns: readonly string[];\n}\n\n/**\n * The two HF repos Kompress needs. kompress-v2-base is the ONNX model\n * (skip its .pt/.safetensors torch artifacts); ModernBERT-base is the\n * TOKENIZER ONLY (skip its model weights).\n */\nexport const HEADROOM_MODELS: readonly HeadroomModelSpec[] = [\n {\n repo: 'chopratejas/kompress-v2-base',\n allowPatterns: ['*.json', 'onnx/*.onnx', 'kompress-int8-wo.onnx'],\n },\n {\n repo: 'answerdotai/ModernBERT-base',\n allowPatterns: ['*.json', 'tokenizer*', '*.txt', 'vocab*', 'merges*'],\n },\n];\n\n/** Formatting knob so each surface can stay byte-identical to its\n * historical literal (the CLI joins patterns with `,`, the codespace\n * bash composer with `, `). */\nexport interface HeadroomPythonRenderOpts {\n /** Put a space after the commas between allow_patterns entries. */\n spaceAfterComma?: boolean;\n}\n\n/** Render one `snapshot_download(...)` python line for a model. */\nexport function headroomSnapshotDownloadLine(\n model: HeadroomModelSpec,\n opts: HeadroomPythonRenderOpts = {},\n): string {\n const sep = opts.spaceAfterComma ? ', ' : ',';\n const patterns = model.allowPatterns.map((p) => `\"${p}\"`).join(sep);\n return `snapshot_download(\"${model.repo}\", allow_patterns=[${patterns}])`;\n}\n\n/**\n * The full model pre-download python snippet (import + one\n * `snapshot_download` per model), newline-joined — what the surfaces pass\n * to `python -c` / a heredoc.\n */\nexport function headroomModelPredownloadScript(opts: HeadroomPythonRenderOpts = {}): string {\n return [\n 'from huggingface_hub import snapshot_download',\n ...HEADROOM_MODELS.map((m) => headroomSnapshotDownloadLine(m, opts)),\n ].join('\\n');\n}\n","/**\n * Canonical names of the per-user SSE bus events (`/api/users/me/stream`).\n *\n * The authoritative list is the `UserEvent` discriminated union in the\n * backend repo: codeagent-mobile/apps/api-v2/src/user-events/user-events.types.ts.\n * Every `type:` literal of that union appears here exactly once — when a new\n * variant lands on the union, add its name here (and in the backend mirror of\n * this file at codeagent-mobile/packages/shared/src/types/events.ts).\n *\n * Producers (CLI event posts, backend `userEvents.publish` calls) and\n * consumers (the `useUserEventsSSE` hooks' switch cases) should reference\n * `USER_EVENTS.*` instead of re-typing the string, so a typo becomes a\n * compile error instead of a silently dropped event.\n */\nexport const USER_EVENTS = {\n PAIRED_SESSION_STATUS: 'paired_session_status',\n PAIRED_SESSION_ADDED: 'paired_session_added',\n PAIRED_SESSION_REMOVED: 'paired_session_removed',\n PAIRED_SESSION_BRANCH_CHANGED: 'paired_session_branch_changed',\n SHARED_WITH_ME_ADDED: 'shared_with_me_added',\n SHARED_WITH_ME_REVOKED: 'shared_with_me_revoked',\n USAGE_CHANGED: 'usage_changed',\n TASK_DONE: 'task_done',\n HUNK_PENDING_REVIEW_ADDED: 'hunk_pending_review_added',\n HUNK_REVIEW_RESOLVED: 'hunk_review_resolved',\n FILE_CHANGED: 'file_changed',\n FILES_BATCH_CHANGED: 'files_batch_changed',\n AGENT_STREAMING_CHUNK: 'agent_streaming_chunk',\n AGENT_AWAITING_ANSWER: 'agent_awaiting_answer',\n AWAITING_INPUT_ADDED: 'awaiting_input_added',\n AGENT_ANSWER_RESOLVED: 'agent_answer_resolved',\n TEMPLATE_ADDED: 'template_added',\n TEMPLATE_REMOVED: 'template_removed',\n TEMPLATE_UPDATED: 'template_updated',\n AGENT_TASK_DISPATCHED: 'agent_task_dispatched',\n AGENT_TASK_COMPLETED: 'agent_task_completed',\n LINKED_AGENT_ADDED: 'linked_agent_added',\n QUOTA_REACHED: 'quota_reached',\n LINKED_AGENT_LINK_FAILED: 'linked_agent_link_failed',\n CODESPACE_AGENT_INSTALLED: 'codespace_agent_installed',\n AGENT_CREDENTIALS_REFRESHED: 'agent_credentials_refreshed',\n CREDENTIAL_INVALID: 'credential_invalid',\n CODESPACE_WAKING: 'codespace_waking',\n CODESPACE_BILLING_BLOCKED: 'codespace_billing_blocked',\n COST_SAVING_UPDATED: 'cost_saving_updated',\n COMMAND_COMPLETED: 'command_completed',\n AI_SUMMARY_PENDING: 'ai_summary_pending',\n AI_SUMMARY_READY: 'ai_summary_ready',\n AI_INSIGHT_PENDING: 'ai_insight_pending',\n AI_INSIGHT_READY: 'ai_insight_ready',\n PUSH_TOKEN_INVALIDATED: 'push_token_invalidated',\n PREVIEW_DETECTION_PENDING: 'preview_detection_pending',\n PREVIEW_DETECTION_READY: 'preview_detection_ready',\n PREVIEW_STARTING: 'preview_starting',\n PREVIEW_READY: 'preview_ready',\n PREVIEW_STOPPED: 'preview_stopped',\n PREVIEW_ERROR: 'preview_error',\n PREVIEW_PROGRESS: 'preview_progress',\n BEADS_STATE_CHANGED: 'beads_state_changed',\n BEADS_PROVISIONING: 'beads_provisioning',\n BEADS_TEAM_MEMORY_CHANGED: 'beads_team_memory_changed',\n AUDIT_EVENT_ADDED: 'audit_event_added',\n SELF_HOSTED_HOST_ADDED: 'self_hosted_host_added',\n SELF_HOSTED_HOST_STATUS: 'self_hosted_host_status',\n SELF_HOSTED_HOST_REMOVED: 'self_hosted_host_removed',\n SELF_HOSTED_HOST_TELEMETRY: 'self_hosted_host_telemetry',\n SELF_HOSTED_HOST_METRICS: 'self_hosted_host_metrics',\n SELF_HOSTED_HOST_SESSIONS: 'self_hosted_host_sessions',\n SELF_HOSTED_DEPLOY_PROGRESS: 'self_hosted_deploy_progress',\n REFERRAL_REWARD_EARNED: 'referral_reward_earned',\n HEADROOM_PROGRESS: 'headroom_progress',\n HEADROOM_STATUS: 'headroom_status',\n BEADS_STATUS: 'beads_status',\n LINKED_AGENT_HEADROOM_BUDGET_UPDATED: 'linked_agent_headroom_budget_updated',\n CLI_UPDATE_AVAILABLE: 'cli_update_available',\n AGENT_INSTALL_PROGRESS: 'agent_install_progress',\n AGENT_INSTALL_FAILED: 'agent_install_failed',\n CLI_UPDATE_PROGRESS: 'cli_update_progress',\n CLI_UPDATE_FAILED: 'cli_update_failed',\n BATON_STATE: 'baton_state',\n INTEGRATION_LINKED: 'integration_linked',\n INTEGRATION_UNLINKED: 'integration_unlinked',\n INTEGRATION_CREDENTIAL_INVALID: 'integration_credential_invalid',\n // CodeRabbit reviewer — the CLI posts these to /api/coderabbit/events; the\n // backend re-publishes them on the per-user SSE bus (mirrored in repo A).\n CODERABBIT_PROGRESS: 'coderabbit_progress',\n CODERABBIT_STATUS: 'coderabbit_status',\n CODERABBIT_REVIEW: 'coderabbit_review',\n} as const;\n\nexport type UserEventName = (typeof USER_EVENTS)[keyof typeof USER_EVENTS];\n","/**\n * Prompt the CLI sends to the user's linked agent (Claude, Codex, …)\n * in a headless one-shot to detect how to start the project's dev\n * server. Same pattern as the AI Insights \"summary\" prompt — the\n * agent runs locally with the user's auth, has read access to the\n * project, and returns a tiny JSON blob the CLI parses.\n *\n * Kept here (in `@codeam/shared`) so the CLI build inlines the\n * exact string at compile time without runtime fetch from the backend.\n */\nexport const PREVIEW_DETECT_PROMPT = `\nAnalyze the project in the current working directory and return how to start\nits development server for in-app preview.\n\nRead package.json, Procfile, Dockerfile, docker-compose.yml, manage.py, app.json,\nmix.exs, Cargo.toml, go.mod, requirements.txt, Gemfile, and any other framework\nmarkers you find at depth <= 2.\n\nReturn ONLY a JSON object on stdout (no prose, no markdown fences):\n\n{\n \"framework\": \"<name, or 'unsupported'>\",\n \"command\": \"<executable>\",\n \"args\": [\"...\"],\n \"port\": <number>,\n \"ready_pattern\": \"<regex matching the server-ready stdout line>\",\n \"env\": { \"HOST\": \"0.0.0.0\" },\n \"setup_commands\": [{ \"cmd\": \"<executable>\", \"args\": [\"...\"] }],\n \"notes\": \"<one-line caveat or null>\"\n}\n\nRules:\n- Pick the script the developer would run locally to see the app (typically \"dev\", \"start\", \"serve\").\n- Prefer binding to 0.0.0.0 — most frameworks default to localhost which the tunnel cannot reach.\n- For Expo: framework=\"Expo\", command=\"npx\", args=[\"expo\",\"start\",\"--tunnel\"], port=8081, notes=\"Scan QR with Expo Go\".\n- If no dev server applies (CLI library, lambda, batch script): {\"framework\":\"unsupported\",\"notes\":\"<reason>\"}.\n\nCRITICAL — setup_commands:\n- DO NOT include an install command (npm install, pnpm install, yarn install,\n yarn, bun install) in setup_commands. A lockfile-aware pre-flight installer\n runs BEFORE setup_commands and picks the correct package manager from the\n lockfile present (pnpm-lock.yaml -> pnpm, yarn.lock -> yarn, bun.lockb -> bun,\n else npm). Emitting an install here either duplicates that work or, worse,\n uses the WRONG package manager on top of node_modules just populated by the\n pre-flight, which crashes (e.g. npm errors with \"Cannot read properties of\n null (reading 'matches')\" when run over pnpm's .pnpm/ layout).\n- ONLY include setup_commands for genuinely non-install work the project needs\n before its dev server can boot: prisma generate, codegen, prebuild scripts,\n database migrations against a local SQLite, etc.\n- Each setup_commands entry MUST be an object {\"cmd\": \"...\", \"args\": [\"...\"]} —\n e.g. {\"cmd\": \"npx\", \"args\": [\"prisma\", \"generate\"]}. NOT a bare string.\n- For most projects, setup_commands should be an empty array [].\n\nOUTPUT JSON ONLY. NO MARKDOWN. NO COMMENTARY.\n`.trim();\n"],"mappings":"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","names":[]}
|
package/dist/index.mjs
CHANGED
|
@@ -448,6 +448,50 @@ function isHeadroomWrappable(agentId) {
|
|
|
448
448
|
return headroomKindFor(agentId) !== null;
|
|
449
449
|
}
|
|
450
450
|
|
|
451
|
+
// src/integrations/registry.ts
|
|
452
|
+
var INTEGRATION_REGISTRY = {
|
|
453
|
+
jira: {
|
|
454
|
+
id: "jira",
|
|
455
|
+
name: "Jira",
|
|
456
|
+
icon: "jira",
|
|
457
|
+
enabled: true,
|
|
458
|
+
auth: {
|
|
459
|
+
kind: "oauth_redirect",
|
|
460
|
+
scopes: ["read:jira-work", "write:jira-work", "offline_access"]
|
|
461
|
+
},
|
|
462
|
+
delivery: {
|
|
463
|
+
mcp: {
|
|
464
|
+
// mcp-atlassian in BYO-token mode (headless; credentials via env only).
|
|
465
|
+
// Version PINNED to the exact release verified headless by Plan 2's
|
|
466
|
+
// Docker integration test (apps/cli mcp-shim.int.test.ts).
|
|
467
|
+
command: "uvx",
|
|
468
|
+
args: ["mcp-atlassian==0.22.1"],
|
|
469
|
+
envMapping: {
|
|
470
|
+
ATLASSIAN_OAUTH_ACCESS_TOKEN: "accessToken",
|
|
471
|
+
ATLASSIAN_OAUTH_CLOUD_ID: "cloudId"
|
|
472
|
+
},
|
|
473
|
+
// Without ATLASSIAN_OAUTH_ENABLE=true, JiraConfig.from_env() raises
|
|
474
|
+
// "Missing required JIRA_URL" (swallowed at server startup) and the
|
|
475
|
+
// server silently registers ZERO Jira tools. The flag activates
|
|
476
|
+
// mcp-atlassian's "minimal OAuth config for user-provided tokens"
|
|
477
|
+
// mode — the BYO-token path the broker feeds. Static + non-secret.
|
|
478
|
+
staticEnv: { ATLASSIAN_OAUTH_ENABLE: "true" }
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
};
|
|
483
|
+
function getEnabledIntegrations() {
|
|
484
|
+
return Object.values(INTEGRATION_REGISTRY).filter((m) => m.enabled);
|
|
485
|
+
}
|
|
486
|
+
function getIntegration(id) {
|
|
487
|
+
const meta = INTEGRATION_REGISTRY[id];
|
|
488
|
+
if (!meta) throw new Error(`Unknown integration id: ${id}`);
|
|
489
|
+
return meta;
|
|
490
|
+
}
|
|
491
|
+
function isKnownIntegrationId(id) {
|
|
492
|
+
return id in INTEGRATION_REGISTRY;
|
|
493
|
+
}
|
|
494
|
+
|
|
451
495
|
// src/api-url.ts
|
|
452
496
|
var DEFAULT_API_BASE_URL = "https://api.codeagent-mobile.com";
|
|
453
497
|
var DEV_API_BASE_URL = "https://dev-api.codeagent-mobile.com";
|
|
@@ -569,6 +613,9 @@ var USER_EVENTS = {
|
|
|
569
613
|
CLI_UPDATE_PROGRESS: "cli_update_progress",
|
|
570
614
|
CLI_UPDATE_FAILED: "cli_update_failed",
|
|
571
615
|
BATON_STATE: "baton_state",
|
|
616
|
+
INTEGRATION_LINKED: "integration_linked",
|
|
617
|
+
INTEGRATION_UNLINKED: "integration_unlinked",
|
|
618
|
+
INTEGRATION_CREDENTIAL_INVALID: "integration_credential_invalid",
|
|
572
619
|
// CodeRabbit reviewer — the CLI posts these to /api/coderabbit/events; the
|
|
573
620
|
// backend re-publishes them on the per-user SSE bus (mirrored in repo A).
|
|
574
621
|
CODERABBIT_PROGRESS: "coderabbit_progress",
|
|
@@ -637,6 +684,7 @@ export {
|
|
|
637
684
|
HOUSE_AGENT_PROVIDER,
|
|
638
685
|
HOUSE_AGENT_SUBTITLE,
|
|
639
686
|
HOUSE_AGENT_VENDOR,
|
|
687
|
+
INTEGRATION_REGISTRY,
|
|
640
688
|
INTERNAL_TO_PUBLIC,
|
|
641
689
|
LINKED_AGENT_IDS,
|
|
642
690
|
MODEL_CONTEXT_WINDOW,
|
|
@@ -652,6 +700,8 @@ export {
|
|
|
652
700
|
getAgent,
|
|
653
701
|
getContextWindow,
|
|
654
702
|
getEnabledAgents,
|
|
703
|
+
getEnabledIntegrations,
|
|
704
|
+
getIntegration,
|
|
655
705
|
getPricing,
|
|
656
706
|
headroomKindFor,
|
|
657
707
|
headroomModelPredownloadScript,
|
|
@@ -660,6 +710,7 @@ export {
|
|
|
660
710
|
internalToPublic,
|
|
661
711
|
isHeadroomWrappable,
|
|
662
712
|
isKnownAgentId,
|
|
713
|
+
isKnownIntegrationId,
|
|
663
714
|
isKnownModel,
|
|
664
715
|
isLinkedAgentId,
|
|
665
716
|
normalizeAgentId,
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/protocol/constants.ts","../src/protocol/renderToLines.ts","../src/protocol/remote-command.ts","../src/models/pricing.ts","../src/agents/registry.ts","../src/agents/identity.ts","../src/api-url.ts","../src/headroom/manifest.ts","../src/types/events.ts","../src/preview-prompts.ts"],"sourcesContent":["/**\n * Shared wire / lifecycle constants. The values here are bundled\n * into the CLI + VS Code extension at build time via tsup / esbuild\n * and mirrored in `apps/jetbrains-plugin/.../protocol/Constants.kt`\n * since Kotlin can't import an npm package.\n *\n * If you change one of these values, also update the Kotlin mirror.\n */\n\n/**\n * Discriminated chunk-protocol version sent as the\n * `X-Codeam-Protocol-Version` header on every authed request. The\n * backend uses this to opt into legacy translations or to reject\n * with 426 when the client is too far behind. Bumped in lockstep\n * with chunk-shape changes (e.g. when the `chrome_steps` chunk\n * type is added).\n */\nexport const PROTOCOL_VERSION = '2.0.0' as const;\n\n/**\n * The VS Code AgentOutputMonitor's loopback HTTP server bound to\n * 127.0.0.1 on this port — the observer JS in the IDE renderer\n * uses it to round-trip captured chat content back into the\n * extension host. The port is intentionally fixed (rather than\n * `listen(0)`) so the observer script can be a static constant\n * rather than dynamically rewriting itself per session.\n *\n * Multi-window collision is solved by listen(0) per-window in the\n * monitor (see #103); this default is still the documented\n * starting port for tooling that needs to probe whether a CodeAgent\n * Mobile session is active locally.\n */\nexport const OBSERVER_BRIDGE_PORT = 47832;\n\n/**\n * Default plugin → backend heartbeat interval. User-configurable\n * via `codeagent-mobile.heartbeatIntervalMs` on VS Code and\n * `heartbeatIntervalMs` in SettingsService.kt's @State on JetBrains.\n * Mirrors the value the apps/api side uses to flip the paired\n * session to offline.\n */\nexport const HEARTBEAT_INTERVAL_MS_DEFAULT = 30_000;\n\n/**\n * SSE + polling reconnect cap. Vercel's serverless functions close\n * SSE connections after ~25 s by default; the client uses 35 s as\n * its overall socket timeout to leave a beat for graceful close.\n */\nexport const SSE_SOCKET_TIMEOUT_MS = 35_000;\n","/**\n * Render raw PTY bytes into an array of screen lines using a simplified\n * virtual terminal. Handles cursor movements (A/B/C/D/G/H), erase (J/K),\n * alternate-screen (?1049h), carriage return, and LF.\n *\n * This is the authoritative implementation used by both codeam-cli (PTY\n * output) and the VS Code extension (shell-integration output) so that\n * the mobile/web client sees identical chunks regardless of surface.\n */\nexport function renderToLines(raw: string): string[] {\n const screen: string[] = [''];\n let row = 0;\n let col = 0;\n\n function ensureRow(): void {\n while (screen.length <= row) screen.push('');\n }\n\n function writeChar(ch: string): void {\n ensureRow();\n if (col < screen[row].length) {\n screen[row] = screen[row].slice(0, col) + ch + screen[row].slice(col + 1);\n } else {\n while (screen[row].length < col) screen[row] += ' ';\n screen[row] += ch;\n }\n col++;\n }\n\n let i = 0;\n while (i < raw.length) {\n const ch = raw[i];\n\n if (ch === '\\x1B') {\n i++;\n if (i >= raw.length) break;\n\n if (raw[i] === '[') {\n i++;\n let param = '';\n while (i < raw.length && !/[@-~]/.test(raw[i])) param += raw[i++];\n const cmd = raw[i] ?? '';\n const n = parseInt(param) || 1;\n\n if (cmd === 'A') { row = Math.max(0, row - n); }\n else if (cmd === 'B') { row += n; ensureRow(); }\n else if (cmd === 'C') { col += n; }\n else if (cmd === 'D') { col = Math.max(0, col - n); }\n else if (cmd === 'G') { col = Math.max(0, n - 1); }\n else if (cmd === 'H' || cmd === 'f') {\n const p = param.split(';');\n row = Math.max(0, (parseInt(p[0] ?? '1') || 1) - 1);\n col = Math.max(0, (parseInt(p[1] ?? '1') || 1) - 1);\n ensureRow();\n } else if (cmd === 'J') {\n if (param === '2' || param === '3') {\n screen.length = 1; screen[0] = ''; row = 0; col = 0;\n } else if (param === '1') {\n for (let r = 0; r < row; r++) screen[r] = '';\n screen[row] = ' '.repeat(col) + screen[row].slice(col);\n } else {\n screen[row] = screen[row].slice(0, col);\n screen.splice(row + 1);\n }\n } else if (cmd === 'K') {\n ensureRow();\n if (param === '' || param === '0') screen[row] = screen[row].slice(0, col);\n else if (param === '1') screen[row] = ' '.repeat(col) + screen[row].slice(col);\n else if (param === '2') screen[row] = '';\n } else if (cmd === 'h' && (param === '?1049' || param === '?47')) {\n screen.length = 1; screen[0] = ''; row = 0; col = 0;\n } else if (cmd === 'l' && (param === '?1049' || param === '?47')) {\n screen.length = 1; screen[0] = ''; row = 0; col = 0;\n }\n } else if (raw[i] === ']') {\n i++;\n while (i < raw.length) {\n if (raw[i] === '\\x07') break;\n if (raw[i] === '\\x1B' && i + 1 < raw.length && raw[i + 1] === '\\\\') { i++; break; }\n i++;\n }\n }\n } else if (ch === '\\r') {\n if (i + 1 < raw.length && raw[i + 1] === '\\n') {\n row++; col = 0; ensureRow(); i++;\n } else {\n col = 0;\n }\n } else if (ch === '\\n') {\n row++; col = 0; ensureRow();\n } else if (ch >= ' ' || ch === '\\t') {\n writeChar(ch);\n }\n\n i++;\n }\n\n return screen;\n}\n","import { z } from 'zod';\n\n/**\n * The command envelope clients receive from the backend relay — both from\n * the `commands` SSE frames on `/api/commands/pending/stream` and from the\n * `GET /api/commands/pending` polling fallback. One schema, shared, so the\n * VS Code extension (and eventually the CLI) stop blind-casting\n * `Record<string, unknown>` into this shape.\n */\nexport interface RemoteCommand {\n id: string;\n sessionId: string;\n pluginId: string;\n type: string;\n payload: Record<string, unknown>;\n status: string;\n createdAt: number;\n}\n\nconst remoteCommandSchema = z.object({\n id: z.string(),\n sessionId: z.string(),\n pluginId: z.string(),\n type: z.string(),\n // The backend may omit `payload` (or send null) for payload-less commands;\n // clients have always normalized that to `{}` — keep that behavior here.\n payload: z.record(z.string(), z.unknown()).nullish(),\n status: z.string(),\n createdAt: z.number(),\n});\n\n/**\n * Validate a raw (already JSON-parsed) value into a `RemoteCommand`.\n * Returns `null` — never throws — on a malformed envelope so callers can\n * log-and-skip the single bad command without dropping the whole batch.\n */\nexport function toRemoteCommand(raw: unknown): RemoteCommand | null {\n const parsed = remoteCommandSchema.safeParse(raw);\n if (!parsed.success) return null;\n const { payload, ...rest } = parsed.data;\n return { ...rest, payload: payload ?? {} };\n}\n","export interface ModelPricing {\n input: number;\n output: number;\n cacheRead: number;\n cacheWrite: number;\n}\n\nexport const MODEL_PRICING: Record<string, ModelPricing> = {\n // ── Anthropic / Claude ────────────────────────────────────\n // The 4.x rows below cover the model ids actually emitted by the CLI\n // (apps/cli/src/agents/claude/runtime.ts listModels) and the JetBrains\n // fallback catalog (RemoteCommandRouter.kt). Prices are copied from the\n // same-family base rows (claude-opus-4 / claude-sonnet-4 /\n // claude-3-5-haiku) until distinct published rates land.\n 'claude-opus-4-7': { input: 15, output: 75, cacheRead: 1.50, cacheWrite: 18.75 },\n 'claude-opus-4-6': { input: 15, output: 75, cacheRead: 1.50, cacheWrite: 18.75 },\n 'claude-sonnet-4-6': { input: 3, output: 15, cacheRead: 0.30, cacheWrite: 3.75 },\n // Haiku-tier prices copied from claude-3-5-haiku (closest same-tier\n // sibling in this table) — previously this id matched NO row and was\n // silently billed at sonnet rates via the unknown-model fallback.\n 'claude-haiku-4-5': { input: 0.80, output: 4, cacheRead: 0.08, cacheWrite: 1 },\n 'claude-sonnet-4': { input: 3, output: 15, cacheRead: 0.30, cacheWrite: 3.75 },\n 'claude-opus-4': { input: 15, output: 75, cacheRead: 1.50, cacheWrite: 18.75 },\n 'claude-3-5-sonnet': { input: 3, output: 15, cacheRead: 0.30, cacheWrite: 3.75 },\n 'claude-3-5-haiku': { input: 0.80, output: 4, cacheRead: 0.08, cacheWrite: 1 },\n 'claude-3-haiku': { input: 0.25, output: 1.25, cacheRead: 0.03, cacheWrite: 0.30 },\n\n // ── Codex / OpenAI ────────────────────────────────────────\n // GPT-5.x rows are derived from OpenAI's published GPT-5 family rates\n // (standard tier: $1.25/1M in, $10/1M out, cached input at ~10% of input;\n // mini tier: $0.25/1M in, $2/1M out). OpenAI has no separate cache-WRITE\n // premium, so cacheWrite mirrors the input rate. Replace with the exact\n // per-version numbers from developers.openai.com/pricing when published —\n // these were the ZERO placeholders that rendered Codex sessions as $0.\n 'gpt-5.5': { input: 1.25, output: 10, cacheRead: 0.125, cacheWrite: 1.25 },\n 'gpt-5.4': { input: 1.25, output: 10, cacheRead: 0.125, cacheWrite: 1.25 },\n 'gpt-5.4-mini': { input: 0.25, output: 2, cacheRead: 0.025, cacheWrite: 0.25 },\n 'gpt-5.3-codex': { input: 1.25, output: 10, cacheRead: 0.125, cacheWrite: 1.25 },\n 'gpt-5.2': { input: 1.25, output: 10, cacheRead: 0.125, cacheWrite: 1.25 },\n 'codex-auto-review': { input: 1.25, output: 10, cacheRead: 0.125, cacheWrite: 1.25 },\n};\n\nexport const MODEL_CONTEXT_WINDOW: Record<string, number> = {\n // ── Anthropic / Claude ────────────────────────────────────\n 'claude-opus-4-7': 1_000_000,\n 'claude-opus-4-6': 1_000_000,\n 'claude-sonnet-4-6': 1_000_000,\n 'claude-haiku-4-5': 200_000,\n 'claude-opus-4': 1_000_000,\n 'claude-sonnet-4': 1_000_000,\n 'claude-3-5-sonnet': 200_000,\n 'claude-3-5-haiku': 200_000,\n 'claude-3-haiku': 200_000,\n\n // ── Codex / OpenAI ────────────────────────────────────────\n 'gpt-5.5': 272_000,\n 'gpt-5.4': 272_000,\n 'gpt-5.4-mini': 272_000,\n 'gpt-5.3-codex': 272_000,\n 'gpt-5.2': 272_000,\n 'codex-auto-review': 272_000,\n};\n\nconst DEFAULT_CONTEXT_WINDOW = 200_000;\n\n/**\n * Longest-prefix lookup. The tables key by model-family prefix; a model id\n * like `claude-opus-4-7` must resolve to its own row, not be shadowed by the\n * shorter `claude-opus-4` — so the match is by prefix LENGTH, never by the\n * table's insertion order.\n */\nfunction longestPrefixMatch<T>(table: Record<string, T>, model: string): T | undefined {\n let best: T | undefined;\n let bestLen = -1;\n for (const [prefix, value] of Object.entries(table)) {\n if (prefix.length > bestLen && model.startsWith(prefix)) {\n best = value;\n bestLen = prefix.length;\n }\n }\n return best;\n}\n\n/** True when the model id resolves to a real MODEL_PRICING row (i.e. getPricing\n * will NOT be guessing via the unknown-model fallback). */\nexport function isKnownModel(model: string): boolean {\n return longestPrefixMatch(MODEL_PRICING, model) !== undefined;\n}\n\n/**\n * Flagged default for an unpriced model id. All-zero so an unknown model is\n * VISIBLY unpriced ($0) rather than silently MISPRICED at some other family's\n * rates (the old sonnet-4 fallback billed unknown ids — including a haiku id\n * that matched no row — at sonnet rates). `getPricing` returns this object for\n * unknown ids so callers that do unconditional arithmetic still work; callers\n * that must distinguish real pricing from the default check `isKnownModel`.\n */\nexport const UNKNOWN_MODEL_PRICING: ModelPricing = {\n input: 0,\n output: 0,\n cacheRead: 0,\n cacheWrite: 0,\n};\n\n/**\n * Resolve pricing by longest matching prefix. Unknown models resolve to the\n * flagged {@link UNKNOWN_MODEL_PRICING} default (all-zero, i.e. visibly\n * unpriced) instead of guessing at another model's rates. Callers that need to\n * distinguish real pricing from the default must check `isKnownModel(model)`.\n */\nexport function getPricing(model: string): ModelPricing {\n return longestPrefixMatch(MODEL_PRICING, model) ?? UNKNOWN_MODEL_PRICING;\n}\n\nexport function getContextWindow(model: string | null): number {\n if (!model) return DEFAULT_CONTEXT_WINDOW;\n return longestPrefixMatch(MODEL_CONTEXT_WINDOW, model) ?? DEFAULT_CONTEXT_WINDOW;\n}\n","import type { AgentId, AgentMetadata } from './types';\n\nexport const AGENT_REGISTRY: Record<AgentId, AgentMetadata> = {\n claude: {\n id: 'claude',\n displayName: 'Claude Code',\n binaryName: 'claude',\n enabled: true,\n // Mirrors the backend registry (codeagent-mobile\n // apps/api-v2/src/codespaces/agent.ts — authoritative for auth\n // capabilities). `setup_token` is the bare `sk-ant-oat01-…` from\n // `claude setup-token` → delivered via CLAUDE_CODE_OAUTH_TOKEN.\n supportedAuthKinds: ['setup_token', 'oauth_token', 'api_key'],\n preferredAuthKind: 'setup_token',\n headroomWrappable: true,\n headroomKind: 'claude',\n // npm adapter `@agentclientprotocol/claude-agent-acp`.\n acp: true,\n },\n codex: {\n id: 'codex',\n displayName: 'Codex CLI',\n binaryName: 'codex',\n enabled: true,\n supportedAuthKinds: ['oauth_token', 'api_key'],\n preferredAuthKind: 'oauth_token',\n headroomWrappable: true,\n headroomKind: 'codex',\n // npm adapter `@agentclientprotocol/codex-acp`.\n acp: true,\n // OAuth device-code flow; the user_code on the OpenAI page IS a real\n // human-typed code — surfaces render it (with a copy affordance).\n deviceFlow: true,\n showsUserCode: true,\n },\n copilot: {\n id: 'copilot',\n displayName: 'GitHub Copilot CLI',\n binaryName: 'gh',\n enabled: false,\n supportedAuthKinds: ['oauth_token'],\n preferredAuthKind: 'oauth_token',\n // `headroom init --global copilot` exists even though the agent is\n // still disabled here (no runtime builder yet).\n headroomWrappable: true,\n headroomKind: 'copilot',\n acp: false,\n },\n coderabbit: {\n id: 'coderabbit',\n displayName: 'CodeRabbit',\n binaryName: 'coderabbit',\n enabled: true,\n // CodeRabbit links via a CLI-driven LOOPBACK OAuth (`coderabbit auth\n // login --agent`): the CLI captures the token and hands it to the vault\n // through `linkFromCli` (method:'oauth'), same as the terminal handoff.\n // `oauth_token` is preferred; a real API key is still accepted as a\n // fallback. There is no backend PKCE provider — the loopback runs on the\n // user's own machine, so linking is always CLI-mediated.\n supportedAuthKinds: ['oauth_token', 'api_key'],\n preferredAuthKind: 'oauth_token',\n headroomWrappable: false,\n // Legacy PTY runtime — no ACP adapter registered.\n acp: false,\n },\n cursor: {\n id: 'cursor',\n displayName: 'Cursor Agent',\n binaryName: 'cursor-agent',\n enabled: true,\n // Backend registry is authoritative: since the Cursor OAuth\n // device-flow shipped, new links are oauth_token only (the login\n // blob written to ~/.config/cursor/auth.json). Legacy vaulted\n // api_key rows may still exist server-side, but the link surface\n // no longer offers api_key.\n supportedAuthKinds: ['oauth_token'],\n preferredAuthKind: 'oauth_token',\n // `headroom wrap cursor` is \"manual/print-only\" (IDE settings; the\n // headless cursor-agent CLI has no base-URL override) — runs native.\n headroomWrappable: false,\n // Native ACP server: `cursor-agent acp`.\n acp: true,\n // Reverse-engineered device/poll flow; `userCode` is the secret PKCE\n // verifier echoed back on poll — NEVER human-facing.\n deviceFlow: true,\n showsUserCode: false,\n },\n aider: {\n id: 'aider',\n displayName: 'Aider',\n binaryName: 'aider',\n enabled: true,\n // Aider is OAuth-less — auth is via ANTHROPIC_API_KEY / OPENAI_API_KEY\n // / etc. env vars or `~/.aider.conf.yml`. The link flow surfaces\n // this via the existing --api-key escape hatch in commands/link.ts.\n supportedAuthKinds: ['api_key'],\n preferredAuthKind: 'api_key',\n headroomWrappable: false,\n // Legacy PTY runtime — no ACP adapter registered.\n acp: false,\n },\n gemini: {\n id: 'gemini',\n displayName: 'Gemini CLI',\n binaryName: 'gemini',\n enabled: true,\n // OAuth via `gemini auth login` (captured by `codeam link gemini`\n // from ~/.gemini/oauth_creds.json) AND GEMINI_API_KEY are both\n // accepted by the backend's GeminiProvisioningStrategy and propagated\n // into codespace deploys.\n supportedAuthKinds: ['oauth_token', 'api_key'],\n preferredAuthKind: 'oauth_token',\n // Not listed by `headroom wrap --help` — runs native.\n headroomWrappable: false,\n // Native ACP server: `gemini --skip-trust --acp`.\n acp: true,\n },\n kimi: {\n id: 'kimi',\n displayName: 'Kimi Code',\n binaryName: 'kimi',\n enabled: true,\n // API key (KIMI_API_KEY, + optional KIMI_BASE_URL) is the shipping auth —\n // fully documented, no reverse-engineering. OAuth `/login` (login-state at\n // ~/.kimi-code/credentials/<name>.json, base https://api.kimi.com/coding/)\n // is declared so it can land later without a wire change, but capturing\n // that blob server-side is a separate reverse-engineering spike (phase 2).\n supportedAuthKinds: ['api_key', 'oauth_token'],\n preferredAuthKind: 'api_key',\n // Moonshot's `kimi` is not listed by `headroom wrap --help` — runs native.\n headroomWrappable: false,\n // Native ACP server: `kimi acp` (stdio JSON-RPC, answers `initialize`).\n acp: true,\n },\n};\n\nexport function getEnabledAgents(): AgentMetadata[] {\n return Object.values(AGENT_REGISTRY).filter(m => m.enabled);\n}\n\nexport function getAgent(id: AgentId): AgentMetadata {\n const meta = AGENT_REGISTRY[id];\n if (!meta) throw new Error(`Unknown agent id: ${id}`);\n return meta;\n}\n\nexport function isKnownAgentId(id: string): id is AgentId {\n return id in AGENT_REGISTRY;\n}\n","/**\n * Agent identity — the ONE place the public (`LinkedAgentId`) and internal\n * (`AgentId`) id spaces are declared and bridged, plus the ONE alias\n * normalizer every surface funnels through.\n *\n * Canonical values consolidated from (Phase 2, PR-1):\n * - backend `apps/api-v2/src/linked-agents/agent-map.ts`\n * (`PUBLIC_TO_INTERNAL` / `INTERNAL_TO_PUBLIC` / `LinkedAgentId`),\n * - CLI `apps/cli/src/commands/host/agent-provisioning.ts`\n * (`PUBLIC_TO_INTERNAL_AGENT`),\n * - VS Code plugin `apps/vsc-plugin/src/utils/cli-agent-id.ts`\n * (marketplace aliases + `__terminal__:` strip),\n * - CLI `apps/cli/src/commands/start/handlers.ts`\n * (the `claude_code` → `claude` normalization),\n * - mobile `apps/mobile/src/lib/agent-id-map.ts`.\n */\n\nimport type { AgentId, HeadroomKind } from './types';\nimport { AGENT_REGISTRY, isKnownAgentId } from './registry';\n\n// ─── House agent constants ───────────────────────────────────────────────────\n// Byte-identical mirrors of the backend repo's canonical\n// `codeagent-mobile/packages/shared/src/constants/house-agent.ts` (which the\n// api-v2 additionally hand-mirrors in `common/constants/house-agent.ts`).\n// PR-3 replaces those copies with re-exports of THESE.\n\n/** Sentinel id for the synthetic \"CodeAgent Cloud (incluido)\" house agent. */\nexport const HOUSE_AGENT_ID = 'house-codeagent-cloud';\n\n/** Internal provider discriminator for the house agent. */\nexport const HOUSE_AGENT_PROVIDER = 'codeagent_cloud';\n\n/** White-label display strings — never mention the backend model. */\nexport const HOUSE_AGENT_NAME = 'CodeAgent Cloud';\nexport const HOUSE_AGENT_VENDOR = 'CodeAgent';\nexport const HOUSE_AGENT_SUBTITLE = 'Included — no setup';\n\n// ─── Public (LinkedAgent) id space ───────────────────────────────────────────\n\n/**\n * Public-facing linked-agent ids — the id space the `/api/agents/...`\n * endpoints and the mobile/web surfaces speak. The internal `AgentId`\n * (`'claude' | 'codex' | …`) is what the runtimes / provisioning key on.\n */\nexport type LinkedAgentId =\n | 'claude_code'\n | 'codex'\n | 'cursor'\n | 'aider'\n | 'coderabbit'\n | 'gemini'\n | 'kimi'\n | typeof HOUSE_AGENT_ID;\n\nexport const LINKED_AGENT_IDS: readonly LinkedAgentId[] = [\n 'claude_code',\n 'codex',\n 'cursor',\n 'aider',\n 'coderabbit',\n 'gemini',\n 'kimi',\n HOUSE_AGENT_ID,\n];\n\nexport function isLinkedAgentId(value: string): value is LinkedAgentId {\n return (LINKED_AGENT_IDS as readonly string[]).includes(value);\n}\n\n/**\n * Every public id → internal `AgentId`.\n *\n * ⚠️ RECONCILED ASYMMETRY — this map is the UNION of what the two sides\n * historically accepted:\n * - The backend's `agent-map.ts` accepts only the `LinkedAgentId` union\n * (incl. the house agent, whose runtime is Claude Code) — no bare\n * `claude`, no `copilot` (there is no public copilot LinkedAgentId).\n * - The CLI's self-hosted `agent-provisioning.ts` additionally accepts\n * bare `'claude'` and `'copilot'` (deploy payloads have carried\n * already-internal ids), but not the house agent.\n * Consumers that must REJECT ids outside their own historical set keep\n * their own guard on top (e.g. `isLinkedAgentId`).\n */\nexport const PUBLIC_TO_INTERNAL: Readonly<\n Record<LinkedAgentId | 'claude' | 'copilot', AgentId>\n> = {\n claude_code: 'claude',\n // CLI-side extra: self-hosted deploy payloads may carry the internal id.\n claude: 'claude',\n codex: 'codex',\n // CLI-side extra: copilot has no public LinkedAgentId (backend doesn't\n // expose it) but the self-hosted path accepts it.\n copilot: 'copilot',\n cursor: 'cursor',\n aider: 'aider',\n coderabbit: 'coderabbit',\n gemini: 'gemini',\n kimi: 'kimi',\n // The house agent runs Claude Code under the hood (pointed at the\n // MiniMax proxy). Its internal runtime is therefore `claude`.\n [HOUSE_AGENT_ID]: 'claude',\n};\n\n/**\n * Internal → public. Partial: `copilot` has no public LinkedAgentId, and\n * `claude` maps back to `claude_code` (never the house agent — that\n * direction is intentionally lossy).\n */\nexport const INTERNAL_TO_PUBLIC: Readonly<Partial<Record<AgentId, LinkedAgentId>>> = {\n claude: 'claude_code',\n codex: 'codex',\n cursor: 'cursor',\n aider: 'aider',\n coderabbit: 'coderabbit',\n gemini: 'gemini',\n kimi: 'kimi',\n};\n\nfunction isPublicToInternalKey(v: string): v is LinkedAgentId | 'claude' | 'copilot' {\n // Not Object.hasOwn — the VS Code plugin's tsconfig lib predates ES2022.\n return Object.prototype.hasOwnProperty.call(PUBLIC_TO_INTERNAL, v);\n}\n\n/** Resolve a public/linked id to the internal `AgentId`, or null. */\nexport function publicToInternal(publicId: string): AgentId | null {\n return isPublicToInternalKey(publicId) ? PUBLIC_TO_INTERNAL[publicId] : null;\n}\n\n/** Resolve an internal `AgentId` to its public `LinkedAgentId`, or null. */\nexport function internalToPublic(internal: AgentId): LinkedAgentId | null {\n return INTERNAL_TO_PUBLIC[internal] ?? null;\n}\n\n// ─── Alias normalization ─────────────────────────────────────────────────────\n\n/** Prefix IDE plugins use for terminal-hosted agent ids. */\nexport const TERMINAL_AGENT_PREFIX = '__terminal__:';\n\n/**\n * Known aliases → internal `AgentId`. Union of every alias set that used\n * to live scattered across the surfaces: the public `claude_code` id, the\n * VS Code / Open VSX marketplace extension ids, and JetBrains plugin ids.\n */\nconst AGENT_ID_ALIASES: Readonly<Record<string, AgentId>> = {\n claude_code: 'claude',\n 'claude-code': 'claude',\n 'anthropic.claude-code': 'claude',\n 'anthropics.claude': 'claude',\n 'anthropic.claude-ce': 'claude',\n 'anthropic.claude': 'claude',\n 'com.anthropic.claudecode': 'claude',\n 'com.anthropic.claude': 'claude',\n 'openai.chatgpt': 'codex',\n 'coderabbitai.coderabbit-vscode': 'coderabbit',\n};\n\n/**\n * THE agent-id normalizer. Collapses every known spelling of an agent id\n * (registry id, public `claude_code` form, marketplace extension id,\n * `__terminal__:`-prefixed plugin id — case/whitespace tolerant) onto the\n * internal `AgentId`, or `null` when unknown.\n *\n * Deliberately does NOT:\n * - gate on `enabled` (callers that need availability check the\n * registry — see the VS Code wrapper `normalizeCliAgentId`);\n * - map the house agent (that's a runtime substitution, not an alias —\n * use {@link publicToInternal});\n * - fall back to anything. Unknown in → `null` out.\n */\nexport function normalizeAgentId(raw: string): AgentId | null {\n const value = (raw ?? '').trim().toLowerCase();\n if (!value) return null;\n\n if (isKnownAgentId(value)) return value;\n\n const unprefixed = value.startsWith(TERMINAL_AGENT_PREFIX)\n ? value.slice(TERMINAL_AGENT_PREFIX.length)\n : value;\n if (isKnownAgentId(unprefixed)) return unprefixed;\n\n return AGENT_ID_ALIASES[unprefixed] ?? null;\n}\n\n// ─── Headroom kind derivation ────────────────────────────────────────────────\n\n/**\n * The `headroom init --global <kind>` subcommand for an agent id, derived\n * from the registry's `headroomKind` flags — or `null` for unknown or\n * non-wrappable agents (cursor / gemini / aider / anything else).\n *\n * ⚠️ NEVER falls back to `'claude'`. The historical CLI fallback is how\n * the 2026-06 Cursor incident happened: an unsupported agent slipped\n * through, defaulted to `claude`, and `headroom wrap claude` launched\n * Claude Code instead of the user's agent. Callers that genuinely need a\n * default (e.g. picking an init subcommand AFTER the wrappable gate has\n * already passed) apply it themselves — see the CLI's\n * `agentIdToHeadroomKind` wrapper.\n *\n * Matching mirrors the historical predicates on BOTH sides (CLI\n * `isHeadroomSupportedAgent`, api-v2 `isHeadroomWrappableAgent`):\n * case-insensitive, `_`/`-` tolerant, prefix match — so `claude_code`,\n * `Claude-Code`, `codex_cli`, `copilot-cli` all resolve.\n */\nexport function headroomKindFor(agentId: string): HeadroomKind | null {\n const normalized = (agentId ?? '').toLowerCase().replace(/[_-]/g, '');\n if (!normalized) return null;\n for (const meta of Object.values(AGENT_REGISTRY)) {\n if (meta.headroomKind !== undefined && normalized.startsWith(meta.id)) {\n return meta.headroomKind;\n }\n }\n return null;\n}\n\n/**\n * Registry-derived replacement for the two scattered predicates\n * (`isHeadroomSupportedAgent` in the CLI, `isHeadroomWrappableAgent` in\n * api-v2). Accepts both id spaces (`claude_code` and `claude`).\n */\nexport function isHeadroomWrappable(agentId: string): boolean {\n return headroomKindFor(agentId) !== null;\n}\n","/**\n * Production API base URL for all CodeAgent Mobile clients.\n *\n * History note: prod migrated from Vercel (`https://api.codeagent-mobile.com`)\n * to Cloud Run / api-v2 (`https://api.codeagent-mobile.com`) in 2026-05. The\n * Vercel deployment is now gated by Vercel deployment protection and returns\n * 403 for unauthed traffic — DO NOT fall back to it.\n *\n * Override at runtime with `CODEAM_API_URL` (full URL override) OR set\n * `CODEAM_TEST_MODE=1` to point every client request at the dev\n * preview without having to know its host.\n */\nexport const DEFAULT_API_BASE_URL = 'https://api.codeagent-mobile.com' as const;\n\n/**\n * Dev-preview API base URL. Same Cloud Run service as prod but routed\n * to the `dev` revision (auto-deploys from the `dev` branch in the\n * backend repo). Manual smoke tests + load runs land here.\n */\nexport const DEV_API_BASE_URL = 'https://dev-api.codeagent-mobile.com' as const;\n\n/**\n * Resolve the active API base URL, honoring in priority order:\n *\n * 1. Explicit `CODEAM_API_URL` env var — full URL, takes precedence.\n * 2. `CODEAM_TEST_MODE=1` shortcut — flips to [DEV_API_BASE_URL]\n * without the user having to know the dev host.\n * 3. The `DEFAULT_API_BASE_URL` constant (prod).\n *\n * Used by every CLI service that talks to the backend so one env var\n * flips heartbeats, command relay, chunk uploads, and the pairing\n * flow in lockstep — eliminates the cross-environment misroute where\n * pairing succeeds in dev (shared Redis) but the CLI keeps\n * heartbeating to prod.\n */\nexport function resolveApiBaseUrl(): string {\n // Guard against non-Node runtimes (browser bundles import this\n // module). `process` is undefined there; treat as prod default.\n // `@codeam/shared` deliberately avoids depending on `@types/node`\n // so its types stay consumable from the mobile RN bundle too, so we\n // reach for the env via a structural cast rather than NodeJS.ProcessEnv.\n const env = (globalThis as { process?: { env?: Record<string, string | undefined> } }).process?.env;\n const explicit = env?.CODEAM_API_URL?.trim();\n if (explicit) return explicit;\n const testFlag = env?.CODEAM_TEST_MODE?.trim();\n if (testFlag === '1' || testFlag?.toLowerCase() === 'true') return DEV_API_BASE_URL;\n return DEFAULT_API_BASE_URL;\n}\n","/**\n * Headroom provisioning manifest — the SINGLE source of truth for what a\n * Headroom install consists of, rendered by every provisioning surface:\n *\n * - codespace bootstrap (bash composer in the backend repo,\n * `apps/api-v2/src/codespaces/github-ssh.service.ts` — adopts in PR-2),\n * - self-hosted deploy (TS installer, CLI `commands/host-agent.ts`\n * `setupHeadroomForSelfHosted`),\n * - on-demand local sessions (\"Session add-ons → Cost-saving\", CLI\n * `services/headroom/configure.ts`).\n *\n * Values are DATA-first (arrays/records, plus tiny pure renderers) so both\n * the TS installer and a bash composer can interpolate from them. Renderers\n * are byte-exact with the literals they replaced — guarded by\n * `packages/shared/__tests__/headroom-manifest.test.ts`.\n *\n * ⚠️ The extras matter: `[proxy,code]` pulls the ONNX compression engines\n * (Kompress + tree-sitter CodeCompressor). NEVER add `[ml]` — that's\n * multi-GB PyTorch, and a broken/cold torch wedges every prompt at\n * \"Thinking…\". The models are pre-downloaded at provision time because the\n * proxy eager-loads with `allow_download=False` and a cold cache defers the\n * ~840 MB download to the first prompt (blowing the agent's ~90 s idle\n * timeout).\n */\n\n/** Local proxy port the agent's config is routed to. */\nexport const HEADROOM_PROXY_PORT = 8787;\n\n/**\n * Env that pins the ONNX backend on the proxy process — never imports\n * torch. Spread into the proxy launch env on every surface.\n */\nexport const HEADROOM_BACKEND_ENV = {\n HEADROOM_KOMPRESS_BACKEND: 'onnx_cpu',\n} as const;\n\n/**\n * The proxy's HTTP/server companion packages, installed alongside the\n * `headroom-ai[...]` package. The COMPRESSION ENGINES come from the\n * headroom-ai extras — NOT this list.\n */\nexport const HEADROOM_PIP_COMPANIONS: readonly string[] = [\n 'fastapi',\n 'uvicorn',\n 'httpx[http2]',\n 'websockets',\n 'zstandard',\n];\n\n/** The three provisioning surfaces (see module doc). */\nexport type HeadroomSurface = 'codespace' | 'selfHosted' | 'onDemand';\n\n/**\n * pip extras per surface. `onDemand` additionally ships `image`\n * (image-compression support, added with the Session add-ons path in\n * codeam-cli@2.49.0); the older codespace/self-hosted install strings\n * remain `[proxy,code]` byte-for-byte.\n */\nexport const HEADROOM_EXTRAS_BY_SURFACE: Readonly<Record<HeadroomSurface, readonly string[]>> = {\n codespace: ['proxy', 'code'],\n selfHosted: ['proxy', 'code'],\n onDemand: ['proxy', 'code', 'image'],\n};\n\n/** `headroom-ai[<extras>]` — the pip requirement string. */\nexport function headroomPipPackage(extras: readonly string[]): string {\n return `headroom-ai[${extras.join(',')}]`;\n}\n\n/** One HuggingFace repo to pre-warm into the HF cache at provision time. */\nexport interface HeadroomModelSpec {\n repo: string;\n /** `snapshot_download(..., allow_patterns=[…])` filter. */\n allowPatterns: readonly string[];\n}\n\n/**\n * The two HF repos Kompress needs. kompress-v2-base is the ONNX model\n * (skip its .pt/.safetensors torch artifacts); ModernBERT-base is the\n * TOKENIZER ONLY (skip its model weights).\n */\nexport const HEADROOM_MODELS: readonly HeadroomModelSpec[] = [\n {\n repo: 'chopratejas/kompress-v2-base',\n allowPatterns: ['*.json', 'onnx/*.onnx', 'kompress-int8-wo.onnx'],\n },\n {\n repo: 'answerdotai/ModernBERT-base',\n allowPatterns: ['*.json', 'tokenizer*', '*.txt', 'vocab*', 'merges*'],\n },\n];\n\n/** Formatting knob so each surface can stay byte-identical to its\n * historical literal (the CLI joins patterns with `,`, the codespace\n * bash composer with `, `). */\nexport interface HeadroomPythonRenderOpts {\n /** Put a space after the commas between allow_patterns entries. */\n spaceAfterComma?: boolean;\n}\n\n/** Render one `snapshot_download(...)` python line for a model. */\nexport function headroomSnapshotDownloadLine(\n model: HeadroomModelSpec,\n opts: HeadroomPythonRenderOpts = {},\n): string {\n const sep = opts.spaceAfterComma ? ', ' : ',';\n const patterns = model.allowPatterns.map((p) => `\"${p}\"`).join(sep);\n return `snapshot_download(\"${model.repo}\", allow_patterns=[${patterns}])`;\n}\n\n/**\n * The full model pre-download python snippet (import + one\n * `snapshot_download` per model), newline-joined — what the surfaces pass\n * to `python -c` / a heredoc.\n */\nexport function headroomModelPredownloadScript(opts: HeadroomPythonRenderOpts = {}): string {\n return [\n 'from huggingface_hub import snapshot_download',\n ...HEADROOM_MODELS.map((m) => headroomSnapshotDownloadLine(m, opts)),\n ].join('\\n');\n}\n","/**\n * Canonical names of the per-user SSE bus events (`/api/users/me/stream`).\n *\n * The authoritative list is the `UserEvent` discriminated union in the\n * backend repo: codeagent-mobile/apps/api-v2/src/user-events/user-events.types.ts.\n * Every `type:` literal of that union appears here exactly once — when a new\n * variant lands on the union, add its name here (and in the backend mirror of\n * this file at codeagent-mobile/packages/shared/src/types/events.ts).\n *\n * Producers (CLI event posts, backend `userEvents.publish` calls) and\n * consumers (the `useUserEventsSSE` hooks' switch cases) should reference\n * `USER_EVENTS.*` instead of re-typing the string, so a typo becomes a\n * compile error instead of a silently dropped event.\n */\nexport const USER_EVENTS = {\n PAIRED_SESSION_STATUS: 'paired_session_status',\n PAIRED_SESSION_ADDED: 'paired_session_added',\n PAIRED_SESSION_REMOVED: 'paired_session_removed',\n PAIRED_SESSION_BRANCH_CHANGED: 'paired_session_branch_changed',\n SHARED_WITH_ME_ADDED: 'shared_with_me_added',\n SHARED_WITH_ME_REVOKED: 'shared_with_me_revoked',\n USAGE_CHANGED: 'usage_changed',\n TASK_DONE: 'task_done',\n HUNK_PENDING_REVIEW_ADDED: 'hunk_pending_review_added',\n HUNK_REVIEW_RESOLVED: 'hunk_review_resolved',\n FILE_CHANGED: 'file_changed',\n FILES_BATCH_CHANGED: 'files_batch_changed',\n AGENT_STREAMING_CHUNK: 'agent_streaming_chunk',\n AGENT_AWAITING_ANSWER: 'agent_awaiting_answer',\n AWAITING_INPUT_ADDED: 'awaiting_input_added',\n AGENT_ANSWER_RESOLVED: 'agent_answer_resolved',\n TEMPLATE_ADDED: 'template_added',\n TEMPLATE_REMOVED: 'template_removed',\n TEMPLATE_UPDATED: 'template_updated',\n AGENT_TASK_DISPATCHED: 'agent_task_dispatched',\n AGENT_TASK_COMPLETED: 'agent_task_completed',\n LINKED_AGENT_ADDED: 'linked_agent_added',\n QUOTA_REACHED: 'quota_reached',\n LINKED_AGENT_LINK_FAILED: 'linked_agent_link_failed',\n CODESPACE_AGENT_INSTALLED: 'codespace_agent_installed',\n AGENT_CREDENTIALS_REFRESHED: 'agent_credentials_refreshed',\n CREDENTIAL_INVALID: 'credential_invalid',\n CODESPACE_WAKING: 'codespace_waking',\n CODESPACE_BILLING_BLOCKED: 'codespace_billing_blocked',\n COST_SAVING_UPDATED: 'cost_saving_updated',\n COMMAND_COMPLETED: 'command_completed',\n AI_SUMMARY_PENDING: 'ai_summary_pending',\n AI_SUMMARY_READY: 'ai_summary_ready',\n AI_INSIGHT_PENDING: 'ai_insight_pending',\n AI_INSIGHT_READY: 'ai_insight_ready',\n PUSH_TOKEN_INVALIDATED: 'push_token_invalidated',\n PREVIEW_DETECTION_PENDING: 'preview_detection_pending',\n PREVIEW_DETECTION_READY: 'preview_detection_ready',\n PREVIEW_STARTING: 'preview_starting',\n PREVIEW_READY: 'preview_ready',\n PREVIEW_STOPPED: 'preview_stopped',\n PREVIEW_ERROR: 'preview_error',\n PREVIEW_PROGRESS: 'preview_progress',\n BEADS_STATE_CHANGED: 'beads_state_changed',\n BEADS_PROVISIONING: 'beads_provisioning',\n BEADS_TEAM_MEMORY_CHANGED: 'beads_team_memory_changed',\n AUDIT_EVENT_ADDED: 'audit_event_added',\n SELF_HOSTED_HOST_ADDED: 'self_hosted_host_added',\n SELF_HOSTED_HOST_STATUS: 'self_hosted_host_status',\n SELF_HOSTED_HOST_REMOVED: 'self_hosted_host_removed',\n SELF_HOSTED_HOST_TELEMETRY: 'self_hosted_host_telemetry',\n SELF_HOSTED_HOST_METRICS: 'self_hosted_host_metrics',\n SELF_HOSTED_HOST_SESSIONS: 'self_hosted_host_sessions',\n SELF_HOSTED_DEPLOY_PROGRESS: 'self_hosted_deploy_progress',\n REFERRAL_REWARD_EARNED: 'referral_reward_earned',\n HEADROOM_PROGRESS: 'headroom_progress',\n HEADROOM_STATUS: 'headroom_status',\n BEADS_STATUS: 'beads_status',\n LINKED_AGENT_HEADROOM_BUDGET_UPDATED: 'linked_agent_headroom_budget_updated',\n CLI_UPDATE_AVAILABLE: 'cli_update_available',\n AGENT_INSTALL_PROGRESS: 'agent_install_progress',\n AGENT_INSTALL_FAILED: 'agent_install_failed',\n CLI_UPDATE_PROGRESS: 'cli_update_progress',\n CLI_UPDATE_FAILED: 'cli_update_failed',\n BATON_STATE: 'baton_state',\n // CodeRabbit reviewer — the CLI posts these to /api/coderabbit/events; the\n // backend re-publishes them on the per-user SSE bus (mirrored in repo A).\n CODERABBIT_PROGRESS: 'coderabbit_progress',\n CODERABBIT_STATUS: 'coderabbit_status',\n CODERABBIT_REVIEW: 'coderabbit_review',\n} as const;\n\nexport type UserEventName = (typeof USER_EVENTS)[keyof typeof USER_EVENTS];\n","/**\n * Prompt the CLI sends to the user's linked agent (Claude, Codex, …)\n * in a headless one-shot to detect how to start the project's dev\n * server. Same pattern as the AI Insights \"summary\" prompt — the\n * agent runs locally with the user's auth, has read access to the\n * project, and returns a tiny JSON blob the CLI parses.\n *\n * Kept here (in `@codeam/shared`) so the CLI build inlines the\n * exact string at compile time without runtime fetch from the backend.\n */\nexport const PREVIEW_DETECT_PROMPT = `\nAnalyze the project in the current working directory and return how to start\nits development server for in-app preview.\n\nRead package.json, Procfile, Dockerfile, docker-compose.yml, manage.py, app.json,\nmix.exs, Cargo.toml, go.mod, requirements.txt, Gemfile, and any other framework\nmarkers you find at depth <= 2.\n\nReturn ONLY a JSON object on stdout (no prose, no markdown fences):\n\n{\n \"framework\": \"<name, or 'unsupported'>\",\n \"command\": \"<executable>\",\n \"args\": [\"...\"],\n \"port\": <number>,\n \"ready_pattern\": \"<regex matching the server-ready stdout line>\",\n \"env\": { \"HOST\": \"0.0.0.0\" },\n \"setup_commands\": [{ \"cmd\": \"<executable>\", \"args\": [\"...\"] }],\n \"notes\": \"<one-line caveat or null>\"\n}\n\nRules:\n- Pick the script the developer would run locally to see the app (typically \"dev\", \"start\", \"serve\").\n- Prefer binding to 0.0.0.0 — most frameworks default to localhost which the tunnel cannot reach.\n- For Expo: framework=\"Expo\", command=\"npx\", args=[\"expo\",\"start\",\"--tunnel\"], port=8081, notes=\"Scan QR with Expo Go\".\n- If no dev server applies (CLI library, lambda, batch script): {\"framework\":\"unsupported\",\"notes\":\"<reason>\"}.\n\nCRITICAL — setup_commands:\n- DO NOT include an install command (npm install, pnpm install, yarn install,\n yarn, bun install) in setup_commands. A lockfile-aware pre-flight installer\n runs BEFORE setup_commands and picks the correct package manager from the\n lockfile present (pnpm-lock.yaml -> pnpm, yarn.lock -> yarn, bun.lockb -> bun,\n else npm). Emitting an install here either duplicates that work or, worse,\n uses the WRONG package manager on top of node_modules just populated by the\n pre-flight, which crashes (e.g. npm errors with \"Cannot read properties of\n null (reading 'matches')\" when run over pnpm's .pnpm/ layout).\n- ONLY include setup_commands for genuinely non-install work the project needs\n before its dev server can boot: prisma generate, codegen, prebuild scripts,\n database migrations against a local SQLite, etc.\n- Each setup_commands entry MUST be an object {\"cmd\": \"...\", \"args\": [\"...\"]} —\n e.g. {\"cmd\": \"npx\", \"args\": [\"prisma\", \"generate\"]}. NOT a bare string.\n- For most projects, setup_commands should be an empty array [].\n\nOUTPUT JSON ONLY. NO MARKDOWN. NO COMMENTARY.\n`.trim();\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/protocol/constants.ts","../src/protocol/renderToLines.ts","../src/protocol/remote-command.ts","../src/models/pricing.ts","../src/agents/registry.ts","../src/agents/identity.ts","../src/integrations/registry.ts","../src/api-url.ts","../src/headroom/manifest.ts","../src/types/events.ts","../src/preview-prompts.ts"],"sourcesContent":["/**\n * Shared wire / lifecycle constants. The values here are bundled\n * into the CLI + VS Code extension at build time via tsup / esbuild\n * and mirrored in `apps/jetbrains-plugin/.../protocol/Constants.kt`\n * since Kotlin can't import an npm package.\n *\n * If you change one of these values, also update the Kotlin mirror.\n */\n\n/**\n * Discriminated chunk-protocol version sent as the\n * `X-Codeam-Protocol-Version` header on every authed request. The\n * backend uses this to opt into legacy translations or to reject\n * with 426 when the client is too far behind. Bumped in lockstep\n * with chunk-shape changes (e.g. when the `chrome_steps` chunk\n * type is added).\n */\nexport const PROTOCOL_VERSION = '2.0.0' as const;\n\n/**\n * The VS Code AgentOutputMonitor's loopback HTTP server bound to\n * 127.0.0.1 on this port — the observer JS in the IDE renderer\n * uses it to round-trip captured chat content back into the\n * extension host. The port is intentionally fixed (rather than\n * `listen(0)`) so the observer script can be a static constant\n * rather than dynamically rewriting itself per session.\n *\n * Multi-window collision is solved by listen(0) per-window in the\n * monitor (see #103); this default is still the documented\n * starting port for tooling that needs to probe whether a CodeAgent\n * Mobile session is active locally.\n */\nexport const OBSERVER_BRIDGE_PORT = 47832;\n\n/**\n * Default plugin → backend heartbeat interval. User-configurable\n * via `codeagent-mobile.heartbeatIntervalMs` on VS Code and\n * `heartbeatIntervalMs` in SettingsService.kt's @State on JetBrains.\n * Mirrors the value the apps/api side uses to flip the paired\n * session to offline.\n */\nexport const HEARTBEAT_INTERVAL_MS_DEFAULT = 30_000;\n\n/**\n * SSE + polling reconnect cap. Vercel's serverless functions close\n * SSE connections after ~25 s by default; the client uses 35 s as\n * its overall socket timeout to leave a beat for graceful close.\n */\nexport const SSE_SOCKET_TIMEOUT_MS = 35_000;\n","/**\n * Render raw PTY bytes into an array of screen lines using a simplified\n * virtual terminal. Handles cursor movements (A/B/C/D/G/H), erase (J/K),\n * alternate-screen (?1049h), carriage return, and LF.\n *\n * This is the authoritative implementation used by both codeam-cli (PTY\n * output) and the VS Code extension (shell-integration output) so that\n * the mobile/web client sees identical chunks regardless of surface.\n */\nexport function renderToLines(raw: string): string[] {\n const screen: string[] = [''];\n let row = 0;\n let col = 0;\n\n function ensureRow(): void {\n while (screen.length <= row) screen.push('');\n }\n\n function writeChar(ch: string): void {\n ensureRow();\n if (col < screen[row].length) {\n screen[row] = screen[row].slice(0, col) + ch + screen[row].slice(col + 1);\n } else {\n while (screen[row].length < col) screen[row] += ' ';\n screen[row] += ch;\n }\n col++;\n }\n\n let i = 0;\n while (i < raw.length) {\n const ch = raw[i];\n\n if (ch === '\\x1B') {\n i++;\n if (i >= raw.length) break;\n\n if (raw[i] === '[') {\n i++;\n let param = '';\n while (i < raw.length && !/[@-~]/.test(raw[i])) param += raw[i++];\n const cmd = raw[i] ?? '';\n const n = parseInt(param) || 1;\n\n if (cmd === 'A') { row = Math.max(0, row - n); }\n else if (cmd === 'B') { row += n; ensureRow(); }\n else if (cmd === 'C') { col += n; }\n else if (cmd === 'D') { col = Math.max(0, col - n); }\n else if (cmd === 'G') { col = Math.max(0, n - 1); }\n else if (cmd === 'H' || cmd === 'f') {\n const p = param.split(';');\n row = Math.max(0, (parseInt(p[0] ?? '1') || 1) - 1);\n col = Math.max(0, (parseInt(p[1] ?? '1') || 1) - 1);\n ensureRow();\n } else if (cmd === 'J') {\n if (param === '2' || param === '3') {\n screen.length = 1; screen[0] = ''; row = 0; col = 0;\n } else if (param === '1') {\n for (let r = 0; r < row; r++) screen[r] = '';\n screen[row] = ' '.repeat(col) + screen[row].slice(col);\n } else {\n screen[row] = screen[row].slice(0, col);\n screen.splice(row + 1);\n }\n } else if (cmd === 'K') {\n ensureRow();\n if (param === '' || param === '0') screen[row] = screen[row].slice(0, col);\n else if (param === '1') screen[row] = ' '.repeat(col) + screen[row].slice(col);\n else if (param === '2') screen[row] = '';\n } else if (cmd === 'h' && (param === '?1049' || param === '?47')) {\n screen.length = 1; screen[0] = ''; row = 0; col = 0;\n } else if (cmd === 'l' && (param === '?1049' || param === '?47')) {\n screen.length = 1; screen[0] = ''; row = 0; col = 0;\n }\n } else if (raw[i] === ']') {\n i++;\n while (i < raw.length) {\n if (raw[i] === '\\x07') break;\n if (raw[i] === '\\x1B' && i + 1 < raw.length && raw[i + 1] === '\\\\') { i++; break; }\n i++;\n }\n }\n } else if (ch === '\\r') {\n if (i + 1 < raw.length && raw[i + 1] === '\\n') {\n row++; col = 0; ensureRow(); i++;\n } else {\n col = 0;\n }\n } else if (ch === '\\n') {\n row++; col = 0; ensureRow();\n } else if (ch >= ' ' || ch === '\\t') {\n writeChar(ch);\n }\n\n i++;\n }\n\n return screen;\n}\n","import { z } from 'zod';\n\n/**\n * The command envelope clients receive from the backend relay — both from\n * the `commands` SSE frames on `/api/commands/pending/stream` and from the\n * `GET /api/commands/pending` polling fallback. One schema, shared, so the\n * VS Code extension (and eventually the CLI) stop blind-casting\n * `Record<string, unknown>` into this shape.\n */\nexport interface RemoteCommand {\n id: string;\n sessionId: string;\n pluginId: string;\n type: string;\n payload: Record<string, unknown>;\n status: string;\n createdAt: number;\n}\n\nconst remoteCommandSchema = z.object({\n id: z.string(),\n sessionId: z.string(),\n pluginId: z.string(),\n type: z.string(),\n // The backend may omit `payload` (or send null) for payload-less commands;\n // clients have always normalized that to `{}` — keep that behavior here.\n payload: z.record(z.string(), z.unknown()).nullish(),\n status: z.string(),\n createdAt: z.number(),\n});\n\n/**\n * Validate a raw (already JSON-parsed) value into a `RemoteCommand`.\n * Returns `null` — never throws — on a malformed envelope so callers can\n * log-and-skip the single bad command without dropping the whole batch.\n */\nexport function toRemoteCommand(raw: unknown): RemoteCommand | null {\n const parsed = remoteCommandSchema.safeParse(raw);\n if (!parsed.success) return null;\n const { payload, ...rest } = parsed.data;\n return { ...rest, payload: payload ?? {} };\n}\n","export interface ModelPricing {\n input: number;\n output: number;\n cacheRead: number;\n cacheWrite: number;\n}\n\nexport const MODEL_PRICING: Record<string, ModelPricing> = {\n // ── Anthropic / Claude ────────────────────────────────────\n // The 4.x rows below cover the model ids actually emitted by the CLI\n // (apps/cli/src/agents/claude/runtime.ts listModels) and the JetBrains\n // fallback catalog (RemoteCommandRouter.kt). Prices are copied from the\n // same-family base rows (claude-opus-4 / claude-sonnet-4 /\n // claude-3-5-haiku) until distinct published rates land.\n 'claude-opus-4-7': { input: 15, output: 75, cacheRead: 1.50, cacheWrite: 18.75 },\n 'claude-opus-4-6': { input: 15, output: 75, cacheRead: 1.50, cacheWrite: 18.75 },\n 'claude-sonnet-4-6': { input: 3, output: 15, cacheRead: 0.30, cacheWrite: 3.75 },\n // Haiku-tier prices copied from claude-3-5-haiku (closest same-tier\n // sibling in this table) — previously this id matched NO row and was\n // silently billed at sonnet rates via the unknown-model fallback.\n 'claude-haiku-4-5': { input: 0.80, output: 4, cacheRead: 0.08, cacheWrite: 1 },\n 'claude-sonnet-4': { input: 3, output: 15, cacheRead: 0.30, cacheWrite: 3.75 },\n 'claude-opus-4': { input: 15, output: 75, cacheRead: 1.50, cacheWrite: 18.75 },\n 'claude-3-5-sonnet': { input: 3, output: 15, cacheRead: 0.30, cacheWrite: 3.75 },\n 'claude-3-5-haiku': { input: 0.80, output: 4, cacheRead: 0.08, cacheWrite: 1 },\n 'claude-3-haiku': { input: 0.25, output: 1.25, cacheRead: 0.03, cacheWrite: 0.30 },\n\n // ── Codex / OpenAI ────────────────────────────────────────\n // GPT-5.x rows are derived from OpenAI's published GPT-5 family rates\n // (standard tier: $1.25/1M in, $10/1M out, cached input at ~10% of input;\n // mini tier: $0.25/1M in, $2/1M out). OpenAI has no separate cache-WRITE\n // premium, so cacheWrite mirrors the input rate. Replace with the exact\n // per-version numbers from developers.openai.com/pricing when published —\n // these were the ZERO placeholders that rendered Codex sessions as $0.\n 'gpt-5.5': { input: 1.25, output: 10, cacheRead: 0.125, cacheWrite: 1.25 },\n 'gpt-5.4': { input: 1.25, output: 10, cacheRead: 0.125, cacheWrite: 1.25 },\n 'gpt-5.4-mini': { input: 0.25, output: 2, cacheRead: 0.025, cacheWrite: 0.25 },\n 'gpt-5.3-codex': { input: 1.25, output: 10, cacheRead: 0.125, cacheWrite: 1.25 },\n 'gpt-5.2': { input: 1.25, output: 10, cacheRead: 0.125, cacheWrite: 1.25 },\n 'codex-auto-review': { input: 1.25, output: 10, cacheRead: 0.125, cacheWrite: 1.25 },\n};\n\nexport const MODEL_CONTEXT_WINDOW: Record<string, number> = {\n // ── Anthropic / Claude ────────────────────────────────────\n 'claude-opus-4-7': 1_000_000,\n 'claude-opus-4-6': 1_000_000,\n 'claude-sonnet-4-6': 1_000_000,\n 'claude-haiku-4-5': 200_000,\n 'claude-opus-4': 1_000_000,\n 'claude-sonnet-4': 1_000_000,\n 'claude-3-5-sonnet': 200_000,\n 'claude-3-5-haiku': 200_000,\n 'claude-3-haiku': 200_000,\n\n // ── Codex / OpenAI ────────────────────────────────────────\n 'gpt-5.5': 272_000,\n 'gpt-5.4': 272_000,\n 'gpt-5.4-mini': 272_000,\n 'gpt-5.3-codex': 272_000,\n 'gpt-5.2': 272_000,\n 'codex-auto-review': 272_000,\n};\n\nconst DEFAULT_CONTEXT_WINDOW = 200_000;\n\n/**\n * Longest-prefix lookup. The tables key by model-family prefix; a model id\n * like `claude-opus-4-7` must resolve to its own row, not be shadowed by the\n * shorter `claude-opus-4` — so the match is by prefix LENGTH, never by the\n * table's insertion order.\n */\nfunction longestPrefixMatch<T>(table: Record<string, T>, model: string): T | undefined {\n let best: T | undefined;\n let bestLen = -1;\n for (const [prefix, value] of Object.entries(table)) {\n if (prefix.length > bestLen && model.startsWith(prefix)) {\n best = value;\n bestLen = prefix.length;\n }\n }\n return best;\n}\n\n/** True when the model id resolves to a real MODEL_PRICING row (i.e. getPricing\n * will NOT be guessing via the unknown-model fallback). */\nexport function isKnownModel(model: string): boolean {\n return longestPrefixMatch(MODEL_PRICING, model) !== undefined;\n}\n\n/**\n * Flagged default for an unpriced model id. All-zero so an unknown model is\n * VISIBLY unpriced ($0) rather than silently MISPRICED at some other family's\n * rates (the old sonnet-4 fallback billed unknown ids — including a haiku id\n * that matched no row — at sonnet rates). `getPricing` returns this object for\n * unknown ids so callers that do unconditional arithmetic still work; callers\n * that must distinguish real pricing from the default check `isKnownModel`.\n */\nexport const UNKNOWN_MODEL_PRICING: ModelPricing = {\n input: 0,\n output: 0,\n cacheRead: 0,\n cacheWrite: 0,\n};\n\n/**\n * Resolve pricing by longest matching prefix. Unknown models resolve to the\n * flagged {@link UNKNOWN_MODEL_PRICING} default (all-zero, i.e. visibly\n * unpriced) instead of guessing at another model's rates. Callers that need to\n * distinguish real pricing from the default must check `isKnownModel(model)`.\n */\nexport function getPricing(model: string): ModelPricing {\n return longestPrefixMatch(MODEL_PRICING, model) ?? UNKNOWN_MODEL_PRICING;\n}\n\nexport function getContextWindow(model: string | null): number {\n if (!model) return DEFAULT_CONTEXT_WINDOW;\n return longestPrefixMatch(MODEL_CONTEXT_WINDOW, model) ?? DEFAULT_CONTEXT_WINDOW;\n}\n","import type { AgentId, AgentMetadata } from './types';\n\nexport const AGENT_REGISTRY: Record<AgentId, AgentMetadata> = {\n claude: {\n id: 'claude',\n displayName: 'Claude Code',\n binaryName: 'claude',\n enabled: true,\n // Mirrors the backend registry (codeagent-mobile\n // apps/api-v2/src/codespaces/agent.ts — authoritative for auth\n // capabilities). `setup_token` is the bare `sk-ant-oat01-…` from\n // `claude setup-token` → delivered via CLAUDE_CODE_OAUTH_TOKEN.\n supportedAuthKinds: ['setup_token', 'oauth_token', 'api_key'],\n preferredAuthKind: 'setup_token',\n headroomWrappable: true,\n headroomKind: 'claude',\n // npm adapter `@agentclientprotocol/claude-agent-acp`.\n acp: true,\n },\n codex: {\n id: 'codex',\n displayName: 'Codex CLI',\n binaryName: 'codex',\n enabled: true,\n supportedAuthKinds: ['oauth_token', 'api_key'],\n preferredAuthKind: 'oauth_token',\n headroomWrappable: true,\n headroomKind: 'codex',\n // npm adapter `@agentclientprotocol/codex-acp`.\n acp: true,\n // OAuth device-code flow; the user_code on the OpenAI page IS a real\n // human-typed code — surfaces render it (with a copy affordance).\n deviceFlow: true,\n showsUserCode: true,\n },\n copilot: {\n id: 'copilot',\n displayName: 'GitHub Copilot CLI',\n binaryName: 'gh',\n enabled: false,\n supportedAuthKinds: ['oauth_token'],\n preferredAuthKind: 'oauth_token',\n // `headroom init --global copilot` exists even though the agent is\n // still disabled here (no runtime builder yet).\n headroomWrappable: true,\n headroomKind: 'copilot',\n acp: false,\n },\n coderabbit: {\n id: 'coderabbit',\n displayName: 'CodeRabbit',\n binaryName: 'coderabbit',\n enabled: true,\n // CodeRabbit links via a CLI-driven LOOPBACK OAuth (`coderabbit auth\n // login --agent`): the CLI captures the token and hands it to the vault\n // through `linkFromCli` (method:'oauth'), same as the terminal handoff.\n // `oauth_token` is preferred; a real API key is still accepted as a\n // fallback. There is no backend PKCE provider — the loopback runs on the\n // user's own machine, so linking is always CLI-mediated.\n supportedAuthKinds: ['oauth_token', 'api_key'],\n preferredAuthKind: 'oauth_token',\n headroomWrappable: false,\n // Legacy PTY runtime — no ACP adapter registered.\n acp: false,\n },\n cursor: {\n id: 'cursor',\n displayName: 'Cursor Agent',\n binaryName: 'cursor-agent',\n enabled: true,\n // Backend registry is authoritative: since the Cursor OAuth\n // device-flow shipped, new links are oauth_token only (the login\n // blob written to ~/.config/cursor/auth.json). Legacy vaulted\n // api_key rows may still exist server-side, but the link surface\n // no longer offers api_key.\n supportedAuthKinds: ['oauth_token'],\n preferredAuthKind: 'oauth_token',\n // `headroom wrap cursor` is \"manual/print-only\" (IDE settings; the\n // headless cursor-agent CLI has no base-URL override) — runs native.\n headroomWrappable: false,\n // Native ACP server: `cursor-agent acp`.\n acp: true,\n // Reverse-engineered device/poll flow; `userCode` is the secret PKCE\n // verifier echoed back on poll — NEVER human-facing.\n deviceFlow: true,\n showsUserCode: false,\n },\n aider: {\n id: 'aider',\n displayName: 'Aider',\n binaryName: 'aider',\n enabled: true,\n // Aider is OAuth-less — auth is via ANTHROPIC_API_KEY / OPENAI_API_KEY\n // / etc. env vars or `~/.aider.conf.yml`. The link flow surfaces\n // this via the existing --api-key escape hatch in commands/link.ts.\n supportedAuthKinds: ['api_key'],\n preferredAuthKind: 'api_key',\n headroomWrappable: false,\n // Legacy PTY runtime — no ACP adapter registered.\n acp: false,\n },\n gemini: {\n id: 'gemini',\n displayName: 'Gemini CLI',\n binaryName: 'gemini',\n enabled: true,\n // OAuth via `gemini auth login` (captured by `codeam link gemini`\n // from ~/.gemini/oauth_creds.json) AND GEMINI_API_KEY are both\n // accepted by the backend's GeminiProvisioningStrategy and propagated\n // into codespace deploys.\n supportedAuthKinds: ['oauth_token', 'api_key'],\n preferredAuthKind: 'oauth_token',\n // Not listed by `headroom wrap --help` — runs native.\n headroomWrappable: false,\n // Native ACP server: `gemini --skip-trust --acp`.\n acp: true,\n },\n kimi: {\n id: 'kimi',\n displayName: 'Kimi Code',\n binaryName: 'kimi',\n enabled: true,\n // API key (KIMI_API_KEY, + optional KIMI_BASE_URL) is the shipping auth —\n // fully documented, no reverse-engineering. OAuth `/login` (login-state at\n // ~/.kimi-code/credentials/<name>.json, base https://api.kimi.com/coding/)\n // is declared so it can land later without a wire change, but capturing\n // that blob server-side is a separate reverse-engineering spike (phase 2).\n supportedAuthKinds: ['api_key', 'oauth_token'],\n preferredAuthKind: 'api_key',\n // Moonshot's `kimi` is not listed by `headroom wrap --help` — runs native.\n headroomWrappable: false,\n // Native ACP server: `kimi acp` (stdio JSON-RPC, answers `initialize`).\n acp: true,\n },\n};\n\nexport function getEnabledAgents(): AgentMetadata[] {\n return Object.values(AGENT_REGISTRY).filter(m => m.enabled);\n}\n\nexport function getAgent(id: AgentId): AgentMetadata {\n const meta = AGENT_REGISTRY[id];\n if (!meta) throw new Error(`Unknown agent id: ${id}`);\n return meta;\n}\n\nexport function isKnownAgentId(id: string): id is AgentId {\n return id in AGENT_REGISTRY;\n}\n","/**\n * Agent identity — the ONE place the public (`LinkedAgentId`) and internal\n * (`AgentId`) id spaces are declared and bridged, plus the ONE alias\n * normalizer every surface funnels through.\n *\n * Canonical values consolidated from (Phase 2, PR-1):\n * - backend `apps/api-v2/src/linked-agents/agent-map.ts`\n * (`PUBLIC_TO_INTERNAL` / `INTERNAL_TO_PUBLIC` / `LinkedAgentId`),\n * - CLI `apps/cli/src/commands/host/agent-provisioning.ts`\n * (`PUBLIC_TO_INTERNAL_AGENT`),\n * - VS Code plugin `apps/vsc-plugin/src/utils/cli-agent-id.ts`\n * (marketplace aliases + `__terminal__:` strip),\n * - CLI `apps/cli/src/commands/start/handlers.ts`\n * (the `claude_code` → `claude` normalization),\n * - mobile `apps/mobile/src/lib/agent-id-map.ts`.\n */\n\nimport type { AgentId, HeadroomKind } from './types';\nimport { AGENT_REGISTRY, isKnownAgentId } from './registry';\n\n// ─── House agent constants ───────────────────────────────────────────────────\n// Byte-identical mirrors of the backend repo's canonical\n// `codeagent-mobile/packages/shared/src/constants/house-agent.ts` (which the\n// api-v2 additionally hand-mirrors in `common/constants/house-agent.ts`).\n// PR-3 replaces those copies with re-exports of THESE.\n\n/** Sentinel id for the synthetic \"CodeAgent Cloud (incluido)\" house agent. */\nexport const HOUSE_AGENT_ID = 'house-codeagent-cloud';\n\n/** Internal provider discriminator for the house agent. */\nexport const HOUSE_AGENT_PROVIDER = 'codeagent_cloud';\n\n/** White-label display strings — never mention the backend model. */\nexport const HOUSE_AGENT_NAME = 'CodeAgent Cloud';\nexport const HOUSE_AGENT_VENDOR = 'CodeAgent';\nexport const HOUSE_AGENT_SUBTITLE = 'Included — no setup';\n\n// ─── Public (LinkedAgent) id space ───────────────────────────────────────────\n\n/**\n * Public-facing linked-agent ids — the id space the `/api/agents/...`\n * endpoints and the mobile/web surfaces speak. The internal `AgentId`\n * (`'claude' | 'codex' | …`) is what the runtimes / provisioning key on.\n */\nexport type LinkedAgentId =\n | 'claude_code'\n | 'codex'\n | 'cursor'\n | 'aider'\n | 'coderabbit'\n | 'gemini'\n | 'kimi'\n | typeof HOUSE_AGENT_ID;\n\nexport const LINKED_AGENT_IDS: readonly LinkedAgentId[] = [\n 'claude_code',\n 'codex',\n 'cursor',\n 'aider',\n 'coderabbit',\n 'gemini',\n 'kimi',\n HOUSE_AGENT_ID,\n];\n\nexport function isLinkedAgentId(value: string): value is LinkedAgentId {\n return (LINKED_AGENT_IDS as readonly string[]).includes(value);\n}\n\n/**\n * Every public id → internal `AgentId`.\n *\n * ⚠️ RECONCILED ASYMMETRY — this map is the UNION of what the two sides\n * historically accepted:\n * - The backend's `agent-map.ts` accepts only the `LinkedAgentId` union\n * (incl. the house agent, whose runtime is Claude Code) — no bare\n * `claude`, no `copilot` (there is no public copilot LinkedAgentId).\n * - The CLI's self-hosted `agent-provisioning.ts` additionally accepts\n * bare `'claude'` and `'copilot'` (deploy payloads have carried\n * already-internal ids), but not the house agent.\n * Consumers that must REJECT ids outside their own historical set keep\n * their own guard on top (e.g. `isLinkedAgentId`).\n */\nexport const PUBLIC_TO_INTERNAL: Readonly<\n Record<LinkedAgentId | 'claude' | 'copilot', AgentId>\n> = {\n claude_code: 'claude',\n // CLI-side extra: self-hosted deploy payloads may carry the internal id.\n claude: 'claude',\n codex: 'codex',\n // CLI-side extra: copilot has no public LinkedAgentId (backend doesn't\n // expose it) but the self-hosted path accepts it.\n copilot: 'copilot',\n cursor: 'cursor',\n aider: 'aider',\n coderabbit: 'coderabbit',\n gemini: 'gemini',\n kimi: 'kimi',\n // The house agent runs Claude Code under the hood (pointed at the\n // MiniMax proxy). Its internal runtime is therefore `claude`.\n [HOUSE_AGENT_ID]: 'claude',\n};\n\n/**\n * Internal → public. Partial: `copilot` has no public LinkedAgentId, and\n * `claude` maps back to `claude_code` (never the house agent — that\n * direction is intentionally lossy).\n */\nexport const INTERNAL_TO_PUBLIC: Readonly<Partial<Record<AgentId, LinkedAgentId>>> = {\n claude: 'claude_code',\n codex: 'codex',\n cursor: 'cursor',\n aider: 'aider',\n coderabbit: 'coderabbit',\n gemini: 'gemini',\n kimi: 'kimi',\n};\n\nfunction isPublicToInternalKey(v: string): v is LinkedAgentId | 'claude' | 'copilot' {\n // Not Object.hasOwn — the VS Code plugin's tsconfig lib predates ES2022.\n return Object.prototype.hasOwnProperty.call(PUBLIC_TO_INTERNAL, v);\n}\n\n/** Resolve a public/linked id to the internal `AgentId`, or null. */\nexport function publicToInternal(publicId: string): AgentId | null {\n return isPublicToInternalKey(publicId) ? PUBLIC_TO_INTERNAL[publicId] : null;\n}\n\n/** Resolve an internal `AgentId` to its public `LinkedAgentId`, or null. */\nexport function internalToPublic(internal: AgentId): LinkedAgentId | null {\n return INTERNAL_TO_PUBLIC[internal] ?? null;\n}\n\n// ─── Alias normalization ─────────────────────────────────────────────────────\n\n/** Prefix IDE plugins use for terminal-hosted agent ids. */\nexport const TERMINAL_AGENT_PREFIX = '__terminal__:';\n\n/**\n * Known aliases → internal `AgentId`. Union of every alias set that used\n * to live scattered across the surfaces: the public `claude_code` id, the\n * VS Code / Open VSX marketplace extension ids, and JetBrains plugin ids.\n */\nconst AGENT_ID_ALIASES: Readonly<Record<string, AgentId>> = {\n claude_code: 'claude',\n 'claude-code': 'claude',\n 'anthropic.claude-code': 'claude',\n 'anthropics.claude': 'claude',\n 'anthropic.claude-ce': 'claude',\n 'anthropic.claude': 'claude',\n 'com.anthropic.claudecode': 'claude',\n 'com.anthropic.claude': 'claude',\n 'openai.chatgpt': 'codex',\n 'coderabbitai.coderabbit-vscode': 'coderabbit',\n};\n\n/**\n * THE agent-id normalizer. Collapses every known spelling of an agent id\n * (registry id, public `claude_code` form, marketplace extension id,\n * `__terminal__:`-prefixed plugin id — case/whitespace tolerant) onto the\n * internal `AgentId`, or `null` when unknown.\n *\n * Deliberately does NOT:\n * - gate on `enabled` (callers that need availability check the\n * registry — see the VS Code wrapper `normalizeCliAgentId`);\n * - map the house agent (that's a runtime substitution, not an alias —\n * use {@link publicToInternal});\n * - fall back to anything. Unknown in → `null` out.\n */\nexport function normalizeAgentId(raw: string): AgentId | null {\n const value = (raw ?? '').trim().toLowerCase();\n if (!value) return null;\n\n if (isKnownAgentId(value)) return value;\n\n const unprefixed = value.startsWith(TERMINAL_AGENT_PREFIX)\n ? value.slice(TERMINAL_AGENT_PREFIX.length)\n : value;\n if (isKnownAgentId(unprefixed)) return unprefixed;\n\n return AGENT_ID_ALIASES[unprefixed] ?? null;\n}\n\n// ─── Headroom kind derivation ────────────────────────────────────────────────\n\n/**\n * The `headroom init --global <kind>` subcommand for an agent id, derived\n * from the registry's `headroomKind` flags — or `null` for unknown or\n * non-wrappable agents (cursor / gemini / aider / anything else).\n *\n * ⚠️ NEVER falls back to `'claude'`. The historical CLI fallback is how\n * the 2026-06 Cursor incident happened: an unsupported agent slipped\n * through, defaulted to `claude`, and `headroom wrap claude` launched\n * Claude Code instead of the user's agent. Callers that genuinely need a\n * default (e.g. picking an init subcommand AFTER the wrappable gate has\n * already passed) apply it themselves — see the CLI's\n * `agentIdToHeadroomKind` wrapper.\n *\n * Matching mirrors the historical predicates on BOTH sides (CLI\n * `isHeadroomSupportedAgent`, api-v2 `isHeadroomWrappableAgent`):\n * case-insensitive, `_`/`-` tolerant, prefix match — so `claude_code`,\n * `Claude-Code`, `codex_cli`, `copilot-cli` all resolve.\n */\nexport function headroomKindFor(agentId: string): HeadroomKind | null {\n const normalized = (agentId ?? '').toLowerCase().replace(/[_-]/g, '');\n if (!normalized) return null;\n for (const meta of Object.values(AGENT_REGISTRY)) {\n if (meta.headroomKind !== undefined && normalized.startsWith(meta.id)) {\n return meta.headroomKind;\n }\n }\n return null;\n}\n\n/**\n * Registry-derived replacement for the two scattered predicates\n * (`isHeadroomSupportedAgent` in the CLI, `isHeadroomWrappableAgent` in\n * api-v2). Accepts both id spaces (`claude_code` and `claude`).\n */\nexport function isHeadroomWrappable(agentId: string): boolean {\n return headroomKindFor(agentId) !== null;\n}\n","import type { IntegrationDefinition, IntegrationId } from './types';\n\n/**\n * The single source of truth for supported integrations. Adding one =\n * 1 entry here + 1 backend OAuth provider + icon. The `delivery` spec is\n * resolved into deploy manifests and executed as data by the CLI, so a new\n * MCP integration with no special logic needs no CLI release.\n */\nexport const INTEGRATION_REGISTRY: Record<IntegrationId, IntegrationDefinition> = {\n jira: {\n id: 'jira',\n name: 'Jira',\n icon: 'jira',\n enabled: true,\n auth: {\n kind: 'oauth_redirect',\n scopes: ['read:jira-work', 'write:jira-work', 'offline_access'],\n },\n delivery: {\n mcp: {\n // mcp-atlassian in BYO-token mode (headless; credentials via env only).\n // Version PINNED to the exact release verified headless by Plan 2's\n // Docker integration test (apps/cli mcp-shim.int.test.ts).\n command: 'uvx',\n args: ['mcp-atlassian==0.22.1'],\n envMapping: {\n ATLASSIAN_OAUTH_ACCESS_TOKEN: 'accessToken',\n ATLASSIAN_OAUTH_CLOUD_ID: 'cloudId',\n },\n // Without ATLASSIAN_OAUTH_ENABLE=true, JiraConfig.from_env() raises\n // \"Missing required JIRA_URL\" (swallowed at server startup) and the\n // server silently registers ZERO Jira tools. The flag activates\n // mcp-atlassian's \"minimal OAuth config for user-provided tokens\"\n // mode — the BYO-token path the broker feeds. Static + non-secret.\n staticEnv: { ATLASSIAN_OAUTH_ENABLE: 'true' },\n },\n },\n },\n};\n\nexport function getEnabledIntegrations(): IntegrationDefinition[] {\n return Object.values(INTEGRATION_REGISTRY).filter((m) => m.enabled);\n}\n\nexport function getIntegration(id: IntegrationId): IntegrationDefinition {\n const meta = INTEGRATION_REGISTRY[id];\n if (!meta) throw new Error(`Unknown integration id: ${id}`);\n return meta;\n}\n\nexport function isKnownIntegrationId(id: string): id is IntegrationId {\n return id in INTEGRATION_REGISTRY;\n}\n","/**\n * Production API base URL for all CodeAgent Mobile clients.\n *\n * History note: prod migrated from Vercel (`https://api.codeagent-mobile.com`)\n * to Cloud Run / api-v2 (`https://api.codeagent-mobile.com`) in 2026-05. The\n * Vercel deployment is now gated by Vercel deployment protection and returns\n * 403 for unauthed traffic — DO NOT fall back to it.\n *\n * Override at runtime with `CODEAM_API_URL` (full URL override) OR set\n * `CODEAM_TEST_MODE=1` to point every client request at the dev\n * preview without having to know its host.\n */\nexport const DEFAULT_API_BASE_URL = 'https://api.codeagent-mobile.com' as const;\n\n/**\n * Dev-preview API base URL. Same Cloud Run service as prod but routed\n * to the `dev` revision (auto-deploys from the `dev` branch in the\n * backend repo). Manual smoke tests + load runs land here.\n */\nexport const DEV_API_BASE_URL = 'https://dev-api.codeagent-mobile.com' as const;\n\n/**\n * Resolve the active API base URL, honoring in priority order:\n *\n * 1. Explicit `CODEAM_API_URL` env var — full URL, takes precedence.\n * 2. `CODEAM_TEST_MODE=1` shortcut — flips to [DEV_API_BASE_URL]\n * without the user having to know the dev host.\n * 3. The `DEFAULT_API_BASE_URL` constant (prod).\n *\n * Used by every CLI service that talks to the backend so one env var\n * flips heartbeats, command relay, chunk uploads, and the pairing\n * flow in lockstep — eliminates the cross-environment misroute where\n * pairing succeeds in dev (shared Redis) but the CLI keeps\n * heartbeating to prod.\n */\nexport function resolveApiBaseUrl(): string {\n // Guard against non-Node runtimes (browser bundles import this\n // module). `process` is undefined there; treat as prod default.\n // `@codeam/shared` deliberately avoids depending on `@types/node`\n // so its types stay consumable from the mobile RN bundle too, so we\n // reach for the env via a structural cast rather than NodeJS.ProcessEnv.\n const env = (globalThis as { process?: { env?: Record<string, string | undefined> } }).process?.env;\n const explicit = env?.CODEAM_API_URL?.trim();\n if (explicit) return explicit;\n const testFlag = env?.CODEAM_TEST_MODE?.trim();\n if (testFlag === '1' || testFlag?.toLowerCase() === 'true') return DEV_API_BASE_URL;\n return DEFAULT_API_BASE_URL;\n}\n","/**\n * Headroom provisioning manifest — the SINGLE source of truth for what a\n * Headroom install consists of, rendered by every provisioning surface:\n *\n * - codespace bootstrap (bash composer in the backend repo,\n * `apps/api-v2/src/codespaces/github-ssh.service.ts` — adopts in PR-2),\n * - self-hosted deploy (TS installer, CLI `commands/host-agent.ts`\n * `setupHeadroomForSelfHosted`),\n * - on-demand local sessions (\"Session add-ons → Cost-saving\", CLI\n * `services/headroom/configure.ts`).\n *\n * Values are DATA-first (arrays/records, plus tiny pure renderers) so both\n * the TS installer and a bash composer can interpolate from them. Renderers\n * are byte-exact with the literals they replaced — guarded by\n * `packages/shared/__tests__/headroom-manifest.test.ts`.\n *\n * ⚠️ The extras matter: `[proxy,code]` pulls the ONNX compression engines\n * (Kompress + tree-sitter CodeCompressor). NEVER add `[ml]` — that's\n * multi-GB PyTorch, and a broken/cold torch wedges every prompt at\n * \"Thinking…\". The models are pre-downloaded at provision time because the\n * proxy eager-loads with `allow_download=False` and a cold cache defers the\n * ~840 MB download to the first prompt (blowing the agent's ~90 s idle\n * timeout).\n */\n\n/** Local proxy port the agent's config is routed to. */\nexport const HEADROOM_PROXY_PORT = 8787;\n\n/**\n * Env that pins the ONNX backend on the proxy process — never imports\n * torch. Spread into the proxy launch env on every surface.\n */\nexport const HEADROOM_BACKEND_ENV = {\n HEADROOM_KOMPRESS_BACKEND: 'onnx_cpu',\n} as const;\n\n/**\n * The proxy's HTTP/server companion packages, installed alongside the\n * `headroom-ai[...]` package. The COMPRESSION ENGINES come from the\n * headroom-ai extras — NOT this list.\n */\nexport const HEADROOM_PIP_COMPANIONS: readonly string[] = [\n 'fastapi',\n 'uvicorn',\n 'httpx[http2]',\n 'websockets',\n 'zstandard',\n];\n\n/** The three provisioning surfaces (see module doc). */\nexport type HeadroomSurface = 'codespace' | 'selfHosted' | 'onDemand';\n\n/**\n * pip extras per surface. `onDemand` additionally ships `image`\n * (image-compression support, added with the Session add-ons path in\n * codeam-cli@2.49.0); the older codespace/self-hosted install strings\n * remain `[proxy,code]` byte-for-byte.\n */\nexport const HEADROOM_EXTRAS_BY_SURFACE: Readonly<Record<HeadroomSurface, readonly string[]>> = {\n codespace: ['proxy', 'code'],\n selfHosted: ['proxy', 'code'],\n onDemand: ['proxy', 'code', 'image'],\n};\n\n/** `headroom-ai[<extras>]` — the pip requirement string. */\nexport function headroomPipPackage(extras: readonly string[]): string {\n return `headroom-ai[${extras.join(',')}]`;\n}\n\n/** One HuggingFace repo to pre-warm into the HF cache at provision time. */\nexport interface HeadroomModelSpec {\n repo: string;\n /** `snapshot_download(..., allow_patterns=[…])` filter. */\n allowPatterns: readonly string[];\n}\n\n/**\n * The two HF repos Kompress needs. kompress-v2-base is the ONNX model\n * (skip its .pt/.safetensors torch artifacts); ModernBERT-base is the\n * TOKENIZER ONLY (skip its model weights).\n */\nexport const HEADROOM_MODELS: readonly HeadroomModelSpec[] = [\n {\n repo: 'chopratejas/kompress-v2-base',\n allowPatterns: ['*.json', 'onnx/*.onnx', 'kompress-int8-wo.onnx'],\n },\n {\n repo: 'answerdotai/ModernBERT-base',\n allowPatterns: ['*.json', 'tokenizer*', '*.txt', 'vocab*', 'merges*'],\n },\n];\n\n/** Formatting knob so each surface can stay byte-identical to its\n * historical literal (the CLI joins patterns with `,`, the codespace\n * bash composer with `, `). */\nexport interface HeadroomPythonRenderOpts {\n /** Put a space after the commas between allow_patterns entries. */\n spaceAfterComma?: boolean;\n}\n\n/** Render one `snapshot_download(...)` python line for a model. */\nexport function headroomSnapshotDownloadLine(\n model: HeadroomModelSpec,\n opts: HeadroomPythonRenderOpts = {},\n): string {\n const sep = opts.spaceAfterComma ? ', ' : ',';\n const patterns = model.allowPatterns.map((p) => `\"${p}\"`).join(sep);\n return `snapshot_download(\"${model.repo}\", allow_patterns=[${patterns}])`;\n}\n\n/**\n * The full model pre-download python snippet (import + one\n * `snapshot_download` per model), newline-joined — what the surfaces pass\n * to `python -c` / a heredoc.\n */\nexport function headroomModelPredownloadScript(opts: HeadroomPythonRenderOpts = {}): string {\n return [\n 'from huggingface_hub import snapshot_download',\n ...HEADROOM_MODELS.map((m) => headroomSnapshotDownloadLine(m, opts)),\n ].join('\\n');\n}\n","/**\n * Canonical names of the per-user SSE bus events (`/api/users/me/stream`).\n *\n * The authoritative list is the `UserEvent` discriminated union in the\n * backend repo: codeagent-mobile/apps/api-v2/src/user-events/user-events.types.ts.\n * Every `type:` literal of that union appears here exactly once — when a new\n * variant lands on the union, add its name here (and in the backend mirror of\n * this file at codeagent-mobile/packages/shared/src/types/events.ts).\n *\n * Producers (CLI event posts, backend `userEvents.publish` calls) and\n * consumers (the `useUserEventsSSE` hooks' switch cases) should reference\n * `USER_EVENTS.*` instead of re-typing the string, so a typo becomes a\n * compile error instead of a silently dropped event.\n */\nexport const USER_EVENTS = {\n PAIRED_SESSION_STATUS: 'paired_session_status',\n PAIRED_SESSION_ADDED: 'paired_session_added',\n PAIRED_SESSION_REMOVED: 'paired_session_removed',\n PAIRED_SESSION_BRANCH_CHANGED: 'paired_session_branch_changed',\n SHARED_WITH_ME_ADDED: 'shared_with_me_added',\n SHARED_WITH_ME_REVOKED: 'shared_with_me_revoked',\n USAGE_CHANGED: 'usage_changed',\n TASK_DONE: 'task_done',\n HUNK_PENDING_REVIEW_ADDED: 'hunk_pending_review_added',\n HUNK_REVIEW_RESOLVED: 'hunk_review_resolved',\n FILE_CHANGED: 'file_changed',\n FILES_BATCH_CHANGED: 'files_batch_changed',\n AGENT_STREAMING_CHUNK: 'agent_streaming_chunk',\n AGENT_AWAITING_ANSWER: 'agent_awaiting_answer',\n AWAITING_INPUT_ADDED: 'awaiting_input_added',\n AGENT_ANSWER_RESOLVED: 'agent_answer_resolved',\n TEMPLATE_ADDED: 'template_added',\n TEMPLATE_REMOVED: 'template_removed',\n TEMPLATE_UPDATED: 'template_updated',\n AGENT_TASK_DISPATCHED: 'agent_task_dispatched',\n AGENT_TASK_COMPLETED: 'agent_task_completed',\n LINKED_AGENT_ADDED: 'linked_agent_added',\n QUOTA_REACHED: 'quota_reached',\n LINKED_AGENT_LINK_FAILED: 'linked_agent_link_failed',\n CODESPACE_AGENT_INSTALLED: 'codespace_agent_installed',\n AGENT_CREDENTIALS_REFRESHED: 'agent_credentials_refreshed',\n CREDENTIAL_INVALID: 'credential_invalid',\n CODESPACE_WAKING: 'codespace_waking',\n CODESPACE_BILLING_BLOCKED: 'codespace_billing_blocked',\n COST_SAVING_UPDATED: 'cost_saving_updated',\n COMMAND_COMPLETED: 'command_completed',\n AI_SUMMARY_PENDING: 'ai_summary_pending',\n AI_SUMMARY_READY: 'ai_summary_ready',\n AI_INSIGHT_PENDING: 'ai_insight_pending',\n AI_INSIGHT_READY: 'ai_insight_ready',\n PUSH_TOKEN_INVALIDATED: 'push_token_invalidated',\n PREVIEW_DETECTION_PENDING: 'preview_detection_pending',\n PREVIEW_DETECTION_READY: 'preview_detection_ready',\n PREVIEW_STARTING: 'preview_starting',\n PREVIEW_READY: 'preview_ready',\n PREVIEW_STOPPED: 'preview_stopped',\n PREVIEW_ERROR: 'preview_error',\n PREVIEW_PROGRESS: 'preview_progress',\n BEADS_STATE_CHANGED: 'beads_state_changed',\n BEADS_PROVISIONING: 'beads_provisioning',\n BEADS_TEAM_MEMORY_CHANGED: 'beads_team_memory_changed',\n AUDIT_EVENT_ADDED: 'audit_event_added',\n SELF_HOSTED_HOST_ADDED: 'self_hosted_host_added',\n SELF_HOSTED_HOST_STATUS: 'self_hosted_host_status',\n SELF_HOSTED_HOST_REMOVED: 'self_hosted_host_removed',\n SELF_HOSTED_HOST_TELEMETRY: 'self_hosted_host_telemetry',\n SELF_HOSTED_HOST_METRICS: 'self_hosted_host_metrics',\n SELF_HOSTED_HOST_SESSIONS: 'self_hosted_host_sessions',\n SELF_HOSTED_DEPLOY_PROGRESS: 'self_hosted_deploy_progress',\n REFERRAL_REWARD_EARNED: 'referral_reward_earned',\n HEADROOM_PROGRESS: 'headroom_progress',\n HEADROOM_STATUS: 'headroom_status',\n BEADS_STATUS: 'beads_status',\n LINKED_AGENT_HEADROOM_BUDGET_UPDATED: 'linked_agent_headroom_budget_updated',\n CLI_UPDATE_AVAILABLE: 'cli_update_available',\n AGENT_INSTALL_PROGRESS: 'agent_install_progress',\n AGENT_INSTALL_FAILED: 'agent_install_failed',\n CLI_UPDATE_PROGRESS: 'cli_update_progress',\n CLI_UPDATE_FAILED: 'cli_update_failed',\n BATON_STATE: 'baton_state',\n INTEGRATION_LINKED: 'integration_linked',\n INTEGRATION_UNLINKED: 'integration_unlinked',\n INTEGRATION_CREDENTIAL_INVALID: 'integration_credential_invalid',\n // CodeRabbit reviewer — the CLI posts these to /api/coderabbit/events; the\n // backend re-publishes them on the per-user SSE bus (mirrored in repo A).\n CODERABBIT_PROGRESS: 'coderabbit_progress',\n CODERABBIT_STATUS: 'coderabbit_status',\n CODERABBIT_REVIEW: 'coderabbit_review',\n} as const;\n\nexport type UserEventName = (typeof USER_EVENTS)[keyof typeof USER_EVENTS];\n","/**\n * Prompt the CLI sends to the user's linked agent (Claude, Codex, …)\n * in a headless one-shot to detect how to start the project's dev\n * server. Same pattern as the AI Insights \"summary\" prompt — the\n * agent runs locally with the user's auth, has read access to the\n * project, and returns a tiny JSON blob the CLI parses.\n *\n * Kept here (in `@codeam/shared`) so the CLI build inlines the\n * exact string at compile time without runtime fetch from the backend.\n */\nexport const PREVIEW_DETECT_PROMPT = `\nAnalyze the project in the current working directory and return how to start\nits development server for in-app preview.\n\nRead package.json, Procfile, Dockerfile, docker-compose.yml, manage.py, app.json,\nmix.exs, Cargo.toml, go.mod, requirements.txt, Gemfile, and any other framework\nmarkers you find at depth <= 2.\n\nReturn ONLY a JSON object on stdout (no prose, no markdown fences):\n\n{\n \"framework\": \"<name, or 'unsupported'>\",\n \"command\": \"<executable>\",\n \"args\": [\"...\"],\n \"port\": <number>,\n \"ready_pattern\": \"<regex matching the server-ready stdout line>\",\n \"env\": { \"HOST\": \"0.0.0.0\" },\n \"setup_commands\": [{ \"cmd\": \"<executable>\", \"args\": [\"...\"] }],\n \"notes\": \"<one-line caveat or null>\"\n}\n\nRules:\n- Pick the script the developer would run locally to see the app (typically \"dev\", \"start\", \"serve\").\n- Prefer binding to 0.0.0.0 — most frameworks default to localhost which the tunnel cannot reach.\n- For Expo: framework=\"Expo\", command=\"npx\", args=[\"expo\",\"start\",\"--tunnel\"], port=8081, notes=\"Scan QR with Expo Go\".\n- If no dev server applies (CLI library, lambda, batch script): {\"framework\":\"unsupported\",\"notes\":\"<reason>\"}.\n\nCRITICAL — setup_commands:\n- DO NOT include an install command (npm install, pnpm install, yarn install,\n yarn, bun install) in setup_commands. A lockfile-aware pre-flight installer\n runs BEFORE setup_commands and picks the correct package manager from the\n lockfile present (pnpm-lock.yaml -> pnpm, yarn.lock -> yarn, bun.lockb -> bun,\n else npm). Emitting an install here either duplicates that work or, worse,\n uses the WRONG package manager on top of node_modules just populated by the\n pre-flight, which crashes (e.g. npm errors with \"Cannot read properties of\n null (reading 'matches')\" when run over pnpm's .pnpm/ layout).\n- ONLY include setup_commands for genuinely non-install work the project needs\n before its dev server can boot: prisma generate, codegen, prebuild scripts,\n database migrations against a local SQLite, etc.\n- Each setup_commands entry MUST be an object {\"cmd\": \"...\", \"args\": [\"...\"]} —\n e.g. {\"cmd\": \"npx\", \"args\": [\"prisma\", \"generate\"]}. NOT a bare string.\n- For most projects, setup_commands should be an empty array [].\n\nOUTPUT JSON ONLY. NO MARKDOWN. NO COMMENTARY.\n`.trim();\n"],"mappings":"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","names":[]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@codeam/shared",
|
|
3
|
-
"version": "2.60.
|
|
3
|
+
"version": "2.60.47",
|
|
4
4
|
"description": "CodeAgent Mobile wire-protocol contract: chunk-protocol renderer, RemoteCommand envelope, SSE event names, model pricing tables, and cross-repo wire types shared by codeam-cli, the VS Code extension, and the backend.",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"module": "./dist/index.mjs",
|