agent-dealer 0.1.13 → 0.3.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.
- package/bundle/server/dist/adapters/agent-health.js +28 -1
- package/bundle/server/dist/cli-env.js +16 -0
- package/bundle/server/dist/cli-env.test.js +14 -1
- package/bundle/server/dist/db/index.js +2 -1
- package/bundle/server/dist/queue/result-qa.js +1 -1
- package/bundle/server/dist/runners/claude.js +6 -87
- package/bundle/server/dist/runners/codex-args.js +59 -0
- package/bundle/server/dist/runners/codex-args.test.js +72 -0
- package/bundle/server/dist/runners/codex-jsonl.js +150 -0
- package/bundle/server/dist/runners/codex-jsonl.test.js +36 -0
- package/bundle/server/dist/runners/codex-resume.test.js +19 -0
- package/bundle/server/dist/runners/codex.js +46 -0
- package/bundle/server/dist/runners/models-codex.test.js +14 -0
- package/bundle/server/dist/runners/models.js +53 -1
- package/bundle/server/dist/runners/persist.js +4 -1
- package/bundle/server/dist/runners/qa.js +17 -1
- package/bundle/server/dist/runners/spawn-cli.js +90 -0
- package/bundle/server/package.json +2 -2
- package/bundle/server/static-ui/assets/index-DTcianAH.js +79 -0
- package/bundle/server/static-ui/index.html +1 -1
- package/bundle/shared/dist/agents.d.ts +18 -17
- package/bundle/shared/dist/agents.js +1 -0
- package/bundle/shared/dist/index.d.ts +83 -83
- package/bundle/shared/dist/runtime.d.ts +1 -1
- package/bundle/shared/dist/runtime.js +1 -1
- package/bundle/shared/package.json +1 -1
- package/dist/doctor.js +18 -0
- package/dist/index.js +14 -2
- package/dist/install.d.ts +8 -0
- package/dist/install.js +72 -0
- package/dist/managed/activate.d.ts +2 -0
- package/dist/managed/activate.js +49 -0
- package/dist/managed/activate.test.d.ts +1 -0
- package/dist/managed/activate.test.js +34 -0
- package/dist/managed/index.d.ts +8 -0
- package/dist/managed/index.js +8 -0
- package/dist/managed/install-kind.d.ts +5 -0
- package/dist/managed/install-kind.js +16 -0
- package/dist/managed/launcher.d.ts +1 -0
- package/dist/managed/launcher.js +19 -0
- package/dist/managed/npm-prefix-install.d.ts +16 -0
- package/dist/managed/npm-prefix-install.js +38 -0
- package/dist/managed/paths.d.ts +11 -0
- package/dist/managed/paths.js +45 -0
- package/dist/managed/semver.d.ts +2 -0
- package/dist/managed/semver.js +12 -0
- package/dist/managed/update-state.d.ts +7 -0
- package/dist/managed/update-state.js +22 -0
- package/dist/managed/updater.d.ts +21 -0
- package/dist/managed/updater.js +107 -0
- package/dist/update-check.d.ts +1 -0
- package/dist/update-check.js +25 -37
- package/dist/upgrade.d.ts +1 -0
- package/dist/upgrade.js +55 -6
- package/package.json +1 -1
- package/bundle/server/static-ui/assets/index-B_7S7xJb.js +0 -79
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import { spawnSync } from "node:child_process";
|
|
2
|
+
import fs from "node:fs";
|
|
3
|
+
import os from "node:os";
|
|
4
|
+
import path from "node:path";
|
|
2
5
|
import { CURSOR_DEFAULT_MODEL, CURSOR_SUBSCRIPTION_MODEL_IDS } from "@agent-dealer/shared";
|
|
3
|
-
import { cursorInvokeArgs, resolveCursorBin } from "../cli-env.js";
|
|
6
|
+
import { cursorInvokeArgs, resolveCursorBin, resolveCodexBin } from "../cli-env.js";
|
|
4
7
|
const CURSOR_PINNED = [
|
|
5
8
|
{ id: CURSOR_DEFAULT_MODEL, label: "Auto (subscription pool)" },
|
|
6
9
|
{ id: "composer-2.5", label: "Composer 2.5 (subscription pool)" },
|
|
@@ -15,6 +18,11 @@ const CLAUDE_FALLBACK = [
|
|
|
15
18
|
{ id: "claude-opus-4-6", label: "Claude Opus 4.6" },
|
|
16
19
|
{ id: "claude-haiku-4-5", label: "Claude Haiku 4.5" },
|
|
17
20
|
];
|
|
21
|
+
const CODEX_FALLBACK = [
|
|
22
|
+
{ id: "gpt-5.6-sol", label: "GPT-5.6 Sol" },
|
|
23
|
+
{ id: "gpt-5.6-terra", label: "GPT-5.6 Terra" },
|
|
24
|
+
{ id: "gpt-5.6-luna", label: "GPT-5.6 Luna" },
|
|
25
|
+
];
|
|
18
26
|
/** Live CLI/API lists change rarely — default 14d; bust with server restart or GET ?refresh=1. */
|
|
19
27
|
const LIVE_CACHE_MS = Number(process.env.RUNTIME_MODELS_CACHE_MS ?? 14 * 24 * 60 * 60 * 1000);
|
|
20
28
|
/** Failed/empty fetch — retry sooner; successful lists use LIVE_CACHE_MS. */
|
|
@@ -90,10 +98,54 @@ function listCursorModels() {
|
|
|
90
98
|
}
|
|
91
99
|
return { models: CURSOR_FALLBACK, source: "fallback" };
|
|
92
100
|
}
|
|
101
|
+
function listCodexModelsFromCache() {
|
|
102
|
+
const home = process.env.HOME ?? os.homedir();
|
|
103
|
+
const cachePath = path.join(home, ".codex", "models_cache.json");
|
|
104
|
+
if (!fs.existsSync(cachePath))
|
|
105
|
+
return [];
|
|
106
|
+
try {
|
|
107
|
+
const raw = JSON.parse(fs.readFileSync(cachePath, "utf8"));
|
|
108
|
+
return parseCodexModelsCache(raw);
|
|
109
|
+
}
|
|
110
|
+
catch {
|
|
111
|
+
return [];
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
/** Picker-visible Codex models only (`visibility === "list"`). Exported for unit tests. */
|
|
115
|
+
export function parseCodexModelsCache(raw) {
|
|
116
|
+
if (!raw || typeof raw !== "object")
|
|
117
|
+
return [];
|
|
118
|
+
const modelsIn = raw.models;
|
|
119
|
+
if (!Array.isArray(modelsIn))
|
|
120
|
+
return [];
|
|
121
|
+
const models = [];
|
|
122
|
+
for (const entry of modelsIn) {
|
|
123
|
+
if (!entry || typeof entry !== "object")
|
|
124
|
+
continue;
|
|
125
|
+
const m = entry;
|
|
126
|
+
if (m.visibility !== "list")
|
|
127
|
+
continue;
|
|
128
|
+
const id = m.id ?? m.slug;
|
|
129
|
+
if (!id)
|
|
130
|
+
continue;
|
|
131
|
+
models.push({ id, label: m.display_name ?? m.label ?? id });
|
|
132
|
+
}
|
|
133
|
+
return models;
|
|
134
|
+
}
|
|
135
|
+
function listCodexModels() {
|
|
136
|
+
void resolveCodexBin();
|
|
137
|
+
const live = listCodexModelsFromCache();
|
|
138
|
+
if (live.length > 0)
|
|
139
|
+
return { models: live, source: "live" };
|
|
140
|
+
return { models: CODEX_FALLBACK, source: "fallback" };
|
|
141
|
+
}
|
|
93
142
|
async function fetchRuntimeModelsFresh(runtime) {
|
|
94
143
|
if (runtime === "cursor_local") {
|
|
95
144
|
return listCursorModels();
|
|
96
145
|
}
|
|
146
|
+
if (runtime === "codex_local") {
|
|
147
|
+
return listCodexModels();
|
|
148
|
+
}
|
|
97
149
|
const fromApi = await tryAnthropicModelsApi();
|
|
98
150
|
if (fromApi.length > 0) {
|
|
99
151
|
const aliasIds = new Set(CLAUDE_FALLBACK.map((m) => m.id));
|
|
@@ -4,6 +4,7 @@ import { detectExecutionBlocker, outboundDraftKind } from "@agent-dealer/shared"
|
|
|
4
4
|
import { addArtifact, appendEvent, getLatestArtifact, getLineageParentRun, resolveBudgetForPhase } from "../repository/runs.js";
|
|
5
5
|
import { getTemporalOutputDir } from "../paths.js";
|
|
6
6
|
import { buildStreamTrace, extractOutboundDraft, extractPlanMarkdown, extractPlanTriage, extractResultIsError, extractResultText, extractSessionId, extractUsage, parseNdjson, } from "./stream-json.js";
|
|
7
|
+
import { normalizeCodexEvents, parseCodexJsonl } from "./codex-jsonl.js";
|
|
7
8
|
import { humanFeedbackText } from "./run-context.js";
|
|
8
9
|
export function seedDeliverableFromParent(run) {
|
|
9
10
|
const parent = getLineageParentRun(run);
|
|
@@ -42,7 +43,9 @@ function expectedDocPath(run) {
|
|
|
42
43
|
export function persistRunOutput(input) {
|
|
43
44
|
const { run, phase, runtime, exitCode, logPath } = input;
|
|
44
45
|
const raw = input.rawTranscript ?? (fs.existsSync(logPath) ? fs.readFileSync(logPath, "utf8") : "");
|
|
45
|
-
const events =
|
|
46
|
+
const events = runtime === "codex_local"
|
|
47
|
+
? normalizeCodexEvents(parseCodexJsonl(raw))
|
|
48
|
+
: parseNdjson(raw);
|
|
46
49
|
const sessionId = extractSessionId(events);
|
|
47
50
|
let resultText = extractResultText(events);
|
|
48
51
|
const outboundExtract = phase === "execute" ? extractOutboundDraft(resultText ?? "") : null;
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { runClaude, runCursor } from "./claude.js";
|
|
2
|
+
import { runCodex } from "./codex.js";
|
|
2
3
|
import { buildQaPrompt } from "./prompts.js";
|
|
3
4
|
import { extractResultIsError, extractResultText, extractUsage, parseNdjson } from "./stream-json.js";
|
|
5
|
+
import { normalizeCodexEvents, parseCodexJsonl } from "./codex-jsonl.js";
|
|
4
6
|
/** One read-only Q&A turn against a finished run. Resumes the execute session when we still have it. */
|
|
5
7
|
export async function runQa(run, question, resumeSessionId) {
|
|
6
8
|
let result;
|
|
@@ -19,13 +21,27 @@ export async function runQa(run, question, resumeSessionId) {
|
|
|
19
21
|
});
|
|
20
22
|
}
|
|
21
23
|
}
|
|
24
|
+
else if (runtime === "codex_local") {
|
|
25
|
+
const prompt = buildQaPrompt(run, question, { grounded: Boolean(resumeSessionId) });
|
|
26
|
+
result = await runCodex(run, "qa", executeModel ?? undefined, {
|
|
27
|
+
promptOverride: prompt,
|
|
28
|
+
...(resumeSessionId ? { resumeSessionId } : {}),
|
|
29
|
+
});
|
|
30
|
+
if (result.exitCode !== 0 && resumeSessionId) {
|
|
31
|
+
result = await runCodex(run, "qa", executeModel ?? undefined, {
|
|
32
|
+
promptOverride: buildQaPrompt(run, question, { grounded: false }),
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
}
|
|
22
36
|
else {
|
|
23
37
|
result = await runClaude(run, "qa", executeModel, {
|
|
24
38
|
promptOverride: buildQaPrompt(run, question, { grounded: Boolean(resumeSessionId) }),
|
|
25
39
|
...(resumeSessionId ? { resumeSessionId } : {}),
|
|
26
40
|
});
|
|
27
41
|
}
|
|
28
|
-
const events =
|
|
42
|
+
const events = runtime === "codex_local"
|
|
43
|
+
? normalizeCodexEvents(parseCodexJsonl(result.transcript))
|
|
44
|
+
: parseNdjson(result.transcript);
|
|
29
45
|
const usage = extractUsage(events, "qa", runtime);
|
|
30
46
|
const answer = extractResultText(events)?.trim() ?? "";
|
|
31
47
|
const failed = result.exitCode !== 0 || extractResultIsError(events) || !answer;
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { spawn } from "node:child_process";
|
|
2
|
+
import fs from "node:fs";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { getTemporalLogsDir } from "../paths.js";
|
|
5
|
+
import { acquireSpawnSlot, killRunProcess, registerChild, releaseSpawnSlot, unregisterChild, } from "./process-registry.js";
|
|
6
|
+
export { getActiveLogPath, killRunProcess } from "./process-registry.js";
|
|
7
|
+
export function timeoutMsForMode(mode) {
|
|
8
|
+
const envKey = mode === "plan"
|
|
9
|
+
? "PLAN_TIMEOUT_MS"
|
|
10
|
+
: mode === "execute"
|
|
11
|
+
? "EXECUTE_TIMEOUT_MS"
|
|
12
|
+
: mode === "reflect"
|
|
13
|
+
? "REFLECT_TIMEOUT_MS"
|
|
14
|
+
: "QA_TIMEOUT_MS";
|
|
15
|
+
const defaults = {
|
|
16
|
+
plan: 15 * 60_000,
|
|
17
|
+
execute: 60 * 60_000,
|
|
18
|
+
reflect: 10 * 60_000,
|
|
19
|
+
qa: 5 * 60_000,
|
|
20
|
+
};
|
|
21
|
+
const raw = process.env[envKey];
|
|
22
|
+
if (raw !== undefined && raw !== "")
|
|
23
|
+
return Number(raw);
|
|
24
|
+
return defaults[mode];
|
|
25
|
+
}
|
|
26
|
+
export async function spawnCli(runId, cmd, args, cwd, opts) {
|
|
27
|
+
await acquireSpawnSlot();
|
|
28
|
+
try {
|
|
29
|
+
return await new Promise((resolve, reject) => {
|
|
30
|
+
const stdoutChunks = [];
|
|
31
|
+
const stderrChunks = [];
|
|
32
|
+
let timedOut = false;
|
|
33
|
+
let settled = false;
|
|
34
|
+
const logStream = fs.createWriteStream(opts.logPath, { flags: "w" });
|
|
35
|
+
const child = spawn(cmd, args, {
|
|
36
|
+
cwd,
|
|
37
|
+
env: { ...process.env },
|
|
38
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
39
|
+
});
|
|
40
|
+
registerChild(runId, child, opts.logPath);
|
|
41
|
+
const finish = (exitCode) => {
|
|
42
|
+
if (settled)
|
|
43
|
+
return;
|
|
44
|
+
settled = true;
|
|
45
|
+
clearTimeout(timer);
|
|
46
|
+
unregisterChild(runId);
|
|
47
|
+
logStream.end();
|
|
48
|
+
const stderr = stderrChunks.join("");
|
|
49
|
+
if (stderr.trim()) {
|
|
50
|
+
logStream.write(`\n--- stderr ---\n${stderr}`);
|
|
51
|
+
}
|
|
52
|
+
resolve({
|
|
53
|
+
exitCode,
|
|
54
|
+
transcript: stdoutChunks.join(""),
|
|
55
|
+
timedOut,
|
|
56
|
+
});
|
|
57
|
+
};
|
|
58
|
+
const timer = setTimeout(() => {
|
|
59
|
+
timedOut = true;
|
|
60
|
+
killRunProcess(runId);
|
|
61
|
+
setTimeout(() => finish(124), 500);
|
|
62
|
+
}, opts.timeoutMs);
|
|
63
|
+
child.stdout?.on("data", (buf) => {
|
|
64
|
+
const chunk = buf.toString();
|
|
65
|
+
stdoutChunks.push(chunk);
|
|
66
|
+
logStream.write(buf);
|
|
67
|
+
});
|
|
68
|
+
child.stderr?.on("data", (buf) => {
|
|
69
|
+
stderrChunks.push(buf.toString());
|
|
70
|
+
});
|
|
71
|
+
child.on("error", (err) => {
|
|
72
|
+
if (settled)
|
|
73
|
+
return;
|
|
74
|
+
settled = true;
|
|
75
|
+
clearTimeout(timer);
|
|
76
|
+
unregisterChild(runId);
|
|
77
|
+
logStream.end();
|
|
78
|
+
reject(err);
|
|
79
|
+
});
|
|
80
|
+
child.on("close", (code) => finish(code ?? 1));
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
finally {
|
|
84
|
+
releaseSpawnSlot();
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
export function logPathFor(run, mode) {
|
|
88
|
+
const logDir = getTemporalLogsDir();
|
|
89
|
+
return path.join(logDir, `${run.id}-${mode}-${Date.now()}.ndjson`);
|
|
90
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agent-dealer/server",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"files": [
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
"typecheck": "tsc --noEmit"
|
|
22
22
|
},
|
|
23
23
|
"dependencies": {
|
|
24
|
-
"@agent-dealer/shared": "
|
|
24
|
+
"@agent-dealer/shared": "0.3.0",
|
|
25
25
|
"@fastify/cors": "^11.0.1",
|
|
26
26
|
"@fastify/static": "^8.2.0",
|
|
27
27
|
"@modelcontextprotocol/sdk": "^1.29.0",
|