compounding-loop 0.4.0 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (92) hide show
  1. package/README.md +14 -2
  2. package/dist/cli/draft.js +69 -0
  3. package/dist/cli/draft.js.map +1 -0
  4. package/dist/cli/index.js +118 -0
  5. package/dist/cli/index.js.map +1 -1
  6. package/dist/cli/lanesInit.js +8 -2
  7. package/dist/cli/lanesInit.js.map +1 -1
  8. package/dist/cli/pace.js +41 -0
  9. package/dist/cli/pace.js.map +1 -0
  10. package/dist/cli/pause.js +3 -3
  11. package/dist/cli/pause.js.map +1 -1
  12. package/dist/cli/runs.js +46 -11
  13. package/dist/cli/runs.js.map +1 -1
  14. package/dist/cli/schedule.js +177 -0
  15. package/dist/cli/schedule.js.map +1 -0
  16. package/dist/core/brief.js +35 -12
  17. package/dist/core/brief.js.map +1 -1
  18. package/dist/core/draftBrief.js +68 -0
  19. package/dist/core/draftBrief.js.map +1 -0
  20. package/dist/core/lanes.js +3 -0
  21. package/dist/core/lanes.js.map +1 -1
  22. package/dist/core/lanesInit.js +19 -0
  23. package/dist/core/lanesInit.js.map +1 -1
  24. package/dist/core/parse/index.js +5 -0
  25. package/dist/core/parse/index.js.map +1 -1
  26. package/dist/core/parse/outcomes.js +51 -0
  27. package/dist/core/parse/outcomes.js.map +1 -0
  28. package/dist/core/parse/policy.js +56 -0
  29. package/dist/core/parse/policy.js.map +1 -0
  30. package/dist/core/parse/schedule.js +101 -0
  31. package/dist/core/parse/schedule.js.map +1 -0
  32. package/dist/core/parse/steer.js +68 -0
  33. package/dist/core/parse/steer.js.map +1 -0
  34. package/dist/core/repo.js +16 -1
  35. package/dist/core/repo.js.map +1 -1
  36. package/dist/server/actionBody.js +54 -0
  37. package/dist/server/actionBody.js.map +1 -0
  38. package/dist/server/checkLabels.js +7 -2
  39. package/dist/server/checkLabels.js.map +1 -1
  40. package/dist/server/claude.js +18 -0
  41. package/dist/server/claude.js.map +1 -0
  42. package/dist/server/controls.js +28 -1
  43. package/dist/server/controls.js.map +1 -1
  44. package/dist/server/data.js +1 -1
  45. package/dist/server/data.js.map +1 -1
  46. package/dist/server/draftInputs.js +33 -0
  47. package/dist/server/draftInputs.js.map +1 -0
  48. package/dist/server/health.js +3 -3
  49. package/dist/server/health.js.map +1 -1
  50. package/dist/server/index.js +48 -0
  51. package/dist/server/index.js.map +1 -1
  52. package/dist/server/laneChecks.js +1 -1
  53. package/dist/server/laneChecks.js.map +1 -1
  54. package/dist/server/laneSchedule.js +15 -0
  55. package/dist/server/laneSchedule.js.map +1 -0
  56. package/dist/server/live/build.js +25 -10
  57. package/dist/server/live/build.js.map +1 -1
  58. package/dist/server/live/index.js +4 -2
  59. package/dist/server/live/index.js.map +1 -1
  60. package/dist/server/live/urls.js +3 -1
  61. package/dist/server/live/urls.js.map +1 -1
  62. package/dist/server/loops.js +138 -20
  63. package/dist/server/loops.js.map +1 -1
  64. package/dist/server/paceNote.js +13 -0
  65. package/dist/server/paceNote.js.map +1 -0
  66. package/dist/server/roundState.js +26 -2
  67. package/dist/server/roundState.js.map +1 -1
  68. package/dist/server/runs.js +72 -9
  69. package/dist/server/runs.js.map +1 -1
  70. package/dist/server/shipped.js +35 -0
  71. package/dist/server/shipped.js.map +1 -0
  72. package/dist/server/static-export.js +2 -2
  73. package/dist/server/static-export.js.map +1 -1
  74. package/dist/server/this-repo.json +2367 -858
  75. package/dist/web/assets/index-BozIcdeb.js +88 -0
  76. package/dist/web/assets/index-Te_olhNA.css +2 -0
  77. package/dist/web/index.html +2 -2
  78. package/method/COMPOUNDING_LOOP.md +5 -0
  79. package/package.json +1 -1
  80. package/plugin/.claude-plugin/plugin.json +1 -1
  81. package/runners/github-actions/lanes.yml +2 -2
  82. package/runners/routine/README.md +4 -0
  83. package/runners/routine/control-room-prompt.md +4 -14
  84. package/runners/routine/lane-prompt.md +4 -10
  85. package/templates/lanes/README.md +5 -1
  86. package/templates/lanes/claude-section.md +1 -0
  87. package/templates/lanes/control-run.md +37 -0
  88. package/templates/lanes/lane-run.md +33 -0
  89. package/templates/lanes/schedule.json +4 -0
  90. package/templates/lanes/steer.md +3 -0
  91. package/dist/web/assets/index-BOPytDNU.js +0 -53
  92. package/dist/web/assets/index-BSHEI7fa.css +0 -2
