agent-work-loop 0.6.36 → 0.6.43

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 (54) hide show
  1. package/dist/{brief-GQRHGJQN.js → brief-GOGJDLY7.js} +5 -5
  2. package/dist/{changelog-HZMH3RPD.js → changelog-NLYZTB44.js} +5 -5
  3. package/dist/{chunk-7TMAQRJS.js → chunk-7CPPZX6X.js} +1 -1
  4. package/dist/{chunk-FKBBGXGF.js → chunk-E6MULIMV.js} +5 -5
  5. package/dist/{chunk-NOU677FX.js → chunk-I3WXYD5C.js} +1 -1
  6. package/dist/{chunk-PFHPIVTO.js → chunk-I5SS6HFR.js} +49 -35
  7. package/dist/{chunk-CMIR4BRM.js → chunk-I5WWLNA6.js} +37 -9
  8. package/dist/{chunk-EEGOR4Y3.js → chunk-JQV65R3M.js} +5 -5
  9. package/dist/{chunk-7D4T7HFK.js → chunk-JR6MKCC4.js} +126 -6
  10. package/dist/{chunk-OJ7YO3MY.js → chunk-MBEY33YA.js} +2 -2
  11. package/dist/{chunk-QMECHIJW.js → chunk-OVLA5DET.js} +99 -21
  12. package/dist/{chunk-6F4VAVKF.js → chunk-QVP5DUND.js} +3 -3
  13. package/dist/{chunk-DNE7BN76.js → chunk-SKLSWS5J.js} +2 -2
  14. package/dist/{chunk-4ZLARTXS.js → chunk-SOUTYYY4.js} +47 -3
  15. package/dist/{chunk-AXES5NVJ.js → chunk-TQUXHTN5.js} +4 -4
  16. package/dist/{chunk-UNANHUG3.js → chunk-UJ6CK5HC.js} +2 -2
  17. package/dist/{chunk-SUF5ISJM.js → chunk-UNAASSQ4.js} +3 -1
  18. package/dist/{chunk-R4EH3WJE.js → chunk-YC23SNVC.js} +5 -5
  19. package/dist/cli.js +40 -40
  20. package/dist/{commit-SU6CTBU3.js → commit-BKN3ZJI7.js} +6 -6
  21. package/dist/{config-Z4G5SBWJ.js → config-DX3WL2JT.js} +9 -3
  22. package/dist/{doctor-UOOJSZBL.js → doctor-TBRNCTDS.js} +8 -8
  23. package/dist/{evolve-SQJ5LIE4.js → evolve-EMGWWWY3.js} +7 -7
  24. package/dist/{feedback-TPITVUZL.js → feedback-ZAAM5VYL.js} +5 -5
  25. package/dist/{gotchas-UEZG3HVO.js → gotchas-6ZWHP5Z6.js} +7 -7
  26. package/dist/{hold-recheck-NZ3OIG4W.js → hold-recheck-K7DV64KW.js} +16 -16
  27. package/dist/{init-AVVD77XM.js → init-3X6NVQQW.js} +2 -2
  28. package/dist/lane-QPZE7KYI.js +41 -0
  29. package/dist/{loop-summary-L4UTUOPY.js → loop-summary-CD6EIAHZ.js} +49 -7
  30. package/dist/{metrics-SOYVRSNM.js → metrics-VVXCH6TR.js} +4 -4
  31. package/dist/{record-V6V5XPPA.js → record-AC7LPU36.js} +5 -5
  32. package/dist/{remove-3XNAPKK6.js → remove-C64QRELY.js} +15 -15
  33. package/dist/{review-USI34ZYP.js → review-VCVPT3P6.js} +13 -13
  34. package/dist/{rules-ASJFXFGG.js → rules-2DIFP7K2.js} +8 -8
  35. package/dist/{state-6TNG2EC5.js → state-UIHEGC5P.js} +4 -4
  36. package/dist/status-2PUVZCFI.js +40 -0
  37. package/dist/{update-3AYB3V4I.js → update-KCQWDQDF.js} +2 -2
  38. package/dist/{verify-WXSV5HLL.js → verify-Y36JFAA7.js} +10 -10
  39. package/dist/version-check-XLXT7NSG.js +14 -0
  40. package/dist/{work-XHJFZIIL.js → work-HHTQTJZW.js} +14 -14
  41. package/engine/skills/claude/awl-loop/SKILL.md +16 -0
  42. package/engine/skills/claude/awl-loop/reference.md +4 -0
  43. package/engine/skills/claude/awl-pipeline/SKILL.md +93 -4
  44. package/engine/skills/claude/awl-pipeline/templates/README.md +44 -0
  45. package/engine/skills/claude/awl-pipeline/templates/watch-exec.sh +62 -0
  46. package/engine/skills/claude/awl-pipeline/templates/watch-inputs.sh +63 -0
  47. package/engine/skills/claude/awl-pipeline-exec/SKILL.md +58 -94
  48. package/engine/skills/claude/awl-pipeline-plan/SKILL.md +9 -3
  49. package/engine/skills/claude/awl-pipeline-review/SKILL.md +40 -71
  50. package/engine/version.json +1 -1
  51. package/package.json +1 -1
  52. package/dist/lane-65DSOYQ3.js +0 -41
  53. package/dist/status-M7KSA2KA.js +0 -40
  54. package/dist/version-check-JFXBDFFV.js +0 -14
