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,44 @@
1
+ import type { Input } from "@openai/codex-sdk";
2
+ import { type ToolCard } from "./event-mapper.js";
3
+ import type { AuthResolutionOk } from "./auth-mode.js";
4
+ export interface CodexHostOptions {
5
+ auth: AuthResolutionOk;
6
+ /** Working directory Codex operates in. Default `<home>/workspace`. */
7
+ workdir?: string;
8
+ /** Optional model override (CODEX_BGOS_MODEL). */
9
+ model?: string;
10
+ }
11
+ export interface RunTurnCallbacks {
12
+ /** Fired once the first time each tool item appears (drives tool_progress). */
13
+ onTool?: (card: ToolCard, id: string) => void;
14
+ /** Periodic keepalive while a turn is in flight (drives the typing dots). */
15
+ onTick?: () => void;
16
+ }
17
+ export interface RunTurnResult {
18
+ replyText: string;
19
+ error: string | null;
20
+ threadId: string | null;
21
+ }
22
+ export declare class CodexHost {
23
+ readonly authMode: "chatgpt" | "apikey";
24
+ readonly workdir: string;
25
+ private readonly codex;
26
+ private readonly model?;
27
+ private readonly threadsFile;
28
+ private readonly map;
29
+ constructor(opts: CodexHostOptions);
30
+ private threadOptions;
31
+ /**
32
+ * Overwrite AGENTS.md with a resolved capability guide (the served canon
33
+ * fetched at connect). The constructor already wrote the bundled
34
+ * BGOS_AGENT_HINTS as the offline fallback, so a failed fetch simply leaves
35
+ * that in place; the adapter calls this only after a valid fetch. Non-fatal:
36
+ * a write error leaves the previous AGENTS.md untouched.
37
+ */
38
+ applyAgentHints(text: string): void;
39
+ /** Drop a chat's thread binding so the next message starts fresh (/new). */
40
+ resetChat(chatId: string | number): void;
41
+ /** Run one turn for a chat, streaming events to the callbacks. */
42
+ runTurn(chatId: string | number, input: Input, cb?: RunTurnCallbacks): Promise<RunTurnResult>;
43
+ }
44
+ //# sourceMappingURL=codex-host.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"codex-host.d.ts","sourceRoot":"","sources":["../src/codex-host.ts"],"names":[],"mappings":"AAiBA,OAAO,KAAK,EAAE,KAAK,EAA8B,MAAM,mBAAmB,CAAC;AAK3E,OAAO,EAAkB,KAAK,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAUlE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAMvD,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,gBAAgB,CAAC;IACvB,uEAAuE;IACvE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,kDAAkD;IAClD,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,gBAAgB;IAC/B,+EAA+E;IAC/E,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IAC9C,6EAA6E;IAC7E,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;CACrB;AAED,MAAM,WAAW,aAAa;IAC5B,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;CACzB;AAED,qBAAa,SAAS;IACpB,QAAQ,CAAC,QAAQ,EAAE,SAAS,GAAG,QAAQ,CAAC;IACxC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IAEzB,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAQ;IAC9B,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAS;IACrC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAY;gBAEpB,IAAI,EAAE,gBAAgB;IA+BlC,OAAO,CAAC,aAAa;IAarB;;;;;;OAMG;IACH,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAQnC,4EAA4E;IAC5E,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IAIxC,kEAAkE;IAC5D,OAAO,CACX,MAAM,EAAE,MAAM,GAAG,MAAM,EACvB,KAAK,EAAE,KAAK,EACZ,EAAE,GAAE,gBAAqB,GACxB,OAAO,CAAC,aAAa,CAAC;CA8C1B"}
@@ -0,0 +1,142 @@
1
+ /**
2
+ * The Codex brain: wraps @openai/codex-sdk and maps one BGOS chat to one
3
+ * persistent Codex thread.
4
+ *
5
+ * - First message in a chat: `codex.startThread()`, capture the thread id from
6
+ * the `thread.started` event, persist it (thread-map).
7
+ * - Later messages: `codex.resumeThread(id)` so context carries across daemon
8
+ * restarts (Codex persists the thread body under ~/.codex/sessions).
9
+ * - `/new`: resetChat() drops the mapping so the next message starts fresh.
10
+ *
11
+ * Runs are streamed (`runStreamed`) so tool events map to a live tool_progress
12
+ * card. Auth is decided by auth-mode (D7): the child env has OPENAI_API_KEY and
13
+ * CODEX_API_KEY stripped so exactly one credential path is active, either the
14
+ * apikey (injected by the SDK as CODEX_API_KEY) or the existing `codex login`
15
+ * (~/.codex/auth.json).
16
+ */
17
+ import { Codex } from "@openai/codex-sdk";
18
+ import { mkdirSync, writeFileSync } from "node:fs";
19
+ import { join } from "node:path";
20
+ import { homedir, tmpdir } from "node:os";
21
+ import { RunAccumulator } from "./event-mapper.js";
22
+ import { loadThreadMap, getThreadId, setThreadId, resetChat, threadsPath, } from "./thread-map.js";
23
+ import { BGOS_AGENT_HINTS } from "./agent-hints.js";
24
+ function codexBgosHome() {
25
+ return process.env.CODEX_BGOS_HOME ?? join(homedir(), ".codex-bgos");
26
+ }
27
+ export class CodexHost {
28
+ authMode;
29
+ workdir;
30
+ codex;
31
+ model;
32
+ threadsFile;
33
+ map;
34
+ constructor(opts) {
35
+ this.authMode = opts.auth.mode;
36
+ this.workdir = opts.workdir ?? join(codexBgosHome(), "workspace");
37
+ this.model = opts.model;
38
+ this.threadsFile = threadsPath();
39
+ this.map = loadThreadMap(this.threadsFile);
40
+ mkdirSync(this.workdir, { recursive: true });
41
+ // Codex reads AGENTS.md from the working directory, so every turn sees the
42
+ // BGOS capability hints without a per-turn system-prompt injection.
43
+ try {
44
+ writeFileSync(join(this.workdir, "AGENTS.md"), BGOS_AGENT_HINTS);
45
+ }
46
+ catch {
47
+ /* non-fatal: hints are a nicety, chat still works without them */
48
+ }
49
+ // Build a child env WITHOUT the OpenAI/Codex keys so exactly one auth path
50
+ // is live and the CLI never warns about multiple auth env vars.
51
+ const cleanEnv = {};
52
+ for (const [k, v] of Object.entries(process.env)) {
53
+ if (v === undefined)
54
+ continue;
55
+ if (k === "OPENAI_API_KEY" || k === "CODEX_API_KEY")
56
+ continue;
57
+ cleanEnv[k] = v;
58
+ }
59
+ this.codex =
60
+ opts.auth.mode === "apikey"
61
+ ? new Codex({ env: cleanEnv, apiKey: opts.auth.apiKey })
62
+ : new Codex({ env: cleanEnv });
63
+ }
64
+ threadOptions() {
65
+ const opts = {
66
+ workingDirectory: this.workdir,
67
+ skipGitRepoCheck: true,
68
+ sandboxMode: "workspace-write",
69
+ approvalPolicy: "never",
70
+ // Let Codex read user attachments downloaded to the OS temp dir.
71
+ additionalDirectories: [tmpdir()],
72
+ };
73
+ if (this.model)
74
+ opts.model = this.model;
75
+ return opts;
76
+ }
77
+ /**
78
+ * Overwrite AGENTS.md with a resolved capability guide (the served canon
79
+ * fetched at connect). The constructor already wrote the bundled
80
+ * BGOS_AGENT_HINTS as the offline fallback, so a failed fetch simply leaves
81
+ * that in place; the adapter calls this only after a valid fetch. Non-fatal:
82
+ * a write error leaves the previous AGENTS.md untouched.
83
+ */
84
+ applyAgentHints(text) {
85
+ try {
86
+ writeFileSync(join(this.workdir, "AGENTS.md"), text);
87
+ }
88
+ catch {
89
+ /* non-fatal: hints are a nicety, chat still works without them */
90
+ }
91
+ }
92
+ /** Drop a chat's thread binding so the next message starts fresh (/new). */
93
+ resetChat(chatId) {
94
+ resetChat(this.threadsFile, this.map, chatId);
95
+ }
96
+ /** Run one turn for a chat, streaming events to the callbacks. */
97
+ async runTurn(chatId, input, cb = {}) {
98
+ const existing = getThreadId(this.map, chatId);
99
+ const thread = existing
100
+ ? this.codex.resumeThread(existing, this.threadOptions())
101
+ : this.codex.startThread(this.threadOptions());
102
+ const acc = new RunAccumulator();
103
+ const reported = new Set();
104
+ let thrown = null;
105
+ let tick = null;
106
+ if (cb.onTick) {
107
+ tick = setInterval(() => cb.onTick?.(), 4000);
108
+ tick.unref?.();
109
+ }
110
+ try {
111
+ const { events } = await thread.runStreamed(input);
112
+ for await (const event of events) {
113
+ acc.handle(event);
114
+ if (cb.onTool) {
115
+ for (const [id, card] of acc.toolEntries()) {
116
+ if (!reported.has(id)) {
117
+ reported.add(id);
118
+ cb.onTool(card, id);
119
+ }
120
+ }
121
+ }
122
+ }
123
+ }
124
+ catch (err) {
125
+ thrown = err instanceof Error ? err.message : String(err);
126
+ }
127
+ finally {
128
+ if (tick)
129
+ clearInterval(tick);
130
+ }
131
+ const threadId = acc.threadId ?? thread.id ?? existing ?? null;
132
+ if (threadId && threadId !== existing) {
133
+ setThreadId(this.threadsFile, this.map, chatId, threadId);
134
+ }
135
+ return {
136
+ replyText: acc.replyText,
137
+ error: acc.error ?? thrown,
138
+ threadId,
139
+ };
140
+ }
141
+ }
142
+ //# sourceMappingURL=codex-host.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"codex-host.js","sourceRoot":"","sources":["../src/codex-host.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,24 @@
1
+ import type { BgosApi } from "./bgos-api.js";
2
+ import type { CommandManifestEntry } from "./types.js";
3
+ /**
4
+ * Per-assistant command manifest sync. Debounces rapid changes into at
5
+ * most one PUT every DEBOUNCE_MS. Analogous to Telegram plugin's
6
+ * setMyCommands flow (see bot-native-commands.ts in OpenClaw's telegram
7
+ * extension).
8
+ */
9
+ export declare class CommandsSync {
10
+ private readonly api;
11
+ private static readonly DEBOUNCE_MS;
12
+ private readonly pending;
13
+ private timers;
14
+ constructor(api: BgosApi);
15
+ /**
16
+ * Queue a replacement manifest for an assistant. Coalesces multiple
17
+ * calls within DEBOUNCE_MS into a single PUT.
18
+ */
19
+ schedule(assistantId: number, commands: CommandManifestEntry[]): void;
20
+ /** Force-sync all pending - useful on graceful shutdown or pair-ready. */
21
+ flushAll(): Promise<void>;
22
+ private flush;
23
+ }
24
+ //# sourceMappingURL=commands-sync.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"commands-sync.d.ts","sourceRoot":"","sources":["../src/commands-sync.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAC7C,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAEvD;;;;;GAKG;AACH,qBAAa,YAAY;IAMX,OAAO,CAAC,QAAQ,CAAC,GAAG;IALhC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,WAAW,CAAQ;IAE3C,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA6C;IACrE,OAAO,CAAC,MAAM,CAAqC;gBAEtB,GAAG,EAAE,OAAO;IAEzC;;;OAGG;IACH,QAAQ,CAAC,WAAW,EAAE,MAAM,EAAE,QAAQ,EAAE,oBAAoB,EAAE,GAAG,IAAI;IAUrE,0EAA0E;IACpE,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;YAKjB,KAAK;CAOpB"}
@@ -0,0 +1,43 @@
1
+ /**
2
+ * Per-assistant command manifest sync. Debounces rapid changes into at
3
+ * most one PUT every DEBOUNCE_MS. Analogous to Telegram plugin's
4
+ * setMyCommands flow (see bot-native-commands.ts in OpenClaw's telegram
5
+ * extension).
6
+ */
7
+ export class CommandsSync {
8
+ api;
9
+ static DEBOUNCE_MS = 2000;
10
+ pending = new Map();
11
+ timers = new Map();
12
+ constructor(api) {
13
+ this.api = api;
14
+ }
15
+ /**
16
+ * Queue a replacement manifest for an assistant. Coalesces multiple
17
+ * calls within DEBOUNCE_MS into a single PUT.
18
+ */
19
+ schedule(assistantId, commands) {
20
+ this.pending.set(assistantId, commands);
21
+ const existing = this.timers.get(assistantId);
22
+ if (existing)
23
+ clearTimeout(existing);
24
+ const t = setTimeout(() => {
25
+ void this.flush(assistantId);
26
+ }, CommandsSync.DEBOUNCE_MS);
27
+ this.timers.set(assistantId, t);
28
+ }
29
+ /** Force-sync all pending - useful on graceful shutdown or pair-ready. */
30
+ async flushAll() {
31
+ const ids = [...this.pending.keys()];
32
+ await Promise.all(ids.map((id) => this.flush(id)));
33
+ }
34
+ async flush(assistantId) {
35
+ const commands = this.pending.get(assistantId);
36
+ this.pending.delete(assistantId);
37
+ this.timers.delete(assistantId);
38
+ if (!commands)
39
+ return;
40
+ await this.api.putCommands(assistantId, commands);
41
+ }
42
+ }
43
+ //# sourceMappingURL=commands-sync.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"commands-sync.js","sourceRoot":"","sources":["../src/commands-sync.ts"],"names":[],"mappings":"AAGA;;;;;GAKG;AACH,MAAM,OAAO,YAAY;IAMM;IALrB,MAAM,CAAU,WAAW,GAAG,IAAI,CAAC;IAE1B,OAAO,GAAG,IAAI,GAAG,EAAkC,CAAC;IAC7D,MAAM,GAAG,IAAI,GAAG,EAA0B,CAAC;IAEnD,YAA6B,GAAY;QAAZ,QAAG,GAAH,GAAG,CAAS;IAAG,CAAC;IAE7C;;;OAGG;IACH,QAAQ,CAAC,WAAmB,EAAE,QAAgC;QAC5D,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,WAAW,EAAE,QAAQ,CAAC,CAAC;QACxC,MAAM,QAAQ,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;QAC9C,IAAI,QAAQ;YAAE,YAAY,CAAC,QAAQ,CAAC,CAAC;QACrC,MAAM,CAAC,GAAG,UAAU,CAAC,GAAG,EAAE;YACxB,KAAK,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC;QAC/B,CAAC,EAAE,YAAY,CAAC,WAAW,CAAC,CAAC;QAC7B,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC;IAClC,CAAC;IAED,0EAA0E;IAC1E,KAAK,CAAC,QAAQ;QACZ,MAAM,GAAG,GAAG,CAAC,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC;QACrC,MAAM,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IACrD,CAAC;IAEO,KAAK,CAAC,KAAK,CAAC,WAAmB;QACrC,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;QAC/C,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;QACjC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;QAChC,IAAI,CAAC,QAAQ;YAAE,OAAO;QACtB,MAAM,IAAI,CAAC,GAAG,CAAC,WAAW,CAAC,WAAW,EAAE,QAAQ,CAAC,CAAC;IACpD,CAAC"}
@@ -0,0 +1,4 @@
1
+ import type { PluginConfig } from "./types.js";
2
+ export declare function loadConfigFromEnv(): PluginConfig;
3
+ export declare function loadConfigFromPluginCfg(cfg: unknown): PluginConfig;
4
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAS/C,wBAAgB,iBAAiB,IAAI,YAAY,CAOhD;AAaD,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,OAAO,GAAG,YAAY,CAUlE"}
package/dist/config.js ADDED
@@ -0,0 +1,36 @@
1
+ import { z } from "zod";
2
+ const DEFAULT_BASE_URL = "https://api.brandgrowthos.ai";
3
+ const envSchema = z.object({
4
+ BGOS_BASE_URL: z.string().url().optional(),
5
+ BGOS_PAIRING_TOKEN: z.string().min(20),
6
+ });
7
+ export function loadConfigFromEnv() {
8
+ const env = envSchema.parse(process.env);
9
+ return {
10
+ baseUrl: (env.BGOS_BASE_URL ?? DEFAULT_BASE_URL).replace(/\/+$/, ""),
11
+ pairingToken: env.BGOS_PAIRING_TOKEN,
12
+ reconnect: { initialDelayMs: 1000, maxDelayMs: 30000 },
13
+ };
14
+ }
15
+ const cfgSchema = z.object({
16
+ baseUrl: z.string().url().optional(),
17
+ pairingToken: z.string().min(20),
18
+ reconnect: z
19
+ .object({
20
+ initialDelayMs: z.number().int().positive().optional(),
21
+ maxDelayMs: z.number().int().positive().optional(),
22
+ })
23
+ .optional(),
24
+ });
25
+ export function loadConfigFromPluginCfg(cfg) {
26
+ const parsed = cfgSchema.parse(cfg);
27
+ return {
28
+ baseUrl: (parsed.baseUrl ?? DEFAULT_BASE_URL).replace(/\/+$/, ""),
29
+ pairingToken: parsed.pairingToken,
30
+ reconnect: {
31
+ initialDelayMs: parsed.reconnect?.initialDelayMs ?? 1000,
32
+ maxDelayMs: parsed.reconnect?.maxDelayMs ?? 30000,
33
+ },
34
+ };
35
+ }
36
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAIxB,MAAM,gBAAgB,GAAG,8BAA8B,CAAC;AAExD,MAAM,SAAS,GAAG,CAAC,CAAC,MAAM,CAAC;IACzB,aAAa,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE;IAC1C,kBAAkB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC;CACvC,CAAC,CAAC;AAEH,MAAM,UAAU,iBAAiB;IAC/B,MAAM,GAAG,GAAG,SAAS,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IACzC,OAAO;QACL,OAAO,EAAE,CAAC,GAAG,CAAC,aAAa,IAAI,gBAAgB,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC;QACpE,YAAY,EAAE,GAAG,CAAC,kBAAkB;QACpC,SAAS,EAAE,EAAE,cAAc,EAAE,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE;KACvD,CAAC;AACJ,CAAC;AAED,MAAM,SAAS,GAAG,CAAC,CAAC,MAAM,CAAC;IACzB,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE;IACpC,YAAY,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC;IAChC,SAAS,EAAE,CAAC;SACT,MAAM,CAAC;QACN,cAAc,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,EAAE;QACtD,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,EAAE;KACnD,CAAC;SACD,QAAQ,EAAE;CACd,CAAC,CAAC;AAEH,MAAM,UAAU,uBAAuB,CAAC,GAAY;IAClD,MAAM,MAAM,GAAG,SAAS,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IACpC,OAAO;QACL,OAAO,EAAE,CAAC,MAAM,CAAC,OAAO,IAAI,gBAAgB,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC;QACjE,YAAY,EAAE,MAAM,CAAC,YAAY;QACjC,SAAS,EAAE;YACT,cAAc,EAAE,MAAM,CAAC,SAAS,EAAE,cAAc,IAAI,IAAI;YACxD,UAAU,EAAE,MAAM,CAAC,SAAS,EAAE,UAAU,IAAI,KAAK;SAClD;KACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,27 @@
1
+ import type { CommandManifestEntry } from "./types.js";
2
+ /**
3
+ * Manifest entries ready to PUT to `/api/v1/integrations/assistants/:id/commands`.
4
+ * `order_index` preserves the order above on the picker.
5
+ */
6
+ export declare const DEFAULT_COMMANDS: ReadonlyArray<CommandManifestEntry>;
7
+ /**
8
+ * Seed-mode controls how aggressively the adapter reseeds the default manifest:
9
+ * - auto seed only when command_count === 0 (safe default; undefined -> skip)
10
+ * - safe like auto but also seeds when command_count is undefined
11
+ * - always seed unconditionally (idempotent)
12
+ * - never never auto-seed
13
+ * Configure via CODEX_BGOS_RESEED_COMMANDS or the commandSeedMode config.
14
+ */
15
+ export type CommandSeedMode = "auto" | "safe" | "always" | "never";
16
+ /** Read CODEX_BGOS_RESEED_COMMANDS -> normalized mode. Empty/invalid -> "auto". */
17
+ export declare function resolveCommandSeedMode(): CommandSeedMode;
18
+ /**
19
+ * Decide whether to seed defaults for an assistant given the command_count from
20
+ * whoami and the seed mode.
21
+ * auto: count===0 -> seed (undefined -> skip)
22
+ * safe: count===0 -> seed (undefined -> seed)
23
+ * always: seed
24
+ * never: skip
25
+ */
26
+ export declare function shouldSeedDefaults(commandCount: number | undefined, mode?: CommandSeedMode): boolean;
27
+ //# sourceMappingURL=default-commands.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"default-commands.d.ts","sourceRoot":"","sources":["../src/default-commands.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAmBvD;;;GAGG;AACH,eAAO,MAAM,gBAAgB,EAAE,aAAa,CAAC,oBAAoB,CAK5D,CAAC;AAEN;;;;;;;GAOG;AACH,MAAM,MAAM,eAAe,GAAG,MAAM,GAAG,MAAM,GAAG,QAAQ,GAAG,OAAO,CAAC;AASnE,mFAAmF;AACnF,wBAAgB,sBAAsB,IAAI,eAAe,CAexD;AAED;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAChC,YAAY,EAAE,MAAM,GAAG,SAAS,EAChC,IAAI,GAAE,eAAwB,GAC7B,OAAO,CAMT"}
@@ -0,0 +1,64 @@
1
+ /**
2
+ * The Codex adapter's built-in user-invocable slash commands.
3
+ *
4
+ * These pre-populate BGOS's slash picker for a freshly bound assistant. They are
5
+ * bridge-local: the daemon handles them and Codex never sees them (see
6
+ * inbound/adapter). Names match `^[a-z0-9_]{1,32}$`, descriptions <=100 chars.
7
+ * Order is the picker order.
8
+ */
9
+ const _DEFAULT_COMMANDS = [
10
+ { name: "new", description: "Start a fresh conversation (resets the Codex thread)" },
11
+ { name: "retry", description: "Re-run your last message" },
12
+ { name: "status", description: "Show the Codex daemon health and auth mode" },
13
+ ];
14
+ /**
15
+ * Manifest entries ready to PUT to `/api/v1/integrations/assistants/:id/commands`.
16
+ * `order_index` preserves the order above on the picker.
17
+ */
18
+ export const DEFAULT_COMMANDS = _DEFAULT_COMMANDS.map((c, i) => ({
19
+ command: c.name,
20
+ description: c.description,
21
+ order_index: i,
22
+ }));
23
+ const VALID_MODES = [
24
+ "auto",
25
+ "safe",
26
+ "always",
27
+ "never",
28
+ ];
29
+ /** Read CODEX_BGOS_RESEED_COMMANDS -> normalized mode. Empty/invalid -> "auto". */
30
+ export function resolveCommandSeedMode() {
31
+ const raw = (process.env.CODEX_BGOS_RESEED_COMMANDS ?? "")
32
+ .trim()
33
+ .toLowerCase();
34
+ if (!raw)
35
+ return "auto";
36
+ if (VALID_MODES.includes(raw)) {
37
+ return raw;
38
+ }
39
+ // eslint-disable-next-line no-console
40
+ console.warn(`[codex-channel-bgos] CODEX_BGOS_RESEED_COMMANDS=${JSON.stringify(raw)} ` +
41
+ `is not recognized (expected one of ${VALID_MODES.join(", ")}). ` +
42
+ `Falling back to "auto".`);
43
+ return "auto";
44
+ }
45
+ /**
46
+ * Decide whether to seed defaults for an assistant given the command_count from
47
+ * whoami and the seed mode.
48
+ * auto: count===0 -> seed (undefined -> skip)
49
+ * safe: count===0 -> seed (undefined -> seed)
50
+ * always: seed
51
+ * never: skip
52
+ */
53
+ export function shouldSeedDefaults(commandCount, mode = "auto") {
54
+ if (mode === "never")
55
+ return false;
56
+ if (mode === "always")
57
+ return true;
58
+ if (commandCount === 0)
59
+ return true;
60
+ if (mode === "safe" && commandCount === undefined)
61
+ return true;
62
+ return false;
63
+ }
64
+ //# sourceMappingURL=default-commands.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"default-commands.js","sourceRoot":"","sources":["../src/default-commands.ts"],"names":[],"mappings":"AAEA;;;;;;;GAOG;AACH,MAAM,iBAAiB,GAGlB;IACH,EAAE,IAAI,EAAE,KAAK,EAAE,WAAW,EAAE,sDAAsD,EAAE;IACpF,EAAE,IAAI,EAAE,OAAO,EAAE,WAAW,EAAE,0BAA0B,EAAE;IAC1D,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,4CAA4C,EAAE;CACrE,CAAC;AAEX;;;GAGG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAC3B,iBAAiB,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC;IAC/B,OAAO,EAAE,CAAC,CAAC,IAAI;IACf,WAAW,EAAE,CAAC,CAAC,WAAW;IAC1B,WAAW,EAAE,CAAC;CACf,CAAC,CAAC,CAAC;AAYN,MAAM,WAAW,GAAmC;IAClD,MAAM;IACN,MAAM;IACN,QAAQ;IACR,OAAO;CACR,CAAC;AAEF,mFAAmF;AACnF,MAAM,UAAU,sBAAsB;IACpC,MAAM,GAAG,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,0BAA0B,IAAI,EAAE,CAAC;SACvD,IAAI,EAAE;SACN,WAAW,EAAE,CAAC;IACjB,IAAI,CAAC,GAAG;QAAE,OAAO,MAAM,CAAC;IACxB,IAAK,WAAiC,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;QACrD,OAAO,GAAsB,CAAC;IAChC,CAAC;IACD,sCAAsC;IACtC,OAAO,CAAC,IAAI,CACV,mDAAmD,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,GAAG;QACvE,sCAAsC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK;QACjE,yBAAyB,CAC5B,CAAC;IACF,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,kBAAkB,CAChC,YAAgC,EAChC,OAAwB,MAAM;IAE9B,IAAI,IAAI,KAAK,OAAO;QAAE,OAAO,KAAK,CAAC;IACnC,IAAI,IAAI,KAAK,QAAQ;QAAE,OAAO,IAAI,CAAC;IACnC,IAAI,YAAY,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IACpC,IAAI,IAAI,KAAK,MAAM,IAAI,YAAY,KAAK,SAAS;QAAE,OAAO,IAAI,CAAC;IAC/D,OAAO,KAAK,CAAC;AACf,CAAC"}
@@ -0,0 +1,43 @@
1
+ /**
2
+ * Fold a Codex `runStreamed()` event stream into the pieces the daemon posts to
3
+ * BGOS: the reply text (agent_message items), the tool_progress cards
4
+ * (command_execution / file_change / mcp_tool_call / web_search items), the
5
+ * token usage, the captured thread id, and any error.
6
+ *
7
+ * Codex streams real tool events, so tool_progress is host-driven here (an
8
+ * advantage over OpenClaw, which has to ask the agent to self-report). The daemon
9
+ * reads `tools()` after each event to POST a running card on the first tool and
10
+ * PATCH it as tools stream in, then finalizes to "done" at turn end.
11
+ *
12
+ * SDK item/event shapes are @openai/codex-sdk 0.144.1 (see docs/DESIGN.md).
13
+ */
14
+ import type { ThreadEvent, ThreadItem, Usage } from "@openai/codex-sdk";
15
+ export type ToolStatus = "running" | "done" | "error";
16
+ export interface ToolCard {
17
+ icon: string;
18
+ name: string;
19
+ args?: string;
20
+ status: ToolStatus;
21
+ }
22
+ /** Map a Codex ThreadItem to a display card, or null if it is not a tool. */
23
+ export declare function toolCardFromItem(item: ThreadItem): ToolCard | null;
24
+ /** Stateful accumulator: feed it each event with handle(). */
25
+ export declare class RunAccumulator {
26
+ threadId: string | null;
27
+ usage: Usage | null;
28
+ error: string | null;
29
+ private readonly messages;
30
+ private readonly toolOrder;
31
+ private readonly toolById;
32
+ handle(event: ThreadEvent): void;
33
+ private absorbItem;
34
+ /** The accumulated reply text (agent_message items joined by a blank line). */
35
+ get replyText(): string;
36
+ /** Whether any tool item has appeared this run. */
37
+ get hadToolActivity(): boolean;
38
+ /** The tool cards in first-seen order. */
39
+ tools(): ToolCard[];
40
+ /** [id, card] pairs in first-seen order (lets the host report each tool once). */
41
+ toolEntries(): Array<[string, ToolCard]>;
42
+ }
43
+ //# sourceMappingURL=event-mapper.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"event-mapper.d.ts","sourceRoot":"","sources":["../src/event-mapper.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,OAAO,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAExE,MAAM,MAAM,UAAU,GAAG,SAAS,GAAG,MAAM,GAAG,OAAO,CAAC;AAEtD,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,UAAU,CAAC;CACpB;AAeD,6EAA6E;AAC7E,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,UAAU,GAAG,QAAQ,GAAG,IAAI,CA4ClE;AAMD,8DAA8D;AAC9D,qBAAa,cAAc;IACzB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAQ;IAC/B,KAAK,EAAE,KAAK,GAAG,IAAI,CAAQ;IAC3B,KAAK,EAAE,MAAM,GAAG,IAAI,CAAQ;IAE5B,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAgB;IACzC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAgB;IAC1C,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAA+B;IAExD,MAAM,CAAC,KAAK,EAAE,WAAW,GAAG,IAAI;IAyBhC,OAAO,CAAC,UAAU;IAalB,+EAA+E;IAC/E,IAAI,SAAS,IAAI,MAAM,CAEtB;IAED,mDAAmD;IACnD,IAAI,eAAe,IAAI,OAAO,CAE7B;IAED,0CAA0C;IAC1C,KAAK,IAAI,QAAQ,EAAE;IAInB,kFAAkF;IAClF,WAAW,IAAI,KAAK,CAAC,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;CAKzC"}
@@ -0,0 +1,127 @@
1
+ const ARGS_MAX = 120;
2
+ function clip(s) {
3
+ const t = s.replace(/\s+/g, " ").trim();
4
+ return t.length > ARGS_MAX ? t.slice(0, ARGS_MAX) : t;
5
+ }
6
+ function statusFrom(raw) {
7
+ if (raw === "in_progress")
8
+ return "running";
9
+ if (raw === "failed")
10
+ return "error";
11
+ return "done";
12
+ }
13
+ /** Map a Codex ThreadItem to a display card, or null if it is not a tool. */
14
+ export function toolCardFromItem(item) {
15
+ switch (item.type) {
16
+ case "command_execution":
17
+ return {
18
+ icon: "⚡",
19
+ name: "shell",
20
+ args: clip(item.command ?? ""),
21
+ status: statusFrom(item.status),
22
+ };
23
+ case "file_change": {
24
+ const paths = (item.changes ?? [])
25
+ .map((c) => `${c.kind} ${c.path}`)
26
+ .join(", ");
27
+ return {
28
+ icon: "✏️",
29
+ name: "edit",
30
+ args: clip(paths),
31
+ status: statusFrom(item.status),
32
+ };
33
+ }
34
+ case "mcp_tool_call": {
35
+ let args = "";
36
+ try {
37
+ args = item.arguments != null ? JSON.stringify(item.arguments) : "";
38
+ }
39
+ catch {
40
+ args = "";
41
+ }
42
+ return {
43
+ icon: "🔌",
44
+ name: `${item.server}.${item.tool}`,
45
+ args: clip(args),
46
+ status: statusFrom(item.status),
47
+ };
48
+ }
49
+ case "web_search":
50
+ return {
51
+ icon: "🔎",
52
+ name: "web_search",
53
+ args: clip(item.query ?? ""),
54
+ status: "done",
55
+ };
56
+ default:
57
+ return null;
58
+ }
59
+ }
60
+ function itemText(item) {
61
+ return item.type === "agent_message" ? item.text ?? "" : null;
62
+ }
63
+ /** Stateful accumulator: feed it each event with handle(). */
64
+ export class RunAccumulator {
65
+ threadId = null;
66
+ usage = null;
67
+ error = null;
68
+ messages = [];
69
+ toolOrder = [];
70
+ toolById = new Map();
71
+ handle(event) {
72
+ switch (event.type) {
73
+ case "thread.started":
74
+ this.threadId = event.thread_id;
75
+ return;
76
+ case "turn.completed":
77
+ this.usage = event.usage;
78
+ return;
79
+ case "turn.failed":
80
+ this.error = event.error?.message ?? "turn failed";
81
+ return;
82
+ case "error":
83
+ this.error = event.message ?? "error";
84
+ return;
85
+ case "item.started":
86
+ case "item.updated":
87
+ case "item.completed": {
88
+ this.absorbItem(event.item, event.type === "item.completed");
89
+ return;
90
+ }
91
+ default:
92
+ return;
93
+ }
94
+ }
95
+ absorbItem(item, completed) {
96
+ const text = itemText(item);
97
+ if (text !== null) {
98
+ if (completed && text.trim().length > 0)
99
+ this.messages.push(text);
100
+ return;
101
+ }
102
+ const card = toolCardFromItem(item);
103
+ if (!card)
104
+ return;
105
+ const id = item.id;
106
+ if (!this.toolById.has(id))
107
+ this.toolOrder.push(id);
108
+ this.toolById.set(id, card);
109
+ }
110
+ /** The accumulated reply text (agent_message items joined by a blank line). */
111
+ get replyText() {
112
+ return this.messages.join("\n\n");
113
+ }
114
+ /** Whether any tool item has appeared this run. */
115
+ get hadToolActivity() {
116
+ return this.toolOrder.length > 0;
117
+ }
118
+ /** The tool cards in first-seen order. */
119
+ tools() {
120
+ return this.toolOrder.map((id) => this.toolById.get(id)).filter(Boolean);
121
+ }
122
+ /** [id, card] pairs in first-seen order (lets the host report each tool once). */
123
+ toolEntries() {
124
+ return this.toolOrder.map((id) => [id, this.toolById.get(id)]);
125
+ }
126
+ }
127
+ //# sourceMappingURL=event-mapper.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"event-mapper.js","sourceRoot":"","sources":["../src/event-mapper.ts"],"names":[],"mappings":"AAwBA,MAAM,QAAQ,GAAG,GAAG,CAAC;AAErB,SAAS,IAAI,CAAC,CAAS;IACrB,MAAM,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC;IACxC,OAAO,CAAC,CAAC,MAAM,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACxD,CAAC;AAED,SAAS,UAAU,CAAC,GAAY;IAC9B,IAAI,GAAG,KAAK,aAAa;QAAE,OAAO,SAAS,CAAC;IAC5C,IAAI,GAAG,KAAK,QAAQ;QAAE,OAAO,OAAO,CAAC;IACrC,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,6EAA6E;AAC7E,MAAM,UAAU,gBAAgB,CAAC,IAAgB;IAC/C,QAAQ,IAAI,CAAC,IAAI,EAAE,CAAC;QAClB,KAAK,mBAAmB;YACtB,OAAO;gBACL,IAAI,EAAE,GAAG;gBACT,IAAI,EAAE,OAAO;gBACb,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,OAAO,IAAI,EAAE,CAAC;gBAC9B,MAAM,EAAE,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC;aAChC,CAAC;QACJ,KAAK,aAAa,CAAC,CAAC,CAAC;YACnB,MAAM,KAAK,GAAG,CAAC,IAAI,CAAC,OAAO,IAAI,EAAE,CAAC;iBAC/B,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC;iBACjC,IAAI,CAAC,IAAI,CAAC,CAAC;YACd,OAAO;gBACL,IAAI,EAAE,IAAI;gBACV,IAAI,EAAE,MAAM;gBACZ,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC;gBACjB,MAAM,EAAE,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC;aAChC,CAAC;QACJ,CAAC;QACD,KAAK,eAAe,CAAC,CAAC,CAAC;YACrB,IAAI,IAAI,GAAG,EAAE,CAAC;YACd,IAAI,CAAC;gBACH,IAAI,GAAG,IAAI,CAAC,SAAS,IAAI,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;YACtE,CAAC;YAAC,MAAM,CAAC;gBACP,IAAI,GAAG,EAAE,CAAC;YACZ,CAAC;YACD,OAAO;gBACL,IAAI,EAAE,IAAI;gBACV,IAAI,EAAE,GAAG,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,IAAI,EAAE;gBACnC,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC;gBAChB,MAAM,EAAE,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC;aAChC,CAAC;QACJ,CAAC;QACD,KAAK,YAAY;YACf,OAAO;gBACL,IAAI,EAAE,IAAI;gBACV,IAAI,EAAE,YAAY;gBAClB,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,KAAK,IAAI,EAAE,CAAC;gBAC5B,MAAM,EAAE,MAAM;aACf,CAAC;QACJ;YACE,OAAO,IAAI,CAAC;IAChB,CAAC;AACH,CAAC;AAED,SAAS,QAAQ,CAAC,IAAgB;IAChC,OAAO,IAAI,CAAC,IAAI,KAAK,eAAe,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;AAChE,CAAC;AAED,8DAA8D;AAC9D,MAAM,OAAO,cAAc;IACzB,QAAQ,GAAkB,IAAI,CAAC;IAC/B,KAAK,GAAiB,IAAI,CAAC;IAC3B,KAAK,GAAkB,IAAI,CAAC;IAEX,QAAQ,GAAa,EAAE,CAAC;IACxB,SAAS,GAAa,EAAE,CAAC;IACzB,QAAQ,GAAG,IAAI,GAAG,EAAoB,CAAC;IAExD,MAAM,CAAC,KAAkB;QACvB,QAAQ,KAAK,CAAC,IAAI,EAAE,CAAC;YACnB,KAAK,gBAAgB;gBACnB,IAAI,CAAC,QAAQ,GAAG,KAAK,CAAC,SAAS,CAAC;gBAChC,OAAO;YACT,KAAK,gBAAgB;gBACnB,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC;gBACzB,OAAO;YACT,KAAK,aAAa;gBAChB,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC,KAAK,EAAE,OAAO,IAAI,aAAa,CAAC;gBACnD,OAAO;YACT,KAAK,OAAO;gBACV,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC,OAAO,IAAI,OAAO,CAAC;gBACtC,OAAO;YACT,KAAK,cAAc,CAAC;YACpB,KAAK,cAAc,CAAC;YACpB,KAAK,gBAAgB,CAAC,CAAC,CAAC;gBACtB,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,KAAK,gBAAgB,CAAC,CAAC;gBAC7D,OAAO;YACT,CAAC;YACD;gBACE,OAAO;QACX,CAAC;IACH,CAAC;IAEO,UAAU,CAAC,IAAgB,EAAE,SAAkB;QACrD,MAAM,IAAI,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC;QAC5B,IAAI,IAAI,KAAK,IAAI,EAAE,CAAC;YAClB,IAAI,SAAS,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC;gBAAE,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAClE,OAAO;QACT,CAAC;QACD,MAAM,IAAI,GAAG,gBAAgB,CAAC,IAAI,CAAC,CAAC;QACpC,IAAI,CAAC,IAAI;YAAE,OAAO;QAClB,MAAM,EAAE,GAAI,IAAuB,CAAC,EAAE,CAAC;QACvC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;YAAE,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACpD,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC;IAC9B,CAAC;IAED,+EAA+E;IAC/E,IAAI,SAAS;QACX,OAAO,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACpC,CAAC;IAED,mDAAmD;IACnD,IAAI,eAAe;QACjB,OAAO,IAAI,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC,CAAC;IACnC,CAAC;IAED,0CAA0C;IAC1C,KAAK;QACH,OAAO,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAE,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IAC5E,CAAC;IAED,kFAAkF;IAClF,WAAW;QACT,OAAO,IAAI,CAAC,SAAS,CAAC,GAAG,CACvB,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAE,CAAuB,CAC3D,CAAC;IACJ,CAAC;CACF"}