@@ -0,0 +1,51 @@
1
+ import { expectedSlots, matchSlots } from './runs.js';
2
+ import { dueEntry, notDueReason } from './schedule.js';
3
+ export const RUN_WINDOW_MS = 50 * 60_000;
4
+ export const SILENCE_MS = 6 * 3_600_000;
5
+ function kindOf(slot, input, lane, entries) {
6
+ if (slot.entry)
7
+ return slot.outcome === 'tests-failed' ? 'tests-failed' : slot.outcome === 'pushed' || slot.entry.units.length > 0 ? 'worked' : 'idle';
8
+ if (slot.outcome === 'pushed')
9
+ return 'worked';
10
+ if (input.rootDone || input.laneDone.has(lane))
11
+ return 'done';
12
+ if (input.paused)
13
+ return 'paused';
14
+ const at = new Date(slot.slot);
15
+ const lastRun = entries.reduce((max, e) => Math.max(max, new Date(e.at).getTime()), 0);
16
+ // A later run proves the lane was due at this slot, whatever the schedule says today.
17
+ if (at.getTime() > lastRun) {
18
+ const entry = input.schedule.lanes[lane] ?? dueEntry();
19
+ const reason = notDueReason(entry, at);
20
+ if (reason)
21
+ return 'not-due';
22
+ }
23
+ return input.now.getTime() - at.getTime() < RUN_WINDOW_MS ? 'running' : 'missed';
24
+ }
25
+ /** Classifies every cron slot of every lane in the window. A lane without a cron has no expected slots. */
26
+ export function classifyRunSlots(input) {
27
+ const from = input.from ?? new Date(input.now.getTime() - 24 * 3_600_000);
28
+ const lanes = input.lanes.map(({ name, cron }) => {
29
+ const entries = input.runs.get(name) ?? [];
30
+ const matched = cron ? matchSlots(expectedSlots(cron, from, input.now), entries, input.commits?.get(name) ?? []) : [];
31
+ return { lane: name, slots: matched.map((s) => ({ ...s, kind: kindOf(s, input, name, entries) })) };
32
+ });
33
+ const newest = [...input.runs.values()].flat().reduce((max, e) => Math.max(max, new Date(e.at).getTime()), 0);
34
+ const silent = input.now.getTime() - newest >= SILENCE_MS;
35
+ const missed = lanes.some((l) => l.slots.some((s) => s.kind === 'missed'));
36
+ const routinesLookOff = !input.paused && !input.rootDone && silent && missed;
37
+ return { lanes, routinesLookOff };
38
+ }
39
+ /** Scheduled runs in a row, newest first, that were due and left no trace. Slots nobody expected a run for are skipped. */
40
+ export function missedRun(slots) {
41
+ let count = 0;
42
+ for (let i = slots.length - 1; i >= 0; i--) {
43
+ const kind = slots[i]?.kind;
44
+ if (kind === 'missed')
45
+ count++;
46
+ else if (kind !== 'not-due' && kind !== 'running')
47
+ break;
48
+ }
49
+ return count;
50
+ }
51
+ //# sourceMappingURL=outcomes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"outcomes.js","sourceRoot":"","sources":["../../../src/core/parse/outcomes.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,56 @@
1
+ export const POLICY_FILE = '.ai/policy.json';
2
+ export const PACES = ['careful', 'balanced', 'fast', 'sprint'];
3
+ export const DEFAULT_PACE = 'balanced';
4
+ export const isPace = (value) => typeof value === 'string' && PACES.includes(value);
5
+ export const emptyPolicy = () => ({ version: 1, pace: DEFAULT_PACE, lanes: {} });
6
+ /** One plain line per preset on what it skips; the floor (no push with a failing check, CI on every push) holds for all. */
7
+ export const PACE_SUMMARY = {
8
+ careful: 'Full tests after every unit and before push; a reviewer on every unit; 40 minutes per run.',
9
+ balanced: 'Related tests after each unit, full tests before push; one reviewer per run; 40 minutes.',
10
+ fast: 'Like balanced, but a reviewer only for shared files or another lane\'s contract; 50 minutes.',
11
+ sprint: 'Typecheck and lint per unit, unit tests before push, e2e once at the end; no reviewer; 50 minutes or 70% context.',
12
+ };
13
+ /** Reads a policy file. Anything unreadable, or any unknown preset, falls back to `balanced`. */
14
+ export function parsePolicy(text) {
15
+ try {
16
+ const raw = JSON.parse(text);
17
+ if (!raw || typeof raw !== 'object' || Array.isArray(raw))
18
+ return emptyPolicy();
19
+ const { pace, lanes } = raw;
20
+ const overrides = {};
21
+ if (lanes && typeof lanes === 'object' && !Array.isArray(lanes)) {
22
+ for (const [lane, value] of Object.entries(lanes)) {
23
+ const lanePace = value && typeof value === 'object' ? value.pace : undefined;
24
+ if (lane !== '__proto__' && isPace(lanePace))
25
+ overrides[lane] = { pace: lanePace };
26
+ }
27
+ }
28
+ return { version: 1, pace: isPace(pace) ? pace : DEFAULT_PACE, lanes: overrides };
29
+ }
30
+ catch {
31
+ return emptyPolicy();
32
+ }
33
+ }
34
+ /** Why a present policy file is not used as written (so `loop pace show` can say it reads as balanced), or undefined when it is fine. */
35
+ export function policyProblem(text) {
36
+ let raw;
37
+ try {
38
+ raw = JSON.parse(text);
39
+ }
40
+ catch {
41
+ return `${POLICY_FILE} is not valid JSON, so every lane runs at ${DEFAULT_PACE}.`;
42
+ }
43
+ const pace = raw && typeof raw === 'object' && !Array.isArray(raw) ? raw.pace : undefined;
44
+ return isPace(pace) ? undefined : `${POLICY_FILE} has no valid "pace" (${PACES.join(', ')}), so it reads as ${DEFAULT_PACE}.`;
45
+ }
46
+ export function formatPolicy(policy) {
47
+ const lanes = Object.entries(policy.lanes).map(([lane, e]) => ` ${JSON.stringify(lane)}: ${JSON.stringify(e)}`);
48
+ return `{\n "version": 1,\n "pace": ${JSON.stringify(policy.pace)},\n "lanes": {${lanes.length ? `\n${lanes.join(',\n')}\n ` : ''}}\n}\n`;
49
+ }
50
+ /** The pace a lane runs at: its own override, else the global one. `lane` undefined (the control room) gets the global pace. */
51
+ export const paceFor = (policy, lane) => (lane !== undefined ? policy.lanes[lane]?.pace : undefined) ?? policy.pace;
52
+ /** The policy after setting the global pace (no lane) or one lane's override. */
53
+ export function withPace(policy, pace, lane) {
54
+ return lane === undefined ? { ...policy, pace } : { ...policy, lanes: { ...policy.lanes, [lane]: { pace } } };
55
+ }
56
+ //# sourceMappingURL=policy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"policy.js","sourceRoot":"","sources":["../../../src/core/parse/policy.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,101 @@
1
+ import { unacknowledged } from './steer.js';
2
+ export const SCHEDULE_FILE = '.ai/schedule.json';
3
+ const HOUR_MS = 3_600_000;
4
+ export const emptySchedule = () => ({ version: 1, lanes: {} });
5
+ /** A lane with nothing in the file is due. */
6
+ export const dueEntry = () => ({ notBefore: null, sleeping: false, paused: false, reason: null });
7
+ const validTime = (v) => typeof v === 'string' && !Number.isNaN(new Date(v).getTime());
8
+ function toEntry(value) {
9
+ const v = value && typeof value === 'object' ? value : {};
10
+ return {
11
+ notBefore: validTime(v.notBefore) ? v.notBefore : null,
12
+ sleeping: v.sleeping === true,
13
+ paused: v.paused === true,
14
+ reason: typeof v.reason === 'string' && v.reason.trim() ? v.reason : null,
15
+ };
16
+ }
17
+ /** Reads a schedule file. Anything unreadable gives an empty schedule, so every lane stays due. */
18
+ export function parseSchedule(text) {
19
+ try {
20
+ const raw = JSON.parse(text);
21
+ const lanes = raw && typeof raw === 'object' ? raw.lanes : undefined;
22
+ if (!lanes || typeof lanes !== 'object' || Array.isArray(lanes))
23
+ return emptySchedule();
24
+ return { version: 1, lanes: Object.fromEntries(Object.entries(lanes).map(([lane, entry]) => [lane, toEntry(entry)])) };
25
+ }
26
+ catch {
27
+ return emptySchedule();
28
+ }
29
+ }
30
+ export function formatSchedule(schedule) {
31
+ const lanes = Object.entries(schedule.lanes).map(([lane, e]) => ` ${JSON.stringify(lane)}: ${JSON.stringify(e)}`);
32
+ return `{\n "version": 1,\n "lanes": {\n${lanes.join(',\n')}${lanes.length ? '\n' : ''} }\n}\n`;
33
+ }
34
+ /** Why a run at `now` should reply "Not due"; undefined when the lane is due. A missing entry is due. */
35
+ export function notDueReason(entry, now) {
36
+ if (!entry)
37
+ return undefined;
38
+ if (entry.paused)
39
+ return 'paused';
40
+ if (entry.sleeping)
41
+ return 'sleeping';
42
+ if (entry.notBefore && new Date(entry.notBefore).getTime() > now.getTime())
43
+ return 'snoozed';
44
+ return undefined;
45
+ }
46
+ export const isDue = (entry, now) => notDueReason(entry, now) === undefined;
47
+ /** Idle runs at the end of the log (a run with no units is idle; any run with units resets the count). */
48
+ export function trailingIdleRuns(runs) {
49
+ const sorted = [...runs].sort((a, b) => a.at.localeCompare(b.at));
50
+ let count = 0;
51
+ for (let i = sorted.length - 1; i >= 0 && sorted[i].units.length === 0; i--)
52
+ count++;
53
+ return count;
54
+ }
55
+ /**
56
+ * The idle backoff for one lane: 1 idle run -> not before last run + 3 h, 2 -> + 6 h, 3 or more -> sleeping.
57
+ * It only looks at the log, so a caller that has just woken the lane must skip it until a new run is logged.
58
+ * No trailing idle run leaves the entry alone (an owner's snooze or pause survives). A paused entry is never changed.
59
+ */
60
+ export function applyBackoff(runs, entry, _now) {
61
+ const current = entry ?? dueEntry();
62
+ const idle = trailingIdleRuns(runs);
63
+ if (idle === 0 || current.paused)
64
+ return current;
65
+ if (idle >= 3)
66
+ return { ...current, sleeping: true, notBefore: null, reason: `${idle} idle runs in a row` };
67
+ const last = [...runs].sort((a, b) => a.at.localeCompare(b.at)).at(-1);
68
+ const backoff = new Date(last.at).getTime() + (idle === 1 ? 3 : 6) * HOUR_MS;
69
+ // An owner's later snooze wins over the automatic backoff.
70
+ const notBefore = new Date(Math.max(backoff, current.notBefore ? new Date(current.notBefore).getTime() : 0)).toISOString();
71
+ return { ...current, sleeping: false, notBefore, reason: `${idle} idle run${idle === 1 ? '' : 's'} in a row` };
72
+ }
73
+ /** Why a sleeping or snoozed lane should be due again. Empty means keep sleeping. */
74
+ export function wakeReasons(input) {
75
+ const reasons = [];
76
+ if (unacknowledged(input.steer).length > 0)
77
+ reasons.push('steer');
78
+ const lane = input.lane.toLowerCase();
79
+ const since = input.lastRunAt ? new Date(input.lastRunAt).getTime() : -Infinity;
80
+ const stamp = (at) => new Date(at.includes('T') ? at : `${at.replace(' UTC', '').replace(' ', 'T')}:00Z`).getTime();
81
+ if (input.messages.some((m) => stamp(m.at) > since && m.to.some((t) => t.toLowerCase() === lane || t.toLowerCase() === 'all')))
82
+ reasons.push('message');
83
+ if (input.newRound)
84
+ reasons.push('new-round');
85
+ return reasons;
86
+ }
87
+ /** The entry after a wake: due now. A pause is a separate decision and stays. */
88
+ export const wakeEntry = (entry) => ({ ...(entry ?? dueEntry()), sleeping: false, notBefore: null, reason: null });
89
+ /** True when the entry holds the lane back only because of the automatic backoff (not an owner's pause). */
90
+ export const isBackedOff = (entry, now) => !entry?.paused && notDueReason(entry, now) !== undefined;
91
+ /**
92
+ * Reads the time a snooze lasts until: an ISO time, a date (midnight UTC), or a span from now such as `3h`, `2d`, `90m`.
93
+ * Undefined when unreadable or not after `now`.
94
+ */
95
+ export function parseUntil(text, now) {
96
+ const t = text.trim();
97
+ const span = /^\+?(\d+)\s*([mhd])$/i.exec(t);
98
+ const at = span ? new Date(now.getTime() + Number(span[1]) * ({ m: 60_000, h: HOUR_MS, d: 24 * HOUR_MS }[span[2].toLowerCase()])) : new Date(/^\d{4}-\d\d-\d\d$/.test(t) ? `${t}T00:00:00Z` : t);
99
+ return Number.isNaN(at.getTime()) || at.getTime() <= now.getTime() ? undefined : at;
100
+ }
101
+ //# sourceMappingURL=schedule.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schedule.js","sourceRoot":"","sources":["../../../src/core/parse/schedule.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,68 @@
1
+ export const steerPath = (lane) => `.ai/lanes/${lane}/steer.md`;
2
+ const HEADING = /^## (\d{4}-\d\d-\d\d) (\d\d:\d\d) UTC · (.+?) · (next-run|standing)\s*$/;
3
+ const ACK_DONE = /^→ done in run (\d+)\s*$/;
4
+ const ACK_NOT_DONE = /^→ not done:\s*(.*)$/;
5
+ export function steerHeading(at, author, scope) {
6
+ return `## ${at.toISOString().slice(0, 16).replace('T', ' ')} UTC · ${author} · ${scope}`;
7
+ }
8
+ /** One entry as it is written to the file (heading, text, blank line). Newlines in the author would break the heading. */
9
+ export function formatSteerEntry(entry) {
10
+ const author = entry.author.replace(/[\r\n·]+/g, ' ').replace(/\s+/g, ' ').trim() || 'unknown';
11
+ return `${steerHeading(entry.at, author, entry.scope)}\n${entry.text.trim().replace(/^##(?= )/gm, '###')}\n`;
12
+ }
13
+ function parseAck(line) {
14
+ const done = ACK_DONE.exec(line);
15
+ if (done)
16
+ return { state: 'done', run: Number(done[1]) };
17
+ const not = ACK_NOT_DONE.exec(line);
18
+ return not ? { state: 'not-done', why: (not[1] ?? '').trim() } : undefined;
19
+ }
20
+ /** Entries in file order (newest first by convention). Text before the first heading is the file's intro and is ignored. */
21
+ export function parseSteer(text) {
22
+ const entries = [];
23
+ let current;
24
+ const flush = () => {
25
+ if (!current)
26
+ return;
27
+ const [, date, time, author, scope] = current.head;
28
+ const lines = current.body;
29
+ const ackAt = lines.findIndex((l) => parseAck(l.trim()) !== undefined);
30
+ const ack = ackAt >= 0 ? parseAck(lines[ackAt].trim()) : undefined;
31
+ const body = (ackAt >= 0 ? lines.filter((_, i) => i !== ackAt) : lines).join('\n').trim();
32
+ entries.push({ at: `${date}T${time}:00.000Z`, author: author.trim(), scope, text: body, ...(ack && { ack }) });
33
+ };
34
+ for (const line of text.split(/\r?\n/)) {
35
+ const head = HEADING.exec(line);
36
+ if (head) {
37
+ flush();
38
+ current = { head, body: [] };
39
+ }
40
+ else if (/^## /.test(line)) {
41
+ flush();
42
+ current = undefined;
43
+ }
44
+ else
45
+ current?.body.push(line);
46
+ }
47
+ flush();
48
+ return entries;
49
+ }
50
+ /** Entries the lane has not read yet. A standing entry counts once, until its first acknowledgement. */
51
+ export const unacknowledged = (entries) => entries.filter((e) => !e.ack);
52
+ /** `next-run` entries first, then standing; each group newest first. This is the order a lane works in. */
53
+ export function steerOrder(entries) {
54
+ const byTimeDesc = (a, b) => b.at.localeCompare(a.at);
55
+ return [...unacknowledged(entries).filter((e) => e.scope === 'next-run').sort(byTimeDesc), ...entries.filter((e) => e.scope === 'standing').sort(byTimeDesc)];
56
+ }
57
+ /** Standing entries that still apply (acknowledged or not; they stay until removed). */
58
+ export const standingEntries = (entries) => entries.filter((e) => e.scope === 'standing');
59
+ /** Puts a new entry first (newest first), directly after the intro. An empty or missing file gets the intro-less entry alone. */
60
+ export function addSteerEntry(fileText, entry) {
61
+ const block = formatSteerEntry(entry);
62
+ const text = fileText.replace(/\r\n/g, '\n');
63
+ const firstEntry = text.search(/^## /m);
64
+ if (firstEntry < 0)
65
+ return `${text.trimEnd()}${text.trim() ? '\n\n' : ''}${block}`;
66
+ return `${text.slice(0, firstEntry)}${block}\n${text.slice(firstEntry)}`;
67
+ }
68
+ //# sourceMappingURL=steer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"steer.js","sourceRoot":"","sources":["../../../src/core/parse/steer.ts"],"names":[],"mappings":"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"}
package/dist/core/repo.js CHANGED
@@ -19,6 +19,21 @@ export function parseLockTime(lockText) {
19
19
  export function countDoneRounds(fileNames) {
20
20
  return fileNames.filter((name) => /^done-v\d+\.md$/.test(name)).length;
21
21
  }
22
+ /**
23
+ * Finished rounds. A brief that has `## Round N` headings is the source: every round heading not marked "current"
24
+ * counts once. Without such headings (a single-loop repo) the `done-vN.md` files are counted, since a handoff note
25
+ * named `done-v5.md` must not make a fifth round.
26
+ */
27
+ export function countRounds(briefText, doneFileNames) {
28
+ const rounds = new Set();
29
+ for (const line of (briefText ?? '').split(/\r?\n/)) {
30
+ const m = /^#{1,3}\s+Round\s+(\d+)\b(.*)$/i.exec(line);
31
+ // "### Round 5 done when" is a checklist inside a round, not a finished round.
32
+ if (m && !/\bcurrent\b/i.test(m[2] ?? '') && !/^\s*done when\b/i.test(m[2] ?? ''))
33
+ rounds.add(Number(m[1]));
34
+ }
35
+ return rounds.size > 0 ? rounds.size : countDoneRounds(doneFileNames);
36
+ }
22
37
  async function exists(file) {
23
38
  try {
24
39
  await stat(file);
@@ -62,7 +77,7 @@ export async function readLoopFacts(dir) {
62
77
  // The stop files sit at the repo root, per CLAUDE.md "Unattended mode".
63
78
  hasBlocked: await exists(path.join(dir, 'BLOCKED.md')),
64
79
  hasDone: await exists(path.join(dir, 'DONE.md')),
65
- roundsDone: countDoneRounds(aiFiles),
80
+ roundsDone: countRounds(await readOptional(path.join(dir, 'IDEA.md')), aiFiles),
66
81
  ...(lockAt && { lockAt }),
67
82
  ...(lastCommitAt && { lastCommitAt }),
68
83
  healthFailures: [],
@@ -1 +1 @@
1
- {"version":3,"file":"repo.js","sourceRoot":"","sources":["../../src/core/repo.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"repo.js","sourceRoot":"","sources":["../../src/core/repo.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,54 @@
1
+ // Pure: turns the JSON body of a steer or schedule POST into a typed action, or says what is wrong with it (HTTP 400).
2
+ import { PACES, isPace } from '../core/parse/policy.js';
3
+ const nonEmpty = (value) => typeof value === 'string' && value.trim() !== '';
4
+ const asRecord = (body) => (typeof body === 'object' && body !== null ? body : {});
5
+ export function parseSteerBody(body) {
6
+ const { lane, text, standing, author } = asRecord(body);
7
+ if (!nonEmpty(lane))
8
+ return { ok: false, error: 'lane must be a non-empty string' };
9
+ // `all` only means every lane for a schedule wake; it is never a lane to steer.
10
+ if (lane === 'all')
11
+ return { ok: false, error: 'steer one lane at a time; "all" is not a lane' };
12
+ if (!nonEmpty(text))
13
+ return { ok: false, error: 'text must be a non-empty string' };
14
+ if (standing !== undefined && typeof standing !== 'boolean')
15
+ return { ok: false, error: 'standing must be true or false' };
16
+ return { ok: true, value: { lane, text, standing: standing === true, ...(nonEmpty(author) && { author }) } };
17
+ }
18
+ export function parseScheduleBody(body) {
19
+ const { action, lane, until, reason } = asRecord(body);
20
+ if (!nonEmpty(lane))
21
+ return { ok: false, error: 'lane must be a non-empty string' };
22
+ const why = nonEmpty(reason) ? { reason } : {};
23
+ switch (action) {
24
+ case 'pause':
25
+ return { ok: true, value: { action, lane, ...why } };
26
+ case 'snooze':
27
+ if (!nonEmpty(until))
28
+ return { ok: false, error: 'until must be an ISO time, a date or a span such as 3h' };
29
+ return { ok: true, value: { action, lane, until, ...why } };
30
+ case 'resume':
31
+ case 'wake':
32
+ return { ok: true, value: { action, lane } };
33
+ default:
34
+ return { ok: false, error: 'action must be pause, resume, snooze or wake' };
35
+ }
36
+ }
37
+ export function parsePaceBody(body) {
38
+ const { pace, lane } = asRecord(body);
39
+ if (!isPace(pace))
40
+ return { ok: false, error: `pace must be one of: ${PACES.join(', ')}` };
41
+ if (lane !== undefined && (!nonEmpty(lane) || lane === 'all'))
42
+ return { ok: false, error: 'lane must be a lane name; leave it out to set the whole loop' };
43
+ return { ok: true, value: { pace, ...(lane !== undefined && { lane }) } };
44
+ }
45
+ /** An optional `model` for `claude -p --model`; it is an argument, never a shell string, but keep it to model-id characters anyway. */
46
+ export function parseDraftBody(body) {
47
+ const { model } = asRecord(body);
48
+ if (model === undefined)
49
+ return { ok: true, value: {} };
50
+ if (typeof model !== 'string' || !/^[A-Za-z0-9][A-Za-z0-9._:[\]-]{0,63}$/.test(model))
51
+ return { ok: false, error: 'model must be a model id such as claude-opus-5-5' };
52
+ return { ok: true, value: { model } };
53
+ }
54
+ //# sourceMappingURL=actionBody.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"actionBody.js","sourceRoot":"","sources":["../../src/server/actionBody.ts"],"names":[],"mappings":"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"}
@@ -20,8 +20,13 @@ export function formatUtc(iso) {
20
20
  return String(iso);
21
21
  return `${d.getUTCDate()} ${MONTHS[d.getUTCMonth()]} ${two(d.getUTCHours())}:${two(d.getUTCMinutes())} UTC`;
22
22
  }
23
- /** Adds the result-stating `label` to a check (with or without its `loopId`); an existing label is kept. */
23
+ /** The three-way result: an explicit `state` wins, else it follows `ok`. */
24
+ export function checkState(check) {
25
+ return check.state ?? (check.ok ? 'pass' : 'fail');
26
+ }
27
+ /** Adds the result-stating `label` and the `state` to a check (with or without its `loopId`); an existing label is kept. */
24
28
  export function withLabel(check) {
25
- return { ...check, label: check.label ?? checkLabel(check.kind, check.ok) };
29
+ const state = checkState(check);
30
+ return { ...check, state, label: check.label ?? (state === 'unchecked' ? 'Not checked' : checkLabel(check.kind, check.ok)) };
26
31
  }
27
32
  //# sourceMappingURL=checkLabels.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"checkLabels.js","sourceRoot":"","sources":["../../src/server/checkLabels.ts"],"names":[],"mappings":"AAGA,MAAM,MAAM,GAAuE;IACjF,IAAI,EAAE,CAAC,UAAU,EAAE,YAAY,CAAC;IAChC,YAAY,EAAE,CAAC,eAAe,EAAE,YAAY,CAAC;IAC7C,YAAY,EAAE,CAAC,mBAAmB,EAAE,qBAAqB,CAAC;IAC1D,eAAe,EAAE,CAAC,YAAY,EAAE,eAAe,CAAC;IAChD,eAAe,EAAE,CAAC,eAAe,EAAE,eAAe,CAAC;IACnD,cAAc,EAAE,CAAC,cAAc,EAAE,cAAc,CAAC;IAChD,0BAA0B,EAAE,CAAC,kCAAkC,EAAE,+BAA+B,CAAC;CAClG,CAAC;AAEF,0GAA0G;AAC1G,MAAM,UAAU,UAAU,CAAC,IAAyB,EAAE,EAAW;IAC/D,OAAO,MAAM,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAClC,CAAC;AAED,MAAM,MAAM,GAAG,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,CAAU,CAAC;AAC7G,MAAM,GAAG,GAAG,CAAC,CAAS,EAAE,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;AAEtD,4FAA4F;AAC5F,MAAM,UAAU,SAAS,CAAC,GAAkB;IAC1C,MAAM,CAAC,GAAG,OAAO,GAAG,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC;IACxD,IAAI,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC;QAAE,OAAO,MAAM,CAAC,GAAG,CAAC,CAAC;IAClD,OAAO,GAAG,CAAC,CAAC,UAAU,EAAE,IAAI,MAAM,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,aAAa,EAAE,CAAC,MAAM,CAAC;AAC9G,CAAC;AAED,4GAA4G;AAC5G,MAAM,UAAU,SAAS,CAAuE,KAAQ;IACtG,OAAO,EAAE,GAAG,KAAK,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,IAAI,UAAU,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,EAAE,CAAC,EAAE,CAAC;AAC9E,CAAC"}
1
+ {"version":3,"file":"checkLabels.js","sourceRoot":"","sources":["../../src/server/checkLabels.ts"],"names":[],"mappings":"AAGA,MAAM,MAAM,GAAuE;IACjF,IAAI,EAAE,CAAC,UAAU,EAAE,YAAY,CAAC;IAChC,YAAY,EAAE,CAAC,eAAe,EAAE,YAAY,CAAC;IAC7C,YAAY,EAAE,CAAC,mBAAmB,EAAE,qBAAqB,CAAC;IAC1D,eAAe,EAAE,CAAC,YAAY,EAAE,eAAe,CAAC;IAChD,eAAe,EAAE,CAAC,eAAe,EAAE,eAAe,CAAC;IACnD,cAAc,EAAE,CAAC,cAAc,EAAE,cAAc,CAAC;IAChD,0BAA0B,EAAE,CAAC,kCAAkC,EAAE,+BAA+B,CAAC;CAClG,CAAC;AAEF,0GAA0G;AAC1G,MAAM,UAAU,UAAU,CAAC,IAAyB,EAAE,EAAW;IAC/D,OAAO,MAAM,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAClC,CAAC;AAED,MAAM,MAAM,GAAG,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,CAAU,CAAC;AAC7G,MAAM,GAAG,GAAG,CAAC,CAAS,EAAE,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;AAEtD,4FAA4F;AAC5F,MAAM,UAAU,SAAS,CAAC,GAAkB;IAC1C,MAAM,CAAC,GAAG,OAAO,GAAG,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC;IACxD,IAAI,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC;QAAE,OAAO,MAAM,CAAC,GAAG,CAAC,CAAC;IAClD,OAAO,GAAG,CAAC,CAAC,UAAU,EAAE,IAAI,MAAM,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,aAAa,EAAE,CAAC,MAAM,CAAC;AAC9G,CAAC;AAED,4EAA4E;AAC5E,MAAM,UAAU,UAAU,CAAC,KAAiE;IAC1F,OAAO,KAAK,CAAC,KAAK,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;AACrD,CAAC;AAED,4HAA4H;AAC5H,MAAM,UAAU,SAAS,CAAkH,KAAQ;IACjJ,MAAM,KAAK,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC;IAChC,OAAO,EAAE,GAAG,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,IAAI,CAAC,KAAK,KAAK,WAAW,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,UAAU,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;AAC/H,CAAC"}
@@ -0,0 +1,18 @@
1
+ import { execFile } from 'node:child_process';
2
+ import { resolveInvocation } from '../cli/run.js';
3
+ export const abortableClaude = async (rawArgs, cwd, signal) => {
4
+ if (signal?.aborted)
5
+ throw new Error('The draft was stopped.');
6
+ const { command, args } = await resolveInvocation('claude', rawArgs);
7
+ return new Promise((resolve, reject) => {
8
+ execFile(command, args, { cwd, maxBuffer: 16 * 1024 * 1024, timeout: 15 * 60_000, ...(signal && { signal }) }, (error, stdout) => {
9
+ if (!error)
10
+ resolve(stdout);
11
+ else if (signal?.aborted)
12
+ reject(new Error('The draft was stopped.'));
13
+ else
14
+ reject(new Error(`Could not run \`claude -p\`: ${error.message}. Is Claude Code installed, on your PATH and signed in? \`loop next-round --draft --print-prompt\` prints the prompt to paste yourself.`));
15
+ });
16
+ });
17
+ };
18
+ //# sourceMappingURL=claude.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"claude.js","sourceRoot":"","sources":["../../src/server/claude.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAKlD,MAAM,CAAC,MAAM,eAAe,GAAoB,KAAK,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,EAAE;IAC7E,IAAI,MAAM,EAAE,OAAO;QAAE,MAAM,IAAI,KAAK,CAAC,wBAAwB,CAAC,CAAC;IAC/D,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,GAAG,MAAM,iBAAiB,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IACrE,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACrC,QAAQ,CAAC,OAAO,EAAE,IAAI,EAAE,EAAE,GAAG,EAAE,SAAS,EAAE,EAAE,GAAG,IAAI,GAAG,IAAI,EAAE,OAAO,EAAE,EAAE,GAAG,MAAM,EAAE,GAAG,CAAC,MAAM,IAAI,EAAE,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE;YAC/H,IAAI,CAAC,KAAK;gBAAE,OAAO,CAAC,MAAM,CAAC,CAAC;iBACvB,IAAI,MAAM,EAAE,OAAO;gBAAE,MAAM,CAAC,IAAI,KAAK,CAAC,wBAAwB,CAAC,CAAC,CAAC;;gBACjE,MAAM,CAAC,IAAI,KAAK,CAAC,gCAAgC,KAAK,CAAC,OAAO,yIAAyI,CAAC,CAAC,CAAC;QACjN,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC,CAAC"}
@@ -1,11 +1,12 @@
1
1
  // Pure (no Node imports): the GitHub pages the static dashboard opens instead of holding a token. Every URL is a
2
2
  // function of the repo slug, so a user with write access to the repo is the only one who can finish the action.
3
- import { formatPaused, PAUSED_FILE } from '../core/parse/index.js';
3
+ import { POLICY_FILE, formatPaused, formatPolicy, formatSchedule, withPace, formatSteerEntry, PAUSED_FILE, SCHEDULE_FILE, steerPath } from '../core/parse/index.js';
4
4
  import { isRepoSlug } from './live/urls.js';
5
5
  export const RELEASE_WORKFLOW = 'release.yml';
6
6
  export const NEXT_ROUND_FILE = '.ai/next-round.md';
7
7
  const GITHUB = 'https://github.com';
8
8
  const API = 'https://api.github.com';
9
+ export const NPM_REGISTRY = 'https://registry.npmjs.org';
9
10
  function checkedSlug(slug) {
10
11
  if (!isRepoSlug(slug))
11
12
  throw new Error(`not a GitHub repo slug: ${slug}`);
@@ -17,6 +18,12 @@ function checkedPath(file) {
17
18
  throw new Error(`not a repo file path: ${file}`);
18
19
  return file;
19
20
  }
21
+ /** A lane name is a single path segment of simple characters (the same rule core applies). */
22
+ function checkedLane(lane) {
23
+ if (!/^[A-Za-z0-9][A-Za-z0-9_-]*$/.test(lane))
24
+ throw new Error(`not a lane name: ${lane}`);
25
+ return lane;
26
+ }
20
27
  /** GitHub answers 414 above roughly 8 KB; stay well under it. */
21
28
  export const MAX_URL_LENGTH = 7500;
22
29
  /** A branch name keeps its slashes (`feature/x`) and encodes every other character. */
@@ -49,12 +56,32 @@ export const resumeUrl = (slug, branch = 'main') => deleteFileUrl(slug, PAUSED_F
49
56
  export function nextRoundUrl(slug, brief, branch = 'main') {
50
57
  return newFileUrl(slug, NEXT_ROUND_FILE, brief.endsWith('\n') ? brief : `${brief}\n`, branch);
51
58
  }
59
+ /** Steer, file missing: the new-file page for the lane's `steer.md` holding the intro line and the first entry. */
60
+ export function steerNewFileUrl(slug, lane, entry, branch = 'main') {
61
+ return newFileUrl(slug, steerPath(checkedLane(lane)), `# Steering for the ${lane} lane\n\n${formatSteerEntry(entry)}`, branch);
62
+ }
63
+ /** Steer, file exists: GitHub cannot prefill an edit, so the UI copies `formatSteerEntry` and opens this editor page. */
64
+ export const steerEditUrl = (slug, lane, branch = 'main') => editFileUrl(slug, steerPath(checkedLane(lane)), branch);
65
+ /** Schedule edit: the editor page for `.ai/schedule.json`; the UI copies `scheduleEditText` to paste over the file. */
66
+ export const scheduleEditUrl = (slug, branch = 'main') => editFileUrl(slug, SCHEDULE_FILE, branch);
67
+ /** The whole `schedule.json` text after the edit, in the exact format `loop schedule` writes. */
68
+ export const scheduleEditText = (schedule) => formatSchedule(schedule);
69
+ /** Pace edit: the editor page for `.ai/policy.json`; the UI copies `paceEditText` to paste over the file. */
70
+ export const paceEditUrl = (slug, branch = 'main') => editFileUrl(slug, POLICY_FILE, branch);
71
+ /** The whole `policy.json` text after setting the loop's pace (or one lane's), in the exact format `loop pace` writes. */
72
+ export const paceEditText = (policy, pace, lane) => formatPolicy(withPace(policy, pace, lane));
52
73
  /** The Actions page where the owner presses "Run workflow" for the release workflow. */
53
74
  export const releaseWorkflowUrl = (slug) => `${GITHUB}/${checkedSlug(slug)}/actions/workflows/${RELEASE_WORKFLOW}`;
54
75
  /** API URL for the latest run of the release workflow (the dashboard shows its result). */
55
76
  export const latestReleaseRunApiUrl = (slug) => `${API}/repos/${checkedSlug(slug)}/actions/workflows/${RELEASE_WORKFLOW}/runs?per_page=1`;
56
77
  /** API URL listing the repo's tags (for the ship-check "tag does not exist yet" item). */
57
78
  export const tagsApiUrl = (slug) => `${API}/repos/${checkedSlug(slug)}/tags?per_page=100`;
79
+ /** The npm registry's package document (`dist-tags`, `versions`); it sends `Access-Control-Allow-Origin: *`, so the static demo may read it. Scoped names keep their `@` and encode the slash. */
80
+ export const npmPackageUrl = (name) => {
81
+ if (!/^(?:@[a-z0-9][a-z0-9._-]*\/)?[a-z0-9][a-z0-9._-]*$/.test(name))
82
+ throw new Error(`not an npm package name: ${name}`);
83
+ return `${NPM_REGISTRY}/${name.replace('/', '%2f')}`;
84
+ };
58
85
  /** API URL matching one release tag by prefix; unlike `tagsApiUrl` it is not capped by the repo's first 100 tags. Response items carry `ref: "refs/tags/<name>"`. */
59
86
  export const tagLookupApiUrl = (slug, version) => `${API}/repos/${checkedSlug(slug)}/git/matching-refs/tags/v${encodeURIComponent(version)}`;
60
87
  /** True when `nextRoundUrl` can carry this brief; otherwise the UI offers Copy and the blank new-file page. */
@@ -1 +1 @@
1
- {"version":3,"file":"controls.js","sourceRoot":"","sources":["../../src/server/controls.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"controls.js","sourceRoot":"","sources":["../../src/server/controls.ts"],"names":[],"mappings":"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"}
@@ -7,7 +7,7 @@ export function sortByAttention(loops) {
7
7
  }
8
8
  /** The detail-only fields stay out of the fleet list. */
9
9
  export function toSummary(detail) {
10
- const { controlNotes: _controlNotes, releases: _releases, ship: _ship, runs: _runs, nextRuns: _nextRuns, laneNotes: _laneNotes, timeline: _timeline, contract: _contract, knowledge: _knowledge, decisions: _decisions, history: _history, ...summary } = detail;
10
+ const { controlNotes: _controlNotes, releases: _releases, ship: _ship, runs: _runs, nextRuns: _nextRuns, schedule: _schedule, pace: _pace, idleRuns: _idleRuns, steer: _steer, laneNotes: _laneNotes, timeline: _timeline, contract: _contract, knowledge: _knowledge, decisions: _decisions, history: _history, ...summary } = detail;
11
11
  return summary;
12
12
  }
13
13
  /** Marks every loop of a bundled snapshot with when it was taken, so the UI says "snapshot 6 Oct" and never "Live". */
@@ -1 +1 @@
1
- {"version":3,"file":"data.js","sourceRoot":"","sources":["../../src/server/data.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"data.js","sourceRoot":"","sources":["../../src/server/data.ts"],"names":[],"mappings":"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"}