@howlil/ez-agents 2.0.1 → 3.0.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 (140) hide show
  1. package/README.md +72 -25
  2. package/README.zh-CN.md +84 -84
  3. package/agents/ez-ui-auditor.md +0 -2
  4. package/agents/ez-ui-checker.md +2 -4
  5. package/agents/ez-ui-researcher.md +0 -2
  6. package/bin/install.js +84 -84
  7. package/commands/ez/debug.md +1 -1
  8. package/commands/ez/map-codebase.md +1 -1
  9. package/commands/ez/reapply-patches.md +3 -3
  10. package/commands/ez/research-phase.md +1 -1
  11. package/{get-shit-done → ez-agents}/bin/ez-tools.cjs +1 -1
  12. package/{get-shit-done → ez-agents}/bin/lib/auth.cjs +2 -2
  13. package/{get-shit-done → ez-agents}/bin/lib/core.cjs +16 -16
  14. package/{get-shit-done → ez-agents}/bin/lib/init.cjs +20 -20
  15. package/{get-shit-done → ez-agents}/bin/lib/logger.cjs +2 -2
  16. package/{get-shit-done → ez-agents}/bin/lib/temp-file.cjs +2 -2
  17. package/{get-shit-done → ez-agents}/bin/lib/test-file-lock.cjs +1 -1
  18. package/{get-shit-done → ez-agents}/bin/lib/test-graceful.cjs +1 -1
  19. package/{get-shit-done → ez-agents}/bin/lib/test-logger.cjs +1 -1
  20. package/{get-shit-done → ez-agents}/bin/lib/test-temp-file.cjs +2 -2
  21. package/{get-shit-done → ez-agents}/workflows/add-phase.md +2 -2
  22. package/{get-shit-done → ez-agents}/workflows/audit-milestone.md +1 -1
  23. package/{get-shit-done → ez-agents}/workflows/complete-milestone.md +3 -3
  24. package/ez-agents/workflows/debug.md +0 -0
  25. package/{get-shit-done → ez-agents}/workflows/discovery-phase.md +5 -5
  26. package/{get-shit-done → ez-agents}/workflows/discuss-phase.md +2 -2
  27. package/{get-shit-done → ez-agents}/workflows/execute-phase.md +5 -5
  28. package/{get-shit-done → ez-agents}/workflows/execute-plan.md +10 -10
  29. package/{get-shit-done → ez-agents}/workflows/help.md +9 -9
  30. package/{get-shit-done → ez-agents}/workflows/insert-phase.md +2 -2
  31. package/{get-shit-done → ez-agents}/workflows/map-codebase.md +3 -3
  32. package/{get-shit-done → ez-agents}/workflows/new-milestone.md +4 -4
  33. package/{get-shit-done → ez-agents}/workflows/new-project.md +8 -8
  34. package/{get-shit-done → ez-agents}/workflows/plan-phase.md +9 -9
  35. package/{get-shit-done → ez-agents}/workflows/progress.md +2 -2
  36. package/{get-shit-done → ez-agents}/workflows/quick.md +10 -10
  37. package/{get-shit-done → ez-agents}/workflows/remove-phase.md +4 -4
  38. package/{get-shit-done → ez-agents}/workflows/research-phase.md +4 -4
  39. package/{get-shit-done → ez-agents}/workflows/resume-project.md +1 -1
  40. package/{get-shit-done → ez-agents}/workflows/set-profile.md +3 -3
  41. package/{get-shit-done → ez-agents}/workflows/transition.md +3 -3
  42. package/{get-shit-done → ez-agents}/workflows/ui-phase.md +12 -12
  43. package/{get-shit-done → ez-agents}/workflows/ui-review.md +6 -6
  44. package/{get-shit-done → ez-agents}/workflows/update.md +29 -29
  45. package/{get-shit-done → ez-agents}/workflows/validate-phase.md +5 -5
  46. package/{get-shit-done → ez-agents}/workflows/verify-phase.md +6 -6
  47. package/{get-shit-done → ez-agents}/workflows/verify-work.md +5 -5
  48. package/hooks/dist/ez-check-update.js +81 -0
  49. package/hooks/dist/ez-context-monitor.js +141 -0
  50. package/hooks/dist/ez-statusline.js +115 -0
  51. package/package.json +13 -3
  52. package/scripts/build-hooks.js +3 -3
  53. /package/{get-shit-done → ez-agents}/bin/lib/assistant-adapter.cjs +0 -0
  54. /package/{get-shit-done → ez-agents}/bin/lib/audit-exec.cjs +0 -0
  55. /package/{get-shit-done → ez-agents}/bin/lib/circuit-breaker.cjs +0 -0
  56. /package/{get-shit-done → ez-agents}/bin/lib/commands.cjs +0 -0
  57. /package/{get-shit-done → ez-agents}/bin/lib/config.cjs +0 -0
  58. /package/{get-shit-done → ez-agents}/bin/lib/file-lock.cjs +0 -0
  59. /package/{get-shit-done → ez-agents}/bin/lib/frontmatter.cjs +0 -0
  60. /package/{get-shit-done → ez-agents}/bin/lib/fs-utils.cjs +0 -0
  61. /package/{get-shit-done → ez-agents}/bin/lib/git-utils.cjs +0 -0
  62. /package/{get-shit-done → ez-agents}/bin/lib/health-check.cjs +0 -0
  63. /package/{get-shit-done → ez-agents}/bin/lib/index.cjs +0 -0
  64. /package/{get-shit-done → ez-agents}/bin/lib/milestone.cjs +0 -0
  65. /package/{get-shit-done → ez-agents}/bin/lib/model-provider.cjs +0 -0
  66. /package/{get-shit-done → ez-agents}/bin/lib/phase.cjs +0 -0
  67. /package/{get-shit-done → ez-agents}/bin/lib/retry.cjs +0 -0
  68. /package/{get-shit-done → ez-agents}/bin/lib/roadmap.cjs +0 -0
  69. /package/{get-shit-done → ez-agents}/bin/lib/safe-exec.cjs +0 -0
  70. /package/{get-shit-done → ez-agents}/bin/lib/safe-path.cjs +0 -0
  71. /package/{get-shit-done → ez-agents}/bin/lib/state.cjs +0 -0
  72. /package/{get-shit-done → ez-agents}/bin/lib/template.cjs +0 -0
  73. /package/{get-shit-done → ez-agents}/bin/lib/test-safe-exec.cjs +0 -0
  74. /package/{get-shit-done → ez-agents}/bin/lib/test-safe-path.cjs +0 -0
  75. /package/{get-shit-done → ez-agents}/bin/lib/timeout-exec.cjs +0 -0
  76. /package/{get-shit-done → ez-agents}/bin/lib/verify.cjs +0 -0
  77. /package/{get-shit-done → ez-agents}/references/checkpoints.md +0 -0
  78. /package/{get-shit-done → ez-agents}/references/continuation-format.md +0 -0
  79. /package/{get-shit-done → ez-agents}/references/decimal-phase-calculation.md +0 -0
  80. /package/{get-shit-done → ez-agents}/references/git-integration.md +0 -0
  81. /package/{get-shit-done → ez-agents}/references/git-planning-commit.md +0 -0
  82. /package/{get-shit-done → ez-agents}/references/model-profile-resolution.md +0 -0
  83. /package/{get-shit-done → ez-agents}/references/model-profiles.md +0 -0
  84. /package/{get-shit-done → ez-agents}/references/phase-argument-parsing.md +0 -0
  85. /package/{get-shit-done → ez-agents}/references/planning-config.md +0 -0
  86. /package/{get-shit-done → ez-agents}/references/questioning.md +0 -0
  87. /package/{get-shit-done → ez-agents}/references/tdd.md +0 -0
  88. /package/{get-shit-done → ez-agents}/references/ui-brand.md +0 -0
  89. /package/{get-shit-done → ez-agents}/references/verification-patterns.md +0 -0
  90. /package/{get-shit-done → ez-agents}/templates/DEBUG.md +0 -0
  91. /package/{get-shit-done → ez-agents}/templates/UAT.md +0 -0
  92. /package/{get-shit-done → ez-agents}/templates/UI-SPEC.md +0 -0
  93. /package/{get-shit-done → ez-agents}/templates/VALIDATION.md +0 -0
  94. /package/{get-shit-done → ez-agents}/templates/codebase/architecture.md +0 -0
  95. /package/{get-shit-done → ez-agents}/templates/codebase/concerns.md +0 -0
  96. /package/{get-shit-done → ez-agents}/templates/codebase/conventions.md +0 -0
  97. /package/{get-shit-done → ez-agents}/templates/codebase/integrations.md +0 -0
  98. /package/{get-shit-done → ez-agents}/templates/codebase/stack.md +0 -0
  99. /package/{get-shit-done → ez-agents}/templates/codebase/structure.md +0 -0
  100. /package/{get-shit-done → ez-agents}/templates/codebase/testing.md +0 -0
  101. /package/{get-shit-done → ez-agents}/templates/config.json +0 -0
  102. /package/{get-shit-done → ez-agents}/templates/context.md +0 -0
  103. /package/{get-shit-done → ez-agents}/templates/continue-here.md +0 -0
  104. /package/{get-shit-done → ez-agents}/templates/copilot-instructions.md +0 -0
  105. /package/{get-shit-done → ez-agents}/templates/debug-subagent-prompt.md +0 -0
  106. /package/{get-shit-done → ez-agents}/templates/discovery.md +0 -0
  107. /package/{get-shit-done → ez-agents}/templates/milestone-archive.md +0 -0
  108. /package/{get-shit-done → ez-agents}/templates/milestone.md +0 -0
  109. /package/{get-shit-done → ez-agents}/templates/phase-prompt.md +0 -0
  110. /package/{get-shit-done → ez-agents}/templates/planner-subagent-prompt.md +0 -0
  111. /package/{get-shit-done → ez-agents}/templates/project.md +0 -0
  112. /package/{get-shit-done → ez-agents}/templates/requirements.md +0 -0
  113. /package/{get-shit-done → ez-agents}/templates/research-project/ARCHITECTURE.md +0 -0
  114. /package/{get-shit-done → ez-agents}/templates/research-project/FEATURES.md +0 -0
  115. /package/{get-shit-done → ez-agents}/templates/research-project/PITFALLS.md +0 -0
  116. /package/{get-shit-done → ez-agents}/templates/research-project/STACK.md +0 -0
  117. /package/{get-shit-done → ez-agents}/templates/research-project/SUMMARY.md +0 -0
  118. /package/{get-shit-done → ez-agents}/templates/research.md +0 -0
  119. /package/{get-shit-done → ez-agents}/templates/retrospective.md +0 -0
  120. /package/{get-shit-done → ez-agents}/templates/roadmap.md +0 -0
  121. /package/{get-shit-done → ez-agents}/templates/state.md +0 -0
  122. /package/{get-shit-done → ez-agents}/templates/summary-complex.md +0 -0
  123. /package/{get-shit-done → ez-agents}/templates/summary-minimal.md +0 -0
  124. /package/{get-shit-done → ez-agents}/templates/summary-standard.md +0 -0
  125. /package/{get-shit-done → ez-agents}/templates/summary.md +0 -0
  126. /package/{get-shit-done → ez-agents}/templates/user-setup.md +0 -0
  127. /package/{get-shit-done → ez-agents}/templates/verification-report.md +0 -0
  128. /package/{get-shit-done → ez-agents}/workflows/add-tests.md +0 -0
  129. /package/{get-shit-done → ez-agents}/workflows/add-todo.md +0 -0
  130. /package/{get-shit-done → ez-agents}/workflows/autonomous.md +0 -0
  131. /package/{get-shit-done → ez-agents}/workflows/check-todos.md +0 -0
  132. /package/{get-shit-done → ez-agents}/workflows/cleanup.md +0 -0
  133. /package/{get-shit-done → ez-agents}/workflows/diagnose-issues.md +0 -0
  134. /package/{get-shit-done → ez-agents}/workflows/health.md +0 -0
  135. /package/{get-shit-done → ez-agents}/workflows/list-phase-assumptions.md +0 -0
  136. /package/{get-shit-done → ez-agents}/workflows/node-repair.md +0 -0
  137. /package/{get-shit-done → ez-agents}/workflows/pause-work.md +0 -0
  138. /package/{get-shit-done → ez-agents}/workflows/plan-milestone-gaps.md +0 -0
  139. /package/{get-shit-done → ez-agents}/workflows/settings.md +0 -0
  140. /package/{get-shit-done → ez-agents}/workflows/stats.md +0 -0
