popeye-cli 1.7.0 → 1.9.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 (174) hide show
  1. package/README.md +148 -7
  2. package/cheatsheet.md +440 -0
  3. package/dist/cli/commands/db.d.ts +10 -0
  4. package/dist/cli/commands/db.d.ts.map +1 -0
  5. package/dist/cli/commands/db.js +240 -0
  6. package/dist/cli/commands/db.js.map +1 -0
  7. package/dist/cli/commands/doctor.d.ts +18 -0
  8. package/dist/cli/commands/doctor.d.ts.map +1 -0
  9. package/dist/cli/commands/doctor.js +255 -0
  10. package/dist/cli/commands/doctor.js.map +1 -0
  11. package/dist/cli/commands/index.d.ts +3 -0
  12. package/dist/cli/commands/index.d.ts.map +1 -1
  13. package/dist/cli/commands/index.js +3 -0
  14. package/dist/cli/commands/index.js.map +1 -1
  15. package/dist/cli/commands/review.d.ts +31 -0
  16. package/dist/cli/commands/review.d.ts.map +1 -0
  17. package/dist/cli/commands/review.js +156 -0
  18. package/dist/cli/commands/review.js.map +1 -0
  19. package/dist/cli/index.d.ts.map +1 -1
  20. package/dist/cli/index.js +4 -1
  21. package/dist/cli/index.js.map +1 -1
  22. package/dist/cli/interactive.d.ts.map +1 -1
  23. package/dist/cli/interactive.js +218 -61
  24. package/dist/cli/interactive.js.map +1 -1
  25. package/dist/generators/admin-wizard.d.ts +25 -0
  26. package/dist/generators/admin-wizard.d.ts.map +1 -0
  27. package/dist/generators/admin-wizard.js +123 -0
  28. package/dist/generators/admin-wizard.js.map +1 -0
  29. package/dist/generators/all.d.ts.map +1 -1
  30. package/dist/generators/all.js +10 -3
  31. package/dist/generators/all.js.map +1 -1
  32. package/dist/generators/database.d.ts +58 -0
  33. package/dist/generators/database.d.ts.map +1 -0
  34. package/dist/generators/database.js +229 -0
  35. package/dist/generators/database.js.map +1 -0
  36. package/dist/generators/fullstack.d.ts.map +1 -1
  37. package/dist/generators/fullstack.js +23 -7
  38. package/dist/generators/fullstack.js.map +1 -1
  39. package/dist/generators/index.d.ts +2 -0
  40. package/dist/generators/index.d.ts.map +1 -1
  41. package/dist/generators/index.js +2 -0
  42. package/dist/generators/index.js.map +1 -1
  43. package/dist/generators/templates/admin-wizard-python.d.ts +32 -0
  44. package/dist/generators/templates/admin-wizard-python.d.ts.map +1 -0
  45. package/dist/generators/templates/admin-wizard-python.js +425 -0
  46. package/dist/generators/templates/admin-wizard-python.js.map +1 -0
  47. package/dist/generators/templates/admin-wizard-react.d.ts +48 -0
  48. package/dist/generators/templates/admin-wizard-react.d.ts.map +1 -0
  49. package/dist/generators/templates/admin-wizard-react.js +554 -0
  50. package/dist/generators/templates/admin-wizard-react.js.map +1 -0
  51. package/dist/generators/templates/database-docker.d.ts +23 -0
  52. package/dist/generators/templates/database-docker.d.ts.map +1 -0
  53. package/dist/generators/templates/database-docker.js +221 -0
  54. package/dist/generators/templates/database-docker.js.map +1 -0
  55. package/dist/generators/templates/database-python.d.ts +54 -0
  56. package/dist/generators/templates/database-python.d.ts.map +1 -0
  57. package/dist/generators/templates/database-python.js +723 -0
  58. package/dist/generators/templates/database-python.js.map +1 -0
  59. package/dist/generators/templates/database-typescript.d.ts +34 -0
  60. package/dist/generators/templates/database-typescript.d.ts.map +1 -0
  61. package/dist/generators/templates/database-typescript.js +232 -0
  62. package/dist/generators/templates/database-typescript.js.map +1 -0
  63. package/dist/generators/templates/fullstack.d.ts.map +1 -1
  64. package/dist/generators/templates/fullstack.js +29 -0
  65. package/dist/generators/templates/fullstack.js.map +1 -1
  66. package/dist/generators/templates/index.d.ts +5 -0
  67. package/dist/generators/templates/index.d.ts.map +1 -1
  68. package/dist/generators/templates/index.js +5 -0
  69. package/dist/generators/templates/index.js.map +1 -1
  70. package/dist/state/index.d.ts +10 -0
  71. package/dist/state/index.d.ts.map +1 -1
  72. package/dist/state/index.js +21 -0
  73. package/dist/state/index.js.map +1 -1
  74. package/dist/types/audit.d.ts +623 -0
  75. package/dist/types/audit.d.ts.map +1 -0
  76. package/dist/types/audit.js +240 -0
  77. package/dist/types/audit.js.map +1 -0
  78. package/dist/types/database-runtime.d.ts +86 -0
  79. package/dist/types/database-runtime.d.ts.map +1 -0
  80. package/dist/types/database-runtime.js +61 -0
  81. package/dist/types/database-runtime.js.map +1 -0
  82. package/dist/types/database.d.ts +85 -0
  83. package/dist/types/database.d.ts.map +1 -0
  84. package/dist/types/database.js +71 -0
  85. package/dist/types/database.js.map +1 -0
  86. package/dist/types/index.d.ts +2 -0
  87. package/dist/types/index.d.ts.map +1 -1
  88. package/dist/types/index.js +4 -0
  89. package/dist/types/index.js.map +1 -1
  90. package/dist/types/workflow.d.ts +36 -0
  91. package/dist/types/workflow.d.ts.map +1 -1
  92. package/dist/types/workflow.js +7 -0
  93. package/dist/types/workflow.js.map +1 -1
  94. package/dist/workflow/audit-analyzer.d.ts +58 -0
  95. package/dist/workflow/audit-analyzer.d.ts.map +1 -0
  96. package/dist/workflow/audit-analyzer.js +420 -0
  97. package/dist/workflow/audit-analyzer.js.map +1 -0
  98. package/dist/workflow/audit-mode.d.ts +28 -0
  99. package/dist/workflow/audit-mode.d.ts.map +1 -0
  100. package/dist/workflow/audit-mode.js +169 -0
  101. package/dist/workflow/audit-mode.js.map +1 -0
  102. package/dist/workflow/audit-recovery.d.ts +61 -0
  103. package/dist/workflow/audit-recovery.d.ts.map +1 -0
  104. package/dist/workflow/audit-recovery.js +242 -0
  105. package/dist/workflow/audit-recovery.js.map +1 -0
  106. package/dist/workflow/audit-reporter.d.ts +65 -0
  107. package/dist/workflow/audit-reporter.d.ts.map +1 -0
  108. package/dist/workflow/audit-reporter.js +301 -0
  109. package/dist/workflow/audit-reporter.js.map +1 -0
  110. package/dist/workflow/audit-scanner.d.ts +87 -0
  111. package/dist/workflow/audit-scanner.d.ts.map +1 -0
  112. package/dist/workflow/audit-scanner.js +768 -0
  113. package/dist/workflow/audit-scanner.js.map +1 -0
  114. package/dist/workflow/db-setup-runner.d.ts +63 -0
  115. package/dist/workflow/db-setup-runner.d.ts.map +1 -0
  116. package/dist/workflow/db-setup-runner.js +336 -0
  117. package/dist/workflow/db-setup-runner.js.map +1 -0
  118. package/dist/workflow/db-state-machine.d.ts +30 -0
  119. package/dist/workflow/db-state-machine.d.ts.map +1 -0
  120. package/dist/workflow/db-state-machine.js +51 -0
  121. package/dist/workflow/db-state-machine.js.map +1 -0
  122. package/dist/workflow/index.d.ts +7 -0
  123. package/dist/workflow/index.d.ts.map +1 -1
  124. package/dist/workflow/index.js +7 -0
  125. package/dist/workflow/index.js.map +1 -1
  126. package/package.json +1 -1
  127. package/src/cli/commands/db.ts +281 -0
  128. package/src/cli/commands/doctor.ts +273 -0
  129. package/src/cli/commands/index.ts +3 -0
  130. package/src/cli/commands/review.ts +187 -0
  131. package/src/cli/index.ts +6 -0
  132. package/src/cli/interactive.ts +174 -4
  133. package/src/generators/admin-wizard.ts +146 -0
  134. package/src/generators/all.ts +10 -3
  135. package/src/generators/database.ts +286 -0
  136. package/src/generators/fullstack.ts +26 -9
  137. package/src/generators/index.ts +12 -0
  138. package/src/generators/templates/admin-wizard-python.ts +431 -0
  139. package/src/generators/templates/admin-wizard-react.ts +560 -0
  140. package/src/generators/templates/database-docker.ts +227 -0
  141. package/src/generators/templates/database-python.ts +734 -0
  142. package/src/generators/templates/database-typescript.ts +238 -0
  143. package/src/generators/templates/fullstack.ts +29 -0
  144. package/src/generators/templates/index.ts +5 -0
  145. package/src/state/index.ts +28 -0
  146. package/src/types/audit.ts +294 -0
  147. package/src/types/database-runtime.ts +69 -0
  148. package/src/types/database.ts +84 -0
  149. package/src/types/index.ts +29 -0
  150. package/src/types/workflow.ts +20 -0
  151. package/src/workflow/audit-analyzer.ts +491 -0
  152. package/src/workflow/audit-mode.ts +240 -0
  153. package/src/workflow/audit-recovery.ts +284 -0
  154. package/src/workflow/audit-reporter.ts +370 -0
  155. package/src/workflow/audit-scanner.ts +873 -0
  156. package/src/workflow/db-setup-runner.ts +391 -0
  157. package/src/workflow/db-state-machine.ts +58 -0
  158. package/src/workflow/index.ts +7 -0
  159. package/tests/cli/commands/review.test.ts +52 -0
  160. package/tests/generators/admin-wizard-orchestrator.test.ts +64 -0
  161. package/tests/generators/admin-wizard-templates.test.ts +366 -0
  162. package/tests/generators/cross-phase-integration.test.ts +383 -0
  163. package/tests/generators/database.test.ts +456 -0
  164. package/tests/generators/fe-be-db-integration.test.ts +613 -0
  165. package/tests/types/audit.test.ts +250 -0
  166. package/tests/types/database-runtime.test.ts +158 -0
  167. package/tests/types/database.test.ts +187 -0
  168. package/tests/workflow/audit-analyzer.test.ts +281 -0
  169. package/tests/workflow/audit-mode.test.ts +114 -0
  170. package/tests/workflow/audit-recovery.test.ts +237 -0
  171. package/tests/workflow/audit-reporter.test.ts +254 -0
  172. package/tests/workflow/audit-scanner.test.ts +270 -0
  173. package/tests/workflow/db-setup-runner.test.ts +211 -0
  174. package/tests/workflow/db-state-machine.test.ts +117 -0
