discord-agent-bridge 0.1.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 (201) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +195 -0
  3. package/dist/app.js +210 -0
  4. package/dist/app.js.map +1 -0
  5. package/dist/app.test.js +117 -0
  6. package/dist/app.test.js.map +1 -0
  7. package/dist/cli.js +63 -0
  8. package/dist/cli.js.map +1 -0
  9. package/dist/cli.test.js +91 -0
  10. package/dist/cli.test.js.map +1 -0
  11. package/dist/core/auditLog.js +65 -0
  12. package/dist/core/auditLog.js.map +1 -0
  13. package/dist/core/auditLog.test.js +124 -0
  14. package/dist/core/auditLog.test.js.map +1 -0
  15. package/dist/core/auth.js +106 -0
  16. package/dist/core/auth.js.map +1 -0
  17. package/dist/core/auth.test.js +216 -0
  18. package/dist/core/auth.test.js.map +1 -0
  19. package/dist/core/channelRegistry.js +119 -0
  20. package/dist/core/channelRegistry.js.map +1 -0
  21. package/dist/core/channelRegistry.test.js +114 -0
  22. package/dist/core/channelRegistry.test.js.map +1 -0
  23. package/dist/core/commandPolicy.js +6 -0
  24. package/dist/core/commandPolicy.js.map +1 -0
  25. package/dist/core/commandRouter.js +9 -0
  26. package/dist/core/commandRouter.js.map +1 -0
  27. package/dist/core/config.js +141 -0
  28. package/dist/core/config.js.map +1 -0
  29. package/dist/core/config.test.js +149 -0
  30. package/dist/core/config.test.js.map +1 -0
  31. package/dist/core/configResolver.js +90 -0
  32. package/dist/core/configResolver.js.map +1 -0
  33. package/dist/core/configResolver.test.js +138 -0
  34. package/dist/core/configResolver.test.js.map +1 -0
  35. package/dist/core/configSchema.js +164 -0
  36. package/dist/core/configSchema.js.map +1 -0
  37. package/dist/core/contracts.js +5 -0
  38. package/dist/core/contracts.js.map +1 -0
  39. package/dist/core/eventBus.js +42 -0
  40. package/dist/core/eventBus.js.map +1 -0
  41. package/dist/core/eventBus.test.js +72 -0
  42. package/dist/core/eventBus.test.js.map +1 -0
  43. package/dist/core/hookBridge.js +11 -0
  44. package/dist/core/hookBridge.js.map +1 -0
  45. package/dist/core/logger.js +116 -0
  46. package/dist/core/logger.js.map +1 -0
  47. package/dist/core/logger.test.js +88 -0
  48. package/dist/core/logger.test.js.map +1 -0
  49. package/dist/core/modeRegistry.js +33 -0
  50. package/dist/core/modeRegistry.js.map +1 -0
  51. package/dist/core/permissionResolver.js +43 -0
  52. package/dist/core/permissionResolver.js.map +1 -0
  53. package/dist/core/permissionResolver.test.js +136 -0
  54. package/dist/core/permissionResolver.test.js.map +1 -0
  55. package/dist/core/providerCatalog.js +240 -0
  56. package/dist/core/providerCatalog.js.map +1 -0
  57. package/dist/core/providerCatalog.test.js +230 -0
  58. package/dist/core/providerCatalog.test.js.map +1 -0
  59. package/dist/core/sessionOrchestrator.js +463 -0
  60. package/dist/core/sessionOrchestrator.js.map +1 -0
  61. package/dist/core/sessionOrchestrator.test.js +344 -0
  62. package/dist/core/sessionOrchestrator.test.js.map +1 -0
  63. package/dist/core/state/schema.js +49 -0
  64. package/dist/core/state/schema.js.map +1 -0
  65. package/dist/core/state/store.js +86 -0
  66. package/dist/core/state/store.js.map +1 -0
  67. package/dist/core/state/store.test.js +99 -0
  68. package/dist/core/state/store.test.js.map +1 -0
  69. package/dist/core/usageService.js +310 -0
  70. package/dist/core/usageService.js.map +1 -0
  71. package/dist/core/usageService.test.js +234 -0
  72. package/dist/core/usageService.test.js.map +1 -0
  73. package/dist/discord/alwaysAllow.test.js +181 -0
  74. package/dist/discord/alwaysAllow.test.js.map +1 -0
  75. package/dist/discord/client.js +666 -0
  76. package/dist/discord/client.js.map +1 -0
  77. package/dist/discord/client.test.js +256 -0
  78. package/dist/discord/client.test.js.map +1 -0
  79. package/dist/discord/configPanel.js +270 -0
  80. package/dist/discord/configPanel.js.map +1 -0
  81. package/dist/discord/configPanel.test.js +332 -0
  82. package/dist/discord/configPanel.test.js.map +1 -0
  83. package/dist/discord/directoryBrowser.js +151 -0
  84. package/dist/discord/directoryBrowser.js.map +1 -0
  85. package/dist/discord/directoryBrowser.test.js +163 -0
  86. package/dist/discord/directoryBrowser.test.js.map +1 -0
  87. package/dist/discord/favorites.js +10 -0
  88. package/dist/discord/favorites.js.map +1 -0
  89. package/dist/discord/fileDownload.js +94 -0
  90. package/dist/discord/fileDownload.js.map +1 -0
  91. package/dist/discord/fileDownload.test.js +59 -0
  92. package/dist/discord/fileDownload.test.js.map +1 -0
  93. package/dist/discord/format.js +104 -0
  94. package/dist/discord/format.js.map +1 -0
  95. package/dist/discord/format.test.js +40 -0
  96. package/dist/discord/format.test.js.map +1 -0
  97. package/dist/discord/guildChannels.js +97 -0
  98. package/dist/discord/guildChannels.js.map +1 -0
  99. package/dist/discord/guildChannels.test.js +231 -0
  100. package/dist/discord/guildChannels.test.js.map +1 -0
  101. package/dist/discord/i18n.js +207 -0
  102. package/dist/discord/i18n.js.map +1 -0
  103. package/dist/discord/i18n.test.js +31 -0
  104. package/dist/discord/i18n.test.js.map +1 -0
  105. package/dist/discord/interactionRouter.js +954 -0
  106. package/dist/discord/interactionRouter.js.map +1 -0
  107. package/dist/discord/interactionRouter.test.js +1245 -0
  108. package/dist/discord/interactionRouter.test.js.map +1 -0
  109. package/dist/discord/messageRouter.js +221 -0
  110. package/dist/discord/messageRouter.js.map +1 -0
  111. package/dist/discord/messageRouter.test.js +360 -0
  112. package/dist/discord/messageRouter.test.js.map +1 -0
  113. package/dist/discord/ports.js +12 -0
  114. package/dist/discord/ports.js.map +1 -0
  115. package/dist/discord/renderers/defaultSet.test.js +97 -0
  116. package/dist/discord/renderers/defaultSet.test.js.map +1 -0
  117. package/dist/discord/renderers/diffView.js +73 -0
  118. package/dist/discord/renderers/diffView.js.map +1 -0
  119. package/dist/discord/renderers/diffView.test.js +54 -0
  120. package/dist/discord/renderers/diffView.test.js.map +1 -0
  121. package/dist/discord/renderers/index.js +143 -0
  122. package/dist/discord/renderers/index.js.map +1 -0
  123. package/dist/discord/renderers/index.test.js +124 -0
  124. package/dist/discord/renderers/index.test.js.map +1 -0
  125. package/dist/discord/renderers/mentionOnComplete.js +19 -0
  126. package/dist/discord/renderers/mentionOnComplete.js.map +1 -0
  127. package/dist/discord/renderers/mentionOnComplete.test.js +35 -0
  128. package/dist/discord/renderers/mentionOnComplete.test.js.map +1 -0
  129. package/dist/discord/renderers/permissionButtons.js +150 -0
  130. package/dist/discord/renderers/permissionButtons.js.map +1 -0
  131. package/dist/discord/renderers/permissionButtons.test.js +108 -0
  132. package/dist/discord/renderers/permissionButtons.test.js.map +1 -0
  133. package/dist/discord/renderers/resultLine.js +25 -0
  134. package/dist/discord/renderers/resultLine.js.map +1 -0
  135. package/dist/discord/renderers/statusEmbed.js +20 -0
  136. package/dist/discord/renderers/statusEmbed.js.map +1 -0
  137. package/dist/discord/renderers/statusEmbed.test.js +32 -0
  138. package/dist/discord/renderers/statusEmbed.test.js.map +1 -0
  139. package/dist/discord/renderers/streamEmbed.js +134 -0
  140. package/dist/discord/renderers/streamEmbed.js.map +1 -0
  141. package/dist/discord/renderers/streamEmbed.test.js +97 -0
  142. package/dist/discord/renderers/streamEmbed.test.js.map +1 -0
  143. package/dist/discord/renderers/toolThread.js +65 -0
  144. package/dist/discord/renderers/toolThread.js.map +1 -0
  145. package/dist/discord/renderers/toolThread.test.js +54 -0
  146. package/dist/discord/renderers/toolThread.test.js.map +1 -0
  147. package/dist/discord/renderers/transcriptFeed.js +33 -0
  148. package/dist/discord/renderers/transcriptFeed.js.map +1 -0
  149. package/dist/discord/renderers/usageEmbed.js +78 -0
  150. package/dist/discord/renderers/usageEmbed.js.map +1 -0
  151. package/dist/discord/renderers/usageEmbed.test.js +42 -0
  152. package/dist/discord/renderers/usageEmbed.test.js.map +1 -0
  153. package/dist/discord/wiring.js +214 -0
  154. package/dist/discord/wiring.js.map +1 -0
  155. package/dist/discord/wiring.test.js +252 -0
  156. package/dist/discord/wiring.test.js.map +1 -0
  157. package/dist/discord/wizard/channelWizard.js +305 -0
  158. package/dist/discord/wizard/channelWizard.js.map +1 -0
  159. package/dist/discord/wizard/channelWizard.test.js +298 -0
  160. package/dist/discord/wizard/channelWizard.test.js.map +1 -0
  161. package/dist/discord/wizard/resumeWizard.js +123 -0
  162. package/dist/discord/wizard/resumeWizard.js.map +1 -0
  163. package/dist/modes/claude/index.js +80 -0
  164. package/dist/modes/claude/index.js.map +1 -0
  165. package/dist/modes/claude/listResumable.test.js +72 -0
  166. package/dist/modes/claude/listResumable.test.js.map +1 -0
  167. package/dist/modes/claude/mcpFileTool.js +82 -0
  168. package/dist/modes/claude/mcpFileTool.js.map +1 -0
  169. package/dist/modes/claude/permissions.js +35 -0
  170. package/dist/modes/claude/permissions.js.map +1 -0
  171. package/dist/modes/claude/plugins.js +56 -0
  172. package/dist/modes/claude/plugins.js.map +1 -0
  173. package/dist/modes/claude/session.js +324 -0
  174. package/dist/modes/claude/session.js.map +1 -0
  175. package/dist/modes/claude/session.test.js +415 -0
  176. package/dist/modes/claude/session.test.js.map +1 -0
  177. package/dist/modes/codex/discovery.js +221 -0
  178. package/dist/modes/codex/discovery.js.map +1 -0
  179. package/dist/modes/codex/discovery.test.js +213 -0
  180. package/dist/modes/codex/discovery.test.js.map +1 -0
  181. package/dist/modes/codex/eventMapper.js +262 -0
  182. package/dist/modes/codex/eventMapper.js.map +1 -0
  183. package/dist/modes/codex/index.js +132 -0
  184. package/dist/modes/codex/index.js.map +1 -0
  185. package/dist/modes/codex/index.test.js +170 -0
  186. package/dist/modes/codex/index.test.js.map +1 -0
  187. package/dist/modes/codex/runner.js +207 -0
  188. package/dist/modes/codex/runner.js.map +1 -0
  189. package/dist/modes/codex/runner.test.js +587 -0
  190. package/dist/modes/codex/runner.test.js.map +1 -0
  191. package/dist/modes/codex/sqliteReader.js +171 -0
  192. package/dist/modes/codex/sqliteReader.js.map +1 -0
  193. package/dist/modes/codex/sqliteReader.test.js +137 -0
  194. package/dist/modes/codex/sqliteReader.test.js.map +1 -0
  195. package/dist/setup/wizard.js +115 -0
  196. package/dist/setup/wizard.js.map +1 -0
  197. package/dist/setup/wizard.test.js +216 -0
  198. package/dist/setup/wizard.test.js.map +1 -0
  199. package/dist/startBot.test.js +78 -0
  200. package/dist/startBot.test.js.map +1 -0
  201. package/package.json +58 -0
