popeye-cli 1.5.0 → 1.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (161) hide show
  1. package/CHANGELOG.md +54 -0
  2. package/README.md +50 -8
  3. package/dist/cli/commands/create.d.ts.map +1 -1
  4. package/dist/cli/commands/create.js +54 -4
  5. package/dist/cli/commands/create.js.map +1 -1
  6. package/dist/cli/interactive.d.ts +29 -0
  7. package/dist/cli/interactive.d.ts.map +1 -1
  8. package/dist/cli/interactive.js +90 -7
  9. package/dist/cli/interactive.js.map +1 -1
  10. package/dist/generators/all.d.ts +4 -1
  11. package/dist/generators/all.d.ts.map +1 -1
  12. package/dist/generators/all.js +36 -316
  13. package/dist/generators/all.js.map +1 -1
  14. package/dist/generators/doc-parser.d.ts +18 -3
  15. package/dist/generators/doc-parser.d.ts.map +1 -1
  16. package/dist/generators/doc-parser.js +81 -10
  17. package/dist/generators/doc-parser.js.map +1 -1
  18. package/dist/generators/frontend-design-analyzer.d.ts +30 -0
  19. package/dist/generators/frontend-design-analyzer.d.ts.map +1 -0
  20. package/dist/generators/frontend-design-analyzer.js +208 -0
  21. package/dist/generators/frontend-design-analyzer.js.map +1 -0
  22. package/dist/generators/shared-packages.d.ts +45 -0
  23. package/dist/generators/shared-packages.d.ts.map +1 -0
  24. package/dist/generators/shared-packages.js +456 -0
  25. package/dist/generators/shared-packages.js.map +1 -0
  26. package/dist/generators/templates/index.d.ts +4 -0
  27. package/dist/generators/templates/index.d.ts.map +1 -1
  28. package/dist/generators/templates/index.js +4 -0
  29. package/dist/generators/templates/index.js.map +1 -1
  30. package/dist/generators/templates/website-components.d.ts.map +1 -1
  31. package/dist/generators/templates/website-components.js +36 -11
  32. package/dist/generators/templates/website-components.js.map +1 -1
  33. package/dist/generators/templates/website-config.d.ts +15 -1
  34. package/dist/generators/templates/website-config.d.ts.map +1 -1
  35. package/dist/generators/templates/website-config.js +155 -13
  36. package/dist/generators/templates/website-config.js.map +1 -1
  37. package/dist/generators/templates/website-landing.d.ts +24 -0
  38. package/dist/generators/templates/website-landing.d.ts.map +1 -0
  39. package/dist/generators/templates/website-landing.js +276 -0
  40. package/dist/generators/templates/website-landing.js.map +1 -0
  41. package/dist/generators/templates/website-layout.d.ts +42 -0
  42. package/dist/generators/templates/website-layout.d.ts.map +1 -0
  43. package/dist/generators/templates/website-layout.js +408 -0
  44. package/dist/generators/templates/website-layout.js.map +1 -0
  45. package/dist/generators/templates/website-pricing.d.ts +11 -0
  46. package/dist/generators/templates/website-pricing.d.ts.map +1 -0
  47. package/dist/generators/templates/website-pricing.js +313 -0
  48. package/dist/generators/templates/website-pricing.js.map +1 -0
  49. package/dist/generators/templates/website-sections.d.ts +102 -0
  50. package/dist/generators/templates/website-sections.d.ts.map +1 -0
  51. package/dist/generators/templates/website-sections.js +444 -0
  52. package/dist/generators/templates/website-sections.js.map +1 -0
  53. package/dist/generators/templates/website.d.ts +10 -50
  54. package/dist/generators/templates/website.d.ts.map +1 -1
  55. package/dist/generators/templates/website.js +12 -788
  56. package/dist/generators/templates/website.js.map +1 -1
  57. package/dist/generators/website-content-scanner.d.ts +37 -0
  58. package/dist/generators/website-content-scanner.d.ts.map +1 -0
  59. package/dist/generators/website-content-scanner.js +165 -0
  60. package/dist/generators/website-content-scanner.js.map +1 -0
  61. package/dist/generators/website-context.d.ts +38 -2
  62. package/dist/generators/website-context.d.ts.map +1 -1
  63. package/dist/generators/website-context.js +179 -19
  64. package/dist/generators/website-context.js.map +1 -1
  65. package/dist/generators/website-debug.d.ts +68 -0
  66. package/dist/generators/website-debug.d.ts.map +1 -0
  67. package/dist/generators/website-debug.js +93 -0
  68. package/dist/generators/website-debug.js.map +1 -0
  69. package/dist/generators/website.d.ts +2 -0
  70. package/dist/generators/website.d.ts.map +1 -1
  71. package/dist/generators/website.js +66 -4
  72. package/dist/generators/website.js.map +1 -1
  73. package/dist/generators/workspace-root.d.ts +27 -0
  74. package/dist/generators/workspace-root.d.ts.map +1 -0
  75. package/dist/generators/workspace-root.js +100 -0
  76. package/dist/generators/workspace-root.js.map +1 -0
  77. package/dist/state/index.d.ts +8 -0
  78. package/dist/state/index.d.ts.map +1 -1
  79. package/dist/state/index.js +10 -0
  80. package/dist/state/index.js.map +1 -1
  81. package/dist/types/workflow.d.ts +6 -0
  82. package/dist/types/workflow.d.ts.map +1 -1
  83. package/dist/types/workflow.js +2 -0
  84. package/dist/types/workflow.js.map +1 -1
  85. package/dist/upgrade/handlers.d.ts +15 -0
  86. package/dist/upgrade/handlers.d.ts.map +1 -1
  87. package/dist/upgrade/handlers.js +52 -0
  88. package/dist/upgrade/handlers.js.map +1 -1
  89. package/dist/workflow/auto-fix-bundler.d.ts +37 -0
  90. package/dist/workflow/auto-fix-bundler.d.ts.map +1 -0
  91. package/dist/workflow/auto-fix-bundler.js +320 -0
  92. package/dist/workflow/auto-fix-bundler.js.map +1 -0
  93. package/dist/workflow/auto-fix.d.ts.map +1 -1
  94. package/dist/workflow/auto-fix.js +10 -3
  95. package/dist/workflow/auto-fix.js.map +1 -1
  96. package/dist/workflow/index.d.ts +1 -0
  97. package/dist/workflow/index.d.ts.map +1 -1
  98. package/dist/workflow/index.js +12 -0
  99. package/dist/workflow/index.js.map +1 -1
  100. package/dist/workflow/overview.d.ts.map +1 -1
  101. package/dist/workflow/overview.js +4 -0
  102. package/dist/workflow/overview.js.map +1 -1
  103. package/dist/workflow/plan-mode.d.ts +4 -3
  104. package/dist/workflow/plan-mode.d.ts.map +1 -1
  105. package/dist/workflow/plan-mode.js +69 -5
  106. package/dist/workflow/plan-mode.js.map +1 -1
  107. package/dist/workflow/website-strategy.d.ts +9 -0
  108. package/dist/workflow/website-strategy.d.ts.map +1 -1
  109. package/dist/workflow/website-strategy.js +73 -1
  110. package/dist/workflow/website-strategy.js.map +1 -1
  111. package/dist/workflow/website-updater.d.ts.map +1 -1
  112. package/dist/workflow/website-updater.js +15 -4
  113. package/dist/workflow/website-updater.js.map +1 -1
  114. package/package.json +1 -1
  115. package/src/cli/commands/create.ts +58 -4
  116. package/src/cli/interactive.ts +96 -7
  117. package/src/generators/all.ts +44 -332
  118. package/src/generators/doc-parser.ts +87 -10
  119. package/src/generators/frontend-design-analyzer.ts +261 -0
  120. package/src/generators/shared-packages.ts +500 -0
  121. package/src/generators/templates/index.ts +4 -0
  122. package/src/generators/templates/website-components.ts +36 -11
  123. package/src/generators/templates/website-config.ts +166 -13
  124. package/src/generators/templates/website-landing.ts +331 -0
  125. package/src/generators/templates/website-layout.ts +443 -0
  126. package/src/generators/templates/website-pricing.ts +330 -0
  127. package/src/generators/templates/website-sections.ts +541 -0
  128. package/src/generators/templates/website.ts +38 -851
  129. package/src/generators/website-content-scanner.ts +208 -0
  130. package/src/generators/website-context.ts +248 -20
  131. package/src/generators/website-debug.ts +130 -0
  132. package/src/generators/website.ts +71 -3
  133. package/src/generators/workspace-root.ts +113 -0
  134. package/src/state/index.ts +14 -0
  135. package/src/types/workflow.ts +6 -0
  136. package/src/upgrade/handlers.ts +65 -0
  137. package/src/workflow/auto-fix-bundler.ts +392 -0
  138. package/src/workflow/auto-fix.ts +11 -3
  139. package/src/workflow/index.ts +12 -0
  140. package/src/workflow/overview.ts +6 -0
  141. package/src/workflow/plan-mode.ts +81 -7
  142. package/src/workflow/website-strategy.ts +75 -1
  143. package/src/workflow/website-updater.ts +17 -6
  144. package/tests/cli/project-naming.test.ts +136 -0
  145. package/tests/generators/doc-parser.test.ts +121 -0
  146. package/tests/generators/frontend-design-analyzer.test.ts +90 -0
  147. package/tests/generators/quality-gate.test.ts +183 -0
  148. package/tests/generators/shared-packages.test.ts +83 -0
  149. package/tests/generators/website-components.test.ts +1 -1
  150. package/tests/generators/website-config.test.ts +84 -0
  151. package/tests/generators/website-content-scanner.test.ts +181 -0
  152. package/tests/generators/website-context.test.ts +109 -0
  153. package/tests/generators/website-debug.test.ts +77 -0
  154. package/tests/generators/website-landing.test.ts +188 -0
  155. package/tests/generators/website-pricing.test.ts +98 -0
  156. package/tests/generators/website-sections.test.ts +245 -0
  157. package/tests/generators/workspace-root.test.ts +105 -0
  158. package/tests/upgrade/handlers.test.ts +162 -0
  159. package/tests/workflow/auto-fix-bundler.test.ts +242 -0
  160. package/tests/workflow/plan-mode.test.ts +111 -1
  161. package/tests/workflow/website-strategy.test.ts +55 -0
