@howlil/ez-agents 3.1.0 → 3.4.2

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 (110) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +288 -718
  3. package/bin/install.js +438 -71
  4. package/commands/ez/auth.md +87 -0
  5. package/commands/ez/join-discord.md +18 -18
  6. package/ez-agents/bin/ez-tools.cjs +120 -2
  7. package/ez-agents/bin/lib/assistant-adapter.cjs +264 -205
  8. package/ez-agents/bin/lib/audit-exec.cjs +26 -9
  9. package/ez-agents/bin/lib/auth.cjs +2 -1
  10. package/ez-agents/bin/lib/circuit-breaker.cjs +118 -118
  11. package/ez-agents/bin/lib/commands.cjs +42 -23
  12. package/ez-agents/bin/lib/config.cjs +190 -183
  13. package/ez-agents/bin/lib/core.cjs +42 -25
  14. package/ez-agents/bin/lib/file-lock.cjs +236 -236
  15. package/ez-agents/bin/lib/frontmatter.cjs +299 -299
  16. package/ez-agents/bin/lib/fs-utils.cjs +153 -153
  17. package/ez-agents/bin/lib/git-utils.cjs +203 -203
  18. package/ez-agents/bin/lib/health-check.cjs +2 -3
  19. package/ez-agents/bin/lib/index.cjs +113 -113
  20. package/ez-agents/bin/lib/init.cjs +757 -710
  21. package/ez-agents/bin/lib/logger.cjs +52 -15
  22. package/ez-agents/bin/lib/milestone.cjs +241 -241
  23. package/ez-agents/bin/lib/model-provider.cjs +241 -146
  24. package/ez-agents/bin/lib/phase.cjs +925 -908
  25. package/ez-agents/bin/lib/planning-write.cjs +107 -0
  26. package/ez-agents/bin/lib/retry.cjs +119 -119
  27. package/ez-agents/bin/lib/roadmap.cjs +306 -305
  28. package/ez-agents/bin/lib/safe-exec.cjs +91 -5
  29. package/ez-agents/bin/lib/safe-path.cjs +130 -130
  30. package/ez-agents/bin/lib/state.cjs +736 -721
  31. package/ez-agents/bin/lib/temp-file.cjs +239 -239
  32. package/ez-agents/bin/lib/template.cjs +223 -222
  33. package/ez-agents/bin/lib/test-file-lock.cjs +112 -112
  34. package/ez-agents/bin/lib/test-graceful.cjs +93 -93
  35. package/ez-agents/bin/lib/test-logger.cjs +60 -60
  36. package/ez-agents/bin/lib/test-safe-exec.cjs +38 -38
  37. package/ez-agents/bin/lib/test-safe-path.cjs +33 -33
  38. package/ez-agents/bin/lib/test-temp-file.cjs +125 -125
  39. package/ez-agents/bin/lib/timeout-exec.cjs +63 -62
  40. package/ez-agents/bin/lib/verify.cjs +69 -26
  41. package/ez-agents/references/checkpoints.md +776 -776
  42. package/ez-agents/references/continuation-format.md +249 -249
  43. package/ez-agents/references/questioning.md +162 -162
  44. package/ez-agents/references/tdd.md +263 -263
  45. package/ez-agents/templates/codebase/concerns.md +310 -310
  46. package/ez-agents/templates/codebase/conventions.md +307 -307
  47. package/ez-agents/templates/codebase/integrations.md +280 -280
  48. package/ez-agents/templates/codebase/stack.md +186 -186
  49. package/ez-agents/templates/codebase/testing.md +480 -480
  50. package/ez-agents/templates/config.json +37 -37
  51. package/ez-agents/templates/continue-here.md +78 -78
  52. package/ez-agents/templates/milestone-archive.md +123 -123
  53. package/ez-agents/templates/milestone.md +115 -115
  54. package/ez-agents/templates/requirements.md +231 -231
  55. package/ez-agents/templates/research-project/ARCHITECTURE.md +204 -204
  56. package/ez-agents/templates/research-project/FEATURES.md +147 -147
  57. package/ez-agents/templates/research-project/PITFALLS.md +200 -200
  58. package/ez-agents/templates/research-project/STACK.md +120 -120
  59. package/ez-agents/templates/research-project/SUMMARY.md +170 -170
  60. package/ez-agents/templates/retrospective.md +54 -54
  61. package/ez-agents/templates/roadmap.md +202 -202
  62. package/ez-agents/templates/summary-minimal.md +41 -41
  63. package/ez-agents/templates/summary-standard.md +48 -48
  64. package/ez-agents/templates/summary.md +248 -248
  65. package/ez-agents/templates/user-setup.md +311 -311
  66. package/ez-agents/templates/verification-report.md +322 -322
  67. package/ez-agents/workflows/add-phase.md +112 -112
  68. package/ez-agents/workflows/add-tests.md +351 -351
  69. package/ez-agents/workflows/add-todo.md +158 -158
  70. package/ez-agents/workflows/audit-milestone.md +332 -332
  71. package/ez-agents/workflows/autonomous.md +743 -743
  72. package/ez-agents/workflows/check-todos.md +177 -177
  73. package/ez-agents/workflows/cleanup.md +152 -152
  74. package/ez-agents/workflows/complete-milestone.md +766 -766
  75. package/ez-agents/workflows/diagnose-issues.md +219 -219
  76. package/ez-agents/workflows/discovery-phase.md +289 -289
  77. package/ez-agents/workflows/discuss-phase.md +762 -762
  78. package/ez-agents/workflows/execute-phase.md +468 -468
  79. package/ez-agents/workflows/execute-plan.md +483 -483
  80. package/ez-agents/workflows/health.md +159 -159
  81. package/ez-agents/workflows/help.md +492 -492
  82. package/ez-agents/workflows/insert-phase.md +130 -130
  83. package/ez-agents/workflows/list-phase-assumptions.md +178 -178
  84. package/ez-agents/workflows/map-codebase.md +316 -316
  85. package/ez-agents/workflows/new-milestone.md +384 -384
  86. package/ez-agents/workflows/new-project.md +1113 -1111
  87. package/ez-agents/workflows/node-repair.md +92 -92
  88. package/ez-agents/workflows/pause-work.md +122 -122
  89. package/ez-agents/workflows/plan-milestone-gaps.md +274 -274
  90. package/ez-agents/workflows/plan-phase.md +651 -651
  91. package/ez-agents/workflows/progress.md +382 -382
  92. package/ez-agents/workflows/quick.md +610 -610
  93. package/ez-agents/workflows/remove-phase.md +155 -155
  94. package/ez-agents/workflows/research-phase.md +74 -74
  95. package/ez-agents/workflows/resume-project.md +307 -307
  96. package/ez-agents/workflows/set-profile.md +81 -81
  97. package/ez-agents/workflows/settings.md +242 -242
  98. package/ez-agents/workflows/stats.md +57 -57
  99. package/ez-agents/workflows/transition.md +544 -544
  100. package/ez-agents/workflows/ui-phase.md +290 -290
  101. package/ez-agents/workflows/ui-review.md +157 -157
  102. package/ez-agents/workflows/update.md +320 -320
  103. package/ez-agents/workflows/validate-phase.md +167 -167
  104. package/ez-agents/workflows/verify-phase.md +243 -243
  105. package/ez-agents/workflows/verify-work.md +584 -584
  106. package/package.json +2 -3
  107. package/scripts/build-hooks.js +43 -43
  108. package/scripts/fix-qwen-installation.js +144 -0
  109. package/scripts/run-tests.cjs +29 -29
  110. package/README.zh-CN.md +0 -702
