compounding-loop 0.4.0 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (128) hide show
  1. package/README.md +152 -128
  2. package/dist/cli/draft.js +69 -0
  3. package/dist/cli/draft.js.map +1 -0
  4. package/dist/cli/eval.js +186 -0
  5. package/dist/cli/eval.js.map +1 -0
  6. package/dist/cli/hook.js +92 -0
  7. package/dist/cli/hook.js.map +1 -0
  8. package/dist/cli/index.js +336 -1
  9. package/dist/cli/index.js.map +1 -1
  10. package/dist/cli/init.js +41 -4
  11. package/dist/cli/init.js.map +1 -1
  12. package/dist/cli/lanesInit.js +8 -2
  13. package/dist/cli/lanesInit.js.map +1 -1
  14. package/dist/cli/pace.js +41 -0
  15. package/dist/cli/pace.js.map +1 -0
  16. package/dist/cli/pause.js +3 -3
  17. package/dist/cli/pause.js.map +1 -1
  18. package/dist/cli/recipe.js +89 -0
  19. package/dist/cli/recipe.js.map +1 -0
  20. package/dist/cli/recipeDraft.js +64 -0
  21. package/dist/cli/recipeDraft.js.map +1 -0
  22. package/dist/cli/runs.js +49 -11
  23. package/dist/cli/runs.js.map +1 -1
  24. package/dist/cli/schedule.js +177 -0
  25. package/dist/cli/schedule.js.map +1 -0
  26. package/dist/core/brief.js +35 -12
  27. package/dist/core/brief.js.map +1 -1
  28. package/dist/core/draftBrief.js +68 -0
  29. package/dist/core/draftBrief.js.map +1 -0
  30. package/dist/core/eval.js +123 -0
  31. package/dist/core/eval.js.map +1 -0
  32. package/dist/core/hooksInit.js +54 -0
  33. package/dist/core/hooksInit.js.map +1 -0
  34. package/dist/core/laneRound.js +28 -7
  35. package/dist/core/laneRound.js.map +1 -1
  36. package/dist/core/lanes.js +3 -0
  37. package/dist/core/lanes.js.map +1 -1
  38. package/dist/core/lanesInit.js +19 -0
  39. package/dist/core/lanesInit.js.map +1 -1
  40. package/dist/core/parse/index.js +8 -0
  41. package/dist/core/parse/index.js.map +1 -1
  42. package/dist/core/parse/outcomes.js +51 -0
  43. package/dist/core/parse/outcomes.js.map +1 -0
  44. package/dist/core/parse/policy.js +56 -0
  45. package/dist/core/parse/policy.js.map +1 -0
  46. package/dist/core/parse/runs.js +1 -0
  47. package/dist/core/parse/runs.js.map +1 -1
  48. package/dist/core/parse/schedule.js +101 -0
  49. package/dist/core/parse/schedule.js.map +1 -0
  50. package/dist/core/parse/steer.js +68 -0
  51. package/dist/core/parse/steer.js.map +1 -0
  52. package/dist/core/recipeDraft.js +37 -0
  53. package/dist/core/recipeDraft.js.map +1 -0
  54. package/dist/core/recipes.js +185 -0
  55. package/dist/core/recipes.js.map +1 -0
  56. package/dist/core/repo.js +16 -1
  57. package/dist/core/repo.js.map +1 -1
  58. package/dist/core/triggers.js +137 -0
  59. package/dist/core/triggers.js.map +1 -0
  60. package/dist/server/actionBody.js +54 -0
  61. package/dist/server/actionBody.js.map +1 -0
  62. package/dist/server/checkLabels.js +7 -2
  63. package/dist/server/checkLabels.js.map +1 -1
  64. package/dist/server/claude.js +18 -0
  65. package/dist/server/claude.js.map +1 -0
  66. package/dist/server/controls.js +28 -1
  67. package/dist/server/controls.js.map +1 -1
  68. package/dist/server/data.js +8 -3
  69. package/dist/server/data.js.map +1 -1
  70. package/dist/server/draftInputs.js +33 -0
  71. package/dist/server/draftInputs.js.map +1 -0
  72. package/dist/server/health.js +3 -3
  73. package/dist/server/health.js.map +1 -1
  74. package/dist/server/index.js +55 -0
  75. package/dist/server/index.js.map +1 -1
  76. package/dist/server/laneChecks.js +1 -1
  77. package/dist/server/laneChecks.js.map +1 -1
  78. package/dist/server/laneSchedule.js +15 -0
  79. package/dist/server/laneSchedule.js.map +1 -0
  80. package/dist/server/live/build.js +25 -10
  81. package/dist/server/live/build.js.map +1 -1
  82. package/dist/server/live/index.js +4 -2
  83. package/dist/server/live/index.js.map +1 -1
  84. package/dist/server/live/urls.js +3 -1
  85. package/dist/server/live/urls.js.map +1 -1
  86. package/dist/server/loops.js +145 -20
  87. package/dist/server/loops.js.map +1 -1
  88. package/dist/server/memory.js +115 -0
  89. package/dist/server/memory.js.map +1 -0
  90. package/dist/server/memory.json +398 -0
  91. package/dist/server/paceNote.js +13 -0
  92. package/dist/server/paceNote.js.map +1 -0
  93. package/dist/server/roundState.js +26 -2
  94. package/dist/server/roundState.js.map +1 -1
  95. package/dist/server/runs.js +72 -9
  96. package/dist/server/runs.js.map +1 -1
  97. package/dist/server/shipped.js +35 -0
  98. package/dist/server/shipped.js.map +1 -0
  99. package/dist/server/static-export.js +8 -2
  100. package/dist/server/static-export.js.map +1 -1
  101. package/dist/server/this-repo.json +2367 -858
  102. package/dist/web/assets/index-C5q9d5-n.css +2 -0
  103. package/dist/web/assets/index-DDEAcJFt.js +123 -0
  104. package/dist/web/index.html +2 -2
  105. package/method/COMPOUNDING_LOOP.md +33 -6
  106. package/method/operating-card.md +1 -1
  107. package/method/retro.md +4 -3
  108. package/package.json +4 -4
  109. package/plugin/.claude-plugin/plugin.json +1 -1
  110. package/plugin/commands/loop-init.md +1 -0
  111. package/plugin/commands/retro.md +3 -2
  112. package/plugin/hooks/hooks.json +62 -0
  113. package/runners/github-actions/lanes.yml +2 -2
  114. package/runners/routine/README.md +4 -0
  115. package/runners/routine/control-room-prompt.md +4 -14
  116. package/runners/routine/lane-prompt.md +4 -10
  117. package/templates/lanes/README.md +5 -1
  118. package/templates/lanes/claude-section.md +1 -0
  119. package/templates/lanes/control-run.md +37 -0
  120. package/templates/lanes/lane-run.md +33 -0
  121. package/templates/lanes/schedule.json +4 -0
  122. package/templates/lanes/steer.md +3 -0
  123. package/templates/recipe.md +39 -0
  124. package/templates/recipes/cli-command-json.md +47 -0
  125. package/templates/recipes/static-calculator-site.md +50 -0
  126. package/templates/static-site/CLAUDE.md +1 -1
  127. package/dist/web/assets/index-BOPytDNU.js +0 -53
  128. package/dist/web/assets/index-BSHEI7fa.css +0 -2