@@ -3,7 +3,7 @@ Audit Nyquist validation gaps for a completed phase. Generate missing tests. Upd
3
3
  </purpose>
4
4
 
5
5
  <required_reading>
6
- @~/.claude/get-shit-done/references/ui-brand.md
6
+ @~/.claude/ez-agents/references/ui-brand.md
7
7
  </required_reading>
8
8
 
9
9
  <process>
@@ -18,7 +18,7 @@ if [[ "$INIT" == @file:* ]]; then INIT=$(cat "${INIT#@file:}"); fi
18
18
  Parse: `phase_dir`, `phase_number`, `phase_name`, `phase_slug`, `padded_phase`.
19
19
 
20
20
  ```bash
21
- AUDITOR_MODEL=$(node "$HOME/.claude/ez-agents/bin/ez-tools.cjs" resolve-model gsd-nyquist-auditor --raw)
21
+ AUDITOR_MODEL=$(node "$HOME/.claude/ez-agents/bin/ez-tools.cjs" resolve-model ez-nyquist-auditor --raw)
22
22
  NYQUIST_CFG=$(node "$HOME/.claude/ez-agents/bin/ez-tools.cjs" config get workflow.nyquist_validation --raw)
23
23
  ```
24
24
 
@@ -82,11 +82,11 @@ Call AskUserQuestion with gap table and options:
82
82
  2. "Skip — mark manual-only" → add to Manual-Only, Step 6
