@vpxa/aikit 0.1.74 → 0.1.75

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 (134) hide show
  1. package/package.json +6 -1
  2. package/packages/cli/dist/index.js +2 -2
  3. package/packages/cli/dist/{init-DQkar6Es.js → init-CuRXmyD9.js} +1 -1
  4. package/packages/cli/dist/scaffold-WMQ2uQ48.js +2 -0
  5. package/packages/cli/dist/{user-CopNWxHP.js → user-vbJwa7x2.js} +1 -1
  6. package/scaffold/dist/adapters/claude-code.mjs +4 -0
  7. package/scaffold/dist/adapters/copilot.mjs +75 -0
  8. package/scaffold/dist/adapters/flows.mjs +1 -0
  9. package/scaffold/dist/adapters/skills.mjs +1 -0
  10. package/scaffold/{compiled → dist/compiled}/flows-data.mjs +304 -446
  11. package/scaffold/{compiled → dist/compiled}/skills-data.mjs +554 -2281
  12. package/scaffold/dist/definitions/agents.mjs +9 -0
  13. package/scaffold/{definitions → dist/definitions}/bodies.mjs +6 -229
  14. package/scaffold/dist/definitions/exclusions.mjs +1 -0
  15. package/scaffold/dist/definitions/hooks.mjs +1 -0
  16. package/scaffold/dist/definitions/models.mjs +1 -0
  17. package/scaffold/dist/definitions/plugins.mjs +1 -0
  18. package/scaffold/{definitions → dist/definitions}/prompts.mjs +9 -149
  19. package/scaffold/{definitions → dist/definitions}/protocols.mjs +9 -37
  20. package/scaffold/dist/definitions/tools.mjs +1 -0
  21. package/packages/cli/dist/scaffold-ukCDW3wQ.js +0 -2
  22. package/scaffold/_preview/agents/Architect-Reviewer-Alpha.agent.md +0 -132
  23. package/scaffold/_preview/agents/Architect-Reviewer-Beta.agent.md +0 -132
  24. package/scaffold/_preview/agents/Code-Reviewer-Alpha.agent.md +0 -112
  25. package/scaffold/_preview/agents/Code-Reviewer-Beta.agent.md +0 -112
  26. package/scaffold/_preview/agents/Debugger.agent.md +0 -412
  27. package/scaffold/_preview/agents/Documenter.agent.md +0 -468
  28. package/scaffold/_preview/agents/Explorer.agent.md +0 -76
  29. package/scaffold/_preview/agents/Frontend.agent.md +0 -440
  30. package/scaffold/_preview/agents/Implementer.agent.md +0 -425
  31. package/scaffold/_preview/agents/Orchestrator.agent.md +0 -452
  32. package/scaffold/_preview/agents/Planner.agent.md +0 -481
  33. package/scaffold/_preview/agents/README.md +0 -57
  34. package/scaffold/_preview/agents/Refactor.agent.md +0 -435
  35. package/scaffold/_preview/agents/Researcher-Alpha.agent.md +0 -151
  36. package/scaffold/_preview/agents/Researcher-Beta.agent.md +0 -152
  37. package/scaffold/_preview/agents/Researcher-Delta.agent.md +0 -153
  38. package/scaffold/_preview/agents/Researcher-Gamma.agent.md +0 -152
  39. package/scaffold/_preview/agents/Security.agent.md +0 -433
  40. package/scaffold/_preview/agents/_shared/architect-reviewer-base.md +0 -104
  41. package/scaffold/_preview/agents/_shared/code-agent-base.md +0 -366
  42. package/scaffold/_preview/agents/_shared/code-reviewer-base.md +0 -87
  43. package/scaffold/_preview/agents/_shared/decision-protocol.md +0 -27
  44. package/scaffold/_preview/agents/_shared/forge-protocol.md +0 -90
  45. package/scaffold/_preview/agents/_shared/researcher-base.md +0 -114
  46. package/scaffold/_preview/agents/templates/adr-template.md +0 -28
  47. package/scaffold/_preview/agents/templates/execution-state.md +0 -26
  48. package/scaffold/_preview/flows/_epilogue/steps/docs-sync/README.md +0 -120
  49. package/scaffold/_preview/flows/aikit-advanced/README.md +0 -70
  50. package/scaffold/_preview/flows/aikit-advanced/steps/design/README.md +0 -178
  51. package/scaffold/_preview/flows/aikit-advanced/steps/execute/README.md +0 -145
  52. package/scaffold/_preview/flows/aikit-advanced/steps/plan/README.md +0 -122
  53. package/scaffold/_preview/flows/aikit-advanced/steps/spec/README.md +0 -121
  54. package/scaffold/_preview/flows/aikit-advanced/steps/task/README.md +0 -119
  55. package/scaffold/_preview/flows/aikit-advanced/steps/verify/README.md +0 -145
  56. package/scaffold/_preview/flows/aikit-basic/README.md +0 -51
  57. package/scaffold/_preview/flows/aikit-basic/steps/assess/README.md +0 -109
  58. package/scaffold/_preview/flows/aikit-basic/steps/design/README.md +0 -116
  59. package/scaffold/_preview/flows/aikit-basic/steps/implement/README.md +0 -131
  60. package/scaffold/_preview/flows/aikit-basic/steps/verify/README.md +0 -123
  61. package/scaffold/_preview/prompts/aikit-ask.prompt.md +0 -13
  62. package/scaffold/_preview/prompts/aikit-debug.prompt.md +0 -15
  63. package/scaffold/_preview/prompts/aikit-design.prompt.md +0 -15
  64. package/scaffold/_preview/prompts/aikit-flow-add.prompt.md +0 -84
  65. package/scaffold/_preview/prompts/aikit-flow-create.prompt.md +0 -80
  66. package/scaffold/_preview/prompts/aikit-flow-manage.prompt.md +0 -24
  67. package/scaffold/_preview/prompts/aikit-implement.prompt.md +0 -17
  68. package/scaffold/_preview/prompts/aikit-plan.prompt.md +0 -15
  69. package/scaffold/_preview/prompts/aikit-review.prompt.md +0 -24
  70. package/scaffold/_preview/skills/adr-skill/SKILL.md +0 -335
  71. package/scaffold/_preview/skills/adr-skill/assets/templates/adr-madr.md +0 -89
  72. package/scaffold/_preview/skills/adr-skill/assets/templates/adr-readme.md +0 -20
  73. package/scaffold/_preview/skills/adr-skill/assets/templates/adr-simple.md +0 -46
  74. package/scaffold/_preview/skills/adr-skill/references/adr-conventions.md +0 -95
  75. package/scaffold/_preview/skills/adr-skill/references/examples.md +0 -193
  76. package/scaffold/_preview/skills/adr-skill/references/review-checklist.md +0 -77
  77. package/scaffold/_preview/skills/adr-skill/references/template-variants.md +0 -52
  78. package/scaffold/_preview/skills/adr-skill/scripts/bootstrap_adr.js +0 -259
  79. package/scaffold/_preview/skills/adr-skill/scripts/new_adr.js +0 -391
  80. package/scaffold/_preview/skills/adr-skill/scripts/set_adr_status.js +0 -169
  81. package/scaffold/_preview/skills/aikit/SKILL.md +0 -754
  82. package/scaffold/_preview/skills/brainstorming/SKILL.md +0 -265
  83. package/scaffold/_preview/skills/brainstorming/spec-document-reviewer-prompt.md +0 -49
  84. package/scaffold/_preview/skills/c4-architecture/SKILL.md +0 -389
  85. package/scaffold/_preview/skills/c4-architecture/references/advanced-patterns.md +0 -552
  86. package/scaffold/_preview/skills/c4-architecture/references/c4-syntax.md +0 -510
  87. package/scaffold/_preview/skills/c4-architecture/references/common-mistakes.md +0 -437
  88. package/scaffold/_preview/skills/c4-architecture/references/html-design-system.md +0 -337
  89. package/scaffold/_preview/skills/c4-architecture/references/html-template.html +0 -627
  90. package/scaffold/_preview/skills/docs/SKILL.md +0 -553
  91. package/scaffold/_preview/skills/docs/references/diataxis-anti-patterns.md +0 -147
  92. package/scaffold/_preview/skills/docs/references/diataxis-compass.md +0 -123
  93. package/scaffold/_preview/skills/docs/references/diataxis-quadrants.md +0 -192
  94. package/scaffold/_preview/skills/docs/references/diataxis-quality.md +0 -76
  95. package/scaffold/_preview/skills/docs/references/diataxis-templates.md +0 -120
  96. package/scaffold/_preview/skills/docs/references/flow-artifacts-guide.md +0 -70
  97. package/scaffold/_preview/skills/docs/references/project-knowledge-gotchas.md +0 -32
  98. package/scaffold/_preview/skills/docs/references/project-knowledge-templates.md +0 -281
  99. package/scaffold/_preview/skills/docs/references/project-knowledge-workflow.md +0 -80
  100. package/scaffold/_preview/skills/frontend-design/SKILL.md +0 -237
  101. package/scaffold/_preview/skills/lesson-learned/SKILL.md +0 -113
  102. package/scaffold/_preview/skills/lesson-learned/references/anti-patterns.md +0 -55
  103. package/scaffold/_preview/skills/lesson-learned/references/se-principles.md +0 -109
  104. package/scaffold/_preview/skills/multi-agents-development/SKILL.md +0 -448
  105. package/scaffold/_preview/skills/multi-agents-development/architecture-review-prompt.md +0 -81
  106. package/scaffold/_preview/skills/multi-agents-development/code-quality-review-prompt.md +0 -91
  107. package/scaffold/_preview/skills/multi-agents-development/implementer-prompt.md +0 -93
  108. package/scaffold/_preview/skills/multi-agents-development/parallel-dispatch-example.md +0 -167
  109. package/scaffold/_preview/skills/multi-agents-development/spec-review-prompt.md +0 -81
  110. package/scaffold/_preview/skills/present/SKILL.md +0 -616
  111. package/scaffold/_preview/skills/react/SKILL.md +0 -309
  112. package/scaffold/_preview/skills/repo-access/SKILL.md +0 -178
  113. package/scaffold/_preview/skills/repo-access/references/error-patterns.md +0 -116
  114. package/scaffold/_preview/skills/repo-access/references/platform-matrix.md +0 -142
  115. package/scaffold/_preview/skills/requirements-clarity/SKILL.md +0 -333
  116. package/scaffold/_preview/skills/session-handoff/SKILL.md +0 -199
  117. package/scaffold/_preview/skills/session-handoff/references/handoff-template.md +0 -139
  118. package/scaffold/_preview/skills/session-handoff/references/resume-checklist.md +0 -80
  119. package/scaffold/_preview/skills/session-handoff/scripts/check_staleness.js +0 -269
  120. package/scaffold/_preview/skills/session-handoff/scripts/create_handoff.js +0 -299
  121. package/scaffold/_preview/skills/session-handoff/scripts/list_handoffs.js +0 -113
  122. package/scaffold/_preview/skills/session-handoff/scripts/validate_handoff.js +0 -241
  123. package/scaffold/_preview/skills/typescript/SKILL.md +0 -405
  124. package/scaffold/adapters/claude-code.mjs +0 -73
  125. package/scaffold/adapters/copilot.mjs +0 -292
  126. package/scaffold/adapters/flows.mjs +0 -27
  127. package/scaffold/adapters/skills.mjs +0 -25
  128. package/scaffold/definitions/agents.mjs +0 -266
  129. package/scaffold/definitions/exclusions.mjs +0 -58
  130. package/scaffold/definitions/hooks.mjs +0 -43
  131. package/scaffold/definitions/models.mjs +0 -84
  132. package/scaffold/definitions/plugins.mjs +0 -147
  133. package/scaffold/definitions/tools.mjs +0 -250
  134. package/scaffold/generate.mjs +0 -92
