claude-code-scanner 1.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 (65) hide show
  1. package/DOCUMENTATION.md +1210 -0
  2. package/LICENSE +21 -0
  3. package/README.md +306 -0
  4. package/bin/cli.js +305 -0
  5. package/package.json +43 -0
  6. package/template/.claude/agents/api-builder.md +64 -0
  7. package/template/.claude/agents/architect.md +92 -0
  8. package/template/.claude/agents/debugger.md +69 -0
  9. package/template/.claude/agents/explorer.md +71 -0
  10. package/template/.claude/agents/frontend.md +61 -0
  11. package/template/.claude/agents/infra.md +66 -0
  12. package/template/.claude/agents/product-owner.md +73 -0
  13. package/template/.claude/agents/qa-lead.md +102 -0
  14. package/template/.claude/agents/reviewer.md +77 -0
  15. package/template/.claude/agents/security.md +81 -0
  16. package/template/.claude/agents/team-lead.md +128 -0
  17. package/template/.claude/agents/tester.md +72 -0
  18. package/template/.claude/docs/agent-error-protocol.md +89 -0
  19. package/template/.claude/docs/best-practices.md +93 -0
  20. package/template/.claude/docs/commands-template.md +73 -0
  21. package/template/.claude/docs/conflict-resolution-protocol.md +82 -0
  22. package/template/.claude/docs/context-budget.md +54 -0
  23. package/template/.claude/docs/execution-metrics-protocol.md +105 -0
  24. package/template/.claude/docs/flow-engine.md +475 -0
  25. package/template/.claude/docs/smithery-setup.md +51 -0
  26. package/template/.claude/docs/task-record-schema.md +196 -0
  27. package/template/.claude/hooks/drift-detector.js +143 -0
  28. package/template/.claude/hooks/execution-report.js +114 -0
  29. package/template/.claude/hooks/notify-approval.js +30 -0
  30. package/template/.claude/hooks/post-compact-recovery.js +68 -0
  31. package/template/.claude/hooks/post-edit-format.js +43 -0
  32. package/template/.claude/hooks/pre-compact-save.js +94 -0
  33. package/template/.claude/hooks/protect-files.js +39 -0
  34. package/template/.claude/hooks/session-start.js +76 -0
  35. package/template/.claude/hooks/stop-failure-handler.js +77 -0
  36. package/template/.claude/hooks/tool-failure-tracker.js +54 -0
  37. package/template/.claude/hooks/track-file-changes.js +34 -0
  38. package/template/.claude/hooks/validate-bash.js +34 -0
  39. package/template/.claude/manifest.json +22 -0
  40. package/template/.claude/profiles/backend.md +34 -0
  41. package/template/.claude/profiles/devops.md +36 -0
  42. package/template/.claude/profiles/frontend.md +34 -0
  43. package/template/.claude/rules/context-budget.md +34 -0
  44. package/template/.claude/scripts/verify-setup.js +210 -0
  45. package/template/.claude/settings.json +154 -0
  46. package/template/.claude/skills/context-check/SKILL.md +112 -0
  47. package/template/.claude/skills/execution-report/SKILL.md +229 -0
  48. package/template/.claude/skills/generate-environment/SKILL.md +128 -0
  49. package/template/.claude/skills/generate-environment/additional-skills.md +276 -0
  50. package/template/.claude/skills/generate-environment/artifact-templates.md +386 -0
  51. package/template/.claude/skills/generate-environment/domain-agents.md +202 -0
  52. package/template/.claude/skills/impact-analysis/SKILL.md +17 -0
  53. package/template/.claude/skills/metrics/SKILL.md +19 -0
  54. package/template/.claude/skills/progress-report/SKILL.md +27 -0
  55. package/template/.claude/skills/rollback/SKILL.md +75 -0
  56. package/template/.claude/skills/scan-codebase/SKILL.md +59 -0
  57. package/template/.claude/skills/scan-codebase/deep-scan-instructions.md +101 -0
  58. package/template/.claude/skills/scan-codebase/tech-markers.md +87 -0
  59. package/template/.claude/skills/setup-smithery/SKILL.md +38 -0
  60. package/template/.claude/skills/sync/SKILL.md +239 -0
  61. package/template/.claude/skills/task-tracker/SKILL.md +40 -0
  62. package/template/.claude/skills/validate-setup/SKILL.md +30 -0
  63. package/template/.claude/skills/workflow/SKILL.md +333 -0
  64. package/template/.claude/templates/README.md +42 -0
  65. package/template/CLAUDE.md +67 -0
