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,124 @@
1
+ /**
2
+ * Parse a Codex text reply for BGOS outbound markers and strip them from the
3
+ * user-visible text. Codex emits a single text stream, so, like OpenClaw, the
4
+ * agent-facing surface uses marker syntax (documented in agent-hints.ts and
5
+ * AGENTS.md):
6
+ *
7
+ * MEDIA:/abs/path one file per line -> outbound files[]
8
+ * STATUS: <text> set the agent status line (empty clears)
9
+ * [[BGOS_BUTTONS]] ... [[/...]] inline option buttons (Label | value, <=6)
10
+ * [[BGOS_ASK]] ... [[/BGOS_ASK]] blocking multi-question modal (<=4 questions)
11
+ *
12
+ * tool_progress is NOT a marker: Codex streams real tool events, so the daemon
13
+ * drives that card from run() events (see event-mapper.ts), not from the reply.
14
+ */
15
+ const MAX_BUTTONS = 6;
16
+ const MAX_ASK_QUESTIONS = 4;
17
+ const MAX_ASK_OPTIONS = 6;
18
+ const BUTTONS_RE = /\[\[BGOS_BUTTONS\]\]([\s\S]*?)\[\[\/BGOS_BUTTONS\]\]/;
19
+ const ASK_RE = /\[\[BGOS_ASK\]\]([\s\S]*?)\[\[\/BGOS_ASK\]\]/;
20
+ function parseOptionLine(line) {
21
+ const trimmed = line.trim();
22
+ if (!trimmed)
23
+ return null;
24
+ const pipe = trimmed.indexOf("|");
25
+ if (pipe === -1) {
26
+ return { text: trimmed, callbackData: trimmed };
27
+ }
28
+ const text = trimmed.slice(0, pipe).trim();
29
+ const callbackData = trimmed.slice(pipe + 1).trim();
30
+ if (!text)
31
+ return null;
32
+ return { text, callbackData: callbackData || text };
33
+ }
34
+ function parseButtonsBlock(body) {
35
+ const options = [];
36
+ for (const raw of body.split("\n")) {
37
+ const opt = parseOptionLine(raw);
38
+ if (opt)
39
+ options.push(opt);
40
+ if (options.length >= MAX_BUTTONS)
41
+ break;
42
+ }
43
+ return options.length > 0 ? { options } : null;
44
+ }
45
+ function parseAskBlock(body) {
46
+ const questions = [];
47
+ let current = null;
48
+ const push = () => {
49
+ if (current && questions.length < MAX_ASK_QUESTIONS)
50
+ questions.push(current);
51
+ };
52
+ for (const raw of body.split("\n")) {
53
+ const line = raw.trim();
54
+ if (!line)
55
+ continue;
56
+ if (line.startsWith("Q:")) {
57
+ push();
58
+ current =
59
+ questions.length < MAX_ASK_QUESTIONS
60
+ ? {
61
+ text: line.slice(2).trim(),
62
+ options: [],
63
+ allowFreeText: true,
64
+ allowSkip: true,
65
+ }
66
+ : null;
67
+ continue;
68
+ }
69
+ if (!current)
70
+ continue;
71
+ if (line === "noskip") {
72
+ current.allowSkip = false;
73
+ continue;
74
+ }
75
+ if (line === "nofreetext") {
76
+ current.allowFreeText = false;
77
+ continue;
78
+ }
79
+ const opt = parseOptionLine(line);
80
+ if (opt && current.options.length < MAX_ASK_OPTIONS)
81
+ current.options.push(opt);
82
+ }
83
+ push();
84
+ return questions.length > 0 ? { questions } : null;
85
+ }
86
+ function collapse(text) {
87
+ return text.replace(/\n{3,}/g, "\n\n").trim();
88
+ }
89
+ export function parseReply(input) {
90
+ let text = input ?? "";
91
+ const buttonsMatch = BUTTONS_RE.exec(text);
92
+ const buttons = buttonsMatch ? parseButtonsBlock(buttonsMatch[1] ?? "") : null;
93
+ if (buttonsMatch)
94
+ text = text.replace(BUTTONS_RE, "");
95
+ const askMatch = ASK_RE.exec(text);
96
+ const ask = askMatch ? parseAskBlock(askMatch[1] ?? "") : null;
97
+ if (askMatch)
98
+ text = text.replace(ASK_RE, "");
99
+ const media = [];
100
+ let status = null;
101
+ const kept = [];
102
+ for (const line of text.split("\n")) {
103
+ const trimmed = line.trim();
104
+ if (trimmed.startsWith("MEDIA:")) {
105
+ const path = trimmed.slice("MEDIA:".length).trim();
106
+ if (path)
107
+ media.push(path);
108
+ continue;
109
+ }
110
+ if (trimmed === "STATUS:" || trimmed.startsWith("STATUS:")) {
111
+ status = { text: trimmed.slice("STATUS:".length).trim() };
112
+ continue;
113
+ }
114
+ kept.push(line);
115
+ }
116
+ return {
117
+ cleanText: collapse(kept.join("\n")),
118
+ media,
119
+ buttons,
120
+ ask,
121
+ status,
122
+ };
123
+ }
124
+ //# sourceMappingURL=reply-markers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reply-markers.js","sourceRoot":"","sources":["../src/reply-markers.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ export declare const LAUNCHD_LABEL = "ai.brandgrowthos.codex-bgos";
2
+ export declare const SYSTEMD_UNIT = "codex-bgos.service";
3
+ export type SupervisorKind = "launchd" | "systemd" | "manual";
4
+ export declare function pickSupervisor(platform: string): SupervisorKind;
5
+ export interface SupervisorRenderOptions {
6
+ /** Absolute path to the node binary (process.execPath). */
7
+ nodePath: string;
8
+ /** Absolute path to the daemon CLI entry (dist/cli.js). */
9
+ cliEntry: string;
10
+ /** The CODEX_BGOS_HOME root, for log file placement. */
11
+ home: string;
12
+ label?: string;
13
+ }
14
+ export declare function renderLaunchdPlist(opts: SupervisorRenderOptions): string;
15
+ export declare function renderSystemdUnit(opts: SupervisorRenderOptions): string;
16
+ //# sourceMappingURL=supervisor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"supervisor.d.ts","sourceRoot":"","sources":["../../src/setup/supervisor.ts"],"names":[],"mappings":"AASA,eAAO,MAAM,aAAa,gCAAgC,CAAC;AAC3D,eAAO,MAAM,YAAY,uBAAuB,CAAC;AAEjD,MAAM,MAAM,cAAc,GAAG,SAAS,GAAG,SAAS,GAAG,QAAQ,CAAC;AAE9D,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,cAAc,CAI/D;AAED,MAAM,WAAW,uBAAuB;IACtC,2DAA2D;IAC3D,QAAQ,EAAE,MAAM,CAAC;IACjB,2DAA2D;IAC3D,QAAQ,EAAE,MAAM,CAAC;IACjB,wDAAwD;IACxD,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,uBAAuB,GAAG,MAAM,CAyBxE;AAED,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,uBAAuB,GAAG,MAAM,CAgBvE"}
@@ -0,0 +1,61 @@
1
+ /**
2
+ * Process-supervisor rendering + install for the codex-channel-bgos daemon.
3
+ *
4
+ * The pure render* functions produce a launchd plist (macOS) or systemd user
5
+ * unit (Linux) that runs `node <cli.js> start` and keeps it alive. installService
6
+ * writes and loads the unit; the renderers are unit-tested without touching disk.
7
+ */
8
+ import { join } from "node:path";
9
+ export const LAUNCHD_LABEL = "ai.brandgrowthos.codex-bgos";
10
+ export const SYSTEMD_UNIT = "codex-bgos.service";
11
+ export function pickSupervisor(platform) {
12
+ if (platform === "darwin")
13
+ return "launchd";
14
+ if (platform === "linux")
15
+ return "systemd";
16
+ return "manual";
17
+ }
18
+ export function renderLaunchdPlist(opts) {
19
+ const label = opts.label ?? LAUNCHD_LABEL;
20
+ const outLog = join(opts.home, "logs", "codex-bgos.log");
21
+ const errLog = join(opts.home, "logs", "codex-bgos.err");
22
+ return `<?xml version="1.0" encoding="UTF-8"?>
23
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
24
+ <plist version="1.0">
25
+ <dict>
26
+ <key>Label</key><string>${label}</string>
27
+ <key>ProgramArguments</key>
28
+ <array>
29
+ <string>${opts.nodePath}</string>
30
+ <string>${opts.cliEntry}</string>
31
+ <string>start</string>
32
+ </array>
33
+ <key>EnvironmentVariables</key><dict>
34
+ <key>NODE_ENV</key><string>production</string>
35
+ </dict>
36
+ <key>StandardOutPath</key><string>${outLog}</string>
37
+ <key>StandardErrorPath</key><string>${errLog}</string>
38
+ <key>RunAtLoad</key><true/>
39
+ <key>KeepAlive</key><true/>
40
+ </dict>
41
+ </plist>
42
+ `;
43
+ }
44
+ export function renderSystemdUnit(opts) {
45
+ return `[Unit]
46
+ Description=codex-channel-bgos daemon (chat with your Codex agents in BGOS)
47
+ After=network-online.target
48
+ Wants=network-online.target
49
+
50
+ [Service]
51
+ Type=simple
52
+ Environment=NODE_ENV=production
53
+ ExecStart=${opts.nodePath} ${opts.cliEntry} start
54
+ Restart=always
55
+ RestartSec=5
56
+
57
+ [Install]
58
+ WantedBy=default.target
59
+ `;
60
+ }
61
+ //# sourceMappingURL=supervisor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"supervisor.js","sourceRoot":"","sources":["../../src/setup/supervisor.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,MAAM,CAAC,MAAM,aAAa,GAAG,6BAA6B,CAAC;AAC3D,MAAM,CAAC,MAAM,YAAY,GAAG,oBAAoB,CAAC;AAIjD,MAAM,UAAU,cAAc,CAAC,QAAgB;IAC7C,IAAI,QAAQ,KAAK,QAAQ;QAAE,OAAO,SAAS,CAAC;IAC5C,IAAI,QAAQ,KAAK,OAAO;QAAE,OAAO,SAAS,CAAC;IAC3C,OAAO,QAAQ,CAAC;AAClB,CAAC;AAYD,MAAM,UAAU,kBAAkB,CAAC,IAA6B;IAC9D,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,IAAI,aAAa,CAAC;IAC1C,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,gBAAgB,CAAC,CAAC;IACzD,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,gBAAgB,CAAC,CAAC;IACzD,OAAO;;;;4BAImB,KAAK;;;cAGnB,IAAI,CAAC,QAAQ;cACb,IAAI,CAAC,QAAQ;;;;;;sCAMW,MAAM;wCACJ,MAAM;;;;;CAK7C,CAAC;AACF,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,IAA6B;IAC7D,OAAO;;;;;;;;YAQG,IAAI,CAAC,QAAQ,IAAI,IAAI,CAAC,QAAQ;;;;;;CAMzC,CAAC;AACF,CAAC"}
@@ -0,0 +1,12 @@
1
+ export type ThreadMap = Record<string, string>;
2
+ /** Path to threads.json; `dir` overrides the home (used in tests). */
3
+ export declare function threadsPath(dir?: string): string;
4
+ /** Load the map from disk. Returns {} on any read/parse error (never throws). */
5
+ export declare function loadThreadMap(path?: string): ThreadMap;
6
+ /** Read the thread id for a chat, or undefined if unmapped. */
7
+ export declare function getThreadId(map: ThreadMap, chatId: string | number): string | undefined;
8
+ /** Set (or overwrite) the thread id for a chat and persist. Mutates `map`. */
9
+ export declare function setThreadId(path: string, map: ThreadMap, chatId: string | number, threadId: string): void;
10
+ /** Drop a chat's thread binding and persist (bridge-local `/new`). Mutates `map`. */
11
+ export declare function resetChat(path: string, map: ThreadMap, chatId: string | number): void;
12
+ //# sourceMappingURL=thread-map.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"thread-map.d.ts","sourceRoot":"","sources":["../src/thread-map.ts"],"names":[],"mappings":"AAsBA,MAAM,MAAM,SAAS,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AAO/C,sEAAsE;AACtE,wBAAgB,WAAW,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,MAAM,CAEhD;AAMD,iFAAiF;AACjF,wBAAgB,aAAa,CAAC,IAAI,GAAE,MAAsB,GAAG,SAAS,CAarE;AAED,+DAA+D;AAC/D,wBAAgB,WAAW,CACzB,GAAG,EAAE,SAAS,EACd,MAAM,EAAE,MAAM,GAAG,MAAM,GACtB,MAAM,GAAG,SAAS,CAEpB;AAcD,8EAA8E;AAC9E,wBAAgB,WAAW,CACzB,IAAI,EAAE,MAAM,EACZ,GAAG,EAAE,SAAS,EACd,MAAM,EAAE,MAAM,GAAG,MAAM,EACvB,QAAQ,EAAE,MAAM,GACf,IAAI,CAGN;AAED,qFAAqF;AACrF,wBAAgB,SAAS,CACvB,IAAI,EAAE,MAAM,EACZ,GAAG,EAAE,SAAS,EACd,MAAM,EAAE,MAAM,GAAG,MAAM,GACtB,IAAI,CAGN"}
@@ -0,0 +1,72 @@
1
+ /**
2
+ * Persistent map from a BGOS chat id to its Codex thread id.
3
+ *
4
+ * One BGOS chat maps to one long-lived Codex thread: the first user message
5
+ * calls `codex.startThread()`, captures `thread.id` from the `thread.started`
6
+ * event, and stores it here; later messages call `codex.resumeThread(id)` so the
7
+ * conversation keeps its context across daemon restarts (Codex persists the
8
+ * thread body itself under ~/.codex/sessions). The bridge-local `/new` command
9
+ * calls `resetChat` so the next message starts a fresh thread.
10
+ *
11
+ * File: `$CODEX_BGOS_HOME/threads.json` (default `~/.codex-bgos/threads.json`),
12
+ * a flat `{ "<chatId>": "<threadId>" }` object, atomic tmp+rename, mode 0600.
13
+ */
14
+ import { homedir } from "node:os";
15
+ import { join, dirname } from "node:path";
16
+ import { mkdirSync, readFileSync, renameSync, writeFileSync, } from "node:fs";
17
+ /** Resolve the CODEX_BGOS_HOME root (respects the env override). */
18
+ function codexBgosHome() {
19
+ return process.env.CODEX_BGOS_HOME ?? join(homedir(), ".codex-bgos");
20
+ }
21
+ /** Path to threads.json; `dir` overrides the home (used in tests). */
22
+ export function threadsPath(dir) {
23
+ return join(dir ?? codexBgosHome(), "threads.json");
24
+ }
25
+ function keyOf(chatId) {
26
+ return String(chatId);
27
+ }
28
+ /** Load the map from disk. Returns {} on any read/parse error (never throws). */
29
+ export function loadThreadMap(path = threadsPath()) {
30
+ try {
31
+ const raw = readFileSync(path, "utf8");
32
+ const parsed = JSON.parse(raw);
33
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed))
34
+ return {};
35
+ const out = {};
36
+ for (const [k, v] of Object.entries(parsed)) {
37
+ if (typeof v === "string" && v.length > 0)
38
+ out[k] = v;
39
+ }
40
+ return out;
41
+ }
42
+ catch {
43
+ return {};
44
+ }
45
+ }
46
+ /** Read the thread id for a chat, or undefined if unmapped. */
47
+ export function getThreadId(map, chatId) {
48
+ return map[keyOf(chatId)];
49
+ }
50
+ function persist(path, map) {
51
+ try {
52
+ mkdirSync(dirname(path), { recursive: true });
53
+ const tmp = `${path}.${process.pid}.tmp`;
54
+ writeFileSync(tmp, JSON.stringify(map, null, 2), { mode: 0o600 });
55
+ renameSync(tmp, path);
56
+ }
57
+ catch {
58
+ // A persistence hiccup must never crash the daemon; the in-memory map still
59
+ // works for the current process, and the next successful write recovers it.
60
+ }
61
+ }
62
+ /** Set (or overwrite) the thread id for a chat and persist. Mutates `map`. */
63
+ export function setThreadId(path, map, chatId, threadId) {
64
+ map[keyOf(chatId)] = threadId;
65
+ persist(path, map);
66
+ }
67
+ /** Drop a chat's thread binding and persist (bridge-local `/new`). Mutates `map`. */
68
+ export function resetChat(path, map, chatId) {
69
+ delete map[keyOf(chatId)];
70
+ persist(path, map);
71
+ }
72
+ //# sourceMappingURL=thread-map.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"thread-map.js","sourceRoot":"","sources":["../src/thread-map.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EACL,SAAS,EACT,YAAY,EACZ,UAAU,EACV,aAAa,GACd,MAAM,SAAS,CAAC;AAIjB,oEAAoE;AACpE,SAAS,aAAa;IACpB,OAAO,OAAO,CAAC,GAAG,CAAC,eAAe,IAAI,IAAI,CAAC,OAAO,EAAE,EAAE,aAAa,CAAC,CAAC;AACvE,CAAC;AAED,sEAAsE;AACtE,MAAM,UAAU,WAAW,CAAC,GAAY;IACtC,OAAO,IAAI,CAAC,GAAG,IAAI,aAAa,EAAE,EAAE,cAAc,CAAC,CAAC;AACtD,CAAC;AAED,SAAS,KAAK,CAAC,MAAuB;IACpC,OAAO,MAAM,CAAC,MAAM,CAAC,CAAC;AACxB,CAAC;AAED,iFAAiF;AACjF,MAAM,UAAU,aAAa,CAAC,OAAe,WAAW,EAAE;IACxD,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;QACvC,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAY,CAAC;QAC1C,IAAI,CAAC,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC;YAAE,OAAO,EAAE,CAAC;QAC9E,MAAM,GAAG,GAAc,EAAE,CAAC;QAC1B,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAiC,CAAC,EAAE,CAAC;YACvE,IAAI,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,CAAC,MAAM,GAAG,CAAC;gBAAE,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;QACxD,CAAC;QACD,OAAO,GAAG,CAAC;IACb,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAED,+DAA+D;AAC/D,MAAM,UAAU,WAAW,CACzB,GAAc,EACd,MAAuB;IAEvB,OAAO,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC;AAC5B,CAAC;AAED,SAAS,OAAO,CAAC,IAAY,EAAE,GAAc;IAC3C,IAAI,CAAC;QACH,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAC9C,MAAM,GAAG,GAAG,GAAG,IAAI,IAAI,OAAO,CAAC,GAAG,MAAM,CAAC;QACzC,aAAa,CAAC,GAAG,EAAE,IAAI,CAAC,SAAS,CAAC,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;QAClE,UAAU,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;IACxB,CAAC;IAAC,MAAM,CAAC;QACP,4EAA4E;QAC5E,4EAA4E;IAC9E,CAAC;AACH,CAAC;AAED,8EAA8E;AAC9E,MAAM,UAAU,WAAW,CACzB,IAAY,EACZ,GAAc,EACd,MAAuB,EACvB,QAAgB;IAEhB,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,GAAG,QAAQ,CAAC;IAC9B,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;AACrB,CAAC;AAED,qFAAqF;AACrF,MAAM,UAAU,SAAS,CACvB,IAAY,EACZ,GAAc,EACd,MAAuB;IAEvB,OAAO,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC;IAC1B,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;AACrB,CAAC"}
@@ -0,0 +1,103 @@
1
+ /**
2
+ * Tool-progress card lifecycle for Codex.
3
+ *
4
+ * Unlike OpenClaw (which hides tool lifecycle from the channel adapter and
5
+ * relies on a post-hoc agent-emitted marker block), Codex streams Claude's
6
+ * `tool_use` blocks LIVE in `src/lib/claude.ts:391` of the fork via the
7
+ * `onToolStart` hook. The fork wires this hook into our `sendToolStart`
8
+ * method below, so we render REAL live cards - pulsing-dot + auto-collapse
9
+ * at end-of-turn, identical to Hermes's behavior.
10
+ *
11
+ * Lifecycle (per chat, per turn):
12
+ *
13
+ * first sendToolStart(toolName)
14
+ * → POST messages { messageType:"tool_progress", toolProgress: {
15
+ * state:"running", tools:[{ icon, name, status:"done" }] } }
16
+ * → store new card id in `cardByChat[chatId]`
17
+ *
18
+ * subsequent sendToolStart(toolName) within the same turn
19
+ * → push entry, debounce ≥600 ms (configurable), PATCH the card
20
+ *
21
+ * finalizeTurn() at end of dispatch
22
+ * → PATCH the card to { state:"done", tools:[...] }
23
+ * → drop `cardByChat[chatId]`
24
+ *
25
+ * "All status fires post-hoc done" is the same simplification Hermes makes:
26
+ * Claude doesn't emit per-tool result events to the streaming pipeline,
27
+ * only the start event. By the time the next tool_use arrives (or the turn
28
+ * ends), the previous tool has obviously settled. State="running" on the
29
+ * top-level card stays accurate while at least one tool's run might still
30
+ * be in flight; finalize flips it.
31
+ *
32
+ * Throttling: each tool fires its own PATCH only after `debounceMs`
33
+ * elapses since the last PATCH for the same chat. Cumulative tool list
34
+ * lives in memory; the PATCH always carries the FULL list (server-side
35
+ * is replace-not-append for `toolProgress.tools`).
36
+ *
37
+ * Best-effort by design: a PATCH failure logs a warning but does not block
38
+ * the agent's actual reply. The state is pruned from `cardByChat` so the
39
+ * next tool starts a fresh card cleanly.
40
+ */
41
+ import type { BgosApi } from "./bgos-api.js";
42
+ /** Per-tool entry on a tool_progress card. */
43
+ export interface ToolProgressEntry {
44
+ icon: string;
45
+ name: string;
46
+ args?: string;
47
+ status: "running" | "done" | "error";
48
+ }
49
+ export interface ToolProgressOptions {
50
+ /** Minimum delay between PATCHes for the same chat. Default 600 ms -
51
+ * matches Hermes's `_PROGRESS_EDIT_INTERVAL/2` throttle so tightly-
52
+ * packed tools don't slam the backend. */
53
+ debounceMs?: number;
54
+ /** Friendly-name → emoji map override. The default covers Claude Code
55
+ * CLI's canonical tool names (`Bash`, `Read`, `Edit`, …). */
56
+ iconForToolName?: (toolName: string) => string;
57
+ }
58
+ /**
59
+ * Per-chat card lifecycle for Codex. Construct one per `BGOSAdapter`
60
+ * (the adapter owns it; the fork interacts via `ReplyHandle.sendToolStart`
61
+ * + `ReplyHandle.finalizeTurn`).
62
+ */
63
+ export declare class ToolProgressOrchestrator {
64
+ private readonly api;
65
+ private readonly debounceMs;
66
+ private readonly iconForToolName;
67
+ private readonly cardByChat;
68
+ constructor(api: BgosApi, options?: ToolProgressOptions);
69
+ /**
70
+ * Record that a tool just started on the agent's side and surface it
71
+ * to BGOS. First call per chat POSTs a new card; subsequent calls PATCH.
72
+ *
73
+ * `toolName` should be the canonical tool id (`Bash`, `Read`, `Edit`,
74
+ * `Grep`, …) - Codex's `friendlyToolName()` already normalizes this.
75
+ * `args` is an optional short summary (≤120 chars, plugin truncates).
76
+ */
77
+ sendToolStart(params: {
78
+ assistantId: number;
79
+ chatId: number;
80
+ toolName: string;
81
+ args?: string;
82
+ }): Promise<void>;
83
+ /**
84
+ * End-of-turn signal. Flushes any pending PATCH, then PATCHes the card
85
+ * one last time with state="done". Idempotent - no-op when no active
86
+ * card exists for this chat.
87
+ */
88
+ finalizeTurn(chatId: number): Promise<void>;
89
+ /**
90
+ * Disconnect path: cancel pending debounced PATCHes so we don't leak
91
+ * timers across an adapter restart. Does NOT issue final PATCHes - the
92
+ * next adapter boot will see the cards in state="running" until the
93
+ * frontend's derived-done heuristic collapses them (BGOS desktop v2.5.4+).
94
+ */
95
+ dispose(): void;
96
+ /** Test-only - surface internal state so vitest can assert. */
97
+ get _internal(): {
98
+ activeChats: number[];
99
+ };
100
+ private maybePatchSoon;
101
+ private flush;
102
+ }
103
+ //# sourceMappingURL=tool-progress.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tool-progress.d.ts","sourceRoot":"","sources":["../src/tool-progress.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AACH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAE7C,8CAA8C;AAC9C,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,SAAS,GAAG,MAAM,GAAG,OAAO,CAAC;CACtC;AAaD,MAAM,WAAW,mBAAmB;IAClC;;+CAE2C;IAC3C,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;kEAC8D;IAC9D,eAAe,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,MAAM,CAAC;CAChD;AAED;;;;GAIG;AACH,qBAAa,wBAAwB;IACnC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAU;IAC9B,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IACpC,OAAO,CAAC,QAAQ,CAAC,eAAe,CAA+B;IAC/D,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAgC;gBAE/C,GAAG,EAAE,OAAO,EAAE,OAAO,GAAE,mBAAwB;IAM3D;;;;;;;OAOG;IACG,aAAa,CAAC,MAAM,EAAE;QAC1B,WAAW,EAAE,MAAM,CAAC;QACpB,MAAM,EAAE,MAAM,CAAC;QACf,QAAQ,EAAE,MAAM,CAAC;QACjB,IAAI,CAAC,EAAE,MAAM,CAAC;KACf,GAAG,OAAO,CAAC,IAAI,CAAC;IAkDjB;;;;OAIG;IACG,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IA4BjD;;;;;OAKG;IACH,OAAO,IAAI,IAAI;IAUf,+DAA+D;IAC/D,IAAI,SAAS,IAAI;QAAE,WAAW,EAAE,MAAM,EAAE,CAAA;KAAE,CAEzC;YAEa,cAAc;YAkBd,KAAK;CAgCpB"}
@@ -0,0 +1,216 @@
1
+ /**
2
+ * Per-chat card lifecycle for Codex. Construct one per `BGOSAdapter`
3
+ * (the adapter owns it; the fork interacts via `ReplyHandle.sendToolStart`
4
+ * + `ReplyHandle.finalizeTurn`).
5
+ */
6
+ export class ToolProgressOrchestrator {
7
+ api;
8
+ debounceMs;
9
+ iconForToolName;
10
+ cardByChat = new Map();
11
+ constructor(api, options = {}) {
12
+ this.api = api;
13
+ this.debounceMs = options.debounceMs ?? 600;
14
+ this.iconForToolName = options.iconForToolName ?? defaultIconForToolName;
15
+ }
16
+ /**
17
+ * Record that a tool just started on the agent's side and surface it
18
+ * to BGOS. First call per chat POSTs a new card; subsequent calls PATCH.
19
+ *
20
+ * `toolName` should be the canonical tool id (`Bash`, `Read`, `Edit`,
21
+ * `Grep`, …) - Codex's `friendlyToolName()` already normalizes this.
22
+ * `args` is an optional short summary (≤120 chars, plugin truncates).
23
+ */
24
+ async sendToolStart(params) {
25
+ const { assistantId, chatId, toolName, args } = params;
26
+ const entry = {
27
+ icon: this.iconForToolName(toolName),
28
+ name: toolName,
29
+ status: "done", // see lifecycle comment at top - only start events stream
30
+ };
31
+ if (args !== undefined && args.length > 0) {
32
+ entry.args = args.length > 120 ? args.slice(0, 119) + "…" : args;
33
+ }
34
+ const existing = this.cardByChat.get(chatId);
35
+ if (existing) {
36
+ existing.tools.push(entry);
37
+ // Backend caps tools[] at 50 - clip so the PATCH doesn't 400.
38
+ if (existing.tools.length > 50) {
39
+ existing.tools = existing.tools.slice(0, 50);
40
+ }
41
+ await this.maybePatchSoon(chatId);
42
+ return;
43
+ }
44
+ // First tool of the turn - POST a new card.
45
+ try {
46
+ const created = await this.api.postMessage({
47
+ assistantId,
48
+ chatId,
49
+ sender: "assistant",
50
+ text: buildSummary([entry], false),
51
+ messageType: "tool_progress",
52
+ toolProgress: { state: "running", tools: [entry] },
53
+ });
54
+ this.cardByChat.set(chatId, {
55
+ cardId: created.id,
56
+ tools: [entry],
57
+ lastPatchAt: Date.now(),
58
+ pendingFlush: null,
59
+ });
60
+ }
61
+ catch (err) {
62
+ // POST failed - log + drop. Next tool will retry the POST cleanly.
63
+ // eslint-disable-next-line no-console
64
+ console.warn("[codex-channel-bgos] tool_progress POST failed chat=" +
65
+ chatId +
66
+ " err=" +
67
+ (err instanceof Error ? err.message : String(err)));
68
+ }
69
+ }
70
+ /**
71
+ * End-of-turn signal. Flushes any pending PATCH, then PATCHes the card
72
+ * one last time with state="done". Idempotent - no-op when no active
73
+ * card exists for this chat.
74
+ */
75
+ async finalizeTurn(chatId) {
76
+ const state = this.cardByChat.get(chatId);
77
+ if (!state)
78
+ return;
79
+ // Clear pending flush - we're about to send the final PATCH ourselves.
80
+ if (state.pendingFlush) {
81
+ clearTimeout(state.pendingFlush);
82
+ state.pendingFlush = null;
83
+ }
84
+ this.cardByChat.delete(chatId);
85
+ try {
86
+ await this.api.patchMessage(state.cardId, {
87
+ text: buildSummary(state.tools, true),
88
+ toolProgress: { state: "done", tools: state.tools },
89
+ });
90
+ }
91
+ catch (err) {
92
+ // eslint-disable-next-line no-console
93
+ console.warn("[codex-channel-bgos] tool_progress finalize PATCH failed chat=" +
94
+ chatId +
95
+ " card=" +
96
+ state.cardId +
97
+ " err=" +
98
+ (err instanceof Error ? err.message : String(err)));
99
+ }
100
+ }
101
+ /**
102
+ * Disconnect path: cancel pending debounced PATCHes so we don't leak
103
+ * timers across an adapter restart. Does NOT issue final PATCHes - the
104
+ * next adapter boot will see the cards in state="running" until the
105
+ * frontend's derived-done heuristic collapses them (BGOS desktop v2.5.4+).
106
+ */
107
+ dispose() {
108
+ for (const [, state] of this.cardByChat) {
109
+ if (state.pendingFlush) {
110
+ clearTimeout(state.pendingFlush);
111
+ state.pendingFlush = null;
112
+ }
113
+ }
114
+ this.cardByChat.clear();
115
+ }
116
+ /** Test-only - surface internal state so vitest can assert. */
117
+ get _internal() {
118
+ return { activeChats: Array.from(this.cardByChat.keys()) };
119
+ }
120
+ async maybePatchSoon(chatId) {
121
+ const state = this.cardByChat.get(chatId);
122
+ if (!state)
123
+ return;
124
+ const now = Date.now();
125
+ const elapsed = now - state.lastPatchAt;
126
+ if (elapsed >= this.debounceMs) {
127
+ await this.flush(chatId);
128
+ return;
129
+ }
130
+ // Within debounce window - schedule a single deferred flush. Repeat
131
+ // calls within the window coalesce (later writes supersede earlier
132
+ // ones because we always send the FULL tool list).
133
+ if (state.pendingFlush)
134
+ return;
135
+ state.pendingFlush = setTimeout(() => {
136
+ void this.flush(chatId);
137
+ }, this.debounceMs - elapsed);
138
+ }
139
+ async flush(chatId) {
140
+ const state = this.cardByChat.get(chatId);
141
+ if (!state)
142
+ return;
143
+ if (state.pendingFlush) {
144
+ clearTimeout(state.pendingFlush);
145
+ state.pendingFlush = null;
146
+ }
147
+ state.lastPatchAt = Date.now();
148
+ try {
149
+ await this.api.patchMessage(state.cardId, {
150
+ text: buildSummary(state.tools, false),
151
+ toolProgress: { state: "running", tools: state.tools },
152
+ });
153
+ }
154
+ catch (err) {
155
+ // Card may have been deleted upstream - drop our tracking so the
156
+ // next tool starts cleanly via POST. Anything else is just a flaky
157
+ // PATCH; we'll retry on the next tool.
158
+ const msg = err instanceof Error ? err.message : String(err);
159
+ if (/404|not found/i.test(msg)) {
160
+ this.cardByChat.delete(chatId);
161
+ }
162
+ // eslint-disable-next-line no-console
163
+ console.warn("[codex-channel-bgos] tool_progress PATCH failed chat=" +
164
+ chatId +
165
+ " card=" +
166
+ state.cardId +
167
+ " err=" +
168
+ msg);
169
+ }
170
+ }
171
+ }
172
+ function buildSummary(tools, done) {
173
+ if (tools.length === 0) {
174
+ return done ? "No tools used" : "Working…";
175
+ }
176
+ const names = tools.slice(0, 4).map((t) => t.name);
177
+ const tail = tools.length > 4 ? `, +${tools.length - 4} more` : "";
178
+ if (done) {
179
+ const noun = tools.length === 1 ? "tool" : "tools";
180
+ return `Used ${tools.length} ${noun} · ${names.join(", ")}${tail}`;
181
+ }
182
+ return `Working… · ${names.join(", ")}${tail}`;
183
+ }
184
+ /**
185
+ * Default emoji mapper. Mirrors Hermes's per-tool icons + Codex's own
186
+ * Telegram progress format. Lowercase comparison covers Claude Code CLI's
187
+ * `Bash`/`Read`/`Edit`/`Grep`/… as well as the friendlyToolName variants
188
+ * the fork passes through.
189
+ */
190
+ function defaultIconForToolName(toolName) {
191
+ const t = toolName.toLowerCase();
192
+ if (t === "bash" || t === "terminal" || t.startsWith("exec"))
193
+ return "💻";
194
+ if (t === "read" || t === "read_file" || t.startsWith("read"))
195
+ return "📖";
196
+ if (t === "edit" || t === "write" || t === "write_file")
197
+ return "📝";
198
+ if (t === "grep" || t === "search" || t.startsWith("search"))
199
+ return "🔎";
200
+ if (t === "glob" || t === "find" || t === "ls" || t.startsWith("list"))
201
+ return "📂";
202
+ if (t === "fetch" || t === "web_fetch" || t === "curl")
203
+ return "🌐";
204
+ if (t === "task" || t === "todowrite" || t === "todo_write")
205
+ return "✅";
206
+ if (t.includes("test"))
207
+ return "🧪";
208
+ if (t.includes("install") || t.includes("npm") || t.includes("pip"))
209
+ return "📦";
210
+ if (t.includes("db") || t.includes("sql") || t.includes("psql"))
211
+ return "🗃️";
212
+ // Sensible default - a single-character glyph the frontend can render
213
+ // in the card's icon slot without breaking layout.
214
+ return "🔧";
215
+ }
216
+ //# sourceMappingURL=tool-progress.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tool-progress.js","sourceRoot":"","sources":["../src/tool-progress.ts"],"names":[],"mappings":"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"}