@itz4blitz/agentful 0.3.0 → 0.5.1

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 (94) hide show
  1. package/README.md +139 -10
  2. package/bin/cli.js +1032 -48
  3. package/bin/hooks/README.md +338 -82
  4. package/bin/hooks/analyze-trigger.js +69 -0
  5. package/bin/hooks/block-random-docs.js +77 -0
  6. package/bin/hooks/health-check.js +153 -0
  7. package/bin/hooks/post-agent.js +101 -0
  8. package/bin/hooks/post-feature.js +227 -0
  9. package/bin/hooks/pre-agent.js +118 -0
  10. package/bin/hooks/pre-feature.js +138 -0
  11. package/lib/VALIDATION_README.md +455 -0
  12. package/lib/atomic.js +350 -0
  13. package/lib/ci/claude-action-integration.js +641 -0
  14. package/lib/ci/index.js +10 -0
  15. package/lib/core/CLAUDE_EXECUTOR.md +371 -0
  16. package/lib/core/README.md +321 -0
  17. package/lib/core/analyzer.js +497 -0
  18. package/lib/core/claude-executor.example.js +210 -0
  19. package/lib/core/claude-executor.js +1046 -0
  20. package/lib/core/cli.js +141 -0
  21. package/lib/core/detectors/conventions.js +342 -0
  22. package/lib/core/detectors/framework.js +276 -0
  23. package/lib/core/detectors/index.js +15 -0
  24. package/lib/core/detectors/language.js +199 -0
  25. package/lib/core/detectors/patterns.js +356 -0
  26. package/lib/core/generator.js +626 -0
  27. package/lib/core/index.js +9 -0
  28. package/lib/core/output-parser.example.js +250 -0
  29. package/lib/core/output-parser.js +458 -0
  30. package/lib/core/storage.js +515 -0
  31. package/lib/core/templates.js +556 -0
  32. package/lib/index.js +32 -0
  33. package/lib/init.js +497 -25
  34. package/lib/pipeline/cli.js +423 -0
  35. package/lib/pipeline/engine.js +928 -0
  36. package/lib/pipeline/executor.js +440 -0
  37. package/lib/pipeline/index.js +33 -0
  38. package/lib/pipeline/integrations.js +559 -0
  39. package/lib/pipeline/schemas.js +288 -0
  40. package/lib/presets.js +207 -0
  41. package/lib/remote/client.js +361 -0
  42. package/lib/server/auth.js +286 -0
  43. package/lib/server/client-example.js +190 -0
  44. package/lib/server/executor.js +426 -0
  45. package/lib/server/index.js +469 -0
  46. package/lib/update-helpers.js +505 -0
  47. package/lib/validation.js +460 -0
  48. package/package.json +19 -2
  49. package/template/.claude/agents/architect.md +260 -0
  50. package/template/.claude/agents/backend.md +203 -0
  51. package/template/.claude/agents/fixer.md +244 -0
  52. package/template/.claude/agents/frontend.md +232 -0
  53. package/template/.claude/agents/orchestrator.md +528 -0
  54. package/template/.claude/agents/product-analyzer.md +1130 -0
  55. package/template/.claude/agents/reviewer.md +229 -0
  56. package/template/.claude/agents/tester.md +242 -0
  57. package/{.claude → template/.claude}/commands/agentful-analyze.md +151 -43
  58. package/template/.claude/commands/agentful-decide.md +470 -0
  59. package/{.claude → template/.claude}/commands/agentful-product.md +92 -8
  60. package/template/.claude/commands/agentful-start.md +432 -0
  61. package/{.claude → template/.claude}/commands/agentful-status.md +88 -3
  62. package/template/.claude/commands/agentful-update.md +402 -0
  63. package/template/.claude/commands/agentful-validate.md +369 -0
  64. package/{.claude → template/.claude}/commands/agentful.md +111 -195
  65. package/template/.claude/product/EXAMPLES.md +167 -0
  66. package/{.claude → template/.claude}/settings.json +9 -13
  67. package/{.claude → template/.claude}/skills/conversation/SKILL.md +13 -7
  68. package/template/.claude/skills/deployment/SKILL.md +116 -0
  69. package/template/.claude/skills/product-planning/SKILL.md +463 -0
  70. package/{.claude → template/.claude}/skills/product-tracking/SKILL.md +10 -21
  71. package/template/.claude/skills/testing/SKILL.md +228 -0
  72. package/template/.claude/skills/validation/SKILL.md +650 -0
  73. package/template/CLAUDE.md +84 -16
  74. package/template/bin/hooks/block-random-docs.js +121 -0
  75. package/version.json +1 -1
  76. package/.claude/agents/architect.md +0 -524
  77. package/.claude/agents/backend.md +0 -315
  78. package/.claude/agents/fixer.md +0 -263
  79. package/.claude/agents/frontend.md +0 -274
  80. package/.claude/agents/orchestrator.md +0 -283
  81. package/.claude/agents/product-analyzer.md +0 -799
  82. package/.claude/agents/reviewer.md +0 -332
  83. package/.claude/agents/tester.md +0 -410
  84. package/.claude/commands/agentful-decide.md +0 -214
  85. package/.claude/commands/agentful-start.md +0 -182
  86. package/.claude/commands/agentful-validate.md +0 -127
  87. package/.claude/product/EXAMPLES.md +0 -610
  88. package/.claude/product/README.md +0 -344
  89. package/.claude/skills/validation/SKILL.md +0 -271
  90. package/bin/hooks/analyze-trigger.sh +0 -57
  91. package/bin/hooks/health-check.sh +0 -36
  92. package/template/PRODUCT.md +0 -584
  93. /package/{.claude → template/.claude}/commands/agentful-generate.md +0 -0
  94. /package/{.claude → template/.claude}/product/index.md +0 -0