83
83
  3. "Cancel" → exit
84
84
 
85
- ## 5. Spawn gsd-nyquist-auditor
85
+ ## 5. Spawn ez-nyquist-auditor
86
86
 
87
87
  ```
88
88
  Task(
89
- prompt="Read ~/.claude/agents/gsd-nyquist-auditor.md for instructions.\n\n" +
89
+ prompt="Read ~/.claude/agents/ez-nyquist-auditor.md for instructions.\n\n" +
90
90
  "<files_to_read>{PLAN, SUMMARY, impl files, VALIDATION.md}</files_to_read>" +
91
91
  "<gaps>{gap list}</gaps>" +
92
92
  "<test_infrastructure>{framework, config, commands}</test_infrastructure>" +
@@ -105,7 +105,7 @@ Handle return:
105
105
  ## 6. Generate/Update VALIDATION.md
106
106
 
107
107
  **State B (create):**
108
- 1. Read template from `~/.claude/get-shit-done/templates/VALIDATION.md`
108
+ 1. Read template from `~/.claude/ez-agents/templates/VALIDATION.md`
109
109
  2. Fill: frontmatter, Test Infrastructure, Per-Task Map, Manual-Only, Sign-Off
110
110
  3. Write to `${PHASE_DIR}/${PADDED_PHASE}-VALIDATION.md`
111
111
 
@@ -18,8 +18,8 @@ Then verify each level against the actual codebase.
18
18
  </core_principle>
19
19
 
20
20
  <required_reading>
21
- @~/.claude/get-shit-done/references/verification-patterns.md
22
- @~/.claude/get-shit-done/templates/verification-report.md
21
+ @~/.claude/ez-agents/references/verification-patterns.md
22
+ @~/.claude/ez-agents/templates/verification-report.md
23
23
  </required_reading>
24
24
 
25
25
  <process>
@@ -47,7 +47,7 @@ Extract **phase goal** from ROADMAP.md (the outcome to verify, not tasks) and **
47
47
  <step name="establish_must_haves">
48
48
  **Option A: Must-haves in PLAN frontmatter**
49
49
 
50
- Use gsd-tools to extract must_haves from each PLAN:
50
+ Use ez-tools to extract must_haves from each PLAN:
51
51
 
52
52
  ```bash