@@ -7,8 +7,9 @@ const path = require('path');
7
7
  const { safeReadFile, normalizePhaseName, execGit, findPhaseInternal, getMilestoneInfo, output, error } = require('./core.cjs');
8
8
  const { extractFrontmatter, parseMustHavesBlock } = require('./frontmatter.cjs');
9
9
  const { writeStateMd } = require('./state.cjs');
10
+ const { defaultLogger: logger } = require('./logger.cjs');
10
11
 
11
- function cmdVerifySummary(cwd, summaryPath, checkFileCount, raw) {
12
+ async function cmdVerifySummary(cwd, summaryPath, checkFileCount, raw) {
12
13
  if (!summaryPath) {
13
14
  error('summary-path required');
14
15
  }
@@ -66,7 +67,7 @@ function cmdVerifySummary(cwd, summaryPath, checkFileCount, raw) {
66
67
  let commitsExist = false;
67
68
  if (hashes.length > 0) {
68
69
  for (const hash of hashes.slice(0, 3)) {
69
- const result = execGit(cwd, ['cat-file', '-t', hash]);
70
+ const result = await execGit(cwd, ['cat-file', '-t', hash]);
70
71
  if (result.exitCode === 0 && result.stdout === 'commit') {
71
72
  commitsExist = true;
72
73
  break;
@@ -179,7 +180,13 @@ function cmdVerifyPhaseCompleteness(cwd, phase, raw) {
179
180
 
180
181
  // List plans and summaries
181
182
  let files;
182
- try { files = fs.readdirSync(phaseDir); } catch { output({ error: 'Cannot read phase directory' }, raw); return; }
183
+ try {
184
+ files = fs.readdirSync(phaseDir);
185
+ } catch (err) {
186
+ logger.warn('Failed to read phase directory in cmdVerifyPhaseCompleteness', { phaseDir, error: err.message });
187
+ output({ error: 'Cannot read phase directory' }, raw);
188
+ return;
189
+ }
183
190
 
184
191
  const plans = files.filter(f => f.match(/-PLAN\.md$/i));
185
192
  const summaries = files.filter(f => f.match(/-SUMMARY\.md$/i));
@@ -257,17 +264,31 @@ function cmdVerifyReferences(cwd, filePath, raw) {
257
264
  }, raw, missing.length === 0 ? 'valid' : 'invalid');
258
265
  }
259
266
 
260
- function cmdVerifyCommits(cwd, hashes, raw) {
267
+ async function cmdVerifyCommits(cwd, hashes, raw) {
261
268
  if (!hashes || hashes.length === 0) { error('At least one commit hash required'); }
262
269
 
263
270
  const valid = [];
264
271
  const invalid = [];
265
272
  for (const hash of hashes) {
266
- const result = execGit(cwd, ['cat-file', '-t', hash]);
273
+ // Use git cat-file -t which supports both short and full hashes
274
+ // First try with the hash as-is (works for both short and full)
275
+ const result = await execGit(cwd, ['cat-file', '-t', hash]);
267
276
  if (result.exitCode === 0 && result.stdout.trim() === 'commit') {
268
277
  valid.push(hash);
269
278
  } else {
270
- invalid.push(hash);
279
+ // If that fails, try to resolve to full hash first
280
+ const resolveResult = await execGit(cwd, ['rev-parse', hash]);
281
+ if (resolveResult.exitCode === 0) {
282
+ const fullHash = resolveResult.stdout.trim();
283
+ const result2 = await execGit(cwd, ['cat-file', '-t', fullHash]);
284
+ if (result2.exitCode === 0 && result2.stdout.trim() === 'commit') {
285
+ valid.push(hash);
286
+ } else {
287
+ invalid.push(hash);
288
+ }
289
+ } else {
290
+ invalid.push(hash);
291
+ }
271
292
  }
272
293
  }
273
294
 
@@ -369,7 +390,8 @@ function cmdVerifyKeyLinks(cwd, planFilePath, raw) {
369
390
  check.detail = `Pattern "${link.pattern}" not found in source or target`;
370
391
  }
371
392
  }
372
- } catch {
393
+ } catch (err) {
394
+ logger.warn('Invalid regex while verifying key links', { pattern: link.pattern, error: err.message });
373
395
  check.detail = `Invalid regex pattern: ${link.pattern}`;
374
396
  }
375
397
  } else {
@@ -426,7 +448,9 @@ function cmdValidateConsistency(cwd, raw) {
426
448
  const dm = dir.match(/^(\d+[A-Z]?(?:\.\d+)*)/i);
427
449
  if (dm) diskPhases.add(dm[1]);
428
450
  }
429
- } catch {}
451
+ } catch (err) {
452
+ logger.warn('Failed to enumerate phase directories while validating consistency', { phasesDir, error: err.message });
453
+ }
430
454
 
431
455
  // Check: phases in ROADMAP but not on disk
432
456
  for (const p of roadmapPhases) {
@@ -488,7 +512,9 @@ function cmdValidateConsistency(cwd, raw) {
488
512
  }
489
513
  }
490
514
  }
491
- } catch {}
515
+ } catch (err) {
516
+ logger.warn('Failed to validate plan numbering while validating consistency', { phasesDir, error: err.message });
517
+ }
492
518
 
