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,282 @@
1
+ /**
2
+ * Translate a BGOS WS `inbound_message` into a `dispatch()` call against
3
+ * Codex's existing per-agent handler.
4
+ *
5
+ * The fork wires this up: at boot the fork calls `adapter.setDispatch(fn)`
6
+ * with a closure that runs Codex's `processMessageForAgent` (or
7
+ * equivalent) and uses the supplied `replyHandle` for any outbound
8
+ * action. `dispatch` is dependency-injected because the fork has access
9
+ * to Codex's internal types we deliberately do not import here - keeping
10
+ * this vendor package free of any dependency on the upstream Codex
11
+ * source so it stays npm-installable on its own.
12
+ *
13
+ * What this module owns:
14
+ * - Looking up `agent_route` from `assistant_id` via the adapter's map
15
+ * - Translating BGOS attachments into local file paths via
16
+ * `attachment-bridge`
17
+ * - Building a `ReplyHandle` scoped to BGOS (calls back through the
18
+ * `BgosOutbound` instance, never Telegram)
19
+ * - Persisting `last_id` BEFORE dispatch so a crash inside the agent
20
+ * handler doesn't infinite-loop the cursor
21
+ * - Injecting `BGOS_AGENT_HINTS` into the system prompt before
22
+ * dispatching
23
+ */
24
+ import { randomUUID } from "node:crypto";
25
+ import { ingestBgosAttachment, publishMediaPath, } from "./attachment-bridge.js";
26
+ import { buildSystemPromptWithHints } from "./agent-hints.js";
27
+ import { saveLastId } from "./last-id-store.js";
28
+ import { clearPendingUnknown, recordPendingUnknown, } from "./pending-unknown-store.js";
29
+ import { ProcessedIdsCache } from "./processed-ids.js";
30
+ /**
31
+ * Build a BGOS-scoped ReplyHandle. Extracted so both the inbound dispatch
32
+ * path AND the adapter's `makeReplyHandle` factory (contract C6, for the
33
+ * fork's HITL button-click resume) produce an identical surface.
34
+ *
35
+ * `replyVia` / `replyToId` are set by the inbound path for a2a peer replies;
36
+ * `makeReplyHandle` leaves them undefined (a plain reply into a chat).
37
+ */
38
+ export function buildReplyHandle(deps, target) {
39
+ const { assistantId, chatId, replyVia, replyToId } = target;
40
+ return {
41
+ origin: "bgos",
42
+ sendText: (text) => deps.outbound.sendText({ assistantId, chatId, text, replyVia, replyToId }),
43
+ sendButtons: (text, options) => deps.outbound.sendButtons({
44
+ assistantId,
45
+ chatId,
46
+ text,
47
+ options,
48
+ replyVia,
49
+ replyToId,
50
+ }),
51
+ sendApprovalRequest: (text, meta) => deps.outbound.sendApprovalRequest({
52
+ assistantId,
53
+ chatId,
54
+ text,
55
+ // SECURITY: ignore any agent-supplied request_id and mint a
56
+ // fork-generated UUID. The request_id keys the approval-callback
57
+ // correlation map (ea:<decision>:<reqId>); an agent that picks its
58
+ // own value could collide with another in-flight approval and steal
59
+ // or clobber its decision. A v4 UUID is collision-free.
60
+ meta: { ...meta, request_id: randomUUID() },
61
+ replyVia,
62
+ replyToId,
63
+ }),
64
+ sendAskUserInput: (prompt, options, modal) => deps.outbound.sendAskUserInput({ assistantId, chatId, prompt, options, modal }),
65
+ sendFile: (filePath, caption) => deps.outbound.sendFile({
66
+ assistantId,
67
+ chatId,
68
+ filePath,
69
+ caption,
70
+ replyVia,
71
+ replyToId,
72
+ }),
73
+ sendImage: (filePath, caption) => deps.outbound.sendImage({
74
+ assistantId,
75
+ chatId,
76
+ filePath,
77
+ caption,
78
+ replyVia,
79
+ replyToId,
80
+ }),
81
+ sendVideo: (filePath, caption) => deps.outbound.sendVideo({
82
+ assistantId,
83
+ chatId,
84
+ filePath,
85
+ caption,
86
+ replyVia,
87
+ replyToId,
88
+ }),
89
+ sendTyping: () => deps.outbound.sendTyping({ assistantId, chatId }),
90
+ uploadFile: (filePath, opts) => publishMediaPath(deps.outbound.api, filePath, opts),
91
+ sendToolStart: async (toolName, args) => {
92
+ if (!deps.toolProgress)
93
+ return;
94
+ await deps.toolProgress.sendToolStart({ assistantId, chatId, toolName, args });
95
+ },
96
+ finalizeTurn: async () => {
97
+ if (!deps.toolProgress)
98
+ return;
99
+ await deps.toolProgress.finalizeTurn(chatId);
100
+ },
101
+ };
102
+ }
103
+ /**
104
+ * Build the inbound-event handler. Returns an async function the
105
+ * adapter wires onto `BgosWs`'s `inbound_message` event.
106
+ */
107
+ export function createInboundHandler(deps) {
108
+ // Chats known to be a2a (peer) side-threads. A chat is learned the first
109
+ // time an inbound arrives carrying `peerConversationId` (the WS event
110
+ // stamps it). We remember it so a later message in the same thread that
111
+ // arrives WITHOUT markers - e.g. a REST `integrations/inbound` poll
112
+ // backfill, which strips them - still gets its reply routed correctly.
113
+ const a2aChats = new Set();
114
+ // Dedupe cache shared by the live WS path AND the backfill/poll path (both
115
+ // flow through this handler). Gated AFTER the route resolves so an unknown-
116
+ // assistant message stays UNCONSUMED and the poll re-fetches it until
117
+ // identity heals (contract C3). 500-entry FIFO, ported from openclaw.
118
+ const processedIds = new ProcessedIdsCache(500);
119
+ // Rate-limit the unknown-assistant warning to 1/min per assistant id.
120
+ const unknownWarnedAt = new Map();
121
+ return async function handleInbound(event) {
122
+ let route = deps.getRouteForAssistant(event.assistantId);
123
+ if (!route) {
124
+ // Unknown assistant: the user likely just exposed a new agent. Ask the
125
+ // adapter to refresh identity (rate-limited + single-flight), then retry
126
+ // the lookup ONCE.
127
+ if (deps.onUnknownAssistant) {
128
+ try {
129
+ await deps.onUnknownAssistant(event.assistantId);
130
+ }
131
+ catch {
132
+ /* swallow: the retry below decides the outcome */
133
+ }
134
+ route = deps.getRouteForAssistant(event.assistantId);
135
+ }
136
+ if (!route) {
137
+ // Leave the message UNCONSUMED: do NOT mark dedupe, do NOT saveLastId.
138
+ // Record it as pending-unknown so a sibling KNOWN message's saveLastId
139
+ // cannot advance the disk cursor past this hole (durable clamp). The 5s
140
+ // poll re-fetches it until refreshIdentity fills the map. Warn at most
141
+ // 1/min per assistant so we don't spam the logs.
142
+ recordPendingUnknown(event.messageId);
143
+ const now = Date.now();
144
+ const last = unknownWarnedAt.get(event.assistantId) ?? 0;
145
+ if (now - last >= 60_000) {
146
+ unknownWarnedAt.set(event.assistantId, now);
147
+ // eslint-disable-next-line no-console
148
+ console.warn("[codex-channel-bgos] inbound for unknown assistant_id=" +
149
+ event.assistantId +
150
+ " (leaving unconsumed; poll will retry after identity heals)");
151
+ }
152
+ return;
153
+ }
154
+ }
155
+ // Route resolved. Dedupe SYNCHRONOUSLY before the first await: a message
156
+ // that already dispatched (via the other delivery path) is skipped here,
157
+ // and only a first-seen message advances the disk cursor.
158
+ if (!processedIds.markIfFirstTime(event.messageId))
159
+ return;
160
+ // This id is now consumed: clear any pending-unknown record for it BEFORE
161
+ // saving the cursor so the clamp releases and the cursor can advance to it.
162
+ // (A message that heals after being stranded flows through here once its
163
+ // route resolves.) No-op when the id was never pending.
164
+ clearPendingUnknown(event.messageId);
165
+ // Persist the cursor BEFORE dispatch. A crash inside the agent handler
166
+ // should not cause an infinite replay on restart (matches Hermes).
167
+ saveLastId(event.messageId);
168
+ deps.onInbound?.();
169
+ // Translate BGOS attachments to local file paths. Failures are
170
+ // surfaced as a single agent_error and the message is still
171
+ // dispatched without attachments - better degraded behavior than
172
+ // dropping the user's text entirely.
173
+ const attachments = [];
174
+ for (const f of event.files ?? []) {
175
+ try {
176
+ const ingested = await ingestBgosAttachment(f);
177
+ attachments.push({
178
+ localPath: ingested.localPath,
179
+ fileName: (f.filename || "attachment"),
180
+ mimeType: ingested.mimeType,
181
+ kind: ingested.kind,
182
+ });
183
+ }
184
+ catch (err) {
185
+ // eslint-disable-next-line no-console
186
+ console.warn("[codex-channel-bgos] attachment ingest failed for " +
187
+ (f.filename || "<unnamed>") +
188
+ ": " +
189
+ (err instanceof Error ? err.message : String(err)));
190
+ }
191
+ }
192
+ // a2a peer detection. If this inbound carries a peerConversationId it
193
+ // is a peer agent's side-thread message; remember the chat so later
194
+ // (marker-less) messages in it are still treated as a2a. For any reply
195
+ // into a known a2a chat we (a) route via `/send-message` so the backend
196
+ // peer-reply bridge fires and the initiator's `wait_for_reply`
197
+ // resolves, and (b) anchor the reply to the inbound's messageId via
198
+ // `reply_to_id` for precise correlation (same-chat, so no 400). Normal
199
+ // user replies are untouched: `replyVia`/`replyToId` stay undefined and
200
+ // the outbound falls through to `/messages` exactly as before.
201
+ if (event.peerConversationId !== undefined)
202
+ a2aChats.add(event.chatId);
203
+ const isPeerReply = a2aChats.has(event.chatId);
204
+ const replyVia = isPeerReply
205
+ ? "send-message"
206
+ : undefined;
207
+ const replyToId = isPeerReply
208
+ ? event.messageId
209
+ : undefined;
210
+ // Build the BGOS-scoped ReplyHandle via the shared factory (identical to
211
+ // the surface the adapter's makeReplyHandle exposes for HITL resume).
212
+ const replyHandle = buildReplyHandle({ outbound: deps.outbound, toolProgress: deps.toolProgress }, {
213
+ assistantId: event.assistantId,
214
+ chatId: event.chatId,
215
+ replyVia,
216
+ replyToId,
217
+ });
218
+ const dispatch = deps.getDispatch();
219
+ if (!dispatch) {
220
+ // Fork hasn't installed the dispatch function yet - log and keep
221
+ // going. The cursor was saved above so this message won't replay
222
+ // on restart; users should ensure dispatch is set before pairing.
223
+ // eslint-disable-next-line no-console
224
+ console.warn("[codex-channel-bgos] no dispatch fn registered - message_id=" +
225
+ event.messageId +
226
+ " dropped. Ensure the fork called adapter.setDispatch().");
227
+ return;
228
+ }
229
+ const baseSystemPrompt = deps.getSystemPrompt?.(route) ?? "";
230
+ const systemPrompt = buildSystemPromptWithHints(baseSystemPrompt);
231
+ const command = event.messageType === "slash_command"
232
+ ? {
233
+ name: (event.commandName ?? "").toLowerCase(),
234
+ args: event.commandArgs ?? "",
235
+ }
236
+ : undefined;
237
+ try {
238
+ await dispatch({
239
+ origin: "bgos",
240
+ agentRoute: route,
241
+ assistantId: event.assistantId,
242
+ chatId: event.chatId,
243
+ messageId: event.messageId,
244
+ userId: event.userId,
245
+ text: event.text,
246
+ attachments,
247
+ systemPrompt,
248
+ replyHandle,
249
+ command,
250
+ messageType: event.messageType,
251
+ ...(event.peerConversationId !== undefined
252
+ ? { peerConversationId: event.peerConversationId }
253
+ : {}),
254
+ ...(event.turnState !== undefined
255
+ ? { turnState: event.turnState }
256
+ : {}),
257
+ });
258
+ }
259
+ catch (err) {
260
+ // Fork's dispatch should never throw - but if it does, surface
261
+ // the failure as an `agent_error` so the user sees something
262
+ // rather than a silent dead chat.
263
+ const reason = err instanceof Error ? err.message : String(err);
264
+ // eslint-disable-next-line no-console
265
+ console.error("[codex-channel-bgos] dispatch threw for assistant_id=" +
266
+ event.assistantId +
267
+ ": " +
268
+ reason);
269
+ try {
270
+ await deps.outbound.sendAgentError({
271
+ assistantId: event.assistantId,
272
+ chatId: event.chatId,
273
+ reason,
274
+ });
275
+ }
276
+ catch {
277
+ /* swallow - best-effort */
278
+ }
279
+ }
280
+ };
281
+ }
282
+ //# sourceMappingURL=inbound-handler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"inbound-handler.js","sourceRoot":"","sources":["../src/inbound-handler.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Turn a BGOS inbound message (text + downloaded attachments) into a Codex SDK
3
+ * `Input`. Images map to the SDK's native `local_image` input; other files have
4
+ * no native input type, so we inject a labeled path line into the text (the
5
+ * daemon adds each file's directory to the thread's additionalDirectories so
6
+ * Codex can read it from disk).
7
+ */
8
+ import type { Input } from "@openai/codex-sdk";
9
+ export interface InboundFileForCodex {
10
+ /** Absolute local path the file was downloaded to. */
11
+ path: string;
12
+ mime: string;
13
+ name: string;
14
+ isImage: boolean;
15
+ }
16
+ export declare function buildCodexInput(text: string, files: InboundFileForCodex[]): Input;
17
+ //# sourceMappingURL=inbound-input.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"inbound-input.d.ts","sourceRoot":"","sources":["../src/inbound-input.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,KAAK,EAAE,KAAK,EAAa,MAAM,mBAAmB,CAAC;AAE1D,MAAM,WAAW,mBAAmB;IAClC,sDAAsD;IACtD,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,OAAO,CAAC;CAClB;AAOD,wBAAgB,eAAe,CAC7B,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,mBAAmB,EAAE,GAC3B,KAAK,CAsBP"}
@@ -0,0 +1,25 @@
1
+ function describeFile(f) {
2
+ const name = f.name ? `, name="${f.name}"` : "";
3
+ return `[File attached: ${f.path} (${f.mime})${name}]`;
4
+ }
5
+ export function buildCodexInput(text, files) {
6
+ const images = files.filter((f) => f.isImage);
7
+ const others = files.filter((f) => !f.isImage);
8
+ let composed = text ?? "";
9
+ if (others.length > 0) {
10
+ const lines = others.map(describeFile).join("\n");
11
+ composed = composed.trim().length > 0 ? `${composed}\n\n${lines}` : lines;
12
+ }
13
+ if (images.length === 0) {
14
+ return composed;
15
+ }
16
+ const parts = [];
17
+ if (composed.trim().length > 0) {
18
+ parts.push({ type: "text", text: composed });
19
+ }
20
+ for (const image of images) {
21
+ parts.push({ type: "local_image", path: image.path });
22
+ }
23
+ return parts;
24
+ }
25
+ //# sourceMappingURL=inbound-input.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"inbound-input.js","sourceRoot":"","sources":["../src/inbound-input.ts"],"names":[],"mappings":"AAiBA,SAAS,YAAY,CAAC,CAAsB;IAC1C,MAAM,IAAI,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;IAChD,OAAO,mBAAmB,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,IAAI,IAAI,IAAI,GAAG,CAAC;AACzD,CAAC;AAED,MAAM,UAAU,eAAe,CAC7B,IAAY,EACZ,KAA4B;IAE5B,MAAM,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC;IAC9C,MAAM,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC;IAE/C,IAAI,QAAQ,GAAG,IAAI,IAAI,EAAE,CAAC;IAC1B,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACtB,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAClD,QAAQ,GAAG,QAAQ,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,QAAQ,OAAO,KAAK,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC;IAC5E,CAAC;IAED,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACxB,OAAO,QAAQ,CAAC;IAClB,CAAC;IAED,MAAM,KAAK,GAAgB,EAAE,CAAC;IAC9B,IAAI,QAAQ,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC/B,KAAK,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,CAAC;IAC/C,CAAC;IACD,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,KAAK,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,aAAa,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC;IACxD,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC"}
@@ -0,0 +1,25 @@
1
+ /**
2
+ * codex-channel-bgos: make OpenAI Codex agents first-class BGOS agents.
3
+ *
4
+ * The daemon is normally run via the CLI (`codex-channel-bgos connect <code>`).
5
+ * These exports let the pieces be embedded or tested programmatically.
6
+ */
7
+ export { CodexAdapter } from "./adapter.js";
8
+ export type { CodexAdapterOptions, FatalInfo } from "./adapter.js";
9
+ export { CodexHost } from "./codex-host.js";
10
+ export type { CodexHostOptions, RunTurnCallbacks, RunTurnResult, } from "./codex-host.js";
11
+ export { resolveAuthMode } from "./auth-mode.js";
12
+ export type { AuthForce, AuthResolution } from "./auth-mode.js";
13
+ export { parseReply } from "./reply-markers.js";
14
+ export type { ParsedReply } from "./reply-markers.js";
15
+ export { buildCodexInput } from "./inbound-input.js";
16
+ export type { InboundFileForCodex } from "./inbound-input.js";
17
+ export { RunAccumulator, toolCardFromItem } from "./event-mapper.js";
18
+ export type { ToolCard } from "./event-mapper.js";
19
+ export { BGOS_AGENT_HINTS } from "./agent-hints.js";
20
+ export { BUNDLED_CAPABILITIES, hasCanonMarkers, pickCapabilitiesText, } from "./capabilities.js";
21
+ export type { ServedCapabilities, PickedCapabilities, } from "./capabilities.js";
22
+ export { pairBgos } from "./pair-cli.js";
23
+ export { loadConfig } from "./load-config.js";
24
+ export { getPackageVersion } from "./version.js";
25
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAC5C,YAAY,EAAE,mBAAmB,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AACnE,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,YAAY,EACV,gBAAgB,EAChB,gBAAgB,EAChB,aAAa,GACd,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACjD,YAAY,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAChE,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAChD,YAAY,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AACrD,YAAY,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAC9D,OAAO,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AACrE,YAAY,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAClD,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EACL,oBAAoB,EACpB,eAAe,EACf,oBAAoB,GACrB,MAAM,mBAAmB,CAAC;AAC3B,YAAY,EACV,kBAAkB,EAClB,kBAAkB,GACnB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,18 @@
1
+ /**
2
+ * codex-channel-bgos: make OpenAI Codex agents first-class BGOS agents.
3
+ *
4
+ * The daemon is normally run via the CLI (`codex-channel-bgos connect <code>`).
5
+ * These exports let the pieces be embedded or tested programmatically.
6
+ */
7
+ export { CodexAdapter } from "./adapter.js";
8
+ export { CodexHost } from "./codex-host.js";
9
+ export { resolveAuthMode } from "./auth-mode.js";
10
+ export { parseReply } from "./reply-markers.js";
11
+ export { buildCodexInput } from "./inbound-input.js";
12
+ export { RunAccumulator, toolCardFromItem } from "./event-mapper.js";
13
+ export { BGOS_AGENT_HINTS } from "./agent-hints.js";
14
+ export { BUNDLED_CAPABILITIES, hasCanonMarkers, pickCapabilitiesText, } from "./capabilities.js";
15
+ export { pairBgos } from "./pair-cli.js";
16
+ export { loadConfig } from "./load-config.js";
17
+ export { getPackageVersion } from "./version.js";
18
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAE5C,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAM5C,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAEjD,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAEhD,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAErD,OAAO,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAErE,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EACL,oBAAoB,EACpB,eAAe,EACf,oBAAoB,GACrB,MAAM,mBAAmB,CAAC;AAK3B,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC"}
@@ -0,0 +1,8 @@
1
+ /** Absolute path to the installed CLI entry (dist/cli.js). */
2
+ export declare function cliEntryPath(): string;
3
+ export interface InstallResult {
4
+ ok: boolean;
5
+ message: string;
6
+ }
7
+ export declare function installService(): InstallResult;
8
+ //# sourceMappingURL=install-service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"install-service.d.ts","sourceRoot":"","sources":["../src/install-service.ts"],"names":[],"mappings":"AAwBA,8DAA8D;AAC9D,wBAAgB,YAAY,IAAI,MAAM,CAGrC;AAED,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,OAAO,CAAC;IACZ,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,wBAAgB,cAAc,IAAI,aAAa,CAkD9C"}
@@ -0,0 +1,66 @@
1
+ /**
2
+ * Install the always-on service (launchd on macOS, systemd user unit on Linux)
3
+ * that runs `codex-channel-bgos start`. Run this AFTER a successful `connect`
4
+ * (so the pairing token is on disk) and from a persistent install (a global
5
+ * `npm i -g codex-channel-bgos`), not an ephemeral `npx` cache dir.
6
+ */
7
+ import { mkdirSync, writeFileSync } from "node:fs";
8
+ import { homedir } from "node:os";
9
+ import { dirname, join } from "node:path";
10
+ import { fileURLToPath } from "node:url";
11
+ import { spawnSync } from "node:child_process";
12
+ import { pickSupervisor, renderLaunchdPlist, renderSystemdUnit, LAUNCHD_LABEL, SYSTEMD_UNIT, } from "./setup/supervisor.js";
13
+ function codexBgosHome() {
14
+ return process.env.CODEX_BGOS_HOME ?? join(homedir(), ".codex-bgos");
15
+ }
16
+ /** Absolute path to the installed CLI entry (dist/cli.js). */
17
+ export function cliEntryPath() {
18
+ const here = fileURLToPath(import.meta.url);
19
+ return join(dirname(here), "cli.js");
20
+ }
21
+ export function installService() {
22
+ const kind = pickSupervisor(process.platform);
23
+ const home = codexBgosHome();
24
+ const nodePath = process.execPath;
25
+ const cliEntry = cliEntryPath();
26
+ try {
27
+ mkdirSync(join(home, "logs"), { recursive: true });
28
+ }
29
+ catch {
30
+ /* logs dir is best-effort */
31
+ }
32
+ if (kind === "launchd") {
33
+ const dir = join(homedir(), "Library", "LaunchAgents");
34
+ mkdirSync(dir, { recursive: true });
35
+ const path = join(dir, `${LAUNCHD_LABEL}.plist`);
36
+ writeFileSync(path, renderLaunchdPlist({ nodePath, cliEntry, home }));
37
+ spawnSync("launchctl", ["unload", path], { stdio: "ignore" });
38
+ const r = spawnSync("launchctl", ["load", path], { encoding: "utf8" });
39
+ return {
40
+ ok: r.status === 0,
41
+ message: `launchd agent installed at ${path} (label ${LAUNCHD_LABEL}).\n` +
42
+ `Manage it with: launchctl unload/load ${path}`,
43
+ };
44
+ }
45
+ if (kind === "systemd") {
46
+ const dir = join(homedir(), ".config", "systemd", "user");
47
+ mkdirSync(dir, { recursive: true });
48
+ const path = join(dir, SYSTEMD_UNIT);
49
+ writeFileSync(path, renderSystemdUnit({ nodePath, cliEntry, home }));
50
+ spawnSync("systemctl", ["--user", "daemon-reload"], { stdio: "ignore" });
51
+ const r = spawnSync("systemctl", ["--user", "enable", "--now", SYSTEMD_UNIT], {
52
+ encoding: "utf8",
53
+ });
54
+ return {
55
+ ok: r.status === 0,
56
+ message: `systemd user unit installed at ${path} (${SYSTEMD_UNIT}).\n` +
57
+ `To keep it running after logout: loginctl enable-linger "$USER"`,
58
+ };
59
+ }
60
+ return {
61
+ ok: false,
62
+ message: `Automatic service install is not supported on ${process.platform}. ` +
63
+ `Run 'codex-channel-bgos start' under your own supervisor (pm2, nohup, or Task Scheduler on Windows).`,
64
+ };
65
+ }
66
+ //# sourceMappingURL=install-service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"install-service.js","sourceRoot":"","sources":["../src/install-service.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Read the persisted cursor.
3
+ *
4
+ * Returns 0 when:
5
+ * - The file does not exist (fresh install).
6
+ * - The file is unreadable (permissions, IO error).
7
+ * - The file's contents do not parse as a positive integer (corruption,
8
+ * truncation, manual edit).
9
+ *
10
+ * Never throws - the adapter calls this on hot paths and crashing here
11
+ * would block boot.
12
+ */
13
+ export declare function loadLastId(): number;
14
+ /**
15
+ * Atomically persist the cursor.
16
+ *
17
+ * Skips:
18
+ * - Non-positive ids (0 means "no progress"; negative is malformed).
19
+ * - Ids less than or equal to the currently persisted value (cursor must
20
+ * advance monotonically). This guards against a backfill replay
21
+ * accidentally rewinding the cursor.
22
+ *
23
+ * Clamp: the cursor never advances past the LOWEST still-pending unknown
24
+ * assistant id (see pending-unknown-store). Without this a sibling KNOWN
25
+ * message with a higher id would push the cursor past an unconsumed unknown
26
+ * message, stranding it forever (silent loss). The clamp holds the cursor just
27
+ * below the hole so the inbound window stays re-fetchable until the route heals
28
+ * and the pending id is consumed + cleared.
29
+ *
30
+ * Errors are caught + ignored - see module docstring.
31
+ */
32
+ export declare function saveLastId(id: number): void;
33
+ //# sourceMappingURL=last-id-store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"last-id-store.d.ts","sourceRoot":"","sources":["../src/last-id-store.ts"],"names":[],"mappings":"AAiCA;;;;;;;;;;;GAWG;AACH,wBAAgB,UAAU,IAAI,MAAM,CAUnC;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,UAAU,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAsB3C"}
@@ -0,0 +1,101 @@
1
+ /**
2
+ * Persistent cursor for the BGOS WebSocket inbound stream.
3
+ *
4
+ * CRITICAL - DO NOT REGRESS. Without persistence the adapter will replay
5
+ * every historical message on every restart (the REST backfill cursor
6
+ * starts at the loaded value), producing duplicate agent replies forever.
7
+ *
8
+ * See `memory/hermes_integration_shipped.md` "Critical gotcha: last-id
9
+ * persistence" for the full background - this is the same fix as Hermes
10
+ * commit-to-disk pattern, ported to TypeScript.
11
+ *
12
+ * File location: `$CODEX_BGOS_HOME/bgos_last_id` (default `~/.codex-bgos/bgos_last_id`).
13
+ *
14
+ * Format: a single integer in plain text, no newline. Atomic writes via
15
+ * write-to-tempfile + rename so a crash mid-write can't leave a half-
16
+ * written file.
17
+ *
18
+ * All errors are swallowed - disk full, permission denied, missing
19
+ * directory, etc. The worst case is a one-time replay on the next start;
20
+ * we'd rather not crash the adapter for a persistence hiccup.
21
+ */
22
+ import { mkdirSync, readFileSync, renameSync, writeFileSync } from "node:fs";
23
+ import { homedir } from "node:os";
24
+ import { dirname, join } from "node:path";
25
+ import { lowestPendingUnknown } from "./pending-unknown-store.js";
26
+ /** Resolve the target file path; respects `CODEX_BGOS_HOME` env override. */
27
+ function lastIdPath() {
28
+ const root = process.env.CODEX_BGOS_HOME ?? join(homedir(), ".codex-bgos");
29
+ return join(root, "bgos_last_id");
30
+ }
31
+ /**
32
+ * Read the persisted cursor.
33
+ *
34
+ * Returns 0 when:
35
+ * - The file does not exist (fresh install).
36
+ * - The file is unreadable (permissions, IO error).
37
+ * - The file's contents do not parse as a positive integer (corruption,
38
+ * truncation, manual edit).
39
+ *
40
+ * Never throws - the adapter calls this on hot paths and crashing here
41
+ * would block boot.
42
+ */
43
+ export function loadLastId() {
44
+ try {
45
+ const raw = readFileSync(lastIdPath(), "utf8").trim();
46
+ if (!raw)
47
+ return 0;
48
+ const n = Number(raw);
49
+ if (!Number.isFinite(n) || !Number.isInteger(n) || n < 0)
50
+ return 0;
51
+ return n;
52
+ }
53
+ catch {
54
+ return 0;
55
+ }
56
+ }
57
+ /**
58
+ * Atomically persist the cursor.
59
+ *
60
+ * Skips:
61
+ * - Non-positive ids (0 means "no progress"; negative is malformed).
62
+ * - Ids less than or equal to the currently persisted value (cursor must
63
+ * advance monotonically). This guards against a backfill replay
64
+ * accidentally rewinding the cursor.
65
+ *
66
+ * Clamp: the cursor never advances past the LOWEST still-pending unknown
67
+ * assistant id (see pending-unknown-store). Without this a sibling KNOWN
68
+ * message with a higher id would push the cursor past an unconsumed unknown
69
+ * message, stranding it forever (silent loss). The clamp holds the cursor just
70
+ * below the hole so the inbound window stays re-fetchable until the route heals
71
+ * and the pending id is consumed + cleared.
72
+ *
73
+ * Errors are caught + ignored - see module docstring.
74
+ */
75
+ export function saveLastId(id) {
76
+ if (!Number.isFinite(id) || !Number.isInteger(id) || id <= 0)
77
+ return;
78
+ try {
79
+ const current = loadLastId();
80
+ // Clamp against the lowest pending-unknown id so the cursor never strands
81
+ // an unconsumed message above the hole.
82
+ let advanceTo = id;
83
+ const lowest = lowestPendingUnknown();
84
+ if (lowest !== null && advanceTo >= lowest) {
85
+ advanceTo = lowest - 1;
86
+ }
87
+ if (advanceTo <= current)
88
+ return;
89
+ const target = lastIdPath();
90
+ mkdirSync(dirname(target), { recursive: true });
91
+ // Write to a sibling tempfile then rename so a partial write never
92
+ // leaves us with a corrupt cursor.
93
+ const tmp = `${target}.${process.pid}.tmp`;
94
+ writeFileSync(tmp, String(advanceTo), { mode: 0o600 });
95
+ renameSync(tmp, target);
96
+ }
97
+ catch {
98
+ /* swallow - see module docstring */
99
+ }
100
+ }
101
+ //# sourceMappingURL=last-id-store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"last-id-store.js","sourceRoot":"","sources":["../src/last-id-store.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAC7E,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAE1C,OAAO,EAAE,oBAAoB,EAAE,MAAM,4BAA4B,CAAC;AAElE,6EAA6E;AAC7E,SAAS,UAAU;IACjB,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,eAAe,IAAI,IAAI,CAAC,OAAO,EAAE,EAAE,aAAa,CAAC,CAAC;IAC3E,OAAO,IAAI,CAAC,IAAI,EAAE,cAAc,CAAC,CAAC;AACpC,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,UAAU;IACxB,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,YAAY,CAAC,UAAU,EAAE,EAAE,MAAM,CAAC,CAAC,IAAI,EAAE,CAAC;QACtD,IAAI,CAAC,GAAG;YAAE,OAAO,CAAC,CAAC;QACnB,MAAM,CAAC,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC;QACtB,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC;YAAE,OAAO,CAAC,CAAC;QACnE,OAAO,CAAC,CAAC;IACX,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,CAAC,CAAC;IACX,CAAC;AACH,CAAC;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,UAAU,UAAU,CAAC,EAAU;IACnC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,CAAC;QAAE,OAAO;IACrE,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,UAAU,EAAE,CAAC;QAC7B,0EAA0E;QAC1E,wCAAwC;QACxC,IAAI,SAAS,GAAG,EAAE,CAAC;QACnB,MAAM,MAAM,GAAG,oBAAoB,EAAE,CAAC;QACtC,IAAI,MAAM,KAAK,IAAI,IAAI,SAAS,IAAI,MAAM,EAAE,CAAC;YAC3C,SAAS,GAAG,MAAM,GAAG,CAAC,CAAC;QACzB,CAAC;QACD,IAAI,SAAS,IAAI,OAAO;YAAE,OAAO;QACjC,MAAM,MAAM,GAAG,UAAU,EAAE,CAAC;QAC5B,SAAS,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAChD,mEAAmE;QACnE,mCAAmC;QACnC,MAAM,GAAG,GAAG,GAAG,MAAM,IAAI,OAAO,CAAC,GAAG,MAAM,CAAC;QAC3C,aAAa,CAAC,GAAG,EAAE,MAAM,CAAC,SAAS,CAAC,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;QACvD,UAAU,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;IAC1B,CAAC;IAAC,MAAM,CAAC;QACP,oCAAoC;IACtC,CAAC;AACH,CAAC"}