agentic-engineering-harness 0.4.16 → 0.6.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.
Files changed (104) hide show
  1. package/README.md +159 -189
  2. package/dist/agents/config.js +2 -0
  3. package/dist/agents/config.js.map +1 -1
  4. package/dist/agents/outputContracts.d.ts +1 -0
  5. package/dist/agents/outputContracts.js +12 -0
  6. package/dist/agents/outputContracts.js.map +1 -1
  7. package/dist/agents/parallelism.d.ts +1 -0
  8. package/dist/agents/parallelism.js +101 -14
  9. package/dist/agents/parallelism.js.map +1 -1
  10. package/dist/agents/structuredOutput.js +16 -4
  11. package/dist/agents/structuredOutput.js.map +1 -1
  12. package/dist/agents/waveExecutor.d.ts +41 -0
  13. package/dist/agents/waveExecutor.js +208 -0
  14. package/dist/agents/waveExecutor.js.map +1 -0
  15. package/dist/audit/intent.d.ts +20 -0
  16. package/dist/audit/intent.js +42 -0
  17. package/dist/audit/intent.js.map +1 -0
  18. package/dist/audit/run.d.ts +46 -0
  19. package/dist/audit/run.js +147 -0
  20. package/dist/audit/run.js.map +1 -0
  21. package/dist/cli.js +1 -1
  22. package/dist/cli.js.map +1 -1
  23. package/dist/core/config.js +28 -7
  24. package/dist/core/config.js.map +1 -1
  25. package/dist/core/controlPlane.d.ts +30 -0
  26. package/dist/core/controlPlane.js +131 -0
  27. package/dist/core/controlPlane.js.map +1 -0
  28. package/dist/core/init.js +13 -5
  29. package/dist/core/init.js.map +1 -1
  30. package/dist/core/run.d.ts +21 -0
  31. package/dist/core/run.js +104 -41
  32. package/dist/core/run.js.map +1 -1
  33. package/dist/core/types.d.ts +103 -1
  34. package/dist/distributed/queue.d.ts +11 -0
  35. package/dist/distributed/queue.js +140 -0
  36. package/dist/distributed/queue.js.map +1 -0
  37. package/dist/distributed/types.d.ts +34 -0
  38. package/dist/distributed/types.js +2 -0
  39. package/dist/distributed/types.js.map +1 -0
  40. package/dist/distributed/worker.d.ts +21 -0
  41. package/dist/distributed/worker.js +111 -0
  42. package/dist/distributed/worker.js.map +1 -0
  43. package/dist/entry.js +219 -46
  44. package/dist/entry.js.map +1 -1
  45. package/dist/evals/runner.js +2 -2
  46. package/dist/evals/runner.js.map +1 -1
  47. package/dist/evals/statistics.d.ts +38 -0
  48. package/dist/evals/statistics.js +88 -0
  49. package/dist/evals/statistics.js.map +1 -0
  50. package/dist/evidence/graph.d.ts +48 -0
  51. package/dist/evidence/graph.js +94 -0
  52. package/dist/evidence/graph.js.map +1 -0
  53. package/dist/issues/intake.d.ts +1 -1
  54. package/dist/mcp/benchmark.d.ts +24 -0
  55. package/dist/mcp/benchmark.js +82 -0
  56. package/dist/mcp/benchmark.js.map +1 -0
  57. package/dist/paseo/capabilities.d.ts +24 -0
  58. package/dist/paseo/capabilities.js +104 -0
  59. package/dist/paseo/capabilities.js.map +1 -0
  60. package/dist/paseo/context.d.ts +45 -0
  61. package/dist/paseo/context.js +153 -0
  62. package/dist/paseo/context.js.map +1 -0
  63. package/dist/paseo/start.d.ts +55 -0
  64. package/dist/paseo/start.js +138 -0
  65. package/dist/paseo/start.js.map +1 -0
  66. package/dist/policy/bundles.d.ts +27 -0
  67. package/dist/policy/bundles.js +129 -0
  68. package/dist/policy/bundles.js.map +1 -0
  69. package/dist/security/sandbox.d.ts +12 -0
  70. package/dist/security/sandbox.js +64 -0
  71. package/dist/security/sandbox.js.map +1 -0
  72. package/dist/spec/openspec.d.ts +28 -0
  73. package/dist/spec/openspec.js +179 -0
  74. package/dist/spec/openspec.js.map +1 -0
  75. package/dist/toolchain/resolve.js +54 -90
  76. package/dist/toolchain/resolve.js.map +1 -1
  77. package/dist/utils/process.d.ts +1 -0
  78. package/dist/utils/process.js +6 -1
  79. package/dist/utils/process.js.map +1 -1
  80. package/dist/validators/graphify.js +28 -6
  81. package/dist/validators/graphify.js.map +1 -1
  82. package/dist/workers/agentPrompt.d.ts +6 -1
  83. package/dist/workers/agentPrompt.js +118 -34
  84. package/dist/workers/agentPrompt.js.map +1 -1
  85. package/dist/workers/paseo.js +53 -19
  86. package/dist/workers/paseo.js.map +1 -1
  87. package/dist/workers/podman.js +30 -8
  88. package/dist/workers/podman.js.map +1 -1
  89. package/docs/PASEO.md +56 -4
  90. package/docs/V0.5.1.md +129 -0
  91. package/docs/V0.5.2.md +180 -0
  92. package/docs/V0.5.md +116 -0
  93. package/docs/V0.6.md +148 -0
  94. package/package.json +3 -3
  95. package/presets/agents/orchestration.jsonc +37 -0
  96. package/schemas/project.schema.json +38 -8
  97. package/skills/engineering-workflow/SKILL.md +113 -81
  98. package/skills/openspec-authoring/SKILL.md +26 -0
  99. package/skills/paseo-orchestration/SKILL.md +38 -0
  100. package/templates/AGENTS.md +40 -15
  101. package/templates/agents.source.jsonc +1 -1
  102. package/templates/openspec-config.yaml +24 -0
  103. package/templates/project.yaml +79 -1
  104. package/templates/toolchain.yaml +19 -2
