@oharness/engine 0.9.3 → 0.11.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/dist/acp/claude.d.ts +34 -0
- package/dist/acp/claude.js +122 -0
- package/dist/acp/claude.js.map +1 -0
- package/dist/acp/client.d.ts +193 -0
- package/dist/acp/client.js +279 -0
- package/dist/acp/client.js.map +1 -0
- package/dist/acp/runner.d.ts +80 -0
- package/dist/acp/runner.js +159 -0
- package/dist/acp/runner.js.map +1 -0
- package/dist/agent/agent.d.ts +258 -2
- package/dist/agent/agent.js +1010 -53
- package/dist/agent/agent.js.map +1 -1
- package/dist/agent/background.d.ts +135 -0
- package/dist/agent/background.js +307 -0
- package/dist/agent/background.js.map +1 -0
- package/dist/agent/compaction.d.ts +7 -0
- package/dist/agent/compaction.js +11 -3
- package/dist/agent/compaction.js.map +1 -1
- package/dist/agent/goal.d.ts +36 -0
- package/dist/agent/goal.js +71 -0
- package/dist/agent/goal.js.map +1 -0
- package/dist/agent/hooks.js +6 -6
- package/dist/agent/hooks.js.map +1 -1
- package/dist/agent/permissions.d.ts +6 -0
- package/dist/agent/permissions.js +2 -1
- package/dist/agent/permissions.js.map +1 -1
- package/dist/agent/session.d.ts +38 -0
- package/dist/agent/session.js +91 -2
- package/dist/agent/session.js.map +1 -1
- package/dist/agent/store.d.ts +25 -0
- package/dist/agent/store.js +21 -0
- package/dist/agent/store.js.map +1 -1
- package/dist/agent/subagent.d.ts +21 -0
- package/dist/agent/subagent.js +17 -1
- package/dist/agent/subagent.js.map +1 -1
- package/dist/agent/workspace.d.ts +9 -0
- package/dist/agent/workspace.js +59 -5
- package/dist/agent/workspace.js.map +1 -1
- package/dist/auth/index.d.ts +3 -1
- package/dist/auth/index.js +3 -1
- package/dist/auth/index.js.map +1 -1
- package/dist/auth/manager.d.ts +9 -0
- package/dist/auth/manager.js +71 -6
- package/dist/auth/manager.js.map +1 -1
- package/dist/auth/oauth.d.ts +33 -0
- package/dist/auth/oauth.js +59 -8
- package/dist/auth/oauth.js.map +1 -1
- package/dist/auth/providers/account.js +5 -4
- package/dist/auth/providers/account.js.map +1 -1
- package/dist/auth/providers/anthropic.d.ts +25 -5
- package/dist/auth/providers/anthropic.js +47 -6
- package/dist/auth/providers/anthropic.js.map +1 -1
- package/dist/auth/providers/chatgpt.d.ts +8 -0
- package/dist/auth/providers/chatgpt.js +180 -0
- package/dist/auth/providers/chatgpt.js.map +1 -0
- package/dist/auth/providers/openrouter.d.ts +2 -0
- package/dist/auth/providers/openrouter.js +101 -0
- package/dist/auth/providers/openrouter.js.map +1 -0
- package/dist/auth/types.d.ts +15 -0
- package/dist/auth/types.js.map +1 -1
- package/dist/browser/index.d.ts +1 -1
- package/dist/browser/plugin.d.ts +6 -1
- package/dist/browser/plugin.js.map +1 -1
- package/dist/browser/session.d.ts +47 -0
- package/dist/browser/session.js +177 -2
- package/dist/browser/session.js.map +1 -1
- package/dist/browser/tools.js +142 -18
- package/dist/browser/tools.js.map +1 -1
- package/dist/computer/arbiter.d.ts +69 -0
- package/dist/computer/arbiter.js +128 -0
- package/dist/computer/arbiter.js.map +1 -0
- package/dist/computer/cua-driver.d.ts +174 -0
- package/dist/computer/cua-driver.js +597 -0
- package/dist/computer/cua-driver.js.map +1 -0
- package/dist/computer/helper-client.d.ts +80 -0
- package/dist/computer/helper-client.js +166 -0
- package/dist/computer/helper-client.js.map +1 -0
- package/dist/computer/index.d.ts +16 -0
- package/dist/computer/index.js +9 -0
- package/dist/computer/index.js.map +1 -0
- package/dist/computer/mode.d.ts +34 -0
- package/dist/computer/mode.js +52 -0
- package/dist/computer/mode.js.map +1 -0
- package/dist/computer/plugin.d.ts +24 -0
- package/dist/computer/plugin.js +17 -0
- package/dist/computer/plugin.js.map +1 -0
- package/dist/computer/policy.d.ts +29 -0
- package/dist/computer/policy.js +127 -0
- package/dist/computer/policy.js.map +1 -0
- package/dist/computer/session.d.ts +228 -0
- package/dist/computer/session.js +493 -0
- package/dist/computer/session.js.map +1 -0
- package/dist/computer/target.d.ts +206 -0
- package/dist/computer/target.js +31 -0
- package/dist/computer/target.js.map +1 -0
- package/dist/computer/tools.d.ts +8 -0
- package/dist/computer/tools.js +664 -0
- package/dist/computer/tools.js.map +1 -0
- package/dist/config.d.ts +7 -0
- package/dist/config.js.map +1 -1
- package/dist/core/tokens.js +4 -0
- package/dist/core/tokens.js.map +1 -1
- package/dist/core/types.d.ts +16 -1
- package/dist/core/types.js.map +1 -1
- package/dist/harness.d.ts +128 -1
- package/dist/harness.js +287 -30
- package/dist/harness.js.map +1 -1
- package/dist/index.d.ts +3 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/mcp/manager.d.ts +15 -0
- package/dist/mcp/manager.js +28 -1
- package/dist/mcp/manager.js.map +1 -1
- package/dist/mcp/transport.js +3 -0
- package/dist/mcp/transport.js.map +1 -1
- package/dist/providers/catalog.js +6 -0
- package/dist/providers/catalog.js.map +1 -1
- package/dist/providers/catalog.json +14 -3
- package/dist/providers/discovery.js +10 -2
- package/dist/providers/discovery.js.map +1 -1
- package/dist/providers/models-dev.d.ts +15 -0
- package/dist/providers/models-dev.js +15 -0
- package/dist/providers/models-dev.js.map +1 -1
- package/dist/providers/models-dev.json +114 -102
- package/dist/providers/piai.d.ts +54 -2
- package/dist/providers/piai.js +154 -9
- package/dist/providers/piai.js.map +1 -1
- package/dist/providers/registry.d.ts +16 -1
- package/dist/providers/registry.js +42 -11
- package/dist/providers/registry.js.map +1 -1
- package/dist/providers/types.d.ts +6 -0
- package/dist/providers/types.js.map +1 -1
- package/dist/runtime-plugins/builtin/studio.d.ts +7 -0
- package/dist/runtime-plugins/builtin/studio.js +69 -4
- package/dist/runtime-plugins/builtin/studio.js.map +1 -1
- package/dist/runtime-plugins/cloud-connector.js +5 -0
- package/dist/runtime-plugins/cloud-connector.js.map +1 -1
- package/dist/schedule/scheduler.d.ts +38 -0
- package/dist/schedule/scheduler.js +101 -1
- package/dist/schedule/scheduler.js.map +1 -1
- package/dist/tools/builtin/bash.d.ts +6 -0
- package/dist/tools/builtin/bash.js +8 -11
- package/dist/tools/builtin/bash.js.map +1 -1
- package/dist/tools/builtin/recall.js +4 -0
- package/dist/tools/builtin/recall.js.map +1 -1
- package/dist/tools/builtin/routine.d.ts +9 -0
- package/dist/tools/builtin/routine.js +23 -2
- package/dist/tools/builtin/routine.js.map +1 -1
- package/dist/tools/builtin/task-control.d.ts +21 -0
- package/dist/tools/builtin/task-control.js +120 -0
- package/dist/tools/builtin/task-control.js.map +1 -0
- package/dist/tools/builtin/task.js +50 -9
- package/dist/tools/builtin/task.js.map +1 -1
- package/dist/tools/builtin/todo.d.ts +1 -1
- package/dist/tools/builtin/worktree.d.ts +10 -0
- package/dist/tools/builtin/worktree.js +52 -0
- package/dist/tools/builtin/worktree.js.map +1 -0
- package/dist/tools/define.d.ts +4 -1
- package/dist/tools/define.js +2 -0
- package/dist/tools/define.js.map +1 -1
- package/dist/tools/types.d.ts +112 -0
- package/dist/tools/types.js.map +1 -1
- package/dist/util/shell.d.ts +30 -0
- package/dist/util/shell.js +70 -0
- package/dist/util/shell.js.map +1 -1
- package/dist/worktree/index.d.ts +109 -0
- package/dist/worktree/index.js +463 -0
- package/dist/worktree/index.js.map +1 -0
- package/package.json +3 -3
- package/skills/media-generation/SKILL.md +22 -1
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { SubagentDefinition } from "../agent/subagent.ts";
|
|
2
|
+
/**
|
|
3
|
+
* Claude Code as a subagent, through the ACP adapter.
|
|
4
|
+
*
|
|
5
|
+
* The rules this follows are Anthropic's, and they are the design:
|
|
6
|
+
*
|
|
7
|
+
* - It is the user's own `claude`, unmodified, signed in through Claude
|
|
8
|
+
* Code's own login. The adapter is pointed at that binary
|
|
9
|
+
* (`CLAUDE_CODE_EXECUTABLE`) rather than at a copy bundled here.
|
|
10
|
+
* - OHarness offers no Claude login and reads no token. The ACP client
|
|
11
|
+
* advertises no auth capability, so the adapter cannot ask it to run one;
|
|
12
|
+
* a Claude Code that is not signed in gets a sentence pointing at the
|
|
13
|
+
* terminal hand-off, where the user signs in to Claude Code themselves.
|
|
14
|
+
* - Never `--hide-claude-auth`, never an auth method stripped.
|
|
15
|
+
* - Called "Claude Agent", the name Anthropic allows for this, not
|
|
16
|
+
* "Claude Code".
|
|
17
|
+
*
|
|
18
|
+
* Whatever it spends is spent on the user's own Claude account.
|
|
19
|
+
*/
|
|
20
|
+
/** The adapter, pinned: it ships often and leans on protocol extensions. */
|
|
21
|
+
export declare const CLAUDE_ACP_PACKAGE = "@agentclientprotocol/claude-agent-acp@0.89.0";
|
|
22
|
+
/** The oldest Node the adapter runs on (its `engines.node`). */
|
|
23
|
+
export declare const ADAPTER_MIN_NODE = 22;
|
|
24
|
+
/** The first executable of these names on PATH or in the usual places. */
|
|
25
|
+
export declare function findExecutable(names: string[], env?: NodeJS.ProcessEnv, extra?: string[]): Promise<string | undefined>;
|
|
26
|
+
/**
|
|
27
|
+
* The Claude Agent subagent, or nothing when this machine cannot run it.
|
|
28
|
+
*
|
|
29
|
+
* Offered only when both halves are present: the user's `claude`, and `npx`
|
|
30
|
+
* to fetch the adapter on first use. Whether Claude Code is signed in is not
|
|
31
|
+
* checked here — that would mean reading its credentials — and is found out
|
|
32
|
+
* the honest way, by the adapter refusing to start a session.
|
|
33
|
+
*/
|
|
34
|
+
export declare function claudeAgent(env?: NodeJS.ProcessEnv, extra?: string[]): Promise<SubagentDefinition | undefined>;
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { execFile } from "node:child_process";
|
|
2
|
+
import { access, constants } from "node:fs/promises";
|
|
3
|
+
import { homedir } from "node:os";
|
|
4
|
+
import path from "node:path";
|
|
5
|
+
/**
|
|
6
|
+
* Claude Code as a subagent, through the ACP adapter.
|
|
7
|
+
*
|
|
8
|
+
* The rules this follows are Anthropic's, and they are the design:
|
|
9
|
+
*
|
|
10
|
+
* - It is the user's own `claude`, unmodified, signed in through Claude
|
|
11
|
+
* Code's own login. The adapter is pointed at that binary
|
|
12
|
+
* (`CLAUDE_CODE_EXECUTABLE`) rather than at a copy bundled here.
|
|
13
|
+
* - OHarness offers no Claude login and reads no token. The ACP client
|
|
14
|
+
* advertises no auth capability, so the adapter cannot ask it to run one;
|
|
15
|
+
* a Claude Code that is not signed in gets a sentence pointing at the
|
|
16
|
+
* terminal hand-off, where the user signs in to Claude Code themselves.
|
|
17
|
+
* - Never `--hide-claude-auth`, never an auth method stripped.
|
|
18
|
+
* - Called "Claude Agent", the name Anthropic allows for this, not
|
|
19
|
+
* "Claude Code".
|
|
20
|
+
*
|
|
21
|
+
* Whatever it spends is spent on the user's own Claude account.
|
|
22
|
+
*/
|
|
23
|
+
/** The adapter, pinned: it ships often and leans on protocol extensions. */
|
|
24
|
+
export const CLAUDE_ACP_PACKAGE = "@agentclientprotocol/claude-agent-acp@0.89.0";
|
|
25
|
+
const EXE = process.platform === "win32" ? ["claude.exe", "claude.cmd"] : ["claude"];
|
|
26
|
+
const NPX = process.platform === "win32" ? ["npx.cmd", "npx.exe"] : ["npx"];
|
|
27
|
+
const NODE = process.platform === "win32" ? ["node.exe"] : ["node"];
|
|
28
|
+
/** The oldest Node the adapter runs on (its `engines.node`). */
|
|
29
|
+
export const ADAPTER_MIN_NODE = 22;
|
|
30
|
+
/**
|
|
31
|
+
* Where to look beyond PATH. A desktop app started from the Dock inherits a
|
|
32
|
+
* PATH without the user's shell profile, which is exactly where a CLI
|
|
33
|
+
* installer puts itself.
|
|
34
|
+
*/
|
|
35
|
+
function extraDirs() {
|
|
36
|
+
const home = homedir();
|
|
37
|
+
return process.platform === "win32"
|
|
38
|
+
? [path.join(process.env["APPDATA"] ?? home, "npm"), path.join(home, ".local", "bin")]
|
|
39
|
+
: [
|
|
40
|
+
path.join(home, ".local", "bin"),
|
|
41
|
+
path.join(home, ".claude", "local"),
|
|
42
|
+
"/opt/homebrew/bin",
|
|
43
|
+
"/usr/local/bin",
|
|
44
|
+
path.join(home, ".npm-global", "bin"),
|
|
45
|
+
];
|
|
46
|
+
}
|
|
47
|
+
/** The first executable of these names on PATH or in the usual places. */
|
|
48
|
+
export async function findExecutable(names, env = process.env, extra = extraDirs()) {
|
|
49
|
+
const dirs = [...(env["PATH"] ?? "").split(path.delimiter).filter(Boolean), ...extra];
|
|
50
|
+
for (const dir of dirs) {
|
|
51
|
+
for (const name of names) {
|
|
52
|
+
const candidate = path.join(dir, name);
|
|
53
|
+
try {
|
|
54
|
+
await access(candidate, constants.X_OK);
|
|
55
|
+
return candidate;
|
|
56
|
+
}
|
|
57
|
+
catch {
|
|
58
|
+
// Not here.
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
return undefined;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* The Claude Agent subagent, or nothing when this machine cannot run it.
|
|
66
|
+
*
|
|
67
|
+
* Offered only when both halves are present: the user's `claude`, and `npx`
|
|
68
|
+
* to fetch the adapter on first use. Whether Claude Code is signed in is not
|
|
69
|
+
* checked here — that would mean reading its credentials — and is found out
|
|
70
|
+
* the honest way, by the adapter refusing to start a session.
|
|
71
|
+
*/
|
|
72
|
+
export async function claudeAgent(env = process.env, extra = extraDirs()) {
|
|
73
|
+
const claude = await findExecutable(EXE, env, extra);
|
|
74
|
+
if (!claude)
|
|
75
|
+
return undefined;
|
|
76
|
+
const npx = await findExecutable(NPX, env, extra);
|
|
77
|
+
if (!npx)
|
|
78
|
+
return undefined;
|
|
79
|
+
// npx finds node beside itself; a stripped PATH would not.
|
|
80
|
+
const pathWithTools = [path.dirname(npx), path.dirname(claude), env["PATH"] ?? ""].filter(Boolean).join(path.delimiter);
|
|
81
|
+
const unavailable = await nodeProblem({ ...env, PATH: pathWithTools });
|
|
82
|
+
return {
|
|
83
|
+
name: "claude",
|
|
84
|
+
description: "Claude Agent: hands the task to the user's own Claude Code install, signed in with their own Claude account, " +
|
|
85
|
+
"which pays for it. Use only when the user asks for Claude Code or their Claude plan to do the work.",
|
|
86
|
+
// Unused: the agent runs on its own prompt and its own CLAUDE.md.
|
|
87
|
+
systemPrompt: "",
|
|
88
|
+
runtime: {
|
|
89
|
+
kind: "acp",
|
|
90
|
+
command: npx,
|
|
91
|
+
args: ["-y", CLAUDE_ACP_PACKAGE],
|
|
92
|
+
env: { CLAUDE_CODE_EXECUTABLE: claude, PATH: pathWithTools },
|
|
93
|
+
signInHint: "Claude Code is not signed in. Open Claude Code from the project menu (or run `claude` in a terminal), " +
|
|
94
|
+
"sign in there with your own Claude account, then try again.",
|
|
95
|
+
...(unavailable ? { unavailable } : {}),
|
|
96
|
+
},
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Why the adapter cannot run on this machine's Node, if it cannot.
|
|
101
|
+
*
|
|
102
|
+
* Checked up front because the failure otherwise arrives as the adapter
|
|
103
|
+
* exiting with an engine error halfway through a task, which reads like a
|
|
104
|
+
* bug in Claude Code. The agent is still offered when Node is too old — left
|
|
105
|
+
* out, nobody would learn why it was missing — and answers with this instead.
|
|
106
|
+
*/
|
|
107
|
+
async function nodeProblem(env) {
|
|
108
|
+
const node = await findExecutable(NODE, env, []);
|
|
109
|
+
const need = `Claude Agent needs Node.js ${ADAPTER_MIN_NODE} or newer`;
|
|
110
|
+
if (!node)
|
|
111
|
+
return `${need}, and none was found on PATH. Install it from https://nodejs.org, then restart OHarness.`;
|
|
112
|
+
const version = await new Promise((resolve) => {
|
|
113
|
+
execFile(node, ["--version"], { timeout: 5_000, env }, (err, stdout) => resolve(err ? undefined : String(stdout).trim()));
|
|
114
|
+
});
|
|
115
|
+
const major = Number(/^v?(\d+)\./.exec(version ?? "")?.[1]);
|
|
116
|
+
// A version that cannot be read is let through: the adapter will say
|
|
117
|
+
// whatever is wrong more precisely than a guess here could.
|
|
118
|
+
if (!Number.isFinite(major) || major >= ADAPTER_MIN_NODE)
|
|
119
|
+
return undefined;
|
|
120
|
+
return `${need}; this machine has ${version} (${node}). Update Node, then restart OHarness.`;
|
|
121
|
+
}
|
|
122
|
+
//# sourceMappingURL=claude.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"claude.js","sourceRoot":"","sources":["../../src/acp/claude.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A client for the Agent Client Protocol (agentclientprotocol.com).
|
|
3
|
+
*
|
|
4
|
+
* ACP is how an editor drives an agent it did not write: the agent runs as a
|
|
5
|
+
* child process and the two exchange JSON-RPC 2.0 messages, one per line, over
|
|
6
|
+
* its stdin and stdout. This is the client half, written against the baseline
|
|
7
|
+
* methods only — `initialize`, `session/new`, `session/prompt`,
|
|
8
|
+
* `session/cancel`, the `session/update` stream and
|
|
9
|
+
* `session/request_permission` — because the agents that speak it add
|
|
10
|
+
* extensions faster than any one client should chase.
|
|
11
|
+
*
|
|
12
|
+
* Deliberately small and dependency-free rather than built on the SDK: the
|
|
13
|
+
* surface used here is a few hundred lines of protocol, and owning it keeps
|
|
14
|
+
* the fake agent in the tests and the real one on the same footing.
|
|
15
|
+
*
|
|
16
|
+
* What it advertises is a choice. `fs`, when the caller supplies a file
|
|
17
|
+
* system, so the agent's reads and writes pass through this harness's
|
|
18
|
+
* workspace policy instead of around it. No `terminal`: the agent runs its
|
|
19
|
+
* own commands. And no `auth` capability: an
|
|
20
|
+
* agent that needs signing in is told so and left to its own login, never
|
|
21
|
+
* offered one from here — for Claude Code that is the difference between the
|
|
22
|
+
* user signing in to Claude Code and OHarness brokering a Claude login.
|
|
23
|
+
*/
|
|
24
|
+
export declare const ACP_PROTOCOL_VERSION = 1;
|
|
25
|
+
/** JSON-RPC error code ACP uses for "this agent needs signing in". */
|
|
26
|
+
export declare const ACP_AUTH_REQUIRED = -32000;
|
|
27
|
+
export type AcpStopReason = "end_turn" | "max_tokens" | "max_turn_requests" | "refusal" | "cancelled";
|
|
28
|
+
export interface AcpToolCall {
|
|
29
|
+
toolCallId: string;
|
|
30
|
+
title?: string | null;
|
|
31
|
+
kind?: string | null;
|
|
32
|
+
status?: "pending" | "in_progress" | "completed" | "failed" | null;
|
|
33
|
+
rawInput?: unknown;
|
|
34
|
+
}
|
|
35
|
+
/** The `session/update` variants this client acts on; the rest are ignored. */
|
|
36
|
+
export type AcpUpdate = {
|
|
37
|
+
sessionUpdate: "agent_message_chunk";
|
|
38
|
+
content: {
|
|
39
|
+
type: string;
|
|
40
|
+
text?: string;
|
|
41
|
+
};
|
|
42
|
+
} | {
|
|
43
|
+
sessionUpdate: "agent_thought_chunk";
|
|
44
|
+
content: {
|
|
45
|
+
type: string;
|
|
46
|
+
text?: string;
|
|
47
|
+
};
|
|
48
|
+
} | ({
|
|
49
|
+
sessionUpdate: "tool_call";
|
|
50
|
+
} & AcpToolCall) | ({
|
|
51
|
+
sessionUpdate: "tool_call_update";
|
|
52
|
+
} & AcpToolCall) | {
|
|
53
|
+
sessionUpdate: "plan";
|
|
54
|
+
entries: Array<{
|
|
55
|
+
content: string;
|
|
56
|
+
status?: string;
|
|
57
|
+
}>;
|
|
58
|
+
} | {
|
|
59
|
+
sessionUpdate: "notice";
|
|
60
|
+
severity?: string;
|
|
61
|
+
title: string;
|
|
62
|
+
} | {
|
|
63
|
+
sessionUpdate: string;
|
|
64
|
+
[key: string]: unknown;
|
|
65
|
+
};
|
|
66
|
+
export interface AcpPermissionOption {
|
|
67
|
+
optionId: string;
|
|
68
|
+
name: string;
|
|
69
|
+
kind: "allow_once" | "allow_always" | "reject_once" | "reject_always";
|
|
70
|
+
}
|
|
71
|
+
export interface AcpPermissionRequest {
|
|
72
|
+
sessionId: string;
|
|
73
|
+
toolCall: AcpToolCall;
|
|
74
|
+
options: AcpPermissionOption[];
|
|
75
|
+
}
|
|
76
|
+
export type AcpPermissionOutcome = {
|
|
77
|
+
outcome: "cancelled";
|
|
78
|
+
} | {
|
|
79
|
+
outcome: "selected";
|
|
80
|
+
optionId: string;
|
|
81
|
+
};
|
|
82
|
+
export interface AcpLaunch {
|
|
83
|
+
command: string;
|
|
84
|
+
args?: string[];
|
|
85
|
+
env?: Record<string, string>;
|
|
86
|
+
cwd?: string;
|
|
87
|
+
/**
|
|
88
|
+
* Answer the agent's file reads and writes. Supplied, the `fs` capability
|
|
89
|
+
* is advertised; absent, the agent uses its own tools for files.
|
|
90
|
+
*/
|
|
91
|
+
fs?: AcpFileSystem;
|
|
92
|
+
}
|
|
93
|
+
export interface AcpFileSystem {
|
|
94
|
+
/** `line` is 1-based; `limit` caps the lines returned. */
|
|
95
|
+
read(path: string, line?: number, limit?: number): Promise<string>;
|
|
96
|
+
write(path: string, content: string): Promise<void>;
|
|
97
|
+
}
|
|
98
|
+
/** An MCP server as ACP's `session/new` takes it. */
|
|
99
|
+
export type AcpMcpServer = {
|
|
100
|
+
name: string;
|
|
101
|
+
command: string;
|
|
102
|
+
args: string[];
|
|
103
|
+
env: Array<{
|
|
104
|
+
name: string;
|
|
105
|
+
value: string;
|
|
106
|
+
}>;
|
|
107
|
+
} | {
|
|
108
|
+
type: "http";
|
|
109
|
+
name: string;
|
|
110
|
+
url: string;
|
|
111
|
+
headers: Array<{
|
|
112
|
+
name: string;
|
|
113
|
+
value: string;
|
|
114
|
+
}>;
|
|
115
|
+
};
|
|
116
|
+
export interface AcpHandlers {
|
|
117
|
+
onUpdate?(update: AcpUpdate): void;
|
|
118
|
+
/** Answer a permission question. With no handler, every question is refused. */
|
|
119
|
+
onPermission?(request: AcpPermissionRequest): Promise<AcpPermissionOutcome>;
|
|
120
|
+
}
|
|
121
|
+
/** An error the agent returned, with its JSON-RPC code. */
|
|
122
|
+
export declare class AcpError extends Error {
|
|
123
|
+
readonly code: number;
|
|
124
|
+
readonly data?: unknown;
|
|
125
|
+
constructor(message: string, code: number, data?: unknown);
|
|
126
|
+
}
|
|
127
|
+
export declare class AcpClient {
|
|
128
|
+
private readonly proc;
|
|
129
|
+
private readonly pending;
|
|
130
|
+
private seq;
|
|
131
|
+
private stderr;
|
|
132
|
+
private closed;
|
|
133
|
+
private exitError?;
|
|
134
|
+
/** Prompt-scoped handlers; `session/update` belongs to whoever is prompting. */
|
|
135
|
+
private handlers;
|
|
136
|
+
private readonly fs?;
|
|
137
|
+
authMethods: Array<{
|
|
138
|
+
id: string;
|
|
139
|
+
name?: string;
|
|
140
|
+
}>;
|
|
141
|
+
/** What the agent said it can do, from `initialize`. */
|
|
142
|
+
capabilities: {
|
|
143
|
+
loadSession?: boolean;
|
|
144
|
+
mcpCapabilities?: {
|
|
145
|
+
http?: boolean;
|
|
146
|
+
};
|
|
147
|
+
};
|
|
148
|
+
constructor(launch: AcpLaunch);
|
|
149
|
+
/** Handshake. Resolves with the agent's advertised login methods. */
|
|
150
|
+
initialize(clientName?: string, clientVersion?: string): Promise<void>;
|
|
151
|
+
newSession(cwd: string, mcpServers?: AcpMcpServer[]): Promise<string>;
|
|
152
|
+
/**
|
|
153
|
+
* Pick up an earlier session where it left off, for a follow-up. The agent
|
|
154
|
+
* replays the conversation as updates first; nobody is prompting yet, so
|
|
155
|
+
* those land on no handler and are dropped.
|
|
156
|
+
*/
|
|
157
|
+
loadSession(sessionId: string, cwd: string, mcpServers?: AcpMcpServer[]): Promise<void>;
|
|
158
|
+
/** HTTP servers only for an agent that said it takes them. */
|
|
159
|
+
private supported;
|
|
160
|
+
/**
|
|
161
|
+
* One turn: the prompt in, the agent's updates out through `handlers`, and
|
|
162
|
+
* its stop reason when the turn ends. Aborting sends `session/cancel`, after
|
|
163
|
+
* which the agent is expected to finish the turn with `cancelled`.
|
|
164
|
+
*/
|
|
165
|
+
prompt(sessionId: string, text: string, handlers: AcpHandlers, signal?: AbortSignal): Promise<AcpStopReason>;
|
|
166
|
+
close(): void;
|
|
167
|
+
private request;
|
|
168
|
+
private notify;
|
|
169
|
+
private send;
|
|
170
|
+
private receive;
|
|
171
|
+
private answer;
|
|
172
|
+
private fail;
|
|
173
|
+
private stderrTail;
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* How to start a command on this platform.
|
|
177
|
+
*
|
|
178
|
+
* On Windows `npx` is `npx.cmd`, a batch file, and Node refuses to spawn one
|
|
179
|
+
* without a shell (CVE-2024-27980). Through `cmd` it goes, then — quoted,
|
|
180
|
+
* since the shell joins the line itself and a path under "Program Files"
|
|
181
|
+
* would otherwise split in two. The arguments are fixed by the caller (a
|
|
182
|
+
* flag and a pinned package name), never text from a request, and quoted the
|
|
183
|
+
* same way all the same.
|
|
184
|
+
*/
|
|
185
|
+
export declare function spawnTarget(command: string, args: string[], platform?: NodeJS.Platform): {
|
|
186
|
+
command: string;
|
|
187
|
+
args: string[];
|
|
188
|
+
shell: boolean;
|
|
189
|
+
};
|
|
190
|
+
/** The refusing answer among an agent's options: once, never "always". */
|
|
191
|
+
export declare function refuse(options: AcpPermissionOption[]): AcpPermissionOutcome;
|
|
192
|
+
/** The allowing answer among an agent's options, once rather than always. */
|
|
193
|
+
export declare function allowOnce(options: AcpPermissionOption[]): AcpPermissionOutcome;
|
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
import { spawn } from "node:child_process";
|
|
2
|
+
/**
|
|
3
|
+
* A client for the Agent Client Protocol (agentclientprotocol.com).
|
|
4
|
+
*
|
|
5
|
+
* ACP is how an editor drives an agent it did not write: the agent runs as a
|
|
6
|
+
* child process and the two exchange JSON-RPC 2.0 messages, one per line, over
|
|
7
|
+
* its stdin and stdout. This is the client half, written against the baseline
|
|
8
|
+
* methods only — `initialize`, `session/new`, `session/prompt`,
|
|
9
|
+
* `session/cancel`, the `session/update` stream and
|
|
10
|
+
* `session/request_permission` — because the agents that speak it add
|
|
11
|
+
* extensions faster than any one client should chase.
|
|
12
|
+
*
|
|
13
|
+
* Deliberately small and dependency-free rather than built on the SDK: the
|
|
14
|
+
* surface used here is a few hundred lines of protocol, and owning it keeps
|
|
15
|
+
* the fake agent in the tests and the real one on the same footing.
|
|
16
|
+
*
|
|
17
|
+
* What it advertises is a choice. `fs`, when the caller supplies a file
|
|
18
|
+
* system, so the agent's reads and writes pass through this harness's
|
|
19
|
+
* workspace policy instead of around it. No `terminal`: the agent runs its
|
|
20
|
+
* own commands. And no `auth` capability: an
|
|
21
|
+
* agent that needs signing in is told so and left to its own login, never
|
|
22
|
+
* offered one from here — for Claude Code that is the difference between the
|
|
23
|
+
* user signing in to Claude Code and OHarness brokering a Claude login.
|
|
24
|
+
*/
|
|
25
|
+
export const ACP_PROTOCOL_VERSION = 1;
|
|
26
|
+
/** JSON-RPC error code ACP uses for "this agent needs signing in". */
|
|
27
|
+
export const ACP_AUTH_REQUIRED = -32000;
|
|
28
|
+
/** An error the agent returned, with its JSON-RPC code. */
|
|
29
|
+
export class AcpError extends Error {
|
|
30
|
+
code;
|
|
31
|
+
data;
|
|
32
|
+
constructor(message, code, data) {
|
|
33
|
+
super(message);
|
|
34
|
+
this.name = "AcpError";
|
|
35
|
+
this.code = code;
|
|
36
|
+
this.data = data;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
export class AcpClient {
|
|
40
|
+
proc;
|
|
41
|
+
pending = new Map();
|
|
42
|
+
seq = 0;
|
|
43
|
+
stderr = "";
|
|
44
|
+
closed = false;
|
|
45
|
+
exitError;
|
|
46
|
+
/** Prompt-scoped handlers; `session/update` belongs to whoever is prompting. */
|
|
47
|
+
handlers = {};
|
|
48
|
+
fs;
|
|
49
|
+
authMethods = [];
|
|
50
|
+
/** What the agent said it can do, from `initialize`. */
|
|
51
|
+
capabilities = {};
|
|
52
|
+
constructor(launch) {
|
|
53
|
+
if (launch.fs)
|
|
54
|
+
this.fs = launch.fs;
|
|
55
|
+
const target = spawnTarget(launch.command, launch.args ?? []);
|
|
56
|
+
this.proc = spawn(target.command, target.args, {
|
|
57
|
+
cwd: launch.cwd,
|
|
58
|
+
env: { ...process.env, ...launch.env },
|
|
59
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
60
|
+
...(target.shell ? { shell: true, windowsHide: true } : {}),
|
|
61
|
+
});
|
|
62
|
+
this.proc.stderr.setEncoding("utf8");
|
|
63
|
+
// Kept for the error a failed start reports; logs are the agent's own.
|
|
64
|
+
this.proc.stderr.on("data", (chunk) => {
|
|
65
|
+
this.stderr = (this.stderr + chunk).slice(-4_000);
|
|
66
|
+
});
|
|
67
|
+
this.proc.on("error", (err) => this.fail(err));
|
|
68
|
+
this.proc.on("exit", (code, signal) => {
|
|
69
|
+
this.fail(new Error(`the agent exited (${signal ?? `code ${code}`})${this.stderrTail()}`));
|
|
70
|
+
});
|
|
71
|
+
// One message per line. Split by hand: a chunk can end mid-message.
|
|
72
|
+
let buffered = "";
|
|
73
|
+
this.proc.stdout.setEncoding("utf8");
|
|
74
|
+
this.proc.stdout.on("data", (chunk) => {
|
|
75
|
+
buffered += chunk;
|
|
76
|
+
let newline;
|
|
77
|
+
while ((newline = buffered.indexOf("\n")) !== -1) {
|
|
78
|
+
const line = buffered.slice(0, newline);
|
|
79
|
+
buffered = buffered.slice(newline + 1);
|
|
80
|
+
this.receive(line);
|
|
81
|
+
}
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
/** Handshake. Resolves with the agent's advertised login methods. */
|
|
85
|
+
async initialize(clientName = "OHarness", clientVersion = "0") {
|
|
86
|
+
const files = Boolean(this.fs);
|
|
87
|
+
const result = (await this.request("initialize", {
|
|
88
|
+
protocolVersion: ACP_PROTOCOL_VERSION,
|
|
89
|
+
clientCapabilities: { fs: { readTextFile: files, writeTextFile: files }, terminal: false },
|
|
90
|
+
clientInfo: { name: clientName, version: clientVersion },
|
|
91
|
+
}));
|
|
92
|
+
if (result.protocolVersion !== undefined && result.protocolVersion !== ACP_PROTOCOL_VERSION) {
|
|
93
|
+
throw new Error(`the agent speaks ACP version ${result.protocolVersion}, not ${ACP_PROTOCOL_VERSION}`);
|
|
94
|
+
}
|
|
95
|
+
this.authMethods = result.authMethods ?? [];
|
|
96
|
+
this.capabilities = result.agentCapabilities ?? {};
|
|
97
|
+
}
|
|
98
|
+
async newSession(cwd, mcpServers = []) {
|
|
99
|
+
const result = (await this.request("session/new", { cwd, mcpServers: this.supported(mcpServers) }));
|
|
100
|
+
if (!result.sessionId)
|
|
101
|
+
throw new Error("the agent started no session");
|
|
102
|
+
return result.sessionId;
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Pick up an earlier session where it left off, for a follow-up. The agent
|
|
106
|
+
* replays the conversation as updates first; nobody is prompting yet, so
|
|
107
|
+
* those land on no handler and are dropped.
|
|
108
|
+
*/
|
|
109
|
+
async loadSession(sessionId, cwd, mcpServers = []) {
|
|
110
|
+
if (!this.capabilities.loadSession)
|
|
111
|
+
throw new Error("the agent cannot load sessions");
|
|
112
|
+
this.handlers = {};
|
|
113
|
+
await this.request("session/load", { sessionId, cwd, mcpServers: this.supported(mcpServers) });
|
|
114
|
+
}
|
|
115
|
+
/** HTTP servers only for an agent that said it takes them. */
|
|
116
|
+
supported(servers) {
|
|
117
|
+
return this.capabilities.mcpCapabilities?.http ? servers : servers.filter((server) => !("type" in server));
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* One turn: the prompt in, the agent's updates out through `handlers`, and
|
|
121
|
+
* its stop reason when the turn ends. Aborting sends `session/cancel`, after
|
|
122
|
+
* which the agent is expected to finish the turn with `cancelled`.
|
|
123
|
+
*/
|
|
124
|
+
async prompt(sessionId, text, handlers, signal) {
|
|
125
|
+
this.handlers = handlers;
|
|
126
|
+
const cancel = () => this.notify("session/cancel", { sessionId });
|
|
127
|
+
signal?.addEventListener("abort", cancel, { once: true });
|
|
128
|
+
try {
|
|
129
|
+
const result = (await this.request("session/prompt", {
|
|
130
|
+
sessionId,
|
|
131
|
+
prompt: [{ type: "text", text }],
|
|
132
|
+
}));
|
|
133
|
+
return result.stopReason ?? "end_turn";
|
|
134
|
+
}
|
|
135
|
+
finally {
|
|
136
|
+
signal?.removeEventListener("abort", cancel);
|
|
137
|
+
this.handlers = {};
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
close() {
|
|
141
|
+
if (this.closed)
|
|
142
|
+
return;
|
|
143
|
+
this.closed = true;
|
|
144
|
+
this.proc.stdin.end();
|
|
145
|
+
// A grace period to exit on its own, then a firmer word.
|
|
146
|
+
const timer = setTimeout(() => this.proc.kill("SIGKILL"), 2_000);
|
|
147
|
+
timer.unref?.();
|
|
148
|
+
this.proc.kill("SIGTERM");
|
|
149
|
+
}
|
|
150
|
+
request(method, params) {
|
|
151
|
+
if (this.exitError)
|
|
152
|
+
return Promise.reject(this.exitError);
|
|
153
|
+
const id = ++this.seq;
|
|
154
|
+
return new Promise((resolve, reject) => {
|
|
155
|
+
this.pending.set(id, { resolve, reject });
|
|
156
|
+
this.send({ jsonrpc: "2.0", id, method, params });
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
notify(method, params) {
|
|
160
|
+
if (!this.exitError)
|
|
161
|
+
this.send({ jsonrpc: "2.0", method, params });
|
|
162
|
+
}
|
|
163
|
+
send(message) {
|
|
164
|
+
this.proc.stdin.write(`${JSON.stringify(message)}\n`);
|
|
165
|
+
}
|
|
166
|
+
receive(line) {
|
|
167
|
+
if (!line.trim())
|
|
168
|
+
return;
|
|
169
|
+
let message;
|
|
170
|
+
try {
|
|
171
|
+
message = JSON.parse(line);
|
|
172
|
+
}
|
|
173
|
+
catch {
|
|
174
|
+
// Not a protocol line — an agent printing to stdout by mistake.
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
// A response to one of ours.
|
|
178
|
+
if (message.method === undefined && message.id !== undefined) {
|
|
179
|
+
const waiting = this.pending.get(Number(message.id));
|
|
180
|
+
if (!waiting)
|
|
181
|
+
return;
|
|
182
|
+
this.pending.delete(Number(message.id));
|
|
183
|
+
if (message.error)
|
|
184
|
+
waiting.reject(new AcpError(message.error.message, message.error.code, message.error.data));
|
|
185
|
+
else
|
|
186
|
+
waiting.resolve(message.result ?? {});
|
|
187
|
+
return;
|
|
188
|
+
}
|
|
189
|
+
// A notification from the agent.
|
|
190
|
+
if (message.id === undefined) {
|
|
191
|
+
if (message.method === "session/update") {
|
|
192
|
+
const update = message.params?.update;
|
|
193
|
+
if (update)
|
|
194
|
+
this.handlers.onUpdate?.(update);
|
|
195
|
+
}
|
|
196
|
+
return;
|
|
197
|
+
}
|
|
198
|
+
// A request from the agent.
|
|
199
|
+
void this.answer(message.id, message.method ?? "", message.params);
|
|
200
|
+
}
|
|
201
|
+
async answer(id, method, params) {
|
|
202
|
+
if (method === "session/request_permission") {
|
|
203
|
+
let outcome = { outcome: "cancelled" };
|
|
204
|
+
try {
|
|
205
|
+
const request = params;
|
|
206
|
+
outcome = this.handlers.onPermission
|
|
207
|
+
? await this.handlers.onPermission(request)
|
|
208
|
+
: refuse(request.options);
|
|
209
|
+
}
|
|
210
|
+
catch {
|
|
211
|
+
// A question nobody could answer is a no.
|
|
212
|
+
}
|
|
213
|
+
this.send({ jsonrpc: "2.0", id, result: { outcome } });
|
|
214
|
+
return;
|
|
215
|
+
}
|
|
216
|
+
if (this.fs && (method === "fs/read_text_file" || method === "fs/write_text_file")) {
|
|
217
|
+
const request = params;
|
|
218
|
+
try {
|
|
219
|
+
if (typeof request.path !== "string")
|
|
220
|
+
throw new Error("no path");
|
|
221
|
+
if (method === "fs/read_text_file") {
|
|
222
|
+
const content = await this.fs.read(request.path, request.line ?? undefined, request.limit ?? undefined);
|
|
223
|
+
this.send({ jsonrpc: "2.0", id, result: { content } });
|
|
224
|
+
}
|
|
225
|
+
else {
|
|
226
|
+
await this.fs.write(request.path, request.content ?? "");
|
|
227
|
+
this.send({ jsonrpc: "2.0", id, result: {} });
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
catch (err) {
|
|
231
|
+
// The workspace policy refusing, a missing file: the agent is told why.
|
|
232
|
+
this.send({ jsonrpc: "2.0", id, error: { code: -32603, message: err instanceof Error ? err.message : String(err) } });
|
|
233
|
+
}
|
|
234
|
+
return;
|
|
235
|
+
}
|
|
236
|
+
// terminal/* and the rest were not advertised, so asking is an error.
|
|
237
|
+
this.send({ jsonrpc: "2.0", id, error: { code: -32601, message: `method not supported: ${method}` } });
|
|
238
|
+
}
|
|
239
|
+
fail(err) {
|
|
240
|
+
if (this.exitError)
|
|
241
|
+
return;
|
|
242
|
+
this.exitError = err;
|
|
243
|
+
for (const waiting of this.pending.values())
|
|
244
|
+
waiting.reject(err);
|
|
245
|
+
this.pending.clear();
|
|
246
|
+
}
|
|
247
|
+
stderrTail() {
|
|
248
|
+
const tail = this.stderr.trim().split("\n").slice(-3).join(" ").trim();
|
|
249
|
+
return tail ? `: ${tail}` : "";
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
/**
|
|
253
|
+
* How to start a command on this platform.
|
|
254
|
+
*
|
|
255
|
+
* On Windows `npx` is `npx.cmd`, a batch file, and Node refuses to spawn one
|
|
256
|
+
* without a shell (CVE-2024-27980). Through `cmd` it goes, then — quoted,
|
|
257
|
+
* since the shell joins the line itself and a path under "Program Files"
|
|
258
|
+
* would otherwise split in two. The arguments are fixed by the caller (a
|
|
259
|
+
* flag and a pinned package name), never text from a request, and quoted the
|
|
260
|
+
* same way all the same.
|
|
261
|
+
*/
|
|
262
|
+
export function spawnTarget(command, args, platform = process.platform) {
|
|
263
|
+
if (platform === "win32" && /\.(cmd|bat)$/i.test(command)) {
|
|
264
|
+
const quote = (value) => (/[\s"&|<>^]/.test(value) ? `"${value.replace(/"/g, '""')}"` : value);
|
|
265
|
+
return { command: quote(command), args: args.map(quote), shell: true };
|
|
266
|
+
}
|
|
267
|
+
return { command, args, shell: false };
|
|
268
|
+
}
|
|
269
|
+
/** The refusing answer among an agent's options: once, never "always". */
|
|
270
|
+
export function refuse(options) {
|
|
271
|
+
const reject = options.find((option) => option.kind === "reject_once") ?? options.find((option) => option.kind === "reject_always");
|
|
272
|
+
return reject ? { outcome: "selected", optionId: reject.optionId } : { outcome: "cancelled" };
|
|
273
|
+
}
|
|
274
|
+
/** The allowing answer among an agent's options, once rather than always. */
|
|
275
|
+
export function allowOnce(options) {
|
|
276
|
+
const allow = options.find((option) => option.kind === "allow_once") ?? options.find((option) => option.kind === "allow_always");
|
|
277
|
+
return allow ? { outcome: "selected", optionId: allow.optionId } : { outcome: "cancelled" };
|
|
278
|
+
}
|
|
279
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/acp/client.ts"],"names":[],"mappings":"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"}
|