spec-gen-cli 1.2.6 → 1.2.8

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 (198) hide show
  1. package/README.md +175 -55
  2. package/dist/api/analyze.d.ts.map +1 -1
  3. package/dist/api/analyze.js +6 -1
  4. package/dist/api/analyze.js.map +1 -1
  5. package/dist/api/audit.d.ts +10 -0
  6. package/dist/api/audit.d.ts.map +1 -0
  7. package/dist/api/audit.js +117 -0
  8. package/dist/api/audit.js.map +1 -0
  9. package/dist/api/generate.d.ts.map +1 -1
  10. package/dist/api/generate.js +10 -1
  11. package/dist/api/generate.js.map +1 -1
  12. package/dist/api/index.d.ts +3 -2
  13. package/dist/api/index.d.ts.map +1 -1
  14. package/dist/api/index.js +1 -0
  15. package/dist/api/index.js.map +1 -1
  16. package/dist/api/run.d.ts.map +1 -1
  17. package/dist/api/run.js +5 -1
  18. package/dist/api/run.js.map +1 -1
  19. package/dist/api/types.d.ts +15 -4
  20. package/dist/api/types.d.ts.map +1 -1
  21. package/dist/cli/commands/analyze.d.ts +3 -0
  22. package/dist/cli/commands/analyze.d.ts.map +1 -1
  23. package/dist/cli/commands/analyze.js +112 -17
  24. package/dist/cli/commands/analyze.js.map +1 -1
  25. package/dist/cli/commands/audit.d.ts +9 -0
  26. package/dist/cli/commands/audit.d.ts.map +1 -0
  27. package/dist/cli/commands/audit.js +98 -0
  28. package/dist/cli/commands/audit.js.map +1 -0
  29. package/dist/cli/commands/drift.d.ts.map +1 -1
  30. package/dist/cli/commands/drift.js +8 -10
  31. package/dist/cli/commands/drift.js.map +1 -1
  32. package/dist/cli/commands/generate.d.ts.map +1 -1
  33. package/dist/cli/commands/generate.js +15 -37
  34. package/dist/cli/commands/generate.js.map +1 -1
  35. package/dist/cli/commands/mcp.d.ts +102 -2
  36. package/dist/cli/commands/mcp.d.ts.map +1 -1
  37. package/dist/cli/commands/mcp.js +134 -2
  38. package/dist/cli/commands/mcp.js.map +1 -1
  39. package/dist/cli/commands/run.d.ts.map +1 -1
  40. package/dist/cli/commands/run.js +9 -47
  41. package/dist/cli/commands/run.js.map +1 -1
  42. package/dist/cli/commands/setup.d.ts +17 -0
  43. package/dist/cli/commands/setup.d.ts.map +1 -0
  44. package/dist/cli/commands/setup.js +201 -0
  45. package/dist/cli/commands/setup.js.map +1 -0
  46. package/dist/cli/commands/verify.d.ts.map +1 -1
  47. package/dist/cli/commands/verify.js +7 -8
  48. package/dist/cli/commands/verify.js.map +1 -1
  49. package/dist/cli/index.js +14 -8
  50. package/dist/cli/index.js.map +1 -1
  51. package/dist/constants.d.ts +14 -0
  52. package/dist/constants.d.ts.map +1 -1
  53. package/dist/constants.js +14 -0
  54. package/dist/constants.js.map +1 -1
  55. package/dist/core/analyzer/ai-config-generator.d.ts +54 -0
  56. package/dist/core/analyzer/ai-config-generator.d.ts.map +1 -0
  57. package/dist/core/analyzer/ai-config-generator.js +85 -0
  58. package/dist/core/analyzer/ai-config-generator.js.map +1 -0
  59. package/dist/core/analyzer/artifact-generator.d.ts +27 -2
  60. package/dist/core/analyzer/artifact-generator.d.ts.map +1 -1
  61. package/dist/core/analyzer/artifact-generator.js +86 -8
  62. package/dist/core/analyzer/artifact-generator.js.map +1 -1
  63. package/dist/core/analyzer/codebase-digest.d.ts.map +1 -1
  64. package/dist/core/analyzer/codebase-digest.js +12 -11
  65. package/dist/core/analyzer/codebase-digest.js.map +1 -1
  66. package/dist/core/analyzer/env-extractor.d.ts +33 -0
  67. package/dist/core/analyzer/env-extractor.d.ts.map +1 -0
  68. package/dist/core/analyzer/env-extractor.js +196 -0
  69. package/dist/core/analyzer/env-extractor.js.map +1 -0
  70. package/dist/core/analyzer/http-route-parser.d.ts +36 -1
  71. package/dist/core/analyzer/http-route-parser.d.ts.map +1 -1
  72. package/dist/core/analyzer/http-route-parser.js +276 -0
  73. package/dist/core/analyzer/http-route-parser.js.map +1 -1
  74. package/dist/core/analyzer/middleware-extractor.d.ts +29 -0
  75. package/dist/core/analyzer/middleware-extractor.d.ts.map +1 -0
  76. package/dist/core/analyzer/middleware-extractor.js +195 -0
  77. package/dist/core/analyzer/middleware-extractor.js.map +1 -0
  78. package/dist/core/analyzer/schema-extractor.d.ts +41 -0
  79. package/dist/core/analyzer/schema-extractor.d.ts.map +1 -0
  80. package/dist/core/analyzer/schema-extractor.js +229 -0
  81. package/dist/core/analyzer/schema-extractor.js.map +1 -0
  82. package/dist/core/analyzer/spec-snapshot-generator.d.ts +17 -0
  83. package/dist/core/analyzer/spec-snapshot-generator.d.ts.map +1 -0
  84. package/dist/core/analyzer/spec-snapshot-generator.js +201 -0
  85. package/dist/core/analyzer/spec-snapshot-generator.js.map +1 -0
  86. package/dist/core/analyzer/ui-component-extractor.d.ts +43 -0
  87. package/dist/core/analyzer/ui-component-extractor.d.ts.map +1 -0
  88. package/dist/core/analyzer/ui-component-extractor.js +245 -0
  89. package/dist/core/analyzer/ui-component-extractor.js.map +1 -0
  90. package/dist/core/generator/openspec-format-generator.d.ts.map +1 -1
  91. package/dist/core/generator/openspec-format-generator.js +8 -0
  92. package/dist/core/generator/openspec-format-generator.js.map +1 -1
  93. package/dist/core/generator/spec-pipeline.d.ts +9 -0
  94. package/dist/core/generator/spec-pipeline.d.ts.map +1 -1
  95. package/dist/core/generator/spec-pipeline.js +94 -2
  96. package/dist/core/generator/spec-pipeline.js.map +1 -1
  97. package/dist/core/generator/stages/stage1-survey.d.ts.map +1 -1
  98. package/dist/core/generator/stages/stage1-survey.js +43 -0
  99. package/dist/core/generator/stages/stage1-survey.js.map +1 -1
  100. package/dist/core/generator/stages/stage2-entities.d.ts.map +1 -1
  101. package/dist/core/generator/stages/stage2-entities.js +6 -2
  102. package/dist/core/generator/stages/stage2-entities.js.map +1 -1
  103. package/dist/core/generator/stages/stage3-services.d.ts.map +1 -1
  104. package/dist/core/generator/stages/stage3-services.js +9 -2
  105. package/dist/core/generator/stages/stage3-services.js.map +1 -1
  106. package/dist/core/generator/stages/stage4-api.d.ts.map +1 -1
  107. package/dist/core/generator/stages/stage4-api.js +6 -2
  108. package/dist/core/generator/stages/stage4-api.js.map +1 -1
  109. package/dist/core/services/llm-service.d.ts +26 -10
  110. package/dist/core/services/llm-service.d.ts.map +1 -1
  111. package/dist/core/services/llm-service.js +171 -16
  112. package/dist/core/services/llm-service.js.map +1 -1
  113. package/dist/core/services/mcp-handlers/analysis.d.ts +32 -1
  114. package/dist/core/services/mcp-handlers/analysis.d.ts.map +1 -1
  115. package/dist/core/services/mcp-handlers/analysis.js +185 -2
  116. package/dist/core/services/mcp-handlers/analysis.js.map +1 -1
  117. package/dist/core/verifier/verification-engine.d.ts +67 -6
  118. package/dist/core/verifier/verification-engine.d.ts.map +1 -1
  119. package/dist/core/verifier/verification-engine.js +316 -90
  120. package/dist/core/verifier/verification-engine.js.map +1 -1
  121. package/dist/types/index.d.ts +70 -1
  122. package/dist/types/index.d.ts.map +1 -1
  123. package/dist/types/pipeline.d.ts +9 -0
  124. package/dist/types/pipeline.d.ts.map +1 -1
  125. package/dist/utils/command-helpers.d.ts +30 -0
  126. package/dist/utils/command-helpers.d.ts.map +1 -1
  127. package/dist/utils/command-helpers.js +69 -1
  128. package/dist/utils/command-helpers.js.map +1 -1
  129. package/examples/bmad/README.md +113 -0
  130. package/examples/bmad/agents/architect.md +226 -0
  131. package/examples/bmad/agents/dev-brownfield.md +69 -0
  132. package/examples/bmad/setup/architect.customize.yaml +14 -0
  133. package/examples/bmad/tasks/implement-story.md +254 -0
  134. package/examples/bmad/tasks/onboarding.md +169 -0
  135. package/examples/bmad/tasks/refactor.md +178 -0
  136. package/examples/bmad/tasks/sprint-planning.md +168 -0
  137. package/examples/bmad/templates/story.md +108 -0
  138. package/examples/cline-workflows/spec-gen-analyze-codebase.md +100 -0
  139. package/examples/cline-workflows/spec-gen-check-spec-drift.md +102 -0
  140. package/examples/cline-workflows/spec-gen-execute-refactor.md +194 -0
  141. package/examples/cline-workflows/spec-gen-implement-feature.md +238 -0
  142. package/examples/cline-workflows/spec-gen-plan-refactor.md +255 -0
  143. package/examples/cline-workflows/spec-gen-refactor-codebase.md +16 -0
  144. package/examples/drift-demo/openspec/config.yaml +14 -0
  145. package/examples/drift-demo/openspec/specs/architecture/spec.md +30 -0
  146. package/examples/drift-demo/openspec/specs/auth/spec.md +71 -0
  147. package/examples/drift-demo/openspec/specs/database/spec.md +33 -0
  148. package/examples/drift-demo/openspec/specs/overview/spec.md +20 -0
  149. package/examples/drift-demo/openspec/specs/projects/spec.md +55 -0
  150. package/examples/drift-demo/openspec/specs/tasks/spec.md +78 -0
  151. package/examples/drift-demo/package.json +21 -0
  152. package/examples/drift-demo/src/auth/auth-middleware.ts +30 -0
  153. package/examples/drift-demo/src/auth/auth-routes.ts +29 -0
  154. package/examples/drift-demo/src/auth/auth-service.ts +45 -0
  155. package/examples/drift-demo/src/database/connection.ts +27 -0
  156. package/examples/drift-demo/src/index.ts +16 -0
  157. package/examples/drift-demo/src/projects/project-model.ts +15 -0
  158. package/examples/drift-demo/src/projects/project-service.ts +34 -0
  159. package/examples/drift-demo/src/tasks/task-model.ts +37 -0
  160. package/examples/drift-demo/src/tasks/task-routes.ts +53 -0
  161. package/examples/drift-demo/src/tasks/task-service.ts +60 -0
  162. package/examples/drift-demo/src/utils/validation.ts +11 -0
  163. package/examples/drift-demo/tests/auth.test.ts +4 -0
  164. package/examples/drift-demo/tests/tasks.test.ts +4 -0
  165. package/examples/drift-demo/tsconfig.json +10 -0
  166. package/examples/drift-test/run-drift-test.sh +1087 -0
  167. package/examples/gsd/README.md +119 -0
  168. package/examples/gsd/commands/gsd/spec-gen-drift.md +111 -0
  169. package/examples/gsd/commands/gsd/spec-gen-orient.md +191 -0
  170. package/examples/mistral-vibe/README.md +101 -0
  171. package/examples/mistral-vibe/antipatterns-template.md +18 -0
  172. package/examples/mistral-vibe/skills/spec-gen-analyze-codebase/SKILL.md +123 -0
  173. package/examples/mistral-vibe/skills/spec-gen-brainstorm/SKILL.md +379 -0
  174. package/examples/mistral-vibe/skills/spec-gen-debug/SKILL.md +320 -0
  175. package/examples/mistral-vibe/skills/spec-gen-execute-refactor/SKILL.md +210 -0
  176. package/examples/mistral-vibe/skills/spec-gen-generate/SKILL.md +245 -0
  177. package/examples/mistral-vibe/skills/spec-gen-implement-story/SKILL.md +274 -0
  178. package/examples/mistral-vibe/skills/spec-gen-plan-refactor/SKILL.md +251 -0
  179. package/examples/openspec-analysis/README.md +59 -0
  180. package/examples/openspec-analysis/SUMMARY.md +72 -0
  181. package/examples/openspec-analysis/config.json +16 -0
  182. package/examples/openspec-analysis/dependencies.mermaid +35 -0
  183. package/examples/openspec-analysis/dependency-graph.json +12116 -0
  184. package/examples/openspec-analysis/llm-context.json +119 -0
  185. package/examples/openspec-analysis/repo-structure.json +871 -0
  186. package/examples/openspec-cli/README.md +67 -0
  187. package/examples/openspec-cli/openspec/config.yaml +26 -0
  188. package/examples/openspec-cli/openspec/specs/architecture/spec.md +178 -0
  189. package/examples/openspec-cli/openspec/specs/artifact-graph/spec.md +143 -0
  190. package/examples/openspec-cli/openspec/specs/cli/spec.md +138 -0
  191. package/examples/openspec-cli/openspec/specs/overview/spec.md +60 -0
  192. package/examples/openspec-cli/openspec/specs/parsing/spec.md +123 -0
  193. package/examples/openspec-cli/openspec/specs/validation/spec.md +108 -0
  194. package/examples/spec-kit/README.md +104 -0
  195. package/examples/spec-kit/commands/drift.md +87 -0
  196. package/examples/spec-kit/commands/orient.md +138 -0
  197. package/examples/spec-kit/extension.yml +54 -0
  198. package/package.json +3 -6
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Database Schema Extractor
3
+ *
4
+ * Parses ORM schema definitions from source files using regex-based analysis.
5
+ * Supports Prisma, TypeORM, Drizzle ORM, and SQLAlchemy.
6
+ *
7
+ * Audit fields (createdAt, updatedAt, created_at, updated_at, deletedAt,
8
+ * deleted_at) are excluded from field lists to keep output concise.
9
+ *
10
+ * Uses regex-based analysis without requiring tree-sitter.
11
+ */
12
+ export interface SchemaField {
13
+ name: string;
14
+ type: string;
15
+ nullable: boolean;
16
+ }
17
+ export type OrmType = 'prisma' | 'typeorm' | 'drizzle' | 'sqlalchemy' | 'unknown';
18
+ export interface SchemaTable {
19
+ /** Model / table name */
20
+ name: string;
21
+ /** Path relative to project root */
22
+ file: string;
23
+ /** ORM that owns this schema */
24
+ orm: OrmType;
25
+ /** Extracted fields (audit fields excluded) */
26
+ fields: SchemaField[];
27
+ /** 1-based line of the model declaration */
28
+ line: number;
29
+ }
30
+ /**
31
+ * Extract database schema tables from a list of absolute file paths.
32
+ *
33
+ * @param filePaths - Absolute paths to source files
34
+ * @param rootDir - Project root used to compute relative paths in output
35
+ */
36
+ export declare function extractSchemas(filePaths: string[], rootDir: string): Promise<SchemaTable[]>;
37
+ /**
38
+ * Summarise schema tables by ORM for display / artifact embedding.
39
+ */
40
+ export declare function summarizeSchemas(tables: SchemaTable[]): Record<string, number>;
41
+ //# sourceMappingURL=schema-extractor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema-extractor.d.ts","sourceRoot":"","sources":["../../../src/core/analyzer/schema-extractor.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAUH,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,MAAM,OAAO,GAAG,QAAQ,GAAG,SAAS,GAAG,SAAS,GAAG,YAAY,GAAG,SAAS,CAAC;AAElF,MAAM,WAAW,WAAW;IAC1B,yBAAyB;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,oCAAoC;IACpC,IAAI,EAAE,MAAM,CAAC;IACb,gCAAgC;IAChC,GAAG,EAAE,OAAO,CAAC;IACb,+CAA+C;IAC/C,MAAM,EAAE,WAAW,EAAE,CAAC;IACtB,4CAA4C;IAC5C,IAAI,EAAE,MAAM,CAAC;CACd;AAsMD;;;;;GAKG;AACH,wBAAsB,cAAc,CAClC,SAAS,EAAE,MAAM,EAAE,EACnB,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,WAAW,EAAE,CAAC,CA8BxB;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAC9B,MAAM,EAAE,WAAW,EAAE,GACpB,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAMxB"}
@@ -0,0 +1,229 @@
1
+ /**
2
+ * Database Schema Extractor
3
+ *
4
+ * Parses ORM schema definitions from source files using regex-based analysis.
5
+ * Supports Prisma, TypeORM, Drizzle ORM, and SQLAlchemy.
6
+ *
7
+ * Audit fields (createdAt, updatedAt, created_at, updated_at, deletedAt,
8
+ * deleted_at) are excluded from field lists to keep output concise.
9
+ *
10
+ * Uses regex-based analysis without requiring tree-sitter.
11
+ */
12
+ import { readFile } from 'node:fs/promises';
13
+ import { extname, relative } from 'node:path';
14
+ import { getSkeletonContent } from './code-shaper.js';
15
+ // ============================================================================
16
+ // AUDIT FIELD FILTER
17
+ // ============================================================================
18
+ const AUDIT_FIELD_NAMES = new Set([
19
+ 'createdAt', 'updatedAt', 'deletedAt',
20
+ 'created_at', 'updated_at', 'deleted_at',
21
+ 'createdBy', 'updatedBy', 'created_by', 'updated_by',
22
+ ]);
23
+ function isAuditField(name) {
24
+ return AUDIT_FIELD_NAMES.has(name);
25
+ }
26
+ // ============================================================================
27
+ // HELPERS
28
+ // ============================================================================
29
+ function lineOfIndex(source, index) {
30
+ return source.slice(0, index).split('\n').length;
31
+ }
32
+ // ============================================================================
33
+ // PRISMA PARSER (.prisma files)
34
+ // ============================================================================
35
+ // model User { ... }
36
+ const PRISMA_MODEL_RE = /^model\s+(\w+)\s*\{([^}]+)\}/gm;
37
+ // field line: fieldName FieldType? @...
38
+ const PRISMA_FIELD_RE = /^\s{1,4}(\w+)\s+(\w+)(\?)?/m;
39
+ function parsePrisma(source, rel) {
40
+ const tables = [];
41
+ const modelRe = new RegExp(PRISMA_MODEL_RE.source, PRISMA_MODEL_RE.flags);
42
+ let m;
43
+ while ((m = modelRe.exec(source)) !== null) {
44
+ const name = m[1];
45
+ const body = m[2];
46
+ const line = lineOfIndex(source, m.index);
47
+ const fields = [];
48
+ for (const rawLine of body.split('\n')) {
49
+ const fm = PRISMA_FIELD_RE.exec(rawLine);
50
+ if (!fm)
51
+ continue;
52
+ const fieldName = fm[1];
53
+ if (fieldName.startsWith('@') || fieldName === '@@')
54
+ continue;
55
+ if (isAuditField(fieldName))
56
+ continue;
57
+ fields.push({
58
+ name: fieldName,
59
+ type: fm[2],
60
+ nullable: fm[3] === '?',
61
+ });
62
+ }
63
+ tables.push({ name, file: rel, orm: 'prisma', fields, line });
64
+ }
65
+ return tables;
66
+ }
67
+ // ============================================================================
68
+ // TYPEORM PARSER (.ts files with @Entity)
69
+ // ============================================================================
70
+ // @Entity() ... class ClassName { ... }
71
+ // We capture class name after @Entity decorator region.
72
+ const TYPEORM_ENTITY_RE = /@Entity\s*\([^)]*\)[^]*?class\s+(\w+)/g;
73
+ // @Column() / @PrimaryGeneratedColumn() etc before fieldName: FieldType
74
+ const TYPEORM_COLUMN_RE = /@(?:Column|PrimaryGeneratedColumn|PrimaryColumn|CreateDateColumn|UpdateDateColumn|DeleteDateColumn|ManyToOne|OneToMany|ManyToMany|OneToOne|JoinColumn|JoinTable)\s*\([^)]*\)\s*\n\s*(\w+)\s*[?!]?\s*:\s*([^;\n]+)/g;
75
+ const TYPEORM_CLASS_BODY_RE = /class\s+\w+[^{]*\{([^]*?)^}/m;
76
+ function parseTypeOrm(source, rel) {
77
+ const tables = [];
78
+ const entityRe = new RegExp(TYPEORM_ENTITY_RE.source, TYPEORM_ENTITY_RE.flags);
79
+ let em;
80
+ while ((em = entityRe.exec(source)) !== null) {
81
+ const name = em[1];
82
+ const line = lineOfIndex(source, em.index);
83
+ const fields = [];
84
+ // Extract class body starting from the match
85
+ const afterMatch = source.slice(em.index);
86
+ const bodyMatch = TYPEORM_CLASS_BODY_RE.exec(afterMatch);
87
+ if (bodyMatch) {
88
+ const body = bodyMatch[1];
89
+ const colRe = new RegExp(TYPEORM_COLUMN_RE.source, TYPEORM_COLUMN_RE.flags);
90
+ let cm;
91
+ while ((cm = colRe.exec(body)) !== null) {
92
+ const fieldName = cm[1];
93
+ if (isAuditField(fieldName))
94
+ continue;
95
+ fields.push({
96
+ name: fieldName,
97
+ type: cm[2].trim().replace(/;.*$/, ''),
98
+ nullable: cm[2].includes('null') || false,
99
+ });
100
+ }
101
+ }
102
+ tables.push({ name, file: rel, orm: 'typeorm', fields, line });
103
+ }
104
+ return tables;
105
+ }
106
+ // ============================================================================
107
+ // DRIZZLE ORM PARSER (.ts files)
108
+ // ============================================================================
109
+ // export const users = pgTable('users', { ... })
110
+ const DRIZZLE_TABLE_RE = /(?:export\s+(?:const|let)\s+(\w+)\s*=\s*)?(?:pgTable|mysqlTable|sqliteTable)\s*\(\s*['"`](\w+)['"`]\s*,\s*\{([^}]+)\}/g;
111
+ // fieldName: columnType(...)
112
+ const DRIZZLE_FIELD_RE = /^\s{1,6}(\w+)\s*:\s*([\w.]+)\s*\(/m;
113
+ function parseDrizzle(source, rel) {
114
+ const tables = [];
115
+ const tableRe = new RegExp(DRIZZLE_TABLE_RE.source, DRIZZLE_TABLE_RE.flags);
116
+ let m;
117
+ while ((m = tableRe.exec(source)) !== null) {
118
+ // Prefer the table name literal (m[2]) over the variable name (m[1])
119
+ const name = m[2] || m[1] || 'unknown';
120
+ const body = m[3];
121
+ const line = lineOfIndex(source, m.index);
122
+ const fields = [];
123
+ for (const rawLine of body.split('\n')) {
124
+ const fm = DRIZZLE_FIELD_RE.exec(rawLine);
125
+ if (!fm)
126
+ continue;
127
+ const fieldName = fm[1];
128
+ if (isAuditField(fieldName))
129
+ continue;
130
+ fields.push({
131
+ name: fieldName,
132
+ type: fm[2],
133
+ nullable: rawLine.includes('.nullable()') || rawLine.includes('$default'),
134
+ });
135
+ }
136
+ tables.push({ name, file: rel, orm: 'drizzle', fields, line });
137
+ }
138
+ return tables;
139
+ }
140
+ // ============================================================================
141
+ // SQLALCHEMY PARSER (.py files)
142
+ // ============================================================================
143
+ // class User(Base): or class User(db.Model):
144
+ const SQLALCHEMY_MODEL_RE = /^class\s+(\w+)\s*\([^)]*(?:Base|db\.Model|DeclarativeBase)[^)]*\)\s*:/gm;
145
+ // column_name = Column(Type, ...)
146
+ const SQLALCHEMY_COLUMN_RE = /^\s{4}(\w+)\s*=\s*(?:mapped_column|Column)\s*\(\s*([^,)]+)/m;
147
+ // nullable: nullable=True (default) or nullable=False
148
+ const SQLALCHEMY_NULLABLE_RE = /nullable\s*=\s*(True|False)/;
149
+ function parseSqlAlchemy(source, rel) {
150
+ const tables = [];
151
+ const classRe = new RegExp(SQLALCHEMY_MODEL_RE.source, SQLALCHEMY_MODEL_RE.flags);
152
+ let cm;
153
+ while ((cm = classRe.exec(source)) !== null) {
154
+ const name = cm[1];
155
+ const line = lineOfIndex(source, cm.index);
156
+ const fields = [];
157
+ // Capture up to next class or end of file
158
+ const rest = source.slice(cm.index + cm[0].length);
159
+ const nextClassIdx = rest.search(/^class\s+\w+/m);
160
+ const classBody = nextClassIdx >= 0 ? rest.slice(0, nextClassIdx) : rest;
161
+ for (const rawLine of classBody.split('\n')) {
162
+ const fm = SQLALCHEMY_COLUMN_RE.exec(rawLine);
163
+ if (!fm)
164
+ continue;
165
+ const fieldName = fm[1];
166
+ if (fieldName.startsWith('_') || isAuditField(fieldName))
167
+ continue;
168
+ const nullableMatch = SQLALCHEMY_NULLABLE_RE.exec(rawLine);
169
+ // SQLAlchemy columns are nullable by default
170
+ const nullable = nullableMatch ? nullableMatch[1] === 'True' : true;
171
+ fields.push({
172
+ name: fieldName,
173
+ type: fm[2].trim().replace(/[,)].*/s, ''),
174
+ nullable,
175
+ });
176
+ }
177
+ tables.push({ name, file: rel, orm: 'sqlalchemy', fields, line });
178
+ }
179
+ return tables;
180
+ }
181
+ // ============================================================================
182
+ // PUBLIC API
183
+ // ============================================================================
184
+ /**
185
+ * Extract database schema tables from a list of absolute file paths.
186
+ *
187
+ * @param filePaths - Absolute paths to source files
188
+ * @param rootDir - Project root used to compute relative paths in output
189
+ */
190
+ export async function extractSchemas(filePaths, rootDir) {
191
+ const results = [];
192
+ await Promise.all(filePaths.map(async (filePath) => {
193
+ const ext = extname(filePath).toLowerCase();
194
+ const rel = relative(rootDir, filePath);
195
+ let source;
196
+ try {
197
+ source = getSkeletonContent(await readFile(filePath, 'utf-8'), ext === '.py' ? 'python' : 'typescript');
198
+ }
199
+ catch {
200
+ return;
201
+ }
202
+ if (ext === '.prisma') {
203
+ results.push(...parsePrisma(source, rel));
204
+ }
205
+ else if (ext === '.py' && (source.includes('Column(') || source.includes('mapped_column('))) {
206
+ results.push(...parseSqlAlchemy(source, rel));
207
+ }
208
+ else if (ext === '.ts' || ext === '.tsx') {
209
+ if (source.includes('@Entity(') || source.includes('@Entity()')) {
210
+ results.push(...parseTypeOrm(source, rel));
211
+ }
212
+ else if (/pgTable|mysqlTable|sqliteTable/.test(source)) {
213
+ results.push(...parseDrizzle(source, rel));
214
+ }
215
+ }
216
+ }));
217
+ return results;
218
+ }
219
+ /**
220
+ * Summarise schema tables by ORM for display / artifact embedding.
221
+ */
222
+ export function summarizeSchemas(tables) {
223
+ const counts = {};
224
+ for (const t of tables) {
225
+ counts[t.orm] = (counts[t.orm] ?? 0) + 1;
226
+ }
227
+ return counts;
228
+ }
229
+ //# sourceMappingURL=schema-extractor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema-extractor.js","sourceRoot":"","sources":["../../../src/core/analyzer/schema-extractor.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Spec Snapshot Generator
3
+ *
4
+ * Derives a compact coverage summary from existing analysis artifacts —
5
+ * no LLM required. Reads llm-context.json, mapping.json, and spec files
6
+ * to produce spec-snapshot.json.
7
+ */
8
+ import type { SpecSnapshot } from '../../types/index.js';
9
+ export declare class SpecSnapshotGenerator {
10
+ private readonly rootPath;
11
+ private readonly openspecRelPath;
12
+ constructor(rootPath: string, openspecRelPath?: string);
13
+ generate(): Promise<SpecSnapshot>;
14
+ /** Load a previously generated snapshot, or return null if not found. */
15
+ static load(rootPath: string): Promise<SpecSnapshot | null>;
16
+ }
17
+ //# sourceMappingURL=spec-snapshot-generator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"spec-snapshot-generator.d.ts","sourceRoot":"","sources":["../../../src/core/analyzer/spec-snapshot-generator.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAeH,OAAO,KAAK,EAAE,YAAY,EAAuC,MAAM,sBAAsB,CAAC;AAmH9F,qBAAa,qBAAqB;IAE9B,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,OAAO,CAAC,QAAQ,CAAC,eAAe;gBADf,QAAQ,EAAE,MAAM,EAChB,eAAe,GAAE,MAAqB;IAGnD,QAAQ,IAAI,OAAO,CAAC,YAAY,CAAC;IA4FvC,yEAAyE;WAC5D,IAAI,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC;CAWlE"}
@@ -0,0 +1,201 @@
1
+ /**
2
+ * Spec Snapshot Generator
3
+ *
4
+ * Derives a compact coverage summary from existing analysis artifacts —
5
+ * no LLM required. Reads llm-context.json, mapping.json, and spec files
6
+ * to produce spec-snapshot.json.
7
+ */
8
+ import { execFile } from 'node:child_process';
9
+ import { promisify } from 'node:util';
10
+ import { readFile, stat, readdir, writeFile } from 'node:fs/promises';
11
+ import { join, relative } from 'node:path';
12
+ import { SPEC_GEN_DIR, SPEC_GEN_ANALYSIS_SUBDIR, ARTIFACT_LLM_CONTEXT, ARTIFACT_MAPPING, ARTIFACT_SPEC_SNAPSHOT, OPENSPEC_DIR, OPENSPEC_SPECS_SUBDIR, } from '../../constants.js';
13
+ const execFileAsync = promisify(execFile);
14
+ // ============================================================================
15
+ // GIT HELPERS
16
+ // ============================================================================
17
+ async function getGitState(rootPath) {
18
+ try {
19
+ const [commitResult, branchResult, statusResult] = await Promise.all([
20
+ execFileAsync('git', ['rev-parse', '--short', 'HEAD'], { cwd: rootPath }).catch(() => ({ stdout: '' })),
21
+ execFileAsync('git', ['rev-parse', '--abbrev-ref', 'HEAD'], { cwd: rootPath }).catch(() => ({ stdout: '' })),
22
+ execFileAsync('git', ['status', '--porcelain'], { cwd: rootPath }).catch(() => ({ stdout: '' })),
23
+ ]);
24
+ return {
25
+ commit: commitResult.stdout.trim() || 'unknown',
26
+ branch: branchResult.stdout.trim() || 'unknown',
27
+ dirty: statusResult.stdout.trim().length > 0,
28
+ };
29
+ }
30
+ catch {
31
+ return { commit: 'unknown', branch: 'unknown', dirty: false };
32
+ }
33
+ }
34
+ // ============================================================================
35
+ // SPEC FILE HELPERS
36
+ // ============================================================================
37
+ /** Count H2/H3 headings in a spec.md as a proxy for requirement count. */
38
+ function countRequirements(content) {
39
+ const matches = content.match(/^#{2,3} /gm);
40
+ return matches ? matches.length : 0;
41
+ }
42
+ /** Get max mtime across a list of file paths (returns epoch ISO string if none exist). */
43
+ async function maxMtime(filePaths, rootPath) {
44
+ let max = 0;
45
+ for (const rel of filePaths) {
46
+ try {
47
+ const s = await stat(join(rootPath, rel));
48
+ if (s.mtimeMs > max)
49
+ max = s.mtimeMs;
50
+ }
51
+ catch { /* file may not exist */ }
52
+ }
53
+ return max > 0 ? new Date(max).toISOString() : new Date(0).toISOString();
54
+ }
55
+ async function discoverSpecDomains(openspecPath, rootPath) {
56
+ const specsDir = join(openspecPath, OPENSPEC_SPECS_SUBDIR);
57
+ let entries;
58
+ try {
59
+ entries = await readdir(specsDir);
60
+ }
61
+ catch {
62
+ return [];
63
+ }
64
+ const domains = [];
65
+ for (const entry of entries) {
66
+ const specFilePath = join(specsDir, entry, 'spec.md');
67
+ try {
68
+ const [content, s] = await Promise.all([
69
+ readFile(specFilePath, 'utf-8'),
70
+ stat(specFilePath),
71
+ ]);
72
+ domains.push({
73
+ name: entry,
74
+ specFile: relative(rootPath, specFilePath),
75
+ specModifiedAt: s.mtime.toISOString(),
76
+ requirementCount: countRequirements(content),
77
+ });
78
+ }
79
+ catch { /* skip missing spec.md */ }
80
+ }
81
+ return domains;
82
+ }
83
+ // ============================================================================
84
+ // COVERAGE COMPUTATION
85
+ // ============================================================================
86
+ function buildCoveredFunctionSet(mapping) {
87
+ const covered = new Set();
88
+ for (const m of mapping.mappings) {
89
+ for (const fn of m.functions) {
90
+ if (fn.name && fn.name !== '*') {
91
+ covered.add(`${fn.file}::${fn.name}`);
92
+ covered.add(fn.name); // also by name alone for looser matching
93
+ }
94
+ }
95
+ }
96
+ return covered;
97
+ }
98
+ function isFunctionCovered(node, covered) {
99
+ const byFileAndName = `${node.filePath}::${node.name}`;
100
+ return covered.has(byFileAndName) || covered.has(node.name);
101
+ }
102
+ // ============================================================================
103
+ // PUBLIC API
104
+ // ============================================================================
105
+ export class SpecSnapshotGenerator {
106
+ rootPath;
107
+ openspecRelPath;
108
+ constructor(rootPath, openspecRelPath = OPENSPEC_DIR) {
109
+ this.rootPath = rootPath;
110
+ this.openspecRelPath = openspecRelPath;
111
+ }
112
+ async generate() {
113
+ const analysisDir = join(this.rootPath, SPEC_GEN_DIR, SPEC_GEN_ANALYSIS_SUBDIR);
114
+ const openspecPath = join(this.rootPath, this.openspecRelPath);
115
+ // Load artifacts in parallel
116
+ const [llmContextRaw, mappingRaw, git, specDomains] = await Promise.all([
117
+ readFile(join(analysisDir, ARTIFACT_LLM_CONTEXT), 'utf-8').catch(() => null),
118
+ readFile(join(analysisDir, ARTIFACT_MAPPING), 'utf-8').catch(() => null),
119
+ getGitState(this.rootPath),
120
+ discoverSpecDomains(openspecPath, this.rootPath),
121
+ ]);
122
+ const llmContext = llmContextRaw ? JSON.parse(llmContextRaw) : null;
123
+ const mapping = mappingRaw ? JSON.parse(mappingRaw) : null;
124
+ const callGraph = llmContext?.callGraph;
125
+ const allNodes = callGraph?.nodes ?? [];
126
+ const hubNodes = callGraph?.hubFunctions ?? [];
127
+ // Build coverage index from mapping
128
+ const covered = mapping ? buildCoveredFunctionSet(mapping) : new Set();
129
+ const coveredCount = mapping ? allNodes.filter(n => isFunctionCovered(n, covered)).length : 0;
130
+ const orphanCount = mapping?.orphanFunctions?.length ?? 0;
131
+ const totalFunctions = allNodes.length;
132
+ // Build per-domain info
133
+ // For each spec domain, find which mapping entries belong to it
134
+ const domainMappings = new Map();
135
+ if (mapping) {
136
+ for (const m of mapping.mappings) {
137
+ const entry = domainMappings.get(m.domain) ?? { mappedFunctions: new Set(), sourceFiles: new Set() };
138
+ for (const fn of m.functions) {
139
+ if (fn.name && fn.name !== '*')
140
+ entry.mappedFunctions.add(fn.name);
141
+ if (fn.file && fn.file !== '*')
142
+ entry.sourceFiles.add(fn.file);
143
+ }
144
+ domainMappings.set(m.domain, entry);
145
+ }
146
+ }
147
+ const domains = await Promise.all(specDomains.map(async (d) => {
148
+ const dm = domainMappings.get(d.name);
149
+ const sourceFiles = dm ? Array.from(dm.sourceFiles) : [];
150
+ const mappedFunctionCount = dm ? dm.mappedFunctions.size : 0;
151
+ const sourcesModifiedAt = await maxMtime(sourceFiles, this.rootPath);
152
+ const coveragePct = d.requirementCount > 0
153
+ ? Math.round((mappedFunctionCount / Math.max(d.requirementCount, mappedFunctionCount)) * 100)
154
+ : 0;
155
+ return {
156
+ name: d.name,
157
+ specFile: d.specFile,
158
+ sourceFiles,
159
+ requirementCount: d.requirementCount,
160
+ mappedFunctionCount,
161
+ coveragePct,
162
+ specModifiedAt: d.specModifiedAt,
163
+ sourcesModifiedAt,
164
+ };
165
+ }));
166
+ // Hub coverage
167
+ const hubs = hubNodes.map(n => ({
168
+ name: n.name,
169
+ file: n.filePath,
170
+ fanIn: n.fanIn,
171
+ covered: isFunctionCovered(n, covered),
172
+ }));
173
+ const snapshot = {
174
+ version: '1',
175
+ generatedAt: new Date().toISOString(),
176
+ git,
177
+ coverage: {
178
+ totalFunctions,
179
+ coveredFunctions: coveredCount,
180
+ orphanFunctions: orphanCount,
181
+ coveragePct: totalFunctions > 0 ? Math.round((coveredCount / totalFunctions) * 100) : 0,
182
+ },
183
+ domains,
184
+ hubs,
185
+ };
186
+ // Persist
187
+ await writeFile(join(analysisDir, ARTIFACT_SPEC_SNAPSHOT), JSON.stringify(snapshot, null, 2));
188
+ return snapshot;
189
+ }
190
+ /** Load a previously generated snapshot, or return null if not found. */
191
+ static async load(rootPath) {
192
+ try {
193
+ const raw = await readFile(join(rootPath, SPEC_GEN_DIR, SPEC_GEN_ANALYSIS_SUBDIR, ARTIFACT_SPEC_SNAPSHOT), 'utf-8');
194
+ return JSON.parse(raw);
195
+ }
196
+ catch {
197
+ return null;
198
+ }
199
+ }
200
+ }
201
+ //# sourceMappingURL=spec-snapshot-generator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"spec-snapshot-generator.js","sourceRoot":"","sources":["../../../src/core/analyzer/spec-snapshot-generator.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,43 @@
1
+ /**
2
+ * UI Component Extractor
3
+ *
4
+ * Detects React, Vue, Svelte, and Angular UI components from source files
5
+ * using regex-based analysis (no tree-sitter required).
6
+ *
7
+ * Detection strategy per framework:
8
+ * - React: function/const export with PascalCase name in JSX/TSX files
9
+ * - Vue: Single File Components (.vue) with <template> blocks
10
+ * - Svelte: .svelte files (each file = one component)
11
+ * - Angular: @Component decorator
12
+ */
13
+ export interface ComponentProp {
14
+ name: string;
15
+ type: string;
16
+ required: boolean;
17
+ }
18
+ export interface UIComponent {
19
+ /** PascalCase component name */
20
+ name: string;
21
+ /** Path relative to project root */
22
+ file: string;
23
+ /** UI framework */
24
+ framework: 'react' | 'vue' | 'svelte' | 'angular';
25
+ /** Whether this is the default export */
26
+ isDefault: boolean;
27
+ /** 1-based line number of the declaration */
28
+ line: number;
29
+ /** Extracted props (up to MAX_PROPS) */
30
+ props: ComponentProp[];
31
+ }
32
+ /**
33
+ * Extract UI components from a list of absolute file paths.
34
+ *
35
+ * @param filePaths - Absolute paths to source files
36
+ * @param rootDir - Project root used to compute relative paths in output
37
+ */
38
+ export declare function extractUIComponents(filePaths: string[], rootDir: string): Promise<UIComponent[]>;
39
+ /**
40
+ * Summarise components by framework for display / artifact embedding.
41
+ */
42
+ export declare function summarizeUIComponents(components: UIComponent[]): Record<string, number>;
43
+ //# sourceMappingURL=ui-component-extractor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ui-component-extractor.d.ts","sourceRoot":"","sources":["../../../src/core/analyzer/ui-component-extractor.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AASH,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,WAAW,WAAW;IAC1B,gCAAgC;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,oCAAoC;IACpC,IAAI,EAAE,MAAM,CAAC;IACb,mBAAmB;IACnB,SAAS,EAAE,OAAO,GAAG,KAAK,GAAG,QAAQ,GAAG,SAAS,CAAC;IAClD,yCAAyC;IACzC,SAAS,EAAE,OAAO,CAAC;IACnB,6CAA6C;IAC7C,IAAI,EAAE,MAAM,CAAC;IACb,wCAAwC;IACxC,KAAK,EAAE,aAAa,EAAE,CAAC;CACxB;AAmOD;;;;;GAKG;AACH,wBAAsB,mBAAmB,CACvC,SAAS,EAAE,MAAM,EAAE,EACnB,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,WAAW,EAAE,CAAC,CAUxB;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CACnC,UAAU,EAAE,WAAW,EAAE,GACxB,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAMxB"}