package/lib/init.js CHANGED
@@ -1,35 +1,72 @@
1
1
  import fs from 'fs/promises';
2
2
  import path from 'path';
3
3
  import { fileURLToPath } from 'url';
4
+ import {
5
+ initializeMetadata,
6
+ recordFileMetadata,
7
+ computeFileHash
8
+ } from './update-helpers.js';
9
+ import { generateHooksConfig } from './presets.js';
4
10
 
5
11
  const __dirname = path.dirname(fileURLToPath(import.meta.url));
6
12
  const TEMPLATE_DIR = path.join(__dirname, '..', 'template');
7
- const CLAUDE_DIR = path.join(__dirname, '..', '.claude');
13
+ const CLAUDE_TEMPLATE_DIR = path.join(__dirname, '..', 'template', '.claude');
14
+ const HOOKS_DIR = path.join(__dirname, '..', 'bin', 'hooks');
15
+ const PACKAGE_ROOT = path.join(__dirname, '..');
8
16
 
9
17
  /**
10
18
  * Initialize agentful in a target project directory
11
19
  * @param {string} targetDir - Target project directory
12
- * @param {Object} options - Initialization options
13
- * @param {boolean} options.includeProduct - Whether to include PRODUCT.md template
20
+ * @param {Object} config - Configuration (optional)
21
+ * @param {string[]} config.agents - Array of agent names to install
22
+ * @param {string[]} config.skills - Array of skill names to install
23
+ * @param {string[]} config.hooks - Array of hook identifiers to configure
24
+ * @param {string[]} config.gates - Array of quality gate identifiers
25
+ * @param {Object} config.techStack - Tech stack configuration
14
26
  * @returns {Promise<{success: boolean, files: string[]}>}
15
27
  */