@@ -0,0 +1,196 @@
1
+ # Task Record Schema
2
+
3
+ ## File: `.claude/tasks/TASK-{id}.md`
4
+
5
+ ### Frontmatter
6
+ ```yaml
7
+ ---
8
+ id: TASK-{number}
9
+ title: {title}
10
+ type: feature | bugfix | refactor | hotfix | tech-debt | spike
11
+ scope: frontend-only | backend-only | fullstack | infrastructure | cross-cutting
12
+ complexity: small | medium | large
13
+ priority: P0-critical | P1-high | P2-medium | P3-low
14
+ status: {state — see State Machine below}
15
+ branch: {branch name}
16
+ pr: {PR number or "pending"}
17
+ assigned-to: {agent name or "unassigned"}
18
+ depends-on: {TASK-id or "none"}
19
+ created: {ISO timestamp}
20
+ updated: {ISO timestamp}
21
+ ---
22
+ ```
23
+
24
+ ### Current Status Section
25
+ - Phase, state, progress %, last activity, next action, blocked Y/N
26
+
27
+ ### Loop State Section
28
+ Track all active correspondence loops to survive compaction:
29
+ ```markdown
30
+ ## Loop State
31
+
32
+ ### Dev-Test Loop (Phase 6)
33
+ - dev-test-loop: iteration N/5
34
+ - coverage-baseline: N%
35
+ - coverage-current: N%
36
+ - fix-agent: @debugger|@api-builder|@frontend|@infra
37
+ - last-failure: [test name] — [error] at [ISO timestamp]
38
+
39
+ ### Review-Rework Loop (Phase 7)
40
+ - review-loop: iteration N/3
41
+ - reviewer-status: APPROVE | REQUEST_CHANGES (N critical, M suggestions)
42
+ - security-status: APPROVE | REQUEST_CHANGES (N findings)
43
+ - open-comments: [count] critical, [count] suggestions
44
+ - addressed-comments: [count] fixed, [count] won't-fix
45
+
46
+ ### CI Fix Loop (Phase 8)
47
+ - ci-fix-loop: iteration N/3
48
+ - last-ci-failure: [check name] — [error] at [ISO timestamp]
49
+ - fix-agent: @debugger|@api-builder|@frontend|@infra|@tester
50
+
51
+ ### QA Bug Loop (Phase 9)
52
+ - qa-bug-loop:
53
+ - BUG-{id}-1 (P1): iteration N/3 — [OPEN|FIXED|VERIFIED|REOPENED]
54
+ - BUG-{id}-2 (P3): known-issue
55
+ - total-bugs: N found, M fixed, K verified, J known-issues
56
+ - regression-check-after-each-fix: true
57
+
58
+ ### Sign-off Rejection Loop (Phase 10)
59
+ - signoff-rejection-cycle: N/2
60
+ - qa-signoff: APPROVED|CONDITIONAL|REJECTED|PENDING
61
+ - biz-signoff: APPROVED|REJECTED|PENDING
62
+ - tech-signoff: APPROVED|REJECTED|PENDING
63
+ - last-rejection: [who] — [reason] at [ISO timestamp]
64
+
65
+ ### Deploy Loop (Phase 11)
66
+ - deploy-loop: iteration N/2
67
+ - last-deploy-failure: [error type] — [summary] at [ISO timestamp]
68
+ - rollback-executed: true|false
69
+ ```
70
+
71
+ ### Loop Counter Reset Rules
72
+ | Event | Counters That Reset |
73
+ |-------|-------------------|
74
+ | Phase 10 rejects -> Phase 5 | dev-test, review, ci-fix reset to 0 |
75
+ | Phase 10 rejects -> Phase 4 or 3 | ALL loop counters reset to 0 |
76
+ | Deploy fails -> Phase 5 | dev-test, review, ci-fix reset to 0 |
77
+ | Normal phase advance | Counters preserved for reporting |
78
+ | Agent timeout in loop | Counts as +1 to current loop iteration |
79
+ | ON_HOLD -> resume | ALL loop counters preserved (no reset) |
80
+
81
+ ## Task State Machine
82
+ ```
83
+ Forward flow:
84
+ BACKLOG -> INTAKE -> ANALYZING -> DESIGNING -> APPROVED -> DEVELOPING
85
+ -> DEV_TESTING -> REVIEWING -> CI_PENDING -> QA_TESTING
86
+ -> QA_SIGNOFF -> BIZ_SIGNOFF -> TECH_SIGNOFF
87
+ -> DEPLOYING -> MONITORING -> CLOSED
88
+
89
+ Phase-to-state mapping:
90
+ Phase 1 = INTAKE
91
+ Phase 2 = ANALYZING
92
+ Phase 3 = DESIGNING
93
+ Phase 4 = APPROVED (after user confirms)
94
+ Phase 5 = DEVELOPING
95
+ Phase 6 = DEV_TESTING
96
+ Phase 7 = REVIEWING
97
+ Phase 8 = CI_PENDING
98
+ Phase 9 = QA_TESTING
99
+ Phase 10 = QA_SIGNOFF -> BIZ_SIGNOFF -> TECH_SIGNOFF
100
+ Phase 11 = DEPLOYING
101
+ Phase 12 = MONITORING
102
+ Phase 13 = CLOSED (after final report)
103
+
104
+ Special states (from ANY active state):
105
+ -> BLOCKED (waiting on depends-on or manual unblock)
106
+ -> ON_HOLD (deferred by user/product-owner, resume with /workflow resume)
107
+ -> CANCELLED (terminal, cleanup executed)
108
+
109
+ Reverse transitions (rejection routing):
110
+ QA_SIGNOFF -> DEVELOPING (QA rejects: bugs)
111
+ BIZ_SIGNOFF -> APPROVED (reqs wrong) or DEVELOPING (UI wrong)
112
+ TECH_SIGNOFF -> DESIGNING (architecture) or DEVELOPING (perf/tests)
113
+ DEPLOYING -> DEVELOPING (code bug) or DEPLOYING (config retry)
114
+
115
+ Circuit breaker -> escalated to user (stays in current state until resolved)
116
+ ```
117
+
118
+ ### Timeline Section
119
+ Every event: timestamp, phase, event description, agent/actor, duration
120
+
121
+ ### Handoff Log
122
+ Track every agent-to-agent handoff:
123
+ ```markdown
124
+ ## Handoff Log
125
+ | Timestamp | From | To | Reason | Artifacts | Status |
126
+ |-----------|------|-----|--------|-----------|--------|
127
+ | 2026-03-26T10:00:00Z | @explorer | @team-lead | impact analysis complete | scan-results.md | complete |
128
+ | 2026-03-26T10:05:00Z | @team-lead | @api-builder | backend dev assigned | TASK-001.md | complete |
129
+ ```
130
+
131
+ ### Phase Detail Sections (1-13)
132
+ Each phase records specific outputs:
133
+ - **Phase 1:** type, scope, complexity, branch name, task record created
134
+ - **Phase 2:** files affected, blast radius, test coverage %, security flags, risk level
135
+ - **Phase 3:** approach chosen, alternatives rejected, files to create/modify, breaking changes
136
+ - **Phase 4:** acceptance criteria list with PENDING/VERIFIED/FAILED status
137
+ - **Phase 5:** agents active, files created/modified, lines +/-, tests written, sub-phase status
138
+ - **Phase 6:** unit/integration/e2e results, coverage delta, bugs found/fixed, retry count
139
+ - **Phase 7:** review result, critical issues, suggestions, security review, iteration count
140
+ - **Phase 8:** PR number/URL, CI check results, fix iterations
141
+ - **Phase 9:** scenario results (happy/edge/regression/perf/security/a11y), issues found
142
+ - **Phase 10:** QA/business/tech sign-off status with who/when/conditions
143
+ - **Phase 11:** target env, pre-checks, deploy method, health check, rollback needed
144
+ - **Phase 12:** monitoring duration, error rate, latency impact, issues closed
145
+
146
+ ### Blocker Log
147
+ | Timestamp | Blocker | Severity | Owner | Resolved | Resolution |
148
+
149
+ ### Decision Log
150
+ | Timestamp | Decision | Rationale | Made By | Reversible |
151
+
152
+ ### Risk Register
153
+ | Risk | Likelihood | Impact | Mitigation | Status |
154
+
155
+ ### Execution Report Section
156
+ Per-phase and cumulative execution analytics:
157
+ ```markdown
158
+ ## Execution Reports
159
+ | Phase | Score | Hallucination | Regression | Tokens | Agents | Handoffs |
160
+ |-------|-------|---------------|------------|--------|--------|----------|
161
+ | 2 | 85/100 | 0 (CLEAN) | 0 (CLEAN) | ~12k | 2 | 3 |
162
+ | 5 | 72/100 | 1 (MINOR) | 0 (CLEAN) | ~45k | 4 | 8 |
163
+ | 6 | 90/100 | 0 (CLEAN) | 0 (CLEAN) | ~18k | 2 | 4 |
164
+ | ... | | | | | | |
165
+ | **TOTAL** | **82/100** | **1** | **0** | **~120k** | **8** | **24** |
166
+
167
+ ### Bottleneck Analysis
168
+ - Slowest phase: Phase 5 (Development) — 45k tokens, 4 agents
169
+ - Most rework: Phase 7 (Review) — 2 iterations
170
+ - Highest context: Phase 5 — peaked at 58%
171
+
172
+ ### Lessons Learned
173
+ - {Actionable insight for next time}
174
+ ```
175
+
176
+ Full execution reports saved to: `.claude/reports/executions/TASK-{id}_phase-{N}_{timestamp}.md`
177
+ Cumulative report saved to: `.claude/reports/executions/TASK-{id}_final.md`
178
+
179
+ ## Bug Record Format
180
+ ```
181
+ BUG-{task_id}-{number}
182
+ Severity: P0-P4
183
+ Summary, Steps to Reproduce, Expected/Actual, Evidence
184
+ Assigned: @agent-name
185
+ Status: OPEN -> IN_PROGRESS -> FIXED -> QA_VERIFY -> VERIFIED/REOPENED -> CLOSED
186
+ ```
187
+
188
+ ## Directory Structure
189
+ ```
190
+ .claude/tasks/TASK-001.md
191
+ .claude/tasks/TASK-001_changes.log
192
+ .claude/reports/daily/{date}.md
193
+ .claude/reports/weekly/{week}.md
194
+ .claude/reports/executions/TASK-001_phase-2_2026-03-26T100000Z.md
195
+ .claude/reports/executions/TASK-001_final.md
196
+ ```
@@ -0,0 +1,143 @@
1
+ #!/usr/bin/env node
2
+ // SessionStart hook: lightweight drift detection on startup
3
+ // Checks for obvious staleness — full sync requires /sync skill
4
+
5
+ const fs = require('fs');
6
+ const path = require('path');
7
+ const crypto = require('crypto');
8
+
9
+ const claudeDir = path.join(process.cwd(), '.claude');
10
+ const manifestPath = path.join(claudeDir, 'manifest.json');
11
+
12
+ // Only run if .claude/ exists (environment is set up)
13
+ if (!fs.existsSync(claudeDir)) process.exit(0);
14
+
15
+ const warnings = [];
16
+
17
+ // --- 1. Check manifest freshness ---
18
+ let manifest = null;
19
+ let daysSinceSync = Infinity;
20
+
21
+ if (fs.existsSync(manifestPath)) {
22
+ try {
23
+ manifest = JSON.parse(fs.readFileSync(manifestPath, 'utf-8'));
24
+ const lastSync = new Date(manifest.last_sync);
25
+ daysSinceSync = Math.floor((Date.now() - lastSync.getTime()) / (1000 * 60 * 60 * 24));
26
+
27
+ if (daysSinceSync > 14) {
28
+ warnings.push(`DRIFT: Last sync was ${daysSinceSync} days ago. Run /sync --check`);
29
+ }
30
+ } catch (e) {
31
+ warnings.push('DRIFT: manifest.json is corrupted. Run /sync --fix');
32
+ }
33
+ } else {
34
+ // No manifest = never synced — only warn if environment looks established
35
+ const agentsDir = path.join(claudeDir, 'agents');
36
+ if (fs.existsSync(agentsDir) && fs.readdirSync(agentsDir).filter(f => f.endsWith('.md')).length > 0) {
37
+ warnings.push('DRIFT: No manifest.json found. Run /sync --check to create baseline');
38
+ }
39
+ }
40
+
41
+ // --- 2. Quick agent count check ---
42
+ const agentsDir = path.join(claudeDir, 'agents');
43
+ const claudeMdPath = path.join(process.cwd(), 'CLAUDE.md');
44
+
45
+ if (fs.existsSync(agentsDir) && fs.existsSync(claudeMdPath)) {
46
+ const agentFiles = fs.readdirSync(agentsDir).filter(f => f.endsWith('.md'));
47
+ const claudeMd = fs.readFileSync(claudeMdPath, 'utf-8');
48
+
49
+ // Count @agent mentions in CLAUDE.md (only from the Agent Team table)
50
+ const agentTableMatch = claudeMd.match(/## Agent Team[\s\S]*?(?=\n## |$)/);
51
+ const agentSection = agentTableMatch ? agentTableMatch[0] : '';
52
+ const agentMentions = (agentSection.match(/@[\w-]+/g) || [])
53
+ .filter(a => a !== '@imports' && a !== '@path');
54
+ const uniqueMentions = [...new Set(agentMentions)];
55
+
56
+ if (agentFiles.length !== uniqueMentions.length) {
57
+ warnings.push(`DRIFT: ${agentFiles.length} agent files but ${uniqueMentions.length} agents in CLAUDE.md. Run /sync --fix`);
58
+ }
59
+ }
60
+
61
+ // --- 3. Quick dependency file change check ---
62
+ const depFiles = ['package.json', 'go.mod', 'Cargo.toml', 'requirements.txt', 'pyproject.toml', 'Gemfile', 'pom.xml'];
63
+ if (manifest && manifest.tech_stack) {
64
+ for (const depFile of depFiles) {
65
+ const depPath = path.join(process.cwd(), depFile);
66
+ if (fs.existsSync(depPath)) {
67
+ const currentHash = crypto.createHash('sha256')
68
+ .update(fs.readFileSync(depPath))
69
+ .digest('hex')
70
+ .substring(0, 16);
71
+
72
+ const manifestEntry = manifest.tech_stack[depFile];
73
+ if (manifestEntry && manifestEntry.hash && manifestEntry.hash !== currentHash) {
74
+ warnings.push(`DRIFT: ${depFile} changed since last sync. Run /sync --check`);
75
+ break; // One dependency warning is enough
76
+ }
77
+ }
78
+ }
79
+ }
80
+
81
+ // --- 4. Quick hook registration check ---
82
+ const hooksDir = path.join(claudeDir, 'hooks');
83
+ const settingsPath = path.join(claudeDir, 'settings.json');
84
+
85
+ if (fs.existsSync(hooksDir) && fs.existsSync(settingsPath)) {
86
+ try {
87
+ const settings = JSON.parse(fs.readFileSync(settingsPath, 'utf-8'));
88
+ const hookFiles = fs.readdirSync(hooksDir).filter(f => f.endsWith('.js'));
89
+ const registeredHooks = new Set();
90
+
91
+ for (const [event, matchers] of Object.entries(settings.hooks || {})) {
92
+ for (const matcher of matchers) {
93
+ for (const hook of (matcher.hooks || [])) {
94
+ if (hook.type === 'command' && hook.command) {
95
+ const match = hook.command.match(/([\w-]+\.js)/);
96
+ if (match) registeredHooks.add(match[1]);
97
+ }
98
+ }
99
+ }
100
+ }
101
+
102
+ const orphanHooks = hookFiles.filter(f => !registeredHooks.has(f));
103
+ if (orphanHooks.length > 0) {
104
+ warnings.push(`DRIFT: ${orphanHooks.length} hook(s) not registered in settings.json: ${orphanHooks.join(', ')}`);
105
+ }
106
+
107
+ for (const registered of registeredHooks) {
108
+ if (!hookFiles.includes(registered)) {
109
+ warnings.push(`DRIFT: settings.json references ${registered} but file not found`);
110
+ }
111
+ }
112
+ } catch (e) {
113
+ // settings.json parse error — protect-files hook will catch this
114
+ }
115
+ }
116
+
117
+ // --- 5. Quick skill directory check ---
118
+ const skillsDir = path.join(claudeDir, 'skills');
119
+ if (fs.existsSync(skillsDir)) {
120
+ const skillDirs = fs.readdirSync(skillsDir, { withFileTypes: true })
121
+ .filter(e => e.isDirectory())
122
+ .map(e => e.name);
123
+
124
+ for (const skill of skillDirs) {
125
+ const skillMd = path.join(skillsDir, skill, 'SKILL.md');
126
+ if (!fs.existsSync(skillMd)) {
127
+ warnings.push(`DRIFT: Skill directory ${skill}/ exists but has no SKILL.md`);
128
+ }
129
+ }
130
+ }
131
+
132
+ // --- Output warnings ---
133
+ if (warnings.length > 0) {
134
+ console.log('');
135
+ for (const w of warnings) {
136
+ console.log(w);
137
+ }
138
+ if (warnings.length >= 3) {
139
+ console.log(`\n${warnings.length} drift issues detected. Run: /sync --check (for report) or /sync --fix (to auto-repair)`);
140
+ }
141
+ }
142
+
143
+ process.exit(0);
@@ -0,0 +1,114 @@
1
+ #!/usr/bin/env node
2
+ // Stop hook: collect execution metadata and prompt for execution report generation
3
+ // Runs on session Stop to capture final execution state
4
+
5
+ const fs = require('fs');
6
+ const path = require('path');
7
+
8
+ const tasksDir = path.join(process.cwd(), '.claude', 'tasks');
9
+ const reportsDir = path.join(process.cwd(), '.claude', 'reports', 'executions');
10
+
11
+ // Find active task
12
+ let activeTask = null;
13
+ let activeTaskPath = null;
14
+
15
+ try {
16
+ // Ensure reports directory exists
17
+ if (!fs.existsSync(reportsDir)) {
18
+ fs.mkdirSync(reportsDir, { recursive: true });
19
+ }
20
+
21
+ if (fs.existsSync(tasksDir)) {
22
+ const taskFiles = fs.readdirSync(tasksDir).filter(f => f.endsWith('.md'));
23
+ for (const tf of taskFiles) {
24
+ const taskPath = path.join(tasksDir, tf);
25
+ const content = fs.readFileSync(taskPath, 'utf-8');
26
+ if (/status:\s*(DEVELOPING|DEV_TESTING|REVIEWING|CI_PENDING|QA_TESTING)/.test(content)) {
27
+ activeTask = content;
28
+ activeTaskPath = taskPath;
29
+ break;
30
+ }
31
+ }
32
+ }
33
+
34
+ if (!activeTask) {
35
+ // No active task — output minimal execution snapshot
36
+ const snapshot = {
37
+ timestamp: new Date().toISOString(),
38
+ task: 'none',
39
+ status: 'no active task found'
40
+ };
41
+ console.log(`EXECUTION SNAPSHOT: ${JSON.stringify(snapshot)}`);
42
+ process.exit(0);
43
+ }
44
+
45
+ // Extract task metadata
46
+ const idMatch = activeTask.match(/^id:\s*(.+)$/m);
47
+ const titleMatch = activeTask.match(/^title:\s*(.+)$/m);
48
+ const statusMatch = activeTask.match(/^status:\s*(.+)$/m);
49
+ const taskId = idMatch ? idMatch[1].trim() : 'UNKNOWN';
50
+ const taskTitle = titleMatch ? titleMatch[1].trim() : 'UNKNOWN';
51
+ const taskStatus = statusMatch ? statusMatch[1].trim() : 'UNKNOWN';
52
+
53
+ // Count handoffs from handoff log
54
+ const handoffMatches = activeTask.match(/\| \d{4}-\d{2}-\d{2}T.*?\|.*?\|.*?\|.*?\|.*?\|.*?\|/g);
55
+ const handoffCount = handoffMatches ? handoffMatches.length : 0;
56
+
57
+ // Count loop iterations
58
+ const devTestLoop = activeTask.match(/dev-test-loop:\s*iteration\s*(\d+)/);
59
+ const reviewLoop = activeTask.match(/review-loop:\s*iteration\s*(\d+)/);
60
+ const qaBugLoop = activeTask.match(/qa-bug-loop:\s*iteration\s*(\d+)/);
61
+
62
+ // Count agents mentioned in handoff log
63
+ const agentMentions = activeTask.match(/@[\w-]+/g) || [];
64
+ const agentCounts = {};
65
+ for (const agent of agentMentions) {
66
+ agentCounts[agent] = (agentCounts[agent] || 0) + 1;
67
+ }
68
+
69
+ // Read changes log
70
+ const changesLogPath = activeTaskPath.replace(/\.md$/, '_changes.log');
71
+ let filesChanged = 0;
72
+ let changesLog = '';
73
+ if (fs.existsSync(changesLogPath)) {
74
+ changesLog = fs.readFileSync(changesLogPath, 'utf-8');
75
+ filesChanged = changesLog.split('\n').filter(l => l.trim()).length;
76
+ }
77
+
78
+ // Build execution snapshot
79
+ const snapshot = {
80
+ timestamp: new Date().toISOString(),
81
+ task_id: taskId,
82
+ title: taskTitle,
83
+ status: taskStatus,
84
+ agents_used: Object.keys(agentCounts).length,
85
+ agent_breakdown: agentCounts,
86
+ handoffs: handoffCount,
87
+ loops: {
88
+ dev_test: devTestLoop ? parseInt(devTestLoop[1]) : 0,
89
+ review: reviewLoop ? parseInt(reviewLoop[1]) : 0,
90
+ qa_bug: qaBugLoop ? parseInt(qaBugLoop[1]) : 0
91
+ },
92
+ files_changed: filesChanged
93
+ };
94
+
95
+ // Save execution snapshot
96
+ const snapshotPath = path.join(reportsDir, `${taskId}_snapshot_${Date.now()}.json`);
97
+ fs.writeFileSync(snapshotPath, JSON.stringify(snapshot, null, 2));
98
+
99
+ // Output summary for the Stop prompt hook to consume
100
+ console.log(`\nEXECUTION SNAPSHOT for ${taskId}: ${taskTitle}`);
101
+ console.log(` Status: ${taskStatus}`);
102
+ console.log(` Agents used: ${Object.keys(agentCounts).length} (${Object.keys(agentCounts).join(', ')})`);
103
+ console.log(` Handoffs: ${handoffCount}`);
104
+ console.log(` Loops: dev-test=${snapshot.loops.dev_test}, review=${snapshot.loops.review}, qa-bug=${snapshot.loops.qa_bug}`);
105
+ console.log(` Files changed: ${filesChanged}`);
106
+ console.log(` Snapshot saved: ${snapshotPath}`);
107
+ console.log(`\nRun /execution-report ${taskId} for full analysis with success scoring, hallucination check, and regression impact.`);
108
+
109
+ } catch (err) {
110
+ // Non-fatal — don't block session stop
111
+ console.log(`EXECUTION REPORT HOOK: non-fatal error — ${err.message}`);
112
+ }
113
+
114
+ process.exit(0);
@@ -0,0 +1,30 @@
1
+ #!/usr/bin/env node
2
+ // Cross-platform OS notification when Claude needs user approval
3
+ const { execSync } = require('child_process');
4
+
5
+ const MSG = 'Claude Code needs your approval';
6
+
7
+ function tryExec(cmd) {
8
+ try { execSync(cmd, { stdio: 'ignore', timeout: 5000 }); return true; } catch { return false; }
9
+ }
10
+
11
+ function hasCommand(name) {
12
+ try {
13
+ const check = process.platform === 'win32' ? `where ${name}` : `command -v ${name}`;
14
+ execSync(check, { stdio: 'ignore' });
15
+ return true;
16
+ } catch { return false; }
17
+ }
18
+
19
+ if (process.platform === 'darwin') {
20
+ // macOS
21
+ tryExec(`osascript -e 'display notification "${MSG}" with title "Claude Code"'`);
22
+ } else if (process.platform === 'win32') {
23
+ // Windows — non-blocking balloon tip notification
24
+ tryExec(`powershell.exe -NoProfile -Command "[void][System.Reflection.Assembly]::LoadWithPartialName('System.Windows.Forms'); $n=New-Object System.Windows.Forms.NotifyIcon; $n.Icon=[System.Drawing.SystemIcons]::Information; $n.Visible=$true; $n.ShowBalloonTip(3000,'Claude Code','${MSG}',[System.Windows.Forms.ToolTipIcon]::Info); Start-Sleep -Milliseconds 100; $n.Dispose()"`);
25
+ } else {
26
+ // Linux
27
+ if (hasCommand('notify-send')) {
28
+ tryExec(`notify-send "Claude Code" "${MSG}"`);
29
+ }
30
+ }
@@ -0,0 +1,68 @@
1
+ #!/usr/bin/env node
2
+ // PostCompact hook: re-inject critical workflow state after context compaction
3
+ // Compaction can lose loop counters, phase state, and active handoffs — this restores them
4
+
5
+ const fs = require('fs');
6
+ const path = require('path');
7
+
8
+ const tasksDir = path.join(process.cwd(), '.claude', 'tasks');
9
+ if (!fs.existsSync(tasksDir)) process.exit(0);
10
+
11
+ const files = fs.readdirSync(tasksDir).filter(f => f.endsWith('.md'));
12
+ for (const file of files) {
13
+ const filePath = path.join(tasksDir, file);
14
+ const content = fs.readFileSync(filePath, 'utf-8');
15
+
16
+ // Only process active tasks
17
+ if (!/status:\s*(DEVELOPING|DEV_TESTING|REVIEWING|CI_PENDING|QA_TESTING|QA_SIGNOFF|BIZ_SIGNOFF|TECH_SIGNOFF|DEPLOYING)/.test(content)) {
18
+ continue;
19
+ }
20
+
21
+ const id = (content.match(/^id:\s*(.+)$/m) || [])[1] || 'UNKNOWN';
22
+ const title = (content.match(/^title:\s*(.+)$/m) || [])[1] || 'UNKNOWN';
23
+ const status = (content.match(/^status:\s*(.+)$/m) || [])[1] || 'UNKNOWN';
24
+ const assignedTo = (content.match(/^assigned-to:\s*(.+)$/m) || [])[1] || 'unassigned';
25
+
26
+ console.log('');
27
+ console.log('=== CONTEXT RECOVERY (post-compaction) ===');
28
+ console.log(`ACTIVE TASK: ${id} — ${title.trim()}`);
29
+ console.log(`STATUS: ${status.trim()} | ASSIGNED: ${assignedTo.trim()}`);
30
+
31
+ // Extract and re-inject loop state
32
+ const loopSection = content.match(/## Loop State\n([\s\S]*?)(?=\n##|\n$|$)/);
33
+ if (loopSection) {
34
+ console.log('');
35
+ console.log('LOOP STATE (preserved):');
36
+ const lines = loopSection[1].trim().split('\n').filter(l => l.trim().startsWith('-'));
37
+ for (const line of lines) {
38
+ console.log(` ${line.trim()}`);
39
+ }
40
+ }
41
+
42
+ // Extract last handoff
43
+ const handoffLines = content.match(/\| \d{4}-\d{2}-\d{2}T.*?\|.*?\|.*?\|.*?\|.*?\|.*?\|/g);
44
+ if (handoffLines && handoffLines.length > 0) {
45
+ const lastHandoff = handoffLines[handoffLines.length - 1];
46
+ console.log('');
47
+ console.log(`LAST HANDOFF: ${lastHandoff.trim()}`);
48
+ }
49
+
50
+ // Extract blockers
51
+ if (/blocked:\s*Y/i.test(content)) {
52
+ const blockerMatch = content.match(/BLOCKER:\s*(.+)/i);
53
+ console.log('');
54
+ console.log(`BLOCKER: ${blockerMatch ? blockerMatch[1].trim() : 'See task file for details'}`);
55
+ }
56
+
57
+ // Extract open bugs
58
+ const bugMatches = content.match(/BUG-\S+\s*\(P[0-4]\)/g);
59
+ if (bugMatches) {
60
+ console.log('');
61
+ console.log(`OPEN BUGS: ${bugMatches.join(', ')}`);
62
+ }
63
+
64
+ console.log('');
65
+ console.log(`Full state: .claude/tasks/${file}`);
66
+ console.log('=== END RECOVERY ===');
67
+ break; // Only show the first active task
68
+ }
@@ -0,0 +1,43 @@
1
+ #!/usr/bin/env node
2
+ // Post-tool hook: auto-format edited files
3
+ const { execFileSync } = require('child_process');
4
+ const fs = require('fs');
5
+ const path = require('path');
6
+
7
+ // Timeout: exit if stdin hangs
8
+ setTimeout(() => process.exit(0), 10000);
9
+
10
+ let input = '';
11
+ process.stdin.setEncoding('utf-8');
12
+ process.stdin.on('data', chunk => { input += chunk; });
13
+ process.stdin.on('end', () => {
14
+ try {
15
+ const data = JSON.parse(input);
16
+ const file = (data.tool_input && data.tool_input.file_path) || '';
17
+ if (!file || !fs.existsSync(file)) process.exit(0);
18
+
19
+ // Validate file path is within the project directory
20
+ const resolved = path.resolve(file);
21
+ if (!resolved.startsWith(process.cwd())) process.exit(0);
22
+
23
+ const ext = path.extname(file).toLowerCase();
24
+ const formatters = {
25
+ '.ts': ['npx', ['prettier', '--write']],
26
+ '.tsx': ['npx', ['prettier', '--write']],
27
+ '.js': ['npx', ['prettier', '--write']],
28
+ '.jsx': ['npx', ['prettier', '--write']],
29
+ '.json': ['npx', ['prettier', '--write']],
30
+ '.css': ['npx', ['prettier', '--write']],
31
+ '.py': ['black', []],
32
+ '.go': ['gofmt', ['-w']],
33
+ '.rs': ['rustfmt', []],
34
+ };
35
+
36
+ const formatter = formatters[ext];
37
+ if (formatter) {
38
+ const [cmd, args] = formatter;
39
+ try { execFileSync(cmd, [...args, resolved], { stdio: 'ignore', timeout: 10000 }); } catch {}
40
+ }
41
+ } catch {}
42
+ process.exit(0);
43
+ });
@@ -0,0 +1,94 @@
1
+ #!/usr/bin/env node
2
+ // PreCompact hook: save critical state BEFORE compaction destroys conversation history
3
+ // Fires at ~95% context — this is our last chance to preserve state
4
+
5
+ const fs = require('fs');
6
+ const path = require('path');
7
+
8
+ const tasksDir = path.join(process.cwd(), '.claude', 'tasks');
9
+ const reportsDir = path.join(process.cwd(), '.claude', 'reports');
10
+
11
+ if (!fs.existsSync(tasksDir)) process.exit(0);
12
+
13
+ const files = fs.readdirSync(tasksDir).filter(f => f.endsWith('.md'));
14
+ let saved = false;
15
+
16
+ for (const file of files) {
17
+ const filePath = path.join(tasksDir, file);
18
+ const content = fs.readFileSync(filePath, 'utf-8');
19
+
20
+ if (!/status:\s*(DEVELOPING|DEV_TESTING|REVIEWING|CI_PENDING|QA_TESTING|QA_SIGNOFF|BIZ_SIGNOFF|TECH_SIGNOFF|DEPLOYING)/.test(content)) {
21
+ continue;
22
+ }
23
+
24
+ const id = (content.match(/^id:\s*(.+)$/m) || [])[1] || 'UNKNOWN';
25
+ const title = (content.match(/^title:\s*(.+)$/m) || [])[1] || 'UNKNOWN';
26
+ const status = (content.match(/^status:\s*(.+)$/m) || [])[1] || 'UNKNOWN';
27
+
28
+ // Save pre-compaction state snapshot
29
+ const snapshotDir = path.join(reportsDir, 'executions');
30
+ if (!fs.existsSync(snapshotDir)) {
31
+ fs.mkdirSync(snapshotDir, { recursive: true });
32
+ }
33
+
34
+ const snapshot = {
35
+ event: 'pre-compaction',
36
+ timestamp: new Date().toISOString(),
37
+ task_id: id.trim(),
38
+ title: title.trim(),
39
+ status: status.trim(),
40
+ reason: 'Context approaching 95% — auto-compaction imminent',
41
+ preserved: {
42
+ loop_state: extractSection(content, 'Loop State'),
43
+ last_handoff: extractLastHandoff(content),
44
+ open_bugs: extractBugs(content),
45
+ blocked: /blocked:\s*Y/i.test(content)
46
+ }
47
+ };
48
+
49
+ const snapshotPath = path.join(snapshotDir, `${id.trim()}_precompact_${Date.now()}.json`);
50
+ fs.writeFileSync(snapshotPath, JSON.stringify(snapshot, null, 2));
51
+
52
+ // Output critical context for the compaction to preserve
53
+ console.log('');
54
+ console.log('WARNING: Context at ~95% — compaction starting.');
55
+ console.log(`TASK: ${id.trim()} — ${title.trim()} [${status.trim()}]`);
56
+
57
+ if (snapshot.preserved.loop_state) {
58
+ console.log(`LOOPS: ${snapshot.preserved.loop_state}`);
59
+ }
60
+ if (snapshot.preserved.open_bugs) {
61
+ console.log(`BUGS: ${snapshot.preserved.open_bugs}`);
62
+ }
63
+
64
+ console.log('State snapshot saved. PostCompact will re-inject critical state.');
65
+ console.log('');
66
+ console.log('COMPACTION GUIDANCE: Focus on preserving the current phase instructions.');
67
+ console.log('Discard: file contents already read, intermediate exploration results.');
68
+ console.log('Preserve: task requirements, active phase, loop state, pending decisions.');
69
+
70
+ saved = true;
71
+ break;
72
+ }
73
+
74
+ if (!saved) {
75
+ console.log('Context compaction starting. No active task to preserve.');
76
+ }
77
+
78
+ function extractSection(content, header) {
79
+ const match = content.match(new RegExp(`## ${header}\\n([\\s\\S]*?)(?=\\n##|$)`));
80
+ if (!match) return null;
81
+ return match[1].trim().split('\n').filter(l => l.trim().startsWith('-')).map(l => l.trim()).join('; ');
82
+ }
83
+
84
+ function extractLastHandoff(content) {
85
+ const lines = content.match(/\| \d{4}-\d{2}-\d{2}T.*?\|.*?\|.*?\|.*?\|.*?\|.*?\|/g);
86
+ return lines ? lines[lines.length - 1].trim() : null;
87
+ }
88
+
89
+ function extractBugs(content) {
90
+ const bugs = content.match(/BUG-\S+\s*\(P[0-4]\)/g);
91
+ return bugs ? bugs.join(', ') : null;
92
+ }
93
+
94
+ process.exit(0);