@@ -6,8 +6,11 @@
6
6
  import { promises as fs } from 'node:fs';
7
7
  import path from 'node:path';
8
8
  import { isWorkspace } from '../types/project.js';
9
- import { buildWebsiteContext } from '../generators/website-context.js';
10
- import { generateWebsiteLandingPage, generateWebsitePricingPage, generateWebsiteLayout, generateWebsiteGlobalsCss, } from '../generators/templates/website.js';
9
+ import { buildWebsiteContext, resolveBrandAssets, validateWebsiteContext } from '../generators/website-context.js';
10
+ import { resolveWorkspaceRoot } from '../generators/workspace-root.js';
11
+ import { generateWebsiteLandingPage } from '../generators/templates/website-landing.js';
12
+ import { generateWebsitePricingPage } from '../generators/templates/website-pricing.js';
13
+ import { generateWebsiteLayout, generateWebsiteGlobalsCss, } from '../generators/templates/website-layout.js';
11
14
  import { generateWebsiteHeader, generateWebsiteFooter, } from '../generators/templates/website-components.js';
12
15
  import { loadWebsiteStrategy } from './website-strategy.js';
13
16
  /**
@@ -47,12 +50,20 @@ export async function updateWebsiteContent(projectDir, state, language, onProgre
47
50
  logoPath: state.brandContext.logoPath,
48
51
  };
49
52
  }
53
+ // Resolve brand assets using workspace root for proper logo resolution
54
+ const workspaceRoot = await resolveWorkspaceRoot(parentDir);
55
+ context.brandAssets = await resolveBrandAssets(workspaceRoot, context.brand);
50
56
  // Load website strategy if available
51
57
  const strategyData = await loadWebsiteStrategy(projectDir);
52
58
  if (strategyData) {
53
59
  context.strategy = strategyData.strategy;
54
60
  onProgress?.('Loaded website strategy for content update');
55
61
  }
62
+ // Soft validation: report quality issues via progress callback
63
+ const validation = validateWebsiteContext(context, state.name);
64
+ for (const msg of [...validation.issues, ...validation.warnings]) {
65
+ onProgress?.(`[quality-gate] ${msg}`);
66
+ }
56
67
  onProgress?.('Updating website content with project context...');
57
68
  // Re-generate content files
58
69
  const updates = [
@@ -89,11 +100,11 @@ export async function updateWebsiteContent(projectDir, state, language, onProgre
89
100
  // Non-blocking: individual file update failures should not stop the workflow
90
101
  }
91
102
  }
92
- // Copy logo to public/ if brand context has one
103
+ // Copy logo to public/brand/ if brand context has one
93
104
  if (context.brand?.logoPath) {
94
105
  try {
95
106
  const logoExt = path.extname(context.brand.logoPath);
96
- const destPath = path.join(websiteDir, 'public', `logo${logoExt}`);
107
+ const destPath = path.join(websiteDir, 'public', 'brand', `logo${logoExt}`);
97
108
  await fs.copyFile(context.brand.logoPath, destPath);
98
109
  }
99
110
  catch {
@@ -1 +1 @@
1
- {"version":3,"file":"website-updater.js","sourceRoot":"","sources":["../../src/workflow/website-updater.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"website-updater.js","sourceRoot":"","sources":["../../src/workflow/website-updater.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,QAAQ,IAAI,EAAE,EAAE,MAAM,SAAS,CAAC;AACzC,OAAO,IAAI,MAAM,WAAW,CAAC;AAG7B,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAClD,OAAO,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,sBAAsB,EAAE,MAAM,kCAAkC,CAAC;AACnH,OAAO,EAAE,oBAAoB,EAAE,MAAM,iCAAiC,CAAC;AACvE,OAAO,EAAE,0BAA0B,EAAE,MAAM,4CAA4C,CAAC;AACxF,OAAO,EAAE,0BAA0B,EAAE,MAAM,4CAA4C,CAAC;AACxF,OAAO,EACL,qBAAqB,EACrB,yBAAyB,GAC1B,MAAM,2CAA2C,CAAC;AACnD,OAAO,EACL,qBAAqB,EACrB,qBAAqB,GACtB,MAAM,+CAA+C,CAAC;AACvD,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAE5D;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,oBAAoB,CACxC,UAAkB,EAClB,KAAmB,EACnB,QAAwB,EACxB,UAAsC;IAEtC,oDAAoD;IACpD,MAAM,UAAU,GAAG,WAAW,CAAC,QAAQ,CAAC;QACtC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,MAAM,EAAE,SAAS,CAAC;QAC1C,CAAC,CAAC,UAAU,CAAC;IAEf,oCAAoC;IACpC,IAAI,CAAC;QACH,MAAM,EAAE,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;IAC9B,CAAC;IAAC,MAAM,CAAC;QACP,UAAU,EAAE,CAAC,sDAAsD,CAAC,CAAC;QACrE,OAAO;IACT,CAAC;IAED,yDAAyD;IACzD,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;IAC3C,MAAM,OAAO,GAAG,MAAM,mBAAmB,CACvC,SAAS,EACT,KAAK,CAAC,IAAI,EACV,KAAK,CAAC,aAAa,CACpB,CAAC;IAEF,8CAA8C;IAC9C,IAAI,KAAK,CAAC,YAAY,EAAE,YAAY,EAAE,CAAC;QACrC,OAAO,CAAC,KAAK,GAAG;YACd,GAAG,OAAO,CAAC,KAAK;YAChB,YAAY,EAAE,KAAK,CAAC,YAAY,CAAC,YAAY;SAC9C,CAAC;IACJ,CAAC;IACD,IAAI,KAAK,CAAC,YAAY,EAAE,QAAQ,EAAE,CAAC;QACjC,OAAO,CAAC,KAAK,GAAG;YACd,GAAG,OAAO,CAAC,KAAK;YAChB,QAAQ,EAAE,KAAK,CAAC,YAAY,CAAC,QAAQ;SACtC,CAAC;IACJ,CAAC;IAED,uEAAuE;IACvE,MAAM,aAAa,GAAG,MAAM,oBAAoB,CAAC,SAAS,CAAC,CAAC;IAC5D,OAAO,CAAC,WAAW,GAAG,MAAM,kBAAkB,CAAC,aAAa,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC;IAE7E,qCAAqC;IACrC,MAAM,YAAY,GAAG,MAAM,mBAAmB,CAAC,UAAU,CAAC,CAAC;IAC3D,IAAI,YAAY,EAAE,CAAC;QACjB,OAAO,CAAC,QAAQ,GAAG,YAAY,CAAC,QAAQ,CAAC;QACzC,UAAU,EAAE,CAAC,4CAA4C,CAAC,CAAC;IAC7D,CAAC;IAED,+DAA+D;IAC/D,MAAM,UAAU,GAAG,sBAAsB,CAAC,OAAO,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;IAC/D,KAAK,MAAM,GAAG,IAAI,CAAC,GAAG,UAAU,CAAC,MAAM,EAAE,GAAG,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;QACjE,UAAU,EAAE,CAAC,kBAAkB,GAAG,EAAE,CAAC,CAAC;IACxC,CAAC;IAED,UAAU,EAAE,CAAC,kDAAkD,CAAC,CAAC;IAEjE,4BAA4B;IAC5B,MAAM,OAAO,GAA6C;QACxD;YACE,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,KAAK,EAAE,KAAK,EAAE,UAAU,CAAC;YACrD,OAAO,EAAE,0BAA0B,CAAC,KAAK,CAAC,IAAI,EAAE,OAAO,CAAC;SACzD;QACD;YACE,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,UAAU,CAAC;YAChE,OAAO,EAAE,0BAA0B,CAAC,KAAK,CAAC,IAAI,EAAE,OAAO,CAAC;SACzD;QACD;YACE,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,KAAK,EAAE,KAAK,EAAE,YAAY,CAAC;YACvD,OAAO,EAAE,qBAAqB,CAAC,KAAK,CAAC,IAAI,EAAE,OAAO,CAAC;SACpD;QACD;YACE,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,KAAK,EAAE,KAAK,EAAE,aAAa,CAAC;YACxD,OAAO,EAAE,yBAAyB,CAAC,OAAO,CAAC;SAC5C;QACD;YACE,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,KAAK,EAAE,YAAY,EAAE,YAAY,CAAC;YAC9D,OAAO,EAAE,qBAAqB,CAAC,KAAK,CAAC,IAAI,EAAE,OAAO,EAAE,OAAO,CAAC,QAAQ,CAAC;SACtE;QACD;YACE,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,KAAK,EAAE,YAAY,EAAE,YAAY,CAAC;YAC9D,OAAO,EAAE,qBAAqB,CAAC,KAAK,CAAC,IAAI,EAAE,OAAO,EAAE,OAAO,CAAC,QAAQ,CAAC;SACtE;KACF,CAAC;IAEF,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;QAC7B,IAAI,CAAC;YACH,MAAM,EAAE,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QAC3D,CAAC;QAAC,MAAM,CAAC;YACP,6EAA6E;QAC/E,CAAC;IACH,CAAC;IAED,sDAAsD;IACtD,IAAI,OAAO,CAAC,KAAK,EAAE,QAAQ,EAAE,CAAC;QAC5B,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;YACrD,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,OAAO,EAAE,CAAC,CAAC;YAC5E,MAAM,EAAE,CAAC,QAAQ,CAAC,OAAO,CAAC,KAAK,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;QACtD,CAAC;QAAC,MAAM,CAAC;YACP,eAAe;QACjB,CAAC;IACH,CAAC;IAED,UAAU,EAAE,CAAC,8CAA8C,CAAC,CAAC;AAC/D,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "popeye-cli",
3
- "version": "1.5.0",
3
+ "version": "1.6.0",
4
4
  "description": "Fully autonomous code generation tool powered by Claude CLI and OpenAI consensus",
5
5
  "main": "./dist/index.js",
6
6
  "bin": {
@@ -5,6 +5,7 @@
5
5
 
6
6
  import { Command } from 'commander';
7
7
  import path from 'node:path';
8
+ import { promises as fs } from 'node:fs';
8
9
  import { ProjectSpecSchema, type OutputLanguage, type OpenAIModel } from '../../types/project.js';
9
10
  import { requireAuth } from '../../auth/index.js';
10
11
  import { runWorkflow } from '../../workflow/index.js';
@@ -99,8 +100,8 @@ export function createCreateCommand(): Command {
99
100
  }
100
101
 
101
102
  // Generate project name from idea if not provided
102
- const projectName = options.name || generateProjectName(idea);
103
103
  const outputDir = path.resolve(options.output);
104
+ const projectName = options.name || await generateProjectName(idea, outputDir);
104
105
  const projectDir = path.join(outputDir, projectName);
105
106
  const threshold = parseInt(options.threshold, 10);
106
107
  const maxIterations = parseInt(options.maxIterations, 10);
@@ -255,10 +256,63 @@ export function createCreateCommand(): Command {
255
256
  }
256
257
 
257
258
  /**
258
- * Generate a project name from an idea
259
+ * Directories that are too generic to use as project names
259
260
  */