@@ -6,12 +6,13 @@ import {
6
6
  closeFlow,
7
7
  detectVerify,
8
8
  langScreenLines,
9
+ listRegisteredProjects,
9
10
  openFlow,
10
11
  promptNumber,
11
12
  selectMulti,
12
13
  step,
13
14
  verifyStepLines
14
- } from "./chunk-7TMAQRJS.js";
15
+ } from "./chunk-7CPPZX6X.js";
15
16
  import {
16
17
  caps,
17
18
  findProjectRoot,
@@ -21,7 +22,7 @@ import {
21
22
  makeSymbols,
22
23
  sectionBox,
23
24
  signal
24
- } from "./chunk-SUF5ISJM.js";
25
+ } from "./chunk-UNAASSQ4.js";
25
26
 
26
27
  // src/commands/config.ts
27
28
  import fs from "fs";
@@ -120,6 +121,7 @@ function run(spec) {
120
121
  }
121
122
 
122
123
  // src/commands/config.ts
124
+ var DEFAULT_FEEDBACK_PATH = "/Users/kh1012/MIDAS/Research/agent-work-loop/.tasks/plan/";
123
125
  var VERIFY_ORDER = ["typecheck", "lint", "test", "e2e"];
124
126
  function resolveProjectRoot(cwd = process.cwd()) {
125
127
  try {
@@ -128,6 +130,29 @@ function resolveProjectRoot(cwd = process.cwd()) {
128
130
  return null;
129
131
  }
130
132
  }
133
+ function resolveProjectScope(cwd = process.cwd()) {
134
+ const root = resolveProjectRoot(cwd);
135
+ if (root) {
136
+ return { mode: "single", projectRoot: root };
137
+ }
138
+ const registered = listRegisteredProjects().filter((p) => fs.existsSync(p.path));
139
+ if (registered.length > 0) {
140
+ return { mode: "multi", projects: registered };
141
+ }
142
+ return { mode: "none" };
143
+ }
144
+ function multiProjectFooter(projects, exampleCmd, c) {
145
+ const color = makeColors(c.color);
146
+ const lines = [
147
+ "",
148
+ color.dim(
149
+ `\uD604\uC7AC \uC704\uCE58\uAC00 \uD2B9\uC815 \uD504\uB85C\uC81D\uD2B8\uC5D0 \uC18D\uD558\uC9C0 \uC54A\uC544 \uB4F1\uB85D\uB41C \uD504\uB85C\uC81D\uD2B8 ${projects.length}\uAC1C\uB97C \uBAA8\uB450 \uBCF4\uC5EC\uC90D\uB2C8\uB2E4.`
150
+ ),
151
+ color.dim("\uD2B9\uC815 \uD504\uB85C\uC81D\uD2B8\uB9CC \uBCF4\uB824\uBA74:"),
152
+ ...projects.map((p) => color.dim(` cd ${p.path} && ${exampleCmd}`))
153
+ ];
154
+ return lines.join("\n");
155
+ }
131
156
  function isVerifyEntry(v) {
132
157
  if (v === null) {
133
158
  return true;
@@ -173,6 +198,19 @@ function validateConfig(obj) {
173
198
  if ("protectedFiles" in o && (!Array.isArray(o.protectedFiles) || !o.protectedFiles.every((p) => typeof p === "string"))) {
174
199
  errors.push("protectedFiles \uD615\uC2DD \uC624\uB958 (\uBB38\uC790\uC5F4 \uBC30\uC5F4)");
175
200
  }
201
+ if ("feedback" in o && o.feedback !== void 0) {
202
+ if (typeof o.feedback !== "object" || o.feedback === null) {
203
+ errors.push("feedback \uD615\uC2DD \uC624\uB958 (\uAC1D\uCCB4 \uD544\uC218)");
204
+ } else {
205
+ const fb = o.feedback;
206
+ if (typeof fb.enabled !== "boolean") {
207
+ errors.push("feedback.enabled \uD615\uC2DD \uC624\uB958 (boolean \uD544\uC218)");
208
+ }
209
+ if ("path" in fb && fb.path !== void 0 && typeof fb.path !== "string") {
210
+ errors.push("feedback.path \uD615\uC2DD \uC624\uB958 (\uBB38\uC790\uC5F4)");
211
+ }
212
+ }
213
+ }
176
214
  return errors;
177
215
  }
178
216
  function jsonErrorLocation(text, err) {
@@ -219,6 +257,12 @@ function loadConfig(projectRoot) {
219
257
  ...typeof raw.namingConvention === "string" ? { namingConvention: raw.namingConvention } : {},
220
258
  ...typeof raw.relatedCmd === "string" ? { relatedCmd: raw.relatedCmd } : {},
221
259
  ...Array.isArray(raw.protectedFiles) ? { protectedFiles: raw.protectedFiles } : {},
260
+ ...typeof raw.feedback === "object" && raw.feedback !== null && typeof raw.feedback.enabled === "boolean" ? {
261
+ feedback: {
262
+ enabled: raw.feedback.enabled,
263
+ ...typeof raw.feedback.path === "string" ? { path: raw.feedback.path } : {}
264
+ }
265
+ } : {},
222
266
  verify: {
223
267
  typecheck: rv.typecheck ?? null,
224
268
  lint: rv.lint ?? null,
@@ -276,6 +320,8 @@ var SETTABLE_KEYS = [
276
320
  "namingConvention",
277
321
  "relatedCmd",
278
322
  "protectedFiles",
323
+ "feedback.enabled",
324
+ "feedback.path",
279
325
  ...VERIFY_ORDER.flatMap((n) => [`verify.${n}.cmd`, `verify.${n}.cwd`, `verify.${n}.env`])
280
326
  ];
281
327
  function parseConfigKey(key) {
@@ -295,6 +341,8 @@ function parseConfigKey(key) {
295
341
  return { kind: "relatedCmd" };
296
342
  }
297
343
  if (key === "protectedFiles") return { kind: "protectedFiles" };
344
+ if (key === "feedback.enabled") return { kind: "feedback.enabled" };
345
+ if (key === "feedback.path") return { kind: "feedback.path" };
298
346
  const names = VERIFY_ORDER.join("|");
299
347
  const cmdMatch = new RegExp(`^verify\\.(${names})(?:\\.cmd)?$`).exec(key);
300
348
  if (cmdMatch?.[1]) {
@@ -399,6 +447,35 @@ async function applyConfigValue(config, projectRoot, parsed, rawValue, opts) {
399
447
  config.protectedFiles = files;
400
448
  return { ok: true, message: `protectedFiles = ${files.join(", ") || "(\uBE44\uC6C0)"}` };
401
449
  }
450
+ if (parsed.kind === "feedback.enabled") {
451
+ const v2 = rawValue.trim().toLowerCase();
452
+ const truthy = ["true", "on", "1"];
453
+ const falsy = ["false", "off", "0"];
454
+ if (!truthy.includes(v2) && !falsy.includes(v2)) {
455
+ return {
456
+ ok: false,
457
+ message: `feedback.enabled \uB294 true/false(\uB610\uB294 on/off, 1/0)\uB9CC \uD5C8\uC6A9\uD569\uB2C8\uB2E4: '${rawValue}'`
458
+ };
459
+ }
460
+ const enabled = truthy.includes(v2);
461
+ config.feedback = { enabled, ...config.feedback?.path ? { path: config.feedback.path } : {} };
462
+ return { ok: true, message: `feedback.enabled = ${enabled}` };
463
+ }
464
+ if (parsed.kind === "feedback.path") {
465
+ const v2 = rawValue.trim();
466
+ if (v2 === "") {
467
+ if (config.feedback) {
468
+ config.feedback.path = void 0;
469
+ }
470
+ return {
471
+ ok: true,
472
+ message: `feedback.path = (\uBE44\uC6C0, \uAE30\uBCF8\uAC12 \uC0AC\uC6A9 \u2014 ${DEFAULT_FEEDBACK_PATH})`
473
+ };
474
+ }
475
+ const warn = path.isAbsolute(v2) ? "" : "\n\uCC38\uACE0: \uC0C1\uB300\uACBD\uB85C\uC785\uB2C8\uB2E4 \u2014 \uD504\uB85C\uC81D\uD2B8 \uB8E8\uD2B8 \uAE30\uC900\uC73C\uB85C \uD574\uC11D\uB429\uB2C8\uB2E4.";
476
+ config.feedback = { enabled: config.feedback?.enabled ?? false, path: v2 };
477
+ return { ok: true, message: `feedback.path = ${v2}${warn}` };
478
+ }
402
479
  const name = parsed.verifyName;
403
480
  if (parsed.kind === "verify.cmd") {
404
481
  const entry = parseVerifyValue(rawValue);
@@ -613,8 +690,27 @@ ${flowActiveNode("\uC218\uC815\uD560 \uD56D\uBAA9\uC744 \uACE0\uB974\uC138\uC694
613
690
  return true;
614
691
  }
615
692
  async function runConfig() {
616
- const projectRoot = resolveProjectRoot();
617
- if (!projectRoot) {
693
+ const scope = resolveProjectScope();
694
+ if (scope.mode === "multi" && scope.projects) {
695
+ const c2 = caps();
696
+ const blocks = scope.projects.map((p) => {
697
+ const color = makeColors(c2.color);
698
+ const loaded2 = loadConfig(p.path);
699
+ const header = color.bold(`\uD504\uB85C\uC81D\uD2B8: ${p.name} (${p.path})`);
700
+ if (!loaded2.config) {
701
+ return `${header}
702
+ ${signal(c2, "error")} config.json \uC5D0 \uBB38\uC81C\uAC00 \uC788\uC2B5\uB2C8\uB2E4: ${loaded2.errors.join(", ")}`;
703
+ }
704
+ return `${header}
705
+ ${renderConfig(loaded2.config, c2)}`;
706
+ });
707
+ process.stdout.write(`${blocks.join("\n\n")}
708
+ `);
709
+ process.stdout.write(`${multiProjectFooter(scope.projects, "awl config", c2)}
710
+ `);
711
+ return;
712
+ }
713
+ if (scope.mode === "none") {
618
714
  process.stderr.write(
619
715
  `
620
716
  ${signal(caps(), "error")} \uD504\uB85C\uC81D\uD2B8 \uB8E8\uD2B8\uB97C \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4. awl init \uC744 \uC2E4\uD589\uD558\uC138\uC694.
@@ -622,6 +718,7 @@ async function runConfig() {
622
718
  );
623
719
  process.exit(1);
624
720
  }
721
+ const projectRoot = scope.projectRoot;
625
722
  const loaded = loadConfig(projectRoot);
626
723
  if (!loaded.config) {
627
724
  process.stderr.write(`
@@ -660,6 +757,9 @@ function renderSettableKeys(config, c) {
660
757
  if (key === "project") return config.project;
661
758
  if (key === "mainLanguage") return config.mainLanguage.join(", ") || "(\uC5C6\uC74C)";
662
759
  if (key === "character") return config.character || "(\uC5C6\uC74C)";
760
+ if (key === "feedback.enabled") return String(config.feedback?.enabled ?? false);
761
+ if (key === "feedback.path")
762
+ return config.feedback?.path || `(\uAE30\uBCF8\uAC12) ${DEFAULT_FEEDBACK_PATH}`;
663
763
  const m = /^verify\.(typecheck|lint|test|e2e)\.(cmd|cwd|env)$/.exec(key);
664
764
  if (!m?.[1] || !m[2]) return "";
665
765
  const entry = config.verify[m[1]];
@@ -678,8 +778,24 @@ function renderSettableKeys(config, c) {
678
778
  return out.join("\n");
679
779
  }
680
780
  async function runConfigSet(key, value, opts) {
681
- const projectRoot = resolveProjectRoot();
682
- if (!projectRoot) {
781
+ const scope = resolveProjectScope();
782
+ if (scope.mode === "multi" && scope.projects) {
783
+ const c = caps();
784
+ process.stdout.write(
785
+ `
786
+ ${signal(c, "warn")} \uD604\uC7AC \uC704\uCE58\uAC00 \uD2B9\uC815 \uD504\uB85C\uC81D\uD2B8\uC5D0 \uC18D\uD558\uC9C0 \uC54A\uC544 \uC5B4\uB290 \uD504\uB85C\uC81D\uD2B8\uB97C \uBC14\uAFC0\uC9C0 \uC54C \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.
787
+ `
788
+ );
789
+ process.stdout.write(" \uD574\uB2F9 \uD504\uB85C\uC81D\uD2B8\uB85C \uC774\uB3D9\uD55C \uB4A4 \uB2E4\uC2DC \uC2E4\uD589\uD558\uC138\uC694:\n");
790
+ for (const p of scope.projects) {
791
+ process.stdout.write(
792
+ ` cd ${p.path} && awl config set${key ? ` ${key}` : ""}${value ? ` ${value}` : ""}
793
+ `
794
+ );
795
+ }
796
+ return;
797
+ }
798
+ if (scope.mode === "none") {
683
799
  process.stderr.write(
684
800
  `
685
801
  ${signal(caps(), "error")} \uD504\uB85C\uC81D\uD2B8 \uB8E8\uD2B8\uB97C \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4. awl init \uC744 \uC2E4\uD589\uD558\uC138\uC694.
@@ -687,6 +803,7 @@ async function runConfigSet(key, value, opts) {
687
803
  );
688
804
  process.exit(1);
689
805
  }
806
+ const projectRoot = scope.projectRoot;
690
807
  const loaded = loadConfig(projectRoot);
691
808
  if (!loaded.config) {
692
809
  process.stderr.write(
@@ -747,8 +864,11 @@ export {
747
864
  CommandNotFoundError,
748
865
  tokenize,
749
866
  run,
867
+ DEFAULT_FEEDBACK_PATH,
750
868
  VERIFY_ORDER,
751
869
  resolveProjectRoot,
870
+ resolveProjectScope,
871
+ multiProjectFooter,
752
872
  validateConfig,
753
873
  loadConfig,
754
874
  requireConfig,
@@ -2,14 +2,14 @@ import {
2
2
  acquireLock,
3
3
  loadGotchaList,
4
4
  releaseLock
5
- } from "./chunk-FKBBGXGF.js";
5
+ } from "./chunk-E6MULIMV.js";
6
6
  import {
7
7
  caps,
8
8
  makeColors,
9
9
  rulesDir,
10
10
  sectionBox,
11
11
  signal
12
- } from "./chunk-SUF5ISJM.js";
12
+ } from "./chunk-UNAASSQ4.js";
13
13
 
14
14
  // src/commands/rules.ts
15
15
  import { spawnSync } from "child_process";
@@ -1,16 +1,17 @@
1
1
  import {
2
2
  WORKTREES_DIR
3
- } from "./chunk-EEGOR4Y3.js";
3
+ } from "./chunk-JQV65R3M.js";
4
4
  import {
5
5
  readRecords
6
- } from "./chunk-6F4VAVKF.js";
6
+ } from "./chunk-QVP5DUND.js";
7
7
  import {
8
8
  loadState
9
- } from "./chunk-UNANHUG3.js";
9
+ } from "./chunk-UJ6CK5HC.js";
10
10
  import {
11
- resolveProjectRoot,
11
+ multiProjectFooter,
12
+ resolveProjectScope,
12
13
  run
13
- } from "./chunk-7D4T7HFK.js";
14
+ } from "./chunk-JR6MKCC4.js";
14
15
  import {
15
16
  caps,
16
17
  makeColors,
@@ -21,7 +22,7 @@ import {
21
22
  signal,
22
23
  statusBadge,
23
24
  stringWidth
24
- } from "./chunk-SUF5ISJM.js";
25
+ } from "./chunk-UNAASSQ4.js";
25
26
 
26
27
  // src/commands/status.ts
27
28
  import fs2 from "fs";
@@ -300,28 +301,32 @@ function pipelineLanes(planFiles, execFiles, reviewFiles) {
300
301
  }
301
302
  const lanes = [];
302
303
  for (const name of names) {
304
+ const reviewPending = reviewFiles.includes(`${name}.md`);
305
+ const held = planFiles.includes(`${name}.hold.md`);
306
+ const execVerified = execFiles.includes(`${name}.taken.md`);
307
+ const execHandedOff = execFiles.includes(`${name}.md`);
308
+ const claimed = planFiles.includes(`${name}.taken.md`);
303
309
  let status;
304
- if (reviewFiles.includes(`${name}.md`)) {
310
+ if (reviewPending) {
305
311
  status = "blocked";
306
- } else if (planFiles.includes(`${name}.hold.md`)) {
312
+ } else if (held) {
307
313
  status = "blocked";
308
- } else if (execFiles.includes(`${name}.taken.md`)) {
314
+ } else if (execVerified) {
309
315
  status = "complete";
310
- } else if (execFiles.includes(`${name}.md`)) {
316
+ } else if (execHandedOff) {
311
317
  status = "reviewing";
312
- } else if (planFiles.includes(`${name}.taken.md`)) {
318
+ } else if (claimed) {
313
319
  status = "executing";
314
320
  } else {
315
321
  status = "pending";
316
322
  }
317
- lanes.push({ name, status });
323
+ const execState = execVerified ? "verified" : execHandedOff ? "handed_off" : claimed ? "in_progress" : "pending";
324
+ const reviewState = reviewPending ? "changes_requested" : execVerified ? "passed" : "waiting";
325
+ lanes.push({ name, status, execState, reviewState });
318
326
  }
319
327
  lanes.sort((a, b) => a.name.localeCompare(b.name));
320
328
  return lanes;
321
329
  }
322
- function nameColWidth(names) {
323
- return Math.max(...names.map(stringWidth), 4) + 2;
324
- }
325
330
  function readDirNames(dir) {
326
331
  try {
327
332
  return fs2.readdirSync(dir);
@@ -364,11 +369,30 @@ function mainTreeGroup(root) {
364
369
  )
365
370
  };
366
371
  }
372
+ function tableColWidth(header, values) {
373
+ return Math.max(stringWidth(header), ...values.map(stringWidth));
374
+ }
367
375
  function renderPipelineGroups(groups, c) {
368
376
  const color = makeColors(c.color);
369
- const allNames = groups.flatMap((g) => g.workitems.map((w) => w.name));
370
- const nameWidth = nameColWidth(allNames);
371
- const out = [];
377
+ const all = groups.flatMap((g) => g.workitems);
378
+ const nameWidth = Math.max(
379
+ tableColWidth(
380
+ "\uC6CC\uD06C\uC544\uC774\uD15C",
381
+ all.map((w) => w.name)
382
+ ),
383
+ 4
384
+ );
385
+ const execWidth = tableColWidth(
386
+ "EXEC",
387
+ all.map((w) => w.execState)
388
+ );
389
+ const reviewWidth = tableColWidth(
390
+ "REVIEW",
391
+ all.map((w) => w.reviewState)
392
+ );
393
+ const out = [
394
+ ` ${padEndDisplay("\uC6CC\uD06C\uC544\uC774\uD15C", nameWidth)} ${padEndDisplay("EXEC", execWidth)} ${padEndDisplay("REVIEW", reviewWidth)} \uC0C1\uD0DC`
395
+ ];
372
396
  groups.forEach((g, i) => {
373
397
  if (i > 0) {
374
398
  out.push("");
@@ -379,14 +403,67 @@ function renderPipelineGroups(groups, c) {
379
403
  return;
380
404
  }
381
405
  for (const w of g.workitems) {
382
- out.push(` ${statusBadge(c, w.status)} ${padEndDisplay(w.name, nameWidth)}${w.status}`);
406
+ out.push(
407
+ ` ${padEndDisplay(w.name, nameWidth)} ${padEndDisplay(w.execState, execWidth)} ${padEndDisplay(w.reviewState, reviewWidth)} ${statusBadge(c, w.status)} ${w.status}`
408
+ );
383
409
  }
384
410
  });
385
411
  return sectionBox(`\uD30C\uC774\uD504\uB77C\uC778 ${groups.length}\uAC1C \uB808\uC778`, out, c);
386
412
  }
387
413
  async function runStatus(opts) {
388
- const root = resolveProjectRoot();
389
- if (!root) {
414
+ const scope = resolveProjectScope();
415
+ if (scope.mode === "multi" && scope.projects) {
416
+ const cc = caps();
417
+ const color = makeColors(cc.color);
418
+ if (opts.pipeline === true && opts.archive === true) {
419
+ process.stdout.write(
420
+ ` ${signal(cc, "warn")} --archive \uB294 \uC5EC\uB7EC \uD504\uB85C\uC81D\uD2B8\uC5D0 \uAC78\uCCD0 \uC2E4\uD589\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4. \uD574\uB2F9 \uD504\uB85C\uC81D\uD2B8\uB85C \uC774\uB3D9\uD55C \uB4A4 \uC2E4\uD589\uD558\uC138\uC694.
421
+
422
+ `
423
+ );
424
+ }
425
+ if (opts.json) {
426
+ const projects = await Promise.all(
427
+ scope.projects.map(async (p) => {
428
+ if (opts.pipeline === true) {
429
+ return {
430
+ name: p.name,
431
+ path: p.path,
432
+ lanes: [mainTreeGroup(p.path), ...collectPipelineLaneGroups(p.path)]
433
+ };
434
+ }
435
+ const report2 = {
436
+ ...buildStatus(p.path),
437
+ missingAcCommits: await checkMissingAcCommits(p.path)
438
+ };
439
+ return { name: p.name, path: p.path, ...report2 };
440
+ })
441
+ );
442
+ process.stdout.write(`${JSON.stringify({ multiProject: true, projects }, null, 2)}
443
+ `);
444
+ return;
445
+ }
446
+ const blocks = [];
447
+ for (const p of scope.projects) {
448
+ blocks.push(color.bold(`\uD504\uB85C\uC81D\uD2B8: ${p.name} (${p.path})`));
449
+ if (opts.pipeline === true) {
450
+ const groups = [mainTreeGroup(p.path), ...collectPipelineLaneGroups(p.path)];
451
+ blocks.push(renderPipelineGroups(groups, cc));
452
+ } else {
453
+ const report2 = {
454
+ ...buildStatus(p.path),
455
+ missingAcCommits: await checkMissingAcCommits(p.path)
456
+ };
457
+ blocks.push(renderStatus(report2, cc));
458
+ }
459
+ }
460
+ process.stdout.write(`${blocks.join("\n\n")}
461
+ `);
462
+ process.stdout.write(`${multiProjectFooter(scope.projects, "awl status", cc)}
463
+ `);
464
+ return;
465
+ }
466
+ if (scope.mode === "none") {
390
467
  const cc = caps();
391
468
  process.stderr.write(
392
469
  `
@@ -396,6 +473,7 @@ async function runStatus(opts) {
396
473
  );
397
474
  process.exit(1);
398
475
  }
476
+ const root = scope.projectRoot;
399
477
  if (opts.pipeline === true) {
400
478
  let archived;
401
479
  if (opts.archive === true) {
@@ -2,18 +2,18 @@ import {
2
2
  getCriterion,
3
3
  loadState,
4
4
  writeState
5
- } from "./chunk-UNANHUG3.js";
5
+ } from "./chunk-UJ6CK5HC.js";
6
6
  import {
7
7
  resolveProjectRoot,
8
8
  run
9
- } from "./chunk-7D4T7HFK.js";
9
+ } from "./chunk-JR6MKCC4.js";
10
10
  import {
11
11
  caps,
12
12
  makeColors,
13
13
  recordsDir,
14
14
  sectionBox,
15
15
  signal
16
- } from "./chunk-SUF5ISJM.js";
16
+ } from "./chunk-UNAASSQ4.js";
17
17
 
18
18
  // src/commands/record.ts
19
19
  import crypto from "crypto";
@@ -1,10 +1,10 @@
1
1
  import {
2
2
  npmVersionCachePath
3
- } from "./chunk-SUF5ISJM.js";
3
+ } from "./chunk-UNAASSQ4.js";
4
4
 
5
5
  // package.json
6
6
  var name = "agent-work-loop";
7
- var version = "0.6.36";
7
+ var version = "0.6.43";
8
8
 
9
9
  // src/core/npm-registry.ts
10
10
  import fs from "fs";
@@ -1,6 +1,9 @@
1
1
  import {
2
- requireConfig
3
- } from "./chunk-7D4T7HFK.js";
2
+ loadConfig,
3
+ multiProjectFooter,
4
+ requireConfig,
5
+ resolveProjectScope
6
+ } from "./chunk-JR6MKCC4.js";
4
7
  import {
5
8
  caps,
6
9
  generationsDir,
@@ -8,7 +11,7 @@ import {
8
11
  padEndDisplay,
9
12
  sectionBox,
10
13
  stringWidth
11
- } from "./chunk-SUF5ISJM.js";
14
+ } from "./chunk-UNAASSQ4.js";
12
15
 
13
16
  // src/commands/metrics.ts
14
17
  import fs from "fs";
@@ -169,6 +172,47 @@ function renderCompare(groups, untagged, c) {
169
172
  return sectionBox(`\uCF00\uC774\uC2A4 ${groups.length}\uAC1C \uBE44\uAD50`, out, c);
170
173
  }
171
174
  function runMetrics(opts) {
175
+ const scope = resolveProjectScope();
176
+ if (scope.mode === "multi" && scope.projects) {
177
+ const c = caps();
178
+ const color = makeColors(c.color);
179
+ const perProject = scope.projects.map((p) => {
180
+ const loaded = loadConfig(p.path);
181
+ const generations2 = loaded.config ? loadGenerations(loaded.config.project) : [];
182
+ return { name: p.name, path: p.path, generations: generations2 };
183
+ });
184
+ if (opts.json) {
185
+ const projects = perProject.map(({ name, path: path2, generations: generations2 }) => {
186
+ if (opts.compare === true) {
187
+ const groups = groupByExperiment(generations2);
188
+ const untagged = generations2.filter((g) => g.experiment === void 0).length;
189
+ return { name, path: path2, cases: groups, untagged };
190
+ }
191
+ return { name, path: path2, generations: generations2 };
192
+ });
193
+ process.stdout.write(
194
+ `${JSON.stringify({ multiProject: true, caveat: renderMetricsCaveat(), projects }, null, 2)}
195
+ `
196
+ );
197
+ return;
198
+ }
199
+ const blocks = perProject.map(({ name, path: path2, generations: generations2 }) => {
200
+ const header = color.bold(`\uD504\uB85C\uC81D\uD2B8: ${name} (${path2})`);
201
+ if (opts.compare === true) {
202
+ const groups = groupByExperiment(generations2);
203
+ const untagged = generations2.filter((g) => g.experiment === void 0).length;
204
+ return `${header}
205
+ ${renderCompare(groups, untagged, c)}`;
206
+ }
207
+ return `${header}
208
+ ${renderMetrics(generations2, c)}`;
209
+ });
210
+ process.stdout.write(`${blocks.join("\n\n")}
211
+ `);
212
+ process.stdout.write(`${multiProjectFooter(scope.projects, "awl metrics", c)}
213
+ `);
214
+ return;
215
+ }
172
216
  const { config } = requireConfig();
173
217
  const generations = loadGenerations(config.project);
174
218
  if (opts.compare === true) {
@@ -3,14 +3,14 @@ import {
3
3
  getLatestVersionCached,
4
4
  name,
5
5
  version
6
- } from "./chunk-DNE7BN76.js";
6
+ } from "./chunk-SKLSWS5J.js";
7
7
  import {
8
8
  resolveProjectRoot
9
- } from "./chunk-7D4T7HFK.js";
9
+ } from "./chunk-JR6MKCC4.js";
10
10
  import {
11
11
  packageEngineDir,
12
12
  skillsVersionPath
13
- } from "./chunk-7TMAQRJS.js";
13
+ } from "./chunk-7CPPZX6X.js";
14
14
  import {
15
15
  caps,
16
16
  installedEngineVersion,
@@ -19,7 +19,7 @@ import {
19
19
  makeTokens,
20
20
  sectionBox,
21
21
  signal
22
- } from "./chunk-SUF5ISJM.js";
22
+ } from "./chunk-UNAASSQ4.js";
23
23
 
24
24
  // src/commands/version-check.ts
25
25
  import fs from "fs";
@@ -1,11 +1,11 @@
1
1
  import {
2
2
  resolveProjectRoot
3
- } from "./chunk-7D4T7HFK.js";
3
+ } from "./chunk-JR6MKCC4.js";
4
4
  import {
5
5
  caps,
6
6
  makeColors,
7
7
  sectionBox
8
- } from "./chunk-SUF5ISJM.js";
8
+ } from "./chunk-UNAASSQ4.js";
9
9
 
10
10
  // src/commands/state.ts
11
11
  import fs from "fs";
@@ -41,8 +41,10 @@ function npmVersionCachePath() {
41
41
  }
42
42
  function findProjectRoot(cwd = process.cwd()) {
43
43
  let dir = path.resolve(cwd);
44
+ const global = globalRoot();
44
45
  for (; ; ) {
45
- if (fs.existsSync(path.join(dir, ".git")) || fs.existsSync(path.join(dir, ".awl"))) {
46
+ const awlPath = path.join(dir, ".awl");
47
+ if (fs.existsSync(path.join(dir, ".git")) || awlPath !== global && fs.existsSync(awlPath)) {
46
48
  return dir;
47
49
  }
48
50
  const parent = path.dirname(dir);
@@ -1,26 +1,26 @@
1
1
  import {
2
2
  protectedFilesMessage
3
- } from "./chunk-NOU677FX.js";
3
+ } from "./chunk-I3WXYD5C.js";
4
4
  import {
5
5
  gitDirtyFiles
6
- } from "./chunk-PFHPIVTO.js";
6
+ } from "./chunk-I5SS6HFR.js";
7
7
  import {
8
8
  applyVerificationAttempts,
9
9
  loadState,
10
10
  writeState
11
- } from "./chunk-UNANHUG3.js";
11
+ } from "./chunk-UJ6CK5HC.js";
12
12
  import {
13
13
  CommandNotFoundError,
14
14
  VERIFY_ORDER,
15
15
  requireConfig,
16
16
  run
17
- } from "./chunk-7D4T7HFK.js";
17
+ } from "./chunk-JR6MKCC4.js";
18
18
  import {
19
19
  caps,
20
20
  makeColors,
21
21
  sectionBox,
22
22
  signal
23
- } from "./chunk-SUF5ISJM.js";
23
+ } from "./chunk-UNAASSQ4.js";
24
24
 
25
25
  // src/commands/verify.ts
26
26
  import fs from "fs";