493
519
  // Check: frontmatter in plans has required fields
494
520
  try {
@@ -508,7 +534,9 @@ function cmdValidateConsistency(cwd, raw) {
508
534
  }
509
535
  }
510
536
  }
511
- } catch {}
537
+ } catch (err) {
538
+ logger.warn('Failed to validate plan frontmatter while validating consistency', { phasesDir, error: err.message });
539
+ }
512
540
 
513
541
  const passed = errors.length === 0;
514
542
  output({ passed, errors, warnings, warning_count: warnings.length }, raw, passed ? 'passed' : 'failed');
@@ -537,7 +565,7 @@ function cmdValidateHealth(cwd, options, raw) {
537
565
 
538
566
  // ─── Check 1: .planning/ exists ───────────────────────────────────────────
539
567
  if (!fs.existsSync(planningDir)) {
540
- addIssue('error', 'E001', '.planning/ directory not found', 'Run /gsd:new-project to initialize');
568
+ addIssue('error', 'E001', '.planning/ directory not found', 'Run /ez:new-project to initialize');
541
569
  output({
542
570
  status: 'broken',
543
571
  errors,
@@ -550,7 +578,7 @@ function cmdValidateHealth(cwd, options, raw) {
550
578
 
551
579
  // ─── Check 2: PROJECT.md exists and has required sections ─────────────────
552
580
  if (!fs.existsSync(projectPath)) {
553
- addIssue('error', 'E002', 'PROJECT.md not found', 'Run /gsd:new-project to create');
581
+ addIssue('error', 'E002', 'PROJECT.md not found', 'Run /ez:new-project to create');
554
582
  } else {
555
583
  const content = fs.readFileSync(projectPath, 'utf-8');
556
584
  const requiredSections = ['## What This Is', '## Core Value', '## Requirements'];
@@ -563,12 +591,12 @@ function cmdValidateHealth(cwd, options, raw) {
563
591
 
564
592
  // ─── Check 3: ROADMAP.md exists ───────────────────────────────────────────
565
593
  if (!fs.existsSync(roadmapPath)) {
566
- addIssue('error', 'E003', 'ROADMAP.md not found', 'Run /gsd:new-milestone to create roadmap');
594
+ addIssue('error', 'E003', 'ROADMAP.md not found', 'Run /ez:new-milestone to create roadmap');
567
595
  }
568
596
 
569
597
  // ─── Check 4: STATE.md exists and references valid phases ─────────────────
570
598
  if (!fs.existsSync(statePath)) {
571
- addIssue('error', 'E004', 'STATE.md not found', 'Run /gsd:health --repair to regenerate', true);
599
+ addIssue('error', 'E004', 'STATE.md not found', 'Run /ez:health --repair to regenerate', true);
572
600
  repairs.push('regenerateState');
573
601
  } else {
574
602
  const stateContent = fs.readFileSync(statePath, 'utf-8');
@@ -584,14 +612,16 @@ function cmdValidateHealth(cwd, options, raw) {
584
612
  if (m) diskPhases.add(m[1]);
585
613
  }
586
614
  }
587
- } catch {}
615
+ } catch (err) {
616
+ logger.warn('Failed to read phase directories while validating STATE references', { phasesDir, error: err.message });
617
+ }
588
618
  // Check for invalid references
589
619
  for (const ref of phaseRefs) {
590
620
  const normalizedRef = String(parseInt(ref, 10)).padStart(2, '0');
591
621
  if (!diskPhases.has(ref) && !diskPhases.has(normalizedRef) && !diskPhases.has(String(parseInt(ref, 10)))) {
592
622
  // Only warn if phases dir has any content (not just an empty project)
593
623
  if (diskPhases.size > 0) {
594
- addIssue('warning', 'W002', `STATE.md references phase ${ref}, but only phases ${[...diskPhases].sort().join(', ')} exist`, 'Run /gsd:health --repair to regenerate STATE.md', true);
624
+ addIssue('warning', 'W002', `STATE.md references phase ${ref}, but only phases ${[...diskPhases].sort().join(', ')} exist`, 'Run /ez:health --repair to regenerate STATE.md', true);
595
625
  if (!repairs.includes('regenerateState')) repairs.push('regenerateState');
596
626
  }
597
627
  }
@@ -600,7 +630,7 @@ function cmdValidateHealth(cwd, options, raw) {
600
630
 
601
631
  // ─── Check 5: config.json valid JSON + valid schema ───────────────────────
602
632
  if (!fs.existsSync(configPath)) {
603
- addIssue('warning', 'W003', 'config.json not found', 'Run /gsd:health --repair to create with defaults', true);
633
+ addIssue('warning', 'W003', 'config.json not found', 'Run /ez:health --repair to create with defaults', true);
604
634
  repairs.push('createConfig');
605
635
  } else {
606
636
  try {
@@ -612,7 +642,8 @@ function cmdValidateHealth(cwd, options, raw) {
612
642
  addIssue('warning', 'W004', `config.json: invalid model_profile "${parsed.model_profile}"`, `Valid values: ${validProfiles.join(', ')}`);
613
643
  }
614
644
  } catch (err) {
615
- addIssue('error', 'E005', `config.json: JSON parse error - ${err.message}`, 'Run /gsd:health --repair to reset to defaults', true);
645
+ logger.warn('Failed to parse config.json in cmdValidateHealth', { configPath, error: err.message });
646
+ addIssue('error', 'E005', `config.json: JSON parse error - ${err.message}`, 'Run /ez:health --repair to reset to defaults', true);
616
647
  repairs.push('resetConfig');
617
648
  }
618
649
  }
@@ -623,10 +654,12 @@ function cmdValidateHealth(cwd, options, raw) {
623
654
  const configRaw = fs.readFileSync(configPath, 'utf-8');
624
655
  const configParsed = JSON.parse(configRaw);
625
656
  if (configParsed.workflow && configParsed.workflow.nyquist_validation === undefined) {
626
- addIssue('warning', 'W008', 'config.json: workflow.nyquist_validation absent (defaults to enabled but agents may skip)', 'Run /gsd:health --repair to add key', true);
657
+ addIssue('warning', 'W008', 'config.json: workflow.nyquist_validation absent (defaults to enabled but agents may skip)', 'Run /ez:health --repair to add key', true);
627
658
  if (!repairs.includes('addNyquistKey')) repairs.push('addNyquistKey');
628
659
  }
629
- } catch {}
660
+ } catch (err) {
661
+ logger.warn('Failed to parse config for nyquist key check', { configPath, error: err.message });
662
+ }
630
663
  }
631
664
 
632
665
  // ─── Check 6: Phase directory naming (NN-name format) ─────────────────────
@@ -637,7 +670,9 @@ function cmdValidateHealth(cwd, options, raw) {
637
670
  addIssue('warning', 'W005', `Phase directory "${e.name}" doesn't follow NN-name format`, 'Rename to match pattern (e.g., 01-setup)');
638
671
  }
639
672
  }
640
- } catch {}
673
+ } catch (err) {
674
+ logger.warn('Failed to inspect phase directory naming in health validation', { phasesDir, error: err.message });
675
+ }
641
676
 
642
677
  // ─── Check 7: Orphaned plans (PLAN without SUMMARY) ───────────────────────
643
678
  try {
@@ -656,7 +691,9 @@ function cmdValidateHealth(cwd, options, raw) {
656
691
  }
657
692
  }
658
693
  }
659
- } catch {}
694
+ } catch (err) {
695
+ logger.warn('Failed to inspect orphaned plans in health validation', { phasesDir, error: err.message });
696
+ }
660
697
 