53
53
  for plan in "$PHASE_DIR"/*-PLAN.md; do
@@ -97,7 +97,7 @@ For each truth: identify supporting artifacts → check artifact status → chec
97
97
  </step>
98
98
 
99
99
  <step name="verify_artifacts">
100
- Use gsd-tools for artifact verification against must_haves in each PLAN:
100
+ Use ez-tools for artifact verification against must_haves in each PLAN:
101
101
 
102
102
  ```bash
103
103
  for plan in "$PHASE_DIR"/*-PLAN.md; do
@@ -129,7 +129,7 @@ WIRED = imported AND used. ORPHANED = exists but not imported/used.
129
129
  </step>
130
130
 
131
131
  <step name="verify_wiring">
132
- Use gsd-tools for key link verification against must_haves in each PLAN:
132
+ Use ez-tools for key link verification against must_haves in each PLAN:
133
133
 
134
134
  ```bash
135
135
  for plan in "$PHASE_DIR"/*-PLAN.md; do
@@ -214,7 +214,7 @@ REPORT_PATH="$PHASE_DIR/${PHASE_NUM}-VERIFICATION.md"
214
214
 
215
215
  Fill template sections: frontmatter (phase/timestamp/status/score), goal achievement, artifact table, wiring table, requirements coverage, anti-patterns, human verification, gaps summary, fix plans (if gaps_found), metadata.
216
216
 
217
- See ~/.claude/get-shit-done/templates/verification-report.md for complete template.
217
+ See ~/.claude/ez-agents/templates/verification-report.md for complete template.
218
218
  </step>
219
219
 
220
220
  <step name="return_to_orchestrator">
@@ -15,7 +15,7 @@ No Pass/Fail buttons. No severity questions. Just: "Here's what should happen. D
15
15
  </philosophy>
16
16
 
17
17
  <template>
18
- @~/.claude/get-shit-done/templates/UAT.md
18
+ @~/.claude/ez-agents/templates/UAT.md
19
19
  </template>
20
20
 
21
21
  <process>
@@ -349,7 +349,7 @@ Spawning parallel debug agents to investigate each issue.
349
349
  ```
350
350
 
351
351
  - Load diagnose-issues workflow
352
- - Follow @~/.claude/get-shit-done/workflows/diagnose-issues.md
352
+ - Follow @~/.claude/ez-agents/workflows/diagnose-issues.md
353
353
  - Spawn parallel debug agents for each issue
354
354
  - Collect root causes
355
355
  - Update UAT.md with root causes
@@ -370,7 +370,7 @@ Display:
370
370
  ◆ Spawning planner for gap closure...
371
371
  ```
372
372
 
373
- Spawn gsd-planner in --gaps mode:
373
+ Spawn ez-planner in --gaps mode:
374
374
 
375
375
  ```
376
376
  Task(
@@ -577,8 +577,8 @@ Default to **major** if unclear. User can correct if needed.
577
577
  - [ ] Batched writes: on issue, every 5 passes, or completion
578
578
  - [ ] Committed on completion
579
579
  - [ ] If issues: parallel debug agents diagnose root causes
580
- - [ ] If issues: gsd-planner creates fix plans (gap_closure mode)
581
- - [ ] If issues: gsd-plan-checker verifies fix plans
580
+ - [ ] If issues: ez-planner creates fix plans (gap_closure mode)
581
+ - [ ] If issues: ez-plan-checker verifies fix plans
582
582
  - [ ] If issues: revision loop until plans pass (max 3 iterations)
583
583
  - [ ] Ready for `/ez:execute-phase --gaps-only` when complete
584
584
  </success_criteria>
@@ -0,0 +1,81 @@
1
+ #!/usr/bin/env node
2
+ // Check for EZ Agents updates in background, write result to cache
3
+ // Called by SessionStart hook - runs once per session
4
+
5
+ const fs = require('fs');
6
+ const path = require('path');
7
+ const os = require('os');
8
+ const { spawn } = require('child_process');
9
+
10
+ const homeDir = os.homedir();
11
+ const cwd = process.cwd();
12
+
13
+ // Detect runtime config directory (supports Claude, OpenCode, Gemini)
14
+ // Respects CLAUDE_CONFIG_DIR for custom config directory setups
15
+ function detectConfigDir(baseDir) {
16
+ // Check env override first (supports multi-account setups)
17
+ const envDir = process.env.CLAUDE_CONFIG_DIR;
18
+ if (envDir && fs.existsSync(path.join(envDir, 'ez-agents', 'VERSION'))) {
19
+ return envDir;
20
+ }
21
+ for (const dir of ['.config/opencode', '.opencode', '.gemini', '.claude']) {
22
+ if (fs.existsSync(path.join(baseDir, dir, 'ez-agents', 'VERSION'))) {
23
+ return path.join(baseDir, dir);
24
+ }
25
+ }
26
+ return envDir || path.join(baseDir, '.claude');
27
+ }
28
+
29
+ const globalConfigDir = detectConfigDir(homeDir);
30
+ const projectConfigDir = detectConfigDir(cwd);
31
+ const cacheDir = path.join(globalConfigDir, 'cache');
32
+ const cacheFile = path.join(cacheDir, 'ez-update-check.json');
33
+
34
+ // VERSION file locations (check project first, then global)
35
+ const projectVersionFile = path.join(projectConfigDir, 'ez-agents', 'VERSION');
36
+ const globalVersionFile = path.join(globalConfigDir, 'ez-agents', 'VERSION');
37
+
38
+ // Ensure cache directory exists
39
+ if (!fs.existsSync(cacheDir)) {
40
+ fs.mkdirSync(cacheDir, { recursive: true });
41
+ }
42
+
43
+ // Run check in background (spawn background process, windowsHide prevents console flash)
44
+ const child = spawn(process.execPath, ['-e', `
45
+ const fs = require('fs');
46
+ const { execSync } = require('child_process');
47
+
48
+ const cacheFile = ${JSON.stringify(cacheFile)};
49
+ const projectVersionFile = ${JSON.stringify(projectVersionFile)};
50
+ const globalVersionFile = ${JSON.stringify(globalVersionFile)};
51
+
52
+ // Check project directory first (local install), then global
53
+ let installed = '0.0.0';
54
+ try {
55
+ if (fs.existsSync(projectVersionFile)) {
56
+ installed = fs.readFileSync(projectVersionFile, 'utf8').trim();
57
+ } else if (fs.existsSync(globalVersionFile)) {
58
+ installed = fs.readFileSync(globalVersionFile, 'utf8').trim();
59
+ }
60
+ } catch (e) {}
61
+
62
+ let latest = null;
63
+ try {
64
+ latest = execSync('npm view ez-agents version', { encoding: 'utf8', timeout: 10000, windowsHide: true }).trim();
65
+ } catch (e) {}
66
+
67
+ const result = {
68
+ update_available: latest && installed !== latest,
69
+ installed,
70
+ latest: latest || 'unknown',
71
+ checked: Math.floor(Date.now() / 1000)
72
+ };
73
+
74
+ fs.writeFileSync(cacheFile, JSON.stringify(result));
75
+ `], {
76
+ stdio: 'ignore',
77
+ windowsHide: true,
78
+ detached: true // Required on Windows for proper process detachment
79
+ });
80
+
81
+ child.unref();
@@ -0,0 +1,141 @@
1
+ #!/usr/bin/env node
2
+ // Context Monitor - PostToolUse/AfterTool hook (Gemini uses AfterTool)
3
+ // Reads context metrics from the statusline bridge file and injects
4
+ // warnings when context usage is high. This makes the AGENT aware of
5
+ // context limits (the statusline only shows the user).
6
+ //
7
+ // How it works:
8
+ // 1. The statusline hook writes metrics to /tmp/claude-ctx-{session_id}.json
9
+ // 2. This hook reads those metrics after each tool use
10
+ // 3. When remaining context drops below thresholds, it injects a warning
11
+ // as additionalContext, which the agent sees in its conversation
12
+ //
13
+ // Thresholds:
14
+ // WARNING (remaining <= 35%): Agent should wrap up current task
15
+ // CRITICAL (remaining <= 25%): Agent should stop immediately and save state
16
+ //
17
+ // Debounce: 5 tool uses between warnings to avoid spam
18
+ // Severity escalation bypasses debounce (WARNING -> CRITICAL fires immediately)
19
+
20
+ const fs = require('fs');
21
+ const os = require('os');
22
+ const path = require('path');
23
+
24
+ const WARNING_THRESHOLD = 35; // remaining_percentage <= 35%
25
+ const CRITICAL_THRESHOLD = 25; // remaining_percentage <= 25%
26
+ const STALE_SECONDS = 60; // ignore metrics older than 60s
27
+ const DEBOUNCE_CALLS = 5; // min tool uses between warnings
28
+
29
+ let input = '';
30
+ // Timeout guard: if stdin doesn't close within 3s (e.g. pipe issues on
31
+ // Windows/Git Bash), exit silently instead of hanging until Claude Code
32
+ // kills the process and reports "hook error". See #775.
33
+ const stdinTimeout = setTimeout(() => process.exit(0), 3000);
34
+ process.stdin.setEncoding('utf8');
35
+ process.stdin.on('data', chunk => input += chunk);
36
+ process.stdin.on('end', () => {
37
+ clearTimeout(stdinTimeout);
38
+ try {
39
+ const data = JSON.parse(input);
40
+ const sessionId = data.session_id;
41
+
42
+ if (!sessionId) {
43
+ process.exit(0);
44
+ }
45
+
46
+ const tmpDir = os.tmpdir();
47
+ const metricsPath = path.join(tmpDir, `claude-ctx-${sessionId}.json`);
48
+
49
+ // If no metrics file, this is a subagent or fresh session -- exit silently
50
+ if (!fs.existsSync(metricsPath)) {
51
+ process.exit(0);
52
+ }
53
+
54
+ const metrics = JSON.parse(fs.readFileSync(metricsPath, 'utf8'));
55
+ const now = Math.floor(Date.now() / 1000);
56
+
57
+ // Ignore stale metrics
58
+ if (metrics.timestamp && (now - metrics.timestamp) > STALE_SECONDS) {
59
+ process.exit(0);
60
+ }
61
+
62
+ const remaining = metrics.remaining_percentage;
63
+ const usedPct = metrics.used_pct;
64
+
65
+ // No warning needed
66
+ if (remaining > WARNING_THRESHOLD) {
67
+ process.exit(0);
68
+ }
69
+
70
+ // Debounce: check if we warned recently
71
+ const warnPath = path.join(tmpDir, `claude-ctx-${sessionId}-warned.json`);
72
+ let warnData = { callsSinceWarn: 0, lastLevel: null };
73
+ let firstWarn = true;
74
+
75
+ if (fs.existsSync(warnPath)) {
76
+ try {
77
+ warnData = JSON.parse(fs.readFileSync(warnPath, 'utf8'));
78
+ firstWarn = false;
79
+ } catch (e) {
80
+ // Corrupted file, reset
81
+ }
82
+ }
83
+
84
+ warnData.callsSinceWarn = (warnData.callsSinceWarn || 0) + 1;
85
+
86
+ const isCritical = remaining <= CRITICAL_THRESHOLD;
87
+ const currentLevel = isCritical ? 'critical' : 'warning';
88
+
89
+ // Emit immediately on first warning, then debounce subsequent ones
90
+ // Severity escalation (WARNING -> CRITICAL) bypasses debounce
91
+ const severityEscalated = currentLevel === 'critical' && warnData.lastLevel === 'warning';
92
+ if (!firstWarn && warnData.callsSinceWarn < DEBOUNCE_CALLS && !severityEscalated) {
93
+ // Update counter and exit without warning
94
+ fs.writeFileSync(warnPath, JSON.stringify(warnData));
95
+ process.exit(0);
96
+ }
97
+
98
+ // Reset debounce counter
99
+ warnData.callsSinceWarn = 0;
100
+ warnData.lastLevel = currentLevel;
101
+ fs.writeFileSync(warnPath, JSON.stringify(warnData));
102
+
103
+ // Detect if EZ Agents is active (has .planning/STATE.md in working directory)
104
+ const cwd = data.cwd || process.cwd();
105
+ const isEzActive = fs.existsSync(path.join(cwd, '.planning', 'STATE.md'));
106
+
107
+ // Build advisory warning message (never use imperative commands that
108
+ // override user preferences — see #884)
109
+ let message;
110
+ if (isCritical) {
111
+ message = isEzActive
112
+ ? `CONTEXT CRITICAL: Usage at ${usedPct}%. Remaining: ${remaining}%. ` +
113
+ 'Context is nearly exhausted. Do NOT start new complex work or write handoff files — ' +
114
+ 'EZ Agents state is already tracked in STATE.md. Inform the user so they can run ' +
115
+ '/ez:pause-work at the next natural stopping point.'
116
+ : `CONTEXT CRITICAL: Usage at ${usedPct}%. Remaining: ${remaining}%. ` +
117
+ 'Context is nearly exhausted. Inform the user that context is low and ask how they ' +
118
+ 'want to proceed. Do NOT autonomously save state or write handoff files unless the user asks.';
119
+ } else {
120
+ message = isEzActive
121
+ ? `CONTEXT WARNING: Usage at ${usedPct}%. Remaining: ${remaining}%. ` +
122
+ 'Context is getting limited. Avoid starting new complex work. If not between ' +
123
+ 'defined plan steps, inform the user so they can prepare to pause.'
124
+ : `CONTEXT WARNING: Usage at ${usedPct}%. Remaining: ${remaining}%. ` +
125
+ 'Be aware that context is getting limited. Avoid unnecessary exploration or ' +
126
+ 'starting new complex work.';
127
+ }
128
+
129
+ const output = {
130
+ hookSpecificOutput: {
131
+ hookEventName: process.env.GEMINI_API_KEY ? "AfterTool" : "PostToolUse",
132
+ additionalContext: message
133
+ }
134
+ };
135
+
136
+ process.stdout.write(JSON.stringify(output));
137
+ } catch (e) {
138
+ // Silent fail -- never block tool execution
139
+ process.exit(0);
140
+ }
141
+ });
@@ -0,0 +1,115 @@
1
+ #!/usr/bin/env node
2
+ // Claude Code Statusline - EZ Agents Edition
3
+ // Shows: model | current task | directory | context usage
4
+
5
+ const fs = require('fs');
6
+ const path = require('path');
7
+ const os = require('os');
8
+
9
+ // Read JSON from stdin
10
+ let input = '';
11
+ // Timeout guard: if stdin doesn't close within 3s (e.g. pipe issues on
12
+ // Windows/Git Bash), exit silently instead of hanging. See #775.
13
+ const stdinTimeout = setTimeout(() => process.exit(0), 3000);
14
+ process.stdin.setEncoding('utf8');
15
+ process.stdin.on('data', chunk => input += chunk);
16
+ process.stdin.on('end', () => {
17
+ clearTimeout(stdinTimeout);
18
+ try {
19
+ const data = JSON.parse(input);
20
+ const model = data.model?.display_name || 'Claude';
21
+ const dir = data.workspace?.current_dir || process.cwd();
22
+ const session = data.session_id || '';
23
+ const remaining = data.context_window?.remaining_percentage;
24
+
25
+ // Context window display (shows USED percentage scaled to usable context)
26
+ // Claude Code reserves ~16.5% for autocompact buffer, so usable context
27
+ // is 83.5% of the total window. We normalize to show 100% at that point.
28
+ const AUTO_COMPACT_BUFFER_PCT = 16.5;
29
+ let ctx = '';
30
+ if (remaining != null) {
31
+ // Normalize: subtract buffer from remaining, scale to usable range
32
+ const usableRemaining = Math.max(0, ((remaining - AUTO_COMPACT_BUFFER_PCT) / (100 - AUTO_COMPACT_BUFFER_PCT)) * 100);
33
+ const used = Math.max(0, Math.min(100, Math.round(100 - usableRemaining)));
34
+
35
+ // Write context metrics to bridge file for the context-monitor PostToolUse hook.
36
+ // The monitor reads this file to inject agent-facing warnings when context is low.
37
+ if (session) {
38
+ try {
39
+ const bridgePath = path.join(os.tmpdir(), `claude-ctx-${session}.json`);
40
+ const bridgeData = JSON.stringify({
41
+ session_id: session,
42
+ remaining_percentage: remaining,
43
+ used_pct: used,
44
+ timestamp: Math.floor(Date.now() / 1000)
45
+ });
46
+ fs.writeFileSync(bridgePath, bridgeData);
47
+ } catch (e) {
48
+ // Silent fail -- bridge is best-effort, don't break statusline
49
+ }
50
+ }
51
+
52
+ // Build progress bar (10 segments)
53
+ const filled = Math.floor(used / 10);
54
+ const bar = '█'.repeat(filled) + '░'.repeat(10 - filled);
55
+
56
+ // Color based on usable context thresholds
57
+ if (used < 50) {
58
+ ctx = ` \x1b[32m${bar} ${used}%\x1b[0m`;
59
+ } else if (used < 65) {
60
+ ctx = ` \x1b[33m${bar} ${used}%\x1b[0m`;
61
+ } else if (used < 80) {
62
+ ctx = ` \x1b[38;5;208m${bar} ${used}%\x1b[0m`;
63
+ } else {
64
+ ctx = ` \x1b[5;31m💀 ${bar} ${used}%\x1b[0m`;
65
+ }
66
+ }
67
+
68
+ // Current task from todos
69
+ let task = '';
70
+ const homeDir = os.homedir();
71
+ // Respect CLAUDE_CONFIG_DIR for custom config directory setups (#870)
72
+ const claudeDir = process.env.CLAUDE_CONFIG_DIR || path.join(homeDir, '.claude');
73
+ const todosDir = path.join(claudeDir, 'todos');
74
+ if (session && fs.existsSync(todosDir)) {
75
+ try {
76
+ const files = fs.readdirSync(todosDir)
77
+ .filter(f => f.startsWith(session) && f.includes('-agent-') && f.endsWith('.json'))
78
+ .map(f => ({ name: f, mtime: fs.statSync(path.join(todosDir, f)).mtime }))
79
+ .sort((a, b) => b.mtime - a.mtime);
80
+
81
+ if (files.length > 0) {
82
+ try {
83
+ const todos = JSON.parse(fs.readFileSync(path.join(todosDir, files[0].name), 'utf8'));
84
+ const inProgress = todos.find(t => t.status === 'in_progress');
85
+ if (inProgress) task = inProgress.activeForm || '';
86
+ } catch (e) {}
87
+ }
88
+ } catch (e) {
89
+ // Silently fail on file system errors - don't break statusline
90
+ }
91
+ }
92
+
93
+ // EZ Agents update available?
94
+ let ezUpdate = '';
95
+ const cacheFile = path.join(claudeDir, 'cache', 'ez-update-check.json');
96
+ if (fs.existsSync(cacheFile)) {
97
+ try {
98
+ const cache = JSON.parse(fs.readFileSync(cacheFile, 'utf8'));
99
+ if (cache.update_available) {
100
+ ezUpdate = '\x1b[33m⬆ /ez:update\x1b[0m │ ';
101
+ }
102
+ } catch (e) {}
103
+ }
104
+
105
+ // Output
106
+ const dirname = path.basename(dir);
107
+ if (task) {
108
+ process.stdout.write(`${ezUpdate}\x1b[2m${model}\x1b[0m │ \x1b[1m${task}\x1b[0m │ \x1b[2m${dirname}\x1b[0m${ctx}`);
109
+ } else {
110
+ process.stdout.write(`${ezUpdate}\x1b[2m${model}\x1b[0m │ \x1b[2m${dirname}\x1b[0m${ctx}`);
111
+ }
112
+ } catch (e) {
113
+ // Silent fail - don't break statusline on parse errors
114
+ }
115
+ });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@howlil/ez-agents",
3
- "version": "2.0.1",
3
+ "version": "3.0.0",
4
4
  "description": "EZ Agents — Meta-prompting with multi-model support (Qwen, Kimi, OpenAI)",
5
5
  "bin": {
6
6
  "ez-agents": "bin/install.js",
@@ -9,7 +9,7 @@
9
9
  "files": [
10
10
  "bin",
11
11
  "commands",
12
- "get-shit-done",
12
+ "ez-agents",
13
13
  "agents",
14
14
  "hooks/dist",
15
15
  "scripts"
@@ -44,12 +44,22 @@
44
44
  "devDependencies": {
45
45
  "c8": "^11.0.0",
46
46
  "esbuild": "^0.24.2",
47
+ "husky": "^9.1.7",
48
+ "lint-staged": "^15.5.2",
47
49
  "proper-lockfile": "^4.1.2"
48
50
  },
49
51
  "scripts": {
50
52
  "build:hooks": "node scripts/build-hooks.js",
51
53
  "prepublishOnly": "npm run build:hooks",
52
54
  "test": "node scripts/run-tests.cjs",
53
- "test:coverage": "c8 --check-coverage --lines 70 --reporter text --include 'get-shit-done/bin/lib/*.cjs' --exclude 'tests/**' --all node scripts/run-tests.cjs"
55
+ "test:coverage": "c8 --check-coverage --lines 70 --reporter text --include 'ez-agents/bin/lib/*.cjs' --exclude 'tests/**' --all node scripts/run-tests.cjs"
56
+ },
57
+ "lint-staged": {
58
+ "*.cjs": [
59
+ "node --test"
60
+ ],
61
+ "*.md": [
62
+ "node scripts/run-tests.cjs"
63
+ ]
54
64
  }
55
65
  }
@@ -11,9 +11,9 @@ const DIST_DIR = path.join(HOOKS_DIR, 'dist');
11
11
 
12
12
  // Hooks to copy (pure Node.js, no bundling needed)
13
13
  const HOOKS_TO_COPY = [
14
- 'gsd-check-update.js',
15
- 'gsd-context-monitor.js',
16
- 'gsd-statusline.js'
14
+ 'ez-check-update.js',
15
+ 'ez-context-monitor.js',
16
+ 'ez-statusline.js'
17
17
  ];
18
18
 
19
19
  function build() {
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes