@rarebit-one/harness-kernel 0.5.1
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 +21 -0
- package/README.md +286 -0
- package/dist/agent.d.ts +71 -0
- package/dist/agent.d.ts.map +1 -0
- package/dist/agent.js +258 -0
- package/dist/agent.js.map +1 -0
- package/dist/connectors/mcpClient.d.ts +22 -0
- package/dist/connectors/mcpClient.d.ts.map +1 -0
- package/dist/connectors/mcpClient.js +63 -0
- package/dist/connectors/mcpClient.js.map +1 -0
- package/dist/context/types.d.ts +68 -0
- package/dist/context/types.d.ts.map +1 -0
- package/dist/context/types.js +43 -0
- package/dist/context/types.js.map +1 -0
- package/dist/engines/capability.d.ts +67 -0
- package/dist/engines/capability.d.ts.map +1 -0
- package/dist/engines/capability.js +73 -0
- package/dist/engines/capability.js.map +1 -0
- package/dist/engines/capabilityEmissions.d.ts +27 -0
- package/dist/engines/capabilityEmissions.d.ts.map +1 -0
- package/dist/engines/capabilityEmissions.js +37 -0
- package/dist/engines/capabilityEmissions.js.map +1 -0
- package/dist/engines/capabilityMcp.d.ts +23 -0
- package/dist/engines/capabilityMcp.d.ts.map +1 -0
- package/dist/engines/capabilityMcp.js +36 -0
- package/dist/engines/capabilityMcp.js.map +1 -0
- package/dist/engines/capabilityStdio.d.ts +46 -0
- package/dist/engines/capabilityStdio.d.ts.map +1 -0
- package/dist/engines/capabilityStdio.js +39 -0
- package/dist/engines/capabilityStdio.js.map +1 -0
- package/dist/engines/claudeCode.d.ts +73 -0
- package/dist/engines/claudeCode.d.ts.map +1 -0
- package/dist/engines/claudeCode.js +100 -0
- package/dist/engines/claudeCode.js.map +1 -0
- package/dist/engines/claudeCodeDriver.d.ts +14 -0
- package/dist/engines/claudeCodeDriver.d.ts.map +1 -0
- package/dist/engines/claudeCodeDriver.js +90 -0
- package/dist/engines/claudeCodeDriver.js.map +1 -0
- package/dist/engines/codex.d.ts +72 -0
- package/dist/engines/codex.d.ts.map +1 -0
- package/dist/engines/codex.js +157 -0
- package/dist/engines/codex.js.map +1 -0
- package/dist/engines/codexDriver.d.ts +43 -0
- package/dist/engines/codexDriver.d.ts.map +1 -0
- package/dist/engines/codexDriver.js +110 -0
- package/dist/engines/codexDriver.js.map +1 -0
- package/dist/engines/connectorMcp.d.ts +60 -0
- package/dist/engines/connectorMcp.d.ts.map +1 -0
- package/dist/engines/connectorMcp.js +137 -0
- package/dist/engines/connectorMcp.js.map +1 -0
- package/dist/engines/index.d.ts +33 -0
- package/dist/engines/index.d.ts.map +1 -0
- package/dist/engines/index.js +29 -0
- package/dist/engines/index.js.map +1 -0
- package/dist/engines/native.d.ts +55 -0
- package/dist/engines/native.d.ts.map +1 -0
- package/dist/engines/native.js +117 -0
- package/dist/engines/native.js.map +1 -0
- package/dist/engines/types.d.ts +107 -0
- package/dist/engines/types.d.ts.map +1 -0
- package/dist/engines/types.js +2 -0
- package/dist/engines/types.js.map +1 -0
- package/dist/events.d.ts +211 -0
- package/dist/events.d.ts.map +1 -0
- package/dist/events.js +69 -0
- package/dist/events.js.map +1 -0
- package/dist/index.d.ts +63 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +82 -0
- package/dist/index.js.map +1 -0
- package/dist/loop.d.ts +132 -0
- package/dist/loop.d.ts.map +1 -0
- package/dist/loop.js +77 -0
- package/dist/loop.js.map +1 -0
- package/dist/models/chat.d.ts +65 -0
- package/dist/models/chat.d.ts.map +1 -0
- package/dist/models/chat.js +66 -0
- package/dist/models/chat.js.map +1 -0
- package/dist/models/middleware.d.ts +63 -0
- package/dist/models/middleware.d.ts.map +1 -0
- package/dist/models/middleware.js +139 -0
- package/dist/models/middleware.js.map +1 -0
- package/dist/models/registry.d.ts +78 -0
- package/dist/models/registry.d.ts.map +1 -0
- package/dist/models/registry.js +0 -0
- package/dist/models/registry.js.map +1 -0
- package/dist/models/types.d.ts +149 -0
- package/dist/models/types.d.ts.map +1 -0
- package/dist/models/types.js +64 -0
- package/dist/models/types.js.map +1 -0
- package/dist/primitives/codeExec.d.ts +25 -0
- package/dist/primitives/codeExec.d.ts.map +1 -0
- package/dist/primitives/codeExec.js +69 -0
- package/dist/primitives/codeExec.js.map +1 -0
- package/dist/primitives/download.d.ts +19 -0
- package/dist/primitives/download.d.ts.map +1 -0
- package/dist/primitives/download.js +113 -0
- package/dist/primitives/download.js.map +1 -0
- package/dist/primitives/fs.d.ts +5 -0
- package/dist/primitives/fs.d.ts.map +1 -0
- package/dist/primitives/fs.js +59 -0
- package/dist/primitives/fs.js.map +1 -0
- package/dist/primitives/http.d.ts +100 -0
- package/dist/primitives/http.d.ts.map +1 -0
- package/dist/primitives/http.js +257 -0
- package/dist/primitives/http.js.map +1 -0
- package/dist/providers/anthropic.d.ts +15 -0
- package/dist/providers/anthropic.d.ts.map +1 -0
- package/dist/providers/anthropic.js +90 -0
- package/dist/providers/anthropic.js.map +1 -0
- package/dist/providers/clientOptions.d.ts +14 -0
- package/dist/providers/clientOptions.d.ts.map +1 -0
- package/dist/providers/clientOptions.js +26 -0
- package/dist/providers/clientOptions.js.map +1 -0
- package/dist/providers/index.d.ts +24 -0
- package/dist/providers/index.d.ts.map +1 -0
- package/dist/providers/index.js +51 -0
- package/dist/providers/index.js.map +1 -0
- package/dist/providers/mock.d.ts +25 -0
- package/dist/providers/mock.d.ts.map +1 -0
- package/dist/providers/mock.js +85 -0
- package/dist/providers/mock.js.map +1 -0
- package/dist/providers/openai.d.ts +32 -0
- package/dist/providers/openai.d.ts.map +1 -0
- package/dist/providers/openai.js +118 -0
- package/dist/providers/openai.js.map +1 -0
- package/dist/providers/openrouter.d.ts +29 -0
- package/dist/providers/openrouter.d.ts.map +1 -0
- package/dist/providers/openrouter.js +35 -0
- package/dist/providers/openrouter.js.map +1 -0
- package/dist/providers/types.d.ts +60 -0
- package/dist/providers/types.d.ts.map +1 -0
- package/dist/providers/types.js +2 -0
- package/dist/providers/types.js.map +1 -0
- package/dist/routing/staticResolver.d.ts +41 -0
- package/dist/routing/staticResolver.d.ts.map +1 -0
- package/dist/routing/staticResolver.js +67 -0
- package/dist/routing/staticResolver.js.map +1 -0
- package/dist/routing/types.d.ts +72 -0
- package/dist/routing/types.d.ts.map +1 -0
- package/dist/routing/types.js +11 -0
- package/dist/routing/types.js.map +1 -0
- package/dist/secrets.d.ts +8 -0
- package/dist/secrets.d.ts.map +1 -0
- package/dist/secrets.js +14 -0
- package/dist/secrets.js.map +1 -0
- package/dist/tools/metadata.d.ts +93 -0
- package/dist/tools/metadata.d.ts.map +1 -0
- package/dist/tools/metadata.js +49 -0
- package/dist/tools/metadata.js.map +1 -0
- package/dist/tools/modelTool.d.ts +35 -0
- package/dist/tools/modelTool.d.ts.map +1 -0
- package/dist/tools/modelTool.js +37 -0
- package/dist/tools/modelTool.js.map +1 -0
- package/dist/tools/registry.d.ts +65 -0
- package/dist/tools/registry.d.ts.map +1 -0
- package/dist/tools/registry.js +166 -0
- package/dist/tools/registry.js.map +1 -0
- package/dist/types.d.ts +71 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +10 -0
- package/dist/types.js.map +1 -0
- package/package.json +72 -0
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import type { ConnectorConfig } from "../types.js";
|
|
2
|
+
import type { AgentEngine, EngineContext, EngineResult, EngineSupport, RunSpec } from "./types.js";
|
|
3
|
+
import { type CapabilityContext, type CapabilityTool } from "./capability.js";
|
|
4
|
+
/**
|
|
5
|
+
* Driver-neutral options the engine derives from a {@link RunSpec} and hands to
|
|
6
|
+
* the Claude Code harness. The default driver maps these onto the Anthropic Agent
|
|
7
|
+
* SDK; tests inject a fake driver and assert this mapping.
|
|
8
|
+
*/
|
|
9
|
+
export interface ClaudeCodeOptions {
|
|
10
|
+
/** The task prompt (workflow prompt + inputs). */
|
|
11
|
+
prompt: string;
|
|
12
|
+
/** The prepared sandbox working tree — the harness's cwd; edits land here. */
|
|
13
|
+
cwd: string;
|
|
14
|
+
/** Model id (resolved: per-run model, else the engine default). */
|
|
15
|
+
model: string;
|
|
16
|
+
/** API key (per-org BYO, else the runner env key). */
|
|
17
|
+
apiKey?: string;
|
|
18
|
+
/** Tool allowlist; undefined means the harness's defaults. */
|
|
19
|
+
allowedTools?: string[];
|
|
20
|
+
/** Wall-clock budget in ms; undefined means no engine-imposed limit. */
|
|
21
|
+
maxDurationMs?: number;
|
|
22
|
+
/** Workspace-scoped capabilities the driver mounts as an in-process MCP server.
|
|
23
|
+
* Which ones is the application's choice — see {@link CapabilityToolFactory}. */
|
|
24
|
+
mcpTools?: CapabilityTool[];
|
|
25
|
+
/** The run's external MCP connectors; the driver mounts them as SDK mcpServers so
|
|
26
|
+
* they become tools inside Claude Code (parity with the native engine). */
|
|
27
|
+
connectors?: ConnectorConfig[];
|
|
28
|
+
}
|
|
29
|
+
/** A normalized message from the harness (driver-agnostic). */
|
|
30
|
+
export type ClaudeCodeMessage = {
|
|
31
|
+
kind: "assistant";
|
|
32
|
+
text: string;
|
|
33
|
+
} | {
|
|
34
|
+
kind: "result";
|
|
35
|
+
text: string;
|
|
36
|
+
isError: boolean;
|
|
37
|
+
};
|
|
38
|
+
/**
|
|
39
|
+
* The injectable boundary to the Claude Code harness: given mapped options, yield
|
|
40
|
+
* a normalized message stream. The default implementation drives the Agent SDK;
|
|
41
|
+
* tests inject a fake so no CLI/network runs.
|
|
42
|
+
*/
|
|
43
|
+
export type ClaudeCodeDriver = (opts: ClaudeCodeOptions) => AsyncIterable<ClaudeCodeMessage>;
|
|
44
|
+
/**
|
|
45
|
+
* Builds the capability surface a run gets, bound to that run's workspace scope
|
|
46
|
+
* and working tree. The kernel supplies only the generic
|
|
47
|
+
* {@link writeFileCapability}; an application injects a factory that composes
|
|
48
|
+
* its own capabilities alongside it, closing over whatever sinks it wants the
|
|
49
|
+
* emissions to land in.
|
|
50
|
+
*/
|
|
51
|
+
export type CapabilityToolFactory = (ctx: CapabilityContext) => CapabilityTool[];
|
|
52
|
+
/** The kernel's default surface: the one capability that carries no product semantics. */
|
|
53
|
+
export declare const defaultCapabilityTools: CapabilityToolFactory;
|
|
54
|
+
/**
|
|
55
|
+
* Drives a run with the Claude Code harness (its own grep/glob/edit/bash tools +
|
|
56
|
+
* tuned loop) against the sandbox working tree. File edits land on disk and are
|
|
57
|
+
* captured by the caller's change-set diff — the engine returns prose only.
|
|
58
|
+
*
|
|
59
|
+
* Claude Code runs arbitrary bash, so it must not run on the warm shared runner.
|
|
60
|
+
* `supports()` refuses unless (a) the operator has explicitly enabled it and (b)
|
|
61
|
+
* the run is on the `ephemeral` runner profile (one throwaway container per run —
|
|
62
|
+
* the container, not a human, is the safety boundary). The SDK is loaded lazily by
|
|
63
|
+
* the driver, so this module stays cheap to import on the warm runner.
|
|
64
|
+
*/
|
|
65
|
+
export declare class ClaudeCodeEngine implements AgentEngine {
|
|
66
|
+
readonly name = "claude-code";
|
|
67
|
+
private readonly drive;
|
|
68
|
+
private readonly capabilityTools;
|
|
69
|
+
constructor(drive?: ClaudeCodeDriver, capabilityTools?: CapabilityToolFactory);
|
|
70
|
+
supports(spec: RunSpec): EngineSupport;
|
|
71
|
+
run(spec: RunSpec, ctx: EngineContext): Promise<EngineResult>;
|
|
72
|
+
}
|
|
73
|
+
//# sourceMappingURL=claudeCode.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"claudeCode.d.ts","sourceRoot":"","sources":["../../src/engines/claudeCode.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;AAClD,OAAO,KAAK,EAAE,WAAW,EAAE,aAAa,EAAE,YAAY,EAAE,aAAa,EAAE,OAAO,EAAE,MAAM,YAAY,CAAA;AAElG,OAAO,EAAuB,KAAK,iBAAiB,EAAE,KAAK,cAAc,EAAE,MAAM,iBAAiB,CAAA;AAElG;;;;GAIG;AACH,MAAM,WAAW,iBAAiB;IAChC,kDAAkD;IAClD,MAAM,EAAE,MAAM,CAAA;IACd,8EAA8E;IAC9E,GAAG,EAAE,MAAM,CAAA;IACX,mEAAmE;IACnE,KAAK,EAAE,MAAM,CAAA;IACb,sDAAsD;IACtD,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,8DAA8D;IAC9D,YAAY,CAAC,EAAE,MAAM,EAAE,CAAA;IACvB,wEAAwE;IACxE,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB;sFACkF;IAClF,QAAQ,CAAC,EAAE,cAAc,EAAE,CAAA;IAC3B;gFAC4E;IAC5E,UAAU,CAAC,EAAE,eAAe,EAAE,CAAA;CAC/B;AAED,+DAA+D;AAC/D,MAAM,MAAM,iBAAiB,GAC3B;IAAE,IAAI,EAAE,WAAW,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAE,CAAA;AAE1F;;;;GAIG;AACH,MAAM,MAAM,gBAAgB,GAAG,CAAC,IAAI,EAAE,iBAAiB,KAAK,aAAa,CAAC,iBAAiB,CAAC,CAAA;AAK5F;;;;;;GAMG;AACH,MAAM,MAAM,qBAAqB,GAAG,CAAC,GAAG,EAAE,iBAAiB,KAAK,cAAc,EAAE,CAAA;AAEhF,0FAA0F;AAC1F,eAAO,MAAM,sBAAsB,EAAE,qBAA2D,CAAA;AAEhG;;;;;;;;;;GAUG;AACH,qBAAa,gBAAiB,YAAW,WAAW;IAClD,QAAQ,CAAC,IAAI,iBAAgB;IAE7B,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAkB;IACxC,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAuB;gBAGrD,KAAK,GAAE,gBAA0C,EACjD,eAAe,GAAE,qBAA8C;IAMjE,QAAQ,CAAC,IAAI,EAAE,OAAO,GAAG,aAAa;IAiBhC,GAAG,CAAC,IAAI,EAAE,OAAO,EAAE,GAAG,EAAE,aAAa,GAAG,OAAO,CAAC,YAAY,CAAC;CA4CpE"}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { defaultClaudeCodeDriver } from "./claudeCodeDriver.js";
|
|
2
|
+
import { writeFileCapability } from "./capability.js";
|
|
3
|
+
const DEFAULT_MODEL = "claude-opus-4-8";
|
|
4
|
+
const LOG_TRUNCATE = 2000;
|
|
5
|
+
/** The kernel's default surface: the one capability that carries no product semantics. */
|
|
6
|
+
export const defaultCapabilityTools = (ctx) => [writeFileCapability(ctx)];
|
|
7
|
+
/**
|
|
8
|
+
* Drives a run with the Claude Code harness (its own grep/glob/edit/bash tools +
|
|
9
|
+
* tuned loop) against the sandbox working tree. File edits land on disk and are
|
|
10
|
+
* captured by the caller's change-set diff — the engine returns prose only.
|
|
11
|
+
*
|
|
12
|
+
* Claude Code runs arbitrary bash, so it must not run on the warm shared runner.
|
|
13
|
+
* `supports()` refuses unless (a) the operator has explicitly enabled it and (b)
|
|
14
|
+
* the run is on the `ephemeral` runner profile (one throwaway container per run —
|
|
15
|
+
* the container, not a human, is the safety boundary). The SDK is loaded lazily by
|
|
16
|
+
* the driver, so this module stays cheap to import on the warm runner.
|
|
17
|
+
*/
|
|
18
|
+
export class ClaudeCodeEngine {
|
|
19
|
+
name = "claude-code";
|
|
20
|
+
drive;
|
|
21
|
+
capabilityTools;
|
|
22
|
+
constructor(drive = defaultClaudeCodeDriver, capabilityTools = defaultCapabilityTools) {
|
|
23
|
+
this.drive = drive;
|
|
24
|
+
this.capabilityTools = capabilityTools;
|
|
25
|
+
}
|
|
26
|
+
supports(spec) {
|
|
27
|
+
if (process.env.RUNNER_ENABLE_CLAUDE_CODE !== "1") {
|
|
28
|
+
return {
|
|
29
|
+
ok: false,
|
|
30
|
+
reason: "claude-code engine is disabled (set RUNNER_ENABLE_CLAUDE_CODE=1)",
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
if (spec.workflow.runner?.profile !== "ephemeral") {
|
|
34
|
+
return {
|
|
35
|
+
ok: false,
|
|
36
|
+
reason: "claude-code engine requires the ephemeral runner profile (per-run container isolation)",
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
return { ok: true };
|
|
40
|
+
}
|
|
41
|
+
async run(spec, ctx) {
|
|
42
|
+
const apiKey = spec.provider.credentials?.anthropic ?? process.env.ANTHROPIC_API_KEY;
|
|
43
|
+
const model = spec.provider.model || DEFAULT_MODEL;
|
|
44
|
+
const allowedTools = Array.isArray(spec.permissions.tools) && spec.permissions.tools.length > 0
|
|
45
|
+
? spec.permissions.tools
|
|
46
|
+
: undefined;
|
|
47
|
+
// No emissions from here: injected capabilities close over sinks the
|
|
48
|
+
// APPLICATION owns, so it reads what a run emitted from those directly.
|
|
49
|
+
// Omitted rather than returned empty — see EngineResult.
|
|
50
|
+
const mcpTools = this.capabilityTools({
|
|
51
|
+
workspaceId: spec.workspaceId,
|
|
52
|
+
workdir: spec.workdir,
|
|
53
|
+
});
|
|
54
|
+
const options = {
|
|
55
|
+
prompt: buildPrompt(spec),
|
|
56
|
+
cwd: spec.workdir,
|
|
57
|
+
model,
|
|
58
|
+
mcpTools,
|
|
59
|
+
...(spec.connectors.length > 0 ? { connectors: spec.connectors } : {}),
|
|
60
|
+
...(apiKey ? { apiKey } : {}),
|
|
61
|
+
...(allowedTools ? { allowedTools } : {}),
|
|
62
|
+
...(spec.limits?.maxDurationMs !== undefined
|
|
63
|
+
? { maxDurationMs: spec.limits.maxDurationMs }
|
|
64
|
+
: {}),
|
|
65
|
+
};
|
|
66
|
+
ctx.log(`claude-code: driving model ${model} in ${spec.workdir}`);
|
|
67
|
+
let finalText = "";
|
|
68
|
+
for await (const message of this.drive(options)) {
|
|
69
|
+
if (message.kind === "assistant") {
|
|
70
|
+
if (message.text)
|
|
71
|
+
ctx.log(`claude-code: ${truncate(message.text, LOG_TRUNCATE)}`);
|
|
72
|
+
}
|
|
73
|
+
else {
|
|
74
|
+
finalText = message.text;
|
|
75
|
+
if (message.isError)
|
|
76
|
+
ctx.log("claude-code: harness reported an error");
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
return { text: finalText || "(no output)" };
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
function buildPrompt(spec) {
|
|
83
|
+
const inputs = JSON.stringify(spec.inputs ?? {}, null, 2);
|
|
84
|
+
return [
|
|
85
|
+
spec.workflow.prompt ?? `Execute the "${spec.workflow.name ?? spec.workflowPath}" workflow.`,
|
|
86
|
+
"",
|
|
87
|
+
"## Inputs",
|
|
88
|
+
"```json",
|
|
89
|
+
inputs,
|
|
90
|
+
"```",
|
|
91
|
+
"",
|
|
92
|
+
"You are running as an autonomous workflow. The current working directory is the",
|
|
93
|
+
"workspace — inspect and edit its files directly with your tools. When finished,",
|
|
94
|
+
"reply with the workflow's output as Markdown.",
|
|
95
|
+
].join("\n");
|
|
96
|
+
}
|
|
97
|
+
function truncate(text, max) {
|
|
98
|
+
return text.length <= max ? text : `${text.slice(0, max)}…`;
|
|
99
|
+
}
|
|
100
|
+
//# sourceMappingURL=claudeCode.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"claudeCode.js","sourceRoot":"","sources":["../../src/engines/claudeCode.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { ClaudeCodeMessage, ClaudeCodeOptions } from "./claudeCode.js";
|
|
2
|
+
/**
|
|
3
|
+
* The default Claude Code driver: runs the Anthropic Agent SDK's `query()` (which
|
|
4
|
+
* spawns the Claude Code CLI) against the prepared workdir and normalizes its
|
|
5
|
+
* message stream. This is the ONLY module that touches the SDK, and it loads it
|
|
6
|
+
* lazily (dynamic import) so the warm runner — where this engine never runs —
|
|
7
|
+
* doesn't pay to import it.
|
|
8
|
+
*
|
|
9
|
+
* Permission mode is `bypassPermissions`: this engine only runs inside a throwaway
|
|
10
|
+
* ephemeral container (enforced by ClaudeCodeEngine.supports), so the container,
|
|
11
|
+
* not an interactive human, is the safety boundary.
|
|
12
|
+
*/
|
|
13
|
+
export declare function defaultClaudeCodeDriver(opts: ClaudeCodeOptions): AsyncIterable<ClaudeCodeMessage>;
|
|
14
|
+
//# sourceMappingURL=claudeCodeDriver.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"claudeCodeDriver.d.ts","sourceRoot":"","sources":["../../src/engines/claudeCodeDriver.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAA;AAI3E;;;;;;;;;;GAUG;AACH,wBAAuB,uBAAuB,CAC5C,IAAI,EAAE,iBAAiB,GACtB,aAAa,CAAC,iBAAiB,CAAC,CAqDlC"}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { CAPABILITY_SERVER_NAME, capabilitySdkServer, capabilityToolIds } from "./capabilityMcp.js";
|
|
2
|
+
import { connectorServers } from "./connectorMcp.js";
|
|
3
|
+
/**
|
|
4
|
+
* The default Claude Code driver: runs the Anthropic Agent SDK's `query()` (which
|
|
5
|
+
* spawns the Claude Code CLI) against the prepared workdir and normalizes its
|
|
6
|
+
* message stream. This is the ONLY module that touches the SDK, and it loads it
|
|
7
|
+
* lazily (dynamic import) so the warm runner — where this engine never runs —
|
|
8
|
+
* doesn't pay to import it.
|
|
9
|
+
*
|
|
10
|
+
* Permission mode is `bypassPermissions`: this engine only runs inside a throwaway
|
|
11
|
+
* ephemeral container (enforced by ClaudeCodeEngine.supports), so the container,
|
|
12
|
+
* not an interactive human, is the safety boundary.
|
|
13
|
+
*/
|
|
14
|
+
export async function* defaultClaudeCodeDriver(opts) {
|
|
15
|
+
const { query } = await import("@anthropic-ai/claude-agent-sdk");
|
|
16
|
+
const controller = new AbortController();
|
|
17
|
+
const timer = opts.maxDurationMs && opts.maxDurationMs > 0
|
|
18
|
+
? setTimeout(() => controller.abort(), opts.maxDurationMs)
|
|
19
|
+
: undefined;
|
|
20
|
+
// Mount the run's MCP servers: the runner-hosted, workspace-scoped capability
|
|
21
|
+
// surface (in-process) so Claude Code emits issues/knowledge/files uniformly with
|
|
22
|
+
// native, plus the run's external connectors (Slack, an Airwallex MCP, …) so they
|
|
23
|
+
// become tools inside Claude Code too. Same connector source the native engine uses.
|
|
24
|
+
const capabilities = opts.mcpTools ?? [];
|
|
25
|
+
const connectors = connectorServers(opts.connectors ?? []);
|
|
26
|
+
const mcpServers = { ...connectors };
|
|
27
|
+
if (capabilities.length > 0) {
|
|
28
|
+
mcpServers[CAPABILITY_SERVER_NAME] = await capabilitySdkServer(capabilities);
|
|
29
|
+
}
|
|
30
|
+
const hasMcpServers = Object.keys(mcpServers).length > 0;
|
|
31
|
+
// When the workflow narrows tools (allowedTools set), the mounted MCP tools must
|
|
32
|
+
// still be permitted; append the capability tool ids and a server-level allow for
|
|
33
|
+
// each connector (whose tool names are only known at connect time). With no
|
|
34
|
+
// allowlist, bypassPermissions already permits every tool.
|
|
35
|
+
const allowedTools = opts.allowedTools && opts.allowedTools.length > 0
|
|
36
|
+
? [
|
|
37
|
+
...opts.allowedTools,
|
|
38
|
+
...capabilityToolIds(capabilities),
|
|
39
|
+
...Object.keys(connectors).map((name) => `mcp__${name}`),
|
|
40
|
+
]
|
|
41
|
+
: opts.allowedTools;
|
|
42
|
+
const options = {
|
|
43
|
+
cwd: opts.cwd,
|
|
44
|
+
model: opts.model,
|
|
45
|
+
permissionMode: "bypassPermissions",
|
|
46
|
+
allowDangerouslySkipPermissions: true,
|
|
47
|
+
abortController: controller,
|
|
48
|
+
env: { ...process.env, ...(opts.apiKey ? { ANTHROPIC_API_KEY: opts.apiKey } : {}) },
|
|
49
|
+
...(hasMcpServers ? { mcpServers } : {}),
|
|
50
|
+
...(allowedTools ? { allowedTools } : {}),
|
|
51
|
+
};
|
|
52
|
+
try {
|
|
53
|
+
for await (const message of query({ prompt: opts.prompt, options })) {
|
|
54
|
+
const normalized = normalize(message);
|
|
55
|
+
if (normalized)
|
|
56
|
+
yield normalized;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
finally {
|
|
60
|
+
if (timer)
|
|
61
|
+
clearTimeout(timer);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
function normalize(message) {
|
|
65
|
+
if (message.type === "assistant") {
|
|
66
|
+
const text = extractText(message.message.content);
|
|
67
|
+
return text ? { kind: "assistant", text } : undefined;
|
|
68
|
+
}
|
|
69
|
+
if (message.type === "result") {
|
|
70
|
+
const text = message.subtype === "success" ? message.result : "";
|
|
71
|
+
return { kind: "result", text, isError: message.is_error };
|
|
72
|
+
}
|
|
73
|
+
return undefined;
|
|
74
|
+
}
|
|
75
|
+
/** Concatenate the text blocks of an assistant message's content. */
|
|
76
|
+
function extractText(content) {
|
|
77
|
+
if (!Array.isArray(content))
|
|
78
|
+
return "";
|
|
79
|
+
const texts = [];
|
|
80
|
+
for (const block of content) {
|
|
81
|
+
if (typeof block === "object" &&
|
|
82
|
+
block !== null &&
|
|
83
|
+
block.type === "text" &&
|
|
84
|
+
typeof block.text === "string") {
|
|
85
|
+
texts.push(block.text);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
return texts.join("\n");
|
|
89
|
+
}
|
|
90
|
+
//# sourceMappingURL=claudeCodeDriver.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"claudeCodeDriver.js","sourceRoot":"","sources":["../../src/engines/claudeCodeDriver.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import type { AgentEngine, EngineContext, EngineResult, EngineSupport, RunSpec } from "./types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Driver-neutral options the engine derives from a {@link RunSpec} and hands to
|
|
4
|
+
* the codex harness. The default driver maps these onto the OpenAI Codex CLI;
|
|
5
|
+
* tests inject a fake driver and assert this mapping.
|
|
6
|
+
*/
|
|
7
|
+
export interface CodexOptions {
|
|
8
|
+
/** The task prompt (workflow prompt + inputs). */
|
|
9
|
+
prompt: string;
|
|
10
|
+
/** The prepared sandbox working tree — the harness's cwd; edits land here. */
|
|
11
|
+
cwd: string;
|
|
12
|
+
/** Model id (resolved: per-run model, else the engine default). */
|
|
13
|
+
model: string;
|
|
14
|
+
/** API key (per-org BYO, else the runner env key). */
|
|
15
|
+
apiKey?: string;
|
|
16
|
+
/**
|
|
17
|
+
* The transient `CODEX_HOME` for this run — a temp dir OUTSIDE the sandbox that
|
|
18
|
+
* holds the `config.toml` the engine wrote (the run's MCP servers). The driver
|
|
19
|
+
* points the codex process at it via the `CODEX_HOME` env var.
|
|
20
|
+
*/
|
|
21
|
+
codexHome: string;
|
|
22
|
+
/**
|
|
23
|
+
* Env the runner-hosted capability stdio MCP server needs (workspace id, workdir,
|
|
24
|
+
* emissions-file path). These are ALSO declared in the server's `config.toml` env
|
|
25
|
+
* table, but the driver sets them on the codex process env too so the spawned
|
|
26
|
+
* server inherits them even if codex doesn't forward the config env table.
|
|
27
|
+
*/
|
|
28
|
+
capabilityEnv: Record<string, string>;
|
|
29
|
+
/** Wall-clock budget in ms; undefined means no engine-imposed limit. */
|
|
30
|
+
maxDurationMs?: number;
|
|
31
|
+
}
|
|
32
|
+
/** A normalized message from the harness (driver-agnostic). */
|
|
33
|
+
export type CodexMessage = {
|
|
34
|
+
kind: "assistant";
|
|
35
|
+
text: string;
|
|
36
|
+
} | {
|
|
37
|
+
kind: "result";
|
|
38
|
+
text: string;
|
|
39
|
+
isError: boolean;
|
|
40
|
+
};
|
|
41
|
+
/** The injectable boundary to the codex harness. Tests supply a fake. */
|
|
42
|
+
export type CodexDriver = (opts: CodexOptions) => AsyncIterable<CodexMessage>;
|
|
43
|
+
/** The runner-hosted capability MCP server the codex `config.toml` points at. */
|
|
44
|
+
/**
|
|
45
|
+
* Drives a run with the OpenAI Codex CLI against the sandbox working tree,
|
|
46
|
+
* mirroring the Claude Code engine. Because codex runs as an EXTERNAL process, it
|
|
47
|
+
* reaches the run's tools through a `config.toml` the engine writes into a transient
|
|
48
|
+
* `CODEX_HOME` (codex's REAL MCP discovery mechanism — it ignores `.mcp.json`):
|
|
49
|
+
* the run's connectors (Pillar 4) plus the runner-hosted, workspace-scoped
|
|
50
|
+
* capability server (Pillar 3) as a stdio MCP server. The capability server
|
|
51
|
+
* persists issue/knowledge emits to a file outside the tree, which this engine
|
|
52
|
+
* reads back — so codex reaches emit parity with native and Claude Code.
|
|
53
|
+
*
|
|
54
|
+
* Codex runs arbitrary code, so — like Claude Code — `supports()` refuses unless
|
|
55
|
+
* the operator enabled it (RUNNER_ENABLE_CODEX=1) AND the run is on the ephemeral
|
|
56
|
+
* runner profile (one throwaway container per run is the safety boundary).
|
|
57
|
+
*/
|
|
58
|
+
export declare class CodexEngine implements AgentEngine {
|
|
59
|
+
readonly name = "codex";
|
|
60
|
+
private readonly drive;
|
|
61
|
+
private readonly capabilityServerScript;
|
|
62
|
+
/**
|
|
63
|
+
* `capabilityServerScript` is REQUIRED: the capability surface is injected,
|
|
64
|
+
* and a child process cannot be handed a closure, so the application must
|
|
65
|
+
* supply the entrypoint that builds and serves its own tools. There is no
|
|
66
|
+
* sensible kernel default — one would silently serve an empty surface.
|
|
67
|
+
*/
|
|
68
|
+
constructor(drive: CodexDriver | undefined, capabilityServerScript: string);
|
|
69
|
+
supports(spec: RunSpec): EngineSupport;
|
|
70
|
+
run(spec: RunSpec, ctx: EngineContext): Promise<EngineResult>;
|
|
71
|
+
}
|
|
72
|
+
//# sourceMappingURL=codex.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"codex.d.ts","sourceRoot":"","sources":["../../src/engines/codex.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,WAAW,EAAE,aAAa,EAAE,YAAY,EAAE,aAAa,EAAE,OAAO,EAAE,MAAM,YAAY,CAAA;AAMlG;;;;GAIG;AACH,MAAM,WAAW,YAAY;IAC3B,kDAAkD;IAClD,MAAM,EAAE,MAAM,CAAA;IACd,8EAA8E;IAC9E,GAAG,EAAE,MAAM,CAAA;IACX,mEAAmE;IACnE,KAAK,EAAE,MAAM,CAAA;IACb,sDAAsD;IACtD,MAAM,CAAC,EAAE,MAAM,CAAA;IACf;;;;OAIG;IACH,SAAS,EAAE,MAAM,CAAA;IACjB;;;;;OAKG;IACH,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IACrC,wEAAwE;IACxE,aAAa,CAAC,EAAE,MAAM,CAAA;CACvB;AAED,+DAA+D;AAC/D,MAAM,MAAM,YAAY,GACtB;IAAE,IAAI,EAAE,WAAW,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAE,CAAA;AAE1F,yEAAyE;AACzE,MAAM,MAAM,WAAW,GAAG,CAAC,IAAI,EAAE,YAAY,KAAK,aAAa,CAAC,YAAY,CAAC,CAAA;AAK7E,iFAAiF;AAEjF;;;;;;;;;;;;;GAaG;AACH,qBAAa,WAAY,YAAW,WAAW;IAC7C,QAAQ,CAAC,IAAI,WAAU;IAEvB,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAa;IACnC,OAAO,CAAC,QAAQ,CAAC,sBAAsB,CAAQ;IAE/C;;;;;OAKG;gBACS,KAAK,EAAE,WAAW,YAAqB,EAAE,sBAAsB,EAAE,MAAM;IAKnF,QAAQ,CAAC,IAAI,EAAE,OAAO,GAAG,aAAa;IAahC,GAAG,CAAC,IAAI,EAAE,OAAO,EAAE,GAAG,EAAE,aAAa,GAAG,OAAO,CAAC,YAAY,CAAC;CA+FpE"}
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
import { mkdtemp, rm, stat } from "node:fs/promises";
|
|
2
|
+
import { tmpdir } from "node:os";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { CAPABILITY_SERVER_NAME } from "./capabilityMcp.js";
|
|
5
|
+
import { connectorServers, writeCodexConfig } from "./connectorMcp.js";
|
|
6
|
+
import { readEmissions } from "./capabilityEmissions.js";
|
|
7
|
+
import { defaultCodexDriver } from "./codexDriver.js";
|
|
8
|
+
const DEFAULT_MODEL = "gpt-5-codex";
|
|
9
|
+
const LOG_TRUNCATE = 2000;
|
|
10
|
+
/** The runner-hosted capability MCP server the codex `config.toml` points at. */
|
|
11
|
+
/**
|
|
12
|
+
* Drives a run with the OpenAI Codex CLI against the sandbox working tree,
|
|
13
|
+
* mirroring the Claude Code engine. Because codex runs as an EXTERNAL process, it
|
|
14
|
+
* reaches the run's tools through a `config.toml` the engine writes into a transient
|
|
15
|
+
* `CODEX_HOME` (codex's REAL MCP discovery mechanism — it ignores `.mcp.json`):
|
|
16
|
+
* the run's connectors (Pillar 4) plus the runner-hosted, workspace-scoped
|
|
17
|
+
* capability server (Pillar 3) as a stdio MCP server. The capability server
|
|
18
|
+
* persists issue/knowledge emits to a file outside the tree, which this engine
|
|
19
|
+
* reads back — so codex reaches emit parity with native and Claude Code.
|
|
20
|
+
*
|
|
21
|
+
* Codex runs arbitrary code, so — like Claude Code — `supports()` refuses unless
|
|
22
|
+
* the operator enabled it (RUNNER_ENABLE_CODEX=1) AND the run is on the ephemeral
|
|
23
|
+
* runner profile (one throwaway container per run is the safety boundary).
|
|
24
|
+
*/
|
|
25
|
+
export class CodexEngine {
|
|
26
|
+
name = "codex";
|
|
27
|
+
drive;
|
|
28
|
+
capabilityServerScript;
|
|
29
|
+
/**
|
|
30
|
+
* `capabilityServerScript` is REQUIRED: the capability surface is injected,
|
|
31
|
+
* and a child process cannot be handed a closure, so the application must
|
|
32
|
+
* supply the entrypoint that builds and serves its own tools. There is no
|
|
33
|
+
* sensible kernel default — one would silently serve an empty surface.
|
|
34
|
+
*/
|
|
35
|
+
constructor(drive = defaultCodexDriver, capabilityServerScript) {
|
|
36
|
+
this.drive = drive;
|
|
37
|
+
this.capabilityServerScript = capabilityServerScript;
|
|
38
|
+
}
|
|
39
|
+
supports(spec) {
|
|
40
|
+
if (process.env.RUNNER_ENABLE_CODEX !== "1") {
|
|
41
|
+
return { ok: false, reason: "codex engine is disabled (set RUNNER_ENABLE_CODEX=1)" };
|
|
42
|
+
}
|
|
43
|
+
if (spec.workflow.runner?.profile !== "ephemeral") {
|
|
44
|
+
return {
|
|
45
|
+
ok: false,
|
|
46
|
+
reason: "codex engine requires the ephemeral runner profile (per-run container isolation)",
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
return { ok: true };
|
|
50
|
+
}
|
|
51
|
+
async run(spec, ctx) {
|
|
52
|
+
const apiKey = spec.provider.credentials?.openai ?? process.env.OPENAI_API_KEY;
|
|
53
|
+
const model = spec.provider.model || DEFAULT_MODEL;
|
|
54
|
+
// Emissions land OUTSIDE the sandbox so the bookkeeping file is never captured
|
|
55
|
+
// by the change set; the capability server (an external process) writes here and
|
|
56
|
+
// we read it back after the run.
|
|
57
|
+
const emissionsDir = await mkdtemp(path.join(tmpdir(), "harness-emit-"));
|
|
58
|
+
const emissionsFile = path.join(emissionsDir, "emissions.json");
|
|
59
|
+
// The codex `config.toml` carries resolved connector auth tokens, so it lives in
|
|
60
|
+
// a transient CODEX_HOME OUTSIDE the sandbox — it can never reach the change set —
|
|
61
|
+
// and is deleted in `finally` regardless.
|
|
62
|
+
//
|
|
63
|
+
// On /tmp, codex logs one harmless warning per run ("Refusing to create helper
|
|
64
|
+
// binaries under temporary dir /tmp") and PROCEEDS: it only skips creating the
|
|
65
|
+
// PATH-alias helper binaries, which we never use. Kept on /tmp deliberately —
|
|
66
|
+
// relocating off /tmp (e.g. to the `node` user's home in the container) would
|
|
67
|
+
// silence the log but flip codex into actually writing those unneeded helpers
|
|
68
|
+
// every run, and couple this to assumptions about the runtime image's writable
|
|
69
|
+
// dirs. The warning is purely cosmetic; not worth that trade.
|
|
70
|
+
const codexHome = await mkdtemp(path.join(tmpdir(), "harness-codex-home-"));
|
|
71
|
+
// The env the capability stdio server needs — set both in its config.toml env
|
|
72
|
+
// table AND on the codex process env (see CodexOptions.capabilityEnv) so it
|
|
73
|
+
// arrives regardless of whether codex forwards the config env table.
|
|
74
|
+
const capabilityEnv = {
|
|
75
|
+
HARNESS_WORKSPACE_ID: spec.workspaceId,
|
|
76
|
+
HARNESS_WORKDIR: spec.workdir,
|
|
77
|
+
HARNESS_EMISSIONS_FILE: emissionsFile,
|
|
78
|
+
};
|
|
79
|
+
const servers = {
|
|
80
|
+
...connectorServers(spec.connectors),
|
|
81
|
+
[CAPABILITY_SERVER_NAME]: {
|
|
82
|
+
type: "stdio",
|
|
83
|
+
command: process.execPath,
|
|
84
|
+
args: [this.capabilityServerScript],
|
|
85
|
+
env: capabilityEnv,
|
|
86
|
+
},
|
|
87
|
+
};
|
|
88
|
+
await writeCodexConfig(codexHome, servers);
|
|
89
|
+
const options = {
|
|
90
|
+
prompt: buildPrompt(spec),
|
|
91
|
+
cwd: spec.workdir,
|
|
92
|
+
model,
|
|
93
|
+
codexHome,
|
|
94
|
+
capabilityEnv,
|
|
95
|
+
...(apiKey ? { apiKey } : {}),
|
|
96
|
+
...(spec.limits?.maxDurationMs !== undefined
|
|
97
|
+
? { maxDurationMs: spec.limits.maxDurationMs }
|
|
98
|
+
: {}),
|
|
99
|
+
};
|
|
100
|
+
ctx.log(`codex: driving model ${model} in ${spec.workdir}`);
|
|
101
|
+
let finalText = "";
|
|
102
|
+
try {
|
|
103
|
+
for await (const message of this.drive(options)) {
|
|
104
|
+
if (message.kind === "assistant") {
|
|
105
|
+
if (message.text)
|
|
106
|
+
ctx.log(`codex: ${truncate(message.text, LOG_TRUNCATE)}`);
|
|
107
|
+
}
|
|
108
|
+
else {
|
|
109
|
+
finalText = message.text;
|
|
110
|
+
if (message.isError)
|
|
111
|
+
ctx.log("codex: harness reported an error");
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
finally {
|
|
116
|
+
// The token-bearing config is transient — never let it linger.
|
|
117
|
+
await rm(codexHome, { recursive: true, force: true });
|
|
118
|
+
}
|
|
119
|
+
// The stat's SIZE is the log's byte count, for two reasons. It is the only
|
|
120
|
+
// honest one — `JSON.stringify(x).length` counts UTF-16 code units, not
|
|
121
|
+
// bytes, and under-reports anything outside the BMP. And measuring by
|
|
122
|
+
// re-serializing allocates a second copy of a payload that may be large,
|
|
123
|
+
// to produce a number we already have on disk.
|
|
124
|
+
const emissionsStat = await stat(emissionsFile).then((st) => st, () => undefined);
|
|
125
|
+
const emissions = await readEmissions(emissionsFile);
|
|
126
|
+
// The engine reports whether the round trip HAPPENED, not what it carried:
|
|
127
|
+
// counting entries would mean knowing the shape, which is the coupling this
|
|
128
|
+
// is rid of. Presence plus size separates "the server never wrote" from "it
|
|
129
|
+
// wrote and the run emitted nothing".
|
|
130
|
+
ctx.log(`codex: capability emissions — file ${emissionsStat ? `present (${emissionsStat.size} bytes)` : "absent"}` +
|
|
131
|
+
`${emissionsStat && emissions === undefined ? ", unreadable" : ""}`);
|
|
132
|
+
await rm(emissionsDir, { recursive: true, force: true });
|
|
133
|
+
return {
|
|
134
|
+
text: finalText || "(no output)",
|
|
135
|
+
...(emissions !== undefined ? { emissions } : {}),
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
function buildPrompt(spec) {
|
|
140
|
+
const inputs = JSON.stringify(spec.inputs ?? {}, null, 2);
|
|
141
|
+
return [
|
|
142
|
+
spec.workflow.prompt ?? `Execute the "${spec.workflow.name ?? spec.workflowPath}" workflow.`,
|
|
143
|
+
"",
|
|
144
|
+
"## Inputs",
|
|
145
|
+
"```json",
|
|
146
|
+
inputs,
|
|
147
|
+
"```",
|
|
148
|
+
"",
|
|
149
|
+
"You are running as an autonomous workflow. The current working directory is the",
|
|
150
|
+
"workspace — inspect and edit its files directly with your tools. When finished,",
|
|
151
|
+
"reply with the workflow's output as Markdown.",
|
|
152
|
+
].join("\n");
|
|
153
|
+
}
|
|
154
|
+
function truncate(text, max) {
|
|
155
|
+
return text.length <= max ? text : `${text.slice(0, max)}…`;
|
|
156
|
+
}
|
|
157
|
+
//# sourceMappingURL=codex.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"codex.js","sourceRoot":"","sources":["../../src/engines/codex.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type { CodexMessage, CodexOptions } from "./codex.js";
|
|
2
|
+
/**
|
|
3
|
+
* The default codex driver: the single integration boundary to the OpenAI Codex
|
|
4
|
+
* CLI, mirroring claudeCodeDriver's injectable shape. It runs codex
|
|
5
|
+
* non-interactively (`codex exec`) against the prepared sandbox. The engine has
|
|
6
|
+
* already written the run's MCP servers (connectors + the runner-hosted capability
|
|
7
|
+
* server) into `config.toml` inside `opts.codexHome`; pointing the child at it via
|
|
8
|
+
* the `CODEX_HOME` env var is how codex discovers them.
|
|
9
|
+
*
|
|
10
|
+
* Invocation (verified against the OpenAI Codex CLI reference, `codex exec`):
|
|
11
|
+
* - `-m <model>` — model override
|
|
12
|
+
* - `-C <cwd>` — workspace root
|
|
13
|
+
* - `--skip-git-repo-check` — the tarball sandbox is not a git repo; without this
|
|
14
|
+
* `codex exec` refuses to run ("not inside a trusted
|
|
15
|
+
* directory")
|
|
16
|
+
* - `-o <file>` — write only the assistant's final message to a file,
|
|
17
|
+
* which we read back as the result (cleaner than the
|
|
18
|
+
* formatted stdout transcript)
|
|
19
|
+
* - `--dangerously-bypass-approvals-and-sandbox`
|
|
20
|
+
* — auto-approve every action (incl. MCP tool calls such
|
|
21
|
+
* as the runner-hosted open_issue) and disable codex's
|
|
22
|
+
* local sandbox. Under the default `approval: never` +
|
|
23
|
+
* `sandbox: read-only`, codex auto-CANCELS tool calls
|
|
24
|
+
* it would otherwise need approval for, so the
|
|
25
|
+
* capability tools never fire. This is codex's
|
|
26
|
+
* equivalent of the Claude Code driver's
|
|
27
|
+
* `bypassPermissions` and is justified the same way:
|
|
28
|
+
* this engine only runs inside a throwaway ephemeral
|
|
29
|
+
* container, so the container — not codex's sandbox —
|
|
30
|
+
* is the safety boundary.
|
|
31
|
+
* - `-` — read the prompt from stdin
|
|
32
|
+
* The API key rides on `CODEX_API_KEY` (codex exec's dedicated, preferred key,
|
|
33
|
+
* which also avoids reading `~/.codex/auth.json`); `OPENAI_API_KEY` is set too for
|
|
34
|
+
* compatibility (codex deprioritizes it but still accepts it).
|
|
35
|
+
*
|
|
36
|
+
* Like the Claude Code driver this only runs inside a throwaway ephemeral
|
|
37
|
+
* container (enforced by CodexEngine.supports) — the container, not a human, is
|
|
38
|
+
* the safety boundary. It is exercised only when the operator sets
|
|
39
|
+
* RUNNER_ENABLE_CODEX=1; every test injects a fake driver, so no binary/network
|
|
40
|
+
* is touched in CI.
|
|
41
|
+
*/
|
|
42
|
+
export declare function defaultCodexDriver(opts: CodexOptions): AsyncIterable<CodexMessage>;
|
|
43
|
+
//# sourceMappingURL=codexDriver.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"codexDriver.d.ts","sourceRoot":"","sources":["../../src/engines/codexDriver.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AAE5D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AACH,wBAAuB,kBAAkB,CAAC,IAAI,EAAE,YAAY,GAAG,aAAa,CAAC,YAAY,CAAC,CAyEzF"}
|