661
698
  // ─── Check 7b: Nyquist VALIDATION.md consistency ────────────────────────
662
699
  try {
@@ -670,11 +707,13 @@ function cmdValidateHealth(cwd, options, raw) {
670
707
  const researchFile = phaseFiles.find(f => f.endsWith('-RESEARCH.md'));
671
708
  const researchContent = fs.readFileSync(path.join(phasesDir, e.name, researchFile), 'utf-8');
672
709
  if (researchContent.includes('## Validation Architecture')) {
673
- addIssue('warning', 'W009', `Phase ${e.name}: has Validation Architecture in RESEARCH.md but no VALIDATION.md`, 'Re-run /gsd:plan-phase with --research to regenerate');
710
+ addIssue('warning', 'W009', `Phase ${e.name}: has Validation Architecture in RESEARCH.md but no VALIDATION.md`, 'Re-run /ez-plan-phase with --research to regenerate');
674
711
  }
675
712
  }
676
713
  }
677
- } catch {}
714
+ } catch (err) {
715
+ logger.warn('Failed to inspect validation architecture consistency in health validation', { phasesDir, error: err.message });
716
+ }
678
717
 
679
718
  // ─── Check 8: Run existing consistency checks ─────────────────────────────
680
719
  // Inline subset of cmdValidateConsistency
