@moxxy/plugin-provider-codex-agent 0.0.0-stage → 0.46.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 (83) hide show
  1. package/LICENSE +21 -0
  2. package/dist/account-limit.d.ts +11 -0
  3. package/dist/account-limit.d.ts.map +1 -0
  4. package/dist/account-limit.js +24 -0
  5. package/dist/account-limit.js.map +1 -0
  6. package/dist/agent-provider.d.ts +62 -0
  7. package/dist/agent-provider.d.ts.map +1 -0
  8. package/dist/agent-provider.js +209 -0
  9. package/dist/agent-provider.js.map +1 -0
  10. package/dist/codex-session.d.ts +220 -0
  11. package/dist/codex-session.d.ts.map +1 -0
  12. package/dist/codex-session.js +1113 -0
  13. package/dist/codex-session.js.map +1 -0
  14. package/dist/constants.d.ts +15 -0
  15. package/dist/constants.d.ts.map +1 -0
  16. package/dist/constants.js +15 -0
  17. package/dist/constants.js.map +1 -0
  18. package/dist/executable.d.ts +16 -0
  19. package/dist/executable.d.ts.map +1 -0
  20. package/dist/executable.js +43 -0
  21. package/dist/executable.js.map +1 -0
  22. package/dist/index.d.ts +9 -0
  23. package/dist/index.d.ts.map +1 -0
  24. package/dist/index.js +79 -0
  25. package/dist/index.js.map +1 -0
  26. package/dist/login.d.ts +37 -0
  27. package/dist/login.d.ts.map +1 -0
  28. package/dist/login.js +127 -0
  29. package/dist/login.js.map +1 -0
  30. package/dist/offered-models.d.ts +12 -0
  31. package/dist/offered-models.d.ts.map +1 -0
  32. package/dist/offered-models.js +53 -0
  33. package/dist/offered-models.js.map +1 -0
  34. package/dist/own-settings.d.ts +9 -0
  35. package/dist/own-settings.d.ts.map +1 -0
  36. package/dist/own-settings.js +34 -0
  37. package/dist/own-settings.js.map +1 -0
  38. package/dist/protocol.d.ts +279 -0
  39. package/dist/protocol.d.ts.map +1 -0
  40. package/dist/protocol.js +30 -0
  41. package/dist/protocol.js.map +1 -0
  42. package/dist/subagents.d.ts +20 -0
  43. package/dist/subagents.d.ts.map +1 -0
  44. package/dist/subagents.js +90 -0
  45. package/dist/subagents.js.map +1 -0
  46. package/dist/translate.d.ts +87 -0
  47. package/dist/translate.d.ts.map +1 -0
  48. package/dist/translate.js +334 -0
  49. package/dist/translate.js.map +1 -0
  50. package/dist/view-image.d.ts +4 -0
  51. package/dist/view-image.d.ts.map +1 -0
  52. package/dist/view-image.js +47 -0
  53. package/dist/view-image.js.map +1 -0
  54. package/package.json +82 -3
  55. package/src/account-limit.ts +25 -0
  56. package/src/agent-cli.test.ts +76 -0
  57. package/src/agent-provider.test.ts +1556 -0
  58. package/src/agent-provider.ts +234 -0
  59. package/src/codex-session.ts +1258 -0
  60. package/src/constants.ts +18 -0
  61. package/src/event-coverage.test.ts +200 -0
  62. package/src/executable.test.ts +53 -0
  63. package/src/executable.ts +49 -0
  64. package/src/fake-codex.testkit.ts +576 -0
  65. package/src/fixtures/codex-app-server-0.155.1.json +122 -0
  66. package/src/fixtures/codex-app-server-0.163.0.json +125 -0
  67. package/src/fixtures/codex-model-list-0.163.0.json +436 -0
  68. package/src/index.test.ts +45 -0
  69. package/src/index.ts +99 -0
  70. package/src/login.test.ts +93 -0
  71. package/src/login.ts +167 -0
  72. package/src/offered-models.test.ts +87 -0
  73. package/src/offered-models.ts +65 -0
  74. package/src/own-settings.test.ts +45 -0
  75. package/src/own-settings.ts +39 -0
  76. package/src/protocol.ts +256 -0
  77. package/src/subagents.test.ts +47 -0
  78. package/src/subagents.ts +98 -0
  79. package/src/translate.test.ts +160 -0
  80. package/src/translate.ts +362 -0
  81. package/src/view-image.test.ts +29 -0
  82. package/src/view-image.ts +47 -0
  83. package/README.md +0 -3
@@ -0,0 +1,334 @@
1
+ import { diffPathIn, fileDiffFromPatch, fileDiffFromText, imageToolOutput, parseUnifiedDiff, stepListOutput, stepStatusOf } from '@moxxy/sdk';
2
+ import { MOXXY_MCP_SERVER } from './constants.js';
3
+ import { knownItem, otherItem, } from './protocol.js';
4
+ const STILL_RUNNING = 'Still running in the background when Codex ended its turn.';
5
+ /**
6
+ * Codex's notifications for one Moxxy turn, as Moxxy agent events. Calls to
7
+ * Moxxy's own tools are left out: Moxxy records those when it runs them.
8
+ */
9
+ export class TurnTranslator {
10
+ cwd;
11
+ readImage;
12
+ announced = new Set();
13
+ calls = new Map();
14
+ /** Items that started and have not ended yet. */
15
+ running = new Map();
16
+ /** Plan updates shown this turn; each is a call of its own. */
17
+ plans = 0;
18
+ /** Questions Codex just asked in a message, until the session takes them. */
19
+ asked;
20
+ /** The item Codex is on: the last one it started or finished. */
21
+ latestItem;
22
+ /** Codex's last message so far. */
23
+ latestMessage;
24
+ /**
25
+ * `cwd`: the project folder, which the paths of file diffs are shown relative to.
26
+ * `readImage`: the picture at a path, for an image Codex viewed (it names only the file).
27
+ */
28
+ constructor(cwd = '', readImage = () => undefined) {
29
+ this.cwd = cwd;
30
+ this.readImage = readImage;
31
+ }
32
+ /** Show a call before Moxxy decides on it, unless it is already shown. */
33
+ announce(callId, call) {
34
+ if (this.announced.has(callId))
35
+ return [];
36
+ this.announced.add(callId);
37
+ this.calls.set(callId, call);
38
+ return [{ type: 'tool_call', callId, name: call.name, input: call.input }];
39
+ }
40
+ /**
41
+ * What Codex left running as its turn ended (a command in the background):
42
+ * shown as still running, and handed back so its end can be shown when it comes.
43
+ */
44
+ leftRunning() {
45
+ const calls = new Map(this.running);
46
+ this.running.clear();
47
+ const events = [...calls.keys()].map((callId) => ({ type: 'tool_result', callId, ok: true, output: STILL_RUNNING }));
48
+ return { events, calls };
49
+ }
50
+ /** The questions Codex just asked in a message (`delivery: 'async'`), handed out once. */
51
+ takeQuestions() {
52
+ const asked = this.asked;
53
+ this.asked = undefined;
54
+ return asked;
55
+ }
56
+ /** Codex started or finished another item since `itemId`: it works on without waiting. */
57
+ movedOnFrom(itemId) {
58
+ return this.latestItem !== undefined && this.latestItem !== itemId;
59
+ }
60
+ /** Message `itemId` is the last thing Codex said. */
61
+ lastSaid(itemId) {
62
+ return this.latestMessage === itemId;
63
+ }
64
+ /** The call shown for an item, for an approval that names only the item. */
65
+ callOf(callId) {
66
+ return this.calls.get(callId);
67
+ }
68
+ translate(method, params) {
69
+ const p = (params ?? {});
70
+ switch (method) {
71
+ case 'item/agentMessage/delta':
72
+ return typeof p.delta === 'string' && p.delta ? [{ type: 'text_delta', delta: p.delta }] : [];
73
+ case 'item/reasoning/summaryTextDelta':
74
+ return typeof p.delta === 'string' && p.delta ? [{ type: 'reasoning_delta', delta: p.delta }] : [];
75
+ case 'item/started': {
76
+ this.noteItem(p.item);
77
+ const other = otherItem(p.item);
78
+ const item = knownItem(p.item);
79
+ // A search is shown once it ends: Codex knows its query only then.
80
+ const call = other ? { name: other.type, input: other.fields } : item && item.type !== 'webSearch' ? toolCallOf(item) : undefined;
81
+ const id = other?.id ?? item?.id;
82
+ if (!call || id === undefined)
83
+ return [];
84
+ this.running.set(id, call);
85
+ return this.announce(id, call);
86
+ }
87
+ case 'item/completed': {
88
+ this.noteItem(p.item);
89
+ const ended = p.item?.id;
90
+ if (typeof ended === 'string')
91
+ this.running.delete(ended);
92
+ const other = otherItem(p.item);
93
+ if (other)
94
+ return this.otherCompleted(other);
95
+ const item = knownItem(p.item);
96
+ return item ? this.completed(item) : [];
97
+ }
98
+ case 'turn/plan/updated':
99
+ return this.planUpdated(p);
100
+ case 'thread/tokenUsage/updated': {
101
+ const last = p.tokenUsage?.last;
102
+ return last ? [{ type: 'usage', usage: toTokenUsage(last) }] : [];
103
+ }
104
+ default:
105
+ return [];
106
+ }
107
+ }
108
+ noteItem(item) {
109
+ const id = item?.id;
110
+ if (typeof id === 'string')
111
+ this.latestItem = id;
112
+ }
113
+ /**
114
+ * Codex's checklist (its `update_plan` tool) as it stands after a change.
115
+ * Codex reports it as a notification, not an item, so it is shown as a call
116
+ * of its own; the plan of plan mode is a `plan` item instead.
117
+ */
118
+ planUpdated(p) {
119
+ if (!Array.isArray(p.plan))
120
+ return [];
121
+ const steps = p.plan.flatMap((item) => {
122
+ const step = (item ?? {});
123
+ const status = stepStatusOf(step.status);
124
+ return typeof step.step === 'string' && step.step.trim() && status ? [{ text: step.step.trim(), status }] : [];
125
+ });
126
+ const explanation = typeof p.explanation === 'string' && p.explanation.trim() ? p.explanation.trim() : undefined;
127
+ this.plans += 1;
128
+ const callId = `plan-${String(p.turnId ?? 'turn')}-${this.plans}`;
129
+ const forModel = steps.map((step) => `${step.status === 'completed' ? '[x]' : '[ ]'} ${step.text}`).join('\n');
130
+ return [
131
+ ...this.announce(callId, { name: 'update_plan', input: { plan: p.plan, ...(explanation ? { explanation } : {}) } }),
132
+ { type: 'tool_result', callId, ok: true, output: stepListOutput(forModel, steps, explanation) },
133
+ ];
134
+ }
135
+ /**
136
+ * An item of a kind Moxxy does not know (one a newer Codex added), shown as
137
+ * a call named after it: what Codex said as it started, and what it added by the end.
138
+ */
139
+ otherCompleted(item) {
140
+ const announced = this.announce(item.id, { name: item.type, input: item.fields });
141
+ const before = (this.calls.get(item.id)?.input ?? {});
142
+ const added = Object.fromEntries(Object.entries(item.fields).filter(([key, value]) => JSON.stringify(before[key]) !== JSON.stringify(value)));
143
+ const failed = item.status !== undefined && /fail|declin|error/i.test(item.status);
144
+ const result = failed
145
+ ? { type: 'tool_result', callId: item.id, ok: false, error: `Codex reports ${item.type} as ${item.status}.` }
146
+ : { type: 'tool_result', callId: item.id, ok: true, output: Object.keys(added).length > 0 ? added : '' };
147
+ return [...announced, result];
148
+ }
149
+ completed(item) {
150
+ switch (item.type) {
151
+ case 'agentMessage':
152
+ this.latestMessage = item.id;
153
+ if (item.delivery === 'async' && item.questions && item.questions.length > 0)
154
+ this.asked = { itemId: item.id, questions: item.questions };
155
+ return item.text ? [{ type: 'message', text: item.text, stopReason: item.phase === 'commentary' ? 'tool_use' : 'end_turn' }] : [];
156
+ case 'plan':
157
+ return [{ type: 'plan', text: item.text }];
158
+ case 'reasoning': {
159
+ const text = item.summary.join('\n\n').trim();
160
+ return text ? [{ type: 'reasoning', text }] : [];
161
+ }
162
+ default: {
163
+ const call = toolCallOf(item);
164
+ if (!call)
165
+ return [];
166
+ return [...this.announce(item.id, call), { type: 'tool_result', callId: item.id, ...toolResultOf(item, this.cwd, this.readImage) }];
167
+ }
168
+ }
169
+ }
170
+ }
171
+ export function toolCallOf(item) {
172
+ switch (item.type) {
173
+ case 'commandExecution':
174
+ return { name: 'Bash', input: { command: shownCommand(item.command), cwd: item.cwd } };
175
+ case 'fileChange':
176
+ return { name: 'apply_patch', input: { changes: item.changes.map((change) => ({ path: change.path, kind: change.kind.type })) } };
177
+ case 'mcpToolCall':
178
+ return item.server === MOXXY_MCP_SERVER ? undefined : { name: `mcp__${item.server}__${item.tool}`, input: item.arguments };
179
+ case 'webSearch':
180
+ return { name: 'web_search', input: webSearchInput(item.query, item.action) };
181
+ case 'imageView':
182
+ return { name: 'view_image', input: { path: item.path } };
183
+ case 'sleep':
184
+ return { name: 'Sleep', input: { ms: item.durationMs } };
185
+ case 'imageGeneration':
186
+ return { name: 'image_generation', input: item.revisedPrompt ? { prompt: item.revisedPrompt } : {} };
187
+ default:
188
+ return undefined;
189
+ }
190
+ }
191
+ function toolResultOf(item, cwd, readImage) {
192
+ const status = 'status' in item ? item.status : 'completed';
193
+ if (status === 'declined')
194
+ return { ok: false, error: 'The person declined this.' };
195
+ switch (item.type) {
196
+ case 'commandExecution': {
197
+ const output = item.aggregatedOutput ?? '';
198
+ const ok = status === 'completed' && (item.exitCode === null || item.exitCode === 0);
199
+ return ok ? { ok, output } : { ok, error: output || `The command ended with exit code ${item.exitCode ?? 'unknown'}.` };
200
+ }
201
+ case 'fileChange': {
202
+ if (status !== 'completed')
203
+ return { ok: false, error: 'The change was not applied.' };
204
+ const text = item.changes.map((change) => change.diff ?? `${change.kind.type} ${change.path}`).join('\n');
205
+ const display = item.changes.length === 1 && item.changes[0] ? fileDiffOf(item.changes[0], cwd) : undefined;
206
+ return { ok: true, output: display ? { forModel: text, display } : text };
207
+ }
208
+ case 'mcpToolCall': {
209
+ if (item.error)
210
+ return { ok: false, error: item.error.message };
211
+ const shown = mcpImagesOf(item.result);
212
+ return { ok: status !== 'failed', output: shown ? imageToolOutput(shown.text, shown.images) : item.result };
213
+ }
214
+ case 'imageView': {
215
+ const image = readImage(item.path);
216
+ return { ok: true, output: image ? imageToolOutput(item.path, [image]) : '' };
217
+ }
218
+ case 'sleep':
219
+ return { ok: true, output: `Waited ${Math.round(item.durationMs / 1000)} s.` };
220
+ case 'imageGeneration': {
221
+ if (item.failure || status === 'failed') {
222
+ return { ok: false, error: item.failure?.type === 'usageLimitExceeded' ? 'Codex has used up its limit for pictures.' : 'Codex could not make the picture.' };
223
+ }
224
+ const saved = item.savedPath ? readImage(item.savedPath) : undefined;
225
+ const image = saved ?? (item.result ? { mediaType: 'image/png', base64: item.result } : undefined);
226
+ const text = item.savedPath ? `Saved to ${item.savedPath}` : 'The picture Codex made.';
227
+ return { ok: true, output: image ? imageToolOutput(text, [image]) : text };
228
+ }
229
+ default:
230
+ return { ok: true, output: '' };
231
+ }
232
+ }
233
+ /** The images of an MCP result, in order, and its text; Codex's computer use sends each screenshot twice. */
234
+ function mcpImagesOf(result) {
235
+ const content = result?.content;
236
+ if (!Array.isArray(content))
237
+ return undefined;
238
+ const parts = content;
239
+ const images = parts.flatMap((part) => part.type === 'image' && typeof part.data === 'string' && typeof part.mimeType === 'string' ? [{ mediaType: part.mimeType, base64: part.data }] : []);
240
+ if (images.length === 0)
241
+ return undefined;
242
+ const text = parts.flatMap((part) => (part.type === 'text' && typeof part.text === 'string' ? [part.text] : [])).join('\n');
243
+ return { images, text };
244
+ }
245
+ /** A new or changed file as a diff: Codex sends a new file's content, and a change as a unified diff. */
246
+ function fileDiffOf(change, cwd) {
247
+ if (change.diff === undefined)
248
+ return undefined;
249
+ if (change.kind.type === 'add')
250
+ return fileDiffFromText({ path: diffPathIn(cwd, change.path), mode: 'create', before: '', after: change.diff });
251
+ if (change.kind.type !== 'update')
252
+ return undefined;
253
+ const hunks = parseUnifiedDiff(change.diff);
254
+ const path = diffPathIn(cwd, change.kind.move_path ?? change.path);
255
+ return hunks.length > 0 ? fileDiffFromPatch({ path, mode: 'update', hunks }) : undefined;
256
+ }
257
+ function webSearchInput(query, action) {
258
+ if (action?.type === 'open_page' && action.url)
259
+ return { url: action.url };
260
+ if (action?.type === 'find_in_page' && action.url)
261
+ return { url: action.url, ...(action.pattern ? { pattern: action.pattern } : {}) };
262
+ const searched = action?.type === 'search' ? action.query || action.queries?.join(' · ') : undefined;
263
+ return { query: query || searched || '' };
264
+ }
265
+ /** The command as the person would type it: Codex wraps it in `<shell> -lc '…'`. */
266
+ export function shownCommand(command) {
267
+ const wrapped = /^\S*\b(?:ba|z)?sh -l?c '((?:[^']|'\\'')*)'$/s.exec(command);
268
+ return wrapped?.[1] !== undefined ? wrapped[1].replace(/'\\''/g, "'") : command;
269
+ }
270
+ /** Codex counts cached prompt tokens inside `inputTokens`; Moxxy keeps them apart. */
271
+ export function toTokenUsage(usage) {
272
+ const cached = usage.cachedInputTokens;
273
+ return {
274
+ inputTokens: Math.max(0, usage.inputTokens - cached),
275
+ outputTokens: usage.outputTokens,
276
+ ...(cached > 0 ? { cacheReadTokens: cached } : {}),
277
+ };
278
+ }
279
+ /** The person's message as Codex input: text as it is, images inline. */
280
+ export function toCodexInput(prompt) {
281
+ return prompt.flatMap((block) => {
282
+ if (block.type === 'text')
283
+ return [{ type: 'text', text: block.text, text_elements: [] }];
284
+ if (block.type === 'image')
285
+ return [{ type: 'image', url: `data:${block.mediaType};base64,${block.data}` }];
286
+ return [];
287
+ });
288
+ }
289
+ export function promptText(prompt) {
290
+ return prompt.flatMap((block) => (block.type === 'text' ? [block.text] : [])).join('\n');
291
+ }
292
+ /** Codex plan-mode questions as Moxxy Questions. Codex takes any text back, so an own answer always fits. */
293
+ export function fromAsyncQuestions(questions) {
294
+ return questions.map((q, i) => ({
295
+ id: `q${i}`,
296
+ question: q.title,
297
+ options: (q.options ?? []).map((label, j) => ({ id: `q${i}o${j}`, label })),
298
+ multiSelect: false,
299
+ allowOther: true,
300
+ }));
301
+ }
302
+ /** The answers as the next message Codex reads: one `question: answer` line each. */
303
+ export function answersMessage(items, answers) {
304
+ return items
305
+ .map((item) => `${item.question}: ${chosenLabels(item, answers).join(', ')}`)
306
+ .join('\n');
307
+ }
308
+ /** `item/tool/requestUserInput` questions as Moxxy Questions. */
309
+ export function fromUserInputQuestions(questions) {
310
+ return questions.map((q) => ({
311
+ id: q.id,
312
+ ...(q.header ? { header: q.header } : {}),
313
+ question: q.question,
314
+ options: (q.options ?? []).map((option, j) => ({ id: `${q.id}o${j}`, label: option.label, ...(option.description ? { description: option.description } : {}) })),
315
+ multiSelect: false,
316
+ allowOther: q.isOther || (q.options ?? []).length === 0,
317
+ }));
318
+ }
319
+ export function toUserInputAnswers(items, answers) {
320
+ const out = {};
321
+ for (const item of items)
322
+ out[item.id] = { answers: chosenLabels(item, answers) };
323
+ return out;
324
+ }
325
+ function chosenLabels(item, answers) {
326
+ const answer = answers[item.id];
327
+ if (!answer)
328
+ return [];
329
+ const labels = item.options.filter((option) => answer.selected.includes(option.id)).map((option) => option.label);
330
+ if (answer.other)
331
+ labels.push(answer.other);
332
+ return labels;
333
+ }
334
+ //# sourceMappingURL=translate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"translate.js","sourceRoot":"","sources":["../src/translate.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import type { ToolImage } from '@moxxy/sdk';
2
+ /** The picture at `path` (relative to `cwd`), or `undefined` when it is no picture, missing or too large. */
3
+ export declare function readImageFile(path: string, cwd: string, maxBytes?: number): ToolImage | undefined;
4
+ //# sourceMappingURL=view-image.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"view-image.d.ts","sourceRoot":"","sources":["../src/view-image.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAc5C,6GAA6G;AAC7G,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,QAAQ,SAAkB,GAAG,SAAS,GAAG,SAAS,CAU1G"}
@@ -0,0 +1,47 @@
1
+ import { closeSync, openSync, readSync } from 'node:fs';
2
+ import { extname, isAbsolute, resolve } from 'node:path';
3
+ /** As large as an image the person may attach in the desktop. */
4
+ const MAX_IMAGE_BYTES = 8 * 1024 * 1024;
5
+ const READ_CHUNK_BYTES = 64 * 1024;
6
+ const MEDIA_TYPES = {
7
+ '.png': 'image/png',
8
+ '.jpg': 'image/jpeg',
9
+ '.jpeg': 'image/jpeg',
10
+ '.gif': 'image/gif',
11
+ '.webp': 'image/webp',
12
+ };
13
+ /** The picture at `path` (relative to `cwd`), or `undefined` when it is no picture, missing or too large. */
14
+ export function readImageFile(path, cwd, maxBytes = MAX_IMAGE_BYTES) {
15
+ const mediaType = MEDIA_TYPES[extname(path).toLowerCase()];
16
+ if (!mediaType)
17
+ return undefined;
18
+ const file = isAbsolute(path) ? path : resolve(cwd, path);
19
+ try {
20
+ const bytes = readAtMost(file, maxBytes + 1);
21
+ return bytes.length > maxBytes ? undefined : { mediaType, base64: bytes.toString('base64') };
22
+ }
23
+ catch {
24
+ return undefined;
25
+ }
26
+ }
27
+ /** The cap holds while reading: a size checked first could change before the read. */
28
+ function readAtMost(file, limit) {
29
+ const fd = openSync(file, 'r');
30
+ try {
31
+ const chunks = [];
32
+ let total = 0;
33
+ while (total < limit) {
34
+ const chunk = Buffer.alloc(Math.min(READ_CHUNK_BYTES, limit - total));
35
+ const read = readSync(fd, chunk, 0, chunk.length, null);
36
+ if (read === 0)
37
+ break;
38
+ chunks.push(chunk.subarray(0, read));
39
+ total += read;
40
+ }
41
+ return Buffer.concat(chunks, total);
42
+ }
43
+ finally {
44
+ closeSync(fd);
45
+ }
46
+ }
47
+ //# sourceMappingURL=view-image.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"view-image.js","sourceRoot":"","sources":["../src/view-image.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AACxD,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAGzD,iEAAiE;AACjE,MAAM,eAAe,GAAG,CAAC,GAAG,IAAI,GAAG,IAAI,CAAC;AACxC,MAAM,gBAAgB,GAAG,EAAE,GAAG,IAAI,CAAC;AAEnC,MAAM,WAAW,GAAqC;IACpD,MAAM,EAAE,WAAW;IACnB,MAAM,EAAE,YAAY;IACpB,OAAO,EAAE,YAAY;IACrB,MAAM,EAAE,WAAW;IACnB,OAAO,EAAE,YAAY;CACtB,CAAC;AAEF,6GAA6G;AAC7G,MAAM,UAAU,aAAa,CAAC,IAAY,EAAE,GAAW,EAAE,QAAQ,GAAG,eAAe;IACjF,MAAM,SAAS,GAAG,WAAW,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC;IAC3D,IAAI,CAAC,SAAS;QAAE,OAAO,SAAS,CAAC;IACjC,MAAM,IAAI,GAAG,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;IAC1D,IAAI,CAAC;QACH,MAAM,KAAK,GAAG,UAAU,CAAC,IAAI,EAAE,QAAQ,GAAG,CAAC,CAAC,CAAC;QAC7C,OAAO,KAAK,CAAC,MAAM,GAAG,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,MAAM,EAAE,KAAK,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC;IAC/F,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAC;IACnB,CAAC;AACH,CAAC;AAED,sFAAsF;AACtF,SAAS,UAAU,CAAC,IAAY,EAAE,KAAa;IAC7C,MAAM,EAAE,GAAG,QAAQ,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;IAC/B,IAAI,CAAC;QACH,MAAM,MAAM,GAAa,EAAE,CAAC;QAC5B,IAAI,KAAK,GAAG,CAAC,CAAC;QACd,OAAO,KAAK,GAAG,KAAK,EAAE,CAAC;YACrB,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,gBAAgB,EAAE,KAAK,GAAG,KAAK,CAAC,CAAC,CAAC;YACtE,MAAM,IAAI,GAAG,QAAQ,CAAC,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,KAAK,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;YACxD,IAAI,IAAI,KAAK,CAAC;gBAAE,MAAM;YACtB,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC;YACrC,KAAK,IAAI,IAAI,CAAC;QAChB,CAAC;QACD,OAAO,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;IACtC,CAAC;YAAS,CAAC;QACT,SAAS,CAAC,EAAE,CAAC,CAAC;IAChB,CAAC;AACH,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,85 @@
1
1
  {
2
2
  "name": "@moxxy/plugin-provider-codex-agent",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
3
+ "version": "0.46.0",
4
+ "description": "Codex agent connection for moxxy: OpenAI Codex itself does the work through `codex app-server`, on the person's ChatGPT sign-in, while Moxxy shows it, asks for approvals and questions, and lends its own tools over MCP.",
5
+ "keywords": [
6
+ "moxxy",
7
+ "agent",
8
+ "provider",
9
+ "openai",
10
+ "codex",
11
+ "chatgpt",
12
+ "llm"
13
+ ],
14
+ "homepage": "https://moxxy.ai",
15
+ "bugs": {
16
+ "url": "https://github.com/moxxy-ai/moxxy/issues"
17
+ },
18
+ "repository": {
19
+ "type": "git",
20
+ "url": "git+https://github.com/moxxy-ai/moxxy.git",
21
+ "directory": "packages/plugin-provider-codex-agent"
22
+ },
23
+ "author": "Michal Makowski <michal.makowski97@gmail.com>",
24
+ "license": "MIT",
25
+ "publishConfig": {
26
+ "access": "public"
27
+ },
28
+ "type": "module",
29
+ "main": "./dist/index.js",
30
+ "types": "./dist/index.d.ts",
31
+ "exports": {
32
+ ".": {
33
+ "types": "./dist/index.d.ts",
34
+ "import": "./dist/index.js"
35
+ }
36
+ },
37
+ "files": [
38
+ "dist",
39
+ "src"
40
+ ],
41
+ "moxxy": {
42
+ "plugin": {
43
+ "entry": "./dist/index.js",
44
+ "kind": "provider"
45
+ },
46
+ "catalog": {
47
+ "label": "ChatGPT — Codex agent",
48
+ "description": "Codex does the work on your ChatGPT sign-in; Moxxy shows it and lends its browser and tools.",
49
+ "provides": [
50
+ {
51
+ "category": "provider",
52
+ "name": "codex-agent"
53
+ }
54
+ ],
55
+ "provider": {
56
+ "auth": "oauth",
57
+ "defaultModel": "gpt-6-astra"
58
+ }
59
+ }
60
+ },
61
+ "dependencies": {
62
+ "@moxxy/agent-connection-kit": "0.1.1",
63
+ "@moxxy/sdk": "0.46.0"
64
+ },
65
+ "devDependencies": {
66
+ "@modelcontextprotocol/sdk": "^1.31.0",
67
+ "@types/node": "^22.20.5",
68
+ "typescript": "^6.0.3",
69
+ "vitest": "^5.0.3",
70
+ "zod": "^4.6.6",
71
+ "@moxxy/mode-default": "0.46.0",
72
+ "@moxxy/core": "0.46.0",
73
+ "@moxxy/mode-goal": "0.46.0",
74
+ "@moxxy/mode-plan": "0.46.0",
75
+ "@moxxy/testing": "0.0.76",
76
+ "@moxxy/tsconfig": "0.0.0",
77
+ "@moxxy/vitest-preset": "0.0.0"
78
+ },
79
+ "scripts": {
80
+ "build": "tsc -p tsconfig.json",
81
+ "typecheck": "tsc -p tsconfig.json --noEmit",
82
+ "test": "vitest run",
83
+ "clean": "rm -rf dist .turbo"
84
+ }
6
85
  }
@@ -0,0 +1,25 @@
1
+ import { ACCOUNT_LIMIT_NEAR_PERCENT, type AgentAccountLimit } from '@moxxy/sdk';
2
+ import type { CodexRateLimitSnapshot, CodexRateLimitWindow } from './protocol.js';
3
+
4
+ /**
5
+ * Codex's rate limits as Moxxy's account limit, from the most used of its windows; undefined when
6
+ * the update leaves the windows out (they stay as they were). Codex does not say when a window is
7
+ * near, so it is near from the share Claude warns at.
8
+ */
9
+ export function accountLimitFrom(snapshot: CodexRateLimitSnapshot): AgentAccountLimit | undefined {
10
+ const windows = [snapshot.primary, snapshot.secondary].filter((w): w is CodexRateLimitWindow => w !== null && w !== undefined);
11
+ const top = windows.reduce<CodexRateLimitWindow | undefined>((most, w) => (!most || w.usedPercent > most.usedPercent ? w : most), undefined);
12
+ if (!top) return undefined;
13
+ const reached = (snapshot.rateLimitReachedType !== null && snapshot.rateLimitReachedType !== undefined) || top.usedPercent >= 100;
14
+ return {
15
+ state: reached ? 'reached' : top.usedPercent >= ACCOUNT_LIMIT_NEAR_PERCENT ? 'near' : 'ok',
16
+ usedPercent: top.usedPercent,
17
+ ...(top.windowDurationMins !== null ? { windowMinutes: top.windowDurationMins } : {}),
18
+ ...(top.resetsAt !== null ? { resetsAt: top.resetsAt * 1000 } : {}),
19
+ };
20
+ }
21
+
22
+ /** Whether Codex failed a turn because the account's usage limit is used up. */
23
+ export function failedOnUsageLimit(errorInfo: unknown): boolean {
24
+ return errorInfo === 'usageLimitExceeded';
25
+ }
@@ -0,0 +1,76 @@
1
+ /**
2
+ * The connection's CLI: found where the vendor's installer puts it even when
3
+ * this process's PATH does not reach there, and checked for updates. The CLI
4
+ * is a real executable in a temporary home; the registry's answer is a fresh
5
+ * entry in Moxxy's cache, so nothing goes to the network.
6
+ */
7
+ import { chmodSync, mkdirSync, mkdtempSync, writeFileSync } from 'node:fs';
8
+ import { tmpdir } from 'node:os';
9
+ import path from 'node:path';
10
+ import { afterEach, describe, expect, it } from 'vitest';
11
+ import { assertDefined } from '@moxxy/sdk';
12
+ import { removeDirSync } from '@moxxy/vitest-preset/fs';
13
+ import { codexAgentProviderDef } from './index.js';
14
+ import { codexTarget } from './executable.js';
15
+
16
+ const saved = { HOME: process.env.HOME, PATH: process.env.PATH, MOXXY_HOME: process.env.MOXXY_HOME, CODEX_EXECUTABLE: process.env.CODEX_EXECUTABLE };
17
+ let home: string | undefined;
18
+
19
+ afterEach(() => {
20
+ for (const [key, value] of Object.entries(saved)) {
21
+ if (value === undefined) delete process.env[key];
22
+ else process.env[key] = value;
23
+ }
24
+ if (home) removeDirSync(home);
25
+ home = undefined;
26
+ });
27
+
28
+ function installed(printed: string, script = ''): string {
29
+ home = mkdtempSync(path.join(tmpdir(), 'moxxy-codex-cli-'));
30
+ const file = path.join(home, '.local/bin', 'codex');
31
+ mkdirSync(path.dirname(file), { recursive: true });
32
+ writeFileSync(file, `#!/bin/sh\n${script}\nprintf '%s\\n' ${JSON.stringify(printed)}\n`);
33
+ chmodSync(file, 0o755);
34
+ process.env.HOME = home;
35
+ process.env.PATH = '';
36
+ delete process.env.CODEX_EXECUTABLE;
37
+ return file;
38
+ }
39
+
40
+ describe.skipIf(process.platform === 'win32')('the codex CLI', () => {
41
+ it("is found where the vendor's installer put it, off PATH", () => {
42
+ const file = installed('codex-cli 0.150.0');
43
+
44
+ expect(JSON.stringify(codexTarget('codex'))).toContain(JSON.stringify(file).slice(1, -1));
45
+ });
46
+
47
+ it('is checked for updates against the version the registry last gave', async () => {
48
+ installed('codex-cli 0.150.0');
49
+ const moxxyHome = path.join(home ?? '', 'moxxy');
50
+ mkdirSync(path.join(moxxyHome, 'cache'), { recursive: true });
51
+ writeFileSync(
52
+ path.join(moxxyHome, 'cache', 'agent-cli-latest.json'),
53
+ JSON.stringify({ '@openai/codex': { version: '0.162.1', at: Date.now() } }),
54
+ );
55
+ process.env.MOXXY_HOME = moxxyHome;
56
+ const cli = codexAgentProviderDef.agentCli;
57
+ assertDefined(cli, 'the provider checks its CLI');
58
+
59
+ const report = await cli.check();
60
+
61
+ expect(report).toMatchObject({ installed: '0.150.0', latest: '0.162.1' });
62
+ expect(['update-required', 'update-available']).toContain(report.state);
63
+ });
64
+
65
+ it('says who the agent is signed in as', async () => {
66
+ installed('codex-cli 0.162.1', 'if [ "$1" = "login" ]; then echo "Logged in using ChatGPT"; exit 0; fi');
67
+ const moxxyHome = path.join(home ?? '', 'moxxy');
68
+ mkdirSync(path.join(moxxyHome, 'cache'), { recursive: true });
69
+ writeFileSync(path.join(moxxyHome, 'cache', 'agent-cli-latest.json'), JSON.stringify({ '@openai/codex': { version: '0.162.1', at: Date.now() } }));
70
+ process.env.MOXXY_HOME = moxxyHome;
71
+ const cli = codexAgentProviderDef.agentCli;
72
+ assertDefined(cli, 'the provider checks its CLI');
73
+
74
+ expect(await cli.check()).toMatchObject({ signedIn: true, account: 'ChatGPT' });
75
+ });
76
+ });