@paigy/harness 0.3.10 → 0.3.12
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/agy-acp.js +144 -0
- package/dist/cli.js +170 -93
- package/dist/main.js +164 -90
- package/package.json +4 -2
package/dist/agy-acp.js
ADDED
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { createRequire as __cr } from 'node:module'; const require = __cr(import.meta.url);
|
|
3
|
+
|
|
4
|
+
// src/harness/agy-acp.ts
|
|
5
|
+
import { spawn } from "child_process";
|
|
6
|
+
import { randomUUID } from "crypto";
|
|
7
|
+
import { createInterface } from "readline";
|
|
8
|
+
var frame = (body) => JSON.stringify({ jsonrpc: "2.0", ...body });
|
|
9
|
+
function agyArgs(bypass) {
|
|
10
|
+
return [
|
|
11
|
+
"--input-format",
|
|
12
|
+
"stream-json",
|
|
13
|
+
"--output-format",
|
|
14
|
+
"stream-json",
|
|
15
|
+
...bypass ? ["--dangerously-skip-permissions"] : [],
|
|
16
|
+
"--print="
|
|
17
|
+
];
|
|
18
|
+
}
|
|
19
|
+
var AgyAcp = class {
|
|
20
|
+
sessionId;
|
|
21
|
+
cwd = process.cwd();
|
|
22
|
+
bypass = false;
|
|
23
|
+
started = false;
|
|
24
|
+
promptId;
|
|
25
|
+
/** A frame from the harness. */
|
|
26
|
+
fromClient(msg) {
|
|
27
|
+
const out = { client: [], agy: [] };
|
|
28
|
+
if (msg.method === void 0 || msg.id === void 0) return out;
|
|
29
|
+
switch (msg.method) {
|
|
30
|
+
case "initialize":
|
|
31
|
+
out.client.push(frame({ id: msg.id, result: { protocolVersion: 2, agentCapabilities: {}, authMethods: [] } }));
|
|
32
|
+
return out;
|
|
33
|
+
case "session/new":
|
|
34
|
+
this.sessionId = randomUUID();
|
|
35
|
+
if (typeof msg.params?.cwd === "string") this.cwd = msg.params.cwd;
|
|
36
|
+
out.client.push(frame({ id: msg.id, result: { sessionId: this.sessionId } }));
|
|
37
|
+
return out;
|
|
38
|
+
case "session/set_mode":
|
|
39
|
+
case "session/set_config_option": {
|
|
40
|
+
const value = msg.params?.modeId ?? msg.params?.value;
|
|
41
|
+
if (typeof value === "string") this.bypass = value === "bypassPermissions";
|
|
42
|
+
out.client.push(frame({ id: msg.id, result: {} }));
|
|
43
|
+
return out;
|
|
44
|
+
}
|
|
45
|
+
case "session/prompt": {
|
|
46
|
+
const blocks = msg.params?.prompt ?? [];
|
|
47
|
+
const content = blocks.map((b) => b.type === "text" ? b.text ?? "" : "").filter(Boolean).join("\n\n");
|
|
48
|
+
if (!this.started) {
|
|
49
|
+
this.started = true;
|
|
50
|
+
out.start = { cwd: this.cwd, args: agyArgs(this.bypass) };
|
|
51
|
+
}
|
|
52
|
+
this.promptId = msg.id;
|
|
53
|
+
out.agy.push(JSON.stringify({ event: "user", message: { role: "user", content } }));
|
|
54
|
+
return out;
|
|
55
|
+
}
|
|
56
|
+
default:
|
|
57
|
+
out.client.push(frame({ id: msg.id, error: { code: -32601, message: `Method not found: ${msg.method}` } }));
|
|
58
|
+
return out;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
/** A line from `agy`. */
|
|
62
|
+
fromAgy(line) {
|
|
63
|
+
const out = { client: [], agy: [] };
|
|
64
|
+
let ev;
|
|
65
|
+
try {
|
|
66
|
+
ev = JSON.parse(line);
|
|
67
|
+
} catch {
|
|
68
|
+
return out;
|
|
69
|
+
}
|
|
70
|
+
const update = (body) => out.client.push(frame({ method: "session/update", params: { sessionId: this.sessionId, update: body } }));
|
|
71
|
+
if (ev.event === "step_update") {
|
|
72
|
+
const s = ev.step_update ?? {};
|
|
73
|
+
if (s.step_type === "agent_response" && typeof s.text_delta === "string" && s.text_delta) {
|
|
74
|
+
update({ sessionUpdate: "agent_message_chunk", content: { type: "text", text: s.text_delta } });
|
|
75
|
+
} else if (s.step_type === "tool" && s.state === "ACTIVE" && typeof s.tool_name === "string") {
|
|
76
|
+
update({ sessionUpdate: "tool_call", title: s.tool_name, kind: s.tool_name });
|
|
77
|
+
}
|
|
78
|
+
return out;
|
|
79
|
+
}
|
|
80
|
+
if (ev.event === "result" && this.promptId !== void 0) {
|
|
81
|
+
const r = ev.result ?? {};
|
|
82
|
+
const denied = Array.isArray(r.denied_actions) ? r.denied_actions : [];
|
|
83
|
+
if (denied.length) {
|
|
84
|
+
const names = denied.map((d) => d.display_name ?? d.action ?? "a tool").join(", ");
|
|
85
|
+
update({ sessionUpdate: "agent_message_chunk", content: {
|
|
86
|
+
type: "text",
|
|
87
|
+
text: `
|
|
88
|
+
|
|
89
|
+
Antigravity cannot ask for permission when it runs in the background, so it was denied: ${names}.`
|
|
90
|
+
} });
|
|
91
|
+
}
|
|
92
|
+
const id = this.promptId;
|
|
93
|
+
this.promptId = void 0;
|
|
94
|
+
out.client.push(r.status === "SUCCESS" ? frame({ id, result: { stopReason: "end_turn" } }) : frame({ id, error: { code: -32e3, message: String(r.error ?? r.status ?? "agy turn failed") } }));
|
|
95
|
+
}
|
|
96
|
+
return out;
|
|
97
|
+
}
|
|
98
|
+
/** `agy` exited: a turn still open fails by name rather than hanging the harness. */
|
|
99
|
+
exited(code) {
|
|
100
|
+
const out = { client: [], agy: [] };
|
|
101
|
+
if (this.promptId !== void 0) {
|
|
102
|
+
out.client.push(frame({ id: this.promptId, error: { code: -32e3, message: `agy exited ${code ?? "by signal"}` } }));
|
|
103
|
+
this.promptId = void 0;
|
|
104
|
+
}
|
|
105
|
+
return out;
|
|
106
|
+
}
|
|
107
|
+
};
|
|
108
|
+
function main() {
|
|
109
|
+
const adapter = new AgyAcp();
|
|
110
|
+
let agy;
|
|
111
|
+
const apply = (out) => {
|
|
112
|
+
for (const f of out.client) process.stdout.write(`${f}
|
|
113
|
+
`);
|
|
114
|
+
if (out.start) {
|
|
115
|
+
agy = spawn("agy", out.start.args, { cwd: out.start.cwd, stdio: ["pipe", "pipe", "pipe"], env: process.env });
|
|
116
|
+
createInterface({ input: agy.stdout }).on("line", (l) => apply(adapter.fromAgy(l)));
|
|
117
|
+
agy.stderr.on("data", (chunk) => process.stderr.write(chunk));
|
|
118
|
+
agy.on("exit", (code) => {
|
|
119
|
+
apply(adapter.exited(code));
|
|
120
|
+
process.exit(code ?? 1);
|
|
121
|
+
});
|
|
122
|
+
agy.on("error", (e) => {
|
|
123
|
+
process.stderr.write(`agy: ${e.message}
|
|
124
|
+
`);
|
|
125
|
+
apply(adapter.exited(null));
|
|
126
|
+
process.exit(1);
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
for (const l of out.agy) agy?.stdin?.write(`${l}
|
|
130
|
+
`);
|
|
131
|
+
};
|
|
132
|
+
createInterface({ input: process.stdin }).on("line", (line) => {
|
|
133
|
+
try {
|
|
134
|
+
apply(adapter.fromClient(JSON.parse(line)));
|
|
135
|
+
} catch {
|
|
136
|
+
}
|
|
137
|
+
}).on("close", () => {
|
|
138
|
+
agy?.stdin?.end();
|
|
139
|
+
if (!agy) process.exit(0);
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// src/agy-acp.ts
|
|
144
|
+
main();
|