@@ -0,0 +1,238 @@
1
+ /**
2
+ * TypeScript backend database template functions
3
+ * Generates Prisma + pgvector files for future TS backend projects
4
+ * NOT wired into any generator in Phase 1 - templates exist for future use
5
+ */
6
+
7
+ /**
8
+ * Generate Prisma schema with PostgreSQL datasource and pgvector
9
+ */
10
+ export function generatePrismaSchema(projectName: string): string {
11
+ return `// Prisma schema for ${projectName}
12
+ // Learn more: https://pris.ly/d/prisma-schema
13
+
14
+ generator client {
15
+ provider = "prisma-client-js"
16
+ previewFeatures = ["postgresqlExtensions"]
17
+ }
18
+
19
+ datasource db {
20
+ provider = "postgresql"
21
+ url = env("DATABASE_URL")
22
+ extensions = [pgvector(map: "vector", schema: "public")]
23
+ }
24
+
25
+ model AppSettings {
26
+ id Int @id @default(autoincrement())
27
+ key String @unique
28
+ value String
29
+ createdAt DateTime @default(now()) @map("created_at")
30
+ updatedAt DateTime @updatedAt @map("updated_at")
31
+
32
+ @@map("app_settings")
33
+ }
34
+ `;
35
+ }
36
+
37
+ /**
38
+ * Generate PrismaClient singleton with connection handling
39
+ */
40
+ export function generatePrismaClient(projectName: string): string {
41
+ return `/**
42
+ * Prisma client singleton for ${projectName}.
43
+ *
44
+ * Ensures a single PrismaClient instance is reused across the application.
45
+ */
46
+
47
+ import { PrismaClient } from "@prisma/client";
48
+
49
+ const globalForPrisma = globalThis as unknown as {
50
+ prisma: PrismaClient | undefined;
51
+ };
52
+
53
+ export const prisma =
54
+ globalForPrisma.prisma ??
55
+ new PrismaClient({
56
+ log:
57
+ process.env.NODE_ENV === "development"
58
+ ? ["query", "error", "warn"]
59
+ : ["error"],
60
+ });
61
+
62
+ if (process.env.NODE_ENV !== "production") {
63
+ globalForPrisma.prisma = prisma;
64
+ }
65
+
66
+ export default prisma;
67
+ `;
68
+ }
69
+
70
+ /**
71
+ * Generate .env.example additions for Prisma
72
+ */
73
+ export function generatePrismaEnv(): string {
74
+ return `# Database
75
+ DATABASE_URL="postgresql://postgres:postgres@localhost:5432/mydb?schema=public"
76
+ `;
77
+ }
78
+
79
+ /**
80
+ * Generate Prisma seed script
81
+ */
82
+ export function generatePrismaSeed(): string {
83
+ return `/**
84
+ * Prisma seed script.
85
+ *
86
+ * Seeds the database with initial data using upsert pattern.
87
+ * Run with: npx prisma db seed
88
+ */
89
+
90
+ import { PrismaClient } from "@prisma/client";
91
+
92
+ const prisma = new PrismaClient();
93
+
94
+ async function main() {
95
+ console.log("Seeding database...");
96
+
97
+ // Upsert default app settings
98
+ await prisma.appSettings.upsert({
99
+ where: { key: "app_version" },
100
+ update: { value: "1.0.0" },
101
+ create: { key: "app_version", value: "1.0.0" },
102
+ });
103
+
104
+ console.log("Seeding complete.");
105
+ }
106
+
107
+ main()
108
+ .then(async () => {
109
+ await prisma.$disconnect();
110
+ })
111
+ .catch(async (e) => {
112
+ console.error(e);
113
+ await prisma.$disconnect();
114
+ process.exit(1);
115
+ });
116
+ `;
117
+ }
118
+
119
+ /**
120
+ * Generate database health check for Prisma
121
+ */
122
+ export function generatePrismaDbHealth(): string {
123
+ return `/**
124
+ * Database health check utilities.
125
+ *
126
+ * Tests connection and checks migration status.
127
+ */
128
+
129
+ import prisma from "./client";
130
+
131
+ export interface DbHealthResult {
132
+ connected: boolean;
133
+ migrations?: { current: string | null };
134
+ error?: string;
135
+ }
136
+
137
+ /**
138
+ * Check database connectivity and migration status.
139
+ */
140
+ export async function checkDbHealth(): Promise<DbHealthResult> {
141
+ try {
142
+ // Test basic connectivity
143
+ await prisma.$queryRaw\`SELECT 1\`;
144
+
145
+ // Check migration status
146
+ let currentMigration: string | null = null;
147
+ try {
148
+ const result = await prisma.$queryRaw<
149
+ Array<{ migration_name: string }>
150
+ >\`SELECT migration_name FROM _prisma_migrations ORDER BY finished_at DESC LIMIT 1\`;
151
+ currentMigration = result[0]?.migration_name ?? null;
152
+ } catch {
153
+ // _prisma_migrations table may not exist yet
154
+ }
155
+
156
+ return {
157
+ connected: true,
158
+ migrations: { current: currentMigration },
159
+ };
160
+ } catch (error) {
161
+ return {
162
+ connected: false,
163
+ error: error instanceof Error ? error.message : "Unknown error",
164
+ };
165
+ }
166
+ }
167
+ `;
168
+ }
169
+
170
+ /**
171
+ * Generate pgvector raw query helpers for Prisma
172
+ */
173
+ export function generatePrismaVectorHelpers(): string {
174
+ return `/**
175
+ * pgvector helpers using Prisma raw queries.
176
+ *
177
+ * Provides cosine similarity search and vector extension checks.
178
+ */
179
+
180
+ import prisma from "./client";
181
+
182
+ /**
183
+ * Perform cosine similarity search against a vector column.
184
+ */
185
+ export async function cosineSimilaritySearch(
186
+ tableName: string,
187
+ columnName: string,
188
+ queryVector: number[],
189
+ limit: number = 10
190
+ ): Promise<Array<{ id: number; similarity: number }>> {
191
+ const vectorStr = \`[\${queryVector.join(",")}]\`;
192
+
193
+ const results = await prisma.$queryRawUnsafe<
194
+ Array<{ id: number; similarity: number }>
195
+ >(
196
+ \`SELECT id, 1 - (\${columnName} <=> $1::vector) AS similarity \` +
197
+ \`FROM \${tableName} \` +
198
+ \`ORDER BY \${columnName} <=> $1::vector \` +
199
+ \`LIMIT $2\`,
200
+ vectorStr,
201
+ limit
202
+ );
203
+
204
+ return results;
205
+ }
206
+
207
+ /**
208
+ * Check if the pgvector extension is installed.
209
+ */
210
+ export async function checkVectorExtension(): Promise<boolean> {
211
+ try {
212
+ const result = await prisma.$queryRaw<Array<{ extname: string }>>\`
213
+ SELECT extname FROM pg_extension WHERE extname = 'vector'
214
+ \`;
215
+ return result.length > 0;
216
+ } catch {
217
+ return false;
218
+ }
219
+ }
220
+ `;
221
+ }
222
+
223
+ /**
224
+ * Generate Prisma DB index.ts with re-exports
225
+ */
226
+ export function generatePrismaDbInit(): string {
227
+ return `/**
228
+ * Database package re-exports.
229
+ */
230
+
231
+ export { prisma, default as PrismaClient } from "./client";
232
+ export { checkDbHealth, type DbHealthResult } from "./health";
233
+ export {
234
+ cosineSimilaritySearch,
235
+ checkVectorExtension,
236
+ } from "./vector";
237
+ `;
238
+ }
@@ -212,6 +212,35 @@ cd apps/frontend && npm run lint
212
212
  cd apps/backend && ruff check .
