@proagentstore/cli 0.4.56 → 0.4.58
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/browser-runner/coding/engine-acts.js +7 -7
- package/dist/browser-runner/coding/engine-adapter.js +186 -0
- package/dist/browser-runner/coding/engine-usage.js +27 -3
- package/dist/browser-runner/coding/github-browse.js +796 -0
- package/dist/browser-runner/coding/handlers.js +1 -1
- package/dist/browser-runner/coding/headless.js +121 -118
- package/dist/browser-runner/coding/inspect.js +188 -13
- package/dist/browser-runner/coding/repo.js +44 -1
- package/dist/browser-runner/coding/runtime.js +20 -3
- package/dist/browser-runner/server.js +103 -0
- package/package.json +1 -1
|
@@ -29,10 +29,10 @@
|
|
|
29
29
|
*
|
|
30
30
|
* ── THE HONEST GAP ──
|
|
31
31
|
*
|
|
32
|
-
* Only
|
|
33
|
-
*
|
|
34
|
-
* empty act list
|
|
35
|
-
* has to say so rather than render it as an all-clear.
|
|
32
|
+
* Only structured engines produce these. Claude Code emits `tool_use`/`tool_result`; Codex
|
|
33
|
+
* `exec --json` emits `command_execution` events that the adapter normalizes to the same shape.
|
|
34
|
+
* A raw engine emits nothing parseable, so an empty act list means "nothing observed", never
|
|
35
|
+
* "nothing happened", and every consumer has to say so rather than render it as an all-clear.
|
|
36
36
|
*/
|
|
37
37
|
/** Acts whose consequences reach outside the machine, or cannot be walked back locally. */
|
|
38
38
|
const IRREVERSIBLE = new Set([
|
|
@@ -183,9 +183,9 @@ function wantsPrNumber(act) {
|
|
|
183
183
|
* true costs more than it saves. The act still carries `ok: false`, so the record remains honest
|
|
184
184
|
* that the command failed.
|
|
185
185
|
*
|
|
186
|
-
* Only reachable from
|
|
187
|
-
*
|
|
188
|
-
*
|
|
186
|
+
* Only reachable from structured adapter events. A raw spawn has no `tool_use`/`tool_result`
|
|
187
|
+
* framing at all, so its PRs stay unattributed — regexing its transcript instead would reintroduce
|
|
188
|
+
* exactly the temporal guess this design refuses.
|
|
189
189
|
*/
|
|
190
190
|
export function fillTargetFromResult(acts, content) {
|
|
191
191
|
if (!acts.some(wantsPrNumber))
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
export function engineInvocationModeFromAdapter(mode) {
|
|
2
|
+
return mode === "stream-json" ? "structured" : "raw";
|
|
3
|
+
}
|
|
4
|
+
export function structuredCapableEngine(clientType) {
|
|
5
|
+
return clientType === "claude" || clientType === "codex";
|
|
6
|
+
}
|
|
7
|
+
export function engineInvocationWarning(clientType, mode) {
|
|
8
|
+
if (mode !== "raw" || clientType !== "claude")
|
|
9
|
+
return null;
|
|
10
|
+
return `running raw — structured not available on this machine's ${clientType} CLI`;
|
|
11
|
+
}
|
|
12
|
+
const RESERVED_CLAUDE_FLAGS = new Set(["-p", "--print", "--input-format", "--output-format", "--verbose", "--resume"]);
|
|
13
|
+
/** Structural flags PAGS owns for Claude's stream-json engine. */
|
|
14
|
+
export function buildClaudeArgs(userArgs, resumeId) {
|
|
15
|
+
const args = ["-p", "--input-format", "stream-json", "--output-format", "stream-json", "--verbose"];
|
|
16
|
+
for (let i = 0; i < userArgs.length; i++) {
|
|
17
|
+
const a = userArgs[i];
|
|
18
|
+
if (RESERVED_CLAUDE_FLAGS.has(a)) {
|
|
19
|
+
if (i + 1 < userArgs.length && !userArgs[i + 1].startsWith("-"))
|
|
20
|
+
i++;
|
|
21
|
+
continue;
|
|
22
|
+
}
|
|
23
|
+
args.push(a);
|
|
24
|
+
}
|
|
25
|
+
if (!args.includes("--dangerously-skip-permissions"))
|
|
26
|
+
args.push("--dangerously-skip-permissions");
|
|
27
|
+
if (resumeId)
|
|
28
|
+
args.push("--resume", resumeId);
|
|
29
|
+
return args;
|
|
30
|
+
}
|
|
31
|
+
function record(v) {
|
|
32
|
+
return v && typeof v === "object" && !Array.isArray(v) ? v : null;
|
|
33
|
+
}
|
|
34
|
+
function contentBlocks(ev) {
|
|
35
|
+
const message = record(ev.message);
|
|
36
|
+
const content = Array.isArray(message?.content) ? message.content : [];
|
|
37
|
+
return content.flatMap((block) => {
|
|
38
|
+
const r = record(block);
|
|
39
|
+
return r ? [r] : [];
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
function parseClaudeLine(line) {
|
|
43
|
+
let ev;
|
|
44
|
+
try {
|
|
45
|
+
const parsed = JSON.parse(line);
|
|
46
|
+
const parsedRecord = record(parsed);
|
|
47
|
+
if (!parsedRecord)
|
|
48
|
+
return [];
|
|
49
|
+
ev = parsedRecord;
|
|
50
|
+
}
|
|
51
|
+
catch {
|
|
52
|
+
return [];
|
|
53
|
+
}
|
|
54
|
+
const type = typeof ev.type === "string" ? ev.type : "";
|
|
55
|
+
switch (type) {
|
|
56
|
+
case "system": {
|
|
57
|
+
if (ev.subtype === "init" && typeof ev.session_id === "string" && ev.session_id)
|
|
58
|
+
return [{ kind: "session", sessionId: ev.session_id }];
|
|
59
|
+
return [];
|
|
60
|
+
}
|
|
61
|
+
case "assistant":
|
|
62
|
+
return contentBlocks(ev).flatMap((block) => {
|
|
63
|
+
if (block.type === "text" && typeof block.text === "string" && block.text.trim())
|
|
64
|
+
return [{ kind: "assistant_text", text: block.text.trim() }];
|
|
65
|
+
if (block.type !== "tool_use")
|
|
66
|
+
return [];
|
|
67
|
+
const name = String(block.name ?? "tool");
|
|
68
|
+
return [
|
|
69
|
+
{
|
|
70
|
+
kind: "tool_use",
|
|
71
|
+
block,
|
|
72
|
+
id: typeof block.id === "string" ? block.id : "",
|
|
73
|
+
name,
|
|
74
|
+
input: block.input,
|
|
75
|
+
},
|
|
76
|
+
];
|
|
77
|
+
});
|
|
78
|
+
case "user":
|
|
79
|
+
return contentBlocks(ev).flatMap((block) => {
|
|
80
|
+
if (block.type !== "tool_result")
|
|
81
|
+
return [];
|
|
82
|
+
return [
|
|
83
|
+
{
|
|
84
|
+
kind: "tool_result",
|
|
85
|
+
block,
|
|
86
|
+
toolUseId: typeof block.tool_use_id === "string" ? block.tool_use_id : "",
|
|
87
|
+
content: block.content,
|
|
88
|
+
},
|
|
89
|
+
];
|
|
90
|
+
});
|
|
91
|
+
case "result": {
|
|
92
|
+
const result = typeof ev.result === "string" ? ev.result : typeof ev.subtype === "string" ? ev.subtype : "failed";
|
|
93
|
+
return [{ kind: "turn_end", raw: ev, isError: ev.is_error === true, result }];
|
|
94
|
+
}
|
|
95
|
+
default:
|
|
96
|
+
return [];
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
export const claudeEngineAdapter = {
|
|
100
|
+
mode: "stream-json",
|
|
101
|
+
persistent: true,
|
|
102
|
+
buildLaunchArgs: buildClaudeArgs,
|
|
103
|
+
buildTurnArgs: (userArgs, turnText) => [...userArgs, turnText],
|
|
104
|
+
parseLine: parseClaudeLine,
|
|
105
|
+
};
|
|
106
|
+
function hasFlag(args, flag) {
|
|
107
|
+
return args.some((a) => a === flag || a.startsWith(`${flag}=`));
|
|
108
|
+
}
|
|
109
|
+
function buildCodexExecArgs(userArgs, turnText) {
|
|
110
|
+
const args = [...userArgs];
|
|
111
|
+
if (!hasFlag(args, "--json"))
|
|
112
|
+
args.splice(1, 0, "--json");
|
|
113
|
+
args.push(turnText);
|
|
114
|
+
return args;
|
|
115
|
+
}
|
|
116
|
+
function parseCodexLine(line) {
|
|
117
|
+
let ev;
|
|
118
|
+
try {
|
|
119
|
+
const parsed = JSON.parse(line);
|
|
120
|
+
const parsedRecord = record(parsed);
|
|
121
|
+
if (!parsedRecord)
|
|
122
|
+
return [];
|
|
123
|
+
ev = parsedRecord;
|
|
124
|
+
}
|
|
125
|
+
catch {
|
|
126
|
+
return [];
|
|
127
|
+
}
|
|
128
|
+
const type = typeof ev.type === "string" ? ev.type : "";
|
|
129
|
+
const item = record(ev.item);
|
|
130
|
+
if (type === "thread.started" && typeof ev.thread_id === "string" && ev.thread_id)
|
|
131
|
+
return [{ kind: "session", sessionId: ev.thread_id }];
|
|
132
|
+
if (type === "turn.completed" || type === "turn.failed") {
|
|
133
|
+
const result = typeof ev.error === "string" ? ev.error : typeof ev.message === "string" ? ev.message : type === "turn.failed" ? "failed" : "";
|
|
134
|
+
return [{ kind: "turn_end", raw: ev, isError: type === "turn.failed", result }];
|
|
135
|
+
}
|
|
136
|
+
if (!item)
|
|
137
|
+
return [];
|
|
138
|
+
const itemType = typeof item.type === "string" ? item.type : "";
|
|
139
|
+
if (type === "item.completed" && itemType === "agent_message" && typeof item.text === "string" && item.text.trim()) {
|
|
140
|
+
return [{ kind: "assistant_text", text: item.text.trim() }];
|
|
141
|
+
}
|
|
142
|
+
if (itemType !== "command_execution")
|
|
143
|
+
return [];
|
|
144
|
+
const id = typeof item.id === "string" ? item.id : "";
|
|
145
|
+
const command = typeof item.command === "string" ? item.command : "";
|
|
146
|
+
const block = type === "item.completed"
|
|
147
|
+
? {
|
|
148
|
+
type: "tool_result",
|
|
149
|
+
tool_use_id: id,
|
|
150
|
+
is_error: item.status === "failed" || (typeof item.exit_code === "number" && item.exit_code !== 0),
|
|
151
|
+
content: typeof item.aggregated_output === "string" ? item.aggregated_output : "",
|
|
152
|
+
}
|
|
153
|
+
: {
|
|
154
|
+
type: "tool_use",
|
|
155
|
+
id,
|
|
156
|
+
name: "Bash",
|
|
157
|
+
input: { command },
|
|
158
|
+
};
|
|
159
|
+
if (type === "item.completed") {
|
|
160
|
+
return [{ kind: "tool_result", block, toolUseId: id, content: block.content }];
|
|
161
|
+
}
|
|
162
|
+
if (type === "item.started" && command)
|
|
163
|
+
return [{ kind: "tool_use", block, id, name: "Bash", input: { command } }];
|
|
164
|
+
return [];
|
|
165
|
+
}
|
|
166
|
+
export const codexEngineAdapter = {
|
|
167
|
+
mode: "stream-json",
|
|
168
|
+
persistent: false,
|
|
169
|
+
buildLaunchArgs: (userArgs) => [...userArgs],
|
|
170
|
+
buildTurnArgs: buildCodexExecArgs,
|
|
171
|
+
parseLine: parseCodexLine,
|
|
172
|
+
};
|
|
173
|
+
export const genericRawEngineAdapter = {
|
|
174
|
+
mode: "raw",
|
|
175
|
+
persistent: false,
|
|
176
|
+
buildLaunchArgs: (userArgs) => [...userArgs],
|
|
177
|
+
buildTurnArgs: (userArgs, turnText) => [...userArgs, turnText],
|
|
178
|
+
parseLine: () => [],
|
|
179
|
+
};
|
|
180
|
+
export function engineAdapterFor(clientType, userArgs = []) {
|
|
181
|
+
if (clientType === "claude")
|
|
182
|
+
return claudeEngineAdapter;
|
|
183
|
+
if (clientType === "codex" && userArgs[0] === "exec" && !["resume", "fork", "review", "help"].includes(userArgs[1] ?? ""))
|
|
184
|
+
return codexEngineAdapter;
|
|
185
|
+
return genericRawEngineAdapter;
|
|
186
|
+
}
|
|
@@ -12,9 +12,10 @@
|
|
|
12
12
|
* whole ledger that is NOT an estimate, so it is carried through as reported rather than being
|
|
13
13
|
* re-derived from `ai-pricing.ts` list prices.
|
|
14
14
|
*
|
|
15
|
-
* Raw
|
|
16
|
-
*
|
|
17
|
-
*
|
|
15
|
+
* Raw engines never reach this module: `HeadlessSession` only parses usage from structured engine
|
|
16
|
+
* events. Codex `exec --json` reports tokens but no dollar figure on the observed 0.151.0 schema,
|
|
17
|
+
* so those rows carry provider `openai`, model `codex`, and `costUsd: 0` without pretending the CLI
|
|
18
|
+
* reported a price.
|
|
18
19
|
*/
|
|
19
20
|
const num = (v) => {
|
|
20
21
|
const n = Number(v);
|
|
@@ -55,6 +56,8 @@ export function parseEngineUsage(ev, fallbackId) {
|
|
|
55
56
|
if (!ev || typeof ev !== "object")
|
|
56
57
|
return null;
|
|
57
58
|
const e = ev;
|
|
59
|
+
if (e.type === "turn.completed")
|
|
60
|
+
return parseCodexUsage(e, fallbackId);
|
|
58
61
|
if (e.type !== "result")
|
|
59
62
|
return null;
|
|
60
63
|
const usage = (e.usage && typeof e.usage === "object" ? e.usage : {});
|
|
@@ -68,6 +71,7 @@ export function parseEngineUsage(ev, fallbackId) {
|
|
|
68
71
|
const uuid = typeof e.uuid === "string" && e.uuid.trim() ? e.uuid.trim() : "";
|
|
69
72
|
return {
|
|
70
73
|
id: uuid || fallbackId,
|
|
74
|
+
provider: "anthropic",
|
|
71
75
|
model: pickModel(e.modelUsage),
|
|
72
76
|
inputTokens,
|
|
73
77
|
outputTokens,
|
|
@@ -77,3 +81,23 @@ export function parseEngineUsage(ev, fallbackId) {
|
|
|
77
81
|
at: new Date().toISOString(),
|
|
78
82
|
};
|
|
79
83
|
}
|
|
84
|
+
function parseCodexUsage(e, fallbackId) {
|
|
85
|
+
const usage = (e.usage && typeof e.usage === "object" ? e.usage : {});
|
|
86
|
+
const inputTokens = num(usage.input_tokens);
|
|
87
|
+
const outputTokens = num(usage.output_tokens);
|
|
88
|
+
const cacheReadTokens = num(usage.cached_input_tokens);
|
|
89
|
+
const cacheWriteTokens = num(usage.cache_write_input_tokens);
|
|
90
|
+
if (!inputTokens && !outputTokens && !cacheReadTokens && !cacheWriteTokens)
|
|
91
|
+
return null;
|
|
92
|
+
return {
|
|
93
|
+
id: fallbackId,
|
|
94
|
+
provider: "openai",
|
|
95
|
+
model: "codex",
|
|
96
|
+
inputTokens,
|
|
97
|
+
outputTokens,
|
|
98
|
+
cacheReadTokens,
|
|
99
|
+
cacheWriteTokens,
|
|
100
|
+
costUsd: 0,
|
|
101
|
+
at: new Date().toISOString(),
|
|
102
|
+
};
|
|
103
|
+
}
|