@puzzmo/cli 1.0.35 → 1.0.36
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/lib/agents/codex.d.ts +2 -4
- package/lib/agents/codex.js +32 -61
- package/lib/agents/codex.js.map +1 -1
- package/lib/agents/copilot.d.ts +3 -4
- package/lib/agents/copilot.js +24 -94
- package/lib/agents/copilot.js.map +1 -1
- package/package.json +1 -3
- package/src/agents/codex.ts +37 -62
- package/src/agents/copilot.ts +27 -94
package/lib/agents/codex.d.ts
CHANGED
|
@@ -1,6 +1,4 @@
|
|
|
1
1
|
import type { Agent } from "./types.js";
|
|
2
|
-
/**
|
|
3
|
-
*
|
|
4
|
-
* user's installed `codex` CLI and reuses its ChatGPT subscription auth.
|
|
5
|
-
*/
|
|
2
|
+
/** Codex adapter — wraps the local `codex` CLI in `exec --json` mode so the
|
|
3
|
+
* user's existing ChatGPT subscription auth keeps working. */
|
|
6
4
|
export declare const codexAgent: Agent;
|
package/lib/agents/codex.js
CHANGED
|
@@ -1,92 +1,63 @@
|
|
|
1
|
-
import {
|
|
2
|
-
/**
|
|
3
|
-
*
|
|
4
|
-
* user's installed `codex` CLI and reuses its ChatGPT subscription auth.
|
|
5
|
-
*/
|
|
1
|
+
import { runStreamJsonCli } from "./stream-json-cli.js";
|
|
2
|
+
/** Codex adapter — wraps the local `codex` CLI in `exec --json` mode so the
|
|
3
|
+
* user's existing ChatGPT subscription auth keeps working. */
|
|
6
4
|
export const codexAgent = {
|
|
7
5
|
name: "codex",
|
|
8
|
-
run(input) {
|
|
9
|
-
|
|
10
|
-
|
|
6
|
+
run: (input) => runStreamJsonCli({
|
|
7
|
+
cmd: "codex",
|
|
8
|
+
buildArgs: (prompt) => ["exec", "--json", "--skip-git-repo-check", prompt],
|
|
9
|
+
parseLine: parseCodexLine,
|
|
10
|
+
}, input),
|
|
11
11
|
};
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
12
|
+
/** Map one JSONL event from `codex exec --json` to an AgentEvent. Schema matches
|
|
13
|
+
* the `ThreadEvent` union in `@openai/codex-sdk`. */
|
|
14
|
+
const parseCodexLine = (line) => {
|
|
15
|
+
let event;
|
|
15
16
|
try {
|
|
16
|
-
|
|
17
|
-
workingDirectory: input.cwd ?? process.cwd(),
|
|
18
|
-
skipGitRepoCheck: true,
|
|
19
|
-
});
|
|
17
|
+
event = JSON.parse(line);
|
|
20
18
|
}
|
|
21
|
-
catch
|
|
22
|
-
|
|
23
|
-
return;
|
|
19
|
+
catch {
|
|
20
|
+
return { type: "system", text: line };
|
|
24
21
|
}
|
|
25
|
-
let streamed;
|
|
26
|
-
try {
|
|
27
|
-
streamed = await thread.runStreamed(input.prompt, { signal: input.signal });
|
|
28
|
-
}
|
|
29
|
-
catch (e) {
|
|
30
|
-
yield { type: "error", message: `Codex run failed: ${e.message}` };
|
|
31
|
-
return;
|
|
32
|
-
}
|
|
33
|
-
try {
|
|
34
|
-
for await (const event of streamed.events) {
|
|
35
|
-
const mapped = mapCodexEvent(event);
|
|
36
|
-
for (const m of mapped)
|
|
37
|
-
yield m;
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
catch (e) {
|
|
41
|
-
yield { type: "error", message: e.message ?? String(e) };
|
|
42
|
-
return;
|
|
43
|
-
}
|
|
44
|
-
};
|
|
45
|
-
const mapCodexEvent = (event) => {
|
|
46
22
|
if (event.type === "item.completed" || event.type === "item.updated") {
|
|
47
23
|
const item = event.item;
|
|
48
24
|
if (!item)
|
|
49
|
-
return
|
|
25
|
+
return null;
|
|
50
26
|
if (item.type === "agent_message" && event.type === "item.completed")
|
|
51
|
-
return
|
|
27
|
+
return { type: "text", text: appendNL(item.text ?? "") };
|
|
52
28
|
if (item.type === "reasoning" && event.type === "item.completed")
|
|
53
|
-
return
|
|
29
|
+
return { type: "thinking", text: appendNL(item.text ?? "") };
|
|
54
30
|
if (item.type === "command_execution") {
|
|
55
31
|
if (item.status === "in_progress" && event.type === "item.updated")
|
|
56
|
-
return
|
|
32
|
+
return null;
|
|
57
33
|
if (item.status === "completed" || item.status === "failed")
|
|
58
|
-
return
|
|
59
|
-
return
|
|
34
|
+
return { type: "tool_result", ok: item.status === "completed", summary: item.command ?? "" };
|
|
35
|
+
return { type: "tool_use", name: "Bash", summary: item.command ?? "" };
|
|
60
36
|
}
|
|
61
37
|
if (item.type === "file_change") {
|
|
62
38
|
const summary = (item.changes ?? []).map((c) => `${c.kind} ${c.path}`).join(", ");
|
|
63
|
-
return
|
|
39
|
+
return { type: "tool_result", ok: item.status === "completed", summary };
|
|
64
40
|
}
|
|
65
41
|
if (item.type === "mcp_tool_call") {
|
|
66
42
|
if (item.status === "in_progress")
|
|
67
|
-
return
|
|
68
|
-
return
|
|
43
|
+
return { type: "tool_use", name: `${item.server}/${item.tool}`, summary: "" };
|
|
44
|
+
return { type: "tool_result", ok: item.status === "completed", summary: item.error?.message ?? "" };
|
|
69
45
|
}
|
|
70
46
|
if (item.type === "web_search")
|
|
71
|
-
return
|
|
72
|
-
if (item.type === "todo_list")
|
|
73
|
-
return [];
|
|
47
|
+
return { type: "tool_use", name: "WebSearch", summary: item.query ?? "" };
|
|
74
48
|
if (item.type === "error")
|
|
75
|
-
return
|
|
76
|
-
return
|
|
49
|
+
return { type: "error", message: item.message ?? "" };
|
|
50
|
+
return null;
|
|
77
51
|
}
|
|
78
52
|
if (event.type === "turn.completed")
|
|
79
|
-
return
|
|
53
|
+
return { type: "result", ok: true };
|
|
80
54
|
if (event.type === "turn.failed")
|
|
81
|
-
return
|
|
82
|
-
{ type: "error", message: event.error?.message ?? "turn failed" },
|
|
83
|
-
{ type: "result", ok: false },
|
|
84
|
-
];
|
|
55
|
+
return { type: "error", message: event.error?.message ?? "turn failed" };
|
|
85
56
|
if (event.type === "thread.started")
|
|
86
|
-
return
|
|
57
|
+
return { type: "system", text: "Thread started" };
|
|
87
58
|
if (event.type === "error")
|
|
88
|
-
return
|
|
89
|
-
return
|
|
59
|
+
return { type: "error", message: event.message ?? "" };
|
|
60
|
+
return null;
|
|
90
61
|
};
|
|
91
62
|
const appendNL = (s) => (s.endsWith("\n") ? s : s + "\n");
|
|
92
63
|
//# sourceMappingURL=codex.js.map
|
package/lib/agents/codex.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"codex.js","sourceRoot":"","sources":["../../src/agents/codex.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"codex.js","sourceRoot":"","sources":["../../src/agents/codex.ts"],"names":[],"mappings":"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"}
|
package/lib/agents/copilot.d.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import type { Agent } from "./types.js";
|
|
2
|
-
/**
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*/
|
|
2
|
+
/** Copilot adapter — wraps the local `copilot` CLI (`@github/copilot`) in
|
|
3
|
+
* `--output-format json` mode so the user's existing OAuth/Copilot Pro
|
|
4
|
+
* subscription auth keeps working. */
|
|
6
5
|
export declare const copilotAgent: Agent;
|
package/lib/agents/copilot.js
CHANGED
|
@@ -1,115 +1,45 @@
|
|
|
1
|
-
import {
|
|
2
|
-
/**
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*/
|
|
1
|
+
import { runStreamJsonCli } from "./stream-json-cli.js";
|
|
2
|
+
/** Copilot adapter — wraps the local `copilot` CLI (`@github/copilot`) in
|
|
3
|
+
* `--output-format json` mode so the user's existing OAuth/Copilot Pro
|
|
4
|
+
* subscription auth keeps working. */
|
|
6
5
|
export const copilotAgent = {
|
|
7
6
|
name: "copilot",
|
|
8
|
-
run(input) {
|
|
9
|
-
|
|
10
|
-
|
|
7
|
+
run: (input) => runStreamJsonCli({
|
|
8
|
+
cmd: "copilot",
|
|
9
|
+
buildArgs: (prompt) => ["-p", prompt, "--output-format", "json", "--stream", "on", "--allow-all-tools"],
|
|
10
|
+
parseLine: parseCopilotLine,
|
|
11
|
+
}, input),
|
|
11
12
|
};
|
|
12
|
-
|
|
13
|
-
|
|
13
|
+
/** Map one JSONL event from `copilot --output-format json` to an AgentEvent.
|
|
14
|
+
* Schema: `node_modules/@github/copilot/schemas/session-events.schema.json`. */
|
|
15
|
+
const parseCopilotLine = (line) => {
|
|
16
|
+
let event;
|
|
14
17
|
try {
|
|
15
|
-
|
|
16
|
-
}
|
|
17
|
-
catch (e) {
|
|
18
|
-
yield { type: "error", message: `Copilot client failed to start: ${e.message}` };
|
|
19
|
-
return;
|
|
20
|
-
}
|
|
21
|
-
const events = [];
|
|
22
|
-
let waiting = null;
|
|
23
|
-
const push = (e) => {
|
|
24
|
-
events.push(e);
|
|
25
|
-
waiting?.();
|
|
26
|
-
waiting = null;
|
|
27
|
-
};
|
|
28
|
-
let session;
|
|
29
|
-
try {
|
|
30
|
-
session = await client.createSession({
|
|
31
|
-
streaming: true,
|
|
32
|
-
workingDirectory: input.cwd ?? process.cwd(),
|
|
33
|
-
onPermissionRequest: approveAll,
|
|
34
|
-
onEvent: (event) => {
|
|
35
|
-
const mapped = mapCopilotEvent(event);
|
|
36
|
-
for (const m of mapped)
|
|
37
|
-
push(m);
|
|
38
|
-
},
|
|
39
|
-
});
|
|
40
|
-
}
|
|
41
|
-
catch (e) {
|
|
42
|
-
yield { type: "error", message: `Copilot session creation failed: ${e.message}` };
|
|
43
|
-
await safeStop(client);
|
|
44
|
-
return;
|
|
45
|
-
}
|
|
46
|
-
const cancel = () => {
|
|
47
|
-
session.disconnect().catch(() => { });
|
|
48
|
-
};
|
|
49
|
-
if (input.signal)
|
|
50
|
-
input.signal.addEventListener("abort", cancel);
|
|
51
|
-
let runError = null;
|
|
52
|
-
let runDone = false;
|
|
53
|
-
session
|
|
54
|
-
.sendAndWait({ prompt: input.prompt }, 600_000)
|
|
55
|
-
.catch((e) => {
|
|
56
|
-
runError = e;
|
|
57
|
-
})
|
|
58
|
-
.finally(() => {
|
|
59
|
-
runDone = true;
|
|
60
|
-
waiting?.();
|
|
61
|
-
waiting = null;
|
|
62
|
-
});
|
|
63
|
-
try {
|
|
64
|
-
while (true) {
|
|
65
|
-
if (events.length > 0) {
|
|
66
|
-
yield events.shift();
|
|
67
|
-
continue;
|
|
68
|
-
}
|
|
69
|
-
if (runDone) {
|
|
70
|
-
if (runError)
|
|
71
|
-
yield { type: "error", message: runError.message };
|
|
72
|
-
yield { type: "result", ok: !runError };
|
|
73
|
-
return;
|
|
74
|
-
}
|
|
75
|
-
await new Promise((r) => (waiting = r));
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
finally {
|
|
79
|
-
await session.disconnect().catch(() => { });
|
|
80
|
-
await safeStop(client);
|
|
81
|
-
}
|
|
82
|
-
};
|
|
83
|
-
const safeStop = async (client) => {
|
|
84
|
-
try {
|
|
85
|
-
await client.stop();
|
|
18
|
+
event = JSON.parse(line);
|
|
86
19
|
}
|
|
87
20
|
catch {
|
|
88
|
-
|
|
21
|
+
return { type: "system", text: line };
|
|
89
22
|
}
|
|
90
|
-
};
|
|
91
|
-
const mapCopilotEvent = (event) => {
|
|
92
23
|
if (event.type === "assistant.message_delta")
|
|
93
|
-
return
|
|
24
|
+
return { type: "text", text: event.data?.deltaContent ?? "" };
|
|
94
25
|
if (event.type === "assistant.reasoning_delta")
|
|
95
|
-
return
|
|
26
|
+
return { type: "thinking", text: event.data?.deltaContent ?? event.data?.delta ?? "" };
|
|
96
27
|
if (event.type === "tool.execution_start") {
|
|
97
28
|
const name = event.data?.toolName ?? "tool";
|
|
98
|
-
|
|
99
|
-
return [{ type: "tool_use", name, summary: summarizeToolArgs(name, args) }];
|
|
29
|
+
return { type: "tool_use", name, summary: summarizeToolArgs(event.data?.arguments) };
|
|
100
30
|
}
|
|
101
31
|
if (event.type === "tool.execution_complete") {
|
|
102
32
|
const ok = event.data?.success === true;
|
|
103
33
|
const summary = event.data?.result?.content?.slice(0, 200) ?? event.data?.error?.message ?? "";
|
|
104
|
-
return
|
|
34
|
+
return { type: "tool_result", ok, summary };
|
|
105
35
|
}
|
|
106
36
|
if (event.type === "session.error")
|
|
107
|
-
return
|
|
108
|
-
if (event.type === "
|
|
109
|
-
return
|
|
110
|
-
return
|
|
37
|
+
return { type: "error", message: event.data?.message ?? "session error" };
|
|
38
|
+
if (event.type === "assistant.turn_end")
|
|
39
|
+
return { type: "result", ok: true };
|
|
40
|
+
return null;
|
|
111
41
|
};
|
|
112
|
-
const summarizeToolArgs = (
|
|
42
|
+
const summarizeToolArgs = (args) => {
|
|
113
43
|
if (!args || typeof args !== "object")
|
|
114
44
|
return "";
|
|
115
45
|
if (typeof args.command === "string")
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"copilot.js","sourceRoot":"","sources":["../../src/agents/copilot.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"copilot.js","sourceRoot":"","sources":["../../src/agents/copilot.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@puzzmo/cli",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.36",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"bin": {
|
|
6
6
|
"puzzmo": "./lib/index.js"
|
|
@@ -23,8 +23,6 @@
|
|
|
23
23
|
"dependencies": {
|
|
24
24
|
"@cfworker/json-schema": "^4.1.1",
|
|
25
25
|
"@clack/prompts": "^1.1.0",
|
|
26
|
-
"@github/copilot-sdk": "0.2.2",
|
|
27
|
-
"@openai/codex-sdk": "0.122.0",
|
|
28
26
|
"@opencode-ai/sdk": "1.14.20",
|
|
29
27
|
"@puzzmo/agent-cli-detect": "*"
|
|
30
28
|
}
|
package/src/agents/codex.ts
CHANGED
|
@@ -1,84 +1,59 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { runStreamJsonCli } from "./stream-json-cli.js"
|
|
2
|
+
import type { AgentEvent, Agent } from "./types.js"
|
|
2
3
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Codex adapter — wraps `@openai/codex-sdk`, which itself shells out to the
|
|
7
|
-
* user's installed `codex` CLI and reuses its ChatGPT subscription auth.
|
|
8
|
-
*/
|
|
4
|
+
/** Codex adapter — wraps the local `codex` CLI in `exec --json` mode so the
|
|
5
|
+
* user's existing ChatGPT subscription auth keeps working. */
|
|
9
6
|
export const codexAgent: Agent = {
|
|
10
7
|
name: "codex",
|
|
11
|
-
run(input)
|
|
12
|
-
|
|
13
|
-
|
|
8
|
+
run: (input) =>
|
|
9
|
+
runStreamJsonCli(
|
|
10
|
+
{
|
|
11
|
+
cmd: "codex",
|
|
12
|
+
buildArgs: (prompt) => ["exec", "--json", "--skip-git-repo-check", prompt],
|
|
13
|
+
parseLine: parseCodexLine,
|
|
14
|
+
},
|
|
15
|
+
input,
|
|
16
|
+
),
|
|
14
17
|
}
|
|
15
18
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
+
/** Map one JSONL event from `codex exec --json` to an AgentEvent. Schema matches
|
|
20
|
+
* the `ThreadEvent` union in `@openai/codex-sdk`. */
|
|
21
|
+
const parseCodexLine = (line: string): AgentEvent | null => {
|
|
22
|
+
let event: any
|
|
19
23
|
try {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
})
|
|
24
|
-
} catch (e: any) {
|
|
25
|
-
yield { type: "error", message: `Failed to start codex thread: ${e.message}` }
|
|
26
|
-
return
|
|
24
|
+
event = JSON.parse(line)
|
|
25
|
+
} catch {
|
|
26
|
+
return { type: "system", text: line }
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
-
let streamed
|
|
30
|
-
try {
|
|
31
|
-
streamed = await thread.runStreamed(input.prompt, { signal: input.signal })
|
|
32
|
-
} catch (e: any) {
|
|
33
|
-
yield { type: "error", message: `Codex run failed: ${e.message}` }
|
|
34
|
-
return
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
try {
|
|
38
|
-
for await (const event of streamed.events) {
|
|
39
|
-
const mapped = mapCodexEvent(event)
|
|
40
|
-
for (const m of mapped) yield m
|
|
41
|
-
}
|
|
42
|
-
} catch (e: any) {
|
|
43
|
-
yield { type: "error", message: e.message ?? String(e) }
|
|
44
|
-
return
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
const mapCodexEvent = (event: any): AgentEvent[] => {
|
|
49
29
|
if (event.type === "item.completed" || event.type === "item.updated") {
|
|
50
30
|
const item = event.item
|
|
51
|
-
if (!item) return
|
|
52
|
-
if (item.type === "agent_message" && event.type === "item.completed") return
|
|
53
|
-
if (item.type === "reasoning" && event.type === "item.completed") return
|
|
31
|
+
if (!item) return null
|
|
32
|
+
if (item.type === "agent_message" && event.type === "item.completed") return { type: "text", text: appendNL(item.text ?? "") }
|
|
33
|
+
if (item.type === "reasoning" && event.type === "item.completed") return { type: "thinking", text: appendNL(item.text ?? "") }
|
|
54
34
|
if (item.type === "command_execution") {
|
|
55
|
-
if (item.status === "in_progress" && event.type === "item.updated") return
|
|
35
|
+
if (item.status === "in_progress" && event.type === "item.updated") return null
|
|
56
36
|
if (item.status === "completed" || item.status === "failed")
|
|
57
|
-
return
|
|
58
|
-
return
|
|
37
|
+
return { type: "tool_result", ok: item.status === "completed", summary: item.command ?? "" }
|
|
38
|
+
return { type: "tool_use", name: "Bash", summary: item.command ?? "" }
|
|
59
39
|
}
|
|
60
40
|
if (item.type === "file_change") {
|
|
61
41
|
const summary = (item.changes ?? []).map((c: any) => `${c.kind} ${c.path}`).join(", ")
|
|
62
|
-
return
|
|
42
|
+
return { type: "tool_result", ok: item.status === "completed", summary }
|
|
63
43
|
}
|
|
64
44
|
if (item.type === "mcp_tool_call") {
|
|
65
|
-
if (item.status === "in_progress") return
|
|
66
|
-
return
|
|
45
|
+
if (item.status === "in_progress") return { type: "tool_use", name: `${item.server}/${item.tool}`, summary: "" }
|
|
46
|
+
return { type: "tool_result", ok: item.status === "completed", summary: item.error?.message ?? "" }
|
|
67
47
|
}
|
|
68
|
-
if (item.type === "web_search") return
|
|
69
|
-
if (item.type === "
|
|
70
|
-
|
|
71
|
-
return []
|
|
48
|
+
if (item.type === "web_search") return { type: "tool_use", name: "WebSearch", summary: item.query ?? "" }
|
|
49
|
+
if (item.type === "error") return { type: "error", message: item.message ?? "" }
|
|
50
|
+
return null
|
|
72
51
|
}
|
|
73
|
-
if (event.type === "turn.completed") return
|
|
74
|
-
if (event.type === "turn.failed")
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
]
|
|
79
|
-
if (event.type === "thread.started") return [{ type: "system", text: "Thread started" }]
|
|
80
|
-
if (event.type === "error") return [{ type: "error", message: event.message ?? "" }]
|
|
81
|
-
return []
|
|
52
|
+
if (event.type === "turn.completed") return { type: "result", ok: true }
|
|
53
|
+
if (event.type === "turn.failed") return { type: "error", message: event.error?.message ?? "turn failed" }
|
|
54
|
+
if (event.type === "thread.started") return { type: "system", text: "Thread started" }
|
|
55
|
+
if (event.type === "error") return { type: "error", message: event.message ?? "" }
|
|
56
|
+
return null
|
|
82
57
|
}
|
|
83
58
|
|
|
84
59
|
const appendNL = (s: string) => (s.endsWith("\n") ? s : s + "\n")
|
package/src/agents/copilot.ts
CHANGED
|
@@ -1,116 +1,49 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { runStreamJsonCli } from "./stream-json-cli.js"
|
|
2
|
+
import type { Agent, AgentEvent } from "./types.js"
|
|
2
3
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
* Copilot adapter — wraps `@github/copilot-sdk`, which spawns the bundled
|
|
7
|
-
* `@github/copilot` CLI and reuses its OAuth/Copilot Pro subscription auth.
|
|
8
|
-
*/
|
|
4
|
+
/** Copilot adapter — wraps the local `copilot` CLI (`@github/copilot`) in
|
|
5
|
+
* `--output-format json` mode so the user's existing OAuth/Copilot Pro
|
|
6
|
+
* subscription auth keeps working. */
|
|
9
7
|
export const copilotAgent: Agent = {
|
|
10
8
|
name: "copilot",
|
|
11
|
-
run(input)
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
const client = new CopilotClient({ cwd: input.cwd ?? process.cwd() })
|
|
18
|
-
try {
|
|
19
|
-
await client.start()
|
|
20
|
-
} catch (e: any) {
|
|
21
|
-
yield { type: "error", message: `Copilot client failed to start: ${e.message}` }
|
|
22
|
-
return
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
const events: AgentEvent[] = []
|
|
26
|
-
let waiting: (() => void) | null = null
|
|
27
|
-
const push = (e: AgentEvent) => {
|
|
28
|
-
events.push(e)
|
|
29
|
-
waiting?.()
|
|
30
|
-
waiting = null
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
let session
|
|
34
|
-
try {
|
|
35
|
-
session = await client.createSession({
|
|
36
|
-
streaming: true,
|
|
37
|
-
workingDirectory: input.cwd ?? process.cwd(),
|
|
38
|
-
onPermissionRequest: approveAll,
|
|
39
|
-
onEvent: (event: any) => {
|
|
40
|
-
const mapped = mapCopilotEvent(event)
|
|
41
|
-
for (const m of mapped) push(m)
|
|
9
|
+
run: (input) =>
|
|
10
|
+
runStreamJsonCli(
|
|
11
|
+
{
|
|
12
|
+
cmd: "copilot",
|
|
13
|
+
buildArgs: (prompt) => ["-p", prompt, "--output-format", "json", "--stream", "on", "--allow-all-tools"],
|
|
14
|
+
parseLine: parseCopilotLine,
|
|
42
15
|
},
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
yield { type: "error", message: `Copilot session creation failed: ${e.message}` }
|
|
46
|
-
await safeStop(client)
|
|
47
|
-
return
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
const cancel = () => {
|
|
51
|
-
session.disconnect().catch(() => {})
|
|
52
|
-
}
|
|
53
|
-
if (input.signal) input.signal.addEventListener("abort", cancel)
|
|
54
|
-
|
|
55
|
-
let runError = null as Error | null
|
|
56
|
-
let runDone = false
|
|
57
|
-
session
|
|
58
|
-
.sendAndWait({ prompt: input.prompt }, 600_000)
|
|
59
|
-
.catch((e: Error) => {
|
|
60
|
-
runError = e
|
|
61
|
-
})
|
|
62
|
-
.finally(() => {
|
|
63
|
-
runDone = true
|
|
64
|
-
waiting?.()
|
|
65
|
-
waiting = null
|
|
66
|
-
})
|
|
67
|
-
|
|
68
|
-
try {
|
|
69
|
-
while (true) {
|
|
70
|
-
if (events.length > 0) {
|
|
71
|
-
yield events.shift()!
|
|
72
|
-
continue
|
|
73
|
-
}
|
|
74
|
-
if (runDone) {
|
|
75
|
-
if (runError) yield { type: "error", message: runError.message }
|
|
76
|
-
yield { type: "result", ok: !runError }
|
|
77
|
-
return
|
|
78
|
-
}
|
|
79
|
-
await new Promise<void>((r) => (waiting = r))
|
|
80
|
-
}
|
|
81
|
-
} finally {
|
|
82
|
-
await session.disconnect().catch(() => {})
|
|
83
|
-
await safeStop(client)
|
|
84
|
-
}
|
|
16
|
+
input,
|
|
17
|
+
),
|
|
85
18
|
}
|
|
86
19
|
|
|
87
|
-
|
|
20
|
+
/** Map one JSONL event from `copilot --output-format json` to an AgentEvent.
|
|
21
|
+
* Schema: `node_modules/@github/copilot/schemas/session-events.schema.json`. */
|
|
22
|
+
const parseCopilotLine = (line: string): AgentEvent | null => {
|
|
23
|
+
let event: any
|
|
88
24
|
try {
|
|
89
|
-
|
|
25
|
+
event = JSON.parse(line)
|
|
90
26
|
} catch {
|
|
91
|
-
|
|
27
|
+
return { type: "system", text: line }
|
|
92
28
|
}
|
|
93
|
-
}
|
|
94
29
|
|
|
95
|
-
|
|
96
|
-
if (event.type === "assistant.
|
|
97
|
-
if (event.type === "assistant.reasoning_delta") return [{ type: "thinking", text: event.data?.deltaContent ?? event.data?.delta ?? "" }]
|
|
30
|
+
if (event.type === "assistant.message_delta") return { type: "text", text: event.data?.deltaContent ?? "" }
|
|
31
|
+
if (event.type === "assistant.reasoning_delta") return { type: "thinking", text: event.data?.deltaContent ?? event.data?.delta ?? "" }
|
|
98
32
|
if (event.type === "tool.execution_start") {
|
|
99
33
|
const name = event.data?.toolName ?? "tool"
|
|
100
|
-
|
|
101
|
-
return [{ type: "tool_use", name, summary: summarizeToolArgs(name, args) }]
|
|
34
|
+
return { type: "tool_use", name, summary: summarizeToolArgs(event.data?.arguments) }
|
|
102
35
|
}
|
|
103
36
|
if (event.type === "tool.execution_complete") {
|
|
104
37
|
const ok = event.data?.success === true
|
|
105
38
|
const summary = event.data?.result?.content?.slice(0, 200) ?? event.data?.error?.message ?? ""
|
|
106
|
-
return
|
|
39
|
+
return { type: "tool_result", ok, summary }
|
|
107
40
|
}
|
|
108
|
-
if (event.type === "session.error") return
|
|
109
|
-
if (event.type === "
|
|
110
|
-
return
|
|
41
|
+
if (event.type === "session.error") return { type: "error", message: event.data?.message ?? "session error" }
|
|
42
|
+
if (event.type === "assistant.turn_end") return { type: "result", ok: true }
|
|
43
|
+
return null
|
|
111
44
|
}
|
|
112
45
|
|
|
113
|
-
const summarizeToolArgs = (
|
|
46
|
+
const summarizeToolArgs = (args: any): string => {
|
|
114
47
|
if (!args || typeof args !== "object") return ""
|
|
115
48
|
if (typeof args.command === "string") return args.command.slice(0, 200)
|
|
116
49
|
if (typeof args.file_path === "string") return args.file_path
|