@q-agent/agent 0.1.19 → 0.1.21
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/dist/src/runner.js +73 -26
- package/package.json +1 -1
- package/vendor/authoring_browser.cjs +1 -1
package/dist/src/runner.js
CHANGED
|
@@ -957,13 +957,14 @@ async function processAuthoringJob(cfg, job) {
|
|
|
957
957
|
}
|
|
958
958
|
const sess = origin ? (0, session_1.sessionPathsForOrigin)(origin) : null;
|
|
959
959
|
const profileDir = sess ? path.join(sess.dir, "browser-profile") : "";
|
|
960
|
-
const finalize = async (code, discovered, summary, ok) => {
|
|
960
|
+
const finalize = async (code, discovered, summary, ok, costUsd = 0) => {
|
|
961
961
|
await api
|
|
962
962
|
.postAuthoringFinalize(cfg, job.sessionId, {
|
|
963
963
|
code,
|
|
964
964
|
discovered: discovered || {},
|
|
965
965
|
summary,
|
|
966
966
|
ok,
|
|
967
|
+
costUsd,
|
|
967
968
|
})
|
|
968
969
|
.catch((err) => console.error("postAuthoringFinalize failed:", err));
|
|
969
970
|
};
|
|
@@ -988,7 +989,7 @@ async function processAuthoringJob(cfg, job) {
|
|
|
988
989
|
// (emitted AFTER the replay is armed) so browser-harness never navigates
|
|
989
990
|
// before the session is restored.
|
|
990
991
|
const nm = (0, paths_1.agentNodeModules)();
|
|
991
|
-
launcher = (0, child_process_1.spawn)((0, paths_1.nodeBin)(), [(0, paths_1.vendorAuthoringScript)(), job.baseUrl, String(port), profileDir, sess ? sess.sessionStoragePath : ""], { env: nodePathEnv(nm), stdio: ["pipe", "pipe", "pipe"] });
|
|
992
|
+
launcher = (0, child_process_1.spawn)((0, paths_1.nodeBin)(), [(0, paths_1.vendorAuthoringScript)(), job.baseUrl, String(port), profileDir, sess ? sess.sessionStoragePath : ""], { env: nodePathEnv(nm), stdio: ["pipe", "pipe", "pipe"], windowsHide: true });
|
|
992
993
|
activeChild = launcher;
|
|
993
994
|
let launcherErr = "";
|
|
994
995
|
launcher.stderr?.on("data", (d) => { launcherErr += String(d); });
|
|
@@ -1041,9 +1042,12 @@ async function processAuthoringJob(cfg, job) {
|
|
|
1041
1042
|
}
|
|
1042
1043
|
catch { /* best-effort on Windows */ }
|
|
1043
1044
|
}
|
|
1045
|
+
// Prompt goes as the -p ARGUMENT (not stdin — headless `claude -p` reads the
|
|
1046
|
+
// prompt from argv). stream-json + verbose lets us surface every step live.
|
|
1044
1047
|
const claudeArgs = [
|
|
1045
|
-
"-p",
|
|
1046
|
-
"--output-format", "json",
|
|
1048
|
+
"-p", job.taskPrompt,
|
|
1049
|
+
"--output-format", "stream-json",
|
|
1050
|
+
"--verbose",
|
|
1047
1051
|
"--model", job.model,
|
|
1048
1052
|
"--append-system-prompt-file", systemFile,
|
|
1049
1053
|
"--allowedTools", "Bash", "Read", "Write", "Glob", "Grep",
|
|
@@ -1065,21 +1069,64 @@ async function processAuthoringJob(cfg, job) {
|
|
|
1065
1069
|
claude = (0, child_process_1.spawn)((0, paths_1.claudeCli)(), claudeArgs, {
|
|
1066
1070
|
cwd: workDir,
|
|
1067
1071
|
env: claudeEnv,
|
|
1068
|
-
stdio: ["
|
|
1072
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
1073
|
+
windowsHide: true,
|
|
1069
1074
|
});
|
|
1070
1075
|
activeChild = claude;
|
|
1071
|
-
|
|
1076
|
+
// Surface each step to the agent console + the run WebSocket so the operator
|
|
1077
|
+
// can watch Claude drive browser-harness live.
|
|
1078
|
+
const emitStep = (line) => {
|
|
1079
|
+
const trimmed = line.length > 300 ? line.slice(0, 300) + "…" : line;
|
|
1080
|
+
console.log(`[authoring ${job.caseId}] ${trimmed}`);
|
|
1081
|
+
(0, bus_1.emit)("authoring-step", { caseId: job.caseId, line: trimmed });
|
|
1082
|
+
void api
|
|
1083
|
+
.postAuthoringEvent(cfg, job.sessionId, "authoring.progress", {
|
|
1084
|
+
case: job.caseId, phase: "step", message: trimmed,
|
|
1085
|
+
})
|
|
1086
|
+
.catch(() => { });
|
|
1087
|
+
};
|
|
1072
1088
|
let cerr = "";
|
|
1073
|
-
|
|
1089
|
+
let finalResult = "";
|
|
1090
|
+
let costUsd = 0;
|
|
1091
|
+
let buf = "";
|
|
1092
|
+
const handleEvent = (ev) => {
|
|
1093
|
+
if (ev.type === "assistant" && ev.message?.content) {
|
|
1094
|
+
for (const c of ev.message.content) {
|
|
1095
|
+
if (c.type === "text" && typeof c.text === "string" && c.text.trim()) {
|
|
1096
|
+
emitStep(`Claude: ${c.text.trim()}`);
|
|
1097
|
+
}
|
|
1098
|
+
else if (c.type === "tool_use") {
|
|
1099
|
+
const inp = c.input || {};
|
|
1100
|
+
const detail = inp.command ?? inp.file_path ?? inp.path ?? inp.pattern ?? JSON.stringify(inp).slice(0, 200);
|
|
1101
|
+
emitStep(`▷ ${String(c.name)}: ${String(detail).replace(/\s+/g, " ").trim()}`);
|
|
1102
|
+
}
|
|
1103
|
+
}
|
|
1104
|
+
}
|
|
1105
|
+
else if (ev.type === "result") {
|
|
1106
|
+
if (typeof ev.result === "string")
|
|
1107
|
+
finalResult = ev.result;
|
|
1108
|
+
if (typeof ev.total_cost_usd === "number")
|
|
1109
|
+
costUsd = ev.total_cost_usd;
|
|
1110
|
+
}
|
|
1111
|
+
};
|
|
1112
|
+
claude.stdout?.on("data", (d) => {
|
|
1113
|
+
buf += String(d);
|
|
1114
|
+
let nl;
|
|
1115
|
+
while ((nl = buf.indexOf("\n")) >= 0) {
|
|
1116
|
+
const line = buf.slice(0, nl).trim();
|
|
1117
|
+
buf = buf.slice(nl + 1);
|
|
1118
|
+
if (!line)
|
|
1119
|
+
continue;
|
|
1120
|
+
try {
|
|
1121
|
+
handleEvent(JSON.parse(line));
|
|
1122
|
+
}
|
|
1123
|
+
catch { /* ignore non-JSON noise */ }
|
|
1124
|
+
}
|
|
1125
|
+
});
|
|
1074
1126
|
claude.stderr?.on("data", (d) => { cerr += String(d); });
|
|
1075
|
-
|
|
1076
|
-
claude.
|
|
1077
|
-
claude.
|
|
1078
|
-
}
|
|
1079
|
-
catch { }
|
|
1080
|
-
await new Promise((resolve) => {
|
|
1081
|
-
claude.on("close", () => resolve());
|
|
1082
|
-
claude.on("error", (e) => { cerr += `\nclaude spawn error: ${e.message}`; resolve(); });
|
|
1127
|
+
const exitCode = await new Promise((resolve) => {
|
|
1128
|
+
claude.on("close", (c) => resolve(c ?? 0));
|
|
1129
|
+
claude.on("error", (e) => { cerr += `\nclaude spawn error: ${e.message}`; resolve(-1); });
|
|
1083
1130
|
});
|
|
1084
1131
|
// 3) Read emitted artifacts.
|
|
1085
1132
|
const specPath = path.join(workDir, job.specFilename);
|
|
@@ -1092,22 +1139,22 @@ async function processAuthoringJob(cfg, job) {
|
|
|
1092
1139
|
}
|
|
1093
1140
|
catch { /* keep default */ }
|
|
1094
1141
|
}
|
|
1095
|
-
let summary = "";
|
|
1096
|
-
try {
|
|
1097
|
-
summary = JSON.parse(cout).result || "";
|
|
1098
|
-
}
|
|
1099
|
-
catch {
|
|
1100
|
-
summary = (cout || cerr).slice(0, 800);
|
|
1101
|
-
}
|
|
1102
|
-
if (!code.trim() && !summary)
|
|
1103
|
-
summary = "Live authoring produced no spec.";
|
|
1104
1142
|
const ok = code.trim().length > 0;
|
|
1143
|
+
let summary = finalResult || "";
|
|
1144
|
+
if (!ok) {
|
|
1145
|
+
// Make failures diagnosable: include claude's exit + stderr tail.
|
|
1146
|
+
const errTail = cerr.trim().slice(-500);
|
|
1147
|
+
summary = `${summary || "Live authoring produced no spec."} (claude exit ${exitCode})` +
|
|
1148
|
+
(errTail ? `\n[claude stderr] ${errTail}` : "");
|
|
1149
|
+
}
|
|
1150
|
+
emitStep(ok ? `✓ spec authored · $${costUsd.toFixed(2)}` : `✗ no spec (claude exit ${exitCode})`);
|
|
1151
|
+
// Terminal event (carries the run cost) so the UI can close the trail + show $.
|
|
1105
1152
|
await api
|
|
1106
1153
|
.postAuthoringEvent(cfg, job.sessionId, "authoring.progress", {
|
|
1107
|
-
case: job.caseId, phase: ok ? "done" : "failed", message: summary.slice(0,
|
|
1154
|
+
case: job.caseId, phase: ok ? "done" : "failed", message: (summary || "").slice(0, 300), costUsd,
|
|
1108
1155
|
})
|
|
1109
1156
|
.catch(() => { });
|
|
1110
|
-
await finalize(code, discovered, summary, ok);
|
|
1157
|
+
await finalize(code, discovered, summary, ok, costUsd);
|
|
1111
1158
|
}
|
|
1112
1159
|
finally {
|
|
1113
1160
|
try {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@q-agent/agent",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.21",
|
|
4
4
|
"description": "Q-Agent Local Agent — claims execution jobs from the Q-Agent server and runs Playwright locally, so manual login/MFA happens on the user's own machine and session credentials never leave it.",
|
|
5
5
|
"license": "UNLICENSED",
|
|
6
6
|
"bin": {
|
|
@@ -149,7 +149,7 @@ async function armAuthAndNavigate(chromium, port, byOrigin) {
|
|
|
149
149
|
'--no-first-run', '--no-default-browser-check', '--new-window',
|
|
150
150
|
...containerFlags(),
|
|
151
151
|
launchUrl,
|
|
152
|
-
], { detached: false, stdio: 'ignore' });
|
|
152
|
+
], { detached: false, stdio: 'ignore', windowsHide: true });
|
|
153
153
|
console.error('authoring_browser launched:', exe, 'port', PORT, 'replay:', Boolean(chromium));
|
|
154
154
|
|
|
155
155
|
if (!(await waitForCDP(PORT, 20000))) {
|