oxe-cc 0.9.3 → 1.0.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/README.md +1 -1
- package/bin/banner.txt +1 -1
- package/bin/lib/oxe-dashboard.cjs +9 -7
- package/bin/lib/oxe-operational.cjs +569 -4
- package/bin/oxe-cc.js +141 -57
- package/lib/runtime/compiler/graph-compiler.d.ts +83 -0
- package/lib/runtime/compiler/graph-compiler.js +135 -0
- package/lib/runtime/compiler/index.d.ts +1 -0
- package/lib/runtime/compiler/index.js +17 -0
- package/lib/runtime/context/context-pack-builder.d.ts +36 -0
- package/lib/runtime/context/context-pack-builder.js +136 -0
- package/lib/runtime/context/index.d.ts +1 -0
- package/lib/runtime/context/index.js +17 -0
- package/lib/runtime/delivery/branch-manager.d.ts +19 -0
- package/lib/runtime/delivery/branch-manager.js +78 -0
- package/lib/runtime/delivery/ci-checks.d.ts +34 -0
- package/lib/runtime/delivery/ci-checks.js +209 -0
- package/lib/runtime/delivery/index.d.ts +3 -0
- package/lib/runtime/delivery/index.js +19 -0
- package/lib/runtime/delivery/pr-manager.d.ts +30 -0
- package/lib/runtime/delivery/pr-manager.js +82 -0
- package/lib/runtime/events/bus.d.ts +9 -0
- package/lib/runtime/events/bus.js +63 -0
- package/lib/runtime/events/catalog.d.ts +3 -0
- package/lib/runtime/events/catalog.js +30 -0
- package/lib/runtime/events/envelope.d.ts +13 -0
- package/lib/runtime/events/envelope.js +2 -0
- package/lib/runtime/events/index.d.ts +3 -0
- package/lib/runtime/events/index.js +19 -0
- package/lib/runtime/evidence/evidence-store.d.ts +22 -0
- package/lib/runtime/evidence/evidence-store.js +106 -0
- package/lib/runtime/evidence/index.d.ts +1 -0
- package/lib/runtime/evidence/index.js +17 -0
- package/lib/runtime/gate/gate-manager.d.ts +39 -0
- package/lib/runtime/gate/gate-manager.js +104 -0
- package/lib/runtime/gate/index.d.ts +1 -0
- package/lib/runtime/gate/index.js +17 -0
- package/lib/runtime/index.d.ts +16 -0
- package/lib/runtime/index.js +40 -0
- package/lib/runtime/models/attempt.d.ts +12 -0
- package/lib/runtime/models/attempt.js +2 -0
- package/lib/runtime/models/evidence.d.ts +9 -0
- package/lib/runtime/models/evidence.js +2 -0
- package/lib/runtime/models/gate-decision.d.ts +10 -0
- package/lib/runtime/models/gate-decision.js +2 -0
- package/lib/runtime/models/index.d.ts +8 -0
- package/lib/runtime/models/index.js +24 -0
- package/lib/runtime/models/run.d.ts +13 -0
- package/lib/runtime/models/run.js +2 -0
- package/lib/runtime/models/session.d.ts +10 -0
- package/lib/runtime/models/session.js +2 -0
- package/lib/runtime/models/verification-result.d.ts +9 -0
- package/lib/runtime/models/verification-result.js +2 -0
- package/lib/runtime/models/work-item.d.ts +15 -0
- package/lib/runtime/models/work-item.js +2 -0
- package/lib/runtime/models/workspace.d.ts +25 -0
- package/lib/runtime/models/workspace.js +2 -0
- package/lib/runtime/plugins/index.d.ts +2 -0
- package/lib/runtime/plugins/index.js +18 -0
- package/lib/runtime/plugins/plugin-abi.d.ts +76 -0
- package/lib/runtime/plugins/plugin-abi.js +2 -0
- package/lib/runtime/plugins/plugin-registry.d.ts +21 -0
- package/lib/runtime/plugins/plugin-registry.js +114 -0
- package/lib/runtime/policy/index.d.ts +1 -0
- package/lib/runtime/policy/index.js +17 -0
- package/lib/runtime/policy/policy-engine.d.ts +40 -0
- package/lib/runtime/policy/policy-engine.js +80 -0
- package/lib/runtime/projection/index.d.ts +1 -0
- package/lib/runtime/projection/index.js +17 -0
- package/lib/runtime/projection/projection-engine.d.ts +11 -0
- package/lib/runtime/projection/projection-engine.js +218 -0
- package/lib/runtime/reducers/debug-reducer.d.ts +10 -0
- package/lib/runtime/reducers/debug-reducer.js +30 -0
- package/lib/runtime/reducers/index.d.ts +2 -0
- package/lib/runtime/reducers/index.js +18 -0
- package/lib/runtime/reducers/run-state-reducer.d.ts +20 -0
- package/lib/runtime/reducers/run-state-reducer.js +110 -0
- package/lib/runtime/scheduler/index.d.ts +1 -0
- package/lib/runtime/scheduler/index.js +17 -0
- package/lib/runtime/scheduler/multi-agent-coordinator.d.ts +34 -0
- package/lib/runtime/scheduler/multi-agent-coordinator.js +166 -0
- package/lib/runtime/scheduler/scheduler.d.ts +39 -0
- package/lib/runtime/scheduler/scheduler.js +196 -0
- package/lib/runtime/verification/index.d.ts +1 -0
- package/lib/runtime/verification/index.js +17 -0
- package/lib/runtime/verification/verification-compiler.d.ts +56 -0
- package/lib/runtime/verification/verification-compiler.js +147 -0
- package/lib/runtime/workspace/index.d.ts +5 -0
- package/lib/runtime/workspace/index.js +24 -0
- package/lib/runtime/workspace/strategies/ephemeral-container.d.ts +22 -0
- package/lib/runtime/workspace/strategies/ephemeral-container.js +109 -0
- package/lib/runtime/workspace/strategies/git-worktree.d.ts +12 -0
- package/lib/runtime/workspace/strategies/git-worktree.js +79 -0
- package/lib/runtime/workspace/strategies/inplace.d.ts +10 -0
- package/lib/runtime/workspace/strategies/inplace.js +37 -0
- package/lib/runtime/workspace/workspace-manager.d.ts +13 -0
- package/lib/runtime/workspace/workspace-manager.js +2 -0
- package/lib/sdk/index.cjs +24 -7
- package/lib/sdk/index.d.ts +17 -7
- package/package.json +9 -3
- package/packages/runtime/package.json +17 -0
- package/packages/runtime/src/compiler/graph-compiler.ts +245 -0
- package/packages/runtime/src/compiler/index.ts +1 -0
- package/packages/runtime/src/context/context-pack-builder.ts +193 -0
- package/packages/runtime/src/context/index.ts +1 -0
- package/packages/runtime/src/delivery/branch-manager.ts +84 -0
- package/packages/runtime/src/delivery/ci-checks.ts +252 -0
- package/packages/runtime/src/delivery/index.ts +3 -0
- package/packages/runtime/src/delivery/pr-manager.ts +112 -0
- package/packages/runtime/src/events/bus.ts +92 -0
- package/packages/runtime/src/events/catalog.ts +29 -0
- package/packages/runtime/src/events/envelope.ts +14 -0
- package/packages/runtime/src/events/index.ts +3 -0
- package/packages/runtime/src/evidence/evidence-store.ts +130 -0
- package/packages/runtime/src/evidence/index.ts +1 -0
- package/packages/runtime/src/gate/gate-manager.ts +137 -0
- package/packages/runtime/src/gate/index.ts +1 -0
- package/packages/runtime/src/index.ts +32 -0
- package/packages/runtime/src/models/attempt.ts +19 -0
- package/packages/runtime/src/models/evidence.ts +21 -0
- package/packages/runtime/src/models/gate-decision.ts +21 -0
- package/packages/runtime/src/models/index.ts +8 -0
- package/packages/runtime/src/models/run.ts +24 -0
- package/packages/runtime/src/models/session.ts +11 -0
- package/packages/runtime/src/models/verification-result.ts +10 -0
- package/packages/runtime/src/models/work-item.ts +25 -0
- package/packages/runtime/src/models/workspace.ts +28 -0
- package/packages/runtime/src/plugins/index.ts +2 -0
- package/packages/runtime/src/plugins/plugin-abi.ts +95 -0
- package/packages/runtime/src/plugins/plugin-registry.ts +119 -0
- package/packages/runtime/src/policy/index.ts +1 -0
- package/packages/runtime/src/policy/policy-engine.ts +113 -0
- package/packages/runtime/src/projection/index.ts +1 -0
- package/packages/runtime/src/projection/projection-engine.ts +249 -0
- package/packages/runtime/src/reducers/debug-reducer.ts +36 -0
- package/packages/runtime/src/reducers/index.ts +2 -0
- package/packages/runtime/src/reducers/run-state-reducer.ts +127 -0
- package/packages/runtime/src/scheduler/index.ts +1 -0
- package/packages/runtime/src/scheduler/multi-agent-coordinator.ts +231 -0
- package/packages/runtime/src/scheduler/scheduler.ts +281 -0
- package/packages/runtime/src/verification/index.ts +1 -0
- package/packages/runtime/src/verification/verification-compiler.ts +225 -0
- package/packages/runtime/src/workspace/index.ts +5 -0
- package/packages/runtime/src/workspace/strategies/ephemeral-container.ts +121 -0
- package/packages/runtime/src/workspace/strategies/git-worktree.ts +77 -0
- package/packages/runtime/src/workspace/strategies/inplace.ts +35 -0
- package/packages/runtime/src/workspace/workspace-manager.ts +15 -0
- package/packages/runtime/tsconfig.json +17 -0
- package/vscode-extension/oxe-agents-0.9.2.vsix +0 -0
- package/vscode-extension/oxe-agents-1.0.0.vsix +0 -0
- package/vscode-extension/package.json +1 -1
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.compile = compile;
|
|
7
|
+
exports.runCheck = runCheck;
|
|
8
|
+
exports.runSuite = runSuite;
|
|
9
|
+
exports.summarizeSuite = summarizeSuite;
|
|
10
|
+
const crypto_1 = __importDefault(require("crypto"));
|
|
11
|
+
const child_process_1 = require("child_process");
|
|
12
|
+
function inferCheckType(howToVerify) {
|
|
13
|
+
const v = howToVerify.toLowerCase();
|
|
14
|
+
if (v.includes('npm test') || v.includes('jest') || v.includes('vitest') || v.includes('node --test'))
|
|
15
|
+
return 'unit';
|
|
16
|
+
if (v.includes('postman') || v.includes('newman') || v.includes('integration'))
|
|
17
|
+
return 'integration';
|
|
18
|
+
if (v.includes('smoke') || v.includes('curl'))
|
|
19
|
+
return 'smoke';
|
|
20
|
+
if (v.includes('eslint') || v.includes('lint') || v.includes('oxe-policy'))
|
|
21
|
+
return 'policy';
|
|
22
|
+
if (v.includes('security') || v.includes('audit') || v.includes('trivy'))
|
|
23
|
+
return 'security';
|
|
24
|
+
return 'custom';
|
|
25
|
+
}
|
|
26
|
+
function inferEvidenceType(checkType) {
|
|
27
|
+
switch (checkType) {
|
|
28
|
+
case 'unit': return 'junit_xml';
|
|
29
|
+
case 'integration': return 'api_output';
|
|
30
|
+
case 'security': return 'security_report';
|
|
31
|
+
case 'policy': return 'log';
|
|
32
|
+
default: return 'stdout';
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
function compile(spec, plan) {
|
|
36
|
+
const checks = [];
|
|
37
|
+
const seenRefs = new Set();
|
|
38
|
+
// Generate checks from spec criteria
|
|
39
|
+
for (const criterion of spec.criteria) {
|
|
40
|
+
// Find the verify command from the task that references this criterion
|
|
41
|
+
const task = plan.tasks.find((t) => t.aceite.includes(criterion.id));
|
|
42
|
+
const command = task?.verifyCommand ?? null;
|
|
43
|
+
const type = inferCheckType(criterion.howToVerify);
|
|
44
|
+
checks.push({
|
|
45
|
+
id: `check-${criterion.id.toLowerCase()}`,
|
|
46
|
+
type,
|
|
47
|
+
command: command ?? (criterion.howToVerify.startsWith('#') ? null : criterion.howToVerify),
|
|
48
|
+
evidence_type_expected: inferEvidenceType(type),
|
|
49
|
+
acceptance_ref: criterion.id,
|
|
50
|
+
description: criterion.criterion,
|
|
51
|
+
});
|
|
52
|
+
seenRefs.add(criterion.id);
|
|
53
|
+
}
|
|
54
|
+
// Add checks for task verify commands not already covered
|
|
55
|
+
for (const task of plan.tasks) {
|
|
56
|
+
if (!task.verifyCommand)
|
|
57
|
+
continue;
|
|
58
|
+
const uncovered = task.aceite.filter((ref) => !seenRefs.has(ref));
|
|
59
|
+
if (uncovered.length === 0 && checks.some((c) => c.command === task.verifyCommand))
|
|
60
|
+
continue;
|
|
61
|
+
checks.push({
|
|
62
|
+
id: `check-task-${task.id.toLowerCase()}`,
|
|
63
|
+
type: inferCheckType(task.verifyCommand),
|
|
64
|
+
command: task.verifyCommand,
|
|
65
|
+
evidence_type_expected: 'stdout',
|
|
66
|
+
acceptance_ref: uncovered[0] ?? null,
|
|
67
|
+
description: `Verify command for task ${task.id}`,
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
return {
|
|
71
|
+
checks,
|
|
72
|
+
compiled_at: new Date().toISOString(),
|
|
73
|
+
spec_hash: hashObject(spec),
|
|
74
|
+
plan_hash: hashObject(plan),
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
async function runCheck(check, cwd, timeoutMs = 60000) {
|
|
78
|
+
if (!check.command) {
|
|
79
|
+
return {
|
|
80
|
+
check_id: check.id,
|
|
81
|
+
acceptance_ref: check.acceptance_ref,
|
|
82
|
+
status: 'skip',
|
|
83
|
+
stdout: '',
|
|
84
|
+
stderr: '',
|
|
85
|
+
exit_code: null,
|
|
86
|
+
duration_ms: 0,
|
|
87
|
+
error: null,
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
const start = Date.now();
|
|
91
|
+
try {
|
|
92
|
+
// Split command into program + args (simple split; no shell expansion)
|
|
93
|
+
const parts = check.command.split(/\s+/);
|
|
94
|
+
const prog = parts[0];
|
|
95
|
+
const args = parts.slice(1);
|
|
96
|
+
const result = (0, child_process_1.spawnSync)(prog, args, {
|
|
97
|
+
cwd,
|
|
98
|
+
encoding: 'utf8',
|
|
99
|
+
timeout: timeoutMs,
|
|
100
|
+
maxBuffer: 2 * 1024 * 1024,
|
|
101
|
+
});
|
|
102
|
+
const duration_ms = Date.now() - start;
|
|
103
|
+
const status = result.status === 0 ? 'pass' : 'fail';
|
|
104
|
+
return {
|
|
105
|
+
check_id: check.id,
|
|
106
|
+
acceptance_ref: check.acceptance_ref,
|
|
107
|
+
status,
|
|
108
|
+
stdout: result.stdout ?? '',
|
|
109
|
+
stderr: result.stderr ?? '',
|
|
110
|
+
exit_code: result.status ?? null,
|
|
111
|
+
duration_ms,
|
|
112
|
+
error: result.error ? String(result.error) : null,
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
catch (err) {
|
|
116
|
+
return {
|
|
117
|
+
check_id: check.id,
|
|
118
|
+
acceptance_ref: check.acceptance_ref,
|
|
119
|
+
status: 'error',
|
|
120
|
+
stdout: '',
|
|
121
|
+
stderr: '',
|
|
122
|
+
exit_code: null,
|
|
123
|
+
duration_ms: Date.now() - start,
|
|
124
|
+
error: String(err),
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
async function runSuite(suite, cwd, timeoutMs = 60000) {
|
|
129
|
+
const results = [];
|
|
130
|
+
for (const check of suite.checks) {
|
|
131
|
+
results.push(await runCheck(check, cwd, timeoutMs));
|
|
132
|
+
}
|
|
133
|
+
return results;
|
|
134
|
+
}
|
|
135
|
+
function summarizeSuite(results) {
|
|
136
|
+
const counts = { total: results.length, pass: 0, fail: 0, skip: 0, error: 0 };
|
|
137
|
+
for (const r of results)
|
|
138
|
+
counts[r.status]++;
|
|
139
|
+
return { ...counts, allPassed: counts.fail === 0 && counts.error === 0 };
|
|
140
|
+
}
|
|
141
|
+
function hashObject(obj) {
|
|
142
|
+
return crypto_1.default
|
|
143
|
+
.createHash('sha256')
|
|
144
|
+
.update(JSON.stringify(obj))
|
|
145
|
+
.digest('hex')
|
|
146
|
+
.slice(0, 12);
|
|
147
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export * from './workspace-manager';
|
|
2
|
+
export { InplaceWorkspaceManager } from './strategies/inplace';
|
|
3
|
+
export { GitWorktreeManager } from './strategies/git-worktree';
|
|
4
|
+
export { EphemeralContainerManager } from './strategies/ephemeral-container';
|
|
5
|
+
export type { ContainerOptions } from './strategies/ephemeral-container';
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
exports.EphemeralContainerManager = exports.GitWorktreeManager = exports.InplaceWorkspaceManager = void 0;
|
|
18
|
+
__exportStar(require("./workspace-manager"), exports);
|
|
19
|
+
var inplace_1 = require("./strategies/inplace");
|
|
20
|
+
Object.defineProperty(exports, "InplaceWorkspaceManager", { enumerable: true, get: function () { return inplace_1.InplaceWorkspaceManager; } });
|
|
21
|
+
var git_worktree_1 = require("./strategies/git-worktree");
|
|
22
|
+
Object.defineProperty(exports, "GitWorktreeManager", { enumerable: true, get: function () { return git_worktree_1.GitWorktreeManager; } });
|
|
23
|
+
var ephemeral_container_1 = require("./strategies/ephemeral-container");
|
|
24
|
+
Object.defineProperty(exports, "EphemeralContainerManager", { enumerable: true, get: function () { return ephemeral_container_1.EphemeralContainerManager; } });
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { WorkspaceManager, WorkspaceRequest } from '../workspace-manager';
|
|
2
|
+
import type { WorkspaceLease, SnapshotRef } from '../../models/workspace';
|
|
3
|
+
export interface ContainerOptions {
|
|
4
|
+
image: string;
|
|
5
|
+
mountPath: string;
|
|
6
|
+
extraEnv?: Record<string, string>;
|
|
7
|
+
/** Gracefully fall back to git_worktree if Docker is unavailable */
|
|
8
|
+
fallback?: boolean;
|
|
9
|
+
}
|
|
10
|
+
export declare class EphemeralContainerManager implements WorkspaceManager {
|
|
11
|
+
private readonly projectRoot;
|
|
12
|
+
private readonly opts;
|
|
13
|
+
private readonly fallbackManager;
|
|
14
|
+
private containerIds;
|
|
15
|
+
private useFallback;
|
|
16
|
+
constructor(projectRoot: string, opts?: ContainerOptions);
|
|
17
|
+
get usingFallback(): boolean;
|
|
18
|
+
allocate(req: WorkspaceRequest): Promise<WorkspaceLease>;
|
|
19
|
+
snapshot(id: string): Promise<SnapshotRef>;
|
|
20
|
+
reset(id: string, snapRef: SnapshotRef): Promise<void>;
|
|
21
|
+
dispose(id: string): Promise<void>;
|
|
22
|
+
}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.EphemeralContainerManager = void 0;
|
|
7
|
+
const child_process_1 = require("child_process");
|
|
8
|
+
const crypto_1 = __importDefault(require("crypto"));
|
|
9
|
+
const git_worktree_1 = require("./git-worktree");
|
|
10
|
+
function isDockerAvailable() {
|
|
11
|
+
const result = (0, child_process_1.spawnSync)('docker', ['version', '--format', '{{.Server.Version}}'], {
|
|
12
|
+
encoding: 'utf8',
|
|
13
|
+
timeout: 5000,
|
|
14
|
+
});
|
|
15
|
+
return result.status === 0;
|
|
16
|
+
}
|
|
17
|
+
class EphemeralContainerManager {
|
|
18
|
+
constructor(projectRoot, opts = { image: 'node:20-alpine', mountPath: '/workspace', fallback: true }) {
|
|
19
|
+
this.projectRoot = projectRoot;
|
|
20
|
+
this.opts = opts;
|
|
21
|
+
this.containerIds = new Map();
|
|
22
|
+
this.useFallback = false;
|
|
23
|
+
this.fallbackManager = new git_worktree_1.GitWorktreeManager(projectRoot);
|
|
24
|
+
if (!isDockerAvailable()) {
|
|
25
|
+
if (opts.fallback !== false) {
|
|
26
|
+
this.useFallback = true;
|
|
27
|
+
}
|
|
28
|
+
else {
|
|
29
|
+
throw new Error('Docker is not available and fallback is disabled');
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
get usingFallback() { return this.useFallback; }
|
|
34
|
+
async allocate(req) {
|
|
35
|
+
if (this.useFallback)
|
|
36
|
+
return this.fallbackManager.allocate(req);
|
|
37
|
+
const wsId = `ws-container-${req.work_item_id}-a${req.attempt_number}`;
|
|
38
|
+
const envArgs = Object.entries(this.opts.extraEnv ?? {}).flatMap(([k, v]) => ['-e', `${k}=${v}`]);
|
|
39
|
+
const result = (0, child_process_1.spawnSync)('docker', [
|
|
40
|
+
'run', '-d',
|
|
41
|
+
'-v', `${this.projectRoot}:${this.opts.mountPath}`,
|
|
42
|
+
'-w', this.opts.mountPath,
|
|
43
|
+
...envArgs,
|
|
44
|
+
this.opts.image,
|
|
45
|
+
'sleep', '3600',
|
|
46
|
+
], { encoding: 'utf8' });
|
|
47
|
+
if (result.status !== 0) {
|
|
48
|
+
if (this.opts.fallback !== false) {
|
|
49
|
+
this.useFallback = true;
|
|
50
|
+
return this.fallbackManager.allocate(req);
|
|
51
|
+
}
|
|
52
|
+
throw new Error(`docker run failed: ${result.stderr}`);
|
|
53
|
+
}
|
|
54
|
+
const containerId = result.stdout.trim().slice(0, 12);
|
|
55
|
+
this.containerIds.set(wsId, containerId);
|
|
56
|
+
return {
|
|
57
|
+
workspace_id: wsId,
|
|
58
|
+
strategy: 'ephemeral_container',
|
|
59
|
+
branch: null,
|
|
60
|
+
base_commit: null,
|
|
61
|
+
root_path: `docker:${containerId}:${this.opts.mountPath}`,
|
|
62
|
+
ttl_minutes: 60,
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
async snapshot(id) {
|
|
66
|
+
if (this.useFallback)
|
|
67
|
+
return this.fallbackManager.snapshot(id);
|
|
68
|
+
const containerId = this.containerIds.get(id);
|
|
69
|
+
if (!containerId)
|
|
70
|
+
throw new Error(`Container for workspace ${id} not found`);
|
|
71
|
+
const tag = `oxe-snap-${crypto_1.default.randomBytes(4).toString('hex')}`;
|
|
72
|
+
(0, child_process_1.execFileSync)('docker', ['commit', containerId, tag]);
|
|
73
|
+
return {
|
|
74
|
+
snapshot_id: tag,
|
|
75
|
+
workspace_id: id,
|
|
76
|
+
commit: tag,
|
|
77
|
+
created_at: new Date().toISOString(),
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
async reset(id, snapRef) {
|
|
81
|
+
if (this.useFallback)
|
|
82
|
+
return this.fallbackManager.reset(id, snapRef);
|
|
83
|
+
const containerId = this.containerIds.get(id);
|
|
84
|
+
if (!containerId)
|
|
85
|
+
return;
|
|
86
|
+
// Stop current container and start from snapshot
|
|
87
|
+
(0, child_process_1.spawnSync)('docker', ['stop', containerId]);
|
|
88
|
+
(0, child_process_1.spawnSync)('docker', ['rm', containerId]);
|
|
89
|
+
const result = (0, child_process_1.spawnSync)('docker', [
|
|
90
|
+
'run', '-d',
|
|
91
|
+
'-v', `${this.projectRoot}:${this.opts.mountPath}`,
|
|
92
|
+
snapRef.commit,
|
|
93
|
+
'sleep', '3600',
|
|
94
|
+
], { encoding: 'utf8' });
|
|
95
|
+
const newId = result.stdout.trim().slice(0, 12);
|
|
96
|
+
this.containerIds.set(id, newId);
|
|
97
|
+
}
|
|
98
|
+
async dispose(id) {
|
|
99
|
+
if (this.useFallback)
|
|
100
|
+
return this.fallbackManager.dispose(id);
|
|
101
|
+
const containerId = this.containerIds.get(id);
|
|
102
|
+
if (!containerId)
|
|
103
|
+
return;
|
|
104
|
+
(0, child_process_1.spawnSync)('docker', ['stop', containerId], { encoding: 'utf8' });
|
|
105
|
+
(0, child_process_1.spawnSync)('docker', ['rm', containerId], { encoding: 'utf8' });
|
|
106
|
+
this.containerIds.delete(id);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
exports.EphemeralContainerManager = EphemeralContainerManager;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { WorkspaceManager, WorkspaceRequest } from '../workspace-manager';
|
|
2
|
+
import type { WorkspaceLease, SnapshotRef } from '../../models/workspace';
|
|
3
|
+
export declare class GitWorktreeManager implements WorkspaceManager {
|
|
4
|
+
private readonly projectRoot;
|
|
5
|
+
private leases;
|
|
6
|
+
constructor(projectRoot: string);
|
|
7
|
+
allocate(req: WorkspaceRequest): Promise<WorkspaceLease>;
|
|
8
|
+
snapshot(id: string): Promise<SnapshotRef>;
|
|
9
|
+
reset(id: string, snapRef: SnapshotRef): Promise<void>;
|
|
10
|
+
dispose(id: string): Promise<void>;
|
|
11
|
+
private git;
|
|
12
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.GitWorktreeManager = void 0;
|
|
7
|
+
const child_process_1 = require("child_process");
|
|
8
|
+
const path_1 = __importDefault(require("path"));
|
|
9
|
+
const fs_1 = __importDefault(require("fs"));
|
|
10
|
+
const crypto_1 = __importDefault(require("crypto"));
|
|
11
|
+
class GitWorktreeManager {
|
|
12
|
+
constructor(projectRoot) {
|
|
13
|
+
this.projectRoot = projectRoot;
|
|
14
|
+
this.leases = new Map();
|
|
15
|
+
}
|
|
16
|
+
async allocate(req) {
|
|
17
|
+
const wsId = `ws-${req.work_item_id}-a${req.attempt_number}`;
|
|
18
|
+
const branch = `oxe/${req.work_item_id}-attempt${req.attempt_number}`;
|
|
19
|
+
const worktreePath = path_1.default.join(this.projectRoot, '.oxe', 'workspaces', wsId);
|
|
20
|
+
const baseCommit = this.git(['rev-parse', 'HEAD']).trim();
|
|
21
|
+
fs_1.default.mkdirSync(path_1.default.dirname(worktreePath), { recursive: true });
|
|
22
|
+
// Create worktree on a new branch starting from HEAD
|
|
23
|
+
this.git(['worktree', 'add', worktreePath, '-b', branch]);
|
|
24
|
+
const lease = {
|
|
25
|
+
workspace_id: wsId,
|
|
26
|
+
strategy: 'git_worktree',
|
|
27
|
+
branch,
|
|
28
|
+
base_commit: baseCommit,
|
|
29
|
+
root_path: worktreePath,
|
|
30
|
+
ttl_minutes: 45,
|
|
31
|
+
};
|
|
32
|
+
this.leases.set(wsId, lease);
|
|
33
|
+
return lease;
|
|
34
|
+
}
|
|
35
|
+
async snapshot(id) {
|
|
36
|
+
const lease = this.leases.get(id);
|
|
37
|
+
if (!lease || !lease.root_path)
|
|
38
|
+
throw new Error(`Workspace ${id} not found`);
|
|
39
|
+
const commit = this.git(['rev-parse', 'HEAD'], lease.root_path).trim();
|
|
40
|
+
return {
|
|
41
|
+
snapshot_id: `snap-${crypto_1.default.randomBytes(4).toString('hex')}`,
|
|
42
|
+
workspace_id: id,
|
|
43
|
+
commit,
|
|
44
|
+
created_at: new Date().toISOString(),
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
async reset(id, snapRef) {
|
|
48
|
+
const lease = this.leases.get(id);
|
|
49
|
+
if (!lease)
|
|
50
|
+
return;
|
|
51
|
+
this.git(['reset', '--hard', snapRef.commit], lease.root_path);
|
|
52
|
+
}
|
|
53
|
+
async dispose(id) {
|
|
54
|
+
const lease = this.leases.get(id);
|
|
55
|
+
if (!lease)
|
|
56
|
+
return;
|
|
57
|
+
try {
|
|
58
|
+
this.git(['worktree', 'remove', lease.root_path, '--force']);
|
|
59
|
+
}
|
|
60
|
+
catch {
|
|
61
|
+
// worktree may already be gone
|
|
62
|
+
}
|
|
63
|
+
try {
|
|
64
|
+
if (lease.branch)
|
|
65
|
+
this.git(['branch', '-D', lease.branch]);
|
|
66
|
+
}
|
|
67
|
+
catch {
|
|
68
|
+
// branch may already be deleted
|
|
69
|
+
}
|
|
70
|
+
this.leases.delete(id);
|
|
71
|
+
}
|
|
72
|
+
git(args, cwd) {
|
|
73
|
+
return (0, child_process_1.execFileSync)('git', args, {
|
|
74
|
+
cwd: cwd ?? this.projectRoot,
|
|
75
|
+
encoding: 'utf8',
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
exports.GitWorktreeManager = GitWorktreeManager;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { WorkspaceManager, WorkspaceRequest } from '../workspace-manager';
|
|
2
|
+
import type { WorkspaceLease, SnapshotRef } from '../../models/workspace';
|
|
3
|
+
export declare class InplaceWorkspaceManager implements WorkspaceManager {
|
|
4
|
+
private readonly projectRoot;
|
|
5
|
+
constructor(projectRoot: string);
|
|
6
|
+
allocate(req: WorkspaceRequest): Promise<WorkspaceLease>;
|
|
7
|
+
snapshot(id: string): Promise<SnapshotRef>;
|
|
8
|
+
reset(_id: string, _snapRef: SnapshotRef): Promise<void>;
|
|
9
|
+
dispose(_id: string): Promise<void>;
|
|
10
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.InplaceWorkspaceManager = void 0;
|
|
7
|
+
const crypto_1 = __importDefault(require("crypto"));
|
|
8
|
+
class InplaceWorkspaceManager {
|
|
9
|
+
constructor(projectRoot) {
|
|
10
|
+
this.projectRoot = projectRoot;
|
|
11
|
+
}
|
|
12
|
+
async allocate(req) {
|
|
13
|
+
return {
|
|
14
|
+
workspace_id: `ws-inplace-${req.work_item_id}-a${req.attempt_number}`,
|
|
15
|
+
strategy: 'inplace',
|
|
16
|
+
branch: null,
|
|
17
|
+
base_commit: null,
|
|
18
|
+
root_path: this.projectRoot,
|
|
19
|
+
ttl_minutes: 60,
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
async snapshot(id) {
|
|
23
|
+
return {
|
|
24
|
+
snapshot_id: `snap-${crypto_1.default.randomBytes(4).toString('hex')}`,
|
|
25
|
+
workspace_id: id,
|
|
26
|
+
commit: 'HEAD',
|
|
27
|
+
created_at: new Date().toISOString(),
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
async reset(_id, _snapRef) {
|
|
31
|
+
// inplace: no filesystem isolation — reset is a no-op
|
|
32
|
+
}
|
|
33
|
+
async dispose(_id) {
|
|
34
|
+
// inplace: nothing to tear down
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
exports.InplaceWorkspaceManager = InplaceWorkspaceManager;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { WorkspaceLease, SnapshotRef, WorkspaceStrategy } from '../models/workspace';
|
|
2
|
+
export interface WorkspaceRequest {
|
|
3
|
+
work_item_id: string;
|
|
4
|
+
attempt_number: number;
|
|
5
|
+
strategy: WorkspaceStrategy;
|
|
6
|
+
mutation_scope: string[];
|
|
7
|
+
}
|
|
8
|
+
export interface WorkspaceManager {
|
|
9
|
+
allocate(req: WorkspaceRequest): Promise<WorkspaceLease>;
|
|
10
|
+
snapshot(id: string): Promise<SnapshotRef>;
|
|
11
|
+
reset(id: string, snapRef: SnapshotRef): Promise<void>;
|
|
12
|
+
dispose(id: string): Promise<void>;
|
|
13
|
+
}
|
package/lib/sdk/index.cjs
CHANGED
|
@@ -648,13 +648,20 @@ module.exports = {
|
|
|
648
648
|
operationalPaths: operational.operationalPaths,
|
|
649
649
|
appendEvent: operational.appendEvent,
|
|
650
650
|
readEvents: operational.readEvents,
|
|
651
|
-
summarizeEvents: operational.summarizeEvents,
|
|
652
|
-
writeRunState: operational.writeRunState,
|
|
653
|
-
readRunState: operational.readRunState,
|
|
654
|
-
buildOperationalGraph: operational.buildOperationalGraph,
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
651
|
+
summarizeEvents: operational.summarizeEvents,
|
|
652
|
+
writeRunState: operational.writeRunState,
|
|
653
|
+
readRunState: operational.readRunState,
|
|
654
|
+
buildOperationalGraph: operational.buildOperationalGraph,
|
|
655
|
+
serializeCanonicalState: operational.serializeCanonicalState,
|
|
656
|
+
hydrateCanonicalState: operational.hydrateCanonicalState,
|
|
657
|
+
reduceCanonicalRunState: operational.reduceCanonicalRunState,
|
|
658
|
+
compileExecutionGraphFromArtifacts: operational.compileExecutionGraphFromArtifacts,
|
|
659
|
+
compileVerificationSuiteFromArtifacts: operational.compileVerificationSuiteFromArtifacts,
|
|
660
|
+
projectRuntimeArtifacts: operational.projectRuntimeArtifacts,
|
|
661
|
+
runRuntimeCiChecks: operational.runRuntimeCiChecks,
|
|
662
|
+
applyRuntimeAction: operational.applyRuntimeAction,
|
|
663
|
+
parseCapabilityManifest: operational.parseCapabilityManifest,
|
|
664
|
+
readCapabilityCatalog: operational.readCapabilityCatalog,
|
|
658
665
|
buildMemoryLayers: operational.buildMemoryLayers,
|
|
659
666
|
replayEvents: operational.replayEvents,
|
|
660
667
|
},
|
|
@@ -735,3 +742,13 @@ module.exports = {
|
|
|
735
742
|
/** Um único objeto com verificações tipo `doctor` + relatório de saúde. */
|
|
736
743
|
runDoctorChecks,
|
|
737
744
|
};
|
|
745
|
+
|
|
746
|
+
|
|
747
|
+
// Re-exports from @oxe/runtime (R1 — Runtime Foundation)
|
|
748
|
+
// The compiled runtime lives at lib/runtime/ alongside this file.
|
|
749
|
+
try {
|
|
750
|
+
const runtime = require('../runtime/index.js');
|
|
751
|
+
Object.assign(module.exports, runtime);
|
|
752
|
+
} catch {
|
|
753
|
+
// Runtime not built yet — safe to skip during development
|
|
754
|
+
}
|
package/lib/sdk/index.d.ts
CHANGED
|
@@ -573,13 +573,20 @@ export interface OxeSdk {
|
|
|
573
573
|
operationalPaths: (projectRoot: string, activeSession: string | null) => Record<string, string | null>;
|
|
574
574
|
appendEvent: (projectRoot: string, activeSession: string | null, event?: Record<string, unknown>) => Record<string, unknown>;
|
|
575
575
|
readEvents: (projectRoot: string, activeSession: string | null) => Array<Record<string, unknown>>;
|
|
576
|
-
summarizeEvents: (events: Array<Record<string, unknown>>) => Record<string, unknown>;
|
|
577
|
-
writeRunState: (projectRoot: string, activeSession: string | null, runState?: Record<string, unknown>) => Record<string, unknown>;
|
|
578
|
-
readRunState: (projectRoot: string, activeSession: string | null) => Record<string, unknown> | null;
|
|
579
|
-
buildOperationalGraph: (runState?: Record<string, unknown>) => { nodes: Array<Record<string, unknown>>; edges: Array<Record<string, unknown>> };
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
576
|
+
summarizeEvents: (events: Array<Record<string, unknown>>) => Record<string, unknown>;
|
|
577
|
+
writeRunState: (projectRoot: string, activeSession: string | null, runState?: Record<string, unknown>) => Record<string, unknown>;
|
|
578
|
+
readRunState: (projectRoot: string, activeSession: string | null) => Record<string, unknown> | null;
|
|
579
|
+
buildOperationalGraph: (runState?: Record<string, unknown>) => { nodes: Array<Record<string, unknown>>; edges: Array<Record<string, unknown>> };
|
|
580
|
+
serializeCanonicalState: (state: unknown) => Record<string, unknown> | null;
|
|
581
|
+
hydrateCanonicalState: (serialized: unknown) => Record<string, unknown>;
|
|
582
|
+
reduceCanonicalRunState: (projectRoot: string, activeSession: string | null, options?: Record<string, unknown>) => Record<string, unknown> | null;
|
|
583
|
+
compileExecutionGraphFromArtifacts: (projectRoot: string, activeSession: string | null, options?: Record<string, unknown>) => Record<string, unknown>;
|
|
584
|
+
compileVerificationSuiteFromArtifacts: (projectRoot: string, activeSession: string | null, options?: Record<string, unknown>) => Record<string, unknown>;
|
|
585
|
+
projectRuntimeArtifacts: (projectRoot: string, activeSession: string | null, options?: Record<string, unknown>) => Record<string, unknown>;
|
|
586
|
+
runRuntimeCiChecks: (projectRoot: string, activeSession: string | null, options?: Record<string, unknown>) => Promise<Record<string, unknown>>;
|
|
587
|
+
applyRuntimeAction: (projectRoot: string, activeSession: string | null, input?: Record<string, unknown>) => Record<string, unknown>;
|
|
588
|
+
parseCapabilityManifest: (text: string) => Record<string, unknown>;
|
|
589
|
+
readCapabilityCatalog: (projectRoot: string) => Array<Record<string, unknown>>;
|
|
583
590
|
buildMemoryLayers: (projectRoot: string, activeSession: string | null) => Record<string, unknown>;
|
|
584
591
|
replayEvents: (projectRoot: string, activeSession: string | null, options?: {
|
|
585
592
|
fromEventId?: string;
|
|
@@ -631,3 +638,6 @@ export interface OxeSdk {
|
|
|
631
638
|
|
|
632
639
|
declare const sdk: OxeSdk;
|
|
633
640
|
export = sdk;
|
|
641
|
+
|
|
642
|
+
// Re-exports from @oxe/runtime (R1 — Runtime Foundation)
|
|
643
|
+
export * from '../runtime/index';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "oxe-cc",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "1.0.0",
|
|
4
4
|
"description": "OXE — spec-driven workflows in .oxe/; integrates with Cursor, GitHub Copilot, Claude, OpenCode, Gemini, Codex, Windsurf, Antigravity (npx)",
|
|
5
5
|
"license": "GPL-3.0",
|
|
6
6
|
"author": "",
|
|
@@ -49,14 +49,20 @@
|
|
|
49
49
|
".github",
|
|
50
50
|
"commands",
|
|
51
51
|
"vscode-extension",
|
|
52
|
+
"packages/runtime/src",
|
|
53
|
+
"packages/runtime/package.json",
|
|
54
|
+
"packages/runtime/tsconfig.json",
|
|
52
55
|
"AGENTS.md",
|
|
53
56
|
"README.md",
|
|
54
57
|
"CHANGELOG.md"
|
|
55
58
|
],
|
|
56
59
|
"scripts": {
|
|
60
|
+
"build:runtime": "cd packages/runtime && npm run build",
|
|
57
61
|
"sync:runtime-metadata": "node scripts/sync-runtime-metadata.cjs",
|
|
58
62
|
"sync:cursor": "node scripts/sync-cursor-from-prompts.cjs",
|
|
59
|
-
"test": "node --test tests/install.test.cjs tests/oxe-project-health.test.cjs tests/oxe-dashboard.test.cjs tests/oxe-operational.test.cjs tests/oxe-azure.test.cjs tests/oxe-sdk.test.cjs tests/oxe-manifest.test.cjs tests/oxe-agent-install.test.cjs tests/oxe-install-resolve-full.test.cjs tests/oxe-health-extended.test.cjs tests/oxe-workflows-edge.test.cjs tests/oxe-sdk-edge.test.cjs tests/oxe-cli-edge.test.cjs tests/oxe-npm-version.test.cjs tests/oxe-scripts.test.cjs tests/oxe-retro-health.test.cjs tests/oxe-security-permissions.test.cjs tests/oxe-runtime-semantics.test.cjs",
|
|
63
|
+
"test:root": "node --test tests/install.test.cjs tests/oxe-project-health.test.cjs tests/oxe-dashboard.test.cjs tests/oxe-operational.test.cjs tests/oxe-azure.test.cjs tests/oxe-sdk.test.cjs tests/oxe-manifest.test.cjs tests/oxe-agent-install.test.cjs tests/oxe-install-resolve-full.test.cjs tests/oxe-health-extended.test.cjs tests/oxe-workflows-edge.test.cjs tests/oxe-sdk-edge.test.cjs tests/oxe-cli-edge.test.cjs tests/oxe-npm-version.test.cjs tests/oxe-scripts.test.cjs tests/oxe-retro-health.test.cjs tests/oxe-security-permissions.test.cjs tests/oxe-runtime-semantics.test.cjs",
|
|
64
|
+
"test:runtime": "cd packages/runtime && npm test",
|
|
65
|
+
"test": "npm run build:runtime && npm run test:root && npm run test:runtime",
|
|
60
66
|
"test:coverage": "c8 --check-coverage --lines 82 --functions 85 --branches 58 --statements 82 npm test",
|
|
61
67
|
"scan:assets": "node scripts/oxe-assets-scan.cjs",
|
|
62
68
|
"build:vscode-ext": "cd vscode-extension && npx @vscode/vsce package --no-yarn --allow-missing-repository",
|
|
@@ -83,4 +89,4 @@
|
|
|
83
89
|
"dependencies": {
|
|
84
90
|
"semver": "^7.7.4"
|
|
85
91
|
}
|
|
86
|
-
}
|
|
92
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@oxe/runtime",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"private": true,
|
|
5
|
+
"description": "OXE agentic execution engine — Runtime Foundation (R1)",
|
|
6
|
+
"main": "../../lib/runtime/index.js",
|
|
7
|
+
"types": "../../lib/runtime/index.d.ts",
|
|
8
|
+
"scripts": {
|
|
9
|
+
"build": "tsc",
|
|
10
|
+
"test": "tsc --project tsconfig.test.json && node --test dist-tests/tests/*.test.js",
|
|
11
|
+
"clean": "node -e \"const fs=require('fs');['../../lib/runtime','dist-tests'].forEach(d=>{try{fs.rmSync(d,{recursive:true})}catch{}});\""
|
|
12
|
+
},
|
|
13
|
+
"devDependencies": {
|
|
14
|
+
"@types/node": "^25.6.0",
|
|
15
|
+
"typescript": "^5.4.5"
|
|
16
|
+
}
|
|
17
|
+
}
|