forge-workflow 0.0.2 → 0.0.4

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 (175) hide show
  1. package/.claude/commands/dev.md +26 -0
  2. package/.claude/commands/plan.md +141 -9
  3. package/.claude/commands/premerge.md +0 -3
  4. package/.claude/commands/rollback.md +4 -4
  5. package/.claude/commands/ship.md +71 -41
  6. package/.claude/commands/status.md +9 -38
  7. package/.claude/commands/validate.md +47 -2
  8. package/.cline/workflows/dev.md +337 -0
  9. package/.cline/workflows/plan.md +518 -0
  10. package/.cline/workflows/premerge.md +173 -0
  11. package/.cline/workflows/research.md +39 -0
  12. package/.cline/workflows/review.md +439 -0
  13. package/.cline/workflows/rollback.md +718 -0
  14. package/.cline/workflows/ship.md +161 -0
  15. package/.cline/workflows/sonarcloud.md +146 -0
  16. package/.cline/workflows/status.md +45 -0
  17. package/.cline/workflows/validate.md +279 -0
  18. package/.cline/workflows/verify.md +218 -0
  19. package/.codex/config.toml +11 -0
  20. package/.codex/skills/dev/SKILL.md +340 -0
  21. package/.codex/skills/plan/SKILL.md +521 -0
  22. package/.codex/skills/premerge/SKILL.md +176 -0
  23. package/.codex/skills/research/SKILL.md +42 -0
  24. package/.codex/skills/review/SKILL.md +442 -0
  25. package/.codex/skills/rollback/SKILL.md +721 -0
  26. package/.codex/skills/ship/SKILL.md +164 -0
  27. package/.codex/skills/sonarcloud/SKILL.md +149 -0
  28. package/.codex/skills/status/SKILL.md +48 -0
  29. package/.codex/skills/validate/SKILL.md +282 -0
  30. package/.codex/skills/verify/SKILL.md +221 -0
  31. package/.cursor/commands/dev.md +337 -0
  32. package/.cursor/commands/plan.md +518 -0
  33. package/.cursor/commands/premerge.md +173 -0
  34. package/.cursor/commands/research.md +39 -0
  35. package/.cursor/commands/review.md +439 -0
  36. package/.cursor/commands/rollback.md +718 -0
  37. package/.cursor/commands/ship.md +161 -0
  38. package/.cursor/commands/sonarcloud.md +146 -0
  39. package/.cursor/commands/status.md +45 -0
  40. package/.cursor/commands/validate.md +279 -0
  41. package/.cursor/commands/verify.md +218 -0
  42. package/.cursor/hooks/state/continual-learning-index.json +19 -0
  43. package/.cursor/hooks/state/continual-learning.json +8 -0
  44. package/.cursor/rules/permissions-guidance.mdc +37 -0
  45. package/.github/prompts/dev.prompt.md +342 -0
  46. package/.github/prompts/plan.prompt.md +523 -0
  47. package/.github/prompts/premerge.prompt.md +178 -0
  48. package/.github/prompts/research.prompt.md +44 -0
  49. package/.github/prompts/review.prompt.md +444 -0
  50. package/.github/prompts/rollback.prompt.md +723 -0
  51. package/.github/prompts/ship.prompt.md +166 -0
  52. package/.github/prompts/sonarcloud.prompt.md +151 -0
  53. package/.github/prompts/status.prompt.md +50 -0
  54. package/.github/prompts/validate.prompt.md +284 -0
  55. package/.github/prompts/verify.prompt.md +223 -0
  56. package/.kilocode/workflows/dev.md +341 -0
  57. package/.kilocode/workflows/plan.md +522 -0
  58. package/.kilocode/workflows/premerge.md +177 -0
  59. package/.kilocode/workflows/research.md +43 -0
  60. package/.kilocode/workflows/review.md +443 -0
  61. package/.kilocode/workflows/rollback.md +722 -0
  62. package/.kilocode/workflows/ship.md +165 -0
  63. package/.kilocode/workflows/sonarcloud.md +150 -0
  64. package/.kilocode/workflows/status.md +49 -0
  65. package/.kilocode/workflows/validate.md +283 -0
  66. package/.kilocode/workflows/verify.md +222 -0
  67. package/.opencode/commands/dev.md +340 -0
  68. package/.opencode/commands/plan.md +521 -0
  69. package/.opencode/commands/premerge.md +176 -0
  70. package/.opencode/commands/research.md +42 -0
  71. package/.opencode/commands/review.md +442 -0
  72. package/.opencode/commands/rollback.md +721 -0
  73. package/.opencode/commands/ship.md +164 -0
  74. package/.opencode/commands/sonarcloud.md +149 -0
  75. package/.opencode/commands/status.md +48 -0
  76. package/.opencode/commands/validate.md +282 -0
  77. package/.opencode/commands/verify.md +221 -0
  78. package/.roo/commands/dev.md +341 -0
  79. package/.roo/commands/plan.md +522 -0
  80. package/.roo/commands/premerge.md +177 -0
  81. package/.roo/commands/research.md +43 -0
  82. package/.roo/commands/review.md +443 -0
  83. package/.roo/commands/rollback.md +722 -0
  84. package/.roo/commands/ship.md +165 -0
  85. package/.roo/commands/sonarcloud.md +150 -0
  86. package/.roo/commands/status.md +49 -0
  87. package/.roo/commands/validate.md +283 -0
  88. package/.roo/commands/verify.md +222 -0
  89. package/AGENTS.md +7 -1
  90. package/CLAUDE.md +5 -4
  91. package/README.md +21 -19
  92. package/bin/{forge-validate.js → forge-preflight.js} +21 -15
  93. package/bin/forge.js +209 -138
  94. package/docs/AGENT_INSTALL_PROMPT.md +1 -1
  95. package/docs/BEADS_GITHUB_SYNC.md +251 -0
  96. package/docs/ENHANCED_ONBOARDING.md +8 -8
  97. package/docs/EXAMPLES.md +4 -4
  98. package/docs/GREPTILE_SETUP.md +1 -1
  99. package/docs/MANUAL_REVIEW_GUIDE.md +1 -1
  100. package/docs/ROADMAP.md +6 -6
  101. package/docs/SETUP.md +1 -2
  102. package/docs/TOOLCHAIN.md +15 -234
  103. package/docs/VALIDATION.md +11 -11
  104. package/install.sh +33 -39
  105. package/lib/agents-config.js +3 -3
  106. package/lib/commands/plan.js +11 -15
  107. package/lib/commands/recommend.js +2 -2
  108. package/lib/dep-guard/analyzer.js +294 -0
  109. package/lib/dep-guard/behavior-detector.js +98 -0
  110. package/lib/dep-guard/contract-detector.js +162 -0
  111. package/lib/dep-guard/import-detector.js +498 -0
  112. package/lib/dep-guard/path-utils.js +13 -0
  113. package/lib/dep-guard/rubric.js +120 -0
  114. package/lib/dep-guard/task-parser.js +318 -0
  115. package/lib/detect-agent.js +191 -0
  116. package/lib/detect-worktree.js +47 -0
  117. package/lib/file-hash.js +26 -0
  118. package/lib/plugin-catalog.js +18 -28
  119. package/lib/setup-action-log.js +139 -0
  120. package/lib/setup-summary-renderer.js +106 -0
  121. package/lib/setup.js +75 -1
  122. package/lib/workflow-profiles.js +5 -11
  123. package/package.json +17 -7
  124. package/skills/parallel-deep-research/SKILL.md +108 -0
  125. package/skills/parallel-deep-research/evals/README.md +27 -0
  126. package/skills/parallel-deep-research/evals/evals.json +62 -0
  127. package/skills/sonarcloud-analysis/SKILL.md +171 -0
  128. package/skills/sonarcloud-analysis/evals/README.md +27 -0
  129. package/skills/sonarcloud-analysis/evals/evals.json +50 -0
  130. package/skills/sonarcloud-analysis/references/api-reference.md +466 -0
  131. package/docs/WORKFLOW.md +0 -400
  132. package/docs/planning/PROGRESS.md +0 -396
  133. package/docs/plans/.gitkeep +0 -0
  134. package/docs/plans/2026-02-27-forge-test-suite-v2-decisions.md +0 -21
  135. package/docs/plans/2026-02-27-forge-test-suite-v2-design.md +0 -362
  136. package/docs/plans/2026-02-27-forge-test-suite-v2-tasks.md +0 -343
  137. package/docs/plans/2026-03-02-superpowers-gaps-decisions.md +0 -26
  138. package/docs/plans/2026-03-02-superpowers-gaps-design.md +0 -239
  139. package/docs/plans/2026-03-02-superpowers-gaps-tasks.md +0 -260
  140. package/docs/plans/2026-03-04-agent-command-parity-design.md +0 -163
  141. package/docs/plans/2026-03-04-verify-worktree-cleanup-decisions.md +0 -7
  142. package/docs/plans/2026-03-04-verify-worktree-cleanup-design.md +0 -165
  143. package/docs/plans/2026-03-05-forge-uto-decisions.md +0 -6
  144. package/docs/plans/2026-03-05-forge-uto-design.md +0 -116
  145. package/docs/plans/2026-03-05-forge-uto-tasks.md +0 -244
  146. package/docs/plans/2026-03-10-command-creator-and-eval-decisions.md +0 -52
  147. package/docs/plans/2026-03-10-command-creator-and-eval-design.md +0 -350
  148. package/docs/plans/2026-03-10-command-creator-and-eval-tasks.md +0 -426
  149. package/docs/plans/2026-03-10-stale-workflow-refs-decisions.md +0 -8
  150. package/docs/plans/2026-03-10-stale-workflow-refs-design.md +0 -80
  151. package/docs/plans/2026-03-10-stale-workflow-refs-tasks.md +0 -90
  152. package/docs/plans/2026-03-14-beads-plan-context-decisions.md +0 -9
  153. package/docs/plans/2026-03-14-beads-plan-context-design.md +0 -171
  154. package/docs/plans/2026-03-14-beads-plan-context-tasks.md +0 -160
  155. package/docs/plans/2026-03-14-skill-eval-loop-decisions.md +0 -33
  156. package/docs/plans/2026-03-14-skill-eval-loop-design.md +0 -118
  157. package/docs/plans/2026-03-14-skill-eval-loop-results.md +0 -78
  158. package/docs/plans/2026-03-14-skill-eval-loop-tasks.md +0 -160
  159. package/docs/plans/2026-03-15-agent-command-parity-v2-decisions.md +0 -11
  160. package/docs/plans/2026-03-15-agent-command-parity-v2-design.md +0 -145
  161. package/docs/plans/2026-03-15-agent-command-parity-v2-tasks.md +0 -211
  162. package/docs/research/TEMPLATE.md +0 -292
  163. package/docs/research/advanced-testing.md +0 -297
  164. package/docs/research/agent-permissions.md +0 -167
  165. package/docs/research/dependency-chain.md +0 -328
  166. package/docs/research/forge-workflow-v2.md +0 -550
  167. package/docs/research/plugin-architecture.md +0 -772
  168. package/docs/research/pr4-cli-automation.md +0 -326
  169. package/docs/research/premerge-verify-restructure.md +0 -205
  170. package/docs/research/skills-restructure.md +0 -508
  171. package/docs/research/sonarcloud-perfection-plan.md +0 -166
  172. package/docs/research/sonarcloud-quality-gate.md +0 -184
  173. package/docs/research/superpowers-integration.md +0 -403
  174. package/docs/research/superpowers.md +0 -319
  175. package/docs/research/test-environment.md +0 -519