260
- function generateProjectName(idea: string): string {
261
- // Take first few words, lowercase, replace spaces with hyphens
261
+ const GENERIC_DIR_NAMES = new Set([
262
+ 'home', 'desktop', 'documents', 'downloads', 'projects', 'project',
263
+ 'repos', 'code', 'dev', 'workspace', 'workspaces', 'src', 'tmp',
264
+ 'temp', 'users', 'user', 'root', 'var', 'opt',
265
+ ]);
266
+
267
+ /**
268
+ * Generate a project name, preferring CWD-derived names over prompt text.
269
+ *
270
+ * Priority: docs in CWD -> CWD basename -> idea text extraction
271
+ *
272
+ * @param idea - The user's project idea text
273
+ * @param cwd - Optional directory for context-aware naming
274
+ * @returns A kebab-case project name
275
+ */
276
+ async function generateProjectName(idea: string, cwd?: string): Promise<string> {
277
+ const toKebab = (name: string): string =>
278
+ name
279
+ .replace(/([a-z])([A-Z])/g, '$1-$2')
280
+ .toLowerCase()
281
+ .replace(/[^a-z0-9-]/g, '-')
282
+ .replace(/-+/g, '-')
283
+ .replace(/^-|-$/g, '');
284
+
285
+ if (cwd) {
286
+ // Check for doc-derived name
287
+ try {
288
+ const entries = await fs.readdir(cwd, { withFileTypes: true });
289
+ const mdFiles = entries
290
+ .filter(e => e.isFile() && e.name.endsWith('.md') && !e.name.toLowerCase().startsWith('readme'))
291
+ .map(e => path.join(cwd, e.name));
292
+
293
+ for (const mdFile of mdFiles) {
294
+ try {
295
+ const content = await fs.readFile(mdFile, 'utf-8');
296
+ const headingMatch = content.match(/^#\s+([A-Z][a-zA-Z0-9]+)/m);
297
+ if (headingMatch && headingMatch[1] && headingMatch[1].length >= 3 && headingMatch[1].length <= 30) {
298
+ return toKebab(headingMatch[1]);
299
+ }
300
+ } catch {
301
+ // Skip unreadable files
302
+ }
303
+ }
304
+ } catch {
305
+ // Directory not readable
306
+ }
307
+
308
+ // Check CWD basename
309
+ const dirName = path.basename(cwd);
310
+ if (dirName.length >= 3 && !GENERIC_DIR_NAMES.has(dirName.toLowerCase())) {
311
+ return toKebab(dirName);
312
+ }
313
+ }
314
+
315
+ // Fallback: extract from idea text
262
316
  return idea
263
317
  .toLowerCase()
264
318
  .replace(/[^a-z0-9\s]/g, '')
@@ -2262,10 +2262,99 @@ async function handleResume(state: SessionState, args: string[]): Promise<void>
2262
2262
  }
2263
2263
 
2264
2264
  /**
2265
- * Generate a meaningful project name from an idea
2266
- * Extracts key nouns and creates a kebab-case name
2265
+ * Directories that are too generic to use as project names.
2266
+ * If the CWD basename matches one of these, we skip CWD-based naming.
2267
2267
  */
2268
- function generateProjectName(idea: string): string {
2268
+ const GENERIC_DIR_NAMES = new Set([
2269
+ 'home', 'desktop', 'documents', 'downloads', 'projects', 'project',
2270
+ 'repos', 'code', 'dev', 'workspace', 'workspaces', 'src', 'tmp',
2271
+ 'temp', 'users', 'user', 'root', 'var', 'opt',
2272
+ ]);
2273
+
2274
+ /**
2275
+ * Try to extract a product name from .md files in a directory.
2276
+ * Looks for top-level headings (# ProductName) in markdown files.
2277
+ *
2278
+ * @param dir - Directory to scan for .md files
2279
+ * @returns Product name if found, null otherwise
2280
+ */
2281
+ export async function extractNameFromDocs(dir: string): Promise<string | null> {
2282
+ try {
2283
+ const entries = await fs.readdir(dir, { withFileTypes: true });
2284
+ const mdFiles = entries
2285
+ .filter(e => e.isFile() && e.name.endsWith('.md') && !e.name.toLowerCase().startsWith('readme'))
2286
+ .map(e => path.join(dir, e.name));
2287
+
2288
+ for (const mdFile of mdFiles) {
2289
+ try {
2290
+ const content = await fs.readFile(mdFile, 'utf-8');
2291
+ // Look for a top-level heading like "# Gateco" or "# Gateco - Subtitle"
2292
+ const headingMatch = content.match(/^#\s+([A-Z][a-zA-Z0-9]+)/m);
2293
+ if (headingMatch && headingMatch[1]) {
2294
+ const name = headingMatch[1];
2295
+ // Validate: must be a reasonable product name (3-30 chars, not a generic word)
2296
+ if (name.length >= 3 && name.length <= 30 && !GENERIC_DIR_NAMES.has(name.toLowerCase())) {
2297
+ return name;
2298
+ }
2299
+ }
2300
+ } catch {
2301
+ // Skip unreadable files
2302
+ }
2303
+ }
2304
+ } catch {
2305
+ // Directory not readable
2306
+ }
2307
+ return null;
2308
+ }
2309
+
2310
+ /**
2311
+ * Generate a meaningful project name from an idea, with CWD-aware logic.
2312
+ *
2313
+ * Priority chain:
2314
+ * 1. If CWD contains .md docs with a "# ProductName" heading, use that
2315
+ * 2. If CWD basename is a meaningful name (not generic), use it
2316
+ * 3. Fall back to extracting a name from the idea text
2317
+ *
2318
+ * @param idea - The user's project idea text
2319
+ * @param cwd - Optional current working directory for context-aware naming
2320
+ * @returns A kebab-case project name
2321
+ */
2322
+ export async function generateProjectName(idea: string, cwd?: string): Promise<string> {
2323
+ // Normalize to kebab-case helper
2324
+ const toKebab = (name: string): string =>
2325
+ name
2326
+ .replace(/([a-z])([A-Z])/g, '$1-$2')
2327
+ .toLowerCase()
2328
+ .replace(/[^a-z0-9-]/g, '-')
2329
+ .replace(/-+/g, '-')
2330
+ .replace(/^-|-$/g, '');
2331
+
2332
+ if (cwd) {
2333
+ // Priority 1: Check for doc-derived name in CWD
2334
+ const docName = await extractNameFromDocs(cwd);
2335
+ if (docName) {
2336
+ return toKebab(docName);
2337
+ }
2338
+
2339
+ // Priority 2: Use CWD basename if it's meaningful
2340
+ const dirName = path.basename(cwd);
2341
+ if (dirName.length >= 3 && !GENERIC_DIR_NAMES.has(dirName.toLowerCase())) {
2342
+ return toKebab(dirName);
2343
+ }
2344
+ }
2345
+
2346
+ // Priority 3: Extract from idea text (original logic)
2347
+ return generateProjectNameFromIdea(idea);
2348
+ }
2349
+
2350
+ /**
2351
+ * Extract a project name from the idea text alone.
2352
+ * This is the original generateProjectName logic, used as a fallback.
2353
+ *
2354
+ * @param idea - The user's project idea text
2355
+ * @returns A kebab-case project name
2356
+ */
2357
+ export function generateProjectNameFromIdea(idea: string): string {
2269
2358
  // 1. First, try to find explicit project name patterns
2270
2359
  const explicitPatterns = [
2271
2360
  /(?:called|named|for|planning|project)\s+["']?([A-Z][a-zA-Z0-9]+)["']?/i,
@@ -2465,8 +2554,8 @@ async function handleIdea(idea: string, state: SessionState): Promise<void> {
2465
2554
  }
2466
2555
  }
2467
2556
 
2468
- // Generate a meaningful project name
2469
- const projectName = generateProjectName(idea);
2557
+ // Generate a meaningful project name (CWD-aware: checks docs and dir name first)
2558
+ const projectName = await generateProjectName(idea, cwd);
2470
2559
  const projectDir = path.join(cwd, projectName);
2471
2560
 
2472
2561
  console.log();
@@ -2581,8 +2670,8 @@ async function handleNewProject(idea: string, state: SessionState): Promise<void
2581
2670
 
2582
2671
  const cwd = state.projectDir || process.cwd();
2583
2672
 
2584
- // Generate a meaningful project name
2585
- const projectName = generateProjectName(idea);
2673
+ // Generate a meaningful project name (CWD-aware: checks docs and dir name first)
2674
+ const projectName = await generateProjectName(idea, cwd);
2586
2675
  const projectDir = path.join(cwd, projectName);
2587
2676
 
2588
2677
  console.log();