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.
- package/README.md +148 -7
- package/cheatsheet.md +440 -0
- package/dist/cli/commands/db.d.ts +10 -0
- package/dist/cli/commands/db.d.ts.map +1 -0
- package/dist/cli/commands/db.js +240 -0
- package/dist/cli/commands/db.js.map +1 -0
- package/dist/cli/commands/doctor.d.ts +18 -0
- package/dist/cli/commands/doctor.d.ts.map +1 -0
- package/dist/cli/commands/doctor.js +255 -0
- package/dist/cli/commands/doctor.js.map +1 -0
- package/dist/cli/commands/index.d.ts +3 -0
- package/dist/cli/commands/index.d.ts.map +1 -1
- package/dist/cli/commands/index.js +3 -0
- package/dist/cli/commands/index.js.map +1 -1
- package/dist/cli/commands/review.d.ts +31 -0
- package/dist/cli/commands/review.d.ts.map +1 -0
- package/dist/cli/commands/review.js +156 -0
- package/dist/cli/commands/review.js.map +1 -0
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +4 -1
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/interactive.d.ts.map +1 -1
- package/dist/cli/interactive.js +218 -61
- package/dist/cli/interactive.js.map +1 -1
- package/dist/generators/admin-wizard.d.ts +25 -0
- package/dist/generators/admin-wizard.d.ts.map +1 -0
- package/dist/generators/admin-wizard.js +123 -0
- package/dist/generators/admin-wizard.js.map +1 -0
- package/dist/generators/all.d.ts.map +1 -1
- package/dist/generators/all.js +10 -3
- package/dist/generators/all.js.map +1 -1
- package/dist/generators/database.d.ts +58 -0
- package/dist/generators/database.d.ts.map +1 -0
- package/dist/generators/database.js +229 -0
- package/dist/generators/database.js.map +1 -0
- package/dist/generators/fullstack.d.ts.map +1 -1
- package/dist/generators/fullstack.js +23 -7
- package/dist/generators/fullstack.js.map +1 -1
- package/dist/generators/index.d.ts +2 -0
- package/dist/generators/index.d.ts.map +1 -1
- package/dist/generators/index.js +2 -0
- package/dist/generators/index.js.map +1 -1
- package/dist/generators/templates/admin-wizard-python.d.ts +32 -0
- package/dist/generators/templates/admin-wizard-python.d.ts.map +1 -0
- package/dist/generators/templates/admin-wizard-python.js +425 -0
- package/dist/generators/templates/admin-wizard-python.js.map +1 -0
- package/dist/generators/templates/admin-wizard-react.d.ts +48 -0
- package/dist/generators/templates/admin-wizard-react.d.ts.map +1 -0
- package/dist/generators/templates/admin-wizard-react.js +554 -0
- package/dist/generators/templates/admin-wizard-react.js.map +1 -0
- package/dist/generators/templates/database-docker.d.ts +23 -0
- package/dist/generators/templates/database-docker.d.ts.map +1 -0
- package/dist/generators/templates/database-docker.js +221 -0
- package/dist/generators/templates/database-docker.js.map +1 -0
- package/dist/generators/templates/database-python.d.ts +54 -0
- package/dist/generators/templates/database-python.d.ts.map +1 -0
- package/dist/generators/templates/database-python.js +723 -0
- package/dist/generators/templates/database-python.js.map +1 -0
- package/dist/generators/templates/database-typescript.d.ts +34 -0
- package/dist/generators/templates/database-typescript.d.ts.map +1 -0
- package/dist/generators/templates/database-typescript.js +232 -0
- package/dist/generators/templates/database-typescript.js.map +1 -0
- package/dist/generators/templates/fullstack.d.ts.map +1 -1
- package/dist/generators/templates/fullstack.js +29 -0
- package/dist/generators/templates/fullstack.js.map +1 -1
- package/dist/generators/templates/index.d.ts +5 -0
- package/dist/generators/templates/index.d.ts.map +1 -1
- package/dist/generators/templates/index.js +5 -0
- package/dist/generators/templates/index.js.map +1 -1
- package/dist/state/index.d.ts +10 -0
- package/dist/state/index.d.ts.map +1 -1
- package/dist/state/index.js +21 -0
- package/dist/state/index.js.map +1 -1
- package/dist/types/audit.d.ts +623 -0
- package/dist/types/audit.d.ts.map +1 -0
- package/dist/types/audit.js +240 -0
- package/dist/types/audit.js.map +1 -0
- package/dist/types/database-runtime.d.ts +86 -0
- package/dist/types/database-runtime.d.ts.map +1 -0
- package/dist/types/database-runtime.js +61 -0
- package/dist/types/database-runtime.js.map +1 -0
- package/dist/types/database.d.ts +85 -0
- package/dist/types/database.d.ts.map +1 -0
- package/dist/types/database.js +71 -0
- package/dist/types/database.js.map +1 -0
- package/dist/types/index.d.ts +2 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js +4 -0
- package/dist/types/index.js.map +1 -1
- package/dist/types/workflow.d.ts +36 -0
- package/dist/types/workflow.d.ts.map +1 -1
- package/dist/types/workflow.js +7 -0
- package/dist/types/workflow.js.map +1 -1
- package/dist/workflow/audit-analyzer.d.ts +58 -0
- package/dist/workflow/audit-analyzer.d.ts.map +1 -0
- package/dist/workflow/audit-analyzer.js +420 -0
- package/dist/workflow/audit-analyzer.js.map +1 -0
- package/dist/workflow/audit-mode.d.ts +28 -0
- package/dist/workflow/audit-mode.d.ts.map +1 -0
- package/dist/workflow/audit-mode.js +169 -0
- package/dist/workflow/audit-mode.js.map +1 -0
- package/dist/workflow/audit-recovery.d.ts +61 -0
- package/dist/workflow/audit-recovery.d.ts.map +1 -0
- package/dist/workflow/audit-recovery.js +242 -0
- package/dist/workflow/audit-recovery.js.map +1 -0
- package/dist/workflow/audit-reporter.d.ts +65 -0
- package/dist/workflow/audit-reporter.d.ts.map +1 -0
- package/dist/workflow/audit-reporter.js +301 -0
- package/dist/workflow/audit-reporter.js.map +1 -0
- package/dist/workflow/audit-scanner.d.ts +87 -0
- package/dist/workflow/audit-scanner.d.ts.map +1 -0
- package/dist/workflow/audit-scanner.js +768 -0
- package/dist/workflow/audit-scanner.js.map +1 -0
- package/dist/workflow/db-setup-runner.d.ts +63 -0
- package/dist/workflow/db-setup-runner.d.ts.map +1 -0
- package/dist/workflow/db-setup-runner.js +336 -0
- package/dist/workflow/db-setup-runner.js.map +1 -0
- package/dist/workflow/db-state-machine.d.ts +30 -0
- package/dist/workflow/db-state-machine.d.ts.map +1 -0
- package/dist/workflow/db-state-machine.js +51 -0
- package/dist/workflow/db-state-machine.js.map +1 -0
- package/dist/workflow/index.d.ts +7 -0
- package/dist/workflow/index.d.ts.map +1 -1
- package/dist/workflow/index.js +7 -0
- package/dist/workflow/index.js.map +1 -1
- package/package.json +1 -1
- package/src/cli/commands/db.ts +281 -0
- package/src/cli/commands/doctor.ts +273 -0
- package/src/cli/commands/index.ts +3 -0
- package/src/cli/commands/review.ts +187 -0
- package/src/cli/index.ts +6 -0
- package/src/cli/interactive.ts +174 -4
- package/src/generators/admin-wizard.ts +146 -0
- package/src/generators/all.ts +10 -3
- package/src/generators/database.ts +286 -0
- package/src/generators/fullstack.ts +26 -9
- package/src/generators/index.ts +12 -0
- package/src/generators/templates/admin-wizard-python.ts +431 -0
- package/src/generators/templates/admin-wizard-react.ts +560 -0
- package/src/generators/templates/database-docker.ts +227 -0
- package/src/generators/templates/database-python.ts +734 -0
- package/src/generators/templates/database-typescript.ts +238 -0
- package/src/generators/templates/fullstack.ts +29 -0
- package/src/generators/templates/index.ts +5 -0
- package/src/state/index.ts +28 -0
- package/src/types/audit.ts +294 -0
- package/src/types/database-runtime.ts +69 -0
- package/src/types/database.ts +84 -0
- package/src/types/index.ts +29 -0
- package/src/types/workflow.ts +20 -0
- package/src/workflow/audit-analyzer.ts +491 -0
- package/src/workflow/audit-mode.ts +240 -0
- package/src/workflow/audit-recovery.ts +284 -0
- package/src/workflow/audit-reporter.ts +370 -0
- package/src/workflow/audit-scanner.ts +873 -0
- package/src/workflow/db-setup-runner.ts +391 -0
- package/src/workflow/db-state-machine.ts +58 -0
- package/src/workflow/index.ts +7 -0
- package/tests/cli/commands/review.test.ts +52 -0
- package/tests/generators/admin-wizard-orchestrator.test.ts +64 -0
- package/tests/generators/admin-wizard-templates.test.ts +366 -0
- package/tests/generators/cross-phase-integration.test.ts +383 -0
- package/tests/generators/database.test.ts +456 -0
- package/tests/generators/fe-be-db-integration.test.ts +613 -0
- package/tests/types/audit.test.ts +250 -0
- package/tests/types/database-runtime.test.ts +158 -0
- package/tests/types/database.test.ts +187 -0
- package/tests/workflow/audit-analyzer.test.ts +281 -0
- package/tests/workflow/audit-mode.test.ts +114 -0
- package/tests/workflow/audit-recovery.test.ts +237 -0
- package/tests/workflow/audit-reporter.test.ts +254 -0
- package/tests/workflow/audit-scanner.test.ts +270 -0
- package/tests/workflow/db-setup-runner.test.ts +211 -0
- 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';
|
package/src/state/index.ts
CHANGED
|
@@ -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>;
|