@@ -0,0 +1,132 @@
1
+ import * as os from 'node:os';
2
+ import * as path from 'node:path';
3
+ import { runCodexTurn } from './runner.js';
4
+ import { CodexDiscovery } from './discovery.js';
5
+ import { CODEX_PERMISSION_MODES } from '../../core/providerCatalog.js';
6
+ export class CodexMode {
7
+ name = 'codex';
8
+ capabilities = {
9
+ streaming: false,
10
+ thinking: false,
11
+ toolThreads: false,
12
+ // Codex does NOT surface per-action Discord Allow/Deny; control is via the
13
+ // sandbox/approval flags (PermMode → runner) + the core CommandPolicy (§5b).
14
+ permissionPrompts: false,
15
+ progress: true,
16
+ transcript: true,
17
+ sessionResume: true,
18
+ fileAttach: false,
19
+ fileDiff: false,
20
+ usagePanel: false,
21
+ // Only the subset that maps to Codex approval/sandbox flags in the runner
22
+ // (verified, §5b/§7A). 'dontAsk'/'auto' have no Codex mapping and are excluded by
23
+ // the central catalog's CODEX_PERMISSION_MODES.
24
+ permissionModes: [...CODEX_PERMISSION_MODES],
25
+ };
26
+ deps;
27
+ constructor(deps = {}) {
28
+ this.deps = deps;
29
+ }
30
+ async start(ctx) {
31
+ return new CodexSession(ctx, this.sessionDeps());
32
+ }
33
+ async resume(ctx, sessionId) {
34
+ return new CodexSession(ctx, { ...this.sessionDeps(), resumeId: sessionId });
35
+ }
36
+ // For the resume UX (§9): list resumable ~/.codex threads. codexHome resolves the
37
+ // configured value, expanding a leading `~` and defaulting to <home>/.codex when
38
+ // unset (P2-2 Q1). includeSubAgents stays internal/false (Q2).
39
+ async listResumable(ctx) {
40
+ const codexHome = resolveCodexHome(ctx.config.codexHome);
41
+ return this.discovery(ctx).listResumable(codexHome, {});
42
+ }
43
+ sessionDeps() {
44
+ return {
45
+ ...(this.deps.runTurn !== undefined ? { runTurn: this.deps.runTurn } : {}),
46
+ };
47
+ }
48
+ discovery(ctx) {
49
+ return this.deps.discovery ?? new CodexDiscovery({ logger: ctx.logger });
50
+ }
51
+ }
52
+ // A Codex session (§9). It holds the turn-invariant inputs (cwd/model/permMode) and
53
+ // the backend thread id — null until the first turn's `thread.started` sets it,
54
+ // captured from the runCodexTurn result. Each send() runs one `codex exec` turn:
55
+ // a fresh turn first, then `exec resume <id>` once the id is known. stop() aborts
56
+ // any in-flight child via an AbortController the runner honors.
57
+ export class CodexSession {
58
+ sessionId = null;
59
+ ctx;
60
+ runTurn;
61
+ cwd;
62
+ model;
63
+ // A single AbortController for the session; stop() aborts it so the in-flight
64
+ // runCodexTurn kills its `codex` child. Turns are serialized by the orchestrator's
65
+ // per-channel queue, so at most one turn is ever in flight.
66
+ abortController;
67
+ closed = false;
68
+ constructor(ctx, deps = {}) {
69
+ this.ctx = ctx;
70
+ this.runTurn = deps.runTurn ?? runCodexTurn;
71
+ this.cwd = ctx.cwd;
72
+ // Codex reads its OWN model (not ctx.model, which carries the Claude model).
73
+ // Empty → omit `-m` so `codex` uses its own config default (operator-set).
74
+ this.model = ctx.config.codexModel ?? '';
75
+ this.abortController = new AbortController();
76
+ if (deps.resumeId !== undefined) {
77
+ this.sessionId = deps.resumeId;
78
+ }
79
+ }
80
+ // Deliver one user turn. runCodexTurn builds the argv (fresh vs resume), spawns
81
+ // the CLI, streams events through ctx.emit, and returns the (possibly newly
82
+ // captured) thread id. After a FRESH turn we store the id so the next turn resumes.
83
+ // On resume, Codex uses the thread's persisted cwd (resume can't pass --cd), so a
84
+ // resumed session's cwd is informational and may be '' (Q4) — the runner ignores
85
+ // cwd on resume anyway.
86
+ async send(turn) {
87
+ if (this.closed)
88
+ throw new Error('Codex session is closed.');
89
+ const result = await this.runTurn({
90
+ prompt: turn.text,
91
+ cwd: this.cwd,
92
+ permMode: this.ctx.permMode,
93
+ ...(this.model.length > 0 ? { model: this.model } : {}),
94
+ ...(this.ctx.effort !== undefined && this.ctx.effort.length > 0 ? { effort: this.ctx.effort } : {}),
95
+ ...(this.sessionId !== null ? { resumeId: this.sessionId } : {}),
96
+ timeoutMs: this.ctx.config.codexTimeoutMs ?? DEFAULT_CODEX_TIMEOUT_MS,
97
+ ...(this.ctx.config.codexCliCommand !== undefined ? { codexCommand: this.ctx.config.codexCliCommand } : {}),
98
+ ...(this.ctx.config.codexHome !== undefined ? { codexHome: resolveCodexHome(this.ctx.config.codexHome) } : {}),
99
+ emit: this.ctx.emit,
100
+ logger: this.ctx.logger,
101
+ signal: this.abortController.signal,
102
+ });
103
+ // Capture the thread id from the first (fresh) turn so subsequent turns resume it.
104
+ if (this.sessionId === null && result.sessionId !== null) {
105
+ this.sessionId = result.sessionId;
106
+ }
107
+ }
108
+ // Abort the in-flight `codex` child (§7.5 kill switch). The runner drains and
109
+ // resolves the turn as aborted; the AbortController stays aborted so a late turn
110
+ // cannot spawn a fresh child.
111
+ async stop() {
112
+ if (this.closed)
113
+ return;
114
+ this.closed = true;
115
+ this.abortController.abort();
116
+ }
117
+ }
118
+ // Fallback when config.codexTimeoutMs is somehow absent (matches configSchema's
119
+ // limits.codexTimeoutMs default). The resolved ModeConfigView normally supplies it.
120
+ const DEFAULT_CODEX_TIMEOUT_MS = 1_800_000;
121
+ // Resolve the configured codexHome to an absolute path: default to <home>/.codex
122
+ // when unset/empty, and expand a leading `~`/`~/` (config stores it as '~/.codex').
123
+ export function resolveCodexHome(configured) {
124
+ if (!configured || configured.length === 0)
125
+ return path.join(os.homedir(), '.codex');
126
+ if (configured === '~')
127
+ return os.homedir();
128
+ if (configured.startsWith('~/'))
129
+ return path.join(os.homedir(), configured.slice(2));
130
+ return configured;
131
+ }
132
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/modes/codex/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AASlC,OAAO,EAAE,YAAY,EAAqD,MAAM,aAAa,CAAC;AAC9F,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAChD,OAAO,EAAE,sBAAsB,EAAE,MAAM,+BAA+B,CAAC;AAkBvE,MAAM,OAAO,SAAS;IACX,IAAI,GAAG,OAAO,CAAC;IAEf,YAAY,GAAiB;QACpC,SAAS,EAAE,KAAK;QAChB,QAAQ,EAAE,KAAK;QACf,WAAW,EAAE,KAAK;QAClB,2EAA2E;QAC3E,6EAA6E;QAC7E,iBAAiB,EAAE,KAAK;QACxB,QAAQ,EAAE,IAAI;QACd,UAAU,EAAE,IAAI;QAChB,aAAa,EAAE,IAAI;QACnB,UAAU,EAAE,KAAK;QACjB,QAAQ,EAAE,KAAK;QACf,UAAU,EAAE,KAAK;QACjB,0EAA0E;QAC1E,kFAAkF;QAClF,gDAAgD;QAChD,eAAe,EAAE,CAAC,GAAG,sBAAsB,CAAC;KAC7C,CAAC;IAEe,IAAI,CAAgB;IAErC,YAAY,OAAsB,EAAE;QAClC,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;IACnB,CAAC;IAED,KAAK,CAAC,KAAK,CAAC,GAAgB;QAC1B,OAAO,IAAI,YAAY,CAAC,GAAG,EAAE,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC;IACnD,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,GAAgB,EAAE,SAAiB;QAC9C,OAAO,IAAI,YAAY,CAAC,GAAG,EAAE,EAAE,GAAG,IAAI,CAAC,WAAW,EAAE,EAAE,QAAQ,EAAE,SAAS,EAAE,CAAC,CAAC;IAC/E,CAAC;IAED,kFAAkF;IAClF,iFAAiF;IACjF,+DAA+D;IAC/D,KAAK,CAAC,aAAa,CAAC,GAAgB;QAClC,MAAM,SAAS,GAAG,gBAAgB,CAAC,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;QACzD,OAAO,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,aAAa,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC;IAC1D,CAAC;IAEO,WAAW;QACjB,OAAO;YACL,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SAC3E,CAAC;IACJ,CAAC;IAEO,SAAS,CAAC,GAAgB;QAChC,OAAO,IAAI,CAAC,IAAI,CAAC,SAAS,IAAI,IAAI,cAAc,CAAC,EAAE,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC;IAC3E,CAAC;CACF;AASD,oFAAoF;AACpF,gFAAgF;AAChF,iFAAiF;AACjF,kFAAkF;AAClF,gEAAgE;AAChE,MAAM,OAAO,YAAY;IACvB,SAAS,GAAkB,IAAI,CAAC;IAEf,GAAG,CAAc;IACjB,OAAO,CAA6D;IACpE,GAAG,CAAS;IACZ,KAAK,CAAS;IAC/B,8EAA8E;IAC9E,mFAAmF;IACnF,4DAA4D;IAC3C,eAAe,CAAkB;IAC1C,MAAM,GAAG,KAAK,CAAC;IAEvB,YAAY,GAAgB,EAAE,OAAyB,EAAE;QACvD,IAAI,CAAC,GAAG,GAAG,GAAG,CAAC;QACf,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,OAAO,IAAI,YAAY,CAAC;QAC5C,IAAI,CAAC,GAAG,GAAG,GAAG,CAAC,GAAG,CAAC;QACnB,6EAA6E;QAC7E,2EAA2E;QAC3E,IAAI,CAAC,KAAK,GAAG,GAAG,CAAC,MAAM,CAAC,UAAU,IAAI,EAAE,CAAC;QACzC,IAAI,CAAC,eAAe,GAAG,IAAI,eAAe,EAAE,CAAC;QAC7C,IAAI,IAAI,CAAC,QAAQ,KAAK,SAAS,EAAE,CAAC;YAChC,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,QAAQ,CAAC;QACjC,CAAC;IACH,CAAC;IAED,gFAAgF;IAChF,4EAA4E;IAC5E,oFAAoF;IACpF,kFAAkF;IAClF,iFAAiF;IACjF,wBAAwB;IACxB,KAAK,CAAC,IAAI,CAAC,IAAe;QACxB,IAAI,IAAI,CAAC,MAAM;YAAE,MAAM,IAAI,KAAK,CAAC,0BAA0B,CAAC,CAAC;QAC7D,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC;YAChC,MAAM,EAAE,IAAI,CAAC,IAAI;YACjB,GAAG,EAAE,IAAI,CAAC,GAAG;YACb,QAAQ,EAAE,IAAI,CAAC,GAAG,CAAC,QAAQ;YAC3B,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACvD,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,KAAK,SAAS,IAAI,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACnG,GAAG,CAAC,IAAI,CAAC,SAAS,KAAK,IAAI,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,IAAI,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAChE,SAAS,EAAE,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,cAAc,IAAI,wBAAwB;YACrE,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,eAAe,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,YAAY,EAAE,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,eAAe,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAC3G,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,SAAS,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,gBAAgB,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAC9G,IAAI,EAAE,IAAI,CAAC,GAAG,CAAC,IAAI;YACnB,MAAM,EAAE,IAAI,CAAC,GAAG,CAAC,MAAM;YACvB,MAAM,EAAE,IAAI,CAAC,eAAe,CAAC,MAAM;SACpC,CAAC,CAAC;QACH,mFAAmF;QACnF,IAAI,IAAI,CAAC,SAAS,KAAK,IAAI,IAAI,MAAM,CAAC,SAAS,KAAK,IAAI,EAAE,CAAC;YACzD,IAAI,CAAC,SAAS,GAAG,MAAM,CAAC,SAAS,CAAC;QACpC,CAAC;IACH,CAAC;IAED,8EAA8E;IAC9E,iFAAiF;IACjF,8BAA8B;IAC9B,KAAK,CAAC,IAAI;QACR,IAAI,IAAI,CAAC,MAAM;YAAE,OAAO;QACxB,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC;QACnB,IAAI,CAAC,eAAe,CAAC,KAAK,EAAE,CAAC;IAC/B,CAAC;CACF;AAED,gFAAgF;AAChF,oFAAoF;AACpF,MAAM,wBAAwB,GAAG,SAAS,CAAC;AAE3C,iFAAiF;AACjF,oFAAoF;AACpF,MAAM,UAAU,gBAAgB,CAAC,UAA8B;IAC7D,IAAI,CAAC,UAAU,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,QAAQ,CAAC,CAAC;IACrF,IAAI,UAAU,KAAK,GAAG;QAAE,OAAO,EAAE,CAAC,OAAO,EAAE,CAAC;IAC5C,IAAI,UAAU,CAAC,UAAU,CAAC,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IACrF,OAAO,UAAU,CAAC;AACpB,CAAC"}
@@ -0,0 +1,170 @@
1
+ import { describe, it, expect, vi } from 'vitest';
2
+ import * as os from 'node:os';
3
+ import * as path from 'node:path';
4
+ import { CodexMode, resolveCodexHome } from './index.js';
5
+ const nullLogger = { debug() { }, info() { }, warn() { }, error() { } };
6
+ // Build a ModeContext whose config is a ModeConfigView; captures emitted events.
7
+ function makeCtx(opts = {}) {
8
+ const events = [];
9
+ const ctx = {
10
+ guildId: 'g1',
11
+ channelId: 'c1',
12
+ cwd: opts.cwd ?? '/tmp/ws',
13
+ ownerId: 'u1',
14
+ permMode: opts.permMode ?? 'default',
15
+ emit: (ev) => events.push(ev),
16
+ requestPermission: async () => ({ behavior: 'deny' }),
17
+ config: { codexTimeoutMs: 5_000, ...opts.config },
18
+ logger: nullLogger,
19
+ audit: () => { },
20
+ };
21
+ return { ctx, events };
22
+ }
23
+ // A runTurn double: records each call's options and returns a scripted result.
24
+ function makeRunTurn(results) {
25
+ const calls = [];
26
+ let i = 0;
27
+ const runTurn = async (o) => {
28
+ calls.push(o);
29
+ return results[Math.min(i++, results.length - 1)];
30
+ };
31
+ return { runTurn, calls };
32
+ }
33
+ const okResult = (sessionId) => ({
34
+ status: 'completed',
35
+ sessionId,
36
+ finalMessage: 'done',
37
+ exitCode: 0,
38
+ });
39
+ describe('CodexMode.capabilities (§5b)', () => {
40
+ it('declares the Codex capability shape: no streaming/thinking/threads/prompts/usage; transcript+progress+resume', () => {
41
+ const caps = new CodexMode().capabilities;
42
+ expect(caps).toEqual({
43
+ streaming: false,
44
+ thinking: false,
45
+ toolThreads: false,
46
+ permissionPrompts: false,
47
+ progress: true,
48
+ transcript: true,
49
+ sessionResume: true,
50
+ fileAttach: false,
51
+ fileDiff: false,
52
+ usagePanel: false,
53
+ permissionModes: ['default', 'acceptEdits', 'bypassPermissions', 'plan'],
54
+ });
55
+ // The two Codex-defining flags, called out explicitly.
56
+ expect(caps.permissionPrompts).toBe(false);
57
+ expect(caps.usagePanel).toBe(false);
58
+ expect(caps.transcript).toBe(true);
59
+ });
60
+ });
61
+ describe('CodexMode.start / CodexSession.send', () => {
62
+ it('start() returns a session whose send() calls runCodexTurn with the permMode + cwd', async () => {
63
+ const { runTurn, calls } = makeRunTurn([okResult('thread-1')]);
64
+ const mode = new CodexMode({ runTurn });
65
+ const { ctx } = makeCtx({ cwd: '/work/proj', permMode: 'acceptEdits' });
66
+ const session = await mode.start(ctx);
67
+ await session.send({ text: 'hello' });
68
+ expect(calls.length).toBe(1);
69
+ expect(calls[0]?.prompt).toBe('hello');
70
+ expect(calls[0]?.cwd).toBe('/work/proj');
71
+ expect(calls[0]?.permMode).toBe('acceptEdits');
72
+ expect(calls[0]?.resumeId).toBeUndefined(); // fresh turn
73
+ expect(calls[0]?.timeoutMs).toBe(5_000);
74
+ });
75
+ it('captures the sessionId from the first turn and passes it as resumeId on the second', async () => {
76
+ const { runTurn, calls } = makeRunTurn([okResult('thread-xyz'), okResult('thread-xyz')]);
77
+ const mode = new CodexMode({ runTurn });
78
+ const { ctx } = makeCtx();
79
+ const session = await mode.start(ctx);
80
+ expect(session.sessionId).toBeNull();
81
+ await session.send({ text: 'first' });
82
+ expect(session.sessionId).toBe('thread-xyz');
83
+ expect(calls[0]?.resumeId).toBeUndefined();
84
+ await session.send({ text: 'second' });
85
+ expect(calls[1]?.resumeId).toBe('thread-xyz'); // resumes the captured id
86
+ });
87
+ it('passes the Codex model (config.codexModel), NOT ctx.model, and omits -m when codexModel is empty', async () => {
88
+ // With a codexModel set → forwarded.
89
+ const set = makeRunTurn([okResult('t')]);
90
+ const modeSet = new CodexMode({ runTurn: set.runTurn });
91
+ const withModel = makeCtx({ config: { model: 'opus', codexModel: 'gpt-5.1-codex', codexTimeoutMs: 5_000 } });
92
+ await (await modeSet.start(withModel.ctx)).send({ text: 'x' });
93
+ expect(set.calls[0]?.model).toBe('gpt-5.1-codex'); // Codex model, not the Claude 'opus'
94
+ // With codexModel empty → model omitted (codex uses its own config default).
95
+ const empty = makeRunTurn([okResult('t')]);
96
+ const modeEmpty = new CodexMode({ runTurn: empty.runTurn });
97
+ const noModel = makeCtx({ config: { model: 'opus', codexModel: '', codexTimeoutMs: 5_000 } });
98
+ await (await modeEmpty.start(noModel.ctx)).send({ text: 'x' });
99
+ expect(empty.calls[0]?.model).toBeUndefined();
100
+ });
101
+ it('exposes sessionId as readonly on the ModeSession', async () => {
102
+ const { runTurn } = makeRunTurn([okResult('thread-9')]);
103
+ const session = await new CodexMode({ runTurn }).start(makeCtx().ctx);
104
+ await session.send({ text: 'hi' });
105
+ expect(session.sessionId).toBe('thread-9');
106
+ });
107
+ });
108
+ describe('CodexMode.resume', () => {
109
+ it('resume() starts a session already bound to the given id and resumes it on the first turn', async () => {
110
+ const { runTurn, calls } = makeRunTurn([okResult('thread-r')]);
111
+ const mode = new CodexMode({ runTurn });
112
+ const { ctx } = makeCtx({ cwd: '' }); // resumed session cwd may be '' (Q4)
113
+ const session = await mode.resume(ctx, 'thread-r');
114
+ expect(session.sessionId).toBe('thread-r');
115
+ await session.send({ text: 'continue' });
116
+ expect(calls[0]?.resumeId).toBe('thread-r');
117
+ });
118
+ });
119
+ describe('CodexSession.stop', () => {
120
+ it('aborts the in-flight turn via the signal the runner is given', async () => {
121
+ let capturedSignal;
122
+ const runTurn = vi.fn(async (o) => {
123
+ capturedSignal = o.signal;
124
+ return okResult('t');
125
+ });
126
+ const session = await new CodexMode({ runTurn }).start(makeCtx().ctx);
127
+ await session.send({ text: 'hi' });
128
+ expect(capturedSignal).toBeInstanceOf(AbortSignal);
129
+ expect(capturedSignal?.aborted).toBe(false);
130
+ await session.stop();
131
+ expect(capturedSignal?.aborted).toBe(true);
132
+ });
133
+ it('a send() after stop() throws (closed session)', async () => {
134
+ const { runTurn } = makeRunTurn([okResult('t')]);
135
+ const session = await new CodexMode({ runTurn }).start(makeCtx().ctx);
136
+ await session.stop();
137
+ await expect(session.send({ text: 'late' })).rejects.toThrow(/closed/);
138
+ });
139
+ });
140
+ describe('CodexMode.listResumable', () => {
141
+ it('calls discovery with the resolved codexHome (from config, ~ expanded)', async () => {
142
+ const listResumable = vi.fn(async () => [{ sessionId: 's1', cwd: '/work' }]);
143
+ const fakeDiscovery = { listResumable };
144
+ const mode = new CodexMode({ discovery: fakeDiscovery });
145
+ const { ctx } = makeCtx({ config: { codexHome: '~/.codex', codexTimeoutMs: 5_000 } });
146
+ const sessions = await mode.listResumable(ctx);
147
+ expect(sessions).toEqual([{ sessionId: 's1', cwd: '/work' }]);
148
+ expect(listResumable).toHaveBeenCalledTimes(1);
149
+ expect(listResumable.mock.calls[0]?.[0]).toBe(path.join(os.homedir(), '.codex'));
150
+ expect(listResumable.mock.calls[0]?.[1]).toEqual({}); // includeSubAgents internal/false
151
+ });
152
+ it('defaults codexHome to <home>/.codex when config.codexHome is unset', async () => {
153
+ const listResumable = vi.fn(async () => []);
154
+ const fakeDiscovery = { listResumable };
155
+ const mode = new CodexMode({ discovery: fakeDiscovery });
156
+ const { ctx } = makeCtx({ config: { codexTimeoutMs: 5_000 } });
157
+ await mode.listResumable(ctx);
158
+ expect(listResumable.mock.calls[0]?.[0]).toBe(path.join(os.homedir(), '.codex'));
159
+ });
160
+ });
161
+ describe('resolveCodexHome', () => {
162
+ it('expands ~, defaults when empty, and passes absolute paths through', () => {
163
+ expect(resolveCodexHome(undefined)).toBe(path.join(os.homedir(), '.codex'));
164
+ expect(resolveCodexHome('')).toBe(path.join(os.homedir(), '.codex'));
165
+ expect(resolveCodexHome('~')).toBe(os.homedir());
166
+ expect(resolveCodexHome('~/.codex')).toBe(path.join(os.homedir(), '.codex'));
167
+ expect(resolveCodexHome('/abs/codex')).toBe('/abs/codex');
168
+ });
169
+ });
170
+ //# sourceMappingURL=index.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.test.js","sourceRoot":"","sources":["../../../src/modes/codex/index.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,207 @@
1
+ import { spawn as realSpawn } from 'node:child_process';
2
+ import { readFile as realReadFile, mkdtemp as realMkdtemp, rm as realRm } from 'node:fs/promises';
3
+ import { randomBytes } from 'node:crypto';
4
+ import * as os from 'node:os';
5
+ import * as path from 'node:path';
6
+ import { isCodexSandboxMode } from '../../core/providerCatalog.js';
7
+ import { mapCodexLine } from './eventMapper.js';
8
+ // Permission choice → codex approval/sandbox flags for a FRESH turn (verified against
9
+ // codex CLI 0.142.4). `-a`/`--ask-for-approval` is a top-level TUI flag and is NOT
10
+ // accepted by `codex exec` (passing it fails the turn with exit 2), so the approval
11
+ // policy is set via `-c approval_policy="…"`; `-s`/`--sandbox` IS valid on exec.
12
+ //
13
+ // The wizard's Codex permission step offers Codex's OWN sandbox vocabulary
14
+ // (`read-only` / `workspace-write` / `danger-full-access`) rather than Claude's
15
+ // PermMode names. Those flow here on the same string channel; each maps to `-s <mode>`
16
+ // plus a sensible approval policy (danger-full-access → the single bypass flag). The
17
+ // legacy Claude PermMode values still map exactly as before, so a Claude-configured
18
+ // default that reaches a Codex session keeps working.
19
+ export function permModeArgs(permMode) {
20
+ // Codex-native sandbox modes (the wizard's Codex permission step).
21
+ if (isCodexSandboxMode(permMode)) {
22
+ switch (permMode) {
23
+ case 'read-only':
24
+ return ['-c', 'approval_policy="on-request"', '-s', 'read-only'];
25
+ case 'danger-full-access':
26
+ return ['--dangerously-bypass-approvals-and-sandbox'];
27
+ case 'workspace-write':
28
+ default:
29
+ return ['-c', 'approval_policy="on-request"', '-s', 'workspace-write'];
30
+ }
31
+ }
32
+ // Claude PermMode values (unchanged mapping).
33
+ switch (permMode) {
34
+ case 'acceptEdits':
35
+ return ['-c', 'approval_policy="never"', '-s', 'workspace-write'];
36
+ case 'bypassPermissions':
37
+ return ['--dangerously-bypass-approvals-and-sandbox'];
38
+ case 'plan':
39
+ return ['-c', 'approval_policy="on-request"', '-s', 'read-only'];
40
+ case 'default':
41
+ default:
42
+ return ['-c', 'approval_policy="on-request"', '-s', 'workspace-write'];
43
+ }
44
+ }
45
+ // The reasoning-effort argv for a fresh turn: `-c model_reasoning_effort="<level>"`
46
+ // (verified against developers.openai.com/codex/config-reference; accepts minimal /
47
+ // low / medium / high / xhigh). Empty/undefined → no flag, so `codex` uses its own
48
+ // config default (the operator's config.toml model_reasoning_effort).
49
+ export function effortArgs(effort) {
50
+ const trimmed = (effort ?? '').trim();
51
+ return trimmed.length > 0 ? ['-c', `model_reasoning_effort="${trimmed}"`] : [];
52
+ }
53
+ // Build the full argv (excluding the command itself). Fresh and resume differ:
54
+ // resume takes the session id positionally and does NOT accept -s/--cd — the
55
+ // thread's persisted approval/sandbox policy governs it, so we deliberately omit
56
+ // those flags on resume and rely on the thread's stored policy (§5b). Both put a
57
+ // `--` before the prompt so a prompt that begins with `-` can't be parsed as a
58
+ // flag.
59
+ export function buildCodexArgs(opts) {
60
+ const modelArgs = opts.model ? ['-m', opts.model] : [];
61
+ if (opts.resumeId) {
62
+ return ['exec', 'resume', '--json', '--skip-git-repo-check', opts.resumeId, ...modelArgs, '-o', opts.outputPath, '--', opts.prompt];
63
+ }
64
+ return [
65
+ 'exec',
66
+ '--json',
67
+ ...permModeArgs(opts.permMode),
68
+ ...effortArgs(opts.effort),
69
+ ...modelArgs,
70
+ '--skip-git-repo-check',
71
+ '--cd',
72
+ opts.cwd,
73
+ '-o',
74
+ opts.outputPath,
75
+ '--',
76
+ opts.prompt,
77
+ ];
78
+ }
79
+ export async function runCodexTurn(opts) {
80
+ const spawn = opts.spawn ?? realSpawn;
81
+ const readFile = opts.readFile ?? ((p) => realReadFile(p, 'utf8'));
82
+ const now = opts.now ?? Date.now;
83
+ const codexCommand = opts.codexCommand ?? 'codex';
84
+ const baseTmp = opts.tmpDir ?? os.tmpdir();
85
+ const tempRoot = await realMkdtemp(path.join(baseTmp, 'dab-codex-'));
86
+ const outputPath = path.join(tempRoot, `${randomBytes(8).toString('hex')}.txt`);
87
+ const args = buildCodexArgs({
88
+ prompt: opts.prompt,
89
+ cwd: opts.cwd,
90
+ permMode: opts.permMode,
91
+ ...(opts.model !== undefined ? { model: opts.model } : {}),
92
+ ...(opts.effort !== undefined ? { effort: opts.effort } : {}),
93
+ ...(opts.resumeId !== undefined ? { resumeId: opts.resumeId } : {}),
94
+ outputPath,
95
+ });
96
+ // Correlate tool_use/tool_result across the two events a command_execution or
97
+ // mcp_tool_call produces: reuse the item's own id when present, else mint a
98
+ // stable per-item counter so the pair shares one id.
99
+ let toolSeq = 0;
100
+ const idFor = (item) => typeof item.id === 'string' && item.id.length > 0 ? item.id : `codex-tool-${++toolSeq}`;
101
+ const start = now();
102
+ let sessionId = opts.resumeId ?? null;
103
+ let timedOut = false;
104
+ let aborted = false;
105
+ try {
106
+ // Ignore the child's stdin: the prompt is passed as an argv positional, but
107
+ // `codex exec` still waits for stdin EOF ("Reading additional input from
108
+ // stdin…") and would otherwise hang until the timeout.
109
+ const child = spawn(codexCommand, args, {
110
+ cwd: opts.cwd,
111
+ env: { ...process.env, ...(opts.codexHome ? { CODEX_HOME: opts.codexHome } : {}) },
112
+ stdio: ['ignore', 'pipe', 'pipe'],
113
+ });
114
+ const closeResult = await new Promise((resolve) => {
115
+ let settled = false;
116
+ const done = (r) => {
117
+ if (settled)
118
+ return;
119
+ settled = true;
120
+ clearTimeout(timer);
121
+ if (onAbort)
122
+ opts.signal?.removeEventListener('abort', onAbort);
123
+ resolve(r);
124
+ };
125
+ const timer = setTimeout(() => {
126
+ timedOut = true;
127
+ child.kill('SIGTERM');
128
+ }, opts.timeoutMs);
129
+ // Kill on external abort (ModeSession.stop / kill switch). If the signal is
130
+ // already aborted, kill on the next tick so the child's close still drains.
131
+ const onAbort = opts.signal
132
+ ? () => {
133
+ aborted = true;
134
+ child.kill('SIGTERM');
135
+ }
136
+ : undefined;
137
+ if (opts.signal && onAbort) {
138
+ if (opts.signal.aborted)
139
+ setImmediate(onAbort);
140
+ else
141
+ opts.signal.addEventListener('abort', onAbort, { once: true });
142
+ }
143
+ let lineBuffer = '';
144
+ const consumeLine = (line) => {
145
+ const mapped = mapCodexLine(line, opts.logger, idFor);
146
+ if (mapped.sessionId)
147
+ sessionId = mapped.sessionId;
148
+ for (const ev of mapped.events)
149
+ opts.emit(ev);
150
+ };
151
+ child.stdout?.on('data', (chunk) => {
152
+ lineBuffer += typeof chunk === 'string' ? chunk : chunk.toString('utf8');
153
+ const lines = lineBuffer.split(/\r?\n/);
154
+ lineBuffer = lines.pop() ?? '';
155
+ for (const line of lines)
156
+ consumeLine(line);
157
+ });
158
+ // Drain stderr so a full pipe never stalls the child; not surfaced as
159
+ // events (the deprecation warning et al. live here and on stdout).
160
+ child.stderr?.on('data', () => { });
161
+ child.on('error', (err) => done({ code: null, spawnError: err }));
162
+ child.on('close', (code) => {
163
+ if (lineBuffer.trim().length > 0)
164
+ consumeLine(lineBuffer);
165
+ lineBuffer = '';
166
+ done({ code });
167
+ });
168
+ });
169
+ if (closeResult.spawnError) {
170
+ opts.emit({ kind: 'error', message: closeResult.spawnError.message, retryable: false });
171
+ return { status: 'error', sessionId, finalMessage: '', exitCode: null };
172
+ }
173
+ // An external abort (stop/kill switch) is expected shutdown, surfaced as a
174
+ // non-retryable error and reported as 'aborted' (checked before the timeout so
175
+ // a kill-triggered close is not misreported as a natural timeout).
176
+ if (aborted && !timedOut) {
177
+ opts.emit({ kind: 'error', message: 'Codex turn was stopped.', retryable: false });
178
+ return { status: 'aborted', sessionId, finalMessage: '', exitCode: closeResult.code };
179
+ }
180
+ if (timedOut) {
181
+ opts.emit({
182
+ kind: 'error',
183
+ message: `Codex turn timed out after ${opts.timeoutMs}ms.`,
184
+ retryable: true,
185
+ });
186
+ return { status: 'timeout', sessionId, finalMessage: '', exitCode: closeResult.code };
187
+ }
188
+ // The -o file is the authoritative final message (not reconstructed from the
189
+ // stream). A missing/unreadable file degrades to empty rather than throwing.
190
+ const finalMessage = (await readFile(outputPath).catch(() => '')).trimEnd();
191
+ const exitCode = closeResult.code;
192
+ if (exitCode !== 0) {
193
+ opts.emit({
194
+ kind: 'error',
195
+ message: `Codex exited with code ${exitCode ?? 'unknown'}.`,
196
+ retryable: false,
197
+ });
198
+ return { status: 'error', sessionId, finalMessage, exitCode };
199
+ }
200
+ opts.logger.debug('codex turn completed', { durationMs: now() - start });
201
+ return { status: 'completed', sessionId, finalMessage, exitCode };
202
+ }
203
+ finally {
204
+ await realRm(tempRoot, { recursive: true, force: true }).catch(() => { });
205
+ }
206
+ }
207
+ //# sourceMappingURL=runner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runner.js","sourceRoot":"","sources":["../../../src/modes/codex/runner.ts"],"names":[],"mappings":"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"}