atris 3.35.0 → 3.37.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/AGENTS.md +37 -0
- package/README.md +5 -3
- package/atris/GETTING_STARTED.md +1 -1
- package/atris/atris.md +3 -0
- package/atris/policies/day-loop-voice.md +102 -0
- package/atris/policies/outbound-artifact-gate.md +2 -0
- package/atris/skills/design/SKILL.md +56 -32
- package/atris/skills/endgame/SKILL.md +12 -6
- package/atris/skills/engines/SKILL.md +22 -4
- package/atris/skills/fable-method/SKILL.md +66 -0
- package/atris/skills/improve/SKILL.md +65 -45
- package/atris/skills/youtube/SKILL.md +10 -1
- package/atris.md +2 -0
- package/ax +147 -19
- package/bin/atris.js +576 -267
- package/commands/activate.js +194 -88
- package/commands/agents.js +166 -0
- package/commands/autoland.js +459 -107
- package/commands/autopilot-front.js +20 -2
- package/commands/autopilot.js +118 -2
- package/commands/avail.js +407 -0
- package/commands/bench.js +188 -0
- package/commands/brain.js +3 -0
- package/commands/brief.js +651 -0
- package/commands/business-sync.js +192 -6
- package/commands/clean.js +50 -24
- package/commands/close.js +1083 -0
- package/commands/cloud.js +245 -0
- package/commands/compile.js +292 -1
- package/commands/computer.js +150 -3
- package/commands/dream.js +365 -0
- package/commands/drill.js +371 -0
- package/commands/engine.js +993 -32
- package/commands/experiments.js +28 -0
- package/commands/feedback.js +34 -12
- package/commands/fleet-report.js +206 -0
- package/commands/gm.js +23 -0
- package/commands/goal.js +247 -0
- package/commands/improve.js +642 -26
- package/commands/init.js +72 -44
- package/commands/interview.js +67 -1
- package/commands/land.js +152 -52
- package/commands/lifecycle.js +39 -3
- package/commands/log.js +84 -1
- package/commands/loops.js +220 -16
- package/commands/meet.js +220 -0
- package/commands/member.js +511 -34
- package/commands/mission.js +3144 -338
- package/commands/next.js +137 -0
- package/commands/now.js +220 -25
- package/commands/one-lap.js +776 -0
- package/commands/orb.js +314 -0
- package/commands/pack-craft.js +179 -0
- package/commands/pack.js +823 -0
- package/commands/play.js +3 -2
- package/commands/probe.js +30 -3
- package/commands/pulse.js +241 -46
- package/commands/push.js +260 -82
- package/commands/rainmaker.js +49 -0
- package/commands/report.js +415 -0
- package/commands/scout.js +147 -0
- package/commands/search.js +363 -0
- package/commands/skill.js +47 -3
- package/commands/slop.js +50 -2
- package/commands/soul.js +1 -1
- package/commands/stream.js +861 -0
- package/commands/study.js +693 -0
- package/commands/sync.js +67 -54
- package/commands/task.js +1346 -117
- package/commands/team.js +73 -0
- package/commands/verify.js +96 -0
- package/commands/watch.js +303 -0
- package/commands/wish.js +500 -0
- package/commands/workflow.js +11 -5
- package/commands/worktree.js +234 -13
- package/commands/xp.js +29 -11
- package/lib/auto-accept-certified.js +331 -34
- package/lib/autoland.js +319 -54
- package/lib/ax-auto-lane.js +96 -0
- package/lib/bench/context.js +147 -0
- package/lib/bench/engines.js +141 -0
- package/lib/bench/report.js +140 -0
- package/lib/bench/runner.js +512 -0
- package/lib/brief-ledger.js +350 -0
- package/lib/cloud-mission.js +259 -0
- package/lib/codex-flight.js +154 -0
- package/lib/default-runner.js +45 -0
- package/lib/default-verifier.js +70 -0
- package/lib/engine-registry.js +232 -0
- package/lib/experiments/daily.js +640 -0
- package/lib/fleet.js +2219 -67
- package/lib/improve-vitals-html.js +171 -0
- package/lib/known-commands.js +58 -0
- package/lib/loop-doctor.js +416 -0
- package/lib/member-switches.js +144 -0
- package/lib/mission-room.js +1 -0
- package/lib/mission-root.js +52 -0
- package/lib/next-moves.js +327 -10
- package/lib/one-lap-validator.js +60 -0
- package/lib/orb-context.js +477 -0
- package/lib/orb-scorecard.js +224 -0
- package/lib/policy-lessons.js +52 -1
- package/lib/pulse.js +277 -3
- package/lib/receipt-block.js +168 -0
- package/lib/receipt-evidence.js +65 -4
- package/lib/router-brain.js +352 -0
- package/lib/runner-command.js +10 -0
- package/lib/self-drive.js +258 -0
- package/lib/short-name.js +103 -0
- package/lib/spawn-env.js +18 -0
- package/lib/state-detection.js +56 -1
- package/lib/sync-status.js +59 -0
- package/lib/task-db.js +108 -29
- package/lib/task-proof.js +23 -1
- package/lib/team-presence.js +260 -0
- package/lib/tool-result-encode.js +7 -0
- package/lib/trust-tiers.js +90 -0
- package/lib/usage.js +107 -0
- package/lib/voice-gate.js +163 -0
- package/lib/wish-audit.js +1368 -0
- package/lib/wish-delegate.js +1840 -0
- package/lib/wish-design.js +110 -0
- package/lib/wish-stats.js +183 -0
- package/lib/wish-store.js +354 -0
- package/lib/zip.js +221 -0
- package/package.json +3 -1
- package/templates/loops/atris/loops/LOOPS.md +55 -0
- package/templates/loops/atris/loops/TICK.md +24 -0
- package/templates/loops/atris/loops/feedback.md +22 -0
- package/templates/loops/atris/loops/quality.md +22 -0
- package/templates/loops/atris/wiki/systems/loops.md +41 -0
- package/utils/api.js +5 -1
- package/utils/auth.js +57 -21
|
@@ -0,0 +1,371 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const os = require('os');
|
|
5
|
+
const path = require('path');
|
|
6
|
+
const { spawnSync } = require('child_process');
|
|
7
|
+
|
|
8
|
+
const VERIFY_COMMAND = 'node -e "process.exit(0)"';
|
|
9
|
+
const COAUTHOR = 'Co-authored-by: Atris <299057014+atris-builder[bot]@users.noreply.github.com>';
|
|
10
|
+
|
|
11
|
+
function hasFlag(args, name) {
|
|
12
|
+
return args.includes(name);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function runGit(args, cwd, options = {}) {
|
|
16
|
+
const result = spawnSync('git', args, { cwd, encoding: 'utf8' });
|
|
17
|
+
if (options.check === false || result.status === 0) return result;
|
|
18
|
+
const output = (result.stderr || result.stdout || `git ${args.join(' ')} failed`).trim();
|
|
19
|
+
throw new Error(output);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function parseJsonOutput(text) {
|
|
23
|
+
const raw = String(text || '').trim();
|
|
24
|
+
if (!raw) throw new Error('expected JSON output, got empty output');
|
|
25
|
+
return JSON.parse(raw);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function assertOk(condition, message) {
|
|
29
|
+
if (!condition) throw new Error(message);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
async function captureCommand(fn) {
|
|
33
|
+
const originalLog = console.log;
|
|
34
|
+
const originalError = console.error;
|
|
35
|
+
const originalExit = process.exit;
|
|
36
|
+
const originalExitCode = process.exitCode;
|
|
37
|
+
const stdout = [];
|
|
38
|
+
const stderr = [];
|
|
39
|
+
console.log = (...args) => stdout.push(args.map(String).join(' '));
|
|
40
|
+
console.error = (...args) => stderr.push(args.map(String).join(' '));
|
|
41
|
+
process.exitCode = undefined;
|
|
42
|
+
process.exit = (code = 0) => {
|
|
43
|
+
const error = new Error(`process.exit(${code})`);
|
|
44
|
+
error.isProcessExit = true;
|
|
45
|
+
error.exitCode = code;
|
|
46
|
+
throw error;
|
|
47
|
+
};
|
|
48
|
+
try {
|
|
49
|
+
const value = await fn();
|
|
50
|
+
return { value, stdout: stdout.join('\n'), stderr: stderr.join('\n') };
|
|
51
|
+
} catch (error) {
|
|
52
|
+
if (error && error.isProcessExit) {
|
|
53
|
+
const output = `${stderr.join('\n')}\n${stdout.join('\n')}`.trim();
|
|
54
|
+
error.message = output || `process.exit(${error.exitCode})`;
|
|
55
|
+
}
|
|
56
|
+
throw error;
|
|
57
|
+
} finally {
|
|
58
|
+
console.log = originalLog;
|
|
59
|
+
console.error = originalError;
|
|
60
|
+
process.exit = originalExit;
|
|
61
|
+
process.exitCode = originalExitCode;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
async function withSandboxProcessState(sandboxPath, envPatch, fn) {
|
|
66
|
+
const oldCwd = process.cwd();
|
|
67
|
+
const previousEnv = {};
|
|
68
|
+
for (const [key, value] of Object.entries(envPatch)) {
|
|
69
|
+
previousEnv[key] = process.env[key];
|
|
70
|
+
if (value === undefined) delete process.env[key];
|
|
71
|
+
else process.env[key] = value;
|
|
72
|
+
}
|
|
73
|
+
process.chdir(sandboxPath);
|
|
74
|
+
try {
|
|
75
|
+
return await fn();
|
|
76
|
+
} finally {
|
|
77
|
+
process.chdir(oldCwd);
|
|
78
|
+
for (const [key, value] of Object.entries(previousEnv)) {
|
|
79
|
+
if (value === undefined) delete process.env[key];
|
|
80
|
+
else process.env[key] = value;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
async function callInitAtris(sandboxPath) {
|
|
86
|
+
const { initAtris } = require('./init');
|
|
87
|
+
const oldArgv = process.argv;
|
|
88
|
+
process.argv = [process.execPath, 'atris', 'init', '--yes'];
|
|
89
|
+
try {
|
|
90
|
+
await captureCommand(() => initAtris());
|
|
91
|
+
} finally {
|
|
92
|
+
process.argv = oldArgv;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
async function createSandbox(ctx) {
|
|
97
|
+
ctx.tmpRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'atris-drill-'));
|
|
98
|
+
ctx.sandboxPath = path.join(ctx.tmpRoot, 'sandbox');
|
|
99
|
+
fs.mkdirSync(ctx.sandboxPath, { recursive: true });
|
|
100
|
+
runGit(['init', '-b', 'master'], ctx.sandboxPath);
|
|
101
|
+
runGit(['config', 'user.email', 'drill@example.invalid'], ctx.sandboxPath);
|
|
102
|
+
runGit(['config', 'user.name', 'Atris Drill'], ctx.sandboxPath);
|
|
103
|
+
fs.writeFileSync(path.join(ctx.sandboxPath, 'README.md'), '# Atris drill sandbox\n', 'utf8');
|
|
104
|
+
await withSandboxProcessState(ctx.sandboxPath, {
|
|
105
|
+
ATRIS_SKIP_UPDATE_CHECK: '1',
|
|
106
|
+
ATRIS_TASKS_DB: path.join(ctx.sandboxPath, '.atris', 'state', 'drill-tasks.db'),
|
|
107
|
+
NODE_NO_WARNINGS: '1',
|
|
108
|
+
}, async () => {
|
|
109
|
+
await callInitAtris(ctx.sandboxPath);
|
|
110
|
+
});
|
|
111
|
+
runGit(['add', '-A'], ctx.sandboxPath);
|
|
112
|
+
runGit(['commit', '-m', 'initial sandbox'], ctx.sandboxPath);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
async function wishCaptured(ctx) {
|
|
116
|
+
const { wishCommand, readWishes } = require('./wish');
|
|
117
|
+
const result = await captureCommand(() => wishCommand(['fix auth']));
|
|
118
|
+
assertOk(result.value === 1, `wish should request clarification with exit 1, got ${result.value}`);
|
|
119
|
+
const wishes = readWishes(ctx.sandboxPath);
|
|
120
|
+
assertOk(wishes.length > 0, 'wish ledger is empty');
|
|
121
|
+
const latest = wishes[wishes.length - 1];
|
|
122
|
+
assertOk(latest.status === 'needs_input', `wish status should be needs_input, got ${latest.status}`);
|
|
123
|
+
assertOk(latest.text === 'fix auth', `wish text mismatch: ${latest.text}`);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
async function taskClaimed(ctx) {
|
|
127
|
+
const taskCommand = require('./task');
|
|
128
|
+
const taskDb = require('../lib/task-db');
|
|
129
|
+
const createdCapture = await captureCommand(() => taskCommand.delegateTask([
|
|
130
|
+
'Prove drill task ledger health for fast factory diagnosis',
|
|
131
|
+
'--to',
|
|
132
|
+
'executor',
|
|
133
|
+
'--executed-by',
|
|
134
|
+
'drill',
|
|
135
|
+
'--tag',
|
|
136
|
+
'drill',
|
|
137
|
+
]));
|
|
138
|
+
const created = createdCapture.value;
|
|
139
|
+
assertOk(created && created.task_id, 'task delegate did not return a task_id');
|
|
140
|
+
ctx.taskId = created.task_id;
|
|
141
|
+
const claimed = taskDb.claimTask(taskDb.open(), { id: ctx.taskId, claimedBy: 'executor' });
|
|
142
|
+
assertOk(claimed.claimed === true, `task claim failed: ${claimed.reason || 'unknown'}`);
|
|
143
|
+
const row = taskDb.getTask(taskDb.open(), ctx.taskId);
|
|
144
|
+
assertOk(row && row.status === 'claimed', `task should be claimed, got ${row && row.status}`);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
async function missionStarted(ctx) {
|
|
148
|
+
const { startMission } = require('./mission');
|
|
149
|
+
const result = await captureCommand(() => startMission([
|
|
150
|
+
'Prove drill mission receipts for fast factory diagnosis',
|
|
151
|
+
'--owner',
|
|
152
|
+
'executor',
|
|
153
|
+
'--runner',
|
|
154
|
+
'drill',
|
|
155
|
+
'--verify',
|
|
156
|
+
VERIFY_COMMAND,
|
|
157
|
+
'--task',
|
|
158
|
+
ctx.taskId,
|
|
159
|
+
'--json',
|
|
160
|
+
], { silent: true }));
|
|
161
|
+
const payload = result.value;
|
|
162
|
+
assertOk(payload && payload.mission && payload.mission.id, 'mission start did not return a mission');
|
|
163
|
+
assertOk(payload.mission.runner === 'drill', `mission runner should be drill, got ${payload.mission.runner}`);
|
|
164
|
+
assertOk(payload.mission.verifier === VERIFY_COMMAND, `mission verifier mismatch: ${payload.mission.verifier}`);
|
|
165
|
+
ctx.missionId = payload.mission.id;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
async function tickVerified(ctx) {
|
|
169
|
+
const missionCommand = require('./mission');
|
|
170
|
+
const taskDb = require('../lib/task-db');
|
|
171
|
+
const run = await captureCommand(() => missionCommand.missionCommand([
|
|
172
|
+
'run',
|
|
173
|
+
ctx.missionId,
|
|
174
|
+
'--max-ticks',
|
|
175
|
+
'1',
|
|
176
|
+
'--max-wall',
|
|
177
|
+
'60',
|
|
178
|
+
'--complete-on-pass',
|
|
179
|
+
'--json',
|
|
180
|
+
]));
|
|
181
|
+
const payload = parseJsonOutput(run.stdout);
|
|
182
|
+
assertOk(payload.ok === true && payload.action === 'mission_run', `mission run failed: ${run.stdout || run.stderr}`);
|
|
183
|
+
assertOk(payload.ran_ticks === 1, `mission should run one tick, ran ${payload.ran_ticks}`);
|
|
184
|
+
assertOk(payload.ticks && payload.ticks[0] && payload.ticks[0].drill, 'drill runner did not record a touch');
|
|
185
|
+
assertOk(payload.mission && payload.mission.verifier_result && payload.mission.verifier_result.passed === true, 'mission verifier pass was not recorded');
|
|
186
|
+
ctx.receiptPath = payload.mission.receipt_path;
|
|
187
|
+
assertOk(ctx.receiptPath && fs.existsSync(path.join(ctx.sandboxPath, ctx.receiptPath)), `mission receipt missing: ${ctx.receiptPath}`);
|
|
188
|
+
const ready = taskDb.readyTask(taskDb.open(), {
|
|
189
|
+
id: ctx.taskId,
|
|
190
|
+
actor: 'executor',
|
|
191
|
+
proof: `Receipt saved at ${ctx.receiptPath}; ${VERIFY_COMMAND} passed in the drill sandbox.`,
|
|
192
|
+
result: 'Operators can run one command to prove the local factory pipeline still works.',
|
|
193
|
+
});
|
|
194
|
+
assertOk(ready.ready === true, `task ready failed: ${ready.reason}`);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
async function landingShippedLocal(ctx) {
|
|
198
|
+
const worktree = require('./worktree');
|
|
199
|
+
try {
|
|
200
|
+
require('../lib/task-db').close();
|
|
201
|
+
} catch {}
|
|
202
|
+
const dirty = runGit(['status', '--porcelain'], ctx.sandboxPath).stdout.trim();
|
|
203
|
+
if (dirty) {
|
|
204
|
+
runGit(['add', '-A'], ctx.sandboxPath);
|
|
205
|
+
runGit(['commit', '-m', 'record drill pipeline state'], ctx.sandboxPath);
|
|
206
|
+
}
|
|
207
|
+
ctx.landingWorktree = path.join(ctx.tmpRoot, 'landing-worktree');
|
|
208
|
+
const created = worktree.createAgentWorktree({
|
|
209
|
+
root: ctx.sandboxPath,
|
|
210
|
+
member: 'executor',
|
|
211
|
+
task: 'drill local landing',
|
|
212
|
+
path: ctx.landingWorktree,
|
|
213
|
+
base: 'master',
|
|
214
|
+
});
|
|
215
|
+
ctx.landingBranch = created.branch;
|
|
216
|
+
fs.writeFileSync(path.join(ctx.landingWorktree, 'drill-landing.txt'), 'local landing ok\n', 'utf8');
|
|
217
|
+
await withSandboxProcessState(ctx.landingWorktree, {}, async () => {
|
|
218
|
+
const shipped = await captureCommand(() => worktree.worktreeCommand([
|
|
219
|
+
'ship',
|
|
220
|
+
'--message',
|
|
221
|
+
'drill local landing commit',
|
|
222
|
+
'--verify',
|
|
223
|
+
VERIFY_COMMAND,
|
|
224
|
+
'--merge',
|
|
225
|
+
'--local',
|
|
226
|
+
'--target',
|
|
227
|
+
'master',
|
|
228
|
+
]));
|
|
229
|
+
assertOk(shipped.value === 0, `worktree ship exited ${shipped.value}`);
|
|
230
|
+
assertOk(/local mode/.test(`${shipped.stdout}\n${shipped.stderr}`), 'worktree ship did not report local mode');
|
|
231
|
+
});
|
|
232
|
+
runGit(['worktree', 'remove', ctx.landingWorktree, '--force'], ctx.sandboxPath);
|
|
233
|
+
runGit(['branch', '-d', ctx.landingBranch], ctx.sandboxPath);
|
|
234
|
+
const landed = runGit(['show', 'master:drill-landing.txt'], ctx.sandboxPath).stdout;
|
|
235
|
+
assertOk(landed.trim() === 'local landing ok', 'landing file was not merged into sandbox master');
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
async function ledgerChecked(ctx) {
|
|
239
|
+
const taskDb = require('../lib/task-db');
|
|
240
|
+
const mission = require('./mission');
|
|
241
|
+
const task = taskDb.getTask(taskDb.open(), ctx.taskId);
|
|
242
|
+
assertOk(task && ['review', 'done'].includes(task.status), `task should be review or done, got ${task && task.status}`);
|
|
243
|
+
const currentMission = mission.listMissions(ctx.sandboxPath).find((row) => row.id === ctx.missionId);
|
|
244
|
+
assertOk(currentMission, `mission not found: ${ctx.missionId}`);
|
|
245
|
+
assertOk(currentMission.verifier_result && currentMission.verifier_result.passed === true, 'mission verifier result is not passing');
|
|
246
|
+
assertOk(currentMission.receipt_path && fs.existsSync(path.join(ctx.sandboxPath, currentMission.receipt_path)), `mission receipt missing: ${currentMission.receipt_path}`);
|
|
247
|
+
const unmerged = runGit(['branch', '--no-merged', 'master'], ctx.sandboxPath).stdout
|
|
248
|
+
.split(/\r?\n/)
|
|
249
|
+
.map((line) => line.replace(/^\*/, '').trim())
|
|
250
|
+
.filter(Boolean)
|
|
251
|
+
.filter((line) => line !== 'master');
|
|
252
|
+
assertOk(unmerged.length === 0, `unmerged local branches remain: ${unmerged.join(', ')}`);
|
|
253
|
+
const worktrees = worktreeList(ctx.sandboxPath);
|
|
254
|
+
assertOk(worktrees.length === 1, `expected only the primary worktree, got ${worktrees.length}`);
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
function worktreeList(root) {
|
|
258
|
+
const worktree = require('./worktree');
|
|
259
|
+
return worktree.listWorktrees(root);
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
const STAGE_DEFS = [
|
|
263
|
+
['sandbox ready', createSandbox],
|
|
264
|
+
['wish captured', wishCaptured],
|
|
265
|
+
['task claimed', taskClaimed],
|
|
266
|
+
['mission started', missionStarted],
|
|
267
|
+
['tick verified', tickVerified],
|
|
268
|
+
['landing shipped (local mode)', landingShippedLocal],
|
|
269
|
+
['ledger checked', ledgerChecked],
|
|
270
|
+
];
|
|
271
|
+
|
|
272
|
+
async function runDrill(options = {}) {
|
|
273
|
+
const keep = options.keep === true;
|
|
274
|
+
const reporter = typeof options.reporter === 'function' ? options.reporter : null;
|
|
275
|
+
const afterStage = typeof options.afterStage === 'function' ? options.afterStage : null;
|
|
276
|
+
const stages = [];
|
|
277
|
+
const ctx = {};
|
|
278
|
+
const oldCwd = process.cwd();
|
|
279
|
+
const envPatch = {
|
|
280
|
+
ATRIS_SKIP_UPDATE_CHECK: '1',
|
|
281
|
+
NODE_NO_WARNINGS: '1',
|
|
282
|
+
};
|
|
283
|
+
const previousEnv = {};
|
|
284
|
+
for (const [key, value] of Object.entries(envPatch)) {
|
|
285
|
+
previousEnv[key] = process.env[key];
|
|
286
|
+
process.env[key] = value;
|
|
287
|
+
}
|
|
288
|
+
let pass = true;
|
|
289
|
+
try {
|
|
290
|
+
for (const [name, fn] of STAGE_DEFS) {
|
|
291
|
+
const startedAt = Date.now();
|
|
292
|
+
const stage = { name, ok: false, ms: 0 };
|
|
293
|
+
try {
|
|
294
|
+
const runInSandbox = name === 'sandbox ready'
|
|
295
|
+
? () => fn(ctx)
|
|
296
|
+
: () => withSandboxProcessState(ctx.sandboxPath, {
|
|
297
|
+
ATRIS_SKIP_UPDATE_CHECK: '1',
|
|
298
|
+
ATRIS_TASKS_DB: path.join(ctx.sandboxPath, '.atris', 'state', 'drill-tasks.db'),
|
|
299
|
+
NODE_NO_WARNINGS: '1',
|
|
300
|
+
}, () => fn(ctx));
|
|
301
|
+
await runInSandbox();
|
|
302
|
+
stage.ok = true;
|
|
303
|
+
stage.ms = Date.now() - startedAt;
|
|
304
|
+
stages.push(stage);
|
|
305
|
+
if (reporter) reporter(name);
|
|
306
|
+
if (afterStage) await afterStage(name, ctx);
|
|
307
|
+
} catch (error) {
|
|
308
|
+
stage.ok = false;
|
|
309
|
+
stage.ms = Date.now() - startedAt;
|
|
310
|
+
stage.error = error && error.message ? String(error.message) : String(error);
|
|
311
|
+
stages.push(stage);
|
|
312
|
+
pass = false;
|
|
313
|
+
break;
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
return {
|
|
317
|
+
pass,
|
|
318
|
+
stages,
|
|
319
|
+
sandbox_path: ctx.sandboxPath || null,
|
|
320
|
+
tmp_root: ctx.tmpRoot || null,
|
|
321
|
+
kept: keep,
|
|
322
|
+
};
|
|
323
|
+
} finally {
|
|
324
|
+
process.chdir(oldCwd);
|
|
325
|
+
for (const [key, value] of Object.entries(previousEnv)) {
|
|
326
|
+
if (value === undefined) delete process.env[key];
|
|
327
|
+
else process.env[key] = value;
|
|
328
|
+
}
|
|
329
|
+
try {
|
|
330
|
+
require('../lib/task-db').close();
|
|
331
|
+
} catch {}
|
|
332
|
+
if (!keep && ctx.tmpRoot) {
|
|
333
|
+
fs.rmSync(ctx.tmpRoot, { recursive: true, force: true });
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
async function drillCommand(args = []) {
|
|
339
|
+
const asJson = hasFlag(args, '--json');
|
|
340
|
+
const keep = hasFlag(args, '--keep');
|
|
341
|
+
if (hasFlag(args, '--help') || hasFlag(args, '-h') || args[0] === 'help') {
|
|
342
|
+
console.log('Usage: atris drill [--json] [--keep]');
|
|
343
|
+
console.log('');
|
|
344
|
+
console.log('Runs a no-LLM end-to-end drill in a throwaway sandbox repo.');
|
|
345
|
+
return 0;
|
|
346
|
+
}
|
|
347
|
+
const startedAt = Date.now();
|
|
348
|
+
const result = await runDrill({
|
|
349
|
+
keep,
|
|
350
|
+
reporter: asJson ? null : (line) => console.log(line),
|
|
351
|
+
});
|
|
352
|
+
if (asJson) {
|
|
353
|
+
console.log(JSON.stringify({ stages: result.stages, pass: result.pass }, null, 2));
|
|
354
|
+
} else if (result.pass) {
|
|
355
|
+
console.log(`PASS ${Date.now() - startedAt}ms`);
|
|
356
|
+
} else {
|
|
357
|
+
const failed = result.stages.find((stage) => !stage.ok) || result.stages[result.stages.length - 1];
|
|
358
|
+
console.log(`FAIL ${failed.name}: ${failed.error}`);
|
|
359
|
+
}
|
|
360
|
+
if (keep && result.sandbox_path) {
|
|
361
|
+
console.log(`sandbox kept: ${result.sandbox_path}`);
|
|
362
|
+
}
|
|
363
|
+
return result.pass ? 0 : 1;
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
module.exports = {
|
|
367
|
+
COAUTHOR,
|
|
368
|
+
VERIFY_COMMAND,
|
|
369
|
+
drillCommand,
|
|
370
|
+
runDrill,
|
|
371
|
+
};
|