@@ -0,0 +1,55 @@
1
+ import type { ResolvedAgentTopology } from "../agents/types.js";
2
+ import { loadResolvedAgentTopology } from "../agents/config.js";
3
+ import type { HarnessProjectConfig } from "../core/types.js";
4
+ import { setupToolchain } from "../toolchain/setup.js";
5
+ import { commandExists, runProcess } from "../utils/process.js";
6
+ import { detectPaseoCapabilities } from "./capabilities.js";
7
+ export declare const PASEO_BOOTSTRAP_VERSION = 3;
8
+ export type PaseoSessionPolicy = "fresh-on-start" | "reuse-compatible" | "resume-explicit";
9
+ export interface PaseoStartOptions {
10
+ autoSetup?: boolean;
11
+ webUi?: boolean;
12
+ forceNew?: boolean;
13
+ resume?: boolean;
14
+ leadAgent?: string;
15
+ title?: string;
16
+ aehCommand?: string;
17
+ handoffPath?: string;
18
+ }
19
+ export interface PaseoLeadState {
20
+ version: 1;
21
+ bootstrapVersion: number;
22
+ projectRoot: string;
23
+ projectName: string;
24
+ agentId: string;
25
+ title: string;
26
+ leadAgent: string;
27
+ provider: string;
28
+ model: string;
29
+ createdAt: string;
30
+ generation?: number;
31
+ handoffPath?: string;
32
+ }
33
+ export interface PaseoStartResult {
34
+ daemonStarted: boolean;
35
+ session: "created" | "reused";
36
+ agentId: string;
37
+ title: string;
38
+ leadAgent: string;
39
+ provider: string;
40
+ model: string;
41
+ stateFile: string;
42
+ bootstrapFile: string;
43
+ paseoVersion?: string;
44
+ }
45
+ interface PaseoStartDeps {
46
+ run: typeof runProcess;
47
+ commandExists: typeof commandExists;
48
+ setupToolchain: typeof setupToolchain;
49
+ loadTopology: typeof loadResolvedAgentTopology;
50
+ detectCapabilities: typeof detectPaseoCapabilities;
51
+ }
52
+ export declare function startPaseoHarness(root: string, config: HarnessProjectConfig, options?: PaseoStartOptions, deps?: PaseoStartDeps): Promise<PaseoStartResult>;
53
+ export declare function buildPaseoLeadBootstrap(projectName: string, projectRoot: string, aehCommand: string, preferPaseoTools?: boolean, handoffPath?: string): string;
54
+ export declare function resolveLeadAgent(topology: ResolvedAgentTopology, configured?: string): string;
55
+ export {};
@@ -0,0 +1,138 @@
1
+ import fs from "node:fs/promises";
2
+ import path from "node:path";
3
+ import { loadResolvedAgentTopology } from "../agents/config.js";
4
+ import { executionSelectionForAgent } from "../agents/routing.js";
5
+ import { setupToolchain } from "../toolchain/setup.js";
6
+ import { clearToolchainEnvCache, commandExists, runProcess } from "../utils/process.js";
7
+ import { buildPaseoBackgroundRunCommand, detectPaseoCapabilities, extractPaseoAgentId, isRecoverableDaemonStatus } from "./capabilities.js";
8
+ export const PASEO_BOOTSTRAP_VERSION = 3;
9
+ const DEFAULT_DEPS = { run: runProcess, commandExists, setupToolchain, loadTopology: loadResolvedAgentTopology, detectCapabilities: detectPaseoCapabilities };
10
+ export async function startPaseoHarness(root, config, options = {}, deps = DEFAULT_DEPS) {
11
+ const projectRoot = path.resolve(root);
12
+ const settings = config.orchestration?.interactive;
13
+ const autoSetup = options.autoSetup ?? settings?.autoSetup ?? true;
14
+ const webUi = options.webUi ?? settings?.webUi ?? true;
15
+ const stateDir = path.resolve(projectRoot, settings?.stateDir ?? ".harness/paseo");
16
+ const stateFile = path.join(stateDir, "lead-session.json");
17
+ const bootstrapFile = path.join(stateDir, "lead-bootstrap.md");
18
+ const sessionPolicy = settings?.sessionPolicy ?? "fresh-on-start";
19
+ const reuseRequested = options.resume === true || (sessionPolicy === "reuse-compatible" && options.forceNew !== true);
20
+ const topology = await deps.loadTopology(projectRoot, config, config.agents?.activeProfile);
21
+ const leadName = resolveLeadAgent(topology, options.leadAgent ?? settings?.leadAgent);
22
+ const selection = executionSelectionForAgent(topology, leadName);
23
+ const runtimeCommand = runtimeExecutable(topology, leadName);
24
+ const missingBefore = await missingCommands(projectRoot, ["paseo", runtimeCommand], deps);
25
+ if (missingBefore.length && autoSetup) {
26
+ await deps.setupToolchain(projectRoot, config, { skipProjectDependencies: true });
27
+ clearToolchainEnvCache();
28
+ }
29
+ const missingAfter = await missingCommands(projectRoot, ["paseo", runtimeCommand], deps);
30
+ if (missingAfter.length)
31
+ throw new Error(`aeh start cannot launch Paseo because these managed commands are unavailable: ${missingAfter.join(", ")}. Run aeh setup or provide the required host prerequisite/credential.`);
32
+ const capabilities = await deps.detectCapabilities(projectRoot, deps.run);
33
+ let daemonStarted = false;
34
+ const daemonStatusCommand = capabilities.daemonJson ? "paseo daemon status --json" : "paseo daemon status";
35
+ let daemonStatus = await deps.run(daemonStatusCommand, { cwd: projectRoot, timeoutMs: 30_000 });
36
+ if (daemonStatus.exitCode !== 0) {
37
+ if (isRecoverableDaemonStatus(daemonStatus))
38
+ await deps.run("paseo daemon stop", { cwd: projectRoot, timeoutMs: 30_000 }).catch(() => undefined);
39
+ const startCommand = webUi ? "paseo daemon start --web-ui" : "paseo daemon start";
40
+ const daemonStart = await deps.run(startCommand, { cwd: projectRoot, timeoutMs: 60_000 });
41
+ if (daemonStart.exitCode !== 0)
42
+ throw new Error(`Failed to start Paseo daemon: ${diagnostic(daemonStart)}`);
43
+ daemonStarted = true;
44
+ daemonStatus = await deps.run(daemonStatusCommand, { cwd: projectRoot, timeoutMs: 30_000 });
45
+ if (daemonStatus.exitCode !== 0)
46
+ throw new Error(`Paseo daemon did not become ready after startup: ${diagnostic(daemonStatus)}`);
47
+ }
48
+ const provider = selection.paseoProvider;
49
+ const model = paseoModel(selection);
50
+ const title = options.title ?? settings?.title ?? `AEH Lead · ${config.project.name}`;
51
+ const aehCommand = options.aehCommand ?? "aeh";
52
+ const bootstrap = buildPaseoLeadBootstrap(config.project.name, projectRoot, aehCommand, settings?.usePaseoTools !== false, options.handoffPath);
53
+ await fs.mkdir(stateDir, { recursive: true });
54
+ await fs.writeFile(bootstrapFile, `${bootstrap}\n`);
55
+ const previous = await loadState(stateFile);
56
+ if (!options.forceNew && reuseRequested && !options.handoffPath && previous && compatibleState(previous, { projectRoot, leadName, provider, model, title })) {
57
+ const probe = await deps.run(`paseo logs ${quote(previous.agentId)} --tail 1`, { cwd: projectRoot, timeoutMs: 30_000 });
58
+ if (probe.exitCode === 0)
59
+ return { daemonStarted, session: "reused", agentId: previous.agentId, title: previous.title, leadAgent: previous.leadAgent, provider: previous.provider, model: previous.model, stateFile, bootstrapFile, paseoVersion: capabilities.version };
60
+ }
61
+ const launchCommand = buildPaseoBackgroundRunCommand({ title, provider, model, prompt: bootstrap }, capabilities);
62
+ const launch = await deps.run(launchCommand, { cwd: projectRoot, timeoutMs: 60_000 });
63
+ if (launch.exitCode !== 0)
64
+ throw new Error(`Failed to create AEH lead in Paseo${capabilities.version ? ` ${capabilities.version}` : ""}: ${diagnostic(launch)}`);
65
+ const agentId = extractPaseoAgentId(launch.stdout);
66
+ if (!agentId)
67
+ throw new Error(`Paseo created no parseable agent id. Output: ${launch.stdout.trim() || "<empty>"}`);
68
+ const wait = await deps.run(`paseo wait ${quote(agentId)} --timeout 300`, { cwd: projectRoot, timeoutMs: 330_000 });
69
+ if (wait.exitCode !== 0)
70
+ throw new Error(`AEH lead bootstrap did not complete successfully: ${diagnostic(wait)}`);
71
+ const state = { version: 1, bootstrapVersion: PASEO_BOOTSTRAP_VERSION, projectRoot, projectName: config.project.name, agentId, title, leadAgent: leadName, provider, model, createdAt: new Date().toISOString(), generation: (previous?.generation ?? 0) + 1, handoffPath: options.handoffPath };
72
+ await fs.writeFile(stateFile, `${JSON.stringify(state, null, 2)}\n`);
73
+ return { daemonStarted, session: "created", agentId, title, leadAgent: leadName, provider, model, stateFile, bootstrapFile, paseoVersion: capabilities.version };
74
+ }
75
+ export function buildPaseoLeadBootstrap(projectName, projectRoot, aehCommand, preferPaseoTools = true, handoffPath) {
76
+ const handoff = handoffPath ? `\n\nThis lead was created by proactive context rotation. Before handling the next engineering action, read the deterministic handoff artifact ${JSON.stringify(handoffPath)} and every sealed/run/audit/delivery artifact it references. Treat that durable state as authoritative; do not ask the previous lead to replay its conversation. Preserve the same active user goal unless the handoff records a true ambiguity.` : "";
77
+ return `AEH thin-lead Paseo bootstrap v${PASEO_BOOTSTRAP_VERSION}.
78
+
79
+ You are the top-level engineering lead for project ${JSON.stringify(projectName)} at ${JSON.stringify(projectRoot)}. This instruction governs every later user message in this Paseo conversation. This lead is intentionally short-lived: a normal \`aeh start\` creates a fresh lead; explicit resume is opt-in.${handoff}
80
+
81
+ Before engineering work, read AGENTS.md and .harness/skills/engineering-workflow/SKILL.md when present. Every engineering operation must enter through AEH, including read-only audits. Only purely informational questions may bypass. Whenever the workflow says \`aeh\`, invoke exactly: \`${aehCommand}\`.
82
+
83
+ You are an ORCHESTRATOR, not the repository operator. Your responsibilities are: preserve user intent, choose/delegate workflow roles, resolve genuine ambiguity, monitor deterministic state, and perform final semantic acceptance. Do not spend your context doing broad repository exploration, package installation, daemon debugging, specification authoring, implementation, or raw log analysis when a bounded agent/Harness operation can own it.
84
+
85
+ Delegation policy:
86
+ - repository discovery/evidence -> explorer;
87
+ - toolchain, doctor, agents-check or Paseo daemon/provider recovery -> environment-manager;
88
+ - non-trivial triage/decomposition -> planner;
89
+ - SPEC authoring -> spec-manager using OpenSpec, never write proposal/spec/design/tasks yourself;
90
+ - implementation, validation and reviews -> AEH/Harness-selected workers.
91
+
92
+ ${preferPaseoTools ? `Prefer Paseo's injected native/MCP orchestration tools (create_agent, send_agent_prompt, get_agent_status, get_agent_activity, cancel_agent/archive_agent) and load /paseo when exact syntax is needed. Use /paseo-handoff for responsibility transfer. Do not shell out to hand-written paseo run loops from this lead. AEH's CLI adapter is only a compatibility fallback.` : `Use AEH's configured Paseo adapter for delegation; do not hand-write shell orchestration loops.`}
93
+
94
+ For every non-trivial user request:
95
+ 1. check context pressure with Paseo status if exposed, or \`${aehCommand} context guard --agent "$PASEO_AGENT_ID"\`. At 70% stop exploratory work. At 80% AEH automatically creates a deterministic handoff artifact and, when possible, rotates the persisted lead to a fresh Paseo agent; if the command reports rotatedAgentId, tell the user to continue in that fresh lead and stop this lead. At 90% no further engineering work is allowed in the old lead. Do not compact-and-continue after HANDOFF_REQUIRED/HARD_HANDOFF;
96
+ 2. classify INFORMATIONAL | AUDIT | CHANGE using \`${aehCommand} intent\` when not trivially informational;
97
+ 3. for AUDIT, invoke \`${aehCommand} audit\`; do not perform an ad-hoc review;
98
+ 4. for CHANGE, delegate discovery to explorer and planning/triage evidence to planner. Feed only their compact structured evidence into deterministic \`${aehCommand} triage\`;
99
+ 5. QUICK: create/validate/run the bounded QuickContract. Do not broaden QUICK;
100
+ 6. SPEC: delegate to spec-manager. spec-manager owns OpenSpec artifacts and returns a compiled/validated AEH SDD/TaskContract. The lead must not author those files. Then invoke the sealed AEH run;
101
+ 7. if execution reports environment/tool failure, delegate recovery to environment-manager and retry the same sealed operation after deterministic readiness. Do not personally run sequences of npm/git/Paseo diagnostic shells;
102
+ 8. surface only concise state transitions, true human-on-exception decisions, and final audit/acceptance/delivery state.
103
+
104
+ Existing GitHub issue requests use the issue-driven AEH path. A later request to fix audit findings must reuse .harness/audits/latest.json as evidence for a new CHANGE. Security, architecture, schema, public API and cross-module changes still escalate to SPEC.
105
+
106
+ The compiled AEH TaskContract/SDD plus seal are normative during implementation. OpenSpec is an authoring source before freeze, not a competing runtime authority. Harness workers/subagents do not replace this lead unless an explicit context handoff rotates responsibility.
107
+
108
+ Initialize this role now by reading only the project entry instructions needed to understand these rules. Do not run doctor/setup or inspect the repository broadly during bootstrap. When initialization is complete, respond with exactly: AEH READY`;
109
+ }
110
+ export function resolveLeadAgent(topology, configured) {
111
+ if (configured) {
112
+ const selected = topology.agents[configured];
113
+ if (!selected || selected.disabled)
114
+ throw new Error(`Configured interactive lead agent '${configured}' is unavailable.`);
115
+ return configured;
116
+ }
117
+ if (topology.agents.lead && !topology.agents.lead.disabled)
118
+ return "lead";
119
+ const orchestrator = Object.values(topology.agents).find((agent) => agent.role === "orchestrator" && !agent.disabled);
120
+ if (!orchestrator)
121
+ throw new Error("aeh start requires an enabled orchestrator/lead agent in the resolved topology.");
122
+ return orchestrator.name;
123
+ }
124
+ function runtimeExecutable(topology, leadName) { const runtime = topology.agents[leadName].runtime; return runtime.command?.trim().split(/\s+/, 1)[0] || runtime.adapter; }
125
+ async function missingCommands(root, commands, deps) { const result = []; for (const command of [...new Set(commands.filter(Boolean))])
126
+ if (!(await deps.commandExists(command, root)))
127
+ result.push(command); return result; }
128
+ function paseoModel(selection) { return selection.runtimeAdapter === "codex" ? selection.modelName : selection.modelId; }
129
+ async function loadState(file) { try {
130
+ return JSON.parse(await fs.readFile(file, "utf8"));
131
+ }
132
+ catch {
133
+ return undefined;
134
+ } }
135
+ function compatibleState(state, expected) { return state.version === 1 && state.bootstrapVersion === PASEO_BOOTSTRAP_VERSION && state.projectRoot === expected.projectRoot && state.leadAgent === expected.leadName && state.provider === expected.provider && state.model === expected.model && state.title === expected.title; }
136
+ function diagnostic(result) { return [result.stderr.trim(), result.stdout.trim()].filter(Boolean).join("\n") || `exit code ${result.exitCode}`; }
137
+ function quote(value) { return `'${value.replaceAll("'", "'\\''")}'`; }
138
+ //# sourceMappingURL=start.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"start.js","sourceRoot":"","sources":["../../src/paseo/start.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,27 @@
1
+ import type { HarnessProjectConfig } from "../core/types.js";
2
+ export interface PolicyBundleFile {
3
+ path: string;
4
+ sha256: string;
5
+ }
6
+ export interface OrganizationPolicyBundleManifest {
7
+ version: 1;
8
+ name: string;
9
+ extends?: string[];
10
+ policyDirs?: string[];
11
+ files: PolicyBundleFile[];
12
+ }
13
+ export interface ResolvedPolicyBundle {
14
+ name: string;
15
+ root: string;
16
+ manifestSha256: string;
17
+ verifiedSignature: boolean;
18
+ policyDirs: string[];
19
+ extends: string[];
20
+ }
21
+ export interface PolicyBundleResolution {
22
+ bundles: ResolvedPolicyBundle[];
23
+ policyDirs: string[];
24
+ issues: string[];
25
+ }
26
+ export declare function resolveOrganizationPolicyBundles(root: string, config: HarnessProjectConfig): Promise<PolicyBundleResolution>;
27
+ export declare function withOrganizationPolicies(config: HarnessProjectConfig, resolution: PolicyBundleResolution): HarnessProjectConfig;
@@ -0,0 +1,129 @@
1
+ import crypto from "node:crypto";
2
+ import fs from "node:fs/promises";
3
+ import path from "node:path";
4
+ import { commandExists, runProcess } from "../utils/process.js";
5
+ export async function resolveOrganizationPolicyBundles(root, config) {
6
+ const settings = config.organization?.policyBundles;
7
+ const sources = settings?.sources ?? [];
8
+ if (!sources.length)
9
+ return { bundles: [], policyDirs: [], issues: [] };
10
+ const cacheRoot = path.resolve(root, settings?.cacheDir ?? ".harness/policy-bundles");
11
+ await fs.mkdir(cacheRoot, { recursive: true });
12
+ const byName = new Map(sources.map((source) => [source.name, source]));
13
+ const resolved = new Map();
14
+ const issues = [];
15
+ const visiting = new Set();
16
+ const visit = async (name) => {
17
+ if (resolved.has(name))
18
+ return;
19
+ if (visiting.has(name))
20
+ throw new Error(`Organization policy bundle inheritance cycle at ${name}.`);
21
+ const source = byName.get(name);
22
+ if (!source)
23
+ throw new Error(`Organization policy bundle '${name}' is referenced but not configured.`);
24
+ visiting.add(name);
25
+ try {
26
+ const bundle = await materializeBundle(root, cacheRoot, source);
27
+ for (const parent of bundle.extends)
28
+ await visit(parent);
29
+ resolved.set(name, bundle);
30
+ }
31
+ catch (error) {
32
+ const message = `${name}: ${String(error)}`;
33
+ issues.push(message);
34
+ if (source.required !== false || settings?.required === true)
35
+ throw new Error(`Required organization policy bundle failed: ${message}`);
36
+ }
37
+ finally {
38
+ visiting.delete(name);
39
+ }
40
+ };
41
+ for (const source of sources)
42
+ await visit(source.name);
43
+ const bundles = [...resolved.values()];
44
+ return { bundles, policyDirs: [...new Set(bundles.flatMap((bundle) => bundle.policyDirs))], issues };
45
+ }
46
+ export function withOrganizationPolicies(config, resolution) {
47
+ if (!resolution.policyDirs.length)
48
+ return config;
49
+ const existing = config.validation?.opa?.policyDirs ?? [];
50
+ return {
51
+ ...config,
52
+ validation: {
53
+ ...config.validation,
54
+ opa: { ...config.validation?.opa, enabled: config.validation?.opa?.enabled ?? true, policyDirs: [...new Set([...existing, ...resolution.policyDirs])] }
55
+ }
56
+ };
57
+ }
58
+ async function materializeBundle(projectRoot, cacheRoot, source) {
59
+ const target = path.join(cacheRoot, safe(source.name));
60
+ await fs.rm(target, { recursive: true, force: true });
61
+ await fs.mkdir(target, { recursive: true });
62
+ const loaded = source.path ? await loadLocalManifest(projectRoot, source.path) : await loadRemoteManifest(source.url);
63
+ if (loaded.manifest.name !== source.name)
64
+ throw new Error(`manifest name '${loaded.manifest.name}' does not match configured source '${source.name}'.`);
65
+ const manifestHash = sha256(loaded.raw);
66
+ if (source.sha256 && source.sha256 !== manifestHash)
67
+ throw new Error(`manifest SHA-256 mismatch: expected ${source.sha256}, got ${manifestHash}.`);
68
+ const manifestFile = path.join(target, "bundle.json");
69
+ await fs.writeFile(manifestFile, loaded.raw);
70
+ let verifiedSignature = false;
71
+ if (source.signature || source.publicKey) {
72
+ if (!source.signature || !source.publicKey)
73
+ throw new Error("signed bundle requires both signature and publicKey.");
74
+ verifiedSignature = await verifySignature(projectRoot, manifestFile, source.signature, source.publicKey);
75
+ if (!verifiedSignature)
76
+ throw new Error("cosign signature verification failed.");
77
+ }
78
+ for (const file of loaded.manifest.files) {
79
+ if (file.path.includes("..") || path.isAbsolute(file.path))
80
+ throw new Error(`unsafe bundle file path ${file.path}.`);
81
+ const content = source.path ? await readLocalBundleFile(projectRoot, source.path, file.path) : await readRemoteBundleFile(source.url, file.path);
82
+ const actual = sha256(content);
83
+ if (actual !== file.sha256)
84
+ throw new Error(`${file.path} SHA-256 mismatch: expected ${file.sha256}, got ${actual}.`);
85
+ const destination = path.join(target, file.path);
86
+ await fs.mkdir(path.dirname(destination), { recursive: true });
87
+ await fs.writeFile(destination, content);
88
+ }
89
+ const policyDirs = (loaded.manifest.policyDirs?.length ? loaded.manifest.policyDirs : ["policies"]).map((relative) => path.relative(projectRoot, path.resolve(target, relative)).replaceAll("\\", "/"));
90
+ return { name: source.name, root: target, manifestSha256: manifestHash, verifiedSignature, policyDirs, extends: loaded.manifest.extends ?? [] };
91
+ }
92
+ async function loadLocalManifest(projectRoot, configuredPath) {
93
+ const source = path.resolve(projectRoot, configuredPath);
94
+ const stat = await fs.stat(source);
95
+ const manifestFile = stat.isDirectory() ? path.join(source, "bundle.json") : source;
96
+ const raw = await fs.readFile(manifestFile);
97
+ return { manifest: parseManifest(raw), raw };
98
+ }
99
+ async function loadRemoteManifest(url) {
100
+ const response = await fetch(url);
101
+ if (!response.ok)
102
+ throw new Error(`unable to fetch manifest ${url}: HTTP ${response.status}`);
103
+ const raw = Buffer.from(await response.arrayBuffer());
104
+ return { manifest: parseManifest(raw), raw };
105
+ }
106
+ function parseManifest(raw) {
107
+ const value = JSON.parse(raw.toString("utf8"));
108
+ if (value.version !== 1 || !value.name || !Array.isArray(value.files))
109
+ throw new Error("invalid organization policy bundle manifest.");
110
+ for (const file of value.files)
111
+ if (!file.path || !/^[a-f0-9]{64}$/.test(file.sha256))
112
+ throw new Error(`invalid bundle file declaration ${file.path ?? "<missing>"}.`);
113
+ return value;
114
+ }
115
+ async function readLocalBundleFile(projectRoot, configuredPath, relative) { const source = path.resolve(projectRoot, configuredPath); const stat = await fs.stat(source); const base = stat.isDirectory() ? source : path.dirname(source); return fs.readFile(path.resolve(base, relative)); }
116
+ async function readRemoteBundleFile(manifestUrl, relative) { const url = new URL(relative, manifestUrl).toString(); const response = await fetch(url); if (!response.ok)
117
+ throw new Error(`unable to fetch bundle file ${url}: HTTP ${response.status}`); return Buffer.from(await response.arrayBuffer()); }
118
+ async function verifySignature(root, manifestFile, signature, publicKey) {
119
+ if (!(await commandExists("cosign", root)))
120
+ throw new Error("cosign is required to verify the configured organization policy bundle signature.");
121
+ const signaturePath = path.resolve(root, signature);
122
+ const keyPath = path.resolve(root, publicKey);
123
+ const result = await runProcess(`cosign verify-blob --key ${quote(keyPath)} --signature ${quote(signaturePath)} ${quote(manifestFile)}`, { cwd: root, timeoutMs: 60_000 });
124
+ return result.exitCode === 0;
125
+ }
126
+ function sha256(value) { return crypto.createHash("sha256").update(value).digest("hex"); }
127
+ function safe(value) { return value.replace(/[^A-Za-z0-9._-]/g, "-"); }
128
+ function quote(value) { return `'${value.replaceAll("'", "'\\''")}'`; }
129
+ //# sourceMappingURL=bundles.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bundles.js","sourceRoot":"","sources":["../../src/policy/bundles.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ import type { AgentExecutionSelection } from "../agents/types.js";
2
+ import type { HarnessProjectConfig, TaskRisk } from "../core/types.js";
3
+ export interface SandboxDecision {
4
+ required: boolean;
5
+ provider: string;
6
+ reasons: string[];
7
+ selection: AgentExecutionSelection;
8
+ }
9
+ export declare function enforceSandboxPolicy(selection: AgentExecutionSelection, config: HarnessProjectConfig, risk?: TaskRisk): SandboxDecision;
10
+ export declare function hardenedPodmanArgs(config: HarnessProjectConfig, selection: AgentExecutionSelection, writable: boolean): string[];
11
+ export declare function sandboxImage(config: HarnessProjectConfig): string;
12
+ export declare function allowedSandboxEnvironment(config: HarnessProjectConfig, source?: NodeJS.ProcessEnv): Record<string, string>;
@@ -0,0 +1,64 @@
1
+ export function enforceSandboxPolicy(selection, config, risk = "low") {
2
+ const sandbox = config.security?.sandbox;
3
+ const force = (sandbox?.forceForRisks ?? []).includes(risk);
4
+ const required = sandbox?.required === true || force;
5
+ const provider = sandbox?.provider ?? "podman";
6
+ if (!required)
7
+ return { required: false, provider, reasons: [], selection };
8
+ if (provider === "none")
9
+ throw new Error(`Sandbox is required for ${risk}-risk work but security.sandbox.provider is none.`);
10
+ if (selection.runtimeAdapter !== "opencode")
11
+ throw new Error(`Sandbox policy requires ${provider}, but runtime ${selection.runtimeAdapter} is not supported by the hardened worker sandbox.`);
12
+ if (!sandbox?.image)
13
+ throw new Error("Sandbox policy requires security.sandbox.image.");
14
+ return { required: true, provider, reasons: force ? [`risk:${risk}`] : ["security.sandbox.required"], selection: { ...selection, transport: provider === "podman" ? "podman" : selection.transport } };
15
+ }
16
+ export function hardenedPodmanArgs(config, selection, writable) {
17
+ const sandbox = config.security?.sandbox;
18
+ const args = ["--rm", "-i", "--userns=keep-id"];
19
+ if (sandbox?.readOnlyRoot !== false)
20
+ args.push("--read-only");
21
+ if (sandbox?.capDropAll !== false)
22
+ args.push("--cap-drop=ALL");
23
+ if (sandbox?.noNewPrivileges !== false)
24
+ args.push("--security-opt=no-new-privileges");
25
+ args.push(`--pids-limit=${sandbox?.pidsLimit ?? 512}`);
26
+ if (sandbox?.memory)
27
+ args.push(`--memory=${sandbox.memory}`);
28
+ if (sandbox?.cpus)
29
+ args.push(`--cpus=${sandbox.cpus}`);
30
+ if (sandbox?.network === false || selection.permissions.network === "deny")
31
+ args.push("--network=none");
32
+ const tmpfs = sandbox?.tmpfs ?? ["/tmp:rw,nosuid,nodev,noexec,size=1g"];
33
+ for (const mount of tmpfs)
34
+ args.push(`--tmpfs=${mount}`);
35
+ if (sandbox?.ephemeralHome !== false) {
36
+ args.push("--tmpfs=/home/aeh:rw,nosuid,nodev,size=256m");
37
+ args.push("--env=HOME=/home/aeh");
38
+ }
39
+ if (!writable)
40
+ args.push("--env=AEH_WORKSPACE_READ_ONLY=1");
41
+ for (const extra of sandbox?.extraArgs ?? [])
42
+ args.push(extra);
43
+ return args;
44
+ }
45
+ export function sandboxImage(config) {
46
+ const sandbox = config.security?.sandbox;
47
+ if (!sandbox?.image)
48
+ throw new Error("security.sandbox.image is required for Podman execution.");
49
+ if (!sandbox.imageDigest || sandbox.image.includes("@sha256:"))
50
+ return sandbox.image;
51
+ const digest = sandbox.imageDigest.startsWith("sha256:") ? sandbox.imageDigest : `sha256:${sandbox.imageDigest}`;
52
+ return `${sandbox.image.replace(/:[^/@]+$/, "")}@${digest}`;
53
+ }
54
+ export function allowedSandboxEnvironment(config, source = process.env) {
55
+ const sandbox = config.security?.sandbox;
56
+ const allowed = new Set(sandbox?.environmentAllowlist ?? []);
57
+ const credentials = new Set(sandbox?.credentialEnvAllowlist ?? []);
58
+ const result = {};
59
+ for (const name of [...allowed, ...credentials])
60
+ if (source[name] !== undefined)
61
+ result[name] = source[name];
62
+ return result;
63
+ }
64
+ //# sourceMappingURL=sandbox.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sandbox.js","sourceRoot":"","sources":["../../src/security/sandbox.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,28 @@
1
+ import type { HarnessProjectConfig } from "../core/types.js";
2
+ import { runProcess } from "../utils/process.js";
3
+ export interface OpenSpecAuthoringConfig {
4
+ provider?: "openspec" | "native" | string;
5
+ schema?: string;
6
+ managerAgent?: string;
7
+ }
8
+ export interface OpenSpecPreparedChange {
9
+ taskId: string;
10
+ changeName: string;
11
+ directory: string;
12
+ created: boolean;
13
+ schema: string;
14
+ managerAgent: string;
15
+ }
16
+ export interface OpenSpecCompileResult {
17
+ taskId: string;
18
+ changeName: string;
19
+ sddDirectory: string;
20
+ contractPath: string;
21
+ requirements: string[];
22
+ sourceSha256: string;
23
+ validatorId: string;
24
+ }
25
+ export declare function openSpecAuthoringConfig(config: HarnessProjectConfig): Required<Pick<OpenSpecAuthoringConfig, "provider" | "schema" | "managerAgent">>;
26
+ export declare function openSpecChangeName(taskId: string): string;
27
+ export declare function prepareOpenSpecChange(root: string, config: HarnessProjectConfig, taskId: string, title: string, run?: typeof runProcess): Promise<OpenSpecPreparedChange>;
28
+ export declare function compileOpenSpecChange(root: string, config: HarnessProjectConfig, taskId: string, title: string, changeName?: string, run?: typeof runProcess): Promise<OpenSpecCompileResult>;