@@ -0,0 +1,177 @@
1
+ import { mkdir, readFile, writeFile } from 'node:fs/promises';
2
+ import path from 'node:path';
3
+ import { CONTROL_LANE, parseLanesConfig } from '../core/lanes.js';
4
+ import { parseOutbox } from '../core/laneStatus.js';
5
+ import { SCHEDULE_FILE, applyBackoff, dueEntry, formatSchedule, notDueReason, parseSchedule, parseUntil, trailingIdleRuns, wakeEntry, wakeReasons, } from '../core/parse/schedule.js';
6
+ import { parseRunLog, runLogPath } from '../core/parse/runs.js';
7
+ import { addSteerEntry, parseSteer, steerPath } from '../core/parse/steer.js';
8
+ import { git, pushIfWanted, syncFirst } from './pause.js';
9
+ export const read = (dir, rel) => readFile(path.join(dir, ...rel.split('/')), 'utf8').catch(() => undefined);
10
+ export async function readSchedule(dir) {
11
+ return parseSchedule((await read(dir, SCHEDULE_FILE)) ?? '');
12
+ }
13
+ /** Lane names from `.ai/lanes.json`; undefined when the repo has none (any simple name is then accepted). */
14
+ async function knownLanes(dir) {
15
+ const text = await read(dir, '.ai/lanes.json');
16
+ const parsed = text === undefined ? undefined : parseLanesConfig(text).config;
17
+ return parsed?.lanes.map((l) => l.name);
18
+ }
19
+ export async function checkLane(dir, lane) {
20
+ if (!/^[A-Za-z0-9][A-Za-z0-9_-]*$/.test(lane))
21
+ throw new Error(`"${lane}" is not a lane name.`);
22
+ const names = await knownLanes(dir);
23
+ if (names && !names.includes(lane))
24
+ throw new Error(`No lane "${lane}". Lanes here: ${names.join(', ')}.`);
25
+ }
26
+ export async function writeRel(dir, rel, text) {
27
+ const file = path.join(dir, ...rel.split('/'));
28
+ await mkdir(path.dirname(file), { recursive: true });
29
+ await writeFile(file, text);
30
+ }
31
+ /** Writes nothing when `commit` is false; otherwise commits the files with `Lane: control` and (by default) pushes. */
32
+ export async function commitFiles(dir, files, message, options, result, trailer = CONTROL_LANE) {
33
+ if (options.commit === false || result.changed.length === 0)
34
+ return;
35
+ await git(dir, 'add', '--', ...files);
36
+ await git(dir, 'commit', '-qm', `${message}\n\nLane: ${trailer}`, '--', ...files);
37
+ result.committed = true;
38
+ await pushIfWanted(dir, result, options.push);
39
+ }
40
+ export async function runScheduleShow(dir, now = new Date()) {
41
+ const schedule = await readSchedule(dir);
42
+ const names = (await knownLanes(dir)) ?? Object.keys(schedule.lanes);
43
+ const lanes = [];
44
+ for (const lane of names) {
45
+ const entry = schedule.lanes[lane] ?? dueEntry();
46
+ const runs = parseRunLog((await read(dir, runLogPath(lane))) ?? '');
47
+ lanes.push({ lane, state: notDueReason(entry, now) ?? 'due', entry, idleRuns: trailingIdleRuns(runs) });
48
+ }
49
+ return { lanes };
50
+ }
51
+ export function formatScheduleReport(report) {
52
+ if (report.lanes.length === 0)
53
+ return 'No lanes. Create .ai/lanes.json with `loop init --lanes a,b,c`.';
54
+ return report.lanes
55
+ .map(({ lane, state, entry, idleRuns }) => {
56
+ const detail = [entry.notBefore && state === 'snoozed' ? `until ${entry.notBefore.slice(0, 16).replace('T', ' ')} UTC` : '', idleRuns ? `${idleRuns} idle run${idleRuns === 1 ? '' : 's'}` : '', entry.reason ?? ''].filter(Boolean).join(' · ');
57
+ return `${lane.padEnd(10)} ${state.padEnd(9)} ${detail}`.trimEnd();
58
+ })
59
+ .join('\n');
60
+ }
61
+ const WOKEN = 'woken at ';
62
+ /** Applies one owner action to `.ai/schedule.json`. `wake` takes a lane name or `all`. */
63
+ export async function runScheduleAction(dir, act, options = {}) {
64
+ const now = options.now ?? new Date();
65
+ if (options.commit !== false)
66
+ await syncFirst(dir, options.push);
67
+ const lanes = act.action === 'wake' && act.lane === 'all' ? ((await knownLanes(dir)) ?? Object.keys((await readSchedule(dir)).lanes)) : [act.lane];
68
+ if (!(act.action === 'wake' && act.lane === 'all'))
69
+ await checkLane(dir, act.lane);
70
+ const schedule = await readSchedule(dir);
71
+ const result = { changed: [], committed: false };
72
+ for (const lane of lanes) {
73
+ const before = schedule.lanes[lane] ?? dueEntry();
74
+ let after;
75
+ if (act.action === 'pause')
76
+ after = { ...before, paused: true, reason: act.reason?.replace(/\s+/g, ' ').trim() || 'paused by owner' };
77
+ else if (act.action === 'resume')
78
+ after = { ...before, paused: false, reason: null };
79
+ else if (act.action === 'snooze') {
80
+ const until = parseUntil(act.until, now);
81
+ if (!until)
82
+ throw new Error(`Cannot read "${act.until}" as a future time. Use an ISO time, a date, or a span such as 3h or 2d.`);
83
+ after = { ...before, notBefore: until.toISOString(), sleeping: false, reason: act.reason?.replace(/\s+/g, ' ').trim() || 'snoozed by owner' };
84
+ }
85
+ else
86
+ after = { ...wakeEntry(before), reason: `${WOKEN}${now.toISOString()}` };
87
+ if (JSON.stringify(before) !== JSON.stringify(after)) {
88
+ schedule.lanes[lane] = after;
89
+ result.changed.push(lane);
90
+ }
91
+ }
92
+ if (result.changed.length === 0)
93
+ return result;
94
+ await writeRel(dir, SCHEDULE_FILE, formatSchedule(schedule));
95
+ await commitFiles(dir, [SCHEDULE_FILE], `Schedule: ${act.action} ${result.changed.join(', ')}`, options, result);
96
+ return result;
97
+ }
98
+ /**
99
+ * `loop schedule update`: wake lanes that have something waiting (unacknowledged steer, a message newer than their
100
+ * last run, a new round), otherwise apply the idle backoff from each lane's runs.jsonl. A lane woken by hand stays
101
+ * woken until it logs a run.
102
+ */
103
+ export async function runScheduleUpdate(dir, options = {}) {
104
+ const now = options.now ?? new Date();
105
+ if (options.commit !== false)
106
+ await syncFirst(dir, options.push);
107
+ const schedule = await readSchedule(dir);
108
+ if (options.lane)
109
+ await checkLane(dir, options.lane);
110
+ const names = options.lane ? [options.lane] : ((await knownLanes(dir)) ?? Object.keys(schedule.lanes));
111
+ const controlRoom = parseOutbox('control', (await read(dir, '.ai/control-room.md')) ?? '');
112
+ const outboxes = (await Promise.all((await knownLanes(dir) ?? names).map(async (lane) => parseOutbox(lane, (await read(dir, `.ai/lanes/${lane}/outbox.md`)) ?? '')))).flat();
113
+ const result = { changed: [], committed: false, woken: {} };
114
+ for (const lane of names) {
115
+ const before = schedule.lanes[lane] ?? dueEntry();
116
+ if (before.paused)
117
+ continue;
118
+ const runs = parseRunLog((await read(dir, runLogPath(lane))) ?? '');
119
+ const lastRunAt = runs.at(-1)?.at;
120
+ const manualWake = before.reason?.startsWith(WOKEN) && (!lastRunAt || new Date(lastRunAt).getTime() < new Date(before.reason.slice(WOKEN.length)).getTime());
121
+ const reasons = wakeReasons({
122
+ lane,
123
+ ...(lastRunAt && { lastRunAt }),
124
+ steer: parseSteer((await read(dir, steerPath(lane))) ?? ''),
125
+ messages: [...controlRoom, ...outboxes.filter((m) => m.from !== lane)],
126
+ ...(options.newRound && { newRound: true }),
127
+ });
128
+ let after = before;
129
+ if (manualWake)
130
+ continue;
131
+ if (reasons.length > 0) {
132
+ if (notDueReason(before, now)) {
133
+ after = { ...wakeEntry(before), reason: `woken: ${reasons.join(', ')}` };
134
+ result.woken[lane] = reasons;
135
+ }
136
+ }
137
+ else
138
+ after = applyBackoff(runs, before, now);
139
+ if (JSON.stringify(before) !== JSON.stringify(after)) {
140
+ schedule.lanes[lane] = after;
141
+ result.changed.push(lane);
142
+ }
143
+ }
144
+ if (result.changed.length === 0)
145
+ return result;
146
+ await writeRel(dir, SCHEDULE_FILE, formatSchedule(schedule));
147
+ await commitFiles(dir, [SCHEDULE_FILE], `Schedule: update ${result.changed.join(', ')}`, options, result, options.lane ?? CONTROL_LANE);
148
+ return result;
149
+ }
150
+ /** `loop steer`: adds a steer entry for a lane, wakes the lane in the schedule and commits both files. */
151
+ export async function runSteer(dir, lane, text, options = {}) {
152
+ const now = options.now ?? new Date();
153
+ if (!text.trim())
154
+ throw new Error('Say what the lane should do: loop steer <lane> "<text>".');
155
+ await checkLane(dir, lane);
156
+ if (options.commit !== false)
157
+ await syncFirst(dir, options.push);
158
+ const author = (options.author ?? (await git(dir, 'config', 'user.name').then((r) => r.stdout.trim(), () => ''))).trim();
159
+ if (!author)
160
+ throw new Error('Say who you are with --author <name> (git user.name is not set).');
161
+ const scope = options.standing ? 'standing' : 'next-run';
162
+ const file = steerPath(lane);
163
+ const current = (await read(dir, file)) ?? `# Steering for the ${lane} lane\n`;
164
+ await writeRel(dir, file, addSteerEntry(current, { at: now, author, scope, text }));
165
+ const schedule = await readSchedule(dir);
166
+ const before = schedule.lanes[lane];
167
+ const result = { changed: [lane], committed: false };
168
+ const files = [file];
169
+ if (before && (before.sleeping || before.notBefore)) {
170
+ schedule.lanes[lane] = { ...wakeEntry(before), reason: 'woken: steer' };
171
+ await writeRel(dir, SCHEDULE_FILE, formatSchedule(schedule));
172
+ files.push(SCHEDULE_FILE);
173
+ }
174
+ await commitFiles(dir, files, `Steer ${lane} (${scope}): ${text.trim().split(/\r?\n/)[0]?.slice(0, 60)}`, options, result);
175
+ return result;
176
+ }
177
+ //# sourceMappingURL=schedule.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schedule.js","sourceRoot":"","sources":["../../src/cli/schedule.ts"],"names":[],"mappings":"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"}
@@ -4,20 +4,40 @@ const VAGUE_WORDS = /\b(good|nice|great|modern|fast|clean|user-friendly|intuitiv
4
4
  const MIN_WORDS = 120;
5
5
  /** Bold labels (`**Goal:** text`) count as the deepest heading level. */
6
6
  const LABEL_LEVEL = 7;
7
+ /** `**Label:**` or `**Label**:` lead-ins, also several on one line (a round brief runs them together in a paragraph). */
8
+ const INLINE_LABEL = /(?:^|\s)\*\*([^*]{2,80}?)(?::\*\*|\*\*:)\s*/g;
7
9
  function splitSections(text) {
8
10
  const flat = [];
11
+ const addText = (line) => {
12
+ const last = flat[flat.length - 1];
13
+ if (last)
14
+ last.own += `${line}\n`;
15
+ };
9
16
  for (const line of text.split(/\r?\n/)) {
10
17
  const heading = /^(#{1,6})\s+(.*?)\s*#*\s*$/.exec(line);
11
- const label = /^\s*\*\*(.+?)\*\*:?\s*(.*)$/.exec(line) ?? /^\s*\*\*(.+?):\*\*\s*(.*)$/.exec(line);
12
- if (heading)
18
+ if (heading) {
13
19
  flat.push({ heading: heading[2] ?? '', level: (heading[1] ?? '#').length, own: '' });
14
- else if (label && !/^\s*[-*+]\s/.test(line))
15
- flat.push({ heading: (label[1] ?? '').replace(/:$/, ''), level: LABEL_LEVEL, own: `${label[2] ?? ''}\n` });
16
- else {
17
- const last = flat[flat.length - 1];
18
- if (last)
19
- last.own += `${line}\n`;
20
+ continue;
20
21
  }
22
+ const labels = /^\s*[-*+]\s/.test(line) ? [] : [...line.matchAll(INLINE_LABEL)];
23
+ const bare = labels.length === 0 ? /^\s*\*\*([^*]+?)\*\*\s*$/.exec(line) : undefined;
24
+ if (labels.length === 0 && !bare) {
25
+ addText(line);
26
+ continue;
27
+ }
28
+ if (bare) {
29
+ flat.push({ heading: (bare[1] ?? '').replace(/:$/, ''), level: LABEL_LEVEL, own: '' });
30
+ continue;
31
+ }
32
+ const first = labels[0];
33
+ const before = line.slice(0, first.index);
34
+ if (before.trim())
35
+ addText(before);
36
+ labels.forEach((label, i) => {
37
+ const start = (label.index ?? 0) + label[0].length;
38
+ const end = labels[i + 1]?.index ?? line.length;
39
+ flat.push({ heading: (label[1] ?? '').replace(/:$/, '').trim(), level: LABEL_LEVEL, own: `${line.slice(start, end)}\n` });
40
+ });
21
41
  }
22
42
  return flat.map((section, i) => {
23
43
  let body = section.own;
@@ -30,6 +50,8 @@ function splitSections(text) {
30
50
  });
31
51
  }
32
52
  const findSection = (sections, pattern) => sections.find((s) => pattern.test(s.heading));
53
+ /** A round brief lists its must-haves under lettered headings (`### A. P0 bugs`), so every such section counts. */
54
+ const LETTERED = /^\W*[A-Z][.)]\s/;
33
55
  /** Bullet and numbered-list items of a section body, without their markers. */
34
56
  export function listItems(body) {
35
57
  return body
@@ -49,7 +71,7 @@ export function lintBrief(text) {
49
71
  const sections = splitSections(text);
50
72
  const gaps = [];
51
73
  const miss = (gap) => gaps.push(gap);
52
- const oneLine = findSection(sections, /^\W*(one[- ]line|summary|overview|goal|what (this|it) is|pitch)\b/i);
74
+ const oneLine = findSection(sections, /^\W*(one[- ]line|summary|overview|goal|what (this|it|we are|we're) (is |are )?(building|is)?|the new headline|headline|pitch)\b/i);
53
75
  if (!oneLine || oneLine.body.trim().length < 20) {
54
76
  miss({ id: 'one-line', cost: 15, message: 'No one-line description of what you are building.' });
55
77
  }
@@ -57,8 +79,9 @@ export function lintBrief(text) {
57
79
  if (!audience || audience.body.trim().length < 20) {
58
80
  miss({ id: 'audience', cost: 15, message: 'No audience: say who this is for.' });
59
81
  }
60
- const mustHeading = findSection(sections, /^\W*(must[- ]?haves?|requirements?|features?|deliverables?|scope\b)/i);
61
- const items = mustHeading ? listItems(mustHeading.body) : [];
82
+ const mustSections = sections.filter((x) => /^\W*(must[- ]?haves?|requirements?|features?|deliverables?|scope\b)/i.test(x.heading) || LETTERED.test(x.heading));
83
+ // Nested sections repeat their parent's text, so count each list line once.
84
+ const items = [...new Set(mustSections.flatMap((x) => listItems(x.body)))];
62
85
  if (items.length < 3) {
63
86
  miss({ id: 'must-haves', cost: 20, message: 'Fewer than three must-haves listed as bullets.' });
64
87
  }
@@ -72,7 +95,7 @@ export function lintBrief(text) {
72
95
  });
73
96
  }
74
97
  }
75
- const doneWhen = findSection(sections, /^\W*(done[- ]when|definition of done|acceptance|success criteria)/i);
98
+ const doneWhen = findSection(sections, /^\W*(?:round \d+\s+)?(done[- ]when|definition of done|acceptance|success criteria)/i);
76
99
  const checkable = doneWhen ? /`[^`]+`|\b(npm|pnpm|yarn|pytest|make|cargo)\b|\btests?\s+(pass|green)/i.test(doneWhen.body) : false;
77
100
  if (!checkable) {
78
101
  miss({ id: 'done-when', cost: 25, message: 'No checkable done-when: list commands or tests that must pass.' });
@@ -1 +1 @@
1
- {"version":3,"file":"brief.js","sourceRoot":"","sources":["../../src/core/brief.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"brief.js","sourceRoot":"","sources":["../../src/core/brief.ts"],"names":[],"mappings":"AAAA,iGAAiG;AAiBjG,MAAM,CAAC,MAAM,eAAe,GAAG,EAAE,CAAC;AAQlC,MAAM,WAAW,GAAG,4FAA4F,CAAC;AACjH,MAAM,SAAS,GAAG,GAAG,CAAC;AACtB,yEAAyE;AACzE,MAAM,WAAW,GAAG,CAAC,CAAC;AAEtB,yHAAyH;AACzH,MAAM,YAAY,GAAG,8CAA8C,CAAC;AAEpE,SAAS,aAAa,CAAC,IAAY;IACjC,MAAM,IAAI,GAAsD,EAAE,CAAC;IACnE,MAAM,OAAO,GAAG,CAAC,IAAY,EAAE,EAAE;QAC/B,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;QACnC,IAAI,IAAI;YAAE,IAAI,CAAC,GAAG,IAAI,GAAG,IAAI,IAAI,CAAC;IACpC,CAAC,CAAC;IACF,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC;QACvC,MAAM,OAAO,GAAG,4BAA4B,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACxD,IAAI,OAAO,EAAE,CAAC;YACZ,IAAI,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,IAAI,EAAE,EAAE,KAAK,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,MAAM,EAAE,GAAG,EAAE,EAAE,EAAE,CAAC,CAAC;YACrF,SAAS;QACX,CAAC;QACD,MAAM,MAAM,GAAG,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC,CAAC;QAChF,MAAM,IAAI,GAAG,MAAM,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,0BAA0B,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;QACrF,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;YACjC,OAAO,CAAC,IAAI,CAAC,CAAC;YACd,SAAS;QACX,CAAC;QACD,IAAI,IAAI,EAAE,CAAC;YACT,IAAI,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC,EAAE,KAAK,EAAE,WAAW,EAAE,GAAG,EAAE,EAAE,EAAE,CAAC,CAAC;YACvF,SAAS;QACX,CAAC;QACD,MAAM,KAAK,GAAG,MAAM,CAAC,CAAC,CAAqB,CAAC;QAC5C,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC;QAC1C,IAAI,MAAM,CAAC,IAAI,EAAE;YAAE,OAAO,CAAC,MAAM,CAAC,CAAC;QACnC,MAAM,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,CAAC,EAAE,EAAE;YAC1B,MAAM,KAAK,GAAG,CAAC,KAAK,CAAC,KAAK,IAAI,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;YACnD,MAAM,GAAG,GAAG,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,IAAI,IAAI,CAAC,MAAM,CAAC;YAChD,IAAI,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,EAAE,KAAK,EAAE,WAAW,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC;QAC5H,CAAC,CAAC,CAAC;IACL,CAAC;IACD,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,CAAC,EAAE,EAAE;QAC7B,IAAI,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC;QACvB,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC;YACtC,IAAI,KAAK,CAAC,KAAK,IAAI,OAAO,CAAC,KAAK;gBAAE,MAAM;YACxC,IAAI,IAAI,KAAK,CAAC,GAAG,CAAC;QACpB,CAAC;QACD,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC;IAC5C,CAAC,CAAC,CAAC;AACL,CAAC;AAED,MAAM,WAAW,GAAG,CAAC,QAAmB,EAAE,OAAe,EAAE,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;AAE5G,mHAAmH;AACnH,MAAM,QAAQ,GAAG,iBAAiB,CAAC;AAEnC,+EAA+E;AAC/E,MAAM,UAAU,SAAS,CAAC,IAAY;IACpC,OAAO,IAAI;SACR,KAAK,CAAC,OAAO,CAAC;SACd,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,gDAAgD,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC;SACvF,MAAM,CAAC,CAAC,IAAI,EAAkB,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;AACrD,CAAC;AAED,qHAAqH;AACrH,MAAM,UAAU,WAAW,CAAC,IAAY;IACtC,MAAM,WAAW,GAAG,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC5C,IAAI,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,WAAW;QAAE,OAAO,IAAI,CAAC;IAC9D,OAAO,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC;AAChD,CAAC;AAED,wEAAwE;AACxE,MAAM,UAAU,SAAS,CAAC,IAAY;IACpC,MAAM,QAAQ,GAAG,aAAa,CAAC,IAAI,CAAC,CAAC;IACrC,MAAM,IAAI,GAAe,EAAE,CAAC;IAC5B,MAAM,IAAI,GAAG,CAAC,GAAa,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAE/C,MAAM,OAAO,GAAG,WAAW,CAAC,QAAQ,EAAE,kIAAkI,CAAC,CAAC;IAC1K,IAAI,CAAC,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,EAAE,EAAE,CAAC;QAChD,IAAI,CAAC,EAAE,EAAE,EAAE,UAAU,EAAE,IAAI,EAAE,EAAE,EAAE,OAAO,EAAE,mDAAmD,EAAE,CAAC,CAAC;IACnG,CAAC;IAED,MAAM,QAAQ,GAAG,WAAW,CAAC,QAAQ,EAAE,oDAAoD,CAAC,CAAC;IAC7F,IAAI,CAAC,QAAQ,IAAI,QAAQ,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,EAAE,EAAE,CAAC;QAClD,IAAI,CAAC,EAAE,EAAE,EAAE,UAAU,EAAE,IAAI,EAAE,EAAE,EAAE,OAAO,EAAE,mCAAmC,EAAE,CAAC,CAAC;IACnF,CAAC;IAED,MAAM,YAAY,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,sEAAsE,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;IAChK,4EAA4E;IAC5E,MAAM,KAAK,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;IAC3E,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACrB,IAAI,CAAC,EAAE,EAAE,EAAE,YAAY,EAAE,IAAI,EAAE,EAAE,EAAE,OAAO,EAAE,gDAAgD,EAAE,CAAC,CAAC;IAClG,CAAC;SAAM,CAAC;QACN,MAAM,KAAK,GAAG,KAAK,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;QACxC,IAAI,KAAK,CAAC,MAAM,GAAG,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACpC,IAAI,CAAC;gBACH,EAAE,EAAE,kBAAkB;gBACtB,IAAI,EAAE,EAAE;gBACR,OAAO,EAAE,qBAAqB,KAAK,CAAC,MAAM,OAAO,KAAK,CAAC,MAAM,wDAAwD;aACtH,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAED,MAAM,QAAQ,GAAG,WAAW,CAAC,QAAQ,EAAE,qFAAqF,CAAC,CAAC;IAC9H,MAAM,SAAS,GAAG,QAAQ,CAAC,CAAC,CAAC,wEAAwE,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;IAClI,IAAI,CAAC,SAAS,EAAE,CAAC;QACf,IAAI,CAAC,EAAE,EAAE,EAAE,WAAW,EAAE,IAAI,EAAE,EAAE,EAAE,OAAO,EAAE,gEAAgE,EAAE,CAAC,CAAC;IACjH,CAAC;IAED,MAAM,UAAU,GAAG,WAAW,CAAC,QAAQ,EAAE,iEAAiE,CAAC,CAAC;IAC5G,IAAI,CAAC,UAAU,IAAI,UAAU,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,EAAE,EAAE,CAAC;QACtD,IAAI,CAAC,EAAE,EAAE,EAAE,cAAc,EAAE,IAAI,EAAE,EAAE,EAAE,OAAO,EAAE,4DAA4D,EAAE,CAAC,CAAC;IAChH,CAAC;IAED,IAAI,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,MAAM,GAAG,SAAS,EAAE,CAAC;QACzD,IAAI,CAAC,EAAE,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,EAAE,EAAE,OAAO,EAAE,SAAS,SAAS,2CAA2C,EAAE,CAAC,CAAC;IAC3G,CAAC;IAED,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,GAAG,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,CAAC,GAAG,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;IAC9E,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;AACzB,CAAC;AAED,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,IAAe,EAAW,EAAE,CAAC,IAAI,CAAC,KAAK,IAAI,eAAe,CAAC"}
@@ -0,0 +1,68 @@
1
+ // The prompt that asks Claude to draft the next round's brief. Pure and free of Node imports: the server streams the
2
+ // same prompt and the demo offers it as "Copy prompt for Claude Code".
3
+ import { listItems } from './brief.js';
4
+ const cell = (c) => c.replace(/\*\*|`/g, '').trim();
5
+ /** Audit table rows whose last cell says the finding is still open. */
6
+ export function extractOpenFindings(source, auditText) {
7
+ const out = [];
8
+ for (const line of auditText.split(/\r?\n/)) {
9
+ if (!line.startsWith('|') || /^\|[\s:|-]+\|?$/.test(line))
10
+ continue;
11
+ const cells = line.split('|').slice(1, -1).map(cell);
12
+ const last = cells.at(-1) ?? '';
13
+ if (cells.length >= 2 && /\bopen\b/i.test(last) && !/^fixed/i.test(last))
14
+ out.push({ source, text: cells.slice(0, -1).filter(Boolean).join(' · ').slice(0, 300) });
15
+ }
16
+ return out;
17
+ }
18
+ /** The list under the first "Out of scope" line of a brief (heading or bold label). */
19
+ export function extractOutOfScope(ideaText) {
20
+ const lines = ideaText.split(/\r?\n/);
21
+ const start = lines.findIndex((l) => /out of scope/i.test(l) && /^(#{1,6}\s|\s*\*\*)/.test(l));
22
+ if (start < 0)
23
+ return [];
24
+ const rest = lines.slice(start + 1);
25
+ const end = rest.findIndex((l) => /^#{1,6}\s|^---/.test(l));
26
+ return listItems((end < 0 ? rest : rest.slice(0, end)).join('\n'));
27
+ }
28
+ const bullets = (items) => (items.length ? items.map((i) => `- ${i}`).join('\n') : '(none)');
29
+ /** The prompt text. It states the brief format the linter scores, so the draft passes `loop next-round --brief`. */
30
+ export function buildDraftPrompt(input) {
31
+ const next = input.next.map((n) => `From ${n.source}:\n${bullets(n.items)}`).join('\n\n') || '(no DONE.md lists yet)';
32
+ const findings = bullets(input.findings.map((f) => `${f.source}: ${f.text}`));
33
+ const steer = input.steer.flatMap((s) => s.entries.map((e) => `- ${s.lane} (${e.scope}, ${e.author}): ${e.text.replace(/\s+/g, ' ')}`));
34
+ return `You are drafting the brief for round ${input.round} of ${input.name}, a repo built by unattended Claude Code lanes. Use only the inputs below; do not edit files or run commands. Answer with the brief as Markdown and nothing else.
35
+
36
+ ## Inputs
37
+
38
+ ### Next-improvement lists from the finished round
39
+ ${next}
40
+
41
+ ### Open audit findings
42
+ ${findings}
43
+
44
+ ### Steering notes not yet acted on
45
+ ${steer.length ? steer.join('\n') : '(none)'}
46
+
47
+ ### Out of scope in the previous brief (keep unless an input above says otherwise)
48
+ ${bullets(input.outOfScope)}
49
+
50
+ ## Format (an automated check scores it; below 60 it is refused)
51
+ - A heading "## Round ${input.round}: <version and a short name>".
52
+ - "**What we are building:**" and "**Audience:**" lead-ins, one or two sentences each.
53
+ - Must-haves as lettered sections ("### A. ...", "### B. ...") with numbered items. Each item names a path, a command or a number that a test can check. Put the highest-value work first and bugs before features.
54
+ - A "### Round ${input.round} done when" section whose bullets are commands or tests (for example \`npm test\` passes).
55
+ - "**Out of scope:**" with a bullet list.
56
+ - Fit what unattended lanes can finish in about three days. Drop inputs that do not fit and say nothing about them.
57
+ `;
58
+ }
59
+ /** Arguments for a read-only `claude -p` draft: no edits, no shell. The prompt is one argv entry. */
60
+ export function draftClaudeArgs(prompt, model) {
61
+ return ['-p', prompt, ...(model ? ['--model', model] : []), '--permission-mode', 'default', '--allowedTools', 'Read,Glob,Grep'];
62
+ }
63
+ /** The number of the round to draft: one above the highest `Round N` heading (2 when the brief has none, so it is round 1). */
64
+ export function nextRoundNumber(ideaText) {
65
+ const numbers = [...ideaText.matchAll(/^#{1,2}\s+Round\s+(\d+)\b/gim)].map((m) => Number(m[1]));
66
+ return Math.max(1, ...numbers) + 1;
67
+ }
68
+ //# sourceMappingURL=draftBrief.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"draftBrief.js","sourceRoot":"","sources":["../../src/core/draftBrief.ts"],"names":[],"mappings":"AAAA,qHAAqH;AACrH,uEAAuE;AACvE,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAiBvC,MAAM,IAAI,GAAG,CAAC,CAAS,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;AAE5D,uEAAuE;AACvE,MAAM,UAAU,mBAAmB,CAAC,MAAc,EAAE,SAAiB;IACnE,MAAM,GAAG,GAAuC,EAAE,CAAC;IACnD,KAAK,MAAM,IAAI,IAAI,SAAS,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC;QAC5C,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,iBAAiB,CAAC,IAAI,CAAC,IAAI,CAAC;YAAE,SAAS;QACpE,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACrD,MAAM,IAAI,GAAG,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QAChC,IAAI,KAAK,CAAC,MAAM,IAAI,CAAC,IAAI,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC;YAAE,GAAG,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC;IACrK,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,uFAAuF;AACvF,MAAM,UAAU,iBAAiB,CAAC,QAAgB;IAChD,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IACtC,MAAM,KAAK,GAAG,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,qBAAqB,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;IAC/F,IAAI,KAAK,GAAG,CAAC;QAAE,OAAO,EAAE,CAAC;IACzB,MAAM,IAAI,GAAG,KAAK,CAAC,KAAK,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC;IACpC,MAAM,GAAG,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,gBAAgB,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;IAC5D,OAAO,SAAS,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;AACrE,CAAC;AAED,MAAM,OAAO,GAAG,CAAC,KAAwB,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC;AAEhH,oHAAoH;AACpH,MAAM,UAAU,gBAAgB,CAAC,KAAkB;IACjD,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,QAAQ,CAAC,CAAC,MAAM,MAAM,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,wBAAwB,CAAC;IACtH,MAAM,QAAQ,GAAG,OAAO,CAAC,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;IAC9E,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,KAAK,KAAK,CAAC,CAAC,MAAM,MAAM,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC;IACxI,OAAO,wCAAwC,KAAK,CAAC,KAAK,OAAO,KAAK,CAAC,IAAI;;;;;EAK3E,IAAI;;;EAGJ,QAAQ;;;EAGR,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,QAAQ;;;EAG1C,OAAO,CAAC,KAAK,CAAC,UAAU,CAAC;;;wBAGH,KAAK,CAAC,KAAK;;;iBAGlB,KAAK,CAAC,KAAK;;;CAG3B,CAAC;AACF,CAAC;AAED,qGAAqG;AACrG,MAAM,UAAU,eAAe,CAAC,MAAc,EAAE,KAAc;IAC5D,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,mBAAmB,EAAE,SAAS,EAAE,gBAAgB,EAAE,gBAAgB,CAAC,CAAC;AAClI,CAAC;AAED,+HAA+H;AAC/H,MAAM,UAAU,eAAe,CAAC,QAAgB;IAC9C,MAAM,OAAO,GAAG,CAAC,GAAG,QAAQ,CAAC,QAAQ,CAAC,8BAA8B,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAChG,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;AACrC,CAAC"}
@@ -0,0 +1,123 @@
1
+ export const EVAL_ARMS = ['cold', 'recipe', 'recipe+triggers'];
2
+ export const MAX_TURNS = 30;
3
+ /** Edits and `node`/`npm test` only, inside the temp copy. */
4
+ export const EVAL_TOOLS = ['Read', 'Edit', 'Write', 'Glob', 'Grep', 'Bash(node:*)', 'Bash(npm test:*)', 'Bash(npm run:*)'];
5
+ const num = (v) => (typeof v === 'number' && Number.isFinite(v) && v >= 0 ? v : 0);
6
+ /** Reads the result object (a single JSON object, or the last `type: "result"` item of a JSON array). Throws with the reason when it is neither. */
7
+ export function parseClaudeJson(stdout) {
8
+ let raw;
9
+ try {
10
+ raw = JSON.parse(stdout);
11
+ }
12
+ catch {
13
+ throw new Error('claude did not print JSON. Is it a recent Claude Code run with --output-format json?');
14
+ }
15
+ const item = Array.isArray(raw) ? [...raw].reverse().find((x) => x && typeof x === 'object' && x.type === 'result') : raw;
16
+ if (!item || typeof item !== 'object')
17
+ throw new Error('claude printed JSON without a result object.');
18
+ const r = item;
19
+ const usage = (r.usage && typeof r.usage === 'object' ? r.usage : {});
20
+ return {
21
+ inputTokens: num(usage.input_tokens),
22
+ outputTokens: num(usage.output_tokens),
23
+ cacheReadTokens: num(usage.cache_read_input_tokens),
24
+ cacheCreationTokens: num(usage.cache_creation_input_tokens),
25
+ costUsd: num(r.total_cost_usd ?? r.cost_usd),
26
+ durationMs: num(r.duration_ms),
27
+ turns: num(r.num_turns),
28
+ isError: r.is_error === true || (typeof r.subtype === 'string' && r.subtype.startsWith('error')),
29
+ };
30
+ }
31
+ /** `claude -p` arguments for one run: JSON output, a turn cap and the restricted tool list. The prompt is one argv entry. */
32
+ export function evalClaudeArgs(prompt, model) {
33
+ return ['-p', prompt, '--output-format', 'json', '--max-turns', String(MAX_TURNS), '--allowedTools', EVAL_TOOLS.join(','), ...(model ? ['--model', model] : [])];
34
+ }
35
+ /** `evals/results/<YYYY-MM-DD>-<model>.jsonl`; the model is made filename-safe. */
36
+ export const resultsFile = (date, model) => `evals/results/${date}-${model.replace(/[^A-Za-z0-9._-]+/g, '-')}.jsonl`;
37
+ export const formatResult = (r) => `${JSON.stringify(r)}\n`;
38
+ const isArm = (v) => EVAL_ARMS.includes(v);
39
+ export function parseResults(text) {
40
+ const out = [];
41
+ for (const line of text.split(/\r?\n/)) {
42
+ try {
43
+ const r = JSON.parse(line);
44
+ if (typeof r.task !== 'string' || typeof r.model !== 'string' || !isArm(r.arm) || typeof r.pass !== 'boolean')
45
+ continue;
46
+ out.push({
47
+ at: typeof r.at === 'string' ? r.at : '', task: r.task, arm: r.arm, model: r.model, pass: r.pass,
48
+ inputTokens: num(r.inputTokens), outputTokens: num(r.outputTokens), cacheReadTokens: num(r.cacheReadTokens), cacheCreationTokens: num(r.cacheCreationTokens),
49
+ costUsd: num(r.costUsd), durationMs: num(r.durationMs), turns: num(r.turns),
50
+ });
51
+ }
52
+ catch {
53
+ // skip a broken line
54
+ }
55
+ }
56
+ return out;
57
+ }
58
+ export const totalTokens = (r) => r.inputTokens + r.outputTokens + r.cacheReadTokens + r.cacheCreationTokens;
59
+ export function median(values) {
60
+ const sorted = [...values].sort((a, b) => a - b);
61
+ const mid = Math.floor(sorted.length / 2);
62
+ if (sorted.length === 0)
63
+ return 0;
64
+ return sorted.length % 2 === 1 ? sorted[mid] : (sorted[mid - 1] + sorted[mid]) / 2;
65
+ }
66
+ /** One row per task × arm × model with medians over its runs, sorted by model, task, arm. */
67
+ export function evalRows(results) {
68
+ const groups = new Map();
69
+ for (const r of results) {
70
+ const key = `${r.task}\u0000${r.arm}\u0000${r.model}`;
71
+ groups.set(key, [...(groups.get(key) ?? []), r]);
72
+ }
73
+ return [...groups.values()]
74
+ .map((g) => ({
75
+ task: g[0].task,
76
+ arm: g[0].arm,
77
+ model: g[0].model,
78
+ runs: g.length,
79
+ passed: g.filter((r) => r.pass).length,
80
+ medianTokens: Math.round(median(g.map(totalTokens))),
81
+ medianSeconds: Math.round(median(g.map((r) => r.durationMs / 1000))),
82
+ medianTurns: median(g.map((r) => r.turns)),
83
+ }))
84
+ .sort((a, b) => a.model.localeCompare(b.model) || a.task.localeCompare(b.task) || a.arm.localeCompare(b.arm));
85
+ }
86
+ /**
87
+ * One sentence per model, built from the rows alone: "haiku: 3/3 with a recipe vs 1/3 cold, 58% fewer tokens".
88
+ * Needs a cold and a recipe arm for the model; otherwise there is no headline (a number is never invented).
89
+ */
90
+ export function evalHeadline(rows) {
91
+ const sentences = [];
92
+ for (const model of [...new Set(rows.map((r) => r.model))]) {
93
+ // Compare only tasks that have both a cold and a recipe arm on this model, never one task against another.
94
+ const tasksWith = (recipe) => new Set(rows.filter((r) => r.model === model && (r.arm !== 'cold') === recipe).map((r) => r.task));
95
+ const coldTasks = tasksWith(false);
96
+ const recipeTasks = tasksWith(true);
97
+ const sum = (recipe) => {
98
+ const own = rows.filter((r) => r.model === model && coldTasks.has(r.task) && recipeTasks.has(r.task) && (recipe ? r.arm !== 'cold' : r.arm === 'cold'));
99
+ return { runs: own.reduce((n, r) => n + r.runs, 0), passed: own.reduce((n, r) => n + r.passed, 0), tokens: own.reduce((n, r) => n + r.medianTokens * r.runs, 0) };
100
+ };
101
+ const cold = sum(false);
102
+ const recipe = sum(true);
103
+ if (cold.runs === 0 || recipe.runs === 0)
104
+ continue;
105
+ const saved = cold.tokens > 0 ? Math.round((1 - recipe.tokens / recipe.runs / (cold.tokens / cold.runs)) * 100) : 0;
106
+ sentences.push(`${model}: ${recipe.passed}/${recipe.runs} with a recipe vs ${cold.passed}/${cold.runs} cold${saved > 0 ? `, ${saved}% fewer tokens` : ''}`);
107
+ }
108
+ return sentences.length > 0 ? sentences.join('; ') : undefined;
109
+ }
110
+ export function buildEvalReport(results) {
111
+ const rows = evalRows(results);
112
+ const headline = evalHeadline(rows);
113
+ return { rows, ...(headline && { headline }) };
114
+ }
115
+ /** A plain-text table of the rows. */
116
+ export function formatEvalTable(rows) {
117
+ const head = ['task', 'arm', 'model', 'pass', 'tokens', 'time', 'turns'];
118
+ const body = rows.map((r) => [r.task, r.arm, r.model, `${r.passed}/${r.runs}`, String(r.medianTokens), `${r.medianSeconds}s`, String(r.medianTurns)]);
119
+ const widths = head.map((h, i) => Math.max(h.length, ...body.map((row) => row[i].length)));
120
+ const line = (cells) => cells.map((c, i) => c.padEnd(widths[i])).join(' ').trimEnd();
121
+ return [line(head), ...body.map(line)].join('\n');
122
+ }
123
+ //# sourceMappingURL=eval.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"eval.js","sourceRoot":"","sources":["../../src/core/eval.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,54 @@
1
+ // `loop init --hooks`: the starter triggers file and the project `.claude/settings.json` hooks (IDEA.md Round 6 B4). Pure.
2
+ export const SETTINGS_FILE = '.claude/settings.json';
3
+ export const HOOK_EVENTS = ['SessionStart', 'UserPromptSubmit', 'PreToolUse', 'PostToolUse', 'PostToolUseFailure'];
4
+ /** Built-in tools only: additionalContext is dropped for MCP and Agent tool calls. */
5
+ export const TOOL_MATCHER = 'Bash|Read|Edit|Write|Glob|Grep';
6
+ const TOOL_EVENTS = ['PreToolUse', 'PostToolUse', 'PostToolUseFailure'];
7
+ export const HOOK_TIMEOUT_SECONDS = 5;
8
+ export const STARTER_TRIGGERS = `# Triggers: a lesson that fires at the moment it matters (see .ai/method.md, C.5).
9
+ # Each entry: id, on (error | file | command | topic), match (text, /regex/ or a list), inject (text, or a path to a knowledge entry).
10
+ # A hook runs \`loop hook <event>\`; \`loop triggers stats\` shows how often each one fired.
11
+ # - id: K-0001
12
+ # on: error
13
+ # match: "fetch is not a function"
14
+ # inject: .ai/knowledge/K-0001.md
15
+ `;
16
+ const entryFor = (event, command) => ({
17
+ ...(TOOL_EVENTS.includes(event) && { matcher: TOOL_MATCHER }),
18
+ hooks: [{ type: 'command', command: `${command} ${event}`, timeout: HOOK_TIMEOUT_SECONDS }],
19
+ });
20
+ const isObject = (v) => typeof v === 'object' && v !== null && !Array.isArray(v);
21
+ const runsLoopHook = (group) => isObject(group) && Array.isArray(group.hooks) && group.hooks.some((h) => isObject(h) && typeof h.command === 'string' && /\bhook\s+\w+\s*$/.test(h.command) && /loop(\.js)?\s/.test(h.command));
22
+ /**
23
+ * Adds a `loop hook <event>` command for each of the five events to a settings.json text, keeping every other setting and hook.
24
+ * An event that already runs `loop hook` is left alone, so re-running changes nothing. `command` is `loop hook`-style, without the event.
25
+ */
26
+ export function mergeHookSettings(existing, command = 'loop hook') {
27
+ let settings = {};
28
+ if (existing !== undefined && existing.trim() !== '') {
29
+ try {
30
+ const parsed = JSON.parse(existing);
31
+ if (!isObject(parsed))
32
+ return { added: [], error: `${SETTINGS_FILE} must be a JSON object; fix or remove it, then re-run.` };
33
+ settings = parsed;
34
+ }
35
+ catch {
36
+ return { added: [], error: `${SETTINGS_FILE} is not valid JSON; fix or remove it, then re-run.` };
37
+ }
38
+ }
39
+ if (settings.hooks !== undefined && !isObject(settings.hooks))
40
+ return { added: [], error: `"hooks" in ${SETTINGS_FILE} must be an object; fix it, then re-run.` };
41
+ const hooks = { ...settings.hooks };
42
+ const added = [];
43
+ for (const event of HOOK_EVENTS) {
44
+ const groups = hooks[event];
45
+ if (groups !== undefined && !Array.isArray(groups))
46
+ return { added: [], error: `hooks.${event} in ${SETTINGS_FILE} must be a list; fix it, then re-run.` };
47
+ if (groups?.some(runsLoopHook))
48
+ continue;
49
+ hooks[event] = [...(groups ?? []), entryFor(event, command)];
50
+ added.push(event);
51
+ }
52
+ return { content: `${JSON.stringify({ ...settings, hooks }, null, 2)}\n`, added };
53
+ }
54
+ //# sourceMappingURL=hooksInit.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hooksInit.js","sourceRoot":"","sources":["../../src/core/hooksInit.ts"],"names":[],"mappings":"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"}