codex-channel-bgos 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (151) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +114 -0
  3. package/dist/adapter.d.ts +96 -0
  4. package/dist/adapter.d.ts.map +1 -0
  5. package/dist/adapter.js +677 -0
  6. package/dist/adapter.js.map +1 -0
  7. package/dist/agent-hints.d.ts +20 -0
  8. package/dist/agent-hints.d.ts.map +1 -0
  9. package/dist/agent-hints.js +92 -0
  10. package/dist/agent-hints.js.map +1 -0
  11. package/dist/agent-identity.d.ts +36 -0
  12. package/dist/agent-identity.d.ts.map +1 -0
  13. package/dist/agent-identity.js +42 -0
  14. package/dist/agent-identity.js.map +1 -0
  15. package/dist/attachment-bridge.d.ts +64 -0
  16. package/dist/attachment-bridge.d.ts.map +1 -0
  17. package/dist/attachment-bridge.js +216 -0
  18. package/dist/attachment-bridge.js.map +1 -0
  19. package/dist/auth-mode.d.ts +34 -0
  20. package/dist/auth-mode.d.ts.map +1 -0
  21. package/dist/auth-mode.js +48 -0
  22. package/dist/auth-mode.js.map +1 -0
  23. package/dist/bgos-api.d.ts +191 -0
  24. package/dist/bgos-api.d.ts.map +1 -0
  25. package/dist/bgos-api.js +225 -0
  26. package/dist/bgos-api.js.map +1 -0
  27. package/dist/bgos-ws.d.ts +94 -0
  28. package/dist/bgos-ws.d.ts.map +1 -0
  29. package/dist/bgos-ws.js +310 -0
  30. package/dist/bgos-ws.js.map +1 -0
  31. package/dist/capabilities.d.ts +28 -0
  32. package/dist/capabilities.d.ts.map +1 -0
  33. package/dist/capabilities.js +44 -0
  34. package/dist/capabilities.js.map +1 -0
  35. package/dist/catalog-sync.d.ts +26 -0
  36. package/dist/catalog-sync.d.ts.map +1 -0
  37. package/dist/catalog-sync.js +24 -0
  38. package/dist/catalog-sync.js.map +1 -0
  39. package/dist/cli.d.ts +3 -0
  40. package/dist/cli.d.ts.map +1 -0
  41. package/dist/cli.js +152 -0
  42. package/dist/cli.js.map +1 -0
  43. package/dist/codex-host.d.ts +44 -0
  44. package/dist/codex-host.d.ts.map +1 -0
  45. package/dist/codex-host.js +142 -0
  46. package/dist/codex-host.js.map +1 -0
  47. package/dist/commands-sync.d.ts +24 -0
  48. package/dist/commands-sync.d.ts.map +1 -0
  49. package/dist/commands-sync.js +43 -0
  50. package/dist/commands-sync.js.map +1 -0
  51. package/dist/config.d.ts +4 -0
  52. package/dist/config.d.ts.map +1 -0
  53. package/dist/config.js +36 -0
  54. package/dist/config.js.map +1 -0
  55. package/dist/default-commands.d.ts +27 -0
  56. package/dist/default-commands.d.ts.map +1 -0
  57. package/dist/default-commands.js +64 -0
  58. package/dist/default-commands.js.map +1 -0
  59. package/dist/event-mapper.d.ts +43 -0
  60. package/dist/event-mapper.d.ts.map +1 -0
  61. package/dist/event-mapper.js +127 -0
  62. package/dist/event-mapper.js.map +1 -0
  63. package/dist/heartbeat.d.ts +75 -0
  64. package/dist/heartbeat.d.ts.map +1 -0
  65. package/dist/heartbeat.js +186 -0
  66. package/dist/heartbeat.js.map +1 -0
  67. package/dist/inbound-handler.d.ts +167 -0
  68. package/dist/inbound-handler.d.ts.map +1 -0
  69. package/dist/inbound-handler.js +282 -0
  70. package/dist/inbound-handler.js.map +1 -0
  71. package/dist/inbound-input.d.ts +17 -0
  72. package/dist/inbound-input.d.ts.map +1 -0
  73. package/dist/inbound-input.js +25 -0
  74. package/dist/inbound-input.js.map +1 -0
  75. package/dist/index.d.ts +25 -0
  76. package/dist/index.d.ts.map +1 -0
  77. package/dist/index.js +18 -0
  78. package/dist/index.js.map +1 -0
  79. package/dist/install-service.d.ts +8 -0
  80. package/dist/install-service.d.ts.map +1 -0
  81. package/dist/install-service.js +66 -0
  82. package/dist/install-service.js.map +1 -0
  83. package/dist/last-id-store.d.ts +33 -0
  84. package/dist/last-id-store.d.ts.map +1 -0
  85. package/dist/last-id-store.js +101 -0
  86. package/dist/last-id-store.js.map +1 -0
  87. package/dist/load-config.d.ts +30 -0
  88. package/dist/load-config.d.ts.map +1 -0
  89. package/dist/load-config.js +86 -0
  90. package/dist/load-config.js.map +1 -0
  91. package/dist/media-classify.d.ts +37 -0
  92. package/dist/media-classify.d.ts.map +1 -0
  93. package/dist/media-classify.js +108 -0
  94. package/dist/media-classify.js.map +1 -0
  95. package/dist/media-guard.d.ts +13 -0
  96. package/dist/media-guard.d.ts.map +1 -0
  97. package/dist/media-guard.js +159 -0
  98. package/dist/media-guard.js.map +1 -0
  99. package/dist/outbound-retry.d.ts +24 -0
  100. package/dist/outbound-retry.d.ts.map +1 -0
  101. package/dist/outbound-retry.js +75 -0
  102. package/dist/outbound-retry.js.map +1 -0
  103. package/dist/outbound.d.ts +223 -0
  104. package/dist/outbound.d.ts.map +1 -0
  105. package/dist/outbound.js +366 -0
  106. package/dist/outbound.js.map +1 -0
  107. package/dist/outbox.d.ts +16 -0
  108. package/dist/outbox.d.ts.map +1 -0
  109. package/dist/outbox.js +88 -0
  110. package/dist/outbox.js.map +1 -0
  111. package/dist/pair-cli.d.ts +44 -0
  112. package/dist/pair-cli.d.ts.map +1 -0
  113. package/dist/pair-cli.js +182 -0
  114. package/dist/pair-cli.js.map +1 -0
  115. package/dist/pending-unknown-store.d.ts +26 -0
  116. package/dist/pending-unknown-store.d.ts.map +1 -0
  117. package/dist/pending-unknown-store.js +135 -0
  118. package/dist/pending-unknown-store.js.map +1 -0
  119. package/dist/processed-ids.d.ts +36 -0
  120. package/dist/processed-ids.d.ts.map +1 -0
  121. package/dist/processed-ids.js +55 -0
  122. package/dist/processed-ids.js.map +1 -0
  123. package/dist/reply-markers.d.ts +42 -0
  124. package/dist/reply-markers.d.ts.map +1 -0
  125. package/dist/reply-markers.js +124 -0
  126. package/dist/reply-markers.js.map +1 -0
  127. package/dist/setup/supervisor.d.ts +16 -0
  128. package/dist/setup/supervisor.d.ts.map +1 -0
  129. package/dist/setup/supervisor.js +61 -0
  130. package/dist/setup/supervisor.js.map +1 -0
  131. package/dist/thread-map.d.ts +12 -0
  132. package/dist/thread-map.d.ts.map +1 -0
  133. package/dist/thread-map.js +72 -0
  134. package/dist/thread-map.js.map +1 -0
  135. package/dist/tool-progress.d.ts +103 -0
  136. package/dist/tool-progress.d.ts.map +1 -0
  137. package/dist/tool-progress.js +216 -0
  138. package/dist/tool-progress.js.map +1 -0
  139. package/dist/types.d.ts +244 -0
  140. package/dist/types.d.ts.map +1 -0
  141. package/dist/types.js +16 -0
  142. package/dist/types.js.map +1 -0
  143. package/dist/version.d.ts +2 -0
  144. package/dist/version.d.ts.map +1 -0
  145. package/dist/version.js +28 -0
  146. package/dist/version.js.map +1 -0
  147. package/dist/voice-rpc.d.ts +37 -0
  148. package/dist/voice-rpc.d.ts.map +1 -0
  149. package/dist/voice-rpc.js +44 -0
  150. package/dist/voice-rpc.js.map +1 -0
  151. package/package.json +47 -0