16
- export async function initProject(targetDir, options = {}) {
17
- const { includeProduct = false } = options;
28
+ export async function initProject(targetDir, config = null) {
18
29
  const createdFiles = [];
19
30
 
20
31
  try {
21
32
  // Ensure target directory exists
22
33
  await fs.access(targetDir);
23
34
 
24
- // 1. Copy .claude/ directory (agents, skills, commands)
35
+ // Read package version for metadata tracking
36
+ const packageJsonPath = path.join(PACKAGE_ROOT, 'package.json');
37
+ const packageJson = JSON.parse(await fs.readFile(packageJsonPath, 'utf-8'));
38
+ const version = packageJson.version;
39
+
40
+ // Initialize metadata tracking
41
+ await initializeMetadata(targetDir, version);
42
+
43
+ // 1. Copy .claude/ directory (agents, skills, commands) from template
25
44
  const claudeTargetDir = path.join(targetDir, '.claude');
26
45
 
27
46
  try {
28
- await fs.access(CLAUDE_DIR);
29
- await copyDirectory(CLAUDE_DIR, claudeTargetDir);
30
- createdFiles.push('.claude/');
31
- } catch (err) {
32
- // .claude directory doesn't exist in package, skip
47
+ await fs.access(CLAUDE_TEMPLATE_DIR);
48
+
49
+ if (config) {
50
+ // Selective installation based on config
51
+ await copySelectiveComponents(CLAUDE_TEMPLATE_DIR, claudeTargetDir, targetDir, config, version);
52
+ createdFiles.push('.claude/ (selective)');
53
+ } else {
54
+ // Full installation (backward compatible)
55
+ await copyDirectoryWithTracking(CLAUDE_TEMPLATE_DIR, claudeTargetDir, targetDir, '.claude', version);
56
+ createdFiles.push('.claude/');
57
+ }
58
+ } catch {
59
+ // .claude template directory doesn't exist in package, skip
60
+ }
61
+
62
+ // Copy hook scripts
63
+ try {
64
+ await fs.access(HOOKS_DIR);
65
+ const targetHooksDir = path.join(targetDir, 'bin', 'hooks');
66
+ await copyDirectoryWithTracking(HOOKS_DIR, targetHooksDir, targetDir, 'bin/hooks', version);
67
+ createdFiles.push('bin/hooks/');
68
+ } catch {
69
+ console.log('Warning: Hook scripts not found, skipping');
33
70
  }
34
71
 
35
72
  // 2. Copy CLAUDE.md template
@@ -39,8 +76,13 @@ export async function initProject(targetDir, options = {}) {
39
76
  try {
40
77
  await fs.access(claudeMdSource);
41
78
  await fs.copyFile(claudeMdSource, claudeMdTarget);
79
+
80
+ // Track CLAUDE.md
81
+ const hash = await computeFileHash(claudeMdTarget);
82
+ await recordFileMetadata(targetDir, 'CLAUDE.md', hash, version);
83
+
42
84
  createdFiles.push('CLAUDE.md');
43
- } catch (err) {
85
+ } catch {
44
86
  // CLAUDE.md template doesn't exist, skip
45
87
  }
46
88
 
@@ -79,19 +121,311 @@ export async function initProject(targetDir, options = {}) {
79
121
  await fs.writeFile(decisionsFile, JSON.stringify(initialDecisions, null, 2));
80
122
  createdFiles.push('.agentful/decisions.json');
81
123
 
82
- // 4. Optionally copy PRODUCT.md template
83
- if (includeProduct) {
84
- const productMdSource = path.join(TEMPLATE_DIR, 'PRODUCT.md');
85
- const productMdTarget = path.join(targetDir, 'PRODUCT.md');
86
-
87
- try {
88
- await fs.access(productMdSource);
89
- await fs.copyFile(productMdSource, productMdTarget);
90
- createdFiles.push('PRODUCT.md');
91
- } catch (err) {
92
- // PRODUCT.md template doesn't exist, skip
93
- }
94
- }
124
+ // Conversation state for natural language interface
125
+ const conversationState = {
126
+ current_phase: 'idle',
127
+ last_message_time: null,
128
+ active_feature: null,
129
+ unresolved_references: [],
130
+ context_history: []
131
+ };
132
+
133
+ await fs.writeFile(
134
+ path.join(agentfulDir, 'conversation-state.json'),
135
+ JSON.stringify(conversationState, null, 2)
136
+ );
137
+ createdFiles.push('.agentful/conversation-state.json');
138
+
139
+ // Conversation history
140
+ const conversationHistory = {
141
+ messages: [],
142
+ created_at: new Date().toISOString()
143
+ };
144
+
145
+ await fs.writeFile(
146
+ path.join(agentfulDir, 'conversation-history.json'),
147
+ JSON.stringify(conversationHistory, null, 2)
148
+ );
149
+ createdFiles.push('.agentful/conversation-history.json');
150
+
151
+ // Agent metrics for lifecycle hooks
152
+ const agentMetrics = {
153
+ invocations: {},
154
+ last_invocation: null,
155
+ feature_hooks: []
156
+ };
157
+
158
+ await fs.writeFile(
159
+ path.join(agentfulDir, 'agent-metrics.json'),
160
+ JSON.stringify(agentMetrics, null, 2)
161
+ );
162
+ createdFiles.push('.agentful/agent-metrics.json');
163
+
164
+ // 4. Create .claude/product/ hierarchical structure
165
+ const productDir = path.join(targetDir, '.claude', 'product');
166
+ await fs.mkdir(productDir, { recursive: true });
167
+
168
+ // Create basic index.md template
169
+ const indexMdContent = `# Product Specification
170
+
171
+ ## Overview
172
+
173
+ [Describe what you're building in 2-3 sentences]
174
+
175
+ Example:
176
+ > A task management application that helps teams collaborate on projects. Users can create projects, add tasks with deadlines, assign team members, and track progress with real-time updates.
177
+
178
+ ## Goals
179
+
180
+ - [ ] [Primary goal 1]
181
+ - [ ] [Primary goal 2]
182
+ - [ ] [Primary goal 3]
183
+
184
+ ## Tech Stack
185
+
186
+ ### Frontend
187
+ - **Framework**: [Next.js 14 / React + Vite / Vue + Nuxt / SvelteKit]
188
+ - **Language**: [TypeScript / JavaScript]
189
+ - **Styling**: [Tailwind CSS / CSS Modules / styled-components / shadcn/ui]
190
+ - **State Management**: [Zustand / Context API / Redux / Jotai]
191
+
192
+ ### Backend
193
+ - **Runtime**: [Node.js / Bun / Deno]
194
+ - **Framework**: [Next.js API Routes / Express / Fastify / NestJS / Hono]
195
+ - **Language**: [TypeScript / JavaScript]
196
+
197
+ ### Database
198
+ - **Database**: [PostgreSQL / MySQL / SQLite / MongoDB / PlanetScale]
199
+ - **ORM**: [Prisma / Drizzle / TypeORM / Mongoose]
200
+
201
+ ### Authentication
202
+ - **Method**: [JWT / NextAuth / Clerk / Auth0 / Lucia]
203
+
204
+ ### Testing
205
+ - **Unit**: [Vitest / Jest]
206
+ - **E2E**: [Playwright / Cypress]
207
+
208
+ ### Deployment
209
+ - **Hosting**: [Vercel / Netlify / Railway / Fly.io]
210
+
211
+ ## Domains
212
+
213
+ Create domain-specific subdirectories under \`.claude/product/domains/\` to organize your features:
214
+
215
+ \`\`\`
216
+ .claude/product/
217
+ ├── index.md (this file)
218
+ ├── README.md
219
+ └── domains/
220
+ ├── authentication/
221
+ │ ├── index.md
222
+ │ └── features/
223
+ │ ├── login.md
224
+ │ └── register.md
225
+ └── user-management/
226
+ ├── index.md
227
+ └── features/
228
+ └── profile.md
229
+ \`\`\`
230
+
231
+ See \`.claude/product/README.md\` for detailed structure guidance.
232
+
233
+ ## Architecture Notes
234
+
235
+ ### Design Patterns
236
+
237
+ - [Any specific patterns to use]
238
+ - [Any patterns to avoid]
239
+
240
+ ### Constraints
241
+
242
+ - [Performance requirements]
243
+ - [Accessibility requirements]
244
+ - [Browser support requirements]
245
+
246
+ ## Third-Party Integrations (Optional)
247
+
248
+ - [API 1]: [Purpose]
249
+ - [API 2]: [Purpose]
250
+
251
+ ## Out of Scope (for MVP)
252
+
253
+ List what you're explicitly NOT building:
254
+
255
+ - [Feature X] - Will add in v2
256
+ - [Feature Y] - Out of scope
257
+ - [Feature Z] - Not needed
258
+
259
+ ## Success Criteria
260
+
261
+ The product is complete when:
262
+
263
+ 1. [All critical features implemented and tested]
264
+ 2. [All tests passing with 80%+ coverage]
265
+ 3. [No TypeScript errors]
266
+ 4. [No security vulnerabilities]
267
+ 5. [Deployed to production]
268
+
269
+ ## Notes
270
+
271
+ [Any additional context, links, or documentation]
272
+
273
+ ---
274
+
275
+ **Tip**: The more detailed your product specification, the better agentful can understand what to build. Include:
276
+ - Clear acceptance criteria
277
+ - User stories for context
278
+ - Technical constraints
279
+ - Examples when helpful
280
+ `;
281
+
282
+ const indexMdPath = path.join(productDir, 'index.md');
283
+ await fs.writeFile(indexMdPath, indexMdContent);
284
+ createdFiles.push('.claude/product/index.md');
285
+
286
+ // Create README.md explaining the structure
287
+ const readmeMdContent = `# Product Structure Guide
288
+
289
+ agentful uses a hierarchical product structure to organize features by domain.
290
+
291
+ ## Structure
292
+
293
+ \`\`\`
294
+ .claude/product/
295
+ ├── index.md # Product overview (name, description, tech stack)
296
+ ├── README.md # This file - documentation about the structure
297
+ └── domains/ # Business domains (create as needed)
298
+ ├── authentication/
299
+ │ ├── index.md # Domain overview
300
+ │ └── features/
301
+ │ ├── login.md
302
+ │ └── register.md
303
+ └── user-management/
304
+ ├── index.md
305
+ └── features/
306
+ └── profile.md
307
+ \`\`\`
308
+
309
+ ## Files Explained
310
+
311
+ ### \`index.md\` (Product Level)
312
+ - Product name and description
313
+ - Tech stack
314
+ - High-level goals
315
+ - List of domains
316
+ - Architecture notes
317
+ - Success criteria
318
+
319
+ ### \`domains/{domain-name}/index.md\` (Domain Level)
320
+ - Domain description and purpose
321
+ - List of features in this domain
322
+ - Domain-specific constraints
323
+ - Dependencies on other domains
324
+
325
+ ### \`domains/{domain-name}/features/{feature-name}.md\` (Feature Level)
326
+ - Feature description
327
+ - Priority (CRITICAL, HIGH, MEDIUM, LOW)
328
+ - Acceptance criteria (checkboxes)
329
+ - User stories
330
+ - Technical notes
331
+ - Subtasks breakdown
332
+
333
+ ## When to Create a Domain
334
+
335
+ Create a new domain when you have:
336
+ - A distinct business area (e.g., authentication, billing, analytics)
337
+ - Multiple related features (e.g., login, register, password reset)
338
+ - Shared logic or data models
339
+ - Clear boundaries from other domains
340
+
341
+ **Example domains:**
342
+ - \`authentication\` - Login, registration, password reset
343
+ - \`user-management\` - Profile, settings, preferences
344
+ - \`purchasing\` - Cart, checkout, orders, payments
345
+ - \`analytics\` - Dashboards, reports, metrics
346
+ - \`content\` - Posts, comments, media uploads
347
+
348
+ ## Example Feature File
349
+
350
+ \`\`\`markdown
351
+ <!-- .claude/product/domains/authentication/features/login.md -->
352
+
353
+ # Feature: User Login
354
+
355
+ **Priority**: CRITICAL
356
+
357
+ **Description**: Allow existing users to authenticate with email and password.
358
+
359
+ ## Acceptance Criteria
360
+
361
+ - [ ] Login form with email and password fields
362
+ - [ ] Client-side validation before submission
363
+ - [ ] API endpoint POST /api/auth/login
364
+ - [ ] Returns JWT token on success
365
+ - [ ] Sets httpOnly cookie with token
366
+ - [ ] Returns 401 for invalid credentials
367
+ - [ ] Rate limited to 10 requests per minute
368
+ - [ ] Account lockout after 5 failed attempts
369
+
370
+ ## User Stories
371
+
372
+ - As a returning user, I want to log in with my credentials so that I can access my account
373
+
374
+ ## Subtasks
375
+
376
+ ### 1. Create login form UI
377
+ **Status**: pending
378
+
379
+ - [ ] Email and password input fields
380
+ - [ ] "Remember me" checkbox
381
+ - [ ] "Forgot password" link
382
+ - [ ] Loading state during authentication
383
+ - [ ] Error message display
384
+
385
+ ### 2. Implement login API endpoint
386
+ **Status**: pending
387
+
388
+ - [ ] Verify email exists in database
389
+ - [ ] Compare hashed password using bcrypt
390
+ - [ ] Generate JWT token with 7-day expiration
391
+ - [ ] Set secure httpOnly cookie
392
+ - [ ] Implement rate limiting
393
+ - [ ] Track failed login attempts
394
+
395
+ ## Technical Notes
396
+
397
+ - Use jose or jsonwebtoken for JWT
398
+ - Store failed attempts in Redis
399
+ - Set cookie flags: httpOnly, secure, sameSite=strict
400
+ \`\`\`
401
+
402
+ ## Priority Levels
403
+
404
+ - **CRITICAL** - Must have for MVP, blocks other features
405
+ - **HIGH** - Important for MVP, should include
406
+ - **MEDIUM** - Nice to have if time permits
407
+ - **LOW** - Future enhancement, not for MVP
408
+
409
+ ## Status Tracking
410
+
411
+ - \`pending\` - Not started
412
+ - \`in-progress\` - Currently being worked on
413
+ - \`complete\` - Done and tested
414
+ - \`blocked\` - Waiting for decision or dependency
415
+
416
+ ## Getting Started
417
+
418
+ 1. Edit \`index.md\` to describe your product
419
+ 2. Create domains under \`domains/\` for major functional areas
420
+ 3. Add features under each domain's \`features/\` directory
421
+ 4. Run \`/agentful-start\` in Claude Code to begin development
422
+
423
+ For more information, see the agentful documentation.
424
+ `;
425
+
426
+ const readmeMdPath = path.join(productDir, 'README.md');
427
+ await fs.writeFile(readmeMdPath, readmeMdContent);
428
+ createdFiles.push('.claude/product/README.md');
95
429
 
96
430
  return {
97
431
  success: true,
@@ -102,6 +436,109 @@ export async function initProject(targetDir, options = {}) {
102
436
  }
103
437
  }
104
438
 
439
+ /**
440
+ * Selectively copy components based on configuration
441
+ * @param {string} src - Source directory
442
+ * @param {string} dest - Destination directory
443
+ * @param {string} targetDir - Project root directory
444
+ * @param {Object} config - Configuration
445
+ * @param {string} version - Package version
446
+ */
447
+ async function copySelectiveComponents(src, dest, targetDir, config, version) {
448
+ // Ensure orchestrator is always included
449
+ if (!config.agents.includes('orchestrator')) {
450
+ config.agents.unshift('orchestrator');
451
+ }
452
+
453
+ // Create base .claude directory
454
+ await fs.mkdir(dest, { recursive: true });
455
+
456
+ // 1. Copy selected agents
457
+ const agentsSourceDir = path.join(src, 'agents');
458
+ const agentsTargetDir = path.join(dest, 'agents');
459
+ await fs.mkdir(agentsTargetDir, { recursive: true });
460
+
461
+ for (const agentName of config.agents) {
462
+ const agentFile = `${agentName}.md`;
463
+ const sourcePath = path.join(agentsSourceDir, agentFile);
464
+ const targetPath = path.join(agentsTargetDir, agentFile);
465
+
466
+ try {
467
+ await fs.copyFile(sourcePath, targetPath);
468
+ const hash = await computeFileHash(targetPath);
469
+ await recordFileMetadata(targetDir, `.claude/agents/${agentFile}`, hash, version);
470
+ } catch (error) {
471
+ console.warn(`Warning: Agent ${agentName} not found, skipping`);
472
+ }
473
+ }
474
+
475
+ // 2. Copy selected skills
476
+ const skillsSourceDir = path.join(src, 'skills');
477
+ const skillsTargetDir = path.join(dest, 'skills');
478
+ await fs.mkdir(skillsTargetDir, { recursive: true });
479
+
480
+ for (const skillName of config.skills) {
481
+ const skillDir = path.join(skillsSourceDir, skillName);
482
+ const targetSkillDir = path.join(skillsTargetDir, skillName);
483
+
484
+ try {
485
+ await copyDirectoryWithTracking(
486
+ skillDir,
487
+ targetSkillDir,
488
+ targetDir,
489
+ `.claude/skills/${skillName}`,
490
+ version
491
+ );
492
+ } catch (error) {
493
+ console.warn(`Warning: Skill ${skillName} not found, skipping`);
494
+ }
495
+ }
496
+
497
+ // 3. Copy all commands (always include core commands)
498
+ const commandsSourceDir = path.join(src, 'commands');
499
+ const commandsTargetDir = path.join(dest, 'commands');
500
+
501
+ try {
502
+ await copyDirectoryWithTracking(
503
+ commandsSourceDir,
504
+ commandsTargetDir,
505
+ targetDir,
506
+ '.claude/commands',
507
+ version
508
+ );
509
+ } catch (error) {
510
+ console.warn('Warning: Commands directory not found, skipping');
511
+ }
512
+
513
+ // 4. Generate settings.json with selected hooks
514
+ const settingsPath = path.join(dest, 'settings.json');
515
+
516
+ const settings = {
517
+ includeCoAuthoredBy: false,
518
+ env: {
519
+ ENABLE_TOOL_SEARCH: 'true'
520
+ },
521
+ hooks: generateHooksConfig(config.hooks || []),
522
+ permissions: {
523
+ deny: [
524
+ 'Bash(rm -rf /)',
525
+ 'Bash(rm -rf ~/.*)',
526
+ 'Bash(rm -rf /.*)',
527
+ 'Bash(dd:*)',
528
+ 'Bash(mkfs:*)'
529
+ ]
530
+ }
531
+ };
532
+
533
+ await fs.writeFile(settingsPath, JSON.stringify(settings, null, 2));
534
+ const hash = await computeFileHash(settingsPath);
535
+ await recordFileMetadata(targetDir, '.claude/settings.json', hash, version);
536
+
537
+ // 5. Create product directory (always included)
538
+ const productDir = path.join(dest, 'product');
539
+ await fs.mkdir(productDir, { recursive: true });
540
+ }
541
+
105
542
  /**
106
543
  * Recursively copy a directory
107
544
  * @param {string} src - Source directory
@@ -128,6 +565,41 @@ export async function copyDirectory(src, dest) {
128
565
  }
129
566
  }
130
567
 
568
+ /**
569
+ * Recursively copy a directory with metadata tracking
570
+ * @param {string} src - Source directory
571
+ * @param {string} dest - Destination directory
572
+ * @param {string} targetDir - Project root directory
573
+ * @param {string} baseRelativePath - Base relative path for tracking (e.g., '.claude', 'bin/hooks')
574
+ * @param {string} version - Package version
575
+ */
576
+ export async function copyDirectoryWithTracking(src, dest, targetDir, baseRelativePath, version) {
577
+ // Create destination directory
578
+ await fs.mkdir(dest, { recursive: true });
579
+
580
+ // Read source directory
581
+ const entries = await fs.readdir(src, { withFileTypes: true });
582
+
583
+ for (const entry of entries) {
584
+ const srcPath = path.join(src, entry.name);
585
+ const destPath = path.join(dest, entry.name);
586
+
587
+ if (entry.isDirectory()) {
588
+ // Recursively copy subdirectory
589
+ const newBaseRelativePath = path.join(baseRelativePath, entry.name);
590
+ await copyDirectoryWithTracking(srcPath, destPath, targetDir, newBaseRelativePath, version);
591
+ } else {
592
+ // Copy file
593
+ await fs.copyFile(srcPath, destPath);
594
+
595
+ // Compute hash and track file
596
+ const relativePath = path.join(baseRelativePath, entry.name);
597
+ const hash = await computeFileHash(destPath);
598
+ await recordFileMetadata(targetDir, relativePath, hash, version);
599
+ }
600
+ }
601
+ }
602
+
131
603
  /**
132
604
  * Check if project is already initialized
133
605
  * @param {string} targetDir - Target project directory