@everystack/mcp 0.3.2 → 0.4.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/dist/adding-database.md +36 -23
- package/dist/cli.md +44 -3
- package/dist/core.md +19 -1
- package/dist/database-operations.md +236 -0
- package/dist/derived-objects.md +225 -0
- 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 +119 -107
- 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 +35 -18
- 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/schema-patterns.md +92 -106
- 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 +29 -13
- package/src/index.ts +1 -1
- package/src/prompts/add-feature.ts +4 -4
- package/src/prompts/claude-md.ts +4 -2
- package/src/prompts/debug.ts +3 -4
- package/src/prompts/deploy.ts +17 -8
- package/src/prompts/design-schema.ts +45 -59
- package/src/prompts/new-app.ts +21 -19
- package/src/prompts/secure.ts +3 -3
- package/src/resources/adding-database.md +36 -23
- package/src/resources/cli.md +44 -3
- package/src/resources/core.md +19 -1
- package/src/resources/database-operations.md +236 -0
- package/src/resources/derived-objects.md +225 -0
- package/src/resources/index.ts +15 -1
- package/src/resources/project-claude-md.md +35 -18
- package/src/resources/schema-patterns.md +92 -106
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export function registerDesignSchemaPrompt(server) {
|
|
3
|
+
server.prompt('design-schema', 'Interactive schema design: plain English description → Drizzle schema + migrations + RLS policies + handler config + testing checklist.', {
|
|
4
|
+
description: z.string().describe('Plain English description of the data model (e.g., "blog with posts, comments, and tags")'),
|
|
5
|
+
projectPath: z.string().optional().describe('Absolute path to project root (to analyze existing schema)'),
|
|
6
|
+
}, async ({ description, projectPath }) => {
|
|
7
|
+
return {
|
|
8
|
+
messages: [
|
|
9
|
+
{
|
|
10
|
+
role: 'user',
|
|
11
|
+
content: {
|
|
12
|
+
type: 'text',
|
|
13
|
+
text: [
|
|
14
|
+
`Design a database schema for: ${description}`,
|
|
15
|
+
'',
|
|
16
|
+
'## Instructions',
|
|
17
|
+
'',
|
|
18
|
+
'1. Read everystack://schema-patterns for Drizzle schema conventions.',
|
|
19
|
+
'2. Read everystack://security for RLS policy patterns.',
|
|
20
|
+
'3. Read everystack://handler-options for handler configuration.',
|
|
21
|
+
projectPath ? `4. Run schema_analyze with projectPath="${projectPath}" to understand the existing schema.` : '',
|
|
22
|
+
'',
|
|
23
|
+
'## Deliverables',
|
|
24
|
+
'',
|
|
25
|
+
'Generate ALL of the following:',
|
|
26
|
+
'',
|
|
27
|
+
'### 1. Drizzle Schema (db/schema.ts)',
|
|
28
|
+
'',
|
|
29
|
+
'Follow these conventions:',
|
|
30
|
+
'- UUID primary keys: `uuid(\'id\').primaryKey().defaultRandom()`',
|
|
31
|
+
'- Timestamps: `timestamp(\'created_at\', { withTimezone: true }).defaultNow().notNull()`',
|
|
32
|
+
'- Soft delete columns: `deletedAt` + `deletedBy` on user-facing tables',
|
|
33
|
+
'- Foreign keys with `.references(() => table.column)`',
|
|
34
|
+
'- Export all tables as named exports',
|
|
35
|
+
'- Add Drizzle `relations()` for SSR query building and API embedding',
|
|
36
|
+
'',
|
|
37
|
+
'### 2. SQL Migration with RLS',
|
|
38
|
+
'',
|
|
39
|
+
'Generate a custom SQL migration that includes:',
|
|
40
|
+
'',
|
|
41
|
+
'```sql',
|
|
42
|
+
'-- For each table:',
|
|
43
|
+
'ALTER TABLE table_name ENABLE ROW LEVEL SECURITY;',
|
|
44
|
+
'',
|
|
45
|
+
'-- Grant minimum required access per role:',
|
|
46
|
+
'GRANT SELECT ON table_name TO anon;',
|
|
47
|
+
'GRANT SELECT, INSERT, UPDATE, DELETE ON table_name TO authenticated;',
|
|
48
|
+
'GRANT ALL ON table_name TO admin;',
|
|
49
|
+
'',
|
|
50
|
+
'-- Policies per access pattern:',
|
|
51
|
+
'-- Public read:',
|
|
52
|
+
'CREATE POLICY "anon_select" ON table_name FOR SELECT TO anon USING (deleted_at IS NULL);',
|
|
53
|
+
'',
|
|
54
|
+
'-- Own rows only:',
|
|
55
|
+
'CREATE POLICY "own_rows" ON table_name FOR ALL TO authenticated',
|
|
56
|
+
' USING (user_id = current_setting(\'request.jwt.claims\', true)::json->>\'sub\');',
|
|
57
|
+
'',
|
|
58
|
+
'-- Admin full access:',
|
|
59
|
+
'CREATE POLICY "admin_all" ON table_name FOR ALL TO admin USING (true);',
|
|
60
|
+
'```',
|
|
61
|
+
'',
|
|
62
|
+
'Adapt the policies to the specific access patterns for each table.',
|
|
63
|
+
'',
|
|
64
|
+
'### 3. Handler Configuration',
|
|
65
|
+
'',
|
|
66
|
+
'Generate the createHandler() config snippet:',
|
|
67
|
+
'- `exposedTables`: only tables that should be API-accessible',
|
|
68
|
+
'- `relations`: for embedding related data in API queries',
|
|
69
|
+
'- `rowOwnership`: for user-scoped tables',
|
|
70
|
+
'- `softDelete`: for tables with deletedAt columns',
|
|
71
|
+
'- `protectedFields`: fields users cannot set directly (role, deletedAt)',
|
|
72
|
+
'- `hiddenColumns`: sensitive columns not returned in API responses',
|
|
73
|
+
'',
|
|
74
|
+
'### 4. Testing Checklist',
|
|
75
|
+
'',
|
|
76
|
+
'Generate a testing checklist:',
|
|
77
|
+
'- [ ] Anonymous users can read public data',
|
|
78
|
+
'- [ ] Anonymous users cannot write any data',
|
|
79
|
+
'- [ ] Authenticated users can only read/write their own data',
|
|
80
|
+
'- [ ] Soft-deleted rows are hidden from normal queries',
|
|
81
|
+
'- [ ] Admin users can access all data',
|
|
82
|
+
'- [ ] Foreign key constraints prevent orphaned rows',
|
|
83
|
+
'- [ ] RLS policies work with pgSettings claim injection',
|
|
84
|
+
'',
|
|
85
|
+
'Test each RLS policy with:',
|
|
86
|
+
'```sql',
|
|
87
|
+
'SET LOCAL ROLE authenticated;',
|
|
88
|
+
"SELECT set_config('request.jwt.claims', '{\"sub\": \"user-uuid\", \"role\": \"authenticated\"}', true);",
|
|
89
|
+
'SELECT * FROM table_name; -- should only return own rows',
|
|
90
|
+
'```',
|
|
91
|
+
].filter(Boolean).join('\n'),
|
|
92
|
+
},
|
|
93
|
+
},
|
|
94
|
+
],
|
|
95
|
+
};
|
|
96
|
+
});
|
|
97
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
+
/**
|
|
3
|
+
* `governance_setup` — guide the agent to wire the everystack governance hooks
|
|
4
|
+
* into the project's `.claude/settings.json`. The server instructions tell the
|
|
5
|
+
* agent that enforcement runs via hooks; this prompt produces the exact block and
|
|
6
|
+
* the confirm-first procedure.
|
|
7
|
+
*/
|
|
8
|
+
export declare function registerGovernanceSetupPrompt(server: McpServer): void;
|
|
9
|
+
//# sourceMappingURL=governance-setup.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"governance-setup.d.ts","sourceRoot":"","sources":["../../src/prompts/governance-setup.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAGzE;;;;;GAKG;AACH,wBAAgB,6BAA6B,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CA2ErE"}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
/**
|
|
3
|
+
* `governance_setup` — guide the agent to wire the everystack governance hooks
|
|
4
|
+
* into the project's `.claude/settings.json`. The server instructions tell the
|
|
5
|
+
* agent that enforcement runs via hooks; this prompt produces the exact block and
|
|
6
|
+
* the confirm-first procedure.
|
|
7
|
+
*/
|
|
8
|
+
export function registerGovernanceSetupPrompt(server) {
|
|
9
|
+
server.prompt('governance_setup', 'Install the everystack governance hooks (grounding gate + cheat gates) into .claude/settings.json. The MCP server alone does not enforce — the hooks are the teeth.', {
|
|
10
|
+
projectPath: z.string().optional().describe('Absolute path to the project root'),
|
|
11
|
+
mode: z
|
|
12
|
+
.enum(['workspace', 'installed'])
|
|
13
|
+
.optional()
|
|
14
|
+
.describe('"workspace" (run from this monorepo via tsx) or "installed" (the published @everystack/mcp bin). Default: detect.'),
|
|
15
|
+
}, async ({ projectPath, mode }) => {
|
|
16
|
+
const cmd = mode === 'workspace'
|
|
17
|
+
? 'npx tsx packages/mcp/src/index.ts'
|
|
18
|
+
: mode === 'installed'
|
|
19
|
+
? 'everystack-mcp'
|
|
20
|
+
: 'everystack-mcp';
|
|
21
|
+
const hooks = {
|
|
22
|
+
hooks: {
|
|
23
|
+
SessionStart: [{ hooks: [{ type: 'command', command: `${cmd} context` }] }],
|
|
24
|
+
PreToolUse: [{ matcher: '*', hooks: [{ type: 'command', command: `${cmd} gate` }] }],
|
|
25
|
+
PostToolUse: [
|
|
26
|
+
{ matcher: 'Read', hooks: [{ type: 'command', command: `${cmd} mark` }] },
|
|
27
|
+
{ matcher: 'Write|Edit', hooks: [{ type: 'command', command: `${cmd} validate` }] },
|
|
28
|
+
],
|
|
29
|
+
},
|
|
30
|
+
};
|
|
31
|
+
return {
|
|
32
|
+
messages: [
|
|
33
|
+
{
|
|
34
|
+
role: 'user',
|
|
35
|
+
content: {
|
|
36
|
+
type: 'text',
|
|
37
|
+
text: [
|
|
38
|
+
`Install the everystack governance hooks for ${projectPath ? 'the project at ' + projectPath : 'this project'}.`,
|
|
39
|
+
'',
|
|
40
|
+
'## Why',
|
|
41
|
+
'',
|
|
42
|
+
'The everystack MCP server provides knowledge, but ENFORCEMENT (the grounding gate and',
|
|
43
|
+
'cheat gates) runs only when these Claude Code hooks are installed. Without them, nothing',
|
|
44
|
+
'catches off-script work (hand-written migrations, data bundled into the app, secrets behind',
|
|
45
|
+
'EXPO_PUBLIC_*).',
|
|
46
|
+
'',
|
|
47
|
+
'## Procedure (confirm-first — never silent)',
|
|
48
|
+
'',
|
|
49
|
+
'1. Read `docs/governance-setup.md` and `hooks.example.json` from the @everystack/mcp package.',
|
|
50
|
+
`2. Check whether ${projectPath ? projectPath + '/.claude/settings.json' : '.claude/settings.json'} already has these hooks (commands calling \`${cmd} gate\`).`,
|
|
51
|
+
'3. If absent, show the human the exact block below and confirm the command form before writing:',
|
|
52
|
+
' - **Workspace (this monorepo):** `npx tsx packages/mcp/src/index.ts <sub>`',
|
|
53
|
+
' - **Installed package:** `everystack-mcp <sub>` (install `@everystack/mcp`; in a hook prefer',
|
|
54
|
+
' `pnpm exec everystack-mcp <sub>` over bare `npx`, which re-resolves on every tool call).',
|
|
55
|
+
'4. Merge the `hooks` block into `.claude/settings.json` (preserve any existing `hooks`/`permissions`).',
|
|
56
|
+
'5. Remind the human: hooks run a shell command on every tool call. This is a deliberate,',
|
|
57
|
+
' security-relevant change — it is their call, not yours to make silently.',
|
|
58
|
+
'',
|
|
59
|
+
'## The block to merge',
|
|
60
|
+
'',
|
|
61
|
+
'```json',
|
|
62
|
+
JSON.stringify(hooks, null, 2),
|
|
63
|
+
'```',
|
|
64
|
+
'',
|
|
65
|
+
'## After install',
|
|
66
|
+
'',
|
|
67
|
+
'- A fresh session denies every non-Read tool until the project contract (CLAUDE.md + its',
|
|
68
|
+
' REQUIRED-READS) is read. That is the grounding gate working.',
|
|
69
|
+
'- `everystack-mcp report` summarizes what the agent tried (the telemetry sensor).',
|
|
70
|
+
].join('\n'),
|
|
71
|
+
},
|
|
72
|
+
},
|
|
73
|
+
],
|
|
74
|
+
};
|
|
75
|
+
});
|
|
76
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/prompts/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAWzE,wBAAgB,eAAe,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAUvD"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { registerNewAppPrompt } from './new-app.js';
|
|
2
|
+
import { registerAddFeaturePrompt } from './add-feature.js';
|
|
3
|
+
import { registerDesignSchemaPrompt } from './design-schema.js';
|
|
4
|
+
import { registerDeployPrompt } from './deploy.js';
|
|
5
|
+
import { registerDebugPrompt } from './debug.js';
|
|
6
|
+
import { registerSecurePrompt } from './secure.js';
|
|
7
|
+
import { registerGovernanceSetupPrompt } from './governance-setup.js';
|
|
8
|
+
import { registerClaudeMdPrompt } from './claude-md.js';
|
|
9
|
+
import { registerRunbookPrompt } from './runbook.js';
|
|
10
|
+
export function registerPrompts(server) {
|
|
11
|
+
registerNewAppPrompt(server);
|
|
12
|
+
registerAddFeaturePrompt(server);
|
|
13
|
+
registerDesignSchemaPrompt(server);
|
|
14
|
+
registerDeployPrompt(server);
|
|
15
|
+
registerDebugPrompt(server);
|
|
16
|
+
registerSecurePrompt(server);
|
|
17
|
+
registerGovernanceSetupPrompt(server);
|
|
18
|
+
registerClaudeMdPrompt(server);
|
|
19
|
+
registerRunbookPrompt(server);
|
|
20
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"new-app.d.ts","sourceRoot":"","sources":["../../src/prompts/new-app.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAGzE,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAkN5D"}
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export function registerNewAppPrompt(server) {
|
|
3
|
+
server.prompt('new-app', 'Scaffold a new everystack app. Describe what you want to build and Claude will recommend the right tier, check prerequisites, and walk you through setup.', {
|
|
4
|
+
description: z.string().describe('Describe what you want to build (e.g., "a recipe sharing app where people can post and save recipes")'),
|
|
5
|
+
tier: z.enum(['V1', 'V2', 'V3']).optional().describe('Target tier: V1 (static), V2 (dynamic with DB), V3 (full platform). If omitted, recommended based on description.'),
|
|
6
|
+
name: z.string().optional().describe('App name (e.g., my-app). If omitted, suggested from description.'),
|
|
7
|
+
}, async ({ description, tier, name }) => {
|
|
8
|
+
const hasTier = tier !== undefined;
|
|
9
|
+
const hasName = name !== undefined;
|
|
10
|
+
const tierPackages = {
|
|
11
|
+
V1: ['@everystack/server', '@everystack/cli', '@everystack/ui'],
|
|
12
|
+
V2: [
|
|
13
|
+
'@everystack/server', '@everystack/cli', '@everystack/ui',
|
|
14
|
+
'@everystack/api', '@everystack/auth', '@everystack/admin',
|
|
15
|
+
'@everystack/logging', '@everystack/security', '@everystack/query',
|
|
16
|
+
],
|
|
17
|
+
V3: [
|
|
18
|
+
'@everystack/server', '@everystack/cli', '@everystack/ui',
|
|
19
|
+
'@everystack/api', '@everystack/auth', '@everystack/admin',
|
|
20
|
+
'@everystack/logging', '@everystack/security', '@everystack/query',
|
|
21
|
+
'@everystack/jobs', '@everystack/storage', '@everystack/images',
|
|
22
|
+
],
|
|
23
|
+
};
|
|
24
|
+
// When tier is omitted, build an intake phase for Claude to work through
|
|
25
|
+
const intakeSection = !hasTier ? [
|
|
26
|
+
'## Step 1: Understand the Idea',
|
|
27
|
+
'',
|
|
28
|
+
`The user wants to build: "${description}"`,
|
|
29
|
+
'',
|
|
30
|
+
'Read the everystack://getting-started resource for how to explain things to beginners.',
|
|
31
|
+
'Listen to what they want to build. Do NOT categorize into tiers or ask them to choose.',
|
|
32
|
+
'Every app starts the same way: a running Expo app. Build the UI first, add complexity when features demand it.',
|
|
33
|
+
'',
|
|
34
|
+
'## Step 2: Choose a Name',
|
|
35
|
+
'',
|
|
36
|
+
hasName
|
|
37
|
+
? `Use the name: "${name}"`
|
|
38
|
+
: 'Suggest a short, lowercase, hyphenated name based on the description (e.g., "recipe-share", "my-recipes"). Ask the user if they like it or want something different.',
|
|
39
|
+
'',
|
|
40
|
+
'## Step 3: Check Prerequisites',
|
|
41
|
+
'',
|
|
42
|
+
'Run the check_environment tool with phase "local".',
|
|
43
|
+
'Read everystack://getting-started for how to explain each prerequisite to a beginner.',
|
|
44
|
+
'Walk through installing missing tools ONE AT A TIME. Confirm each works before moving to the next.',
|
|
45
|
+
'Only V1 prerequisites are needed now — Node.js, git, pnpm. PostgreSQL is NOT needed yet.',
|
|
46
|
+
'AWS tools (AWS CLI, credentials, SST) are NOT needed now. The user will build and run locally first.',
|
|
47
|
+
'',
|
|
48
|
+
'## Step 4: Scaffold the Project',
|
|
49
|
+
'',
|
|
50
|
+
'Once prerequisites are ready and the user has confirmed the name, proceed with the scaffolding steps below.',
|
|
51
|
+
'The app starts as a static Expo app. Database, auth, and other features are added later when needed.',
|
|
52
|
+
'Explain each step in plain language alongside the technical commands.',
|
|
53
|
+
'',
|
|
54
|
+
].join('\n') : '';
|
|
55
|
+
const effectiveTier = tier || 'V1';
|
|
56
|
+
const effectiveName = name || 'my-app';
|
|
57
|
+
const packages = tierPackages[effectiveTier];
|
|
58
|
+
return {
|
|
59
|
+
messages: [
|
|
60
|
+
{
|
|
61
|
+
role: 'user',
|
|
62
|
+
content: {
|
|
63
|
+
type: 'text',
|
|
64
|
+
text: [
|
|
65
|
+
intakeSection,
|
|
66
|
+
hasTier
|
|
67
|
+
? `Create a new everystack ${effectiveTier} app called "${effectiveName}".`
|
|
68
|
+
: '## Scaffolding Instructions',
|
|
69
|
+
`Description: ${description}`,
|
|
70
|
+
'',
|
|
71
|
+
hasTier ? [
|
|
72
|
+
'## Prerequisites',
|
|
73
|
+
'',
|
|
74
|
+
'Run the check_environment tool with phase "local" to verify local development prerequisites.',
|
|
75
|
+
'If any required tools are missing, help the user install them before proceeding.',
|
|
76
|
+
'AWS tools are not needed yet — the user will build and run locally first.',
|
|
77
|
+
].join('\n') : '',
|
|
78
|
+
'',
|
|
79
|
+
'## Instructions',
|
|
80
|
+
'',
|
|
81
|
+
'1. Read the everystack://core resource for architecture and conventions.',
|
|
82
|
+
effectiveTier !== 'V1' ? '2. Read everystack://security for the security model.' : '',
|
|
83
|
+
effectiveTier !== 'V1' ? '3. Read everystack://schema-patterns for Drizzle schema design.' : '',
|
|
84
|
+
effectiveTier !== 'V1' ? '4. Read everystack://auth for authentication setup.' : '',
|
|
85
|
+
'',
|
|
86
|
+
'## Steps to Execute',
|
|
87
|
+
'',
|
|
88
|
+
'### 1. Project Setup',
|
|
89
|
+
`- Create the project directory: ${effectiveName}/`,
|
|
90
|
+
'- Initialize with: `npx create-expo-app@latest`',
|
|
91
|
+
`- Install packages: \`pnpm add ${packages.join(' ')}\``,
|
|
92
|
+
effectiveTier !== 'V1' ? '- Install peer deps: `pnpm add drizzle-orm && pnpm add -D drizzle-kit`' : '',
|
|
93
|
+
'- Install SST: `pnpm add -D sst`',
|
|
94
|
+
'',
|
|
95
|
+
'### 2. Project Structure',
|
|
96
|
+
'```',
|
|
97
|
+
`${effectiveName}/`,
|
|
98
|
+
'├── app/ # Expo Router pages',
|
|
99
|
+
effectiveTier !== 'V1' ? '├── db/ # Schema, migrations, seed' : '',
|
|
100
|
+
'├── server/ # Lambda handlers',
|
|
101
|
+
effectiveTier !== 'V1' ? '│ └── api.ts # PostgREST handler' : '',
|
|
102
|
+
effectiveTier === 'V3' ? '│ ├── worker.ts # SQS worker handler' : '',
|
|
103
|
+
effectiveTier === 'V3' ? '│ └── image.ts # Image processing handler' : '',
|
|
104
|
+
'├── lib/ # Shared code (auth context, API client)',
|
|
105
|
+
'├── sst.config.ts # Infrastructure',
|
|
106
|
+
'└── package.json',
|
|
107
|
+
'```',
|
|
108
|
+
'',
|
|
109
|
+
effectiveTier !== 'V1' ? [
|
|
110
|
+
'### 3. Database Schema',
|
|
111
|
+
`Create db/schema.ts with tables for the ${description}.`,
|
|
112
|
+
'Follow the patterns from everystack://schema-patterns:',
|
|
113
|
+
'- UUID primary keys with defaultRandom()',
|
|
114
|
+
'- created_at timestamps on all tables',
|
|
115
|
+
'- Foreign key references with proper cascading',
|
|
116
|
+
'- Relations for both SSR and API query embedding',
|
|
117
|
+
'',
|
|
118
|
+
'### 4. Migrations',
|
|
119
|
+
'- Generate: `npx drizzle-kit generate`',
|
|
120
|
+
'- Add RLS policies in a custom SQL migration',
|
|
121
|
+
'- Reference the RLS templates from everystack://security',
|
|
122
|
+
'',
|
|
123
|
+
'### 5. Handler Configuration',
|
|
124
|
+
'Create server/api.ts using createPluginLambdaHandler or createLambdaHandler.',
|
|
125
|
+
'Include:',
|
|
126
|
+
'- auth.verifyToken for JWT verification',
|
|
127
|
+
'- pgSettings for RLS context injection',
|
|
128
|
+
'- exposedTables to limit API surface',
|
|
129
|
+
'- rowOwnership for user-scoped mutation control',
|
|
130
|
+
'- softDelete for reversible deletes',
|
|
131
|
+
'',
|
|
132
|
+
'### 6. Auth Setup',
|
|
133
|
+
'Read everystack://auth for the full auth flow.',
|
|
134
|
+
'- Set up createAuthHandlers with the JWT secret',
|
|
135
|
+
'- Create lib/auth-context.tsx with AuthProvider',
|
|
136
|
+
'- Add signup/signin screens',
|
|
137
|
+
'',
|
|
138
|
+
].join('\n') : '',
|
|
139
|
+
'## Validation',
|
|
140
|
+
'',
|
|
141
|
+
'After scaffolding, run the project_validate tool to check for common mistakes.',
|
|
142
|
+
'',
|
|
143
|
+
'## Run Locally',
|
|
144
|
+
'',
|
|
145
|
+
'Read everystack://first-run for a walkthrough of what to expect.',
|
|
146
|
+
'- Run `npx expo start` (or `pnpm dev`)',
|
|
147
|
+
'- Press `w` to open in a browser',
|
|
148
|
+
'- Verify the app loads and displays correctly',
|
|
149
|
+
'- Try changing text in app/index.tsx to confirm hot reload works',
|
|
150
|
+
'',
|
|
151
|
+
'This is the milestone: the user sees their app running on their own computer.',
|
|
152
|
+
'Celebrate this. Then continue building features.',
|
|
153
|
+
'',
|
|
154
|
+
!hasTier ? [
|
|
155
|
+
'## Growing Your App',
|
|
156
|
+
'',
|
|
157
|
+
'Build the UI together first — screens, navigation, components, styling. Everything is static and visual.',
|
|
158
|
+
'',
|
|
159
|
+
'When a feature needs user accounts, login, or saved data:',
|
|
160
|
+
'- Read everystack://adding-database for the step-by-step guide',
|
|
161
|
+
'- Run check_environment("local") again — PostgreSQL will be needed',
|
|
162
|
+
'',
|
|
163
|
+
'When a feature needs file uploads or background processing:',
|
|
164
|
+
'- Read everystack://storage for file uploads',
|
|
165
|
+
'- Read everystack://jobs for background tasks',
|
|
166
|
+
'- Read everystack://images for image processing',
|
|
167
|
+
].join('\n') : '',
|
|
168
|
+
'',
|
|
169
|
+
'## Project Documentation',
|
|
170
|
+
'Scaffold the project contract (use the claude_md prompt): read the everystack://project-claude-md',
|
|
171
|
+
'resource and write a CLAUDE.md to the project root. This file activates the grounding gate —',
|
|
172
|
+
'every later session must read it before editing — so it carries the non-negotiables the cheat',
|
|
173
|
+
'gates enforce. Keep it current as the project grows (claude_md reconciles it).',
|
|
174
|
+
`Replace {PROJECT_NAME} with "${effectiveName}", {ONE_LINE_DESCRIPTION} with "${description}",`,
|
|
175
|
+
'and {ANNOTATED_DIRECTORY_TREE} with the actual project structure created above.',
|
|
176
|
+
'',
|
|
177
|
+
'## Deployment (Later)',
|
|
178
|
+
'',
|
|
179
|
+
'When the user is ready to put the app on the internet:',
|
|
180
|
+
'1. Run check_environment with phase "deploy" to verify AWS prerequisites',
|
|
181
|
+
'2. Set up AWS credentials (read everystack://aws-setup for beginners, everystack://security for IAM profiles)',
|
|
182
|
+
'### SST Configuration',
|
|
183
|
+
'Create sst.config.ts with:',
|
|
184
|
+
'- S3 bucket for static assets',
|
|
185
|
+
'- CloudFront distribution',
|
|
186
|
+
'- Lambda for SSR',
|
|
187
|
+
effectiveTier !== 'V1' ? '- RDS Aurora Serverless PostgreSQL' : '',
|
|
188
|
+
effectiveTier !== 'V1' ? '- VPC configuration' : '',
|
|
189
|
+
effectiveTier === 'V3' ? '- SQS queue for background jobs' : '',
|
|
190
|
+
effectiveTier === 'V3' ? '- S3 bucket for file uploads' : '',
|
|
191
|
+
'',
|
|
192
|
+
'### Deploy',
|
|
193
|
+
'Read everystack://deployment for the full walkthrough.',
|
|
194
|
+
'1. `pnpm sst deploy --stage dev`',
|
|
195
|
+
effectiveTier !== 'V1' ? '2. `everystack db:migrate`' : '',
|
|
196
|
+
effectiveTier !== 'V1' ? '3. `everystack db:seed` (dev only)' : '',
|
|
197
|
+
].filter(Boolean).join('\n'),
|
|
198
|
+
},
|
|
199
|
+
},
|
|
200
|
+
],
|
|
201
|
+
};
|
|
202
|
+
});
|
|
203
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
+
/**
|
|
3
|
+
* `runbook` — generate or refresh docs/RUNBOOK.md, the per-app operations manual.
|
|
4
|
+
*
|
|
5
|
+
* The compiler lives in the CLI (`everystack runbook` — db:generate for docs:
|
|
6
|
+
* detection → sections keyed by the app's reality → es:gen/es:slot merge). This
|
|
7
|
+
* prompt is the thin agent layer on top: run the compiler, then fill the EMPTY
|
|
8
|
+
* slots with app-specific narrative the compiler cannot know. Generated blocks
|
|
9
|
+
* belong to the compiler — the agent never writes inside them.
|
|
10
|
+
*/
|
|
11
|
+
export declare function registerRunbookPrompt(server: McpServer): void;
|
|
12
|
+
//# sourceMappingURL=runbook.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runbook.d.ts","sourceRoot":"","sources":["../../src/prompts/runbook.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAGzE;;;;;;;;GAQG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAgE7D"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
/**
|
|
3
|
+
* `runbook` — generate or refresh docs/RUNBOOK.md, the per-app operations manual.
|
|
4
|
+
*
|
|
5
|
+
* The compiler lives in the CLI (`everystack runbook` — db:generate for docs:
|
|
6
|
+
* detection → sections keyed by the app's reality → es:gen/es:slot merge). This
|
|
7
|
+
* prompt is the thin agent layer on top: run the compiler, then fill the EMPTY
|
|
8
|
+
* slots with app-specific narrative the compiler cannot know. Generated blocks
|
|
9
|
+
* belong to the compiler — the agent never writes inside them.
|
|
10
|
+
*/
|
|
11
|
+
export function registerRunbookPrompt(server) {
|
|
12
|
+
server.prompt('runbook', 'Generate or refresh docs/RUNBOOK.md — the operations manual compiled from the app\'s detected reality (tier, Models, handlers). Runs `everystack runbook`, then fills empty slots with app narrative (confirm-first). Regenerate after the app grows or an everystack upgrade.', {
|
|
13
|
+
projectPath: z.string().optional().describe('Absolute path to the project root (where docs/RUNBOOK.md lives)'),
|
|
14
|
+
}, async ({ projectPath }) => {
|
|
15
|
+
const root = projectPath ?? '.';
|
|
16
|
+
return {
|
|
17
|
+
messages: [
|
|
18
|
+
{
|
|
19
|
+
role: 'user',
|
|
20
|
+
content: {
|
|
21
|
+
type: 'text',
|
|
22
|
+
text: [
|
|
23
|
+
`Generate or refresh docs/RUNBOOK.md for the project at ${root}.`,
|
|
24
|
+
'',
|
|
25
|
+
'## What this is',
|
|
26
|
+
'',
|
|
27
|
+
'docs/RUNBOOK.md is the per-app operations manual — how to configure, extend, deploy,',
|
|
28
|
+
'monitor, and maintain THIS app. It is COMPILED, not authored: `everystack runbook`',
|
|
29
|
+
'derives it from the app\'s detected reality (installed packages → tier, Models,',
|
|
30
|
+
'handlers, crons) and regenerating after a change diffs in what\'s new. The division',
|
|
31
|
+
'of labor: CLAUDE.md is the terse contract (rules); the runbook is procedures.',
|
|
32
|
+
'',
|
|
33
|
+
'## Step 1 — run the compiler',
|
|
34
|
+
'',
|
|
35
|
+
`- If ${root}/docs/RUNBOOK.md exists, run \`everystack runbook --diff\` first and show`,
|
|
36
|
+
' the human which sections would change.',
|
|
37
|
+
'- Then run `everystack runbook` to write it. If it reports hand-edited generated',
|
|
38
|
+
' sections (a conflict), do NOT reach for --force — help the human move those words',
|
|
39
|
+
' into a slot or the Notes section first, then regenerate. --force only with their',
|
|
40
|
+
' explicit ok.',
|
|
41
|
+
'',
|
|
42
|
+
'## Step 2 — fill the EMPTY slots (and only the slots)',
|
|
43
|
+
'',
|
|
44
|
+
'The document has two kinds of content, mechanically marked:',
|
|
45
|
+
'- `<!-- es:gen section=... -->` blocks belong to the compiler. NEVER write inside one —',
|
|
46
|
+
' your words would be overwritten on the next regeneration, and the hash check flags it.',
|
|
47
|
+
'- `<!-- es:slot name=... -->` blocks are the human/agent seam and survive every',
|
|
48
|
+
' regeneration. A slot still holding its `_(Fill in: ...)_` placeholder is empty.',
|
|
49
|
+
'',
|
|
50
|
+
'For each empty slot, draft content from what you know of the project:',
|
|
51
|
+
'- `overview` — what the app is, who it serves, what an operator should know first.',
|
|
52
|
+
'- `stage-notes` — deployed URLs per stage, channel-to-stage mapping, release cadence',
|
|
53
|
+
' (read `.sst/outputs.json` or ask; do not guess URLs).',
|
|
54
|
+
'- `notes` — anything project-specific that fits nowhere else. Leave it if nothing real.',
|
|
55
|
+
'',
|
|
56
|
+
'Show the human your draft slot content and let them approve before writing — the',
|
|
57
|
+
'runbook is theirs; you assist, you do not own it.',
|
|
58
|
+
'',
|
|
59
|
+
'## Step 3 — verify',
|
|
60
|
+
'',
|
|
61
|
+
'Run `everystack runbook --check`: it must exit clean (slot edits never make it stale).',
|
|
62
|
+
'Tell the human: regenerate any time with `everystack runbook`; CI can enforce currency',
|
|
63
|
+
'with `--check`; after an everystack upgrade the diff reads as release notes for this app.',
|
|
64
|
+
].join('\n'),
|
|
65
|
+
},
|
|
66
|
+
},
|
|
67
|
+
],
|
|
68
|
+
};
|
|
69
|
+
});
|
|
70
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"secure.d.ts","sourceRoot":"","sources":["../../src/prompts/secure.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAGzE,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAmO5D"}
|