@@ -0,0 +1,48 @@
1
+ /**
2
+ * Decision D7: prefer an existing `codex login` (ChatGPT plan, zero marginal
3
+ * cost), fall back to OPENAI_API_KEY (metered), refuse to start with neither.
4
+ *
5
+ * Pure resolver: the daemon feeds it the observable facts (does ~/.codex/auth.json
6
+ * exist, is OPENAI_API_KEY set, was a mode forced) and gets back the active mode,
7
+ * a human label to print at startup, and, for apikey mode, the key to hand the
8
+ * Codex SDK (which injects it as CODEX_API_KEY). See codex-host for how chatgpt
9
+ * mode strips the key from the child env so the CLI uses the login instead.
10
+ */
11
+ const NEITHER_ERROR = "No Codex credentials found. Sign in with `codex login`, or set OPENAI_API_KEY " +
12
+ "(for example in ~/.env), then run the command again.";
13
+ const NO_KEY_ERROR = "CODEX_BGOS_AUTH_MODE=apikey was requested but OPENAI_API_KEY is not set. " +
14
+ "Set OPENAI_API_KEY (for example in ~/.env), then run the command again.";
15
+ const NO_LOGIN_ERROR = "CODEX_BGOS_AUTH_MODE=chatgpt was requested but no `codex login` was found " +
16
+ "(~/.codex/auth.json is missing). Run `codex login` first, then run the command again.";
17
+ function cleanKey(raw) {
18
+ if (typeof raw !== "string")
19
+ return null;
20
+ const trimmed = raw.trim();
21
+ return trimmed.length > 0 ? trimmed : null;
22
+ }
23
+ export function resolveAuthMode(input) {
24
+ const forced = input.forced ?? "auto";
25
+ const key = cleanKey(input.openaiKey);
26
+ const hasLogin = input.authJsonExists === true;
27
+ if (forced === "chatgpt") {
28
+ if (hasLogin) {
29
+ return { ok: true, mode: "chatgpt", label: "codex login (ChatGPT plan)" };
30
+ }
31
+ return { ok: false, error: NO_LOGIN_ERROR };
32
+ }
33
+ if (forced === "apikey") {
34
+ if (key) {
35
+ return { ok: true, mode: "apikey", apiKey: key, label: "OPENAI_API_KEY" };
36
+ }
37
+ return { ok: false, error: NO_KEY_ERROR };
38
+ }
39
+ // auto: prefer the login, then the key, then refuse.
40
+ if (hasLogin) {
41
+ return { ok: true, mode: "chatgpt", label: "codex login (ChatGPT plan)" };
42
+ }
43
+ if (key) {
44
+ return { ok: true, mode: "apikey", apiKey: key, label: "OPENAI_API_KEY" };
45
+ }
46
+ return { ok: false, error: NEITHER_ERROR };
47
+ }
48
+ //# sourceMappingURL=auth-mode.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth-mode.js","sourceRoot":"","sources":["../src/auth-mode.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AA6BH,MAAM,aAAa,GACjB,gFAAgF;IAChF,sDAAsD,CAAC;AAEzD,MAAM,YAAY,GAChB,2EAA2E;IAC3E,yEAAyE,CAAC;AAE5E,MAAM,cAAc,GAClB,4EAA4E;IAC5E,uFAAuF,CAAC;AAE1F,SAAS,QAAQ,CAAC,GAA8B;IAC9C,IAAI,OAAO,GAAG,KAAK,QAAQ;QAAE,OAAO,IAAI,CAAC;IACzC,MAAM,OAAO,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC;IAC3B,OAAO,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC;AAC7C,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,KAAgB;IAC9C,MAAM,MAAM,GAAc,KAAK,CAAC,MAAM,IAAI,MAAM,CAAC;IACjD,MAAM,GAAG,GAAG,QAAQ,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;IACtC,MAAM,QAAQ,GAAG,KAAK,CAAC,cAAc,KAAK,IAAI,CAAC;IAE/C,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;QACzB,IAAI,QAAQ,EAAE,CAAC;YACb,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,4BAA4B,EAAE,CAAC;QAC5E,CAAC;QACD,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,cAAc,EAAE,CAAC;IAC9C,CAAC;IAED,IAAI,MAAM,KAAK,QAAQ,EAAE,CAAC;QACxB,IAAI,GAAG,EAAE,CAAC;YACR,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,EAAE,KAAK,EAAE,gBAAgB,EAAE,CAAC;QAC5E,CAAC;QACD,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,YAAY,EAAE,CAAC;IAC5C,CAAC;IAED,qDAAqD;IACrD,IAAI,QAAQ,EAAE,CAAC;QACb,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,4BAA4B,EAAE,CAAC;IAC5E,CAAC;IACD,IAAI,GAAG,EAAE,CAAC;QACR,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,EAAE,KAAK,EAAE,gBAAgB,EAAE,CAAC;IAC5E,CAAC;IACD,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,aAAa,EAAE,CAAC;AAC7C,CAAC"}
@@ -0,0 +1,191 @@
1
+ import { type AgentCatalogEntry, type BgosMessageEnvelope, type CommandManifestEntry, type InboundMessagePayload, type IntegrationPairing, type OutboundMessagePayload, type PairExchangeResponse, type PluginConfig } from "./types.js";
2
+ import type { VoiceRpcResultBody } from "./voice-rpc.js";
3
+ import type { HeartbeatDto } from "./heartbeat.js";
4
+ /**
5
+ * Thin typed wrapper around the BGOS integration endpoints. All methods
6
+ * attach the X-BGOS-Pairing header from cfg.pairingToken.
7
+ *
8
+ * A 401 from any request is mapped to PairingRevokedError so callers
9
+ * (WS client, outbound adapter) can short-circuit and let the setup
10
+ * wizard prompt for re-pair.
11
+ */
12
+ export declare class BgosApi {
13
+ private readonly http;
14
+ constructor(cfg: PluginConfig);
15
+ /** GET /integrations/me - confirms token + touches last_seen_at.
16
+ * Includes assistant→agent_route bindings so the plugin can seed
17
+ * its dispatch map on cold start.
18
+ */
19
+ whoami(): Promise<{
20
+ pairing_id: number;
21
+ user_id: string;
22
+ device_label: string;
23
+ integration: string;
24
+ assistants?: Array<{
25
+ assistant_id: number;
26
+ agent_route: string | null;
27
+ name: string;
28
+ /** Count of slash-commands currently set; lets callers decide
29
+ * whether to seed defaults without a second round-trip. */
30
+ command_count?: number;
31
+ }>;
32
+ }>;
33
+ /**
34
+ * Fetch the served capability canon for this channel (capability bootstrap).
35
+ * The backend owns the machine-readable canon and serves a per-channel
36
+ * payload; the daemon injects the returned `text` into the Codex agent's
37
+ * AGENTS.md at connect, falling back to the bundled copy when this is
38
+ * unreachable. GET is pairing-token authed like every other method here.
39
+ *
40
+ * `text` is header + shared core + the codex channel delta, ready to inject.
41
+ * Any non-2xx (including a 404 from an older backend that predates the
42
+ * endpoint) throws, and the caller keeps the bundled fallback.
43
+ */
44
+ getCapabilities(channel?: string): Promise<{
45
+ channel: string;
46
+ version: string;
47
+ text: string;
48
+ core: string;
49
+ channelSyntax: string;
50
+ }>;
51
+ /** Pair exchange (Public; does NOT need X-BGOS-Pairing). */
52
+ static pairExchange(baseUrl: string, params: {
53
+ code: string;
54
+ deviceLabel: string;
55
+ agentCatalog?: AgentCatalogEntry[];
56
+ /**
57
+ * Channel label persisted on the pairing row. MUST be `'codex'` for
58
+ * Codex pairings - without it, the backend falls back to `'openclaw'`
59
+ * and the pairing surfaces under the OpenClaw card with assistants
60
+ * created as code='openclaw' (wrong UI gates, wrong slash picker).
61
+ */
62
+ integration?: string;
63
+ /** Daemon version stamped on the pairing row (contract C1). */
64
+ daemonVersion?: string;
65
+ }): Promise<PairExchangeResponse>;
66
+ /** Plugin pushes (or updates) the agent catalog for this pairing. */
67
+ pushAgentCatalog(pairingId: number, agents: AgentCatalogEntry[]): Promise<void>;
68
+ /** Plugin replaces the slash-command manifest for a single bound assistant. */
69
+ putCommands(assistantId: number, commands: CommandManifestEntry[]): Promise<void>;
70
+ /** REST backfill after a WS reconnect. */
71
+ inboundSince(sinceMessageId: number): Promise<{
72
+ messages: InboundMessagePayload[];
73
+ }>;
74
+ /** Fetch the recent message history for a chat - used by the daemon to
75
+ * rebuild conversation context before dispatching to a stateless
76
+ * gateway. Backend returns up to 100 entries ASC by created_at. */
77
+ getMessages(chatId: number, userId: string): Promise<BgosMessageEnvelope[]>;
78
+ /**
79
+ * Self-resolve (or create) this assistant's primary BGOS delivery chat -
80
+ * the target for proactive / check-in sends when no `CODEX_BGOS_CHAT_ID`
81
+ * env override is set (parity root cause D). Pairing-token auth only (the
82
+ * pairing must own the assistant; the backend enforces this).
83
+ *
84
+ * `POST /integrations/assistants/:assistantId/primary-chat` (no body). The
85
+ * backend resolves the assistant's `primaryChatId`, else the newest
86
+ * `kind='main'` chat, else creates a fresh main chat (pinning only on a
87
+ * fresh create). Response is `{ chat_id: number }`.
88
+ *
89
+ * Throws on any non-2xx or a malformed response - the caller (proactive
90
+ * `loadTargets`) treats a throw as "skip this assistant".
91
+ */
92
+ getOrCreatePrimaryChat(assistantId: number): Promise<number>;
93
+ /** Agent reply - assistant message with optional inline buttons/approval. */
94
+ postMessage(payload: OutboundMessagePayload): Promise<{
95
+ id: number;
96
+ }>;
97
+ /**
98
+ * Agent reply via `POST /api/v1/send-message` - the SAME wire payload as
99
+ * `postMessage`, but the endpoint the backend runs its peer-reply bridge
100
+ * (`bridgePeerReplyIfApplicable`) on. For an a2a side-thread chat that
101
+ * bridge stamps `peer_conversation_id` on the reply, which is what
102
+ * resolves the initiating peer's `wait_for_reply`. `/messages` has no
103
+ * such bridge, so peer replies sent there never resolve the wait - hence
104
+ * a dedicated method (see inbound-handler.ts; reference impl
105
+ * bgos-claude-plugin/server.ts uses `bgosPost('send-message', …)`).
106
+ *
107
+ * Response shape differs from `/messages`: the controller returns the
108
+ * created message nested under `message` (HTTP 200) rather than a bare
109
+ * `{ id }` (HTTP 201), so unwrap both shapes.
110
+ */
111
+ sendMessage(payload: OutboundMessagePayload): Promise<{
112
+ id: number;
113
+ }>;
114
+ /**
115
+ * PATCH an existing message. Used by the tool_progress card flow to
116
+ * update a card in place - adding new tools as they fire, transitioning
117
+ * state running → done at end-of-turn.
118
+ *
119
+ * The backend (BGOS PR #200, deployed 2026-05-16) auto-fills userId from
120
+ * the authenticated principal when omitted from the body. We always omit
121
+ * it from this client - pairing auth on the request itself carries the
122
+ * identity. Returns the updated message dto.
123
+ */
124
+ patchMessage(messageId: number, payload: {
125
+ text?: string;
126
+ toolProgress?: {
127
+ state: "running" | "done";
128
+ tools: Array<{
129
+ icon: string;
130
+ name: string;
131
+ args?: string;
132
+ status: "running" | "done" | "error";
133
+ }>;
134
+ };
135
+ }): Promise<{
136
+ id: number;
137
+ }>;
138
+ /** Request a presigned PUT for a file ≥500 KB that the agent wants to send.
139
+ *
140
+ * Route is `POST /api/v1/files/upload-url` (FileController) - NOT under
141
+ * `/integrations/`; the old `integrations/files/upload-url` path 404'd,
142
+ * silently breaking every ≥500 KB media send. The request DTO is camelCase
143
+ * `{ fileName, contentType, size }` and the response is `{ uploadUrl, key }`
144
+ * - both diverged from the snake_case shape this client used. We send the
145
+ * right keys and normalize the response to the `{ upload_url, s3_key }`
146
+ * shape `publishMediaPath` consumes. */
147
+ createUploadUrl(params: {
148
+ filename: string;
149
+ mimeType: string;
150
+ size: number;
151
+ }): Promise<{
152
+ upload_url: string;
153
+ s3_key: string;
154
+ }>;
155
+ /** List this pairing's active/paired state. Mostly used in setup wizard. */
156
+ listPairings(): Promise<IntegrationPairing[]>;
157
+ /**
158
+ * POST a liveness heartbeat (contract C1). Pairing-token auth only. The
159
+ * backend touches last_seen_at + records daemon_version / last_error_*.
160
+ * Additive: older backends 404 this route; callers must treat any failure
161
+ * as non-fatal (the HeartbeatController swallows it).
162
+ */
163
+ postHeartbeat(body: HeartbeatDto): Promise<void>;
164
+ /**
165
+ * Set (or clear) an assistant's status line (contract C4). PATCHes the
166
+ * pairing-scoped `/integrations/assistants/:assistantId/status`. Pass an
167
+ * empty string to clear. Fail-open at the call site (fork throttles + never
168
+ * lets a status write suppress a reply).
169
+ */
170
+ setStatus(assistantId: number, body: {
171
+ statusText: string | null;
172
+ statusEmoji?: string | null;
173
+ }): Promise<void>;
174
+ /**
175
+ * Swap the pairing token (and optionally base URL) in place after a token
176
+ * rotation, so existing references (outbound, tool-progress) keep working
177
+ * without a rebuild. Used by the adapter's re-pair recovery path.
178
+ */
179
+ updateToken(token: string, baseUrl?: string): void;
180
+ /** ACK a voice_rpc frame - cancels the backend's 1.5 s retry-emit.
181
+ * Best-effort; callers must treat a failure as non-fatal. */
182
+ postVoiceRpcAck(rpcId: string): Promise<unknown>;
183
+ /** Settle a voice_rpc op (mint / consult / dispatch-accept). The backend
184
+ * drops results that arrive after its own per-op deadline, so callers
185
+ * keep their inner caps strictly under it (see voice-rpc.ts). */
186
+ postVoiceRpcResult(rpcId: string, body: VoiceRpcResultBody): Promise<unknown>;
187
+ /** Report the outcome of a detached voice dispatch - flips the durable
188
+ * voice_tasks row and fans `voice_task_update` to the user's devices. */
189
+ postVoiceTaskResult(taskId: string, body: VoiceRpcResultBody): Promise<unknown>;
190
+ }
191
+ //# sourceMappingURL=bgos-api.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bgos-api.d.ts","sourceRoot":"","sources":["../src/bgos-api.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,225 @@
1
+ import axios from "axios";
2
+ import { PairingRevokedError, } from "./types.js";
3
+ /**
4
+ * Thin typed wrapper around the BGOS integration endpoints. All methods
5
+ * attach the X-BGOS-Pairing header from cfg.pairingToken.
6
+ *
7
+ * A 401 from any request is mapped to PairingRevokedError so callers
8
+ * (WS client, outbound adapter) can short-circuit and let the setup
9
+ * wizard prompt for re-pair.
10
+ */
11
+ export class BgosApi {
12
+ http;
13
+ constructor(cfg) {
14
+ this.http = axios.create({
15
+ baseURL: cfg.baseUrl + "/api/v1",
16
+ headers: {
17
+ "X-BGOS-Pairing": cfg.pairingToken,
18
+ "Content-Type": "application/json",
19
+ },
20
+ timeout: 30_000,
21
+ });
22
+ this.http.interceptors.response.use((r) => r, (err) => {
23
+ if (err?.response?.status === 401) {
24
+ return Promise.reject(new PairingRevokedError(err.response?.data?.message ?? "pairing rejected by BGOS"));
25
+ }
26
+ return Promise.reject(err);
27
+ });
28
+ }
29
+ /** GET /integrations/me - confirms token + touches last_seen_at.
30
+ * Includes assistant→agent_route bindings so the plugin can seed
31
+ * its dispatch map on cold start.
32
+ */
33
+ async whoami() {
34
+ const r = await this.http.get("integrations/me");
35
+ return r.data;
36
+ }
37
+ /**
38
+ * Fetch the served capability canon for this channel (capability bootstrap).
39
+ * The backend owns the machine-readable canon and serves a per-channel
40
+ * payload; the daemon injects the returned `text` into the Codex agent's
41
+ * AGENTS.md at connect, falling back to the bundled copy when this is
42
+ * unreachable. GET is pairing-token authed like every other method here.
43
+ *
44
+ * `text` is header + shared core + the codex channel delta, ready to inject.
45
+ * Any non-2xx (including a 404 from an older backend that predates the
46
+ * endpoint) throws, and the caller keeps the bundled fallback.
47
+ */
48
+ async getCapabilities(channel = "codex") {
49
+ const r = await this.http.get("integrations/capabilities", {
50
+ params: { channel },
51
+ });
52
+ return r.data;
53
+ }
54
+ /** Pair exchange (Public; does NOT need X-BGOS-Pairing). */
55
+ static async pairExchange(baseUrl, params) {
56
+ const base = baseUrl.replace(/\/+$/, "") + "/api/v1";
57
+ const r = await axios.post(`${base}/integrations/pair-exchange`, params, {
58
+ timeout: 15_000,
59
+ });
60
+ return r.data;
61
+ }
62
+ /** Plugin pushes (or updates) the agent catalog for this pairing. */
63
+ async pushAgentCatalog(pairingId, agents) {
64
+ await this.http.post(`integrations/pairings/${pairingId}/agent-catalog`, {
65
+ agents,
66
+ });
67
+ }
68
+ /** Plugin replaces the slash-command manifest for a single bound assistant. */
69
+ async putCommands(assistantId, commands) {
70
+ await this.http.put(`integrations/assistants/${assistantId}/commands`, { commands });
71
+ }
72
+ /** REST backfill after a WS reconnect. */
73
+ async inboundSince(sinceMessageId) {
74
+ const r = await this.http.get("integrations/inbound", {
75
+ params: { since_message_id: sinceMessageId },
76
+ });
77
+ return r.data;
78
+ }
79
+ /** Fetch the recent message history for a chat - used by the daemon to
80
+ * rebuild conversation context before dispatching to a stateless
81
+ * gateway. Backend returns up to 100 entries ASC by created_at. */
82
+ async getMessages(chatId, userId) {
83
+ const r = await this.http.get(`chats/${chatId}/messages`, {
84
+ params: { userId },
85
+ });
86
+ const rows = r.data?.messages;
87
+ return Array.isArray(rows) ? rows : [];
88
+ }
89
+ /**
90
+ * Self-resolve (or create) this assistant's primary BGOS delivery chat -
91
+ * the target for proactive / check-in sends when no `CODEX_BGOS_CHAT_ID`
92
+ * env override is set (parity root cause D). Pairing-token auth only (the
93
+ * pairing must own the assistant; the backend enforces this).
94
+ *
95
+ * `POST /integrations/assistants/:assistantId/primary-chat` (no body). The
96
+ * backend resolves the assistant's `primaryChatId`, else the newest
97
+ * `kind='main'` chat, else creates a fresh main chat (pinning only on a
98
+ * fresh create). Response is `{ chat_id: number }`.
99
+ *
100
+ * Throws on any non-2xx or a malformed response - the caller (proactive
101
+ * `loadTargets`) treats a throw as "skip this assistant".
102
+ */
103
+ async getOrCreatePrimaryChat(assistantId) {
104
+ const r = await this.http.post(`integrations/assistants/${assistantId}/primary-chat`, {});
105
+ const chatId = r.data?.chat_id;
106
+ if (typeof chatId !== "number" || !Number.isFinite(chatId) || chatId <= 0) {
107
+ throw new Error(`primary-chat endpoint returned no chat_id for assistant ${assistantId}`);
108
+ }
109
+ return chatId;
110
+ }
111
+ /** Agent reply - assistant message with optional inline buttons/approval. */
112
+ async postMessage(payload) {
113
+ const r = await this.http.post("messages", payload);
114
+ return r.data;
115
+ }
116
+ /**
117
+ * Agent reply via `POST /api/v1/send-message` - the SAME wire payload as
118
+ * `postMessage`, but the endpoint the backend runs its peer-reply bridge
119
+ * (`bridgePeerReplyIfApplicable`) on. For an a2a side-thread chat that
120
+ * bridge stamps `peer_conversation_id` on the reply, which is what
121
+ * resolves the initiating peer's `wait_for_reply`. `/messages` has no
122
+ * such bridge, so peer replies sent there never resolve the wait - hence
123
+ * a dedicated method (see inbound-handler.ts; reference impl
124
+ * bgos-claude-plugin/server.ts uses `bgosPost('send-message', …)`).
125
+ *
126
+ * Response shape differs from `/messages`: the controller returns the
127
+ * created message nested under `message` (HTTP 200) rather than a bare
128
+ * `{ id }` (HTTP 201), so unwrap both shapes.
129
+ */
130
+ async sendMessage(payload) {
131
+ const r = await this.http.post("send-message", payload);
132
+ const data = (r.data ?? {});
133
+ return { id: data.message?.id ?? data.id ?? 0 };
134
+ }
135
+ /**
136
+ * PATCH an existing message. Used by the tool_progress card flow to
137
+ * update a card in place - adding new tools as they fire, transitioning
138
+ * state running → done at end-of-turn.
139
+ *
140
+ * The backend (BGOS PR #200, deployed 2026-05-16) auto-fills userId from
141
+ * the authenticated principal when omitted from the body. We always omit
142
+ * it from this client - pairing auth on the request itself carries the
143
+ * identity. Returns the updated message dto.
144
+ */
145
+ async patchMessage(messageId, payload) {
146
+ const r = await this.http.patch(`messages/${messageId}`, payload);
147
+ return r.data;
148
+ }
149
+ /** Request a presigned PUT for a file ≥500 KB that the agent wants to send.
150
+ *
151
+ * Route is `POST /api/v1/files/upload-url` (FileController) - NOT under
152
+ * `/integrations/`; the old `integrations/files/upload-url` path 404'd,
153
+ * silently breaking every ≥500 KB media send. The request DTO is camelCase
154
+ * `{ fileName, contentType, size }` and the response is `{ uploadUrl, key }`
155
+ * - both diverged from the snake_case shape this client used. We send the
156
+ * right keys and normalize the response to the `{ upload_url, s3_key }`
157
+ * shape `publishMediaPath` consumes. */
158
+ async createUploadUrl(params) {
159
+ const r = await this.http.post("files/upload-url", {
160
+ fileName: params.filename,
161
+ contentType: params.mimeType,
162
+ size: params.size,
163
+ });
164
+ return { upload_url: r.data.uploadUrl, s3_key: r.data.key };
165
+ }
166
+ /** List this pairing's active/paired state. Mostly used in setup wizard. */
167
+ async listPairings() {
168
+ const r = await this.http.get("integrations/pairings");
169
+ return r.data;
170
+ }
171
+ /**
172
+ * POST a liveness heartbeat (contract C1). Pairing-token auth only. The
173
+ * backend touches last_seen_at + records daemon_version / last_error_*.
174
+ * Additive: older backends 404 this route; callers must treat any failure
175
+ * as non-fatal (the HeartbeatController swallows it).
176
+ */
177
+ async postHeartbeat(body) {
178
+ await this.http.post("integrations/heartbeat", body);
179
+ }
180
+ /**
181
+ * Set (or clear) an assistant's status line (contract C4). PATCHes the
182
+ * pairing-scoped `/integrations/assistants/:assistantId/status`. Pass an
183
+ * empty string to clear. Fail-open at the call site (fork throttles + never
184
+ * lets a status write suppress a reply).
185
+ */
186
+ async setStatus(assistantId, body) {
187
+ await this.http.patch(`integrations/assistants/${assistantId}/status`, body);
188
+ }
189
+ /**
190
+ * Swap the pairing token (and optionally base URL) in place after a token
191
+ * rotation, so existing references (outbound, tool-progress) keep working
192
+ * without a rebuild. Used by the adapter's re-pair recovery path.
193
+ */
194
+ updateToken(token, baseUrl) {
195
+ const headers = this.http.defaults.headers;
196
+ headers.common["X-BGOS-Pairing"] = token;
197
+ headers["X-BGOS-Pairing"] = token;
198
+ if (baseUrl) {
199
+ this.http.defaults.baseURL = baseUrl.replace(/\/+$/, "") + "/api/v1";
200
+ }
201
+ }
202
+ // -------------------------------------------------------------------
203
+ // Native voice control plane (voice_rpc - see voice-rpc.ts)
204
+ // -------------------------------------------------------------------
205
+ /** ACK a voice_rpc frame - cancels the backend's 1.5 s retry-emit.
206
+ * Best-effort; callers must treat a failure as non-fatal. */
207
+ async postVoiceRpcAck(rpcId) {
208
+ const r = await this.http.post(`integrations/voice-rpc/${encodeURIComponent(rpcId)}/ack`, {});
209
+ return r.data;
210
+ }
211
+ /** Settle a voice_rpc op (mint / consult / dispatch-accept). The backend
212
+ * drops results that arrive after its own per-op deadline, so callers
213
+ * keep their inner caps strictly under it (see voice-rpc.ts). */
214
+ async postVoiceRpcResult(rpcId, body) {
215
+ const r = await this.http.post(`integrations/voice-rpc/${encodeURIComponent(rpcId)}/result`, body);
216
+ return r.data;
217
+ }
218
+ /** Report the outcome of a detached voice dispatch - flips the durable
219
+ * voice_tasks row and fans `voice_task_update` to the user's devices. */
220
+ async postVoiceTaskResult(taskId, body) {
221
+ const r = await this.http.post(`integrations/voice-tasks/${encodeURIComponent(taskId)}/result`, body);
222
+ return r.data;
223
+ }
224
+ }
225
+ //# sourceMappingURL=bgos-api.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bgos-api.js","sourceRoot":"","sources":["../src/bgos-api.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,94 @@
1
+ import type { BgosApi } from "./bgos-api.js";
2
+ import { type VoiceRpcFrame } from "./voice-rpc.js";
3
+ import { type AssistantBoundPayload, type AssistantUnboundPayload, type CallbackResultPayload, type CommandsUpdatedPayload, type InboundClickPayload, type InboundMessagePayload, type PairReadyPayload, type PairingRevokedPayload, type PluginConfig } from "./types.js";
4
+ type EventMap = {
5
+ inbound_message: [InboundMessagePayload];
6
+ inbound_click: [InboundClickPayload];
7
+ commands_updated: [CommandsUpdatedPayload];
8
+ pair_ready: [PairReadyPayload];
9
+ assistant_bound: [AssistantBoundPayload];
10
+ assistant_unbound: [AssistantUnboundPayload];
11
+ pairing_revoked: [PairingRevokedPayload];
12
+ callback_result: [CallbackResultPayload];
13
+ voice_rpc: [VoiceRpcFrame];
14
+ error: [Error];
15
+ /** Socket (re)connected / disconnected, drives heartbeat wsConnected. */
16
+ connect: [];
17
+ disconnect: [];
18
+ /** Manager-level reconnect: adapter refreshes identity + backfills. */
19
+ reconnect: [];
20
+ /** Backfill outcome signals, drive heartbeat lastError (contract C3). */
21
+ backfill_ok: [];
22
+ backfill_error: [Error];
23
+ backfill_storm: [number];
24
+ };
25
+ /**
26
+ * Socket.IO client against BGOS. Handshake passes pairingToken as a query
27
+ * param; backend validates via bcrypt and joins the client to
28
+ * pairing:<id> + every assistant:<id> the pairing owns.
29
+ *
30
+ * Cursor authority is the DISK cursor (bgos_last_id): triggerBackfill reads
31
+ * loadLastId() at call time and the live WS path advances no cursor of its
32
+ * own. Dedupe + saveLastId happen in the inbound handler after the route
33
+ * resolves. Reconnect is handled at the Manager level (socket.io.on) because
34
+ * the Socket does not emit a `reconnect` reserved event in socket.io-client v4.
35
+ */
36
+ export declare class BgosWs {
37
+ private cfg;
38
+ private readonly api;
39
+ private readonly emitter;
40
+ private socket;
41
+ private reconnectAttempts;
42
+ private manualClose;
43
+ private wsConnectedSince;
44
+ private backfillInFlight;
45
+ private readonly typingThrottle;
46
+ constructor(cfg: PluginConfig, api: BgosApi);
47
+ on<K extends keyof EventMap>(event: K, listener: (...args: EventMap[K]) => void): this;
48
+ off<K extends keyof EventMap>(event: K, listener: (...args: EventMap[K]) => void): this;
49
+ /** ISO timestamp of the current connection, or null when disconnected. */
50
+ get connectedSince(): string | null;
51
+ /** Swap the pairing token (and optionally base URL) for re-pair recovery.
52
+ * Caller reconnects (disconnect + connect) to apply it. */
53
+ updateToken(token: string, baseUrl?: string): void;
54
+ connect(): Promise<void>;
55
+ /**
56
+ * Backfill missed messages from the DISK cursor. Single-flight: concurrent
57
+ * calls (poll tick racing a reconnect) coalesce onto the same promise.
58
+ *
59
+ * `opts.initial` marks the boot backfill: when the disk cursor is 0 and the
60
+ * pairing already has history, page through it WITHOUT dispatching and seed
61
+ * the cursor to the newest id (cold-start guard), so a fresh install does
62
+ * not replay the entire history as new messages.
63
+ */
64
+ triggerBackfill(opts?: {
65
+ initial?: boolean;
66
+ }): Promise<void>;
67
+ private runBackfill;
68
+ /**
69
+ * Cold-start seed: page the entire history WITHOUT dispatching, advancing
70
+ * the disk cursor to the newest id. Bounded iterations to guarantee
71
+ * termination even if the backend paginates oddly.
72
+ */
73
+ private coldStartSeed;
74
+ /**
75
+ * Emit a client-side `typing` WS event (contract C4). Best-effort +
76
+ * throttled to 1 per 3s per chat. Safe on old backends: an unknown WS
77
+ * event is ignored server-side.
78
+ */
79
+ emitTyping(params: {
80
+ chatId: number;
81
+ assistantId: number;
82
+ }): void;
83
+ disconnect(): void;
84
+ /**
85
+ * Translate the wire-level payload (snake_case) into our camelCase type.
86
+ * Backend already emits camelCase via the helper service, but defensively
87
+ * handle both so we don't drop messages if someone changes the emitter.
88
+ */
89
+ private normalizeInbound;
90
+ /** Normalize an inbound_click WS payload (camelCase or snake_case). */
91
+ private normalizeInboundClick;
92
+ }
93
+ export {};
94
+ //# sourceMappingURL=bgos-ws.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bgos-ws.d.ts","sourceRoot":"","sources":["../src/bgos-ws.ts"],"names":[],"mappings":"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"}