@harness-control/runner 0.1.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/LICENSE +202 -0
- package/README.md +21 -0
- package/dist/audit/index.d.ts +18 -0
- package/dist/audit/index.js +28 -0
- package/dist/config/index.d.ts +179 -0
- package/dist/config/index.js +124 -0
- package/dist/connection/index.d.ts +2 -0
- package/dist/connection/index.js +2 -0
- package/dist/connection/runner-connection.d.ts +22 -0
- package/dist/connection/runner-connection.js +631 -0
- package/dist/harnesses/adapters/providers/claude-runtime.d.ts +5 -0
- package/dist/harnesses/adapters/providers/claude-runtime.js +186 -0
- package/dist/harnesses/adapters/providers/claude.d.ts +24 -0
- package/dist/harnesses/adapters/providers/claude.js +189 -0
- package/dist/harnesses/adapters/providers/cli-process.d.ts +44 -0
- package/dist/harnesses/adapters/providers/cli-process.js +195 -0
- package/dist/harnesses/adapters/providers/codex-models.d.ts +4 -0
- package/dist/harnesses/adapters/providers/codex-models.js +62 -0
- package/dist/harnesses/adapters/providers/codex-rpc.d.ts +21 -0
- package/dist/harnesses/adapters/providers/codex-rpc.js +114 -0
- package/dist/harnesses/adapters/providers/codex-runtime.d.ts +3 -0
- package/dist/harnesses/adapters/providers/codex-runtime.js +267 -0
- package/dist/harnesses/adapters/providers/codex.d.ts +22 -0
- package/dist/harnesses/adapters/providers/codex.js +161 -0
- package/dist/harnesses/adapters/providers/mock.d.ts +13 -0
- package/dist/harnesses/adapters/providers/mock.js +64 -0
- package/dist/harnesses/adapters/providers/native-process.d.ts +9 -0
- package/dist/harnesses/adapters/providers/native-process.js +41 -0
- package/dist/harnesses/adapters/providers/native-turn.d.ts +17 -0
- package/dist/harnesses/adapters/providers/native-turn.js +139 -0
- package/dist/harnesses/adapters/providers/opencode.d.ts +44 -0
- package/dist/harnesses/adapters/providers/opencode.js +416 -0
- package/dist/harnesses/adapters/providers/shared.d.ts +9 -0
- package/dist/harnesses/adapters/providers/shared.js +97 -0
- package/dist/harnesses/adapters/registry.d.ts +12 -0
- package/dist/harnesses/adapters/registry.js +47 -0
- package/dist/harnesses/adapters/types.d.ts +54 -0
- package/dist/harnesses/adapters/types.js +9 -0
- package/dist/harnesses/adapters.d.ts +8 -0
- package/dist/harnesses/adapters.js +8 -0
- package/dist/harnesses/index.d.ts +93 -0
- package/dist/harnesses/index.js +620 -0
- package/dist/host/provider-registry.d.ts +34 -0
- package/dist/host/provider-registry.js +162 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +201 -0
- package/dist/local-actions/dispatcher.d.ts +28 -0
- package/dist/local-actions/dispatcher.js +407 -0
- package/dist/local-actions/executors.d.ts +159 -0
- package/dist/local-actions/executors.js +1103 -0
- package/dist/local-actions/index.d.ts +74 -0
- package/dist/local-actions/index.js +275 -0
- package/dist/logs/index.d.ts +6 -0
- package/dist/logs/index.js +9 -0
- package/dist/mcp/McpAttachmentClient.d.ts +111 -0
- package/dist/mcp/McpAttachmentClient.js +345 -0
- package/dist/mcp/McpProxyServer.d.ts +18 -0
- package/dist/mcp/McpProxyServer.js +188 -0
- package/dist/mcp/McpStdioProfileClient.d.ts +19 -0
- package/dist/mcp/McpStdioProfileClient.js +91 -0
- package/dist/mcp/index.d.ts +5 -0
- package/dist/mcp/index.js +5 -0
- package/dist/mcp/redaction.d.ts +3 -0
- package/dist/mcp/redaction.js +40 -0
- package/dist/pairing/index.d.ts +38 -0
- package/dist/pairing/index.js +180 -0
- package/dist/state/index.d.ts +76 -0
- package/dist/state/index.js +242 -0
- package/dist/workspaces/index.d.ts +13 -0
- package/dist/workspaces/index.js +110 -0
- package/package.json +76 -0
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { normalizeProviderModels } from "./shared.js";
|
|
2
|
+
export class MockHarnessAdapter {
|
|
3
|
+
driverKind = "mock";
|
|
4
|
+
async probe(provider) {
|
|
5
|
+
return {
|
|
6
|
+
provider_instance_id: provider.id,
|
|
7
|
+
driver_kind: provider.driver_kind,
|
|
8
|
+
installed: true,
|
|
9
|
+
available: true,
|
|
10
|
+
status: "ready",
|
|
11
|
+
version: "0.0.0-mock",
|
|
12
|
+
models: normalizeProviderModels(provider.models),
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
async validateStart() {
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
async startSession(input) {
|
|
19
|
+
return {
|
|
20
|
+
adapter_session_id: input.payload.session_id,
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
async sendTurn(input) {
|
|
24
|
+
return [
|
|
25
|
+
{
|
|
26
|
+
event_type: "turn.started",
|
|
27
|
+
turn_id: input.payload.turn_id,
|
|
28
|
+
data: {
|
|
29
|
+
provider_instance_id: input.provider.id,
|
|
30
|
+
input_length: input.payload.input.length,
|
|
31
|
+
...(input.payload.model_selection ? { model_selection: input.payload.model_selection } : {}),
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
event_type: "turn.completed",
|
|
36
|
+
turn_id: input.payload.turn_id,
|
|
37
|
+
data: {
|
|
38
|
+
status: "accepted",
|
|
39
|
+
final_output: {
|
|
40
|
+
final_text: "",
|
|
41
|
+
},
|
|
42
|
+
},
|
|
43
|
+
},
|
|
44
|
+
];
|
|
45
|
+
}
|
|
46
|
+
async cancelTurn(input) {
|
|
47
|
+
return [
|
|
48
|
+
{
|
|
49
|
+
event_type: "turn.cancelled",
|
|
50
|
+
turn_id: input.turnId,
|
|
51
|
+
data: {
|
|
52
|
+
status: "cancelled",
|
|
53
|
+
final_output: {
|
|
54
|
+
exit_reason: "cancel_requested",
|
|
55
|
+
},
|
|
56
|
+
},
|
|
57
|
+
},
|
|
58
|
+
];
|
|
59
|
+
}
|
|
60
|
+
async stopSession() {
|
|
61
|
+
return [];
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
//# sourceMappingURL=mock.js.map
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { type ChildProcessWithoutNullStreams } from "node:child_process";
|
|
2
|
+
export declare class NativeProcess {
|
|
3
|
+
#private;
|
|
4
|
+
readonly child: ChildProcessWithoutNullStreams;
|
|
5
|
+
readonly closed: Promise<void>;
|
|
6
|
+
constructor(executable: string, args: string[], cwd: string, env: NodeJS.ProcessEnv);
|
|
7
|
+
stop(): Promise<void>;
|
|
8
|
+
}
|
|
9
|
+
//# sourceMappingURL=native-process.d.ts.map
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { spawn } from "node:child_process";
|
|
2
|
+
import { killChildProcess } from "./cli-process.js";
|
|
3
|
+
export class NativeProcess {
|
|
4
|
+
child;
|
|
5
|
+
closed;
|
|
6
|
+
#closed = false;
|
|
7
|
+
#stopping;
|
|
8
|
+
constructor(executable, args, cwd, env) {
|
|
9
|
+
this.child = spawn(executable, args, {
|
|
10
|
+
cwd,
|
|
11
|
+
env,
|
|
12
|
+
stdio: "pipe",
|
|
13
|
+
detached: process.platform !== "win32",
|
|
14
|
+
});
|
|
15
|
+
this.child.on("error", () => { }); // The close event also fires after spawn errors.
|
|
16
|
+
this.child.stdin.on("error", () => { }); // Runtime detects closure; avoid an unhandled EPIPE.
|
|
17
|
+
this.closed = new Promise((resolve) => {
|
|
18
|
+
this.child.once("close", () => {
|
|
19
|
+
this.#closed = true;
|
|
20
|
+
resolve();
|
|
21
|
+
});
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
stop() {
|
|
25
|
+
this.#stopping ??= this.#stop();
|
|
26
|
+
return this.#stopping;
|
|
27
|
+
}
|
|
28
|
+
async #stop() {
|
|
29
|
+
if (this.#closed)
|
|
30
|
+
return;
|
|
31
|
+
killChildProcess(this.child, "SIGTERM");
|
|
32
|
+
const forceKill = setTimeout(() => killChildProcess(this.child, "SIGKILL"), 1_000);
|
|
33
|
+
try {
|
|
34
|
+
await this.closed;
|
|
35
|
+
}
|
|
36
|
+
finally {
|
|
37
|
+
clearTimeout(forceKill);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
//# sourceMappingURL=native-process.js.map
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { HarnessExecutionCapabilities, HarnessModelSelection, HarnessTurnFinalOutput } from "@harness-control/protocol";
|
|
2
|
+
import { type HarnessAdapterEvent, type HarnessAdapterStartInput, type HarnessAdapterTurnInput } from "../types.js";
|
|
3
|
+
export declare function nativeExecutionCapabilities(driver: "codex" | "claude"): HarnessExecutionCapabilities;
|
|
4
|
+
export declare function validateNativeStart(input: HarnessAdapterStartInput, driver: "codex" | "claude"): void;
|
|
5
|
+
export type NativeTurn = (input: HarnessAdapterTurnInput, signal: AbortSignal, emit: (event: HarnessAdapterEvent) => void) => Promise<HarnessTurnFinalOutput>;
|
|
6
|
+
/** Owns terminal decisions after the provider runtime has finished cleanup. */
|
|
7
|
+
export declare class NativeTurns {
|
|
8
|
+
#private;
|
|
9
|
+
readonly driver: string;
|
|
10
|
+
readonly timeoutMs: number;
|
|
11
|
+
constructor(driver: string, timeoutMs: number);
|
|
12
|
+
run(input: HarnessAdapterTurnInput, execute: NativeTurn): Promise<HarnessAdapterEvent[]>;
|
|
13
|
+
cancel(sessionId: string, turnId?: string): Promise<HarnessAdapterEvent[]>;
|
|
14
|
+
stop(sessionId: string): Promise<HarnessAdapterEvent[]>;
|
|
15
|
+
}
|
|
16
|
+
export declare function selectedEffort(selection: HarnessModelSelection, driver: "codex" | "claude"): string | undefined;
|
|
17
|
+
//# sourceMappingURL=native-turn.d.ts.map
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import { HarnessAdapterError, } from "../types.js";
|
|
2
|
+
import { turnFailedEvent } from "./shared.js";
|
|
3
|
+
export function nativeExecutionCapabilities(driver) {
|
|
4
|
+
return {
|
|
5
|
+
streaming: true,
|
|
6
|
+
multi_turn: false,
|
|
7
|
+
session_continuation: false,
|
|
8
|
+
approval_policies: ["full_access"],
|
|
9
|
+
sandbox_modes: driver === "codex"
|
|
10
|
+
? ["read_only", "workspace_write", "danger_full_access"]
|
|
11
|
+
: ["danger_full_access"],
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
export function validateNativeStart(input, driver) {
|
|
15
|
+
const capabilities = nativeExecutionCapabilities(driver);
|
|
16
|
+
if (input.payload.continue_session && !capabilities.session_continuation)
|
|
17
|
+
throw new HarnessAdapterError("continuation_unsupported", "Native continuation is not supported by this runner profile.");
|
|
18
|
+
if (!capabilities.approval_policies.includes(input.payload.approval_policy))
|
|
19
|
+
throw new HarnessAdapterError("approval_policy_unsupported", "Interactive approval policies are not supported by this runner profile.");
|
|
20
|
+
if (!capabilities.sandbox_modes.includes(input.payload.sandbox_mode))
|
|
21
|
+
throw new HarnessAdapterError("sandbox_unsupported", "The requested filesystem containment is not supported by this adapter.");
|
|
22
|
+
if (input.provider.launch_args.length)
|
|
23
|
+
throw new HarnessAdapterError("launch_args_unsupported", "Native drivers require structured configuration instead of launch arguments.");
|
|
24
|
+
selectedEffort(input.payload.model_selection, driver);
|
|
25
|
+
}
|
|
26
|
+
/** Owns terminal decisions after the provider runtime has finished cleanup. */
|
|
27
|
+
export class NativeTurns {
|
|
28
|
+
driver;
|
|
29
|
+
timeoutMs;
|
|
30
|
+
#active = new Map();
|
|
31
|
+
#usedSessions = new Set();
|
|
32
|
+
constructor(driver, timeoutMs) {
|
|
33
|
+
this.driver = driver;
|
|
34
|
+
this.timeoutMs = timeoutMs;
|
|
35
|
+
}
|
|
36
|
+
async run(input, execute) {
|
|
37
|
+
const { session_id: sessionId, turn_id: turnId } = input.payload;
|
|
38
|
+
if (this.#active.has(sessionId)) {
|
|
39
|
+
throw new HarnessAdapterError(`${this.driver}_turn_in_progress`, "The session already has an active turn.");
|
|
40
|
+
}
|
|
41
|
+
if (this.#usedSessions.has(sessionId)) {
|
|
42
|
+
throw new HarnessAdapterError("session_turn_limit", "This provider profile supports one turn per session; native multi-turn sessions are not implemented.");
|
|
43
|
+
}
|
|
44
|
+
this.#usedSessions.add(sessionId);
|
|
45
|
+
const controller = new AbortController();
|
|
46
|
+
let finish;
|
|
47
|
+
const done = new Promise((resolve) => {
|
|
48
|
+
finish = resolve;
|
|
49
|
+
});
|
|
50
|
+
this.#active.set(sessionId, { id: turnId, controller, done });
|
|
51
|
+
const timeout = setTimeout(() => controller.abort("timeout"), this.timeoutMs);
|
|
52
|
+
const events = [];
|
|
53
|
+
const emit = (event) => {
|
|
54
|
+
if (controller.signal.aborted)
|
|
55
|
+
return;
|
|
56
|
+
if (input.emitEvent)
|
|
57
|
+
input.emitEvent(event);
|
|
58
|
+
else
|
|
59
|
+
events.push(event);
|
|
60
|
+
};
|
|
61
|
+
try {
|
|
62
|
+
const output = await execute(input, controller.signal, emit);
|
|
63
|
+
if (!controller.signal.aborted) {
|
|
64
|
+
events.push({
|
|
65
|
+
event_type: "turn.completed",
|
|
66
|
+
turn_id: turnId,
|
|
67
|
+
data: { status: "completed", final_output: output },
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
catch (error) {
|
|
72
|
+
if (!controller.signal.aborted) {
|
|
73
|
+
events.push(turnFailedEvent(turnId, "provider_error", error instanceof HarnessAdapterError
|
|
74
|
+
? error.code
|
|
75
|
+
: `${this.driver}_runtime_failed`, error instanceof HarnessAdapterError
|
|
76
|
+
? error.message
|
|
77
|
+
: "Provider runtime failed; inspect local diagnostics.", false));
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
finally {
|
|
81
|
+
clearTimeout(timeout);
|
|
82
|
+
if (controller.signal.aborted) {
|
|
83
|
+
events.push(controller.signal.reason === "timeout"
|
|
84
|
+
? turnFailedEvent(turnId, "timeout", `${this.driver}_turn_timeout`, "Provider turn timed out.", false)
|
|
85
|
+
: {
|
|
86
|
+
event_type: "turn.cancelled",
|
|
87
|
+
turn_id: turnId,
|
|
88
|
+
data: {
|
|
89
|
+
status: "cancelled",
|
|
90
|
+
final_output: { exit_reason: "cancel_requested" },
|
|
91
|
+
},
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
try {
|
|
95
|
+
if (input.emitEvent) {
|
|
96
|
+
for (const event of events)
|
|
97
|
+
input.emitEvent(event);
|
|
98
|
+
events.length = 0;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
finally {
|
|
102
|
+
this.#active.delete(sessionId);
|
|
103
|
+
finish();
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
return events;
|
|
107
|
+
}
|
|
108
|
+
async cancel(sessionId, turnId) {
|
|
109
|
+
const active = this.#active.get(sessionId);
|
|
110
|
+
if (active && (turnId === undefined || active.id === turnId)) {
|
|
111
|
+
active.controller.abort("cancel_requested");
|
|
112
|
+
await active.done;
|
|
113
|
+
}
|
|
114
|
+
// The running turn owns the single terminal event, including cancellation.
|
|
115
|
+
return [];
|
|
116
|
+
}
|
|
117
|
+
async stop(sessionId) {
|
|
118
|
+
await this.cancel(sessionId);
|
|
119
|
+
this.#usedSessions.delete(sessionId);
|
|
120
|
+
return [];
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
export function selectedEffort(selection, driver) {
|
|
124
|
+
let effort;
|
|
125
|
+
for (const option of selection.options ?? []) {
|
|
126
|
+
const expected = driver === "codex" ? "reasoningEffort" : "effort";
|
|
127
|
+
const values = ["low", "medium", "high", "xhigh", "max"];
|
|
128
|
+
if (option.id !== expected ||
|
|
129
|
+
typeof option.value !== "string" ||
|
|
130
|
+
option.value.length === 0 ||
|
|
131
|
+
(driver === "claude" && !values.includes(option.value)) ||
|
|
132
|
+
effort !== undefined) {
|
|
133
|
+
throw new HarnessAdapterError("unsupported_model_option", "Unsupported or duplicate model option.");
|
|
134
|
+
}
|
|
135
|
+
effort = option.value;
|
|
136
|
+
}
|
|
137
|
+
return effort;
|
|
138
|
+
}
|
|
139
|
+
//# sourceMappingURL=native-turn.js.map
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import type { ProviderInstanceConfig } from "../../../config/index.js";
|
|
2
|
+
import type { ProviderDriverStatus } from "../../../host/provider-registry.js";
|
|
3
|
+
import type { HarnessAdapter, HarnessAdapterCancelInput, HarnessAdapterEvent, HarnessAdapterSession, HarnessAdapterStartInput, HarnessAdapterStopInput, HarnessAdapterTurnInput } from "../types.js";
|
|
4
|
+
type OpenCodeRuntimeStartInput = {
|
|
5
|
+
executable: string;
|
|
6
|
+
launchArgs: string[];
|
|
7
|
+
cwd: string;
|
|
8
|
+
env: Record<string, string>;
|
|
9
|
+
mcpServers: Record<string, {
|
|
10
|
+
type: "remote";
|
|
11
|
+
url: string;
|
|
12
|
+
enabled: true;
|
|
13
|
+
}>;
|
|
14
|
+
};
|
|
15
|
+
export type OpenCodeRuntimeTurnInput = {
|
|
16
|
+
turnId: string;
|
|
17
|
+
input: string;
|
|
18
|
+
model: string;
|
|
19
|
+
emitEvent: (event: HarnessAdapterEvent) => void;
|
|
20
|
+
};
|
|
21
|
+
export type OpenCodeRuntime = {
|
|
22
|
+
readonly sessionId: string;
|
|
23
|
+
sendTurn(input: OpenCodeRuntimeTurnInput): Promise<string>;
|
|
24
|
+
cancelTurn(): Promise<void>;
|
|
25
|
+
close(): Promise<void>;
|
|
26
|
+
};
|
|
27
|
+
export type OpenCodeRuntimeFactory = (input: OpenCodeRuntimeStartInput) => Promise<OpenCodeRuntime>;
|
|
28
|
+
export type OpenCodeHarnessAdapterOptions = {
|
|
29
|
+
runtimeFactory?: OpenCodeRuntimeFactory;
|
|
30
|
+
probeTimeoutMs?: number;
|
|
31
|
+
};
|
|
32
|
+
export declare class OpenCodeHarnessAdapter implements HarnessAdapter {
|
|
33
|
+
#private;
|
|
34
|
+
readonly driverKind = "opencode";
|
|
35
|
+
constructor(options?: OpenCodeHarnessAdapterOptions);
|
|
36
|
+
probe(provider: ProviderInstanceConfig): Promise<ProviderDriverStatus>;
|
|
37
|
+
validateStart(): Promise<void>;
|
|
38
|
+
startSession(input: HarnessAdapterStartInput): Promise<HarnessAdapterSession>;
|
|
39
|
+
sendTurn(input: HarnessAdapterTurnInput): Promise<HarnessAdapterEvent[]>;
|
|
40
|
+
cancelTurn(input: HarnessAdapterCancelInput): Promise<HarnessAdapterEvent[]>;
|
|
41
|
+
stopSession(input: HarnessAdapterStopInput): Promise<HarnessAdapterEvent[]>;
|
|
42
|
+
}
|
|
43
|
+
export {};
|
|
44
|
+
//# sourceMappingURL=opencode.d.ts.map
|