@@ -1,299 +0,0 @@
1
- #!/usr/bin/env node
2
- /**
3
- * Smart scaffold generator for handoff documents.
4
- *
5
- * Creates a new handoff document with auto-detected metadata:
6
- * - Current timestamp
7
- * - Project path
8
- * - Git branch (if available)
9
- * - Recent git log
10
- * - Modified/staged files
11
- * - Handoff chain linking
12
- *
13
- * Usage:
14
- * node create_handoff.js [task-slug]
15
- * node create_handoff.js "implementing-auth"
16
- * node create_handoff.js "auth-part-2" --continues-from 2024-01-15-auth.md
17
- * node create_handoff.js # auto-generates slug from timestamp
18
- */
19
-
20
- const fs = require('node:fs');
21
- const path = require('node:path');
22
- const { execSync } = require('node:child_process');
23
-
24
- function _die(msg) {
25
- process.stderr.write(`${msg}\n`);
26
- process.exit(1);
27
- }
28
-
29
- function runCmd(cmd, cwd) {
30
- try {
31
- return { ok: true, out: execSync(cmd, { cwd, timeout: 10_000, encoding: 'utf-8' }).trim() };
32
- } catch {
33
- return { ok: false, out: '' };
34
- }
35
- }
36
-
37
- function getGitInfo(projectPath) {
38
- const info = {
39
- isGitRepo: false,
40
- branch: null,
41
- recentCommits: [],
42
- modifiedFiles: [],
43
- stagedFiles: [],
44
- };
45
-
46
- if (!runCmd('git rev-parse --git-dir', projectPath).ok) return info;
47
- info.isGitRepo = true;
48
-
49
- const { ok: bOk, out: branch } = runCmd('git branch --show-current', projectPath);
50
- if (bOk && branch) info.branch = branch;
51
-
52
- const { ok: lOk, out: log } = runCmd('git log --oneline -5 --no-decorate', projectPath);
53
- if (lOk && log) info.recentCommits = log.split('\n');
54
-
55
- const { ok: mOk, out: modified } = runCmd('git diff --name-only', projectPath);
56
- if (mOk && modified) info.modifiedFiles = modified.split('\n');
57
-
58
- const { ok: sOk, out: staged } = runCmd('git diff --name-only --cached', projectPath);
59
- if (sOk && staged) info.stagedFiles = staged.split('\n');
60
-
61
- return info;
62
- }
63
-
64
- function findPreviousHandoffs(projectPath) {
65
- const dir = path.join(projectPath, '.handoffs');
66
- if (!fs.existsSync(dir)) return [];
67
-
68
- const handoffs = [];
69
- for (const name of fs.readdirSync(dir)) {
70
- if (!name.endsWith('.md')) continue;
71
- const fp = path.join(dir, name);
72
-
73
- let title = name;
74
- try {
75
- const content = fs.readFileSync(fp, 'utf-8');
76
- const m = content.match(/^#\s+(?:Handoff:\s*)?(.+)$/m);
77
- if (m) title = m[1].trim();
78
- } catch {
79
- /* ignore */
80
- }
81
-
82
- let date = null;
83
- const dm = name.match(/^(\d{4}-\d{2}-\d{2})-(\d{6})/);
84
- if (dm) {
85
- try {
86
- date = new Date(`${dm[1]}T${dm[2].slice(0, 2)}:${dm[2].slice(2, 4)}:${dm[2].slice(4, 6)}`);
87
- } catch {
88
- /* ignore */
89
- }
90
- }
91
-
92
- handoffs.push({ filename: name, path: fp, title, date });
93
- }
94
-
95
- handoffs.sort((a, b) => (b.date || 0) - (a.date || 0));
96
- return handoffs;
97
- }
98
-
99
- function getPreviousHandoffInfo(projectPath, continuesFrom) {
100
- const handoffs = findPreviousHandoffs(projectPath);
101
-
102
- if (continuesFrom) {
103
- const found = handoffs.find((h) => h.filename.includes(continuesFrom));
104
- return found
105
- ? { exists: true, filename: found.filename, title: found.title }
106
- : { exists: false, filename: continuesFrom, title: 'Not found' };
107
- }
108
-
109
- if (handoffs.length > 0) {
110
- return {
111
- exists: true,
112
- filename: handoffs[0].filename,
113
- title: handoffs[0].title,
114
- suggested: true,
115
- };
116
- }
117
-
118
- return { exists: false };
119
- }
120
-
121
- function sanitizeSlug(slug) {
122
- return slug
123
- .toLowerCase()
124
- .replace(/[\s_]/g, '-')
125
- .replace(/[^a-z0-9-]/g, '');
126
- }
127
-
128
- function generateHandoff(projectPath, slug, continuesFrom) {
129
- const now = new Date();
130
- const timestamp = now.toISOString().replace('T', ' ').slice(0, 19);
131
- const fileTs = `${now.toISOString().slice(0, 10)}-${String(now.getHours()).padStart(2, '0')}${String(now.getMinutes()).padStart(2, '0')}${String(now.getSeconds()).padStart(2, '0')}`;
132
-
133
- if (!slug) slug = 'handoff';
134
- slug = sanitizeSlug(slug);
135
- const filename = `${fileTs}-${slug}.md`;
136
-
137
- const handoffsDir = path.join(projectPath, '.handoffs');
138
- fs.mkdirSync(handoffsDir, { recursive: true });
139
- const filepath = path.join(handoffsDir, filename);
140
-
141
- const git = getGitInfo(projectPath);
142
- const prev = getPreviousHandoffInfo(projectPath, continuesFrom);
143
-
144
- const branchLine = git.branch || '[not a git repo or detached HEAD]';
145
-
146
- const commitsSection =
147
- git.recentCommits.length > 0
148
- ? git.recentCommits.map((c) => ` - ${c}`).join('\n')
149
- : ' - [no recent commits or not a git repo]';
150
-
151
- const allModified = [...new Set([...git.modifiedFiles, ...git.stagedFiles])];
152
- let modifiedSection;
153
- if (allModified.length > 0) {
154
- modifiedSection = allModified
155
- .slice(0, 10)
156
- .map((f) => `| ${f} | [describe changes] | [why changed] |`)
157
- .join('\n');
158
- if (allModified.length > 10)
159
- modifiedSection += `\n| ... and ${allModified.length - 10} more files | | |`;
160
- } else {
161
- modifiedSection = '| [no modified files detected] | | |';
162
- }
163
-
164
- let chainSection;
165
- if (prev.exists) {
166
- chainSection = `## Handoff Chain
167
-
168
- - **Continues from**: [${prev.filename}](./${prev.filename})
169
- - Previous title: ${prev.title || 'Unknown'}
170
- - **Supersedes**: [list any older handoffs this replaces, or "None"]
171
-
172
- > Review the previous handoff for full context before filling this one.`;
173
- } else {
174
- chainSection = `## Handoff Chain
175
-
176
- - **Continues from**: None (fresh start)
177
- - **Supersedes**: None
178
-
179
- > This is the first handoff for this task.`;
180
- }
181
-
182
- const content = `# Handoff: [TASK_TITLE - replace this]
183
-
184
- ## Session Metadata
185
- - Created: ${timestamp}
186
- - Project: ${projectPath}
187
- - Branch: ${branchLine}
188
- - Session duration: [estimate how long you worked]
189
-
190
- ### Recent Commits (for context)
191
- ${commitsSection}
192
-
193
- ${chainSection}
194
-
195
- ## Current State Summary
196
-
197
- [TODO: Write one paragraph describing what was being worked on, current status, and where things left off]
198
-
199
- ## Codebase Understanding
200
-
201
- ### Architecture Overview
202
-
203
- [TODO: Document key architectural insights discovered during this session]
204
-
205
- ### Critical Files
206
-
207
- | File | Purpose | Relevance |
208
- |------|---------|-----------|
209
- | [TODO: Add critical files] | | |
210
-
211
- ### Key Patterns Discovered
212
-
213
- [TODO: Document important patterns, conventions, or idioms found in this codebase]
214
-
215
- ## Work Completed
216
-
217
- ### Tasks Finished
218
-
219
- - [ ] [TODO: List completed tasks]
220
-
221
- ### Files Modified
222
-
223
- | File | Changes | Rationale |
224
- |------|---------|-----------|
225
- ${modifiedSection}
226
-
227
- ### Decisions Made
228
-
229
- | Decision | Options Considered | Rationale |
230
- |----------|-------------------|-----------|
231
- | [TODO: Document key decisions] | | |
232
-
233
- ## Pending Work
234
-
235
- ### Immediate Next Steps
236
-
237
- 1. [TODO: Most critical next action]
238
- 2. [TODO: Second priority]
239
- 3. [TODO: Third priority]
240
-
241
- ### Blockers/Open Questions
242
-
243
- - [ ] [TODO: List blockers or open questions]
244
-
245
- ### Deferred Items
246
-
247
- - [TODO: Items deferred and why]
248
-
249
- ## Context for Resuming Agent
250
-
251
- ### Important Context
252
-
253
- [TODO: Critical information the next agent MUST know]
254
-
255
- ### Assumptions Made
256
-
257
- [TODO: List assumptions that might not be obvious]
258
-
259
- ### Potential Gotchas
260
-
261
- [TODO: Things that could trip up the next agent]
262
-
263
- ## Environment State
264
-
265
- [TODO: Required env vars, running processes, DB state]
266
-
267
- ## Related Resources
268
-
269
- [TODO: Links to docs, PRs, issues, Slack threads]
270
- `;
271
-
272
- fs.writeFileSync(filepath, content, 'utf-8');
273
- return { filepath, filename };
274
- }
275
-
276
- // --- Main ---
277
- const args = process.argv.slice(2);
278
- if (args.includes('--help') || args.includes('-h')) {
279
- console.log('Usage: node create_handoff.js [task-slug] [--continues-from <previous>]');
280
- console.log(' node create_handoff.js "implementing-auth"');
281
- console.log(' node create_handoff.js "auth-part-2" --continues-from 2024-01-15-auth.md');
282
- process.exit(0);
283
- }
284
-
285
- let slug = null;
286
- let continuesFrom = null;
287
- for (let i = 0; i < args.length; i++) {
288
- if (args[i] === '--continues-from' && i + 1 < args.length) {
289
- continuesFrom = args[++i];
290
- } else if (!args[i].startsWith('-')) {
291
- slug = args[i];
292
- }
293
- }
294
-
295
- const cwd = process.cwd();
296
- const { filepath } = generateHandoff(cwd, slug, continuesFrom);
297
- console.log(`Created handoff: ${filepath}`);
298
- console.log(`\nNext: Open the file and fill in all [TODO: ...] sections.`);
299
- console.log(`Then validate: node scripts/validate_handoff.js ${filepath}`);
@@ -1,113 +0,0 @@
1
- #!/usr/bin/env node
2
- /**
3
- * List available handoff documents in the current project.
4
- *
5
- * Searches for handoff documents in .handoffs/ and displays:
6
- * - Filename with date
7
- * - Title extracted from document
8
- * - Status (complete / in progress / needs work)
9
- *
10
- * Usage:
11
- * node list_handoffs.js # List handoffs in current project
12
- * node list_handoffs.js /path # List handoffs in specified path
13
- */
14
-
15
- const fs = require('node:fs');
16
- const path = require('node:path');
17
-
18
- function extractTitle(filepath) {
19
- try {
20
- const content = fs.readFileSync(filepath, 'utf-8');
21
- const m = content.match(/^#\s+(?:Handoff:\s*)?(.+)$/m);
22
- if (m) {
23
- const title = m[1].trim();
24
- if (title.startsWith('[') && title.endsWith(']')) return '[Untitled - needs completion]';
25
- return title.length > 50 ? `${title.slice(0, 50)}...` : title;
26
- }
27
- } catch {
28
- /* ignore */
29
- }
30
- return '[Unable to read title]';
31
- }
32
-
33
- function checkCompletion(filepath) {
34
- try {
35
- const content = fs.readFileSync(filepath, 'utf-8');
36
- const count = (content.match(/\[TODO:/g) || []).length;
37
- if (count === 0) return 'Complete';
38
- if (count <= 3) return `In Progress (${count} TODOs)`;
39
- return `Needs Work (${count} TODOs)`;
40
- } catch {
41
- return 'Unknown';
42
- }
43
- }
44
-
45
- function parseDateFromFilename(filename) {
46
- const m = filename.match(/^(\d{4}-\d{2}-\d{2})-(\d{6})/);
47
- if (m) {
48
- try {
49
- return new Date(`${m[1]}T${m[2].slice(0, 2)}:${m[2].slice(2, 4)}:${m[2].slice(4, 6)}`);
50
- } catch {
51
- /* ignore */
52
- }
53
- }
54
- return null;
55
- }
56
-
57
- function listHandoffs(projectPath) {
58
- const dir = path.join(projectPath, '.handoffs');
59
- if (!fs.existsSync(dir)) return [];
60
-
61
- const handoffs = [];
62
- for (const name of fs.readdirSync(dir)) {
63
- if (!name.endsWith('.md')) continue;
64
- const fp = path.join(dir, name);
65
- const stat = fs.statSync(fp);
66
-
67
- handoffs.push({
68
- path: fp,
69
- filename: name,
70
- title: extractTitle(fp),
71
- status: checkCompletion(fp),
72
- date: parseDateFromFilename(name),
73
- size: stat.size,
74
- });
75
- }
76
-
77
- handoffs.sort((a, b) => (b.date || 0) - (a.date || 0));
78
- return handoffs;
79
- }
80
-
81
- function formatDate(dt) {
82
- if (!dt) return 'Unknown date';
83
- return dt.toISOString().replace('T', ' ').slice(0, 16);
84
- }
85
-
86
- // --- Main ---
87
- const args = process.argv.slice(2);
88
- if (args.includes('--help') || args.includes('-h')) {
89
- console.log('Usage: node list_handoffs.js [project-path]');
90
- process.exit(0);
91
- }
92
-
93
- const projectPath = args[0] || process.cwd();
94
- const handoffs = listHandoffs(projectPath);
95
-
96
- if (handoffs.length === 0) {
97
- console.log('No handoff documents found.');
98
- console.log(`Looked in: ${path.join(projectPath, '.handoffs')}`);
99
- console.log('\nCreate one with: node scripts/create_handoff.js [task-slug]');
100
- process.exit(0);
101
- }
102
-
103
- console.log(`\nFound ${handoffs.length} handoff(s) in ${projectPath}:\n`);
104
- console.log(`${'Date'.padEnd(18)} ${'Status'.padEnd(25)} Title`);
105
- console.log(`${'-'.repeat(18)} ${'-'.repeat(25)} ${'-'.repeat(40)}`);
106
-
107
- for (const h of handoffs) {
108
- console.log(`${formatDate(h.date).padEnd(18)} ${h.status.padEnd(25)} ${h.title}`);
109
- }
110
-
111
- if (args.includes('--json')) {
112
- console.log(`\n${JSON.stringify(handoffs, null, 2)}`);
113
- }
@@ -1,241 +0,0 @@
1
- #!/usr/bin/env node
2
- /**
3
- * Validate a handoff document for completeness and quality.
4
- *
5
- * Checks:
6
- * - No TODO placeholders remaining
7
- * - Required sections present and populated
8
- * - No potential secrets detected
9
- * - Referenced files exist
10
- * - Quality scoring (0-100)
11
- *
12
- * Usage:
13
- * node validate_handoff.js <handoff-file>
14
- * node validate_handoff.js .handoffs/2024-01-15-143022-auth.md
15
- */
16
-
17
- const fs = require('node:fs');
18
- const path = require('node:path');
19
-
20
- // Secret detection patterns
21
- const SECRET_PATTERNS = [
22
- [/["']?[a-zA-Z_]*api[_-]?key["']?\s*[:=]\s*["'][^"']{10,}["']/gi, 'API key'],
23
- [/["']?[a-zA-Z_]*password["']?\s*[:=]\s*["'][^"']+["']/gi, 'Password'],
24
- [/["']?[a-zA-Z_]*secret["']?\s*[:=]\s*["'][^"']{10,}["']/gi, 'Secret'],
25
- [/["']?[a-zA-Z_]*token["']?\s*[:=]\s*["'][^"']{20,}["']/gi, 'Token'],
26
- [/["']?[a-zA-Z_]*private[_-]?key["']?\s*[:=]/gi, 'Private key'],
27
- [/-----BEGIN [A-Z]+ PRIVATE KEY-----/g, 'PEM private key'],
28
- [/mongodb(\+srv)?:\/\/[^/\s]+:[^@\s]+@/gi, 'MongoDB connection string with password'],
29
- [/postgres:\/\/[^/\s]+:[^@\s]+@/gi, 'PostgreSQL connection string with password'],
30
- [/mysql:\/\/[^/\s]+:[^@\s]+@/gi, 'MySQL connection string with password'],
31
- [/Bearer\s+[a-zA-Z0-9_\-.]+/g, 'Bearer token'],
32
- [/ghp_[a-zA-Z0-9]{36}/g, 'GitHub personal access token'],
33
- [/sk-[a-zA-Z0-9]{48}/g, 'OpenAI API key'],
34
- [/xox[baprs]-[a-zA-Z0-9-]+/g, 'Slack token'],
35
- ];
36
-
37
- const REQUIRED_SECTIONS = ['Current State Summary', 'Important Context', 'Immediate Next Steps'];
38
- const RECOMMENDED_SECTIONS = [
39
- 'Architecture Overview',
40
- 'Critical Files',
41
- 'Files Modified',
42
- 'Decisions Made',
43
- 'Assumptions Made',
44
- 'Potential Gotchas',
45
- ];
46
-
47
- function checkTodos(content) {
48
- const todos = content.match(/\[TODO:[^\]]*\]/g) || [];
49
- return { clear: todos.length === 0, todos };
50
- }
51
-
52
- function checkRequiredSections(content) {
53
- const missing = [];
54
- for (const section of REQUIRED_SECTIONS) {
55
- const pattern = new RegExp(
56
- `(?:^|\\n)##?\\s*${section.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}`,
57
- 'i',
58
- );
59
- const match = pattern.exec(content);
60
- if (!match) {
61
- missing.push(`${section} (missing)`);
62
- } else {
63
- const start = match.index + match[0].length;
64
- const nextSection = content.slice(start).search(/\n##?\s+/);
65
- const end = nextSection >= 0 ? start + nextSection : content.length;
66
- const sectionContent = content.slice(start, end).trim();
67
- if (sectionContent.length < 50 || sectionContent.includes('[TODO')) {
68
- missing.push(`${section} (incomplete)`);
69
- }
70
- }
71
- }
72
- return { complete: missing.length === 0, missing };
73
- }
74
-
75
- function checkRecommendedSections(content) {
76
- const missing = [];
77
- for (const section of RECOMMENDED_SECTIONS) {
78
- const pattern = new RegExp(
79
- `(?:^|\\n)##?\\s*${section.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}`,
80
- 'i',
81
- );
82
- if (!pattern.test(content)) missing.push(section);
83
- }
84
- return missing;
85
- }
86
-
87
- function scanForSecrets(content) {
88
- const findings = [];
89
- for (const [pattern, description] of SECRET_PATTERNS) {
90
- const matches = content.match(pattern);
91
- if (matches) findings.push({ description, count: matches.length });
92
- }
93
- return findings;
94
- }
95
-
96
- function checkFileReferences(content, basePath) {
97
- const patterns = [
98
- /\|\s*([a-zA-Z0-9_\-./]+\.[a-zA-Z]+)\s*\|/g,
99
- /`([a-zA-Z0-9_\-./]+\.[a-zA-Z]+(?::\d+)?)`/g,
100
- /(?:^|\s)([a-zA-Z0-9_\-./]+\.[a-zA-Z]+:\d+)/gm,
101
- ];
102
-
103
- const foundFiles = new Set();
104
- for (const pattern of patterns) {
105
- for (const m of content.matchAll(pattern)) {
106
- const filepath = m[1].split(':')[0];
107
- if (filepath && !filepath.startsWith('http') && filepath.includes('/')) {
108
- foundFiles.add(filepath);
109
- }
110
- }
111
- }
112
-
113
- const existing = [];
114
- const missing = [];
115
- for (const f of foundFiles) {
116
- if (fs.existsSync(path.join(basePath, f))) existing.push(f);
117
- else missing.push(f);
118
- }
119
- return { existing, missing };
120
- }
121
-
122
- function calculateScore(todosClear, reqComplete, missingReq, missingRec, secrets, filesMissing) {
123
- let score = 100;
124
-
125
- if (!todosClear) score -= 30;
126
- if (!reqComplete) score -= 10 * missingReq.length;
127
- if (secrets.length > 0) score -= 20;
128
- if (filesMissing.length > 0) score -= 5 * Math.min(filesMissing.length, 4);
129
- score -= 2 * missingRec.length;
130
-
131
- score = Math.max(0, score);
132
-
133
- let rating;
134
- if (score >= 90) rating = 'Excellent - Ready for handoff';
135
- else if (score >= 70) rating = 'Good - Minor improvements suggested';
136
- else if (score >= 50) rating = 'Fair - Needs attention before handoff';
137
- else rating = 'Poor - Significant work needed';
138
-
139
- return { score, rating };
140
- }
141
-
142
- function validateHandoff(filepath) {
143
- if (!fs.existsSync(filepath)) return { error: `File not found: ${filepath}` };
144
-
145
- const content = fs.readFileSync(filepath, 'utf-8');
146
- const basePath = path.resolve(path.dirname(filepath), '..'); // Up from .handoffs/
147
-
148
- const { clear: todosClear, todos } = checkTodos(content);
149
- const { complete: reqComplete, missing: missingReq } = checkRequiredSections(content);
150
- const missingRec = checkRecommendedSections(content);
151
- const secrets = scanForSecrets(content);
152
- const { existing: existingFiles, missing: missingFiles } = checkFileReferences(content, basePath);
153
-
154
- const { score, rating } = calculateScore(
155
- todosClear,
156
- reqComplete,
157
- missingReq,
158
- missingRec,
159
- secrets,
160
- missingFiles,
161
- );
162
-
163
- return {
164
- filepath,
165
- score,
166
- rating,
167
- todosClear,
168
- remainingTodos: todos.slice(0, 5),
169
- todoCount: todos.length,
170
- requiredComplete: reqComplete,
171
- missingRequired: missingReq,
172
- missingRecommended: missingRec,
173
- secretsFound: secrets,
174
- filesVerified: existingFiles.length,
175
- filesMissing: missingFiles.slice(0, 5),
176
- };
177
- }
178
-
179
- function printReport(result) {
180
- if (result.error) {
181
- console.log(`Error: ${result.error}`);
182
- return;
183
- }
184
-
185
- console.log(`\n${'='.repeat(60)}`);
186
- console.log('Handoff Validation Report');
187
- console.log('='.repeat(60));
188
- console.log(`File: ${result.filepath}`);
189
- console.log(`\nQuality Score: ${result.score}/100 - ${result.rating}`);
190
- console.log('='.repeat(60));
191
-
192
- if (result.todosClear) {
193
- console.log('\n[PASS] No TODO placeholders remaining');
194
- } else {
195
- console.log(`\n[FAIL] ${result.todoCount} TODO placeholders found:`);
196
- for (const t of result.remainingTodos) console.log(` - ${t.slice(0, 50)}...`);
197
- }
198
-
199
- if (result.requiredComplete) {
200
- console.log('\n[PASS] All required sections complete');
201
- } else {
202
- console.log('\n[FAIL] Missing/incomplete required sections:');
203
- for (const s of result.missingRequired) console.log(` - ${s}`);
204
- }
205
-
206
- if (result.secretsFound.length === 0) {
207
- console.log('\n[PASS] No potential secrets detected');
208
- } else {
209
- console.log('\n[WARN] Potential secrets detected:');
210
- for (const s of result.secretsFound)
211
- console.log(` - ${s.description} (${s.count} match(es))`);
212
- }
213
-
214
- console.log(
215
- `\n[INFO] File references: ${result.filesVerified} verified, ${result.filesMissing.length} missing`,
216
- );
217
- if (result.filesMissing.length > 0) {
218
- for (const f of result.filesMissing) console.log(` - ${f}`);
219
- }
220
-
221
- if (result.missingRecommended.length > 0) {
222
- console.log('\n[INFO] Missing recommended sections:');
223
- for (const s of result.missingRecommended) console.log(` - ${s}`);
224
- }
225
- }
226
-
227
- // --- Main ---
228
- const args = process.argv.slice(2);
229
- if (args.includes('--help') || args.includes('-h') || args.length === 0) {
230
- console.log('Usage: node validate_handoff.js <handoff-file>');
231
- console.log(' node validate_handoff.js .handoffs/2024-01-15-143022-auth.md');
232
- process.exit(args.length === 0 ? 1 : 0);
233
- }
234
-
235
- if (args.includes('--json')) {
236
- const result = validateHandoff(args.find((a) => !a.startsWith('-')));
237
- console.log(JSON.stringify(result, null, 2));
238
- } else {
239
- const result = validateHandoff(args[0]);
240
- printReport(result);
241
- }