@everystack/mcp 0.3.1 → 0.3.3
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/dist/gates/detectors/embedded-data-bundle.d.ts +13 -0
- package/dist/gates/detectors/embedded-data-bundle.d.ts.map +1 -0
- package/dist/gates/detectors/embedded-data-bundle.js +56 -0
- package/dist/gates/detectors/hand-written-migration.d.ts +24 -0
- package/dist/gates/detectors/hand-written-migration.d.ts.map +1 -0
- package/dist/gates/detectors/hand-written-migration.js +54 -0
- package/dist/gates/detectors/secret-in-public-env.d.ts +12 -0
- package/dist/gates/detectors/secret-in-public-env.d.ts.map +1 -0
- package/dist/gates/detectors/secret-in-public-env.js +38 -0
- package/dist/gates/engine.d.ts +28 -0
- package/dist/gates/engine.d.ts.map +1 -0
- package/dist/gates/engine.js +74 -0
- package/dist/gates/registry.d.ts +14 -0
- package/dist/gates/registry.d.ts.map +1 -0
- package/dist/gates/registry.js +21 -0
- package/dist/gates/telemetry.d.ts +47 -0
- package/dist/gates/telemetry.d.ts.map +1 -0
- package/dist/gates/telemetry.js +121 -0
- package/dist/gates/types.d.ts +67 -0
- package/dist/gates/types.d.ts.map +1 -0
- package/dist/gates/types.js +14 -0
- package/dist/governance/cli.d.ts +57 -0
- package/dist/governance/cli.d.ts.map +1 -0
- package/dist/governance/cli.js +169 -0
- package/dist/governance/grounding.d.ts +78 -0
- package/dist/governance/grounding.d.ts.map +1 -0
- package/dist/governance/grounding.js +299 -0
- package/dist/index.cjs +11 -9
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +94 -0
- package/dist/project-claude-md.md +33 -11
- package/dist/prompts/add-feature.d.ts +3 -0
- package/dist/prompts/add-feature.d.ts.map +1 -0
- package/dist/prompts/add-feature.js +154 -0
- package/dist/prompts/claude-md.d.ts +12 -0
- package/dist/prompts/claude-md.d.ts.map +1 -0
- package/dist/prompts/claude-md.js +87 -0
- package/dist/prompts/debug.d.ts +3 -0
- package/dist/prompts/debug.d.ts.map +1 -0
- package/dist/prompts/debug.js +129 -0
- package/dist/prompts/deploy.d.ts +3 -0
- package/dist/prompts/deploy.d.ts.map +1 -0
- package/dist/prompts/deploy.js +118 -0
- package/dist/prompts/design-schema.d.ts +3 -0
- package/dist/prompts/design-schema.d.ts.map +1 -0
- package/dist/prompts/design-schema.js +97 -0
- package/dist/prompts/governance-setup.d.ts +9 -0
- package/dist/prompts/governance-setup.d.ts.map +1 -0
- package/dist/prompts/governance-setup.js +76 -0
- package/dist/prompts/index.d.ts +3 -0
- package/dist/prompts/index.d.ts.map +1 -0
- package/dist/prompts/index.js +20 -0
- package/dist/prompts/new-app.d.ts +3 -0
- package/dist/prompts/new-app.d.ts.map +1 -0
- package/dist/prompts/new-app.js +203 -0
- package/dist/prompts/runbook.d.ts +12 -0
- package/dist/prompts/runbook.d.ts.map +1 -0
- package/dist/prompts/runbook.js +70 -0
- package/dist/prompts/secure.d.ts +3 -0
- package/dist/prompts/secure.d.ts.map +1 -0
- package/dist/prompts/secure.js +219 -0
- package/dist/resources/index.d.ts +12 -0
- package/dist/resources/index.d.ts.map +1 -0
- package/dist/resources/index.js +182 -0
- package/dist/tools/check-environment.d.ts +25 -0
- package/dist/tools/check-environment.d.ts.map +1 -0
- package/dist/tools/check-environment.js +281 -0
- package/dist/tools/index.d.ts +3 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +18 -0
- package/dist/tools/project-status.d.ts +28 -0
- package/dist/tools/project-status.d.ts.map +1 -0
- package/dist/tools/project-status.js +138 -0
- package/dist/tools/project-validate.d.ts +19 -0
- package/dist/tools/project-validate.d.ts.map +1 -0
- package/dist/tools/project-validate.js +323 -0
- package/dist/tools/schema-analyze.d.ts +46 -0
- package/dist/tools/schema-analyze.d.ts.map +1 -0
- package/dist/tools/schema-analyze.js +336 -0
- package/package.json +3 -3
- package/src/gates/detectors/hand-written-migration.ts +23 -10
- package/src/index.ts +1 -1
- package/src/prompts/claude-md.ts +4 -2
- package/src/resources/project-claude-md.md +33 -11
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
import { execSync } from 'node:child_process';
|
|
2
|
+
import { existsSync } from 'node:fs';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
import { homedir } from 'node:os';
|
|
5
|
+
function detectPlatform() {
|
|
6
|
+
const p = process.platform;
|
|
7
|
+
if (p === 'darwin')
|
|
8
|
+
return 'macOS';
|
|
9
|
+
if (p === 'linux')
|
|
10
|
+
return 'linux';
|
|
11
|
+
if (p === 'win32')
|
|
12
|
+
return 'windows';
|
|
13
|
+
return 'unknown';
|
|
14
|
+
}
|
|
15
|
+
function tryExec(cmd, timeout = 10000) {
|
|
16
|
+
try {
|
|
17
|
+
return execSync(cmd, { timeout, stdio: 'pipe', encoding: 'utf-8' }).trim();
|
|
18
|
+
}
|
|
19
|
+
catch {
|
|
20
|
+
return null;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
function parseVersion(output, pattern) {
|
|
24
|
+
if (!output)
|
|
25
|
+
return null;
|
|
26
|
+
if (pattern) {
|
|
27
|
+
const match = output.match(pattern);
|
|
28
|
+
return match?.[1] ?? null;
|
|
29
|
+
}
|
|
30
|
+
return output.replace(/^v/, '');
|
|
31
|
+
}
|
|
32
|
+
function meetsMinVersion(version, major) {
|
|
33
|
+
if (!version)
|
|
34
|
+
return false;
|
|
35
|
+
const parsed = parseInt(version.split('.')[0], 10);
|
|
36
|
+
return !isNaN(parsed) && parsed >= major;
|
|
37
|
+
}
|
|
38
|
+
export function checkEnvironment(phase = 'local') {
|
|
39
|
+
const prerequisites = [];
|
|
40
|
+
const suggestions = [];
|
|
41
|
+
const platform = detectPlatform();
|
|
42
|
+
const isLocal = phase === 'local';
|
|
43
|
+
// Node.js
|
|
44
|
+
const nodeOutput = tryExec('node --version');
|
|
45
|
+
const nodeVersion = parseVersion(nodeOutput);
|
|
46
|
+
const nodeOk = meetsMinVersion(nodeVersion, 20);
|
|
47
|
+
prerequisites.push({
|
|
48
|
+
name: 'node',
|
|
49
|
+
required: true,
|
|
50
|
+
status: nodeVersion ? 'found' : 'not_found',
|
|
51
|
+
version: nodeVersion,
|
|
52
|
+
installHint: 'Install Node.js 20+ from https://nodejs.org',
|
|
53
|
+
tier: 'V1',
|
|
54
|
+
phase: 'local',
|
|
55
|
+
description: 'Node.js runs your code. Your app is written in TypeScript, and Node.js is the engine that executes it.',
|
|
56
|
+
whyNeeded: 'Without Node.js, none of the code can run.',
|
|
57
|
+
installCommands: platform === 'macOS'
|
|
58
|
+
? ['brew install node', 'Or download from https://nodejs.org']
|
|
59
|
+
: platform === 'linux'
|
|
60
|
+
? ['sudo apt install nodejs npm', 'Or download from https://nodejs.org']
|
|
61
|
+
: ['Download and install from https://nodejs.org'],
|
|
62
|
+
});
|
|
63
|
+
if (!nodeVersion) {
|
|
64
|
+
suggestions.push('Node.js is not installed. Install Node.js 20+ from https://nodejs.org');
|
|
65
|
+
}
|
|
66
|
+
else if (!nodeOk) {
|
|
67
|
+
suggestions.push(`Node.js ${nodeVersion} is installed but version 20+ is required. Upgrade at https://nodejs.org`);
|
|
68
|
+
}
|
|
69
|
+
// pnpm (recommended, not required)
|
|
70
|
+
const pnpmOutput = tryExec('pnpm --version');
|
|
71
|
+
const pnpmVersion = parseVersion(pnpmOutput);
|
|
72
|
+
prerequisites.push({
|
|
73
|
+
name: 'pnpm',
|
|
74
|
+
required: false,
|
|
75
|
+
status: pnpmVersion ? 'found' : 'not_found',
|
|
76
|
+
version: pnpmVersion,
|
|
77
|
+
installHint: 'Install pnpm: npm install -g pnpm (recommended for monorepos)',
|
|
78
|
+
tier: 'V1',
|
|
79
|
+
phase: 'local',
|
|
80
|
+
description: 'A faster way to install code libraries your app depends on. Recommended but not required.',
|
|
81
|
+
whyNeeded: 'Makes installing dependencies faster and more reliable.',
|
|
82
|
+
installCommands: ['npm install -g pnpm'],
|
|
83
|
+
});
|
|
84
|
+
if (!pnpmVersion) {
|
|
85
|
+
suggestions.push('pnpm is not installed. Recommended for monorepos: npm install -g pnpm');
|
|
86
|
+
}
|
|
87
|
+
// git
|
|
88
|
+
const gitOutput = tryExec('git --version');
|
|
89
|
+
const gitVersion = parseVersion(gitOutput, /git version (\d+\.\d+\.\d+)/);
|
|
90
|
+
prerequisites.push({
|
|
91
|
+
name: 'git',
|
|
92
|
+
required: true,
|
|
93
|
+
status: gitVersion ? 'found' : 'not_found',
|
|
94
|
+
version: gitVersion,
|
|
95
|
+
installHint: 'Install git from https://git-scm.com',
|
|
96
|
+
tier: 'V1',
|
|
97
|
+
phase: 'local',
|
|
98
|
+
description: 'Tracks every change to your code. Like an unlimited undo button for your entire project.',
|
|
99
|
+
whyNeeded: 'Without git, you cannot track changes, undo mistakes, or collaborate.',
|
|
100
|
+
installCommands: platform === 'macOS'
|
|
101
|
+
? ['xcode-select --install']
|
|
102
|
+
: platform === 'linux'
|
|
103
|
+
? ['sudo apt install git']
|
|
104
|
+
: ['Download from https://git-scm.com'],
|
|
105
|
+
});
|
|
106
|
+
if (!gitVersion) {
|
|
107
|
+
suggestions.push('git is not installed. Install from https://git-scm.com');
|
|
108
|
+
}
|
|
109
|
+
// Expo CLI
|
|
110
|
+
const expoOutput = tryExec('npx expo --version');
|
|
111
|
+
const expoVersion = parseVersion(expoOutput);
|
|
112
|
+
prerequisites.push({
|
|
113
|
+
name: 'expo',
|
|
114
|
+
required: true,
|
|
115
|
+
status: expoVersion ? 'found' : 'not_found',
|
|
116
|
+
version: expoVersion,
|
|
117
|
+
installHint: 'Expo is available via npx. Ensure Node.js is installed, then run: npx create-expo-app',
|
|
118
|
+
tier: 'V1',
|
|
119
|
+
phase: 'local',
|
|
120
|
+
description: 'The framework that makes your app work on phones, tablets, and the web from the same code.',
|
|
121
|
+
whyNeeded: 'Without Expo, you cannot create or run the app.',
|
|
122
|
+
installCommands: ['Runs via npx (no separate install needed). Requires Node.js.'],
|
|
123
|
+
});
|
|
124
|
+
if (!expoVersion) {
|
|
125
|
+
suggestions.push('Expo CLI not available. Ensure Node.js is installed — Expo runs via npx.');
|
|
126
|
+
}
|
|
127
|
+
// SST (deploy phase only)
|
|
128
|
+
const sstOutput = tryExec('npx sst version');
|
|
129
|
+
const sstVersion = parseVersion(sstOutput, /(\d+\.\d+\.\d+)/);
|
|
130
|
+
prerequisites.push({
|
|
131
|
+
name: 'sst',
|
|
132
|
+
required: !isLocal,
|
|
133
|
+
status: sstVersion ? 'found' : 'not_found',
|
|
134
|
+
version: sstVersion,
|
|
135
|
+
installHint: 'SST is installed as a dev dependency: pnpm add -D sst (or npx sst)',
|
|
136
|
+
tier: 'V1',
|
|
137
|
+
phase: 'deploy',
|
|
138
|
+
description: isLocal
|
|
139
|
+
? 'Manages your cloud infrastructure. Not needed yet — you can build and run your app locally first.'
|
|
140
|
+
: 'Manages your cloud infrastructure. Tells AWS what servers, databases, and storage your app needs.',
|
|
141
|
+
whyNeeded: isLocal
|
|
142
|
+
? 'Only needed when you are ready to deploy your app to the internet.'
|
|
143
|
+
: 'Without SST, you cannot deploy your app to the internet.',
|
|
144
|
+
installCommands: ['Installed as a project dependency when you create your app.'],
|
|
145
|
+
});
|
|
146
|
+
if (!sstVersion && !isLocal) {
|
|
147
|
+
suggestions.push('SST not found. It installs as a dev dependency: pnpm add -D sst');
|
|
148
|
+
}
|
|
149
|
+
// AWS CLI (deploy phase only)
|
|
150
|
+
const awsOutput = tryExec('aws --version');
|
|
151
|
+
const awsVersion = parseVersion(awsOutput, /aws-cli\/(\d+\.\d+\.\d+)/);
|
|
152
|
+
prerequisites.push({
|
|
153
|
+
name: 'aws-cli',
|
|
154
|
+
required: !isLocal,
|
|
155
|
+
status: awsVersion ? 'found' : 'not_found',
|
|
156
|
+
version: awsVersion,
|
|
157
|
+
installHint: 'Install AWS CLI from https://aws.amazon.com/cli/',
|
|
158
|
+
tier: 'V1',
|
|
159
|
+
phase: 'deploy',
|
|
160
|
+
description: isLocal
|
|
161
|
+
? 'A command-line tool for Amazon Web Services. Not needed yet — you can build and run your app locally first.'
|
|
162
|
+
: 'A command-line tool that lets your computer talk to Amazon Web Services, where your app runs.',
|
|
163
|
+
whyNeeded: isLocal
|
|
164
|
+
? 'Only needed when you are ready to deploy your app to the internet.'
|
|
165
|
+
: 'Without it, you cannot deploy or manage your app on AWS.',
|
|
166
|
+
installCommands: platform === 'macOS'
|
|
167
|
+
? ['brew install awscli']
|
|
168
|
+
: platform === 'linux'
|
|
169
|
+
? ['curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip" && unzip awscliv2.zip && sudo ./aws/install']
|
|
170
|
+
: ['Download from https://aws.amazon.com/cli/'],
|
|
171
|
+
});
|
|
172
|
+
if (!awsVersion && !isLocal) {
|
|
173
|
+
suggestions.push('AWS CLI is not installed. Install from https://aws.amazon.com/cli/');
|
|
174
|
+
}
|
|
175
|
+
// AWS credentials (deploy phase only)
|
|
176
|
+
const home = homedir();
|
|
177
|
+
const hasAwsCreds = existsSync(join(home, '.aws', 'credentials')) || existsSync(join(home, '.aws', 'config'));
|
|
178
|
+
prerequisites.push({
|
|
179
|
+
name: 'aws-credentials',
|
|
180
|
+
required: !isLocal,
|
|
181
|
+
status: hasAwsCreds ? 'found' : 'not_found',
|
|
182
|
+
version: null,
|
|
183
|
+
installHint: 'Read everystack://aws-setup for step-by-step AWS account and credential setup.',
|
|
184
|
+
tier: 'V1',
|
|
185
|
+
phase: 'deploy',
|
|
186
|
+
description: isLocal
|
|
187
|
+
? 'A password file for your AWS account. Not needed yet — you can build and run your app locally first.'
|
|
188
|
+
: 'A password file that proves your computer is allowed to deploy to your AWS account.',
|
|
189
|
+
whyNeeded: isLocal
|
|
190
|
+
? 'Only needed when you are ready to deploy your app to the internet.'
|
|
191
|
+
: 'Without credentials, AWS will reject all deploy commands.',
|
|
192
|
+
installCommands: ['Read everystack://aws-setup for full setup guide', 'aws configure'],
|
|
193
|
+
});
|
|
194
|
+
if (!hasAwsCreds && !isLocal) {
|
|
195
|
+
suggestions.push("AWS credentials not configured. Read everystack://aws-setup for step-by-step setup, or run 'aws configure' if you already have access keys.");
|
|
196
|
+
}
|
|
197
|
+
// PostgreSQL
|
|
198
|
+
const psqlOutput = tryExec('psql --version');
|
|
199
|
+
const psqlVersion = parseVersion(psqlOutput, /psql \(PostgreSQL\) (\d+\.\d+)/);
|
|
200
|
+
const pgReadyOutput = psqlVersion ? tryExec('pg_isready') : null;
|
|
201
|
+
const pgServiceUp = pgReadyOutput !== null && pgReadyOutput.includes('accepting connections');
|
|
202
|
+
prerequisites.push({
|
|
203
|
+
name: 'postgresql',
|
|
204
|
+
required: true,
|
|
205
|
+
status: psqlVersion ? 'found' : 'not_found',
|
|
206
|
+
version: psqlVersion,
|
|
207
|
+
serviceRunning: psqlVersion ? pgServiceUp : undefined,
|
|
208
|
+
installHint: 'Install PostgreSQL: brew install postgresql (macOS) or https://www.postgresql.org/download/',
|
|
209
|
+
tier: 'V2',
|
|
210
|
+
phase: 'local',
|
|
211
|
+
description: 'A database that stores your app data: users, posts, recipes, or whatever your app needs.',
|
|
212
|
+
whyNeeded: 'Without PostgreSQL, your app cannot have user accounts or saved data (needed for V2+).',
|
|
213
|
+
installCommands: platform === 'macOS'
|
|
214
|
+
? ['brew install postgresql@16', 'brew services start postgresql@16']
|
|
215
|
+
: platform === 'linux'
|
|
216
|
+
? ['sudo apt install postgresql', 'sudo systemctl start postgresql']
|
|
217
|
+
: ['Download from https://www.postgresql.org/download/'],
|
|
218
|
+
});
|
|
219
|
+
if (!psqlVersion) {
|
|
220
|
+
suggestions.push('PostgreSQL is not installed. Needed for V2+ (database tier). Install: brew install postgresql');
|
|
221
|
+
}
|
|
222
|
+
else if (!pgServiceUp) {
|
|
223
|
+
suggestions.push(platform === 'macOS'
|
|
224
|
+
? 'PostgreSQL is installed but the service is not running. Start it: brew services start postgresql@16'
|
|
225
|
+
: platform === 'linux'
|
|
226
|
+
? 'PostgreSQL is installed but the service is not running. Start it: sudo systemctl start postgresql'
|
|
227
|
+
: 'PostgreSQL is installed but the service is not running. Start the PostgreSQL service.');
|
|
228
|
+
}
|
|
229
|
+
// Determine readiness — in local phase, only local-phase prerequisites count
|
|
230
|
+
const relevant = isLocal
|
|
231
|
+
? prerequisites.filter(c => c.phase === 'local')
|
|
232
|
+
: prerequisites;
|
|
233
|
+
const v1Required = relevant.filter(c => c.tier === 'V1' && c.required);
|
|
234
|
+
const v2Required = relevant.filter(c => c.tier === 'V2' && c.required);
|
|
235
|
+
const v1Ready = nodeOk && v1Required.every(c => c.status === 'found');
|
|
236
|
+
const v2Ready = v1Ready && v2Required.every(c => c.status === 'found');
|
|
237
|
+
// V3 uses same prerequisites as V2 (adds SQS/S3 which are AWS services, no local tooling)
|
|
238
|
+
const v3Ready = v2Ready;
|
|
239
|
+
const readyForTier = v3Ready ? 'V3' : v2Ready ? 'V2' : v1Ready ? 'V1' : 'none';
|
|
240
|
+
// Build nextSteps
|
|
241
|
+
const nextSteps = [];
|
|
242
|
+
const missing = relevant.filter(p => p.required && p.status === 'not_found');
|
|
243
|
+
if (missing.length === 0) {
|
|
244
|
+
if (isLocal) {
|
|
245
|
+
nextSteps.push('All local development prerequisites installed. Ready to create and run your app.');
|
|
246
|
+
// Hint about deploy-phase tools if not yet installed
|
|
247
|
+
const deployMissing = prerequisites.filter(p => p.phase === 'deploy' && p.status === 'not_found');
|
|
248
|
+
if (deployMissing.length > 0) {
|
|
249
|
+
nextSteps.push('When you are ready to put your app on the internet, run check_environment with phase "deploy" to see what else is needed.');
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
else {
|
|
253
|
+
nextSteps.push('All prerequisites installed. Ready to create a new app.');
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
else {
|
|
257
|
+
const installOrder = isLocal
|
|
258
|
+
? ['node', 'git', 'pnpm', 'expo', 'postgresql']
|
|
259
|
+
: ['node', 'git', 'pnpm', 'aws-cli', 'aws-credentials', 'expo', 'sst', 'postgresql'];
|
|
260
|
+
const ordered = installOrder
|
|
261
|
+
.map(name => missing.find(p => p.name === name))
|
|
262
|
+
.filter((p) => p !== undefined);
|
|
263
|
+
for (const p of ordered) {
|
|
264
|
+
if (p.tier === 'V2') {
|
|
265
|
+
nextSteps.push(`Optional for now: Install ${p.name} — ${p.description.split('.')[0]}. Only needed for apps with user accounts or a database (V2+).`);
|
|
266
|
+
}
|
|
267
|
+
else {
|
|
268
|
+
nextSteps.push(`Install ${p.name} — ${p.description.split('.')[0]}. ${p.installCommands[0]}`);
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
return {
|
|
273
|
+
phase,
|
|
274
|
+
prerequisites,
|
|
275
|
+
ready: readyForTier !== 'none',
|
|
276
|
+
readyForTier,
|
|
277
|
+
suggestions,
|
|
278
|
+
platform,
|
|
279
|
+
nextSteps,
|
|
280
|
+
};
|
|
281
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/tools/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AASzE,wBAAgB,aAAa,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAcrD"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { checkEnvironment } from './check-environment.js';
|
|
3
|
+
// NOTE (Brick 0): the legacy regex tools — project_status, schema_analyze,
|
|
4
|
+
// project_validate — are intentionally NOT registered. They predate the v3
|
|
5
|
+
// Model/Module surface and return wrong answers on Model-based apps (e.g. they
|
|
6
|
+
// report a securely-derived handler config as "all tables accessible"). They are
|
|
7
|
+
// rebuilt on @everystack/model in Brick 1 and re-registered there. Their source
|
|
8
|
+
// files remain for that rewrite to reference.
|
|
9
|
+
export function registerTools(server) {
|
|
10
|
+
server.tool('check_environment', 'Verify development prerequisites are installed (Node.js, pnpm, git, Expo, SST, AWS CLI, PostgreSQL). Run this first when a user wants to start a new project or is having setup issues. Use phase "local" (default) to check only what is needed to build and run locally. Use phase "deploy" when ready to deploy to AWS.', {
|
|
11
|
+
phase: z.enum(['local', 'deploy']).optional().describe('Check prerequisites for local development (default) or AWS deployment'),
|
|
12
|
+
}, async ({ phase }) => {
|
|
13
|
+
const report = checkEnvironment(phase ?? 'local');
|
|
14
|
+
return {
|
|
15
|
+
content: [{ type: 'text', text: JSON.stringify(report, null, 2) }],
|
|
16
|
+
};
|
|
17
|
+
});
|
|
18
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
interface ProjectStatus {
|
|
2
|
+
tier: 'V1' | 'V2' | 'V3' | 'unknown';
|
|
3
|
+
tierExplanation: string;
|
|
4
|
+
packages: {
|
|
5
|
+
installed: string[];
|
|
6
|
+
missing: string[];
|
|
7
|
+
};
|
|
8
|
+
files: {
|
|
9
|
+
sstConfig: boolean;
|
|
10
|
+
schemaDir: boolean;
|
|
11
|
+
schemaFiles: string[];
|
|
12
|
+
migrationsDir: boolean;
|
|
13
|
+
serverDir: boolean;
|
|
14
|
+
handlerFile: string | null;
|
|
15
|
+
workerFile: string | null;
|
|
16
|
+
imageFile: string | null;
|
|
17
|
+
seedFile: string | null;
|
|
18
|
+
};
|
|
19
|
+
deployment: {
|
|
20
|
+
sstOutputs: boolean;
|
|
21
|
+
stage: string | null;
|
|
22
|
+
secrets: string[];
|
|
23
|
+
};
|
|
24
|
+
warnings: string[];
|
|
25
|
+
}
|
|
26
|
+
export declare function analyzeProjectStatus(projectPath: string): ProjectStatus;
|
|
27
|
+
export {};
|
|
28
|
+
//# sourceMappingURL=project-status.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"project-status.d.ts","sourceRoot":"","sources":["../../src/tools/project-status.ts"],"names":[],"mappings":"AAUA,UAAU,aAAa;IACrB,IAAI,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,SAAS,CAAC;IACrC,eAAe,EAAE,MAAM,CAAC;IACxB,QAAQ,EAAE;QACR,SAAS,EAAE,MAAM,EAAE,CAAC;QACpB,OAAO,EAAE,MAAM,EAAE,CAAC;KACnB,CAAC;IACF,KAAK,EAAE;QACL,SAAS,EAAE,OAAO,CAAC;QACnB,SAAS,EAAE,OAAO,CAAC;QACnB,WAAW,EAAE,MAAM,EAAE,CAAC;QACtB,aAAa,EAAE,OAAO,CAAC;QACvB,SAAS,EAAE,OAAO,CAAC;QACnB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;QAC3B,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;QAC1B,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;QACzB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;KACzB,CAAC;IACF,UAAU,EAAE;QACV,UAAU,EAAE,OAAO,CAAC;QACpB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;QACrB,OAAO,EAAE,MAAM,EAAE,CAAC;KACnB,CAAC;IACF,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AAgCD,wBAAgB,oBAAoB,CAAC,WAAW,EAAE,MAAM,GAAG,aAAa,CAoHvE"}
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
const V1_PACKAGES = ['@everystack/server', '@everystack/cli', '@everystack/ui'];
|
|
4
|
+
const V2_PACKAGES = ['@everystack/api', '@everystack/auth', '@everystack/admin', '@everystack/logging', '@everystack/security', '@everystack/query'];
|
|
5
|
+
const V3_PACKAGES = ['@everystack/jobs', '@everystack/storage', '@everystack/images'];
|
|
6
|
+
function readJson(path) {
|
|
7
|
+
if (!existsSync(path))
|
|
8
|
+
return null;
|
|
9
|
+
try {
|
|
10
|
+
return JSON.parse(readFileSync(path, 'utf-8'));
|
|
11
|
+
}
|
|
12
|
+
catch {
|
|
13
|
+
return null;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
function detectTier(installed) {
|
|
17
|
+
const hasV3 = V3_PACKAGES.some((p) => installed.includes(p));
|
|
18
|
+
const hasV2 = V2_PACKAGES.some((p) => installed.includes(p));
|
|
19
|
+
const hasV1 = V1_PACKAGES.some((p) => installed.includes(p));
|
|
20
|
+
if (hasV3) {
|
|
21
|
+
return { tier: 'V3', explanation: `Full platform — has V3 packages (${V3_PACKAGES.filter((p) => installed.includes(p)).join(', ')})` };
|
|
22
|
+
}
|
|
23
|
+
if (hasV2) {
|
|
24
|
+
return { tier: 'V2', explanation: `Dynamic — has V2 packages (${V2_PACKAGES.filter((p) => installed.includes(p)).join(', ')})` };
|
|
25
|
+
}
|
|
26
|
+
if (hasV1) {
|
|
27
|
+
return { tier: 'V1', explanation: `Static — has V1 packages (${V1_PACKAGES.filter((p) => installed.includes(p)).join(', ')})` };
|
|
28
|
+
}
|
|
29
|
+
return { tier: 'unknown', explanation: 'No everystack packages found in dependencies' };
|
|
30
|
+
}
|
|
31
|
+
export function analyzeProjectStatus(projectPath) {
|
|
32
|
+
const warnings = [];
|
|
33
|
+
// Read package.json
|
|
34
|
+
const pkg = readJson(join(projectPath, 'package.json'));
|
|
35
|
+
if (!pkg) {
|
|
36
|
+
return {
|
|
37
|
+
tier: 'unknown',
|
|
38
|
+
tierExplanation: 'No package.json found at project path',
|
|
39
|
+
packages: { installed: [], missing: [] },
|
|
40
|
+
files: {
|
|
41
|
+
sstConfig: false, schemaDir: false, schemaFiles: [],
|
|
42
|
+
migrationsDir: false, serverDir: false, handlerFile: null,
|
|
43
|
+
workerFile: null, imageFile: null, seedFile: null,
|
|
44
|
+
},
|
|
45
|
+
deployment: { sstOutputs: false, stage: null, secrets: [] },
|
|
46
|
+
warnings: [
|
|
47
|
+
'No package.json found — is this the correct project path?',
|
|
48
|
+
'No project here yet? Describe what you want to build and Claude will help create one.',
|
|
49
|
+
],
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
// Collect everystack dependencies
|
|
53
|
+
const allDeps = { ...(pkg.dependencies || {}), ...(pkg.devDependencies || {}) };
|
|
54
|
+
const installed = Object.keys(allDeps).filter((d) => d.startsWith('@everystack/'));
|
|
55
|
+
const allKnown = [...V1_PACKAGES, ...V2_PACKAGES, ...V3_PACKAGES];
|
|
56
|
+
const missing = allKnown.filter((p) => !installed.includes(p));
|
|
57
|
+
// Detect tier
|
|
58
|
+
const { tier, explanation } = detectTier(installed);
|
|
59
|
+
// Check key files/directories
|
|
60
|
+
const sstConfig = existsSync(join(projectPath, 'sst.config.ts'));
|
|
61
|
+
const schemaDir = existsSync(join(projectPath, 'db'));
|
|
62
|
+
const migrationsDir = existsSync(join(projectPath, 'db', 'migrations')) ||
|
|
63
|
+
existsSync(join(projectPath, 'server', 'drizzle'));
|
|
64
|
+
const serverDir = existsSync(join(projectPath, 'server'));
|
|
65
|
+
// Find schema files
|
|
66
|
+
const schemaFiles = [];
|
|
67
|
+
if (schemaDir) {
|
|
68
|
+
const schemaPath = join(projectPath, 'db', 'schema.ts');
|
|
69
|
+
if (existsSync(schemaPath))
|
|
70
|
+
schemaFiles.push('db/schema.ts');
|
|
71
|
+
const indexPath = join(projectPath, 'db', 'index.ts');
|
|
72
|
+
if (existsSync(indexPath))
|
|
73
|
+
schemaFiles.push('db/index.ts');
|
|
74
|
+
}
|
|
75
|
+
// Check handler files
|
|
76
|
+
const handlerCandidates = ['server/api.ts', 'server/handler.ts', 'server/index.ts'];
|
|
77
|
+
const handlerFile = handlerCandidates.find((f) => existsSync(join(projectPath, f))) ?? null;
|
|
78
|
+
const workerFile = existsSync(join(projectPath, 'server', 'worker.ts')) ? 'server/worker.ts' : null;
|
|
79
|
+
const imageFile = existsSync(join(projectPath, 'server', 'image.ts')) ? 'server/image.ts' : null;
|
|
80
|
+
const seedFile = existsSync(join(projectPath, 'db', 'seed.ts')) ? 'db/seed.ts' : null;
|
|
81
|
+
// Check deployment state
|
|
82
|
+
const sstOutputsPath = join(projectPath, '.sst', 'outputs.json');
|
|
83
|
+
const sstOutputs = existsSync(sstOutputsPath);
|
|
84
|
+
let stage = null;
|
|
85
|
+
const secrets = [];
|
|
86
|
+
if (sstOutputs) {
|
|
87
|
+
const outputs = readJson(sstOutputsPath);
|
|
88
|
+
if (outputs) {
|
|
89
|
+
// SST outputs are keyed by stage
|
|
90
|
+
const keys = Object.keys(outputs);
|
|
91
|
+
if (keys.length > 0)
|
|
92
|
+
stage = keys[0];
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
// Check for sst secret files
|
|
96
|
+
const sstDir = join(projectPath, '.sst');
|
|
97
|
+
if (existsSync(sstDir)) {
|
|
98
|
+
const secretCandidates = ['JwtSecret', 'DatabaseUrl', 'GoogleClientId', 'GoogleClientSecret', 'AppleClientId'];
|
|
99
|
+
for (const s of secretCandidates) {
|
|
100
|
+
if (existsSync(join(sstDir, 'secrets', s))) {
|
|
101
|
+
secrets.push(s);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
// Warnings
|
|
106
|
+
if (tier !== 'unknown' && tier !== 'V1' && !schemaDir) {
|
|
107
|
+
warnings.push('V2+ project but no db/ directory found — schema is required for PostgREST');
|
|
108
|
+
}
|
|
109
|
+
if (tier !== 'unknown' && tier !== 'V1' && schemaFiles.length === 0) {
|
|
110
|
+
warnings.push('No schema.ts found in db/ — create your Drizzle schema');
|
|
111
|
+
}
|
|
112
|
+
if (tier !== 'unknown' && !sstConfig) {
|
|
113
|
+
warnings.push('No sst.config.ts found — required for deployment');
|
|
114
|
+
}
|
|
115
|
+
if (installed.includes('@everystack/api') && !handlerFile) {
|
|
116
|
+
warnings.push('@everystack/api installed but no handler file found in server/');
|
|
117
|
+
}
|
|
118
|
+
if (installed.includes('@everystack/jobs') && !workerFile) {
|
|
119
|
+
warnings.push('@everystack/jobs installed but no server/worker.ts found');
|
|
120
|
+
}
|
|
121
|
+
if (installed.includes('@everystack/images') && !imageFile) {
|
|
122
|
+
warnings.push('@everystack/images installed but no server/image.ts found');
|
|
123
|
+
}
|
|
124
|
+
if (tier !== 'unknown' && tier !== 'V1' && !seedFile) {
|
|
125
|
+
warnings.push('No db/seed.ts found — recommended for development');
|
|
126
|
+
}
|
|
127
|
+
return {
|
|
128
|
+
tier,
|
|
129
|
+
tierExplanation: explanation,
|
|
130
|
+
packages: { installed, missing },
|
|
131
|
+
files: {
|
|
132
|
+
sstConfig, schemaDir, schemaFiles, migrationsDir,
|
|
133
|
+
serverDir, handlerFile, workerFile, imageFile, seedFile,
|
|
134
|
+
},
|
|
135
|
+
deployment: { sstOutputs, stage, secrets },
|
|
136
|
+
warnings,
|
|
137
|
+
};
|
|
138
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
type Severity = 'error' | 'warning' | 'info';
|
|
2
|
+
interface ValidationResult {
|
|
3
|
+
severity: Severity;
|
|
4
|
+
category: string;
|
|
5
|
+
message: string;
|
|
6
|
+
file?: string;
|
|
7
|
+
fix?: string;
|
|
8
|
+
}
|
|
9
|
+
interface ValidationReport {
|
|
10
|
+
results: ValidationResult[];
|
|
11
|
+
summary: {
|
|
12
|
+
errors: number;
|
|
13
|
+
warnings: number;
|
|
14
|
+
info: number;
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
export declare function validateProject(projectPath: string): ValidationReport;
|
|
18
|
+
export {};
|
|
19
|
+
//# sourceMappingURL=project-validate.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"project-validate.d.ts","sourceRoot":"","sources":["../../src/tools/project-validate.ts"],"names":[],"mappings":"AAGA,KAAK,QAAQ,GAAG,OAAO,GAAG,SAAS,GAAG,MAAM,CAAC;AAE7C,UAAU,gBAAgB;IACxB,QAAQ,EAAE,QAAQ,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED,UAAU,gBAAgB;IACxB,OAAO,EAAE,gBAAgB,EAAE,CAAC;IAC5B,OAAO,EAAE;QACP,MAAM,EAAE,MAAM,CAAC;QACf,QAAQ,EAAE,MAAM,CAAC;QACjB,IAAI,EAAE,MAAM,CAAC;KACd,CAAC;CACH;AAqUD,wBAAgB,eAAe,CAAC,WAAW,EAAE,MAAM,GAAG,gBAAgB,CAuBrE"}
|