@@ -696,7 +735,9 @@ function cmdValidateHealth(cwd, options, raw) {
696
735
  if (dm) diskPhases.add(dm[1]);
697
736
  }
698
737
  }
699
- } catch {}
738
+ } catch (err) {
739
+ logger.warn('Failed to run roadmap/disk consistency checks in health validation', { roadmapPath, phasesDir, error: err.message });
740
+ }
700
741
 
701
742
  // Phases in ROADMAP but not on disk
702
743
  for (const p of roadmapPhases) {
@@ -755,7 +796,7 @@ function cmdValidateHealth(cwd, options, raw) {
755
796
  stateContent += `**Current phase:** (determining...)\n`;
756
797
  stateContent += `**Status:** Resuming\n\n`;
757
798
  stateContent += `## Session Log\n\n`;
758
- stateContent += `- ${new Date().toISOString().split('T')[0]}: STATE.md regenerated by /gsd:health --repair\n`;
799
+ stateContent += `- ${new Date().toISOString().split('T')[0]}: STATE.md regenerated by /ez:health --repair\n`;
759
800
  writeStateMd(statePath, stateContent, cwd);
760
801
  repairActions.push({ action: repair, success: true, path: 'STATE.md' });
761
802
  break;
@@ -772,6 +813,7 @@ function cmdValidateHealth(cwd, options, raw) {
772
813
  }
773
814
  repairActions.push({ action: repair, success: true, path: 'config.json' });
774
815
  } catch (err) {
816
+ logger.error('Failed to repair nyquist key', { error: err.message });
775
817
  repairActions.push({ action: repair, success: false, error: err.message });
776
818
  }
777
819
  }
@@ -779,6 +821,7 @@ function cmdValidateHealth(cwd, options, raw) {
779
821
  }
780
822
  }
781
823
  } catch (err) {
824
+ logger.error('Failed to perform repair action', { action: repair, error: err.message });
782
825
  repairActions.push({ action: repair, success: false, error: err.message });
783
826
  }
784
827
  }