@protoboxai/codeloop 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +589 -0
- package/dist/commands/adopt.d.ts +2 -0
- package/dist/commands/adopt.js +26 -0
- package/dist/commands/adopt.js.map +1 -0
- package/dist/commands/brief.d.ts +2 -0
- package/dist/commands/brief.js +22 -0
- package/dist/commands/brief.js.map +1 -0
- package/dist/commands/card.d.ts +6 -0
- package/dist/commands/card.js +159 -0
- package/dist/commands/card.js.map +1 -0
- package/dist/commands/check.d.ts +4 -0
- package/dist/commands/check.js +76 -0
- package/dist/commands/check.js.map +1 -0
- package/dist/commands/cloud.d.ts +8 -0
- package/dist/commands/cloud.js +123 -0
- package/dist/commands/cloud.js.map +1 -0
- package/dist/commands/guard.d.ts +2 -0
- package/dist/commands/guard.js +26 -0
- package/dist/commands/guard.js.map +1 -0
- package/dist/commands/import.d.ts +2 -0
- package/dist/commands/import.js +24 -0
- package/dist/commands/import.js.map +1 -0
- package/dist/commands/inbox.d.ts +2 -0
- package/dist/commands/inbox.js +48 -0
- package/dist/commands/inbox.js.map +1 -0
- package/dist/commands/init.d.ts +2 -0
- package/dist/commands/init.js +142 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/install.d.ts +2 -0
- package/dist/commands/install.js +125 -0
- package/dist/commands/install.js.map +1 -0
- package/dist/commands/lane.d.ts +2 -0
- package/dist/commands/lane.js +100 -0
- package/dist/commands/lane.js.map +1 -0
- package/dist/commands/list.d.ts +2 -0
- package/dist/commands/list.js +35 -0
- package/dist/commands/list.js.map +1 -0
- package/dist/commands/login.d.ts +2 -0
- package/dist/commands/login.js +77 -0
- package/dist/commands/login.js.map +1 -0
- package/dist/commands/mock.d.ts +3 -0
- package/dist/commands/mock.js +22 -0
- package/dist/commands/mock.js.map +1 -0
- package/dist/commands/pack.d.ts +2 -0
- package/dist/commands/pack.js +19 -0
- package/dist/commands/pack.js.map +1 -0
- package/dist/commands/publish.d.ts +2 -0
- package/dist/commands/publish.js +125 -0
- package/dist/commands/publish.js.map +1 -0
- package/dist/commands/remove.d.ts +2 -0
- package/dist/commands/remove.js +31 -0
- package/dist/commands/remove.js.map +1 -0
- package/dist/commands/render.d.ts +5 -0
- package/dist/commands/render.js +47 -0
- package/dist/commands/render.js.map +1 -0
- package/dist/commands/run.d.ts +2 -0
- package/dist/commands/run.js +45 -0
- package/dist/commands/run.js.map +1 -0
- package/dist/commands/scan.d.ts +2 -0
- package/dist/commands/scan.js +26 -0
- package/dist/commands/scan.js.map +1 -0
- package/dist/commands/schedule.d.ts +2 -0
- package/dist/commands/schedule.js +51 -0
- package/dist/commands/schedule.js.map +1 -0
- package/dist/commands/search.d.ts +2 -0
- package/dist/commands/search.js +85 -0
- package/dist/commands/search.js.map +1 -0
- package/dist/commands/serve.d.ts +7 -0
- package/dist/commands/serve.js +126 -0
- package/dist/commands/serve.js.map +1 -0
- package/dist/commands/spec.d.ts +3 -0
- package/dist/commands/spec.js +64 -0
- package/dist/commands/spec.js.map +1 -0
- package/dist/commands/status.d.ts +3 -0
- package/dist/commands/status.js +251 -0
- package/dist/commands/status.js.map +1 -0
- package/dist/commands/update.d.ts +2 -0
- package/dist/commands/update.js +83 -0
- package/dist/commands/update.js.map +1 -0
- package/dist/commands/verify.d.ts +3 -0
- package/dist/commands/verify.js +75 -0
- package/dist/commands/verify.js.map +1 -0
- package/dist/commands/watch.d.ts +6 -0
- package/dist/commands/watch.js +111 -0
- package/dist/commands/watch.js.map +1 -0
- package/dist/commands/wiki.d.ts +3 -0
- package/dist/commands/wiki.js +85 -0
- package/dist/commands/wiki.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +86 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/agent.d.ts +27 -0
- package/dist/lib/agent.js +178 -0
- package/dist/lib/agent.js.map +1 -0
- package/dist/lib/board.d.ts +38 -0
- package/dist/lib/board.js +86 -0
- package/dist/lib/board.js.map +1 -0
- package/dist/lib/cards.d.ts +82 -0
- package/dist/lib/cards.js +107 -0
- package/dist/lib/cards.js.map +1 -0
- package/dist/lib/clock.d.ts +5 -0
- package/dist/lib/clock.js +14 -0
- package/dist/lib/clock.js.map +1 -0
- package/dist/lib/cloud.d.ts +122 -0
- package/dist/lib/cloud.js +580 -0
- package/dist/lib/cloud.js.map +1 -0
- package/dist/lib/competitors.d.ts +28 -0
- package/dist/lib/competitors.js +90 -0
- package/dist/lib/competitors.js.map +1 -0
- package/dist/lib/config.d.ts +7 -0
- package/dist/lib/config.js +25 -0
- package/dist/lib/config.js.map +1 -0
- package/dist/lib/cron.d.ts +5 -0
- package/dist/lib/cron.js +82 -0
- package/dist/lib/cron.js.map +1 -0
- package/dist/lib/detect.d.ts +13 -0
- package/dist/lib/detect.js +60 -0
- package/dist/lib/detect.js.map +1 -0
- package/dist/lib/engine.d.ts +88 -0
- package/dist/lib/engine.js +435 -0
- package/dist/lib/engine.js.map +1 -0
- package/dist/lib/flow.d.ts +44 -0
- package/dist/lib/flow.js +121 -0
- package/dist/lib/flow.js.map +1 -0
- package/dist/lib/glob.d.ts +2 -0
- package/dist/lib/glob.js +10 -0
- package/dist/lib/glob.js.map +1 -0
- package/dist/lib/import.d.ts +13 -0
- package/dist/lib/import.js +127 -0
- package/dist/lib/import.js.map +1 -0
- package/dist/lib/inbox.d.ts +42 -0
- package/dist/lib/inbox.js +65 -0
- package/dist/lib/inbox.js.map +1 -0
- package/dist/lib/lane.d.ts +71 -0
- package/dist/lib/lane.js +105 -0
- package/dist/lib/lane.js.map +1 -0
- package/dist/lib/lock.d.ts +6 -0
- package/dist/lib/lock.js +64 -0
- package/dist/lib/lock.js.map +1 -0
- package/dist/lib/mcp.d.ts +2 -0
- package/dist/lib/mcp.js +57 -0
- package/dist/lib/mcp.js.map +1 -0
- package/dist/lib/mock.d.ts +17 -0
- package/dist/lib/mock.js +137 -0
- package/dist/lib/mock.js.map +1 -0
- package/dist/lib/pack.d.ts +24 -0
- package/dist/lib/pack.js +77 -0
- package/dist/lib/pack.js.map +1 -0
- package/dist/lib/proposals.d.ts +48 -0
- package/dist/lib/proposals.js +240 -0
- package/dist/lib/proposals.js.map +1 -0
- package/dist/lib/render.d.ts +7 -0
- package/dist/lib/render.js +84 -0
- package/dist/lib/render.js.map +1 -0
- package/dist/lib/research.d.ts +8 -0
- package/dist/lib/research.js +39 -0
- package/dist/lib/research.js.map +1 -0
- package/dist/lib/run.d.ts +38 -0
- package/dist/lib/run.js +215 -0
- package/dist/lib/run.js.map +1 -0
- package/dist/lib/scaffold.d.ts +16 -0
- package/dist/lib/scaffold.js +175 -0
- package/dist/lib/scaffold.js.map +1 -0
- package/dist/lib/scan.d.ts +22 -0
- package/dist/lib/scan.js +85 -0
- package/dist/lib/scan.js.map +1 -0
- package/dist/lib/schedule.d.ts +20 -0
- package/dist/lib/schedule.js +66 -0
- package/dist/lib/schedule.js.map +1 -0
- package/dist/lib/server.d.ts +68 -0
- package/dist/lib/server.js +235 -0
- package/dist/lib/server.js.map +1 -0
- package/dist/lib/shell.d.ts +1 -0
- package/dist/lib/shell.js +25 -0
- package/dist/lib/shell.js.map +1 -0
- package/dist/lib/skills.d.ts +20 -0
- package/dist/lib/skills.js +92 -0
- package/dist/lib/skills.js.map +1 -0
- package/dist/lib/spec.d.ts +24 -0
- package/dist/lib/spec.js +102 -0
- package/dist/lib/spec.js.map +1 -0
- package/dist/lib/stats.d.ts +13 -0
- package/dist/lib/stats.js +43 -0
- package/dist/lib/stats.js.map +1 -0
- package/dist/lib/verify.d.ts +25 -0
- package/dist/lib/verify.js +135 -0
- package/dist/lib/verify.js.map +1 -0
- package/dist/lib/version.d.ts +10 -0
- package/dist/lib/version.js +27 -0
- package/dist/lib/version.js.map +1 -0
- package/dist/lib/wiki.d.ts +51 -0
- package/dist/lib/wiki.js +164 -0
- package/dist/lib/wiki.js.map +1 -0
- package/dist/registry/index.d.ts +7 -0
- package/dist/registry/index.js +8 -0
- package/dist/registry/index.js.map +1 -0
- package/dist/registry/installer.d.ts +30 -0
- package/dist/registry/installer.js +133 -0
- package/dist/registry/installer.js.map +1 -0
- package/dist/registry/local-index.d.ts +32 -0
- package/dist/registry/local-index.js +58 -0
- package/dist/registry/local-index.js.map +1 -0
- package/dist/registry/lockfile.d.ts +40 -0
- package/dist/registry/lockfile.js +85 -0
- package/dist/registry/lockfile.js.map +1 -0
- package/dist/registry/security.d.ts +25 -0
- package/dist/registry/security.js +100 -0
- package/dist/registry/security.js.map +1 -0
- package/dist/registry/skill-schema.d.ts +30 -0
- package/dist/registry/skill-schema.js +95 -0
- package/dist/registry/skill-schema.js.map +1 -0
- package/dist/ui/404.html +1 -0
- package/dist/ui/_next/static/6wzGE5sCtbYkSyhMWxL32/_buildManifest.js +1 -0
- package/dist/ui/_next/static/6wzGE5sCtbYkSyhMWxL32/_ssgManifest.js +1 -0
- package/dist/ui/_next/static/chunks/255-54d3085ce94738a4.js +1 -0
- package/dist/ui/_next/static/chunks/423-bb541b7ae2733575.js +1 -0
- package/dist/ui/_next/static/chunks/4bd1b696-c023c6e3521b1417.js +1 -0
- package/dist/ui/_next/static/chunks/app/_not-found/page-d6bc774f7acb716e.js +1 -0
- package/dist/ui/_next/static/chunks/app/layout-e5fc8e78e1c8da95.js +1 -0
- package/dist/ui/_next/static/chunks/app/page-0c34b6e119cef236.js +1 -0
- package/dist/ui/_next/static/chunks/framework-de98b93a850cfc71.js +1 -0
- package/dist/ui/_next/static/chunks/main-49fd204fc9037ea3.js +1 -0
- package/dist/ui/_next/static/chunks/main-app-c46afa2f48f3aaef.js +1 -0
- package/dist/ui/_next/static/chunks/pages/_app-7d307437aca18ad4.js +1 -0
- package/dist/ui/_next/static/chunks/pages/_error-cb2a52f75f2162e2.js +1 -0
- package/dist/ui/_next/static/chunks/polyfills-42372ed130431b0a.js +1 -0
- package/dist/ui/_next/static/chunks/webpack-4a462cecab786e93.js +1 -0
- package/dist/ui/_next/static/css/1bf01240dbfd6088.css +1 -0
- package/dist/ui/index.html +1 -0
- package/dist/ui/index.txt +19 -0
- package/dist/watch/index.d.ts +21 -0
- package/dist/watch/index.js +88 -0
- package/dist/watch/index.js.map +1 -0
- package/dist/watch/reporter.d.ts +11 -0
- package/dist/watch/reporter.js +44 -0
- package/dist/watch/reporter.js.map +1 -0
- package/dist/watch/signals.d.ts +38 -0
- package/dist/watch/signals.js +119 -0
- package/dist/watch/signals.js.map +1 -0
- package/dist/watch/triggers.d.ts +10 -0
- package/dist/watch/triggers.js +67 -0
- package/dist/watch/triggers.js.map +1 -0
- package/package.json +64 -0
- package/registry/index.json +106 -0
- package/starters/generic.yaml +95 -0
- package/starters/go.yaml +99 -0
- package/starters/node-typescript.yaml +108 -0
- package/starters/python.yaml +105 -0
- package/templates/ci/codeloop-pr.yml +29 -0
- package/templates/ci/codeloop-prod.yml +27 -0
- package/templates/ci/codeloop-staging.yml +34 -0
- package/templates/codeloop/board.json +5 -0
- package/templates/codeloop/gotchas.md +13 -0
- package/templates/codeloop/patterns.md +15 -0
- package/templates/codeloop/principles.md +49 -0
- package/templates/codeloop/rules.md +23 -0
- package/templates/commands/commit.md +255 -0
- package/templates/commands/debug.md +142 -0
- package/templates/commands/deploy.md +144 -0
- package/templates/commands/design.md +102 -0
- package/templates/commands/manage.md +77 -0
- package/templates/commands/plan.md +84 -0
- package/templates/commands/qa.md +155 -0
- package/templates/commands/reflect.md +93 -0
- package/templates/commands/ship.md +187 -0
- package/templates/commands/test.md +133 -0
- package/templates/hooks/commit-msg +8 -0
- package/templates/lanes/analyze.yaml +25 -0
- package/templates/lanes/build.yaml +45 -0
- package/templates/lanes/deploy.yaml +24 -0
- package/templates/lanes/learn.yaml +20 -0
- package/templates/lanes/market.yaml +25 -0
- package/templates/lanes/plan.yaml +24 -0
- package/templates/lanes/scan.yaml +11 -0
- package/templates/lanes/triage.yaml +24 -0
- package/templates/mock/template.html +82 -0
- package/templates/seeds/go-gotchas.md +28 -0
- package/templates/seeds/go-patterns.md +22 -0
- package/templates/seeds/node-typescript-gotchas.md +30 -0
- package/templates/seeds/node-typescript-patterns.md +27 -0
- package/templates/seeds/python-gotchas.md +30 -0
- package/templates/seeds/python-patterns.md +19 -0
- package/templates/seeds/universal-gotchas.md +11 -0
- package/templates/seeds/universal-patterns.md +11 -0
- package/templates/spec/plan.md +7 -0
- package/templates/spec/research.md +19 -0
- package/templates/spec/spec.md +14 -0
- package/templates/spec/tasks.md +10 -0
- package/templates/tasks/todo.md +3 -0
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
import { spawnSync } from 'child_process';
|
|
2
|
+
import { checkEnv } from './shell.js';
|
|
3
|
+
import { createHash } from 'crypto';
|
|
4
|
+
import { copyFileSync, existsSync, mkdirSync, mkdtempSync, readdirSync, readFileSync, rmSync, writeFileSync } from 'fs';
|
|
5
|
+
import { tmpdir } from 'os';
|
|
6
|
+
import { dirname, join } from 'path';
|
|
7
|
+
import { parse as parseYaml, stringify } from 'yaml';
|
|
8
|
+
import { DONE, readCards, safeName } from './cards.js';
|
|
9
|
+
import { writeCloudLane } from './cloud.js';
|
|
10
|
+
import { RefusalError } from './engine.js';
|
|
11
|
+
import { clock } from './clock.js';
|
|
12
|
+
import { withLock } from './lock.js';
|
|
13
|
+
import { LANES_DIR, lanePath, lintLane, loadLane, loadLanes, loadSkillsIndex, parseLane, substitute } from './lane.js';
|
|
14
|
+
export const PROPOSALS_DIR = '.codeloop/proposals';
|
|
15
|
+
export const LANE_CHANGES = '.codeloop/state/lane-changes.json';
|
|
16
|
+
const HISTORY_DIR = `${LANES_DIR}/.history`;
|
|
17
|
+
const REPLAY_CARDS = 10;
|
|
18
|
+
const REJECTIONS_TO_PROPOSE = 3;
|
|
19
|
+
const STUCKS_TO_PROPOSE = 2;
|
|
20
|
+
const proposalDir = (projectDir, id) => join(projectDir, PROPOSALS_DIR, safeName(id, 'proposal id'));
|
|
21
|
+
const sha = (file) => createHash('sha256').update(readFileSync(file)).digest('hex');
|
|
22
|
+
const lastLine = (text) => text.trim().split('\n').at(-1) ?? '';
|
|
23
|
+
export function propose(projectDir, now = clock()) {
|
|
24
|
+
const { cards } = readCards(projectDir);
|
|
25
|
+
const root = join(projectDir, PROPOSALS_DIR);
|
|
26
|
+
const existing = existsSync(root) ? readdirSync(root) : [];
|
|
27
|
+
const created = [];
|
|
28
|
+
for (const lane of loadLanes(projectDir)) {
|
|
29
|
+
// Only cards run under the current version count: events from before a promotion were
|
|
30
|
+
// already answered by it and must not raise the same proposal again.
|
|
31
|
+
const events = cards
|
|
32
|
+
.filter(c => c.lane === lane.id && c.laneVersion === lane.version)
|
|
33
|
+
.flatMap(c => c.events.map(e => ({ ...e, card: c.id })));
|
|
34
|
+
for (const stage of lane.stages) {
|
|
35
|
+
const rejects = events.filter(e => e.action === 'reject' && e.stage === stage.id);
|
|
36
|
+
const stucks = events.filter(e => e.action === 'stuck' && e.stage === stage.id);
|
|
37
|
+
const byRejects = rejects.length >= REJECTIONS_TO_PROPOSE;
|
|
38
|
+
const byStucks = stucks.length >= STUCKS_TO_PROPOSE;
|
|
39
|
+
if (!byRejects && !byStucks)
|
|
40
|
+
continue;
|
|
41
|
+
const prefix = `${lane.id}-${stage.id}-`;
|
|
42
|
+
const mine = existing.filter(d => d.startsWith(prefix));
|
|
43
|
+
const open = mine.some(d => {
|
|
44
|
+
const file = join(root, d, 'lane.yaml');
|
|
45
|
+
return existsSync(file) && parseLane(readFileSync(file, 'utf-8')).version === lane.version + 1;
|
|
46
|
+
});
|
|
47
|
+
if (open)
|
|
48
|
+
continue;
|
|
49
|
+
const notes = [
|
|
50
|
+
...(byRejects ? rejects.map(e => e.note ?? '') : []),
|
|
51
|
+
...(byStucks ? stucks.map(e => `done check failed with: ${lastLine(e.note ?? '')}`) : []),
|
|
52
|
+
].filter(Boolean);
|
|
53
|
+
const distinct = [...new Set(notes)];
|
|
54
|
+
const raw = parseYaml(readFileSync(lanePath(projectDir, lane.id), 'utf-8'));
|
|
55
|
+
raw.version = lane.version + 1;
|
|
56
|
+
const target = raw.stages.find((s) => s.id === stage.id);
|
|
57
|
+
target.notes = [...new Set([...(target.notes ?? []), ...distinct])];
|
|
58
|
+
const id = `${prefix}${mine.length + 1}`;
|
|
59
|
+
const dir = join(root, id);
|
|
60
|
+
mkdirSync(dir, { recursive: true });
|
|
61
|
+
writeFileSync(join(dir, 'lane.yaml'), stringify(raw));
|
|
62
|
+
writeFileSync(join(dir, 'why.md'), why(lane.id, lane.version, stage.id, stage.gate?.name, byRejects ? rejects : [], byStucks ? stucks : [], distinct, id, now));
|
|
63
|
+
writeFileSync(join(dir, 'eval.yaml'), EVAL_TEMPLATE);
|
|
64
|
+
created.push(id);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
return created;
|
|
68
|
+
}
|
|
69
|
+
const EVAL_TEMPLATE = `# Fixtures for \`codeloop lane eval\`. Each one runs in an empty temp dir: \`setup\`, then the
|
|
70
|
+
# check (done.cmd) of every stage this proposal changes. The exit code must match \`expect\`.
|
|
71
|
+
# A changed check needs at least one \`expect: fail\` fixture that it really fails on.
|
|
72
|
+
fixtures:
|
|
73
|
+
- name: broken-output
|
|
74
|
+
setup: "" # fill in: a shell command that writes the output the check must reject
|
|
75
|
+
expect: fail
|
|
76
|
+
`;
|
|
77
|
+
function why(lane, version, stage, gate, rejects, stucks, notes, id, now) {
|
|
78
|
+
const row = (e, text) => `| ${e.card} | ${e.at} | ${text.replace(/\|/g, '\\|')} |`;
|
|
79
|
+
const lines = [`# Proposal ${id}: lane ${lane}, stage ${stage} (v${version} to v${version + 1})`, '', `Status: proposed ${now.toISOString().slice(0, 10)}`, '', '## Why', ''];
|
|
80
|
+
if (rejects.length) {
|
|
81
|
+
lines.push(`Gate \`${gate ?? stage}\` on stage \`${stage}\` was rejected ${rejects.length} times.`, '', '| Card | When | Rejection note |', '|---|---|---|', ...rejects.map(e => row(e, e.note ?? '')), '');
|
|
82
|
+
}
|
|
83
|
+
if (stucks.length) {
|
|
84
|
+
lines.push(`Stage \`${stage}\` hit \`stuck\` ${stucks.length} times.`, '', '| Card | When | Last line of the failing check |', '|---|---|---|', ...stucks.map(e => row(e, lastLine(e.note ?? ''))), '');
|
|
85
|
+
}
|
|
86
|
+
lines.push('## Change', '', `\`lane.yaml\` bumps the version and adds these \`notes:\` to stage \`${stage}\`, which \`codeloop card show\` prints for whoever runs the stage:`, '', ...notes.map(n => `- ${n}`), '');
|
|
87
|
+
lines.push('## Next', '', `Fill in \`eval.yaml\`, then \`codeloop lane eval ${id}\` and \`codeloop lane promote ${id} --as owner\`.`, '');
|
|
88
|
+
return lines.join('\n');
|
|
89
|
+
}
|
|
90
|
+
function shell(cmd, cwd) {
|
|
91
|
+
return spawnSync(cmd, { cwd, shell: true, encoding: 'utf-8', timeout: 600_000, env: checkEnv() }).status === 0;
|
|
92
|
+
}
|
|
93
|
+
export function evalProposal(projectDir, id, now = clock()) {
|
|
94
|
+
const dir = proposalDir(projectDir, id);
|
|
95
|
+
const laneFile = join(dir, 'lane.yaml');
|
|
96
|
+
if (!existsSync(laneFile))
|
|
97
|
+
throw new RefusalError(`proposal "${id}" has no lane.yaml under ${PROPOSALS_DIR}`);
|
|
98
|
+
const proposed = parseLane(readFileSync(laneFile, 'utf-8'));
|
|
99
|
+
const current = existsSync(lanePath(projectDir, proposed.id)) ? loadLane(projectDir, proposed.id) : null;
|
|
100
|
+
const lint = lintLane(proposed, loadSkillsIndex(projectDir));
|
|
101
|
+
const evalFile = join(dir, 'eval.yaml');
|
|
102
|
+
const evalSpec = existsSync(evalFile) ? parseYaml(readFileSync(evalFile, 'utf-8')) ?? {} : {};
|
|
103
|
+
const fixtures = evalSpec.fixtures ?? [];
|
|
104
|
+
const accepted = new Set(evalSpec.accept_regressions ?? []);
|
|
105
|
+
const changed = proposed.stages.filter(s => s.done?.cmd && s.done.cmd !== current?.stages.find(c => c.id === s.id)?.done?.cmd);
|
|
106
|
+
const runs = [];
|
|
107
|
+
const vacuous = [];
|
|
108
|
+
for (const stage of changed) {
|
|
109
|
+
if (!fixtures.some(f => f.expect === 'fail')) {
|
|
110
|
+
vacuous.push(`stage ${stage.id}: the check changed but eval.yaml has no \`expect: fail\` fixture, so nothing shows the check can fail`);
|
|
111
|
+
}
|
|
112
|
+
for (const fixture of fixtures) {
|
|
113
|
+
if (!fixture.setup?.trim()) {
|
|
114
|
+
vacuous.push(`stage ${stage.id}: fixture ${fixture.name} has no setup`);
|
|
115
|
+
continue;
|
|
116
|
+
}
|
|
117
|
+
const tmp = mkdtempSync(join(tmpdir(), 'codeloop-eval-'));
|
|
118
|
+
try {
|
|
119
|
+
const got = !shell(fixture.setup, tmp) ? 'setup-failed' : shell(substitute(stage.done.cmd, 'eval-001', { shell: true }), tmp) ? 'pass' : 'fail';
|
|
120
|
+
const ok = got === fixture.expect;
|
|
121
|
+
runs.push({ stage: stage.id, fixture: fixture.name, expect: fixture.expect, got, ok });
|
|
122
|
+
if (!ok)
|
|
123
|
+
vacuous.push(`stage ${stage.id}: fixture ${fixture.name} expected ${fixture.expect}, got ${got}`);
|
|
124
|
+
}
|
|
125
|
+
finally {
|
|
126
|
+
rmSync(tmp, { recursive: true, force: true });
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
const replay = [];
|
|
131
|
+
const replayed = [];
|
|
132
|
+
const finished = readCards(projectDir).cards.filter(c => c.lane === proposed.id && c.stage === DONE);
|
|
133
|
+
// A proposal can pass every check and still make the lane weaker. Each such change has to be
|
|
134
|
+
// named, with a reason, by the person proposing it.
|
|
135
|
+
const reasons = new Map((evalSpec.accept_weakening ?? []).map(a => [String(a?.change), String(a?.reason ?? '').trim()]));
|
|
136
|
+
const found = [];
|
|
137
|
+
for (const before of current?.stages ?? []) {
|
|
138
|
+
const after = proposed.stages.find(s => s.id === before.id);
|
|
139
|
+
if (!after) {
|
|
140
|
+
const passed = finished.filter(c => c.events.some(e => e.stage === before.id && (e.action === 'advance' || e.action === 'approve')));
|
|
141
|
+
if (passed.length)
|
|
142
|
+
found.push([`remove-stage:${before.id}`, `removes stage ${before.id}, which ${passed.map(c => c.id).join(', ')} passed`]);
|
|
143
|
+
continue;
|
|
144
|
+
}
|
|
145
|
+
if (before.gate && !after.gate)
|
|
146
|
+
found.push([`remove-gate:${before.id}`, `removes gate ${before.gate.name} from stage ${before.id}`]);
|
|
147
|
+
if (before.gate && after.gate && before.gate.approver !== after.gate.approver)
|
|
148
|
+
found.push([`approver:${before.id}`, `changes the approver of gate ${before.gate.name} from ${before.gate.approver} to ${after.gate.approver}`]);
|
|
149
|
+
if (before.gate?.outward && after.gate && !after.gate.outward)
|
|
150
|
+
found.push([`remove-outward:${before.id}`, `stage ${before.id} would no longer wait for approval before its public step`]);
|
|
151
|
+
}
|
|
152
|
+
if (current && current.retries > 0 && proposed.retries <= 0)
|
|
153
|
+
found.push(['retries-0', `lowers retries from ${current.retries} to ${proposed.retries}, so a card is stuck on its first failed check`]);
|
|
154
|
+
const weakening = found.map(([change, detail]) => ({ change, detail, accepted: !!reasons.get(change), ...(reasons.get(change) ? { reason: reasons.get(change) } : {}) }));
|
|
155
|
+
for (const w of weakening.filter(w => !w.accepted)) {
|
|
156
|
+
replay.push(`${w.detail}; if that is intended, add \`- { change: "${w.change}", reason: "..." }\` under accept_weakening in eval.yaml`);
|
|
157
|
+
}
|
|
158
|
+
// Each changed check is re-run against work that was already accepted. A stage the card never
|
|
159
|
+
// passed (one the proposal adds) has no artifact to judge, so it is left out.
|
|
160
|
+
const recent = [...finished].sort((a, b) => a.updatedAt.localeCompare(b.updatedAt)).slice(-REPLAY_CARDS);
|
|
161
|
+
for (const card of recent) {
|
|
162
|
+
for (const stage of changed.filter(s => card.events.some(e => e.action === 'advance' && e.stage === s.id))) {
|
|
163
|
+
const passed = shell(substitute(stage.done.cmd, card, { shell: true }), projectDir);
|
|
164
|
+
const ok = accepted.has(card.id);
|
|
165
|
+
replayed.push({ card: card.id, stage: stage.id, passed, accepted: ok });
|
|
166
|
+
if (!passed && !ok) {
|
|
167
|
+
replay.push(`card ${card.id} finished, but its ${stage.id} output fails the new check; fix the check or list ${card.id} under accept_regressions in eval.yaml`);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
const exitCode = lint.length ? 2 : vacuous.length ? 4 : replay.length ? 1 : 0;
|
|
172
|
+
const result = {
|
|
173
|
+
proposal: id, lane: proposed.id, version: proposed.version, at: now.toISOString(), laneSha: sha(laneFile),
|
|
174
|
+
lint, fixtures: runs, vacuous, replay, replayed, weakening, green: exitCode === 0, exitCode,
|
|
175
|
+
};
|
|
176
|
+
writeFileSync(join(dir, 'eval-result.json'), JSON.stringify(result, null, 2) + '\n');
|
|
177
|
+
return result;
|
|
178
|
+
}
|
|
179
|
+
function logChange(projectDir, entry) {
|
|
180
|
+
const file = join(projectDir, LANE_CHANGES);
|
|
181
|
+
withLock(file, () => {
|
|
182
|
+
const log = existsSync(file) ? JSON.parse(readFileSync(file, 'utf-8')) : [];
|
|
183
|
+
writeFileSync(file, JSON.stringify([...log, entry], null, 2) + '\n');
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
export function promote(projectDir, id, role, now = clock()) {
|
|
187
|
+
if (role !== 'owner')
|
|
188
|
+
throw new RefusalError(`a lane change needs the owner; ${role} cannot promote`);
|
|
189
|
+
const dir = proposalDir(projectDir, id);
|
|
190
|
+
const laneFile = join(dir, 'lane.yaml');
|
|
191
|
+
const resultFile = join(dir, 'eval-result.json');
|
|
192
|
+
if (!existsSync(laneFile))
|
|
193
|
+
throw new RefusalError(`proposal "${id}" not found`);
|
|
194
|
+
if (!existsSync(resultFile))
|
|
195
|
+
throw new RefusalError(`proposal ${id} has not been evaluated; run \`codeloop lane eval ${id}\``);
|
|
196
|
+
const result = JSON.parse(readFileSync(resultFile, 'utf-8'));
|
|
197
|
+
if (!result.green)
|
|
198
|
+
throw new RefusalError(`proposal ${id} failed its eval; fix it and re-run \`codeloop lane eval ${id}\``);
|
|
199
|
+
if (result.laneSha !== sha(laneFile))
|
|
200
|
+
throw new RefusalError(`proposal ${id} changed after its eval; re-run \`codeloop lane eval ${id}\``);
|
|
201
|
+
const proposed = parseLane(readFileSync(laneFile, 'utf-8'));
|
|
202
|
+
const target = lanePath(projectDir, proposed.id);
|
|
203
|
+
let from = null;
|
|
204
|
+
if (existsSync(target)) {
|
|
205
|
+
from = loadLane(projectDir, proposed.id).version;
|
|
206
|
+
if (proposed.version !== from + 1)
|
|
207
|
+
throw new RefusalError(`proposal ${id} is v${proposed.version} but lane ${proposed.id} is at v${from}; it was written against an older version`);
|
|
208
|
+
mkdirSync(join(projectDir, HISTORY_DIR), { recursive: true });
|
|
209
|
+
copyFileSync(target, join(projectDir, HISTORY_DIR, `${proposed.id}.v${from}.yaml`));
|
|
210
|
+
}
|
|
211
|
+
// The cloud page goes first, so a lane that someone else changed there refuses this promote
|
|
212
|
+
// before the local file is replaced.
|
|
213
|
+
writeCloudLane(projectDir, proposed.id, readFileSync(laneFile, 'utf-8'));
|
|
214
|
+
mkdirSync(dirname(target), { recursive: true });
|
|
215
|
+
copyFileSync(laneFile, target);
|
|
216
|
+
const weakening = result.weakening ?? [];
|
|
217
|
+
logChange(projectDir, { at: now.toISOString(), action: 'promote', lane: proposed.id, from, to: proposed.version, proposal: id, actor: role, ...(weakening.length ? { weakening } : {}) });
|
|
218
|
+
return { lane: proposed.id, from, to: proposed.version, weakening };
|
|
219
|
+
}
|
|
220
|
+
export function rollback(projectDir, laneId, role, now = clock()) {
|
|
221
|
+
if (role !== 'owner')
|
|
222
|
+
throw new RefusalError(`a lane change needs the owner; ${role} cannot roll back`);
|
|
223
|
+
const dir = join(projectDir, HISTORY_DIR);
|
|
224
|
+
const versions = (existsSync(dir) ? readdirSync(dir) : [])
|
|
225
|
+
.map(f => new RegExp(`^${laneId}\\.v(\\d+)\\.yaml$`).exec(f))
|
|
226
|
+
.filter((m) => m !== null)
|
|
227
|
+
.map(m => parseInt(m[1], 10));
|
|
228
|
+
if (versions.length === 0)
|
|
229
|
+
throw new RefusalError(`lane ${laneId} has no earlier version in ${HISTORY_DIR}`);
|
|
230
|
+
const to = Math.max(...versions);
|
|
231
|
+
const from = loadLane(projectDir, laneId).version;
|
|
232
|
+
const history = join(dir, `${laneId}.v${to}.yaml`);
|
|
233
|
+
writeCloudLane(projectDir, laneId, readFileSync(history, 'utf-8'));
|
|
234
|
+
copyFileSync(history, lanePath(projectDir, laneId));
|
|
235
|
+
// Removed so a second rollback steps back one more version instead of restoring this one again.
|
|
236
|
+
rmSync(history);
|
|
237
|
+
logChange(projectDir, { at: now.toISOString(), action: 'rollback', lane: laneId, from, to, actor: role });
|
|
238
|
+
return { lane: laneId, from, to };
|
|
239
|
+
}
|
|
240
|
+
//# sourceMappingURL=proposals.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"proposals.js","sourceRoot":"","sources":["../../src/lib/proposals.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export type Host = 'claude' | 'cursor' | 'codex';
|
|
2
|
+
export declare const HOSTS: Host[];
|
|
3
|
+
/** Writes only when content differs, so a second run changes nothing. Text outside the AGENTS.md markers is kept. */
|
|
4
|
+
export declare function render(projectDir: string, hosts: Host[]): {
|
|
5
|
+
written: string[];
|
|
6
|
+
unchanged: string[];
|
|
7
|
+
};
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'fs';
|
|
2
|
+
import { dirname, join } from 'path';
|
|
3
|
+
import { loadLanes, loadSkillsIndex } from './lane.js';
|
|
4
|
+
export const HOSTS = ['claude', 'cursor', 'codex'];
|
|
5
|
+
const START = '<!-- codeloop:start -->';
|
|
6
|
+
const END = '<!-- codeloop:end -->';
|
|
7
|
+
const who = (stage) => stage.skill ?? [stage.role ?? ''].flat().join(', ');
|
|
8
|
+
const gateText = (stage) => !stage.gate ? '' : stage.gate.outward ? `${stage.gate.name} (${stage.gate.approver}, before the stage runs)` : `${stage.gate.name} (${stage.gate.approver}, after the check passes)`;
|
|
9
|
+
function stageSteps(lane, stage, skills) {
|
|
10
|
+
const skill = skills.find(s => s.name === stage.skill);
|
|
11
|
+
const steps = [
|
|
12
|
+
'1. Run `codeloop card show <id>`. It prints the output path, the done check, the stage notes and any earlier rejection notes. Follow those over anything remembered.',
|
|
13
|
+
'2. Run `codeloop wiki inject --files <files you expect to touch>` and read every page it prints.',
|
|
14
|
+
stage.skill
|
|
15
|
+
? `3. Do the work with the \`${stage.skill}\` skill${skill ? ` (${skill.source})` : ''}.${skill?.description ? ` ${skill.description}` : ''}`
|
|
16
|
+
: `3. Do the work for the \`${stage.id}\` stage${who(stage) ? ` as ${who(stage)}` : ''}.`,
|
|
17
|
+
stage.output ? `4. Write the result to \`${stage.output}\`.` : '4. Keep the change inside what the card asks for.',
|
|
18
|
+
`5. Run \`codeloop card advance <id>\`. It runs \`${stage.done?.cmd ?? `event ${stage.done?.event}`}\`. If it exits 2, read the output, fix the work and run it again. Stop after ${lane.retries} failures: the card parks as stuck for the owner.`,
|
|
19
|
+
];
|
|
20
|
+
if (stage.gate?.outward)
|
|
21
|
+
steps.unshift(`0. This stage changes something public. The card waits at gate \`${stage.gate.name}\` as it enters. Do nothing until a person has approved it.`);
|
|
22
|
+
else if (stage.gate)
|
|
23
|
+
steps.push(`6. The card then waits at gate \`${stage.gate.name}\` for the ${stage.gate.approver}. Stop there. Never run \`codeloop approve\` yourself.`);
|
|
24
|
+
return steps;
|
|
25
|
+
}
|
|
26
|
+
function laneTable(lane) {
|
|
27
|
+
return ['| Stage | Skill | Output | Done check | Gate |', '|---|---|---|---|---|', ...lane.stages.map(s => `| ${s.id} | ${who(s)} | ${s.output ?? ''} | \`${(s.done?.cmd ?? `event ${s.done?.event}`).replace(/\|/g, '\\|')}\` | ${gateText(s)} |`)];
|
|
28
|
+
}
|
|
29
|
+
function laneBody(lane, skills) {
|
|
30
|
+
const lines = [`# codeloop lane: ${lane.id} (v${lane.version})`, '', 'Run `codeloop card show <id>` first; the card says which stage it is in. Gates are approved only by a person.', '', ...laneTable(lane), ''];
|
|
31
|
+
for (const stage of lane.stages)
|
|
32
|
+
lines.push(`## ${stage.id}`, '', ...stageSteps(lane, stage, skills), '');
|
|
33
|
+
return lines.join('\n');
|
|
34
|
+
}
|
|
35
|
+
function files(lanes, skills, host) {
|
|
36
|
+
const out = {};
|
|
37
|
+
for (const lane of lanes) {
|
|
38
|
+
const description = `Work a codeloop card through the ${lane.id} lane: ${lane.stages.map(s => s.id).join(', ')}.`;
|
|
39
|
+
if (host === 'claude') {
|
|
40
|
+
for (const stage of lane.stages) {
|
|
41
|
+
const name = `codeloop-${lane.id}-${stage.id}`;
|
|
42
|
+
out[`.claude/agents/${name}.md`] = `---\nname: ${name}\ndescription: Run the ${stage.id} stage of the ${lane.id} lane for one codeloop card${stage.skill ? `, using the ${stage.skill} skill` : ''}.\n---\n\n# ${lane.id} / ${stage.id}\n\n${stageSteps(lane, stage, skills).join('\n')}\n`;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
else if (host === 'cursor') {
|
|
46
|
+
out[`.cursor/rules/codeloop-${lane.id}.mdc`] = `---\ndescription: ${description}\nalwaysApply: false\n---\n\n${laneBody(lane, skills)}`;
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
out[`.agents/skills/codeloop-${lane.id}/SKILL.md`] = `---\nname: codeloop-${lane.id}\ndescription: ${description}\n---\n\n${laneBody(lane, skills)}`;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return out;
|
|
53
|
+
}
|
|
54
|
+
function agentsBlock(lanes) {
|
|
55
|
+
const lines = [START, '## codeloop', '', '- Run `codeloop card show <id>` first. It names the stage, the skill, the output path and the done check.', '- Move a card only with `codeloop card advance <id>`. Never edit `.codeloop/cards.json` or a lane file.', '- Gates are approved only by a person. Stop when a card parks.', '- Run `codeloop wiki inject --files <paths>` before changing files.', ''];
|
|
56
|
+
for (const lane of lanes)
|
|
57
|
+
lines.push(`### ${lane.id}`, '', ...laneTable(lane), '');
|
|
58
|
+
lines.push(END);
|
|
59
|
+
return lines.join('\n');
|
|
60
|
+
}
|
|
61
|
+
/** Writes only when content differs, so a second run changes nothing. Text outside the AGENTS.md markers is kept. */
|
|
62
|
+
export function render(projectDir, hosts) {
|
|
63
|
+
const lanes = loadLanes(projectDir);
|
|
64
|
+
const skills = loadSkillsIndex(projectDir) ?? [];
|
|
65
|
+
const out = Object.assign({}, ...hosts.map(h => files(lanes, skills, h)));
|
|
66
|
+
const agentsFile = join(projectDir, 'AGENTS.md');
|
|
67
|
+
const current = existsSync(agentsFile) ? readFileSync(agentsFile, 'utf-8') : '';
|
|
68
|
+
const block = agentsBlock(lanes);
|
|
69
|
+
const [start, end] = [current.indexOf(START), current.indexOf(END)];
|
|
70
|
+
out['AGENTS.md'] = start >= 0 && end > start ? current.slice(0, start) + block + current.slice(end + END.length) : `${current.trimEnd()}${current.trim() ? '\n\n' : ''}${block}\n`;
|
|
71
|
+
const result = { written: [], unchanged: [] };
|
|
72
|
+
for (const [path, text] of Object.entries(out)) {
|
|
73
|
+
const file = join(projectDir, path);
|
|
74
|
+
if (existsSync(file) && readFileSync(file, 'utf-8') === text) {
|
|
75
|
+
result.unchanged.push(path);
|
|
76
|
+
continue;
|
|
77
|
+
}
|
|
78
|
+
mkdirSync(dirname(file), { recursive: true });
|
|
79
|
+
writeFileSync(file, text);
|
|
80
|
+
result.written.push(path);
|
|
81
|
+
}
|
|
82
|
+
return result;
|
|
83
|
+
}
|
|
84
|
+
//# sourceMappingURL=render.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"render.js","sourceRoot":"","sources":["../../src/lib/render.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/** `ref` is a card id or number. The research file is the one in the card's spec folder. */
|
|
2
|
+
export declare function checkResearch(projectDir: string, ref: string, minSources: number): {
|
|
3
|
+
file: string;
|
|
4
|
+
errors: string[];
|
|
5
|
+
urls: string[];
|
|
6
|
+
};
|
|
7
|
+
/** One line per URL that does not answer with 2xx or 3xx. */
|
|
8
|
+
export declare function checkOnline(urls: string[]): Promise<string[]>;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { existsSync, readFileSync } from 'fs';
|
|
2
|
+
import { join } from 'path';
|
|
3
|
+
import { resolveSpecDir } from './spec.js';
|
|
4
|
+
// `- source: <url> — <note>`. A spaced hyphen is accepted in place of the dash.
|
|
5
|
+
const SOURCE = /^- source: (https?:\/\/\S+) (?:—|–|-) \S.*$/;
|
|
6
|
+
const VERDICT = /^verdict:\s*\S/m;
|
|
7
|
+
const ONLINE_TIMEOUT_MS = 10_000;
|
|
8
|
+
/** `ref` is a card id or number. The research file is the one in the card's spec folder. */
|
|
9
|
+
export function checkResearch(projectDir, ref, minSources) {
|
|
10
|
+
const file = `${resolveSpecDir(projectDir, ref)}/research.md`;
|
|
11
|
+
if (!existsSync(join(projectDir, file)))
|
|
12
|
+
return { file, errors: [`missing file: ${file}`], urls: [] };
|
|
13
|
+
const text = readFileSync(join(projectDir, file), 'utf-8');
|
|
14
|
+
const urls = text.split('\n').map(l => SOURCE.exec(l.trim())?.[1]).filter((u) => !!u);
|
|
15
|
+
const errors = [];
|
|
16
|
+
if (!VERDICT.test(text))
|
|
17
|
+
errors.push(`${file} has no line starting with "verdict:"`);
|
|
18
|
+
if (urls.length < minSources)
|
|
19
|
+
errors.push(`${file} cites ${urls.length} ${urls.length === 1 ? 'source' : 'sources'}, needs ${minSources} (\`- source: <url> — <note>\`)`);
|
|
20
|
+
return { file, errors, urls };
|
|
21
|
+
}
|
|
22
|
+
async function answers(url) {
|
|
23
|
+
const ask = (method) => fetch(url, { method, redirect: 'manual', signal: AbortSignal.timeout(ONLINE_TIMEOUT_MS) });
|
|
24
|
+
try {
|
|
25
|
+
let res = await ask('HEAD');
|
|
26
|
+
// Some servers refuse HEAD and serve the page to GET.
|
|
27
|
+
if (res.status >= 400)
|
|
28
|
+
res = await ask('GET');
|
|
29
|
+
return res.status < 400 ? null : `${url} answered ${res.status}`;
|
|
30
|
+
}
|
|
31
|
+
catch (e) {
|
|
32
|
+
return `${url} did not answer (${e.cause instanceof Error ? e.cause.code ?? e.message : e.message})`;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
/** One line per URL that does not answer with 2xx or 3xx. */
|
|
36
|
+
export async function checkOnline(urls) {
|
|
37
|
+
return (await Promise.all(urls.map(answers))).filter((e) => e !== null);
|
|
38
|
+
}
|
|
39
|
+
//# sourceMappingURL=research.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"research.js","sourceRoot":"","sources":["../../src/lib/research.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { type AgentConfig } from './agent.js';
|
|
2
|
+
import { type Outcome } from './engine.js';
|
|
3
|
+
export declare const LAST_RUN = ".codeloop/state/last-run.json";
|
|
4
|
+
export interface RunResult {
|
|
5
|
+
created: {
|
|
6
|
+
lane: string;
|
|
7
|
+
id: string;
|
|
8
|
+
slot: string;
|
|
9
|
+
trigger: string;
|
|
10
|
+
}[];
|
|
11
|
+
skipped: {
|
|
12
|
+
lane: string;
|
|
13
|
+
reason: string;
|
|
14
|
+
}[];
|
|
15
|
+
advanced: {
|
|
16
|
+
id: string;
|
|
17
|
+
outcome: Outcome | 'refused';
|
|
18
|
+
note?: string;
|
|
19
|
+
next?: string;
|
|
20
|
+
}[];
|
|
21
|
+
/** Only on a run with an agent: one entry per card an agent was started for, or would have been. */
|
|
22
|
+
agents?: AgentStep[];
|
|
23
|
+
}
|
|
24
|
+
export interface AgentStep {
|
|
25
|
+
id: string;
|
|
26
|
+
stage: string;
|
|
27
|
+
agent: string;
|
|
28
|
+
started: boolean;
|
|
29
|
+
reason?: string;
|
|
30
|
+
exit?: number | null;
|
|
31
|
+
durationMs?: number;
|
|
32
|
+
log?: string;
|
|
33
|
+
}
|
|
34
|
+
export declare function runDue(projectDir: string, now?: Date): RunResult;
|
|
35
|
+
/** `runDue`, with an agent started first on each card whose stage check does not pass yet. One stage per card. */
|
|
36
|
+
export declare function runDueWithAgent(projectDir: string, agent: AgentConfig, now?: Date): Promise<RunResult>;
|
|
37
|
+
/** What a run would do, for `--dry-run`. Nothing is started, checked or written. */
|
|
38
|
+
export declare function planRun(projectDir: string, agent: AgentConfig | null, now?: Date): string[];
|