package/bin/forge.js CHANGED
@@ -47,10 +47,17 @@ const VERSION = packageJson.version;
47
47
 
48
48
  // Load PluginManager for discoverable agent architecture
49
49
  const PluginManager = require('../lib/plugin-manager');
50
+ const { scaffoldGithubBeadsSync } = require('../lib/setup');
50
51
 
51
52
  // Load enhanced onboarding modules
52
53
  const contextMerge = require(path.join(packageDir, 'lib', 'context-merge'));
53
54
  const projectDiscovery = require(path.join(packageDir, 'lib', 'project-discovery'));
55
+
56
+ // Load incremental setup modules
57
+ const { detectEnvironment } = require('../lib/detect-agent');
58
+ const { fileMatchesContent } = require('../lib/file-hash');
59
+ const { SetupActionLog } = require('../lib/setup-action-log');
60
+ const { renderSetupSummary } = require('../lib/setup-summary-renderer');
54
61
  // workflowProfiles is loaded but not currently used in the setup flow
55
62
  // const _workflowProfiles = require(path.join(packageDir, 'lib', 'workflow-profiles'));
56
63
 
@@ -58,6 +65,11 @@ const projectDiscovery = require(path.join(packageDir, 'lib', 'project-discovery
58
65
  let projectRoot = process.env.INIT_CWD || process.cwd();
59
66
  const args = process.argv.slice(2);
60
67
 
68
+ // Incremental setup state (set during main() from parsed flags)
69
+ let FORCE_MODE = false;
70
+ let VERBOSE_MODE = false;
71
+ let actionLog = new SetupActionLog();
72
+
61
73
  // Detected package manager
62
74
  let PKG_MANAGER = 'npm';
63
75
 
@@ -251,49 +263,26 @@ function _checkWritePermission(filePath) {
251
263
  }
252
264
  }
253
265
 
254
- const COMMANDS = ['status', 'research', 'plan', 'dev', 'check', 'ship', 'review', 'merge', 'verify', 'rollback'];
255
-
256
- // Code review tool options (reserved for future feature)
257
- const _CODE_REVIEW_TOOLS = {
258
- 'github-code-quality': {
259
- name: 'GitHub Code Quality',
260
- description: 'FREE, built-in - Zero setup required',
261
- recommended: true
262
- },
263
- 'coderabbit': {
264
- name: 'CodeRabbit',
265
- description: 'FREE for open source - Install GitHub App at https://coderabbit.ai'
266
- },
267
- 'greptile': {
268
- name: 'Greptile',
269
- description: 'Paid ($99+/mo) - Enterprise code review',
270
- requiresApiKey: true,
271
- envVar: 'GREPTILE_API_KEY',
272
- getKeyUrl: 'https://greptile.com'
273
- }
274
- };
275
-
276
- // Code quality tool options (reserved for future feature)
277
- const _CODE_QUALITY_TOOLS = {
278
- 'eslint': {
279
- name: 'ESLint only',
280
- description: 'FREE, built-in - No external server required',
281
- recommended: true
282
- },
283
- 'sonarcloud': {
284
- name: 'SonarCloud',
285
- description: '50k LoC free, cloud-hosted',
286
- requiresApiKey: true,
287
- envVars: ['SONAR_TOKEN', 'SONAR_ORGANIZATION', 'SONAR_PROJECT_KEY'],
288
- getKeyUrl: 'https://sonarcloud.io/account/security'
289
- },
290
- 'sonarqube': {
291
- name: 'SonarQube Community',
292
- description: 'FREE, self-hosted, unlimited LoC',
293
- envVars: ['SONARQUBE_URL', 'SONARQUBE_TOKEN'],
294
- dockerCommand: 'docker run -d --name sonarqube -p 9000:9000 sonarqube:community'
295
- }
296
- };
266
+ /**
267
+ * Reads workflow command names from .claude/commands/*.md in the package directory.
268
+ * @returns {string[]} Command names (filenames without .md extension)
269
+ */
270
+ function getWorkflowCommands() {
271
+ const commandsDir = path.join(packageDir, '.claude', 'commands');
272
+ try {
273
+ return fs.readdirSync(commandsDir)
274
+ .filter(f => f.endsWith('.md'))
275
+ .map(f => f.replace(/\.md$/, ''));
276
+ } catch (err) {
277
+ if (err.code === 'ENOENT') {
278
+ console.warn(`Warning: .claude/commands directory not found at ${commandsDir}`);
279
+ } else {
280
+ console.warn(`Warning: failed to read .claude/commands — ${err.code}: ${err.message}`);
281
+ }
282
+ return [];
283
+ }
284
+ }
285
+
297
286
 
298
287
  // Helper function to safely execute commands (no user input)
299
288
  function safeExec(cmd) {
@@ -469,24 +458,23 @@ alwaysApply: true
469
458
 
470
459
  Use these commands via \`/command-name\`:
471
460
 
472
- 1. \`/status\` - Check current context, active work, recent completions
473
- 2. \`/research\` - Deep research with web search, document to docs/research/
474
- 3. \`/plan\` - Create implementation plan, branch, tracking
475
- 4. \`/dev\` - TDD development (RED-GREEN-REFACTOR cycles)
476
- 5. \`/check\` - Validation (type/lint/security/tests)
477
- 6. \`/ship\` - Create PR with full documentation
478
- 7. \`/review\` - Address ALL PR feedback
479
- 8. \`/merge\` - Update docs, merge PR, cleanup
480
- 9. \`/verify\` - Final documentation verification
461
+ - \`/status\` (utility) - Check current context, active work, recent completions
462
+ 1. \`/plan\` - Design intent Q&A, research, branch + task list
463
+ 2. \`/dev\` - Subagent-driven TDD per task (spec + quality review)
464
+ 3. \`/validate\` - Type check, lint, security, tests (HARD-GATE)
465
+ 4. \`/ship\` - Push and create PR with design doc reference
466
+ 5. \`/review\` - Handle ALL PR issues (Actions, Greptile, SonarCloud)
467
+ 6. \`/premerge\` - Complete docs on feature branch, hand off PR to user
468
+ 7. \`/verify\` - Post-merge health check (CI on main, close Beads)
481
469
 
482
470
  See AGENTS.md for full workflow details.
483
471
  `;
484
472
 
485
473
  // Helper functions
486
- const resolvedProjectRoot = path.resolve(projectRoot);
487
474
 
488
475
  function ensureDir(dir) {
489
476
  const fullPath = path.resolve(projectRoot, dir);
477
+ const resolvedProjectRoot = path.resolve(projectRoot);
490
478
 
491
479
  // SECURITY: Prevent path traversal
492
480
  if (!fullPath.startsWith(resolvedProjectRoot)) {
@@ -503,6 +491,7 @@ function ensureDir(dir) {
503
491
  function writeFile(filePath, content) {
504
492
  try {
505
493
  const fullPath = path.resolve(projectRoot, filePath);
494
+ const resolvedProjectRoot = path.resolve(projectRoot);
506
495
 
507
496
  // SECURITY: Prevent path traversal
508
497
  if (!fullPath.startsWith(resolvedProjectRoot)) {
@@ -536,6 +525,7 @@ function readFile(filePath) {
536
525
  function copyFile(src, dest) {
537
526
  try {
538
527
  const destPath = path.resolve(projectRoot, dest);
528
+ const resolvedProjectRoot = path.resolve(projectRoot);
539
529
 
540
530
  // SECURITY: Prevent path traversal
541
531
  if (!destPath.startsWith(resolvedProjectRoot)) {
@@ -544,13 +534,25 @@ function copyFile(src, dest) {
544
534
  }
545
535
 
546
536
  if (fs.existsSync(src)) {
537
+ // Content-hash comparison: skip if destination already matches source
538
+ if (!FORCE_MODE) {
539
+ const sourceContent = fs.readFileSync(src, 'utf8');
540
+ if (fileMatchesContent(destPath, sourceContent)) {
541
+ actionLog.add(dest, 'skipped', 'identical content');
542
+ return true;
543
+ }
544
+ }
545
+
547
546
  const destDir = path.dirname(destPath);
548
547
  if (!fs.existsSync(destDir)) {
549
548
  fs.mkdirSync(destDir, { recursive: true });
550
549
  }
550
+ const isNew = !fs.existsSync(destPath);
551
551
  fs.copyFileSync(src, destPath);
552
+ const action = FORCE_MODE ? 'force-created' : (isNew ? 'created' : 'updated');
553
+ actionLog.add(dest, action);
552
554
  return true;
553
- } else if (process.env.DEBUG) {
555
+ } else {
554
556
  console.warn(` ⚠ Source file not found: ${src}`);
555
557
  }
556
558
  } catch (err) {
@@ -766,7 +768,7 @@ function smartMergeAgentsMd(existingContent, newContent) {
766
768
  merged += forgeSection + '\n\n';
767
769
 
768
770
  // Add footer
769
- merged += `---\n\n## 💡 Improving This Workflow\n\nEvery time you give the same instruction twice, add it to this file:\n1. User-specific rules → Add to USER:START section above\n2. Forge workflow improvements → Suggest to forge maintainers\n\n**Keep this file updated as you learn about the project.**\n\n---\n\nSee \`docs/WORKFLOW.md\` for complete workflow guide.\nSee \`docs/TOOLCHAIN.md\` for comprehensive tool reference.\n`;
771
+ merged += `---\n\n## 💡 Improving This Workflow\n\nEvery time you give the same instruction twice, add it to this file:\n1. User-specific rules → Add to USER:START section above\n2. Forge workflow improvements → Suggest to forge maintainers\n\n**Keep this file updated as you learn about the project.**\n\n---\n\nSee \`AGENTS.md\` for complete workflow guide.\nSee \`docs/TOOLCHAIN.md\` for comprehensive tool reference.\n`;
770
772
 
771
773
  return merged;
772
774
  }
@@ -799,7 +801,6 @@ async function detectProjectStatus() {
799
801
  hasClaudeMd: fs.existsSync(path.join(projectRoot, 'CLAUDE.md')),
800
802
  hasClaudeCommands: fs.existsSync(path.join(projectRoot, '.claude/commands')),
801
803
  hasEnvLocal: fs.existsSync(path.join(projectRoot, '.env.local')),
802
- hasDocsWorkflow: fs.existsSync(path.join(projectRoot, 'docs/WORKFLOW.md')),
803
804
  existingEnvVars: {},
804
805
  agentsMdSize: 0,
805
806
  claudeMdSize: 0,
@@ -832,7 +833,7 @@ async function detectProjectStatus() {
832
833
  }
833
834
 
834
835
  // Determine installation type
835
- if (status.hasAgentsMd && status.hasClaudeCommands && status.hasDocsWorkflow) {
836
+ if (status.hasAgentsMd && status.hasClaudeCommands) {
836
837
  status.type = 'upgrade'; // Full forge installation exists
837
838
  } else if (status.hasClaudeCommands || status.hasEnvLocal) {
838
839
  status.type = 'partial'; // Agent-specific files exist (not just base files from postinstall)
@@ -1764,6 +1765,23 @@ async function configureExternalServices(rl, question, selectedAgents = [], proj
1764
1765
  // Write all tokens to .env.local (preserving existing values)
1765
1766
  const { added, preserved } = writeEnvTokens(tokens, true);
1766
1767
  displayEnvTokenResults(added, preserved);
1768
+
1769
+ // GitHub-Beads issue sync setup
1770
+ console.log('');
1771
+ const enableSync = await askYesNo(question, 'Enable GitHub ↔ Beads issue sync?', true);
1772
+ if (enableSync) {
1773
+ try {
1774
+ const result = await scaffoldGithubBeadsSync(projectRoot, packageDir);
1775
+ for (const f of result.created) {
1776
+ console.log(` Created: ${f}`);
1777
+ }
1778
+ for (const f of result.skipped) {
1779
+ console.log(` Skipped: ${f} (already exists)`);
1780
+ }
1781
+ } catch (err) {
1782
+ console.error(` Error scaffolding GitHub-Beads sync: ${err.message}`);
1783
+ }
1784
+ }
1767
1785
  }
1768
1786
 
1769
1787
  // Display the Forge banner
@@ -1782,40 +1800,28 @@ function showBanner(subtitle = 'Universal AI Agent Workflow') {
1782
1800
  }
1783
1801
  }
1784
1802
 
1785
- // Setup core documentation and directories
1786
- function setupCoreDocs() {
1787
- // Create core directories
1788
- ensureDir('docs/planning');
1789
- ensureDir('docs/research');
1790
-
1791
- // Copy WORKFLOW.md
1792
- const workflowSrc = path.join(packageDir, 'docs/WORKFLOW.md');
1793
- if (copyFile(workflowSrc, 'docs/WORKFLOW.md')) {
1794
- console.log(' Created: docs/WORKFLOW.md');
1795
- }
1796
-
1797
- // Copy research TEMPLATE.md
1798
- const templateSrc = path.join(packageDir, 'docs/research/TEMPLATE.md');
1799
- if (copyFile(templateSrc, 'docs/research/TEMPLATE.md')) {
1800
- console.log(' Created: docs/research/TEMPLATE.md');
1803
+ /**
1804
+ * Creates a directory on first use and prints a one-time purpose note.
1805
+ * @param {string} dir - Absolute path to the directory to create.
1806
+ * @param {string} purpose - Human-readable purpose description.
1807
+ * @returns {string|null} Purpose message if created, null if already existed.
1808
+ */
1809
+ function ensureDirWithNote(dir, purpose) {
1810
+ if (fs.existsSync(dir)) {
1811
+ return null;
1801
1812
  }
1813
+ fs.mkdirSync(dir, { recursive: true });
1814
+ const display = dir.replace(/\\/g, '/');
1815
+ const msg = `Created ${display} for ${purpose}`;
1816
+ console.log(` ${msg}`);
1817
+ return msg;
1818
+ }
1802
1819
 
1803
- // Create PROGRESS.md if not exists
1804
- const progressPath = path.join(projectRoot, 'docs/planning/PROGRESS.md');
1805
- if (!fs.existsSync(progressPath)) {
1806
- writeFile('docs/planning/PROGRESS.md', `# Project Progress
1807
-
1808
- ## Current Focus
1809
- <!-- What you're working on -->
1810
-
1811
- ## Completed
1812
- <!-- Completed features -->
1813
-
1814
- ## Upcoming
1815
- <!-- Next priorities -->
1816
- `);
1817
- console.log(' Created: docs/planning/PROGRESS.md');
1818
- }
1820
+ // Setup core documentation and directories
1821
+ function setupCoreDocs() {
1822
+ // docs/planning/ and docs/research/ are created lazily on first use
1823
+ // by /plan Phase 1 and Phase 2 respectively, via ensureDirWithNote().
1824
+ // TEMPLATE.md and PROGRESS.md are also deferred to first use.
1819
1825
  }
1820
1826
 
1821
1827
  // Minimal installation (postinstall)
@@ -1881,11 +1887,13 @@ function setupClaudeAgent(skipFiles = {}) {
1881
1887
  if (skipFiles.claudeCommands) {
1882
1888
  console.log(' Skipped: .claude/commands/ (keeping existing)');
1883
1889
  } else {
1884
- COMMANDS.forEach(cmd => {
1890
+ const cmds = getWorkflowCommands();
1891
+ let copied = 0;
1892
+ cmds.forEach(cmd => {
1885
1893
  const src = path.join(packageDir, `.claude/commands/${cmd}.md`);
1886
- copyFile(src, `.claude/commands/${cmd}.md`);
1894
+ if (copyFile(src, `.claude/commands/${cmd}.md`)) copied++;
1887
1895
  });
1888
- console.log(' Copied: 9 workflow commands');
1896
+ console.log(` Copied: ${copied} workflow commands`);
1889
1897
  }
1890
1898
 
1891
1899
  // Copy rules
@@ -1930,7 +1938,7 @@ function copyAgentCommands(agent, claudeCommands) {
1930
1938
  const targetDir = agent.dirs[0]; // First dir is commands/workflows
1931
1939
  writeFile(`${targetDir}/${targetFile}`, targetContent);
1932
1940
  });
1933
- console.log(' Converted: 9 workflow commands');
1941
+ console.log(` Converted: ${Object.keys(claudeCommands).length} workflow commands`);
1934
1942
  }
1935
1943
 
1936
1944
  // Helper: Copy rules for agent
@@ -2052,7 +2060,6 @@ function displayInstallationStatus(projectStatus) {
2052
2060
  if (projectStatus.hasAgentsMd) console.log(' - AGENTS.md');
2053
2061
  if (projectStatus.hasClaudeCommands) console.log(' - .claude/commands/');
2054
2062
  if (projectStatus.hasEnvLocal) console.log(' - .env.local');
2055
- if (projectStatus.hasDocsWorkflow) console.log(' - docs/WORKFLOW.md');
2056
2063
  console.log('');
2057
2064
  }
2058
2065
 
@@ -2302,7 +2309,7 @@ function loadClaudeCommands(selectedAgents) {
2302
2309
  return claudeCommands;
2303
2310
  }
2304
2311
 
2305
- COMMANDS.forEach(cmd => {
2312
+ getWorkflowCommands().forEach(cmd => {
2306
2313
  const cmdPath = path.join(projectRoot, `.claude/commands/${cmd}.md`);
2307
2314
  const content = readFile(cmdPath);
2308
2315
  if (content) {
@@ -2332,17 +2339,15 @@ function displaySetupSummary(selectedAgents) {
2332
2339
  console.log('');
2333
2340
  console.log('What\'s installed:');
2334
2341
  console.log(' - AGENTS.md (universal instructions)');
2335
- console.log(' - docs/WORKFLOW.md (full workflow guide)');
2336
- console.log(' - docs/research/TEMPLATE.md (research template)');
2337
- console.log(' - docs/planning/PROGRESS.md (progress tracking)');
2338
2342
 
2343
+ const workflowCount = getWorkflowCommands().length;
2339
2344
  selectedAgents.forEach(key => {
2340
2345
  const agent = AGENTS[key];
2341
2346
  if (agent.linkFile) {
2342
2347
  console.log(` - ${agent.linkFile} (${agent.name})`);
2343
2348
  }
2344
2349
  if (agent.hasCommands) {
2345
- console.log(` - .claude/commands/ (9 workflow commands)`);
2350
+ console.log(` - .claude/commands/ (${workflowCount} workflow commands)`);
2346
2351
  }
2347
2352
  if (agent.hasSkill) {
2348
2353
  const skillDir = agent.dirs.find(d => d.includes('/skills/'));
@@ -2521,11 +2526,15 @@ function parseFlags() {
2521
2526
  agents: null,
2522
2527
  all: false,
2523
2528
  help: false,
2529
+ version: false,
2524
2530
  path: null,
2525
2531
  merge: null, // 'smart'|'preserve'|'replace'
2526
2532
  type: null, // 'critical'|'standard'|'simple'|'hotfix'|'docs'|'refactor'
2527
2533
  interview: false, // Force context interview
2528
2534
  budget: null, // Budget mode for recommend command
2535
+ yes: false, // Non-interactive mode (skip prompts, use defaults)
2536
+ force: false, // Force overwrite even if content is identical
2537
+ verbose: false, // Show file-by-file detail in setup summary
2529
2538
  };
2530
2539
 
2531
2540
  for (let i = 0; i < args.length;) {
@@ -2543,6 +2552,9 @@ function parseFlags() {
2543
2552
  } else if (arg === '--help' || arg === '-h') {
2544
2553
  flags.help = true;
2545
2554
  i++;
2555
+ } else if (arg === '--version' || arg === '-V') {
2556
+ flags.version = true;
2557
+ i++;
2546
2558
  } else if (arg === '--path' || arg === '-p' || arg.startsWith('--path=')) {
2547
2559
  const result = parsePathFlag(args, i);
2548
2560
  flags.path = result.value;
@@ -2559,6 +2571,15 @@ function parseFlags() {
2559
2571
  const result = parseTypeFlag(args, i);
2560
2572
  flags.type = result.value;
2561
2573
  i = result.nextIndex;
2574
+ } else if (arg === '--yes' || arg === '-y') {
2575
+ flags.yes = true;
2576
+ i++;
2577
+ } else if (arg === '--force') {
2578
+ flags.force = true;
2579
+ i++;
2580
+ } else if (arg === '--verbose') {
2581
+ flags.verbose = true;
2582
+ i++;
2562
2583
  } else if (arg === '--interview') {
2563
2584
  flags.interview = true;
2564
2585
  i++;
@@ -2697,7 +2718,7 @@ function showHelp() {
2697
2718
  console.log('Usage:');
2698
2719
  console.log(' npx forge setup [options] Interactive agent configuration');
2699
2720
  console.log(' npx forge recommend Show recommended tools for your project');
2700
- console.log(' npx forge Minimal install (AGENTS.md + docs)');
2721
+ console.log(' npx forge --version Show version');
2701
2722
  console.log('');
2702
2723
  console.log('Options:');
2703
2724
  console.log(' --path, -p <dir> Target project directory (default: current directory)');
@@ -2716,6 +2737,9 @@ function showHelp() {
2716
2737
  console.log(' Options: critical, standard, simple, hotfix, docs, refactor');
2717
2738
  console.log(' --interview Force context interview (gather project information)');
2718
2739
  console.log(' --budget <mode> Budget mode for recommend (free, open-source, startup, professional, custom)');
2740
+ console.log(' --yes, -y Non-interactive setup with sensible defaults');
2741
+ console.log(' Defaults to claude agent, skips prompts');
2742
+ console.log(' --version, -V Show version');
2719
2743
  console.log(' --help, -h Show this help message');
2720
2744
  console.log('');
2721
2745
  console.log('Available agents:');
@@ -2733,6 +2757,8 @@ function showHelp() {
2733
2757
  console.log(' npx forge setup --agents=claude,cursor # Same, different syntax');
2734
2758
  console.log(' npx forge setup --skip-external # No service configuration');
2735
2759
  console.log(' npx forge setup --agents claude --quick # Quick + specific agent');
2760
+ console.log(' npx forge setup --yes # Non-interactive, defaults to claude');
2761
+ console.log(' npx forge setup --yes --agents cursor # Non-interactive, specific agent');
2736
2762
  console.log(' npx forge setup --all --skip-external # All agents, no services');
2737
2763
  console.log(' npx forge setup --merge=smart # Use intelligent merge for existing files');
2738
2764
  console.log(' npx forge setup --type=critical # Set workflow profile manually');
@@ -3314,11 +3340,9 @@ async function quickSetup(selectedAgents, skipExternal) {
3314
3340
  checkPrerequisites();
3315
3341
  console.log('');
3316
3342
 
3317
- // Copy AGENTS.md
3343
+ // Copy AGENTS.md (actionLog tracks it via copyFile)
3318
3344
  const agentsSrc = path.join(packageDir, 'AGENTS.md');
3319
- if (copyFile(agentsSrc, 'AGENTS.md')) {
3320
- console.log(' Created: AGENTS.md (universal standard)');
3321
- }
3345
+ copyFile(agentsSrc, 'AGENTS.md');
3322
3346
  console.log('');
3323
3347
 
3324
3348
  // Setup core documentation
@@ -3342,17 +3366,9 @@ async function quickSetup(selectedAgents, skipExternal) {
3342
3366
  // Configure external services with defaults (unless skipped)
3343
3367
  configureDefaultExternalServices(skipExternal);
3344
3368
 
3345
- // Final summary
3346
- console.log('');
3347
- console.log('==============================================');
3348
- console.log(` Forge v${VERSION} Quick Setup Complete!`);
3349
- console.log('==============================================');
3350
- console.log('');
3351
- console.log('Next steps:');
3352
- console.log(' 1. Start with: /status');
3353
- console.log(' 2. Read the guide: docs/WORKFLOW.md');
3369
+ // Progressive setup summary
3354
3370
  console.log('');
3355
- console.log('Happy shipping!');
3371
+ console.log(renderSetupSummary(actionLog, selectedAgents, VERBOSE_MODE));
3356
3372
  console.log('');
3357
3373
  }
3358
3374
 
@@ -3460,7 +3476,6 @@ function displayExistingInstallation(projectStatus) {
3460
3476
  if (projectStatus.hasAgentsMd) console.log(' - AGENTS.md');
3461
3477
  if (projectStatus.hasClaudeCommands) console.log(' - .claude/commands/');
3462
3478
  if (projectStatus.hasEnvLocal) console.log(' - .env.local');
3463
- if (projectStatus.hasDocsWorkflow) console.log(' - docs/WORKFLOW.md');
3464
3479
  console.log('');
3465
3480
  }
3466
3481
 
@@ -3506,7 +3521,7 @@ function loadAndSetupClaudeCommands(selectedAgents, skipFiles) {
3506
3521
  }
3507
3522
 
3508
3523
  // Then load the commands (from existing or newly created)
3509
- COMMANDS.forEach(cmd => {
3524
+ getWorkflowCommands().forEach(cmd => {
3510
3525
  const cmdPath = path.join(projectRoot, `.claude/commands/${cmd}.md`);
3511
3526
  const content = readFile(cmdPath);
3512
3527
  if (content) {
@@ -3600,6 +3615,15 @@ async function interactiveSetupWithFlags(flags) {
3600
3615
  // Prompt for overwrite decisions
3601
3616
  const skipFiles = await promptForOverwriteDecisions(question, projectStatus);
3602
3617
 
3618
+ // Agent auto-detection (suggests but does not force)
3619
+ const envDetection = detectEnvironment(projectRoot);
3620
+ if (envDetection.activeAgent && envDetection.confidence === 'high') {
3621
+ console.log(` Detected: ${envDetection.activeAgent} (${envDetection.activeAgentSource})`);
3622
+ }
3623
+ if (envDetection.configuredAgents.length > 0) {
3624
+ console.log(` Previously configured: ${envDetection.configuredAgents.join(', ')}`);
3625
+ }
3626
+
3603
3627
  // STEP 1: Agent Selection (delegated to helper)
3604
3628
  const agentKeys = Object.keys(AGENTS);
3605
3629
  const selectedAgents = await promptForAgentSelection(question, agentKeys);
@@ -3686,8 +3710,10 @@ function determineSelectedAgents(flags) {
3686
3710
  return [];
3687
3711
  }
3688
3712
 
3689
- // Helper: Handle setup command in non-quick mode
3690
- async function handleSetupCommand(selectedAgents, flags) {
3713
+ // Shared setup executor used by handleSetupCommand
3714
+ async function executeSetup(config) {
3715
+ const { agents, skipExternal } = config;
3716
+
3691
3717
  showBanner('Installing for specified agents...');
3692
3718
  console.log('');
3693
3719
 
@@ -3695,10 +3721,13 @@ async function handleSetupCommand(selectedAgents, flags) {
3695
3721
  checkPrerequisites();
3696
3722
  console.log('');
3697
3723
 
3698
- // Copy AGENTS.md
3699
- const agentsSrc = path.join(packageDir, 'AGENTS.md');
3700
- if (copyFile(agentsSrc, 'AGENTS.md')) {
3701
- console.log(' Created: AGENTS.md (universal standard)');
3724
+ // Copy AGENTS.md (only if not exists — preserve user customizations; actionLog tracks it)
3725
+ const agentsDest = path.join(projectRoot, 'AGENTS.md');
3726
+ if (fs.existsSync(agentsDest)) {
3727
+ actionLog.add('AGENTS.md', 'skipped', 'already exists');
3728
+ } else {
3729
+ const agentsSrc = path.join(packageDir, 'AGENTS.md');
3730
+ copyFile(agentsSrc, 'AGENTS.md');
3702
3731
  }
3703
3732
  console.log('');
3704
3733
 
@@ -3706,28 +3735,35 @@ async function handleSetupCommand(selectedAgents, flags) {
3706
3735
  setupCoreDocs();
3707
3736
  console.log('');
3708
3737
 
3709
- // Load Claude commands if needed
3710
- const claudeCommands = loadClaudeCommands(selectedAgents);
3738
+ // Load Claude commands use loadAndSetupClaudeCommands when claude is selected
3739
+ // so that .claude/commands/ are seeded before reading them
3740
+ const claudeCommands = agents.includes('claude')
3741
+ ? loadAndSetupClaudeCommands(agents)
3742
+ : loadClaudeCommands(agents);
3711
3743
 
3712
- // Setup agents
3713
- selectedAgents.forEach(agentKey => {
3714
- if (agentKey !== 'claude') {
3715
- setupAgent(agentKey, claudeCommands);
3716
- }
3717
- });
3718
-
3719
- console.log('');
3720
- console.log('Agent configuration complete!');
3744
+ // Setup agents with progress output (setupSelectedAgents skips claude internally
3745
+ // since loadAndSetupClaudeCommands already handled it above)
3746
+ setupSelectedAgents(agents, claudeCommands);
3721
3747
 
3722
3748
  // Install git hooks for TDD enforcement
3723
3749
  console.log('');
3724
3750
  installGitHooks();
3725
3751
 
3726
3752
  // External services (unless skipped)
3727
- await handleExternalServices(flags.skipExternal, selectedAgents);
3753
+ await handleExternalServices(skipExternal, agents);
3728
3754
 
3755
+ // Progressive setup summary
3756
+ console.log('');
3757
+ console.log(renderSetupSummary(actionLog, agents, VERBOSE_MODE));
3729
3758
  console.log('');
3730
- console.log('Done! Get started with: /status');
3759
+ }
3760
+
3761
+ // Helper: Handle setup command in non-quick mode
3762
+ async function handleSetupCommand(selectedAgents, flags) {
3763
+ await executeSetup({
3764
+ agents: selectedAgents,
3765
+ skipExternal: flags.skipExternal,
3766
+ });
3731
3767
  }
3732
3768
 
3733
3769
  // Helper: Handle external services configuration
@@ -3761,33 +3797,66 @@ async function main() {
3761
3797
  const command = args[0];
3762
3798
  const flags = parseFlags();
3763
3799
 
3800
+ // Wire up incremental setup state from parsed flags
3801
+ FORCE_MODE = flags.force;
3802
+ VERBOSE_MODE = flags.verbose;
3803
+ actionLog = new SetupActionLog();
3804
+
3764
3805
  // Show help
3765
3806
  if (flags.help) {
3766
3807
  showHelp();
3767
3808
  return;
3768
3809
  }
3769
3810
 
3811
+ // Show version
3812
+ if (flags.version) {
3813
+ console.log(`Forge v${VERSION}`);
3814
+ return;
3815
+ }
3816
+
3770
3817
  // Handle --path option: change to target directory
3771
3818
  if (flags.path) {
3772
3819
  // Update projectRoot after changing directory to maintain state consistency
3773
3820
  projectRoot = handlePathSetup(flags.path);
3774
3821
  }
3775
3822
 
3823
+ // First-run detection: check if Forge is configured in this project
3824
+ // Skip for: setup (needs to run to configure), recommend (read-only)
3825
+ // Note: help and version already returned above, so no need to check here
3826
+ if (command !== 'setup' && command !== 'recommend') {
3827
+ const agentsMdPath = path.join(projectRoot, 'AGENTS.md');
3828
+ if (!fs.existsSync(agentsMdPath)) {
3829
+ console.error('[FORGE_SETUP_REQUIRED] Forge is not configured in this project.\n');
3830
+ console.error(' Run: npx forge setup');
3831
+ console.error(' Or: npx forge setup --yes (non-interactive)\n');
3832
+ process.exit(1);
3833
+ }
3834
+ }
3835
+
3776
3836
  if (command === 'setup') {
3777
3837
  // Determine agents to install
3778
3838
  let selectedAgents = determineSelectedAgents(flags);
3779
3839
 
3840
+ // Non-interactive mode: --yes defaults to claude agent, skips prompts
3841
+ // Applied before --quick so --quick --yes works correctly
3842
+ if (flags.yes && selectedAgents.length === 0) {
3843
+ selectedAgents = ['claude'];
3844
+ }
3845
+ if (flags.yes) {
3846
+ flags.skipExternal = true;
3847
+ }
3848
+
3780
3849
  // Quick mode
3781
3850
  if (flags.quick) {
3782
- // If no agents specified in quick mode, use all
3783
- if (selectedAgents.length === 0) {
3851
+ // If no explicit agents specified, use all (--yes default doesn't count)
3852
+ if (selectedAgents.length === 0 || (flags.yes && !flags.agents)) {
3784
3853
  selectedAgents = Object.keys(AGENTS);
3785
3854
  }
3786
3855
  await quickSetup(selectedAgents, flags.skipExternal);
3787
3856
  return;
3788
3857
  }
3789
3858
 
3790
- // Agents specified via flag (non-quick mode)
3859
+ // Agents specified via flag or --yes default (non-quick mode)
3791
3860
  if (selectedAgents.length > 0) {
3792
3861
  await handleSetupCommand(selectedAgents, flags);
3793
3862
  return;
@@ -4230,3 +4299,5 @@ if (require.main === module) {
4230
4299
  }
4231
4300
  })();
4232
4301
  }
4302
+
4303
+ module.exports = { getWorkflowCommands, ensureDirWithNote };
@@ -201,7 +201,7 @@ Summarize what was completed for the user:
201
201
  - `/plan <feature-slug>` - Design + research + implementation plan
202
202
  - `/dev` - Start TDD development
203
203
 
204
- **Need help?** Check docs/WORKFLOW.md for full guide
204
+ **Need help?** Check AGENTS.md for full guide
205
205
  ```
206
206
 
207
207
  ---