@opensaas/stack-cli 0.4.0 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +76 -0
- package/dist/commands/migrate.d.ts +9 -0
- package/dist/commands/migrate.d.ts.map +1 -0
- package/dist/commands/migrate.js +299 -0
- package/dist/commands/migrate.js.map +1 -0
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -1
- package/dist/mcp/lib/documentation-provider.d.ts +23 -0
- package/dist/mcp/lib/documentation-provider.d.ts.map +1 -1
- package/dist/mcp/lib/documentation-provider.js +471 -0
- package/dist/mcp/lib/documentation-provider.js.map +1 -1
- package/dist/mcp/lib/wizards/migration-wizard.d.ts +80 -0
- package/dist/mcp/lib/wizards/migration-wizard.d.ts.map +1 -0
- package/dist/mcp/lib/wizards/migration-wizard.js +499 -0
- package/dist/mcp/lib/wizards/migration-wizard.js.map +1 -0
- package/dist/mcp/server/index.d.ts.map +1 -1
- package/dist/mcp/server/index.js +103 -0
- package/dist/mcp/server/index.js.map +1 -1
- package/dist/mcp/server/stack-mcp-server.d.ts +85 -0
- package/dist/mcp/server/stack-mcp-server.d.ts.map +1 -1
- package/dist/mcp/server/stack-mcp-server.js +219 -0
- package/dist/mcp/server/stack-mcp-server.js.map +1 -1
- package/dist/migration/generators/migration-generator.d.ts +60 -0
- package/dist/migration/generators/migration-generator.d.ts.map +1 -0
- package/dist/migration/generators/migration-generator.js +510 -0
- package/dist/migration/generators/migration-generator.js.map +1 -0
- package/dist/migration/introspectors/index.d.ts +12 -0
- package/dist/migration/introspectors/index.d.ts.map +1 -0
- package/dist/migration/introspectors/index.js +10 -0
- package/dist/migration/introspectors/index.js.map +1 -0
- package/dist/migration/introspectors/keystone-introspector.d.ts +59 -0
- package/dist/migration/introspectors/keystone-introspector.d.ts.map +1 -0
- package/dist/migration/introspectors/keystone-introspector.js +229 -0
- package/dist/migration/introspectors/keystone-introspector.js.map +1 -0
- package/dist/migration/introspectors/nextjs-introspector.d.ts +59 -0
- package/dist/migration/introspectors/nextjs-introspector.d.ts.map +1 -0
- package/dist/migration/introspectors/nextjs-introspector.js +159 -0
- package/dist/migration/introspectors/nextjs-introspector.js.map +1 -0
- package/dist/migration/introspectors/prisma-introspector.d.ts +45 -0
- package/dist/migration/introspectors/prisma-introspector.d.ts.map +1 -0
- package/dist/migration/introspectors/prisma-introspector.js +190 -0
- package/dist/migration/introspectors/prisma-introspector.js.map +1 -0
- package/dist/migration/types.d.ts +86 -0
- package/dist/migration/types.d.ts.map +1 -0
- package/dist/migration/types.js +5 -0
- package/dist/migration/types.js.map +1 -0
- package/package.json +10 -2
- package/plugin/.claude-plugin/plugin.json +15 -0
- package/plugin/README.md +112 -0
- package/plugin/agents/migration-assistant.md +150 -0
- package/plugin/commands/analyze-schema.md +34 -0
- package/plugin/commands/generate-config.md +33 -0
- package/plugin/commands/validate-migration.md +34 -0
- package/plugin/skills/opensaas-migration/SKILL.md +192 -0
- package/.turbo/turbo-build.log +0 -4
- package/CHANGELOG.md +0 -410
- package/CLAUDE.md +0 -298
- package/src/commands/__snapshots__/generate.test.ts.snap +0 -413
- package/src/commands/dev.test.ts +0 -215
- package/src/commands/dev.ts +0 -48
- package/src/commands/generate.test.ts +0 -282
- package/src/commands/generate.ts +0 -182
- package/src/commands/init.ts +0 -34
- package/src/commands/mcp.ts +0 -135
- package/src/generator/__snapshots__/context.test.ts.snap +0 -361
- package/src/generator/__snapshots__/prisma.test.ts.snap +0 -174
- package/src/generator/__snapshots__/types.test.ts.snap +0 -1702
- package/src/generator/context.test.ts +0 -139
- package/src/generator/context.ts +0 -227
- package/src/generator/index.ts +0 -7
- package/src/generator/lists.test.ts +0 -335
- package/src/generator/lists.ts +0 -140
- package/src/generator/plugin-types.ts +0 -147
- package/src/generator/prisma-config.ts +0 -46
- package/src/generator/prisma-extensions.ts +0 -159
- package/src/generator/prisma.test.ts +0 -211
- package/src/generator/prisma.ts +0 -161
- package/src/generator/types.test.ts +0 -268
- package/src/generator/types.ts +0 -537
- package/src/index.ts +0 -42
- package/src/mcp/lib/documentation-provider.ts +0 -203
- package/src/mcp/lib/features/catalog.ts +0 -301
- package/src/mcp/lib/generators/feature-generator.ts +0 -598
- package/src/mcp/lib/types.ts +0 -89
- package/src/mcp/lib/wizards/wizard-engine.ts +0 -427
- package/src/mcp/server/index.ts +0 -240
- package/src/mcp/server/stack-mcp-server.ts +0 -301
- package/tsconfig.json +0 -13
- package/tsconfig.tsbuildinfo +0 -1
- package/vitest.config.ts +0 -26
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Prisma Schema Introspector
|
|
3
|
+
*
|
|
4
|
+
* Parses prisma/schema.prisma and extracts structured information
|
|
5
|
+
* about models, fields, relationships, and enums.
|
|
6
|
+
*/
|
|
7
|
+
import fs from 'fs-extra';
|
|
8
|
+
import path from 'path';
|
|
9
|
+
export class PrismaIntrospector {
|
|
10
|
+
/**
|
|
11
|
+
* Introspect a Prisma schema file
|
|
12
|
+
*/
|
|
13
|
+
async introspect(cwd, schemaPath = 'prisma/schema.prisma') {
|
|
14
|
+
const fullPath = path.isAbsolute(schemaPath) ? schemaPath : path.join(cwd, schemaPath);
|
|
15
|
+
if (!(await fs.pathExists(fullPath))) {
|
|
16
|
+
throw new Error(`Schema file not found: ${fullPath}`);
|
|
17
|
+
}
|
|
18
|
+
const schema = await fs.readFile(fullPath, 'utf-8');
|
|
19
|
+
return {
|
|
20
|
+
provider: this.extractProvider(schema),
|
|
21
|
+
models: this.extractModels(schema),
|
|
22
|
+
enums: this.extractEnums(schema),
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Extract database provider from datasource block
|
|
27
|
+
*/
|
|
28
|
+
extractProvider(schema) {
|
|
29
|
+
const match = schema.match(/datasource\s+\w+\s*\{[^}]*provider\s*=\s*"(\w+)"/);
|
|
30
|
+
return match ? match[1] : 'unknown';
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Extract all model definitions
|
|
34
|
+
*/
|
|
35
|
+
extractModels(schema) {
|
|
36
|
+
const models = [];
|
|
37
|
+
// Match model blocks
|
|
38
|
+
const modelRegex = /model\s+(\w+)\s*\{([^}]+)\}/g;
|
|
39
|
+
let match;
|
|
40
|
+
while ((match = modelRegex.exec(schema)) !== null) {
|
|
41
|
+
const name = match[1];
|
|
42
|
+
const body = match[2];
|
|
43
|
+
const fields = this.extractFields(body);
|
|
44
|
+
const primaryKey = fields.find((f) => f.isId)?.name || 'id';
|
|
45
|
+
models.push({
|
|
46
|
+
name,
|
|
47
|
+
fields,
|
|
48
|
+
hasRelations: fields.some((f) => f.relation !== undefined),
|
|
49
|
+
primaryKey,
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
return models;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Extract fields from a model body
|
|
56
|
+
*/
|
|
57
|
+
extractFields(body) {
|
|
58
|
+
const fields = [];
|
|
59
|
+
const lines = body.split('\n');
|
|
60
|
+
for (const line of lines) {
|
|
61
|
+
const trimmed = line.trim();
|
|
62
|
+
// Skip empty lines, comments, and model-level attributes
|
|
63
|
+
if (!trimmed || trimmed.startsWith('//') || trimmed.startsWith('@@')) {
|
|
64
|
+
continue;
|
|
65
|
+
}
|
|
66
|
+
const field = this.parseFieldLine(trimmed);
|
|
67
|
+
if (field) {
|
|
68
|
+
fields.push(field);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
return fields;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Parse a single field line
|
|
75
|
+
*/
|
|
76
|
+
parseFieldLine(line) {
|
|
77
|
+
// Basic field pattern: name Type modifiers attributes
|
|
78
|
+
// Examples:
|
|
79
|
+
// id String @id @default(cuid())
|
|
80
|
+
// title String
|
|
81
|
+
// isActive Boolean? @default(true)
|
|
82
|
+
// posts Post[]
|
|
83
|
+
// author User @relation(fields: [authorId], references: [id])
|
|
84
|
+
// Remove comments
|
|
85
|
+
const withoutComment = line.split('//')[0].trim();
|
|
86
|
+
// Match field name and type
|
|
87
|
+
const fieldMatch = withoutComment.match(/^(\w+)\s+(\w+)(\?)?(\[\])?(.*)$/);
|
|
88
|
+
if (!fieldMatch)
|
|
89
|
+
return null;
|
|
90
|
+
const [, name, rawType, optional, isList, rest] = fieldMatch;
|
|
91
|
+
// Skip if this looks like an index or other non-field line
|
|
92
|
+
if (['@@', 'index', 'unique'].some((kw) => name.startsWith(kw))) {
|
|
93
|
+
return null;
|
|
94
|
+
}
|
|
95
|
+
const field = {
|
|
96
|
+
name,
|
|
97
|
+
type: rawType,
|
|
98
|
+
isRequired: !optional,
|
|
99
|
+
isUnique: rest.includes('@unique'),
|
|
100
|
+
isId: rest.includes('@id'),
|
|
101
|
+
isList: !!isList,
|
|
102
|
+
};
|
|
103
|
+
// Extract default value (handle nested parentheses)
|
|
104
|
+
const defaultMatch = rest.match(/@default\(/);
|
|
105
|
+
if (defaultMatch) {
|
|
106
|
+
const startIdx = rest.indexOf('@default(') + '@default('.length;
|
|
107
|
+
let depth = 1;
|
|
108
|
+
let endIdx = startIdx;
|
|
109
|
+
while (depth > 0 && endIdx < rest.length) {
|
|
110
|
+
if (rest[endIdx] === '(')
|
|
111
|
+
depth++;
|
|
112
|
+
else if (rest[endIdx] === ')')
|
|
113
|
+
depth--;
|
|
114
|
+
if (depth > 0)
|
|
115
|
+
endIdx++;
|
|
116
|
+
}
|
|
117
|
+
field.defaultValue = rest.substring(startIdx, endIdx);
|
|
118
|
+
}
|
|
119
|
+
// Extract relation
|
|
120
|
+
const relationMatch = rest.match(/@relation\(([^)]+)\)/);
|
|
121
|
+
if (relationMatch) {
|
|
122
|
+
const relationBody = relationMatch[1];
|
|
123
|
+
// Parse relation parts
|
|
124
|
+
const fieldsMatch = relationBody.match(/fields:\s*\[([^\]]+)\]/);
|
|
125
|
+
const referencesMatch = relationBody.match(/references:\s*\[([^\]]+)\]/);
|
|
126
|
+
const nameMatch = relationBody.match(/name:\s*"([^"]+)"/) || relationBody.match(/"([^"]+)"/);
|
|
127
|
+
field.relation = {
|
|
128
|
+
name: nameMatch ? nameMatch[1] : '',
|
|
129
|
+
model: rawType,
|
|
130
|
+
fields: fieldsMatch ? fieldsMatch[1].split(',').map((f) => f.trim()) : [],
|
|
131
|
+
references: referencesMatch ? referencesMatch[1].split(',').map((r) => r.trim()) : [],
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
return field;
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Extract enum definitions
|
|
138
|
+
*/
|
|
139
|
+
extractEnums(schema) {
|
|
140
|
+
const enums = [];
|
|
141
|
+
// Match enum blocks
|
|
142
|
+
const enumRegex = /enum\s+(\w+)\s*\{([^}]+)\}/g;
|
|
143
|
+
let match;
|
|
144
|
+
while ((match = enumRegex.exec(schema)) !== null) {
|
|
145
|
+
const name = match[1];
|
|
146
|
+
const body = match[2];
|
|
147
|
+
const values = body
|
|
148
|
+
.split('\n')
|
|
149
|
+
.map((line) => line.trim())
|
|
150
|
+
.filter((line) => line && !line.startsWith('//'));
|
|
151
|
+
enums.push({ name, values });
|
|
152
|
+
}
|
|
153
|
+
return enums;
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Map Prisma type to OpenSaaS field type
|
|
157
|
+
*/
|
|
158
|
+
mapPrismaTypeToOpenSaas(prismaType) {
|
|
159
|
+
const mappings = {
|
|
160
|
+
String: { type: 'text', import: 'text' },
|
|
161
|
+
Int: { type: 'integer', import: 'integer' },
|
|
162
|
+
Float: { type: 'float', import: 'float' },
|
|
163
|
+
Boolean: { type: 'checkbox', import: 'checkbox' },
|
|
164
|
+
DateTime: { type: 'timestamp', import: 'timestamp' },
|
|
165
|
+
Json: { type: 'json', import: 'json' },
|
|
166
|
+
BigInt: { type: 'text', import: 'text' }, // No native support
|
|
167
|
+
Decimal: { type: 'text', import: 'text' }, // No native support
|
|
168
|
+
Bytes: { type: 'text', import: 'text' }, // No native support
|
|
169
|
+
};
|
|
170
|
+
return mappings[prismaType] || { type: 'text', import: 'text' };
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Get warnings for unsupported features
|
|
174
|
+
*/
|
|
175
|
+
getWarnings(schema) {
|
|
176
|
+
const warnings = [];
|
|
177
|
+
// Check for unsupported types
|
|
178
|
+
for (const model of schema.models) {
|
|
179
|
+
for (const field of model.fields) {
|
|
180
|
+
if (['BigInt', 'Decimal', 'Bytes'].includes(field.type)) {
|
|
181
|
+
warnings.push(`Field "${model.name}.${field.name}" uses unsupported type "${field.type}" - will be mapped to text()`);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
// Check for composite IDs
|
|
186
|
+
// This would require checking for @@id in the original schema
|
|
187
|
+
return warnings;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
//# sourceMappingURL=prisma-introspector.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prisma-introspector.js","sourceRoot":"","sources":["../../../src/migration/introspectors/prisma-introspector.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,MAAM,UAAU,CAAA;AACzB,OAAO,IAAI,MAAM,MAAM,CAAA;AAGvB,MAAM,OAAO,kBAAkB;IAC7B;;OAEG;IACH,KAAK,CAAC,UAAU,CACd,GAAW,EACX,aAAqB,sBAAsB;QAE3C,MAAM,QAAQ,GAAG,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,UAAU,CAAC,CAAA;QAEtF,IAAI,CAAC,CAAC,MAAM,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC;YACrC,MAAM,IAAI,KAAK,CAAC,0BAA0B,QAAQ,EAAE,CAAC,CAAA;QACvD,CAAC;QAED,MAAM,MAAM,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAA;QAEnD,OAAO;YACL,QAAQ,EAAE,IAAI,CAAC,eAAe,CAAC,MAAM,CAAC;YACtC,MAAM,EAAE,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC;YAClC,KAAK,EAAE,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC;SACjC,CAAA;IACH,CAAC;IAED;;OAEG;IACK,eAAe,CAAC,MAAc;QACpC,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,kDAAkD,CAAC,CAAA;QAC9E,OAAO,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAA;IACrC,CAAC;IAED;;OAEG;IACK,aAAa,CAAC,MAAc;QAClC,MAAM,MAAM,GAAwB,EAAE,CAAA;QAEtC,qBAAqB;QACrB,MAAM,UAAU,GAAG,8BAA8B,CAAA;QACjD,IAAI,KAAK,CAAA;QAET,OAAO,CAAC,KAAK,GAAG,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;YAClD,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,CAAA;YACrB,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,CAAA;YAErB,MAAM,MAAM,GAAG,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,CAAA;YACvC,MAAM,UAAU,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,IAAI,IAAI,IAAI,CAAA;YAE3D,MAAM,CAAC,IAAI,CAAC;gBACV,IAAI;gBACJ,MAAM;gBACN,YAAY,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,SAAS,CAAC;gBAC1D,UAAU;aACX,CAAC,CAAA;QACJ,CAAC;QAED,OAAO,MAAM,CAAA;IACf,CAAC;IAED;;OAEG;IACK,aAAa,CAAC,IAAY;QAChC,MAAM,MAAM,GAAwB,EAAE,CAAA;QACtC,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;QAE9B,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,CAAA;YAE3B,yDAAyD;YACzD,IAAI,CAAC,OAAO,IAAI,OAAO,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,OAAO,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;gBACrE,SAAQ;YACV,CAAC;YAED,MAAM,KAAK,GAAG,IAAI,CAAC,cAAc,CAAC,OAAO,CAAC,CAAA;YAC1C,IAAI,KAAK,EAAE,CAAC;gBACV,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;YACpB,CAAC;QACH,CAAC;QAED,OAAO,MAAM,CAAA;IACf,CAAC;IAED;;OAEG;IACK,cAAc,CAAC,IAAY;QACjC,sDAAsD;QACtD,YAAY;QACZ,4CAA4C;QAC5C,qBAAqB;QACrB,sCAAsC;QACtC,qBAAqB;QACrB,uEAAuE;QAEvE,kBAAkB;QAClB,MAAM,cAAc,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAA;QAEjD,4BAA4B;QAC5B,MAAM,UAAU,GAAG,cAAc,CAAC,KAAK,CAAC,iCAAiC,CAAC,CAAA;QAC1E,IAAI,CAAC,UAAU;YAAE,OAAO,IAAI,CAAA;QAE5B,MAAM,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,CAAC,GAAG,UAAU,CAAA;QAE5D,2DAA2D;QAC3D,IAAI,CAAC,IAAI,EAAE,OAAO,EAAE,QAAQ,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;YAChE,OAAO,IAAI,CAAA;QACb,CAAC;QAED,MAAM,KAAK,GAAsB;YAC/B,IAAI;YACJ,IAAI,EAAE,OAAO;YACb,UAAU,EAAE,CAAC,QAAQ;YACrB,QAAQ,EAAE,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC;YAClC,IAAI,EAAE,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC;YAC1B,MAAM,EAAE,CAAC,CAAC,MAAM;SACjB,CAAA;QAED,oDAAoD;QACpD,MAAM,YAAY,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,CAAA;QAC7C,IAAI,YAAY,EAAE,CAAC;YACjB,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,GAAG,WAAW,CAAC,MAAM,CAAA;YAC/D,IAAI,KAAK,GAAG,CAAC,CAAA;YACb,IAAI,MAAM,GAAG,QAAQ,CAAA;YAErB,OAAO,KAAK,GAAG,CAAC,IAAI,MAAM,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC;gBACzC,IAAI,IAAI,CAAC,MAAM,CAAC,KAAK,GAAG;oBAAE,KAAK,EAAE,CAAA;qBAC5B,IAAI,IAAI,CAAC,MAAM,CAAC,KAAK,GAAG;oBAAE,KAAK,EAAE,CAAA;gBACtC,IAAI,KAAK,GAAG,CAAC;oBAAE,MAAM,EAAE,CAAA;YACzB,CAAC;YAED,KAAK,CAAC,YAAY,GAAG,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAA;QACvD,CAAC;QAED,mBAAmB;QACnB,MAAM,aAAa,GAAG,IAAI,CAAC,KAAK,CAAC,sBAAsB,CAAC,CAAA;QACxD,IAAI,aAAa,EAAE,CAAC;YAClB,MAAM,YAAY,GAAG,aAAa,CAAC,CAAC,CAAC,CAAA;YAErC,uBAAuB;YACvB,MAAM,WAAW,GAAG,YAAY,CAAC,KAAK,CAAC,wBAAwB,CAAC,CAAA;YAChE,MAAM,eAAe,GAAG,YAAY,CAAC,KAAK,CAAC,4BAA4B,CAAC,CAAA;YACxE,MAAM,SAAS,GAAG,YAAY,CAAC,KAAK,CAAC,mBAAmB,CAAC,IAAI,YAAY,CAAC,KAAK,CAAC,WAAW,CAAC,CAAA;YAE5F,KAAK,CAAC,QAAQ,GAAG;gBACf,IAAI,EAAE,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE;gBACnC,KAAK,EAAE,OAAO;gBACd,MAAM,EAAE,WAAW,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE;gBACzE,UAAU,EAAE,eAAe,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE;aACtF,CAAA;QACH,CAAC;QAED,OAAO,KAAK,CAAA;IACd,CAAC;IAED;;OAEG;IACK,YAAY,CAAC,MAAc;QACjC,MAAM,KAAK,GAA8C,EAAE,CAAA;QAE3D,oBAAoB;QACpB,MAAM,SAAS,GAAG,6BAA6B,CAAA;QAC/C,IAAI,KAAK,CAAA;QAET,OAAO,CAAC,KAAK,GAAG,SAAS,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;YACjD,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,CAAA;YACrB,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,CAAA;YAErB,MAAM,MAAM,GAAG,IAAI;iBAChB,KAAK,CAAC,IAAI,CAAC;iBACX,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;iBAC1B,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAA;YAEnD,KAAK,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,CAAA;QAC9B,CAAC;QAED,OAAO,KAAK,CAAA;IACd,CAAC;IAED;;OAEG;IACH,uBAAuB,CAAC,UAAkB;QACxC,MAAM,QAAQ,GAAqD;YACjE,MAAM,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE;YACxC,GAAG,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE;YAC3C,KAAK,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE;YACzC,OAAO,EAAE,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,EAAE,UAAU,EAAE;YACjD,QAAQ,EAAE,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,EAAE,WAAW,EAAE;YACpD,IAAI,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE;YACtC,MAAM,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,oBAAoB;YAC9D,OAAO,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,oBAAoB;YAC/D,KAAK,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,oBAAoB;SAC9D,CAAA;QAED,OAAO,QAAQ,CAAC,UAAU,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,CAAA;IACjE,CAAC;IAED;;OAEG;IACH,WAAW,CAAC,MAA0B;QACpC,MAAM,QAAQ,GAAa,EAAE,CAAA;QAE7B,8BAA8B;QAC9B,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC;YAClC,KAAK,MAAM,KAAK,IAAI,KAAK,CAAC,MAAM,EAAE,CAAC;gBACjC,IAAI,CAAC,QAAQ,EAAE,SAAS,EAAE,OAAO,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;oBACxD,QAAQ,CAAC,IAAI,CACX,UAAU,KAAK,CAAC,IAAI,IAAI,KAAK,CAAC,IAAI,4BAA4B,KAAK,CAAC,IAAI,8BAA8B,CACvG,CAAA;gBACH,CAAC;YACH,CAAC;QACH,CAAC;QAED,0BAA0B;QAC1B,8DAA8D;QAE9D,OAAO,QAAQ,CAAA;IACjB,CAAC;CACF"}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Migration types - Shared types for the migration system
|
|
3
|
+
*/
|
|
4
|
+
export type ProjectType = 'prisma' | 'nextjs' | 'keystone';
|
|
5
|
+
export interface ModelInfo {
|
|
6
|
+
name: string;
|
|
7
|
+
fieldCount: number;
|
|
8
|
+
}
|
|
9
|
+
export interface ProjectAnalysis {
|
|
10
|
+
projectTypes: ProjectType[];
|
|
11
|
+
cwd: string;
|
|
12
|
+
models?: ModelInfo[];
|
|
13
|
+
provider?: string;
|
|
14
|
+
hasAuth?: boolean;
|
|
15
|
+
authLibrary?: string;
|
|
16
|
+
}
|
|
17
|
+
export interface FieldMapping {
|
|
18
|
+
prismaType: string;
|
|
19
|
+
opensaasType: string;
|
|
20
|
+
opensaasImport: string;
|
|
21
|
+
}
|
|
22
|
+
export interface MigrationQuestion {
|
|
23
|
+
id: string;
|
|
24
|
+
text: string;
|
|
25
|
+
type: 'text' | 'select' | 'boolean' | 'multiselect';
|
|
26
|
+
options?: string[];
|
|
27
|
+
defaultValue?: string | boolean | string[];
|
|
28
|
+
required?: boolean;
|
|
29
|
+
dependsOn?: {
|
|
30
|
+
questionId: string;
|
|
31
|
+
value: string | boolean;
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
export interface MigrationSession {
|
|
35
|
+
id: string;
|
|
36
|
+
projectType: ProjectType;
|
|
37
|
+
analysis: ProjectAnalysis;
|
|
38
|
+
currentQuestionIndex: number;
|
|
39
|
+
answers: Record<string, string | boolean | string[]>;
|
|
40
|
+
generatedConfig?: string;
|
|
41
|
+
isComplete: boolean;
|
|
42
|
+
createdAt: Date;
|
|
43
|
+
updatedAt: Date;
|
|
44
|
+
}
|
|
45
|
+
export interface MigrationOutput {
|
|
46
|
+
configContent: string;
|
|
47
|
+
dependencies: string[];
|
|
48
|
+
files: Array<{
|
|
49
|
+
path: string;
|
|
50
|
+
content: string;
|
|
51
|
+
language: string;
|
|
52
|
+
description: string;
|
|
53
|
+
}>;
|
|
54
|
+
steps: string[];
|
|
55
|
+
warnings: string[];
|
|
56
|
+
}
|
|
57
|
+
export interface IntrospectedModel {
|
|
58
|
+
name: string;
|
|
59
|
+
fields: IntrospectedField[];
|
|
60
|
+
hasRelations: boolean;
|
|
61
|
+
primaryKey: string;
|
|
62
|
+
}
|
|
63
|
+
export interface IntrospectedField {
|
|
64
|
+
name: string;
|
|
65
|
+
type: string;
|
|
66
|
+
isRequired: boolean;
|
|
67
|
+
isUnique: boolean;
|
|
68
|
+
isId: boolean;
|
|
69
|
+
isList: boolean;
|
|
70
|
+
defaultValue?: string;
|
|
71
|
+
relation?: {
|
|
72
|
+
name: string;
|
|
73
|
+
model: string;
|
|
74
|
+
fields: string[];
|
|
75
|
+
references: string[];
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
export interface IntrospectedSchema {
|
|
79
|
+
provider: string;
|
|
80
|
+
models: IntrospectedModel[];
|
|
81
|
+
enums: Array<{
|
|
82
|
+
name: string;
|
|
83
|
+
values: string[];
|
|
84
|
+
}>;
|
|
85
|
+
}
|
|
86
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/migration/types.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/migration/types.ts"],"names":[],"mappings":"AAAA;;GAEG"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@opensaas/stack-cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"description": "CLI tools for OpenSaas Stack",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -18,6 +18,11 @@
|
|
|
18
18
|
"bin": {
|
|
19
19
|
"opensaas": "./bin/opensaas.js"
|
|
20
20
|
},
|
|
21
|
+
"files": [
|
|
22
|
+
"dist",
|
|
23
|
+
"bin",
|
|
24
|
+
"plugin"
|
|
25
|
+
],
|
|
21
26
|
"keywords": [
|
|
22
27
|
"opensaas",
|
|
23
28
|
"cli",
|
|
@@ -40,13 +45,16 @@
|
|
|
40
45
|
"chalk": "^5.6.2",
|
|
41
46
|
"chokidar": "^5.0.0",
|
|
42
47
|
"commander": "^14.0.2",
|
|
48
|
+
"fs-extra": "^11.3.2",
|
|
49
|
+
"glob": "^13.0.0",
|
|
43
50
|
"jiti": "^2.6.1",
|
|
44
51
|
"ora": "^9.0.0",
|
|
45
52
|
"prompts": "^2.4.2",
|
|
46
53
|
"zod": "^4.1.13",
|
|
47
|
-
"@opensaas/stack-core": "0.
|
|
54
|
+
"@opensaas/stack-core": "0.6.0"
|
|
48
55
|
},
|
|
49
56
|
"devDependencies": {
|
|
57
|
+
"@types/fs-extra": "^11.0.4",
|
|
50
58
|
"@types/node": "^24.10.1",
|
|
51
59
|
"@types/prompts": "^2.4.9",
|
|
52
60
|
"@vitest/coverage-v8": "^4.0.15",
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "opensaas-migration",
|
|
3
|
+
"description": "OpenSaaS Stack migration assistant with AI-guided configuration, schema analysis, and code generation support",
|
|
4
|
+
"version": "1.0.0",
|
|
5
|
+
"author": {
|
|
6
|
+
"name": "OpenSaaS Team",
|
|
7
|
+
"url": "https://github.com/OpenSaasAU/stack"
|
|
8
|
+
},
|
|
9
|
+
"repository": {
|
|
10
|
+
"type": "git",
|
|
11
|
+
"url": "https://github.com/OpenSaasAU/stack",
|
|
12
|
+
"directory": "packages/cli/plugin"
|
|
13
|
+
},
|
|
14
|
+
"keywords": ["migration", "opensaas", "prisma", "keystone", "nextjs", "code-generation"]
|
|
15
|
+
}
|
package/plugin/README.md
ADDED
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
# OpenSaaS Migration Assistant Plugin
|
|
2
|
+
|
|
3
|
+
A Claude Code plugin that provides AI-guided migration assistance for converting existing Prisma, KeystoneJS, or Next.js projects to OpenSaaS Stack.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **Migration Assistant Agent**: Contextual agent that guides you through the migration process
|
|
8
|
+
- **Interactive Commands**: Slash commands for schema analysis, config generation, and validation
|
|
9
|
+
- **Migration Skill**: Expert knowledge about migration patterns and best practices
|
|
10
|
+
- **MCP Integration**: Works with the OpenSaaS MCP server for advanced tooling
|
|
11
|
+
|
|
12
|
+
## Installation
|
|
13
|
+
|
|
14
|
+
This plugin is automatically set up when you run:
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
npx @opensaas/stack-cli migrate --with-ai
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
The CLI will:
|
|
21
|
+
|
|
22
|
+
1. Install this plugin to your project
|
|
23
|
+
2. Create `.claude/opensaas-project.json` with your project metadata
|
|
24
|
+
3. Configure `.claude/settings.json` to enable the plugin
|
|
25
|
+
4. Set up `.mcp.json` for MCP server integration
|
|
26
|
+
|
|
27
|
+
## What's Included
|
|
28
|
+
|
|
29
|
+
### Migration Assistant Agent
|
|
30
|
+
|
|
31
|
+
A specialized agent that:
|
|
32
|
+
|
|
33
|
+
- Reads your project metadata from `.claude/opensaas-project.json`
|
|
34
|
+
- Guides you through the migration wizard
|
|
35
|
+
- Explains access control patterns
|
|
36
|
+
- Generates `opensaas.config.ts`
|
|
37
|
+
|
|
38
|
+
### Slash Commands
|
|
39
|
+
|
|
40
|
+
- `/analyze-schema` - Detailed schema analysis with recommendations
|
|
41
|
+
- `/generate-config` - Generate opensaas.config.ts
|
|
42
|
+
- `/validate-migration` - Validate generated configuration
|
|
43
|
+
|
|
44
|
+
### Migration Skill
|
|
45
|
+
|
|
46
|
+
Expert knowledge including:
|
|
47
|
+
|
|
48
|
+
- Access control patterns
|
|
49
|
+
- Field type mappings
|
|
50
|
+
- Database configuration examples
|
|
51
|
+
- Common challenges and solutions
|
|
52
|
+
|
|
53
|
+
## Usage
|
|
54
|
+
|
|
55
|
+
Once installed, simply ask Claude:
|
|
56
|
+
|
|
57
|
+
```
|
|
58
|
+
Help me migrate to OpenSaaS Stack
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
The migration assistant will:
|
|
62
|
+
|
|
63
|
+
1. Read your project details
|
|
64
|
+
2. Start the interactive wizard
|
|
65
|
+
3. Guide you through configuration
|
|
66
|
+
4. Generate your opensaas.config.ts
|
|
67
|
+
|
|
68
|
+
## Project Metadata
|
|
69
|
+
|
|
70
|
+
The CLI creates `.claude/opensaas-project.json` with information about your project:
|
|
71
|
+
|
|
72
|
+
```json
|
|
73
|
+
{
|
|
74
|
+
"projectTypes": ["prisma"],
|
|
75
|
+
"provider": "sqlite",
|
|
76
|
+
"models": [
|
|
77
|
+
{ "name": "User", "fieldCount": 5 },
|
|
78
|
+
{ "name": "Post", "fieldCount": 7 }
|
|
79
|
+
],
|
|
80
|
+
"hasAuth": true
|
|
81
|
+
}
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
The plugin reads this file to provide contextual assistance.
|
|
85
|
+
|
|
86
|
+
## Development
|
|
87
|
+
|
|
88
|
+
This plugin is part of the `@opensaas/stack-cli` package and is distributed with it.
|
|
89
|
+
|
|
90
|
+
**Directory structure:**
|
|
91
|
+
|
|
92
|
+
```
|
|
93
|
+
plugin/
|
|
94
|
+
├── .claude-plugin/
|
|
95
|
+
│ └── plugin.json # Plugin manifest
|
|
96
|
+
├── agents/
|
|
97
|
+
│ └── migration-assistant.md # Migration agent
|
|
98
|
+
├── commands/
|
|
99
|
+
│ ├── analyze-schema.md
|
|
100
|
+
│ ├── generate-config.md
|
|
101
|
+
│ └── validate-migration.md
|
|
102
|
+
├── skills/
|
|
103
|
+
│ └── opensaas-migration/
|
|
104
|
+
│ └── SKILL.md
|
|
105
|
+
└── README.md
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
## Links
|
|
109
|
+
|
|
110
|
+
- [OpenSaaS Stack Documentation](https://stack.opensaas.au/)
|
|
111
|
+
- [Migration Guide](https://stack.opensaas.au/guides/migration)
|
|
112
|
+
- [GitHub Repository](https://github.com/OpenSaasAU/stack)
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: migration-assistant
|
|
3
|
+
description: OpenSaaS Stack migration expert. Use when helping users migrate from Prisma, KeystoneJS, or Next.js projects to OpenSaaS Stack. Proactively helps with schema analysis, access control configuration, and opensaas.config.ts generation.
|
|
4
|
+
model: sonnet
|
|
5
|
+
skills: opensaas-migration
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
You are the OpenSaaS Stack Migration Assistant, helping users migrate their existing projects to OpenSaaS Stack.
|
|
9
|
+
|
|
10
|
+
## Getting Project Context
|
|
11
|
+
|
|
12
|
+
**IMPORTANT**: Before starting, read the project metadata from `.claude/opensaas-project.json` to understand:
|
|
13
|
+
|
|
14
|
+
- Project type (Prisma, KeystoneJS, Next.js)
|
|
15
|
+
- Database provider
|
|
16
|
+
- Detected models and their structure
|
|
17
|
+
- Whether authentication is already present
|
|
18
|
+
|
|
19
|
+
This file is created by `npx @opensaas/stack-cli migrate --with-ai` and contains essential project information.
|
|
20
|
+
|
|
21
|
+
## Your Role
|
|
22
|
+
|
|
23
|
+
Guide the user through a complete migration to OpenSaaS Stack:
|
|
24
|
+
|
|
25
|
+
1. **Analyze** their current project structure
|
|
26
|
+
2. **Explain** what OpenSaaS Stack offers (access control, admin UI, type safety)
|
|
27
|
+
3. **Guide** them through the migration wizard
|
|
28
|
+
4. **Generate** a working `opensaas.config.ts`
|
|
29
|
+
5. **Validate** the generated configuration
|
|
30
|
+
6. **Provide** clear next steps
|
|
31
|
+
|
|
32
|
+
## Available MCP Tools
|
|
33
|
+
|
|
34
|
+
### Schema Analysis
|
|
35
|
+
|
|
36
|
+
- `opensaas_introspect_prisma` - Analyze Prisma schema in detail
|
|
37
|
+
- `opensaas_introspect_keystone` - Analyze KeystoneJS config
|
|
38
|
+
|
|
39
|
+
### Migration Wizard
|
|
40
|
+
|
|
41
|
+
- `opensaas_start_migration` - Start the interactive wizard
|
|
42
|
+
- `opensaas_answer_migration` - Answer wizard questions
|
|
43
|
+
|
|
44
|
+
### Documentation
|
|
45
|
+
|
|
46
|
+
- `opensaas_search_migration_docs` - Search migration documentation
|
|
47
|
+
- `opensaas_get_example` - Get example code patterns
|
|
48
|
+
|
|
49
|
+
### Validation
|
|
50
|
+
|
|
51
|
+
- `opensaas_validate_feature` - Validate implementation
|
|
52
|
+
|
|
53
|
+
## Conversation Guidelines
|
|
54
|
+
|
|
55
|
+
### When the user says "help me migrate" or similar:
|
|
56
|
+
|
|
57
|
+
1. **Read project metadata** from `.claude/opensaas-project.json`:
|
|
58
|
+
|
|
59
|
+
```
|
|
60
|
+
Use the Read tool to read .claude/opensaas-project.json
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
2. **Acknowledge** their project based on the metadata:
|
|
64
|
+
|
|
65
|
+
> "I can see you have a [PROJECT_TYPE] project with [MODEL_COUNT] models. Let me help you migrate to OpenSaaS Stack!"
|
|
66
|
+
|
|
67
|
+
3. **Start the wizard** by calling:
|
|
68
|
+
|
|
69
|
+
```
|
|
70
|
+
opensaas_start_migration({ projectType: "[project_type]" })
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
4. **Present questions naturally** - don't mention session IDs or technical details to the user
|
|
74
|
+
|
|
75
|
+
5. **Explain choices** - help them understand what each option means:
|
|
76
|
+
- Access control patterns
|
|
77
|
+
- Authentication options
|
|
78
|
+
- Database configuration
|
|
79
|
+
|
|
80
|
+
6. **Show progress** - let them know how far along they are
|
|
81
|
+
|
|
82
|
+
7. **Generate the config** when complete and explain what was created
|
|
83
|
+
|
|
84
|
+
### When explaining OpenSaaS Stack:
|
|
85
|
+
|
|
86
|
+
Highlight these benefits:
|
|
87
|
+
|
|
88
|
+
- **Built-in access control** - Secure by default
|
|
89
|
+
- **Admin UI** - Auto-generated from your schema
|
|
90
|
+
- **Type safety** - Full TypeScript support
|
|
91
|
+
- **Prisma integration** - Uses familiar ORM
|
|
92
|
+
- **Plugin system** - Easy to extend
|
|
93
|
+
|
|
94
|
+
### When answering questions:
|
|
95
|
+
|
|
96
|
+
- Use `opensaas_search_migration_docs` to find accurate information
|
|
97
|
+
- Use `opensaas_get_example` to show code patterns
|
|
98
|
+
- Be honest if something isn't supported
|
|
99
|
+
|
|
100
|
+
### Tone
|
|
101
|
+
|
|
102
|
+
- Be encouraging and helpful
|
|
103
|
+
- Explain technical concepts simply
|
|
104
|
+
- Celebrate progress ("Great choice!", "Almost there!")
|
|
105
|
+
- Don't overwhelm with information
|
|
106
|
+
|
|
107
|
+
## Example Conversation
|
|
108
|
+
|
|
109
|
+
**User:** Help me migrate to OpenSaaS Stack
|
|
110
|
+
|
|
111
|
+
**You:** Let me check your project details...
|
|
112
|
+
|
|
113
|
+
[Read .claude/opensaas-project.json]
|
|
114
|
+
|
|
115
|
+
I can see you have a Prisma project with 5 models. OpenSaaS Stack will give you:
|
|
116
|
+
|
|
117
|
+
- Automatic admin UI for managing your data
|
|
118
|
+
- Built-in access control to secure your API
|
|
119
|
+
- Type-safe database operations
|
|
120
|
+
|
|
121
|
+
Let me start the migration wizard to configure your project...
|
|
122
|
+
|
|
123
|
+
[Call opensaas_start_migration]
|
|
124
|
+
|
|
125
|
+
**User:** [answers questions]
|
|
126
|
+
|
|
127
|
+
**You:** [Continue through wizard, explain each choice, generate final config]
|
|
128
|
+
|
|
129
|
+
## Error Handling
|
|
130
|
+
|
|
131
|
+
If something goes wrong:
|
|
132
|
+
|
|
133
|
+
1. Explain what happened in simple terms
|
|
134
|
+
2. Suggest alternatives or manual steps
|
|
135
|
+
3. Link to documentation for more help
|
|
136
|
+
|
|
137
|
+
If `.claude/opensaas-project.json` doesn't exist:
|
|
138
|
+
|
|
139
|
+
- Explain that `npx @opensaas/stack-cli migrate --with-ai` should be run first
|
|
140
|
+
- Offer to help them run it
|
|
141
|
+
|
|
142
|
+
## After Migration
|
|
143
|
+
|
|
144
|
+
Once the config is generated, guide them through:
|
|
145
|
+
|
|
146
|
+
1. Installing dependencies
|
|
147
|
+
2. Running `opensaas generate`
|
|
148
|
+
3. Running `prisma db push`
|
|
149
|
+
4. Starting their dev server
|
|
150
|
+
5. Visiting the admin UI
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Analyze the current project schema and provide a detailed breakdown
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
Analyze the current project schema and provide a detailed breakdown.
|
|
6
|
+
|
|
7
|
+
## Instructions
|
|
8
|
+
|
|
9
|
+
1. Read `.claude/opensaas-project.json` to determine the project type
|
|
10
|
+
2. Use `opensaas_introspect_prisma` or `opensaas_introspect_keystone` based on project type
|
|
11
|
+
3. Present the results in a clear, organized format
|
|
12
|
+
4. Highlight:
|
|
13
|
+
- All models and their fields
|
|
14
|
+
- Relationships between models
|
|
15
|
+
- Potential access control patterns
|
|
16
|
+
- Any issues or warnings
|
|
17
|
+
|
|
18
|
+
## Output Format
|
|
19
|
+
|
|
20
|
+
Present like this:
|
|
21
|
+
|
|
22
|
+
### Models Summary
|
|
23
|
+
|
|
24
|
+
| Model | Fields | Has Relations | Suggested Access |
|
|
25
|
+
| ----- | ------ | ------------- | ---------------- |
|
|
26
|
+
| ... | ... | ... | ... |
|
|
27
|
+
|
|
28
|
+
### Detailed Analysis
|
|
29
|
+
|
|
30
|
+
[For each model, show fields and relationships]
|
|
31
|
+
|
|
32
|
+
### Recommendations
|
|
33
|
+
|
|
34
|
+
[Based on the schema, suggest access control patterns]
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Generate the opensaas.config.ts file for this project
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
Generate the opensaas.config.ts file for this project.
|
|
6
|
+
|
|
7
|
+
## Instructions
|
|
8
|
+
|
|
9
|
+
1. Read `.claude/opensaas-project.json` to get project details
|
|
10
|
+
2. If migration wizard hasn't been started, start it:
|
|
11
|
+
|
|
12
|
+
```
|
|
13
|
+
opensaas_start_migration({ projectType: "<project_type>" })
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
3. Guide the user through any remaining questions
|
|
17
|
+
|
|
18
|
+
4. When complete, display:
|
|
19
|
+
- The generated config file
|
|
20
|
+
- Dependencies to install
|
|
21
|
+
- Next steps to run
|
|
22
|
+
|
|
23
|
+
5. Offer to explain any part of the generated config
|
|
24
|
+
|
|
25
|
+
## Quick Mode
|
|
26
|
+
|
|
27
|
+
If the user wants defaults, use these answers based on the project metadata:
|
|
28
|
+
|
|
29
|
+
- preserve_database: true
|
|
30
|
+
- db_provider: [from project metadata]
|
|
31
|
+
- enable_auth: [from project metadata]
|
|
32
|
+
- default_access: "public-read-auth-write"
|
|
33
|
+
- admin_base_path: "/admin"
|