213
213
  \`\`\`
214
214
 
215
+ ## Database
216
+
217
+ Database is **UNCONFIGURED** by default. The app runs without a database in limited mode.
218
+
219
+ ### Local Docker (recommended for development)
220
+
221
+ \`\`\`bash
222
+ # docker-compose starts PostgreSQL automatically
223
+ docker-compose up
224
+ \`\`\`
225
+
226
+ ### Managed Database
227
+
228
+ Set \`DATABASE_URL\` in \`apps/backend/.env\` to connect to a managed PostgreSQL instance (Neon, Supabase, etc.).
229
+
230
+ ### Health Check
231
+
232
+ \`\`\`bash
233
+ # Check database connectivity and migration status
234
+ curl http://localhost:8000/health/db
235
+ \`\`\`
236
+
237
+ ### Migrations
238
+
239
+ \`\`\`bash
240
+ cd apps/backend
241
+ alembic upgrade head
242
+ \`\`\`
243
+
215
244
  ## Apps
216
245
 
217
246
  ### Frontend (apps/frontend)
@@ -14,3 +14,8 @@ export * as websiteLandingTemplates from './website-landing.js';
14
14
  export * as websitePricingTemplates from './website-pricing.js';
15
15
  export * as websiteLayoutTemplates from './website-layout.js';
16
16
  export * as websiteSectionTemplates from './website-sections.js';
17
+ export * as databasePythonTemplates from './database-python.js';
18
+ export * as databaseTypescriptTemplates from './database-typescript.js';
19
+ export * as databaseDockerTemplates from './database-docker.js';
20
+ export * as adminWizardPythonTemplates from './admin-wizard-python.js';
21
+ export * as adminWizardReactTemplates from './admin-wizard-react.js';
@@ -15,6 +15,9 @@ import type {
15
15
  } from '../types/workflow.js';
16
16
  import type { ConsensusIteration } from '../types/consensus.js';
17
17
  import type { ProjectSpec } from '../types/project.js';
18
+ import { isWorkspace } from '../types/project.js';
19
+ import { DEFAULT_DB_CONFIG } from '../types/database.js';
20
+ import type { DbConfig } from '../types/database.js';
18
21
  import {
19
22
  loadState,
20
23
  saveState,
@@ -63,6 +66,11 @@ export async function createProject(
63
66
  qaEnabled: true,
64
67
  };
65
68
 
69
+ // Set default DB config for workspace projects (fullstack / all)
70
+ if (isWorkspace(spec.language)) {
71
+ state.dbConfig = { ...DEFAULT_DB_CONFIG };
72
+ }
73
+
66
74
  await saveState(projectDir, state);
67
75
 
68
76
  // Register project in global registry
@@ -395,6 +403,26 @@ export async function storeWebsiteStrategyPath(
395
403
  return updateState(projectDir, { websiteStrategy: strategyPath });
396
404
  }
397
405
 
406
+ /**
407
+ * Update database configuration with partial updates
408
+ * Merges partial DbConfig updates into the existing config
409
+ *
410
+ * @param projectDir - The project root directory
411
+ * @param updates - Partial DbConfig updates to merge
412
+ * @returns The updated project state
413
+ */
414
+ export async function updateDbConfig(
415
+ projectDir: string,
416
+ updates: Partial<DbConfig>
417
+ ): Promise<ProjectState> {
418
+ const current = await loadProject(projectDir);
419
+ const currentDbConfig = current.dbConfig || { ...DEFAULT_DB_CONFIG };
420
+
421
+ return updateState(projectDir, {
422
+ dbConfig: { ...currentDbConfig, ...updates },
423
+ });
424
+ }
425
+
398
426
  /**
399
427
  * Mark the project as complete
400
428
  *
@@ -0,0 +1,294 @@
1
+ /**
2
+ * Audit system type definitions.
3
+ *
4
+ * Zod schemas and TypeScript types for the post-build audit/review feature.
5
+ * Covers scanning, analysis, reporting, and recovery.
6
+ */
7
+ import { z } from 'zod';
8
+
9
+ // ---------------------------------------------------------------------------
10
+ // Enums
11
+ // ---------------------------------------------------------------------------
12
+
13
+ export const AuditSeveritySchema = z.enum(['critical', 'major', 'minor', 'info']);
14
+ export type AuditSeverity = z.infer<typeof AuditSeveritySchema>;
15
+
16
+ export const AuditCategorySchema = z.enum([
17
+ 'feature-completeness',
18
+ 'integration-wiring',
19
+ 'test-coverage',
20
+ 'config-deployment',
21
+ 'dependency-sanity',
22
+ 'consistency',
23
+ 'security',
24
+ 'documentation',
25
+ ]);
26
+ export type AuditCategory = z.infer<typeof AuditCategorySchema>;
27
+
28
+ export const ComponentKindSchema = z.enum([
29
+ 'frontend',
30
+ 'backend',
31
+ 'website',
32
+ 'shared',
33
+ 'infra',
34
+ ]);
35
+ export type ComponentKind = z.infer<typeof ComponentKindSchema>;
36
+
37
+ // ---------------------------------------------------------------------------
38
+ // Evidence
39
+ // ---------------------------------------------------------------------------
40
+
41
+ export const AuditEvidenceSchema = z.object({
42
+ file: z.string(),
43
+ line: z.number().optional(),
44
+ snippet: z.string().optional(),
45
+ description: z.string().optional(),
46
+ });
47
+ export type AuditEvidence = z.infer<typeof AuditEvidenceSchema>;
48
+
49
+ // ---------------------------------------------------------------------------
50
+ // Dependency manifest
51
+ // ---------------------------------------------------------------------------
52
+
53
+ export const DependencyManifestSchema = z.object({
54
+ file: z.string(),
55
+ type: z.enum(['package.json', 'requirements.txt', 'pyproject.toml', 'other']),
56
+ dependencies: z.record(z.string(), z.string()).optional(),
57
+ devDependencies: z.record(z.string(), z.string()).optional(),
58
+ });
59
+ export type DependencyManifest = z.infer<typeof DependencyManifestSchema>;
60
+
61
+ // ---------------------------------------------------------------------------
62
+ // File entry
63
+ // ---------------------------------------------------------------------------
64
+
65
+ export const FileEntrySchema = z.object({
66
+ path: z.string(),
67
+ lines: z.number().optional(),
68
+ extension: z.string().optional(),
69
+ });
70
+ export type FileEntry = z.infer<typeof FileEntrySchema>;
71
+
72
+ export const FileExcerptSchema = z.object({
73
+ path: z.string(),
74
+ content: z.string(),
75
+ });
76
+ export type FileExcerpt = z.infer<typeof FileExcerptSchema>;
77
+
78
+ // ---------------------------------------------------------------------------
79
+ // Component scan (per-component scanning for upgrade safety)
80
+ // ---------------------------------------------------------------------------
81
+
82
+ export const ComponentScanSchema = z.object({
83
+ kind: ComponentKindSchema,
84
+ rootDir: z.string(),
85
+ language: z.enum(['typescript', 'python', 'mixed']),
86
+ framework: z.string().optional(),
87
+ entryPoints: z.array(z.string()),
88
+ routeFiles: z.array(z.string()),
89
+ testFiles: z.array(FileEntrySchema),
90
+ sourceFiles: z.array(FileEntrySchema),
91
+ dependencyManifests: z.array(DependencyManifestSchema),
92
+ });
93
+ export type ComponentScan = z.infer<typeof ComponentScanSchema>;
94
+
95
+ // ---------------------------------------------------------------------------
96
+ // Wiring matrix (deterministic FE<->BE wiring check)
97
+ // ---------------------------------------------------------------------------
98
+
99
+ export const WiringMismatchSchema = z.object({
100
+ type: z.string(),
101
+ details: z.string(),
102
+ evidence: z.array(AuditEvidenceSchema),
103
+ });
104
+ export type WiringMismatch = z.infer<typeof WiringMismatchSchema>;
105
+
106
+ export const WiringMatrixSchema = z.object({
107
+ frontendApiBaseEnvKeys: z.array(z.string()),
108
+ frontendApiBaseResolved: z.string().optional(),
109
+ backendCorsOrigins: z.array(z.string()).optional(),
110
+ backendApiPrefix: z.string().optional(),
111
+ potentialMismatches: z.array(WiringMismatchSchema),
112
+ });
113
+ export type WiringMatrix = z.infer<typeof WiringMatrixSchema>;
114
+
115
+ // ---------------------------------------------------------------------------
116
+ // Project scan result
117
+ // ---------------------------------------------------------------------------
118
+
119
+ export const ProjectScanResultSchema = z.object({
120
+ tree: z.string(),
121
+ // Component-based scanning (upgrade-safe)
122
+ components: z.array(ComponentScanSchema),
123
+ detectedComposition: z.array(ComponentKindSchema),
124
+ stateLanguage: z.string(),
125
+ compositionMismatch: z.boolean(),
126
+ // Aggregated totals
127
+ sourceFiles: z.array(FileEntrySchema),
128
+ testFiles: z.array(FileEntrySchema),
129
+ configFiles: z.array(z.string()),
130
+ entryPoints: z.array(z.string()),
131
+ routeFiles: z.array(z.string()),
132
+ dependencies: z.array(DependencyManifestSchema),
133
+ totalSourceFiles: z.number(),
134
+ totalTestFiles: z.number(),
135
+ totalLinesOfCode: z.number(),
136
+ totalLinesOfTests: z.number(),
137
+ language: z.string(),
138
+ // Priority doc reads
139
+ claudeMdContent: z.string().optional(),
140
+ readmeContent: z.string().optional(),
141
+ docsIndex: z.array(z.string()),
142
+ keyFileSnippets: z.array(FileExcerptSchema),
143
+ // Wiring matrix
144
+ wiring: WiringMatrixSchema.optional(),
145
+ // Config
146
+ envExampleContent: z.string().optional(),
147
+ dockerComposeContent: z.string().optional(),
148
+ });
149
+ export type ProjectScanResult = z.infer<typeof ProjectScanResultSchema>;
150
+
151
+ // ---------------------------------------------------------------------------
152
+ // Search metadata (Serena tracking)
153
+ // ---------------------------------------------------------------------------
154
+
155
+ export const SearchMetadataSchema = z.object({
156
+ serenaUsed: z.boolean(),
157
+ serenaRetries: z.number(),
158
+ serenaErrors: z.array(z.string()),
159
+ fallbackUsed: z.boolean(),
160
+ fallbackTool: z.string(),
161
+ searchQueries: z.array(z.string()),
162
+ });
163
+ export type SearchMetadata = z.infer<typeof SearchMetadataSchema>;
164
+
165
+ // ---------------------------------------------------------------------------
166
+ // Audit finding
167
+ // ---------------------------------------------------------------------------
168
+
169
+ export const AuditFindingSchema = z.object({
170
+ id: z.string(),
171
+ category: AuditCategorySchema,
172
+ severity: AuditSeveritySchema,
173
+ title: z.string(),
174
+ description: z.string(),
175
+ evidence: z.array(AuditEvidenceSchema),
176
+ recommendation: z.string(),
177
+ autoFixable: z.boolean(),
178
+ });
179
+ export type AuditFinding = z.infer<typeof AuditFindingSchema>;
180
+
181
+ // ---------------------------------------------------------------------------
182
+ // Summary report
183
+ // ---------------------------------------------------------------------------
184
+
185
+ export const ProjectSummaryReportSchema = z.object({
186
+ projectName: z.string(),
187
+ language: z.string(),
188
+ totalSourceFiles: z.number(),
189
+ totalTestFiles: z.number(),
190
+ totalLinesOfCode: z.number(),
191
+ totalLinesOfTests: z.number(),
192
+ componentCount: z.number(),
193
+ detectedComposition: z.array(ComponentKindSchema),
194
+ entryPointCount: z.number(),
195
+ routeCount: z.number(),
196
+ dependencyCount: z.number(),
197
+ hasDocker: z.boolean(),
198
+ hasEnvExample: z.boolean(),
199
+ hasCiConfig: z.boolean(),
200
+ aiOverview: z.string().optional(),
201
+ });
202
+ export type ProjectSummaryReport = z.infer<typeof ProjectSummaryReportSchema>;
203
+
204
+ // ---------------------------------------------------------------------------
205
+ // Audit report
206
+ // ---------------------------------------------------------------------------
207
+
208
+ export const AuditRecommendationSchema = z.enum([
209
+ 'pass',
210
+ 'fix-and-recheck',
211
+ 'major-rework',
212
+ ]);
213
+ export type AuditRecommendation = z.infer<typeof AuditRecommendationSchema>;
214
+
215
+ export const ProjectAuditReportSchema = z.object({
216
+ projectName: z.string(),
217
+ language: z.string(),
218
+ auditedAt: z.string(),
219
+ auditRunId: z.string(),
220
+ summary: ProjectSummaryReportSchema,
221
+ findings: z.array(AuditFindingSchema),
222
+ overallScore: z.number(),
223
+ categoryScores: z.record(AuditCategorySchema, z.number()),
224
+ criticalCount: z.number(),
225
+ majorCount: z.number(),
226
+ minorCount: z.number(),
227
+ infoCount: z.number(),
228
+ passedChecks: z.array(z.string()),
229
+ searchMetadata: SearchMetadataSchema,
230
+ recommendation: AuditRecommendationSchema,
231
+ });
232
+ export type ProjectAuditReport = z.infer<typeof ProjectAuditReportSchema>;
233
+
234
+ // ---------------------------------------------------------------------------
235
+ // Recovery
236
+ // ---------------------------------------------------------------------------
237
+
238
+ export const RecoveryTaskSchema = z.object({
239
+ name: z.string(),
240
+ description: z.string(),
241
+ findingIds: z.array(z.string()),
242
+ acceptanceCriteria: z.array(z.string()),
243
+ testPlan: z.string().optional(),
244
+ appTarget: ComponentKindSchema,
245
+ });
246
+ export type RecoveryTask = z.infer<typeof RecoveryTaskSchema>;
247
+
248
+ export const RecoveryMilestoneSchema = z.object({
249
+ name: z.string(),
250
+ description: z.string(),
251
+ tasks: z.array(RecoveryTaskSchema),
252
+ });
253
+ export type RecoveryMilestone = z.infer<typeof RecoveryMilestoneSchema>;
254
+
255
+ export const RecoveryPlanSchema = z.object({
256
+ generatedAt: z.string(),
257
+ auditScore: z.number(),
258
+ auditRunId: z.string(),
259
+ totalFindings: z.number(),
260
+ criticalFindings: z.number(),
261
+ milestones: z.array(RecoveryMilestoneSchema),
262
+ estimatedEffort: z.string(),
263
+ });
264
+ export type RecoveryPlan = z.infer<typeof RecoveryPlanSchema>;
265
+
266
+ // ---------------------------------------------------------------------------
267
+ // Options & result
268
+ // ---------------------------------------------------------------------------
269
+
270
+ export const AuditModeOptionsSchema = z.object({
271
+ projectDir: z.string(),
272
+ depth: z.number().min(1).max(3).default(2),
273
+ runTests: z.boolean().default(true),
274
+ strict: z.boolean().default(false),
275
+ format: z.enum(['json', 'md', 'both']).default('both'),
276
+ autoRecover: z.boolean().default(true),
277
+ target: z.union([z.literal('all'), ComponentKindSchema]).default('all'),
278
+ });
279
+ export type AuditModeOptions = z.infer<typeof AuditModeOptionsSchema>;
280
+
281
+ export const AuditModeResultSchema = z.object({
282
+ success: z.boolean(),
283
+ summary: ProjectSummaryReportSchema,
284
+ audit: ProjectAuditReportSchema,
285
+ recovery: RecoveryPlanSchema.optional(),
286
+ reportPaths: z.object({
287
+ auditMd: z.string().optional(),
288
+ auditJson: z.string().optional(),
289
+ recoveryMd: z.string().optional(),
290
+ recoveryJson: z.string().optional(),
291
+ }),
292
+ error: z.string().optional(),
293
+ });
294
+ export type AuditModeResult = z.infer<typeof AuditModeResultSchema>;
@@ -0,0 +1,69 @@
1
+ /**
2
+ * Database runtime types and Zod schemas for Phase 2
3
+ * Defines setup pipeline results, readiness checks, and doctor output
4
+ */
5
+
6
+ import { z } from 'zod';
7
+ import { DbStatusSchema, DbSetupStepSchema } from './database.js';
8
+
9
+ /**
10
+ * Result of a single setup pipeline step
11
+ */
12
+ export const SetupStepResultSchema = z.object({
13
+ /** Which pipeline step */
14
+ step: DbSetupStepSchema,
15
+ /** Whether the step succeeded */
16
+ success: z.boolean(),
17
+ /** Human-readable status message */
18
+ message: z.string(),
19
+ /** Duration in milliseconds */
20
+ durationMs: z.number(),
21
+ /** Error details if step failed */
22
+ error: z.string().optional(),
23
+ });
24
+ export type SetupStepResult = z.infer<typeof SetupStepResultSchema>;
25
+
26
+ /**
27
+ * Full setup pipeline result
28
+ */
29
+ export const SetupResultSchema = z.object({
30
+ /** Whether the entire pipeline succeeded */
31
+ success: z.boolean(),
32
+ /** Individual step results */
33
+ steps: z.array(SetupStepResultSchema),
34
+ /** Total pipeline duration in milliseconds */
35
+ totalDurationMs: z.number(),
36
+ /** Final DB status after pipeline */
37
+ finalStatus: DbStatusSchema,
38
+ /** Error message if pipeline failed */
39
+ error: z.string().optional(),
40
+ });
41
+ export type SetupResult = z.infer<typeof SetupResultSchema>;
42
+
43
+ /**
44
+ * Single readiness check (used by doctor command)
45
+ */
46
+ export const ReadinessCheckSchema = z.object({
47
+ /** Check name */
48
+ name: z.string(),
49
+ /** Whether the check passed */
50
+ passed: z.boolean(),
51
+ /** Human-readable result message */
52
+ message: z.string(),
53
+ /** Severity level */
54
+ severity: z.enum(['critical', 'warning', 'info']),
55
+ });
56
+ export type ReadinessCheck = z.infer<typeof ReadinessCheckSchema>;
57
+
58
+ /**
59
+ * Full doctor readiness result
60
+ */
61
+ export const ReadinessResultSchema = z.object({
62
+ /** Overall health status */
63
+ healthy: z.boolean(),
64
+ /** Individual check results */
65
+ checks: z.array(ReadinessCheckSchema),
66
+ /** ISO timestamp of when checks ran */
67
+ timestamp: z.string(),
68
+ });
69
+ export type ReadinessResult = z.infer<typeof ReadinessResultSchema>;