@getjack/jack 0.1.31 → 0.1.33
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/package.json +1 -1
- package/src/commands/deploys.ts +95 -0
- package/src/commands/link.ts +8 -0
- package/src/commands/mcp.ts +179 -4
- package/src/commands/rollback.ts +53 -0
- package/src/commands/services.ts +100 -20
- package/src/commands/ship.ts +30 -3
- package/src/commands/tokens.ts +134 -0
- package/src/commands/whoami.ts +51 -12
- package/src/index.ts +33 -0
- package/src/lib/agent-files.ts +54 -4
- package/src/lib/agent-integration.ts +4 -166
- package/src/lib/auth/client.ts +11 -1
- package/src/lib/auth/guard.ts +1 -1
- package/src/lib/auth/store.ts +3 -0
- package/src/lib/claude-hooks-installer.ts +55 -0
- package/src/lib/control-plane.ts +78 -40
- package/src/lib/debug.ts +2 -1
- package/src/lib/deploy-upload.ts +6 -0
- package/src/lib/hooks.ts +3 -1
- package/src/lib/managed-deploy.ts +12 -9
- package/src/lib/project-link.ts +6 -0
- package/src/lib/project-operations.ts +68 -22
- package/src/lib/services/token-operations.ts +84 -0
- package/src/lib/telemetry.ts +6 -0
- package/src/mcp/README.md +1 -1
- package/src/mcp/resources/index.ts +174 -16
- package/src/mcp/server.ts +23 -0
- package/src/mcp/tools/index.ts +133 -17
- package/src/mcp/types.ts +1 -0
- package/src/mcp/utils.ts +2 -1
- package/src/templates/index.ts +25 -73
- package/templates/CLAUDE.md +41 -0
- package/templates/ai-chat/.jack.json +10 -5
- package/templates/ai-chat/bun.lock +50 -1
- package/templates/ai-chat/package.json +5 -0
- package/templates/ai-chat/public/app.js +73 -0
- package/templates/ai-chat/public/index.html +14 -197
- package/templates/ai-chat/schema.sql +14 -0
- package/templates/ai-chat/src/index.ts +86 -102
- package/templates/ai-chat/wrangler.jsonc +8 -1
- package/templates/cron/.jack.json +66 -0
- package/templates/cron/bun.lock +23 -0
- package/templates/cron/package.json +16 -0
- package/templates/cron/schema.sql +24 -0
- package/templates/cron/src/index.ts +117 -0
- package/templates/cron/src/jobs.ts +139 -0
- package/templates/cron/src/webhooks.ts +95 -0
- package/templates/cron/tsconfig.json +17 -0
- package/templates/cron/wrangler.jsonc +11 -0
- package/templates/miniapp/.jack.json +1 -1
- package/templates/nextjs/.jack.json +1 -1
- package/templates/nextjs-auth/.jack.json +44 -0
- package/templates/nextjs-auth/app/api/auth/[...all]/route.ts +11 -0
- package/templates/nextjs-auth/app/dashboard/loading.tsx +53 -0
- package/templates/nextjs-auth/app/dashboard/page.tsx +73 -0
- package/templates/nextjs-auth/app/error.tsx +44 -0
- package/templates/nextjs-auth/app/globals.css +1 -0
- package/templates/nextjs-auth/app/health/route.ts +3 -0
- package/templates/nextjs-auth/app/layout.tsx +24 -0
- package/templates/nextjs-auth/app/login/page.tsx +10 -0
- package/templates/nextjs-auth/app/page.tsx +86 -0
- package/templates/nextjs-auth/app/signup/page.tsx +10 -0
- package/templates/nextjs-auth/bun.lock +1065 -0
- package/templates/nextjs-auth/cloudflare-env.d.ts +8 -0
- package/templates/nextjs-auth/components/auth-form.tsx +191 -0
- package/templates/nextjs-auth/components/header.tsx +50 -0
- package/templates/nextjs-auth/components/user-menu.tsx +23 -0
- package/templates/nextjs-auth/lib/auth-client.ts +3 -0
- package/templates/nextjs-auth/lib/auth.ts +43 -0
- package/templates/nextjs-auth/lib/utils.ts +6 -0
- package/templates/nextjs-auth/middleware.ts +33 -0
- package/templates/nextjs-auth/next.config.ts +8 -0
- package/templates/nextjs-auth/open-next.config.ts +6 -0
- package/templates/nextjs-auth/package.json +33 -0
- package/templates/nextjs-auth/postcss.config.mjs +8 -0
- package/templates/nextjs-auth/schema.sql +49 -0
- package/templates/nextjs-auth/tsconfig.json +28 -0
- package/templates/nextjs-auth/wrangler.jsonc +23 -0
- package/templates/nextjs-clerk/.jack.json +54 -0
- package/templates/nextjs-clerk/app/dashboard/page.tsx +69 -0
- package/templates/nextjs-clerk/app/globals.css +1 -0
- package/templates/nextjs-clerk/app/health/route.ts +3 -0
- package/templates/nextjs-clerk/app/layout.tsx +26 -0
- package/templates/nextjs-clerk/app/page.tsx +86 -0
- package/templates/nextjs-clerk/app/sign-in/[[...sign-in]]/page.tsx +9 -0
- package/templates/nextjs-clerk/app/sign-up/[[...sign-up]]/page.tsx +9 -0
- package/templates/nextjs-clerk/bun.lock +1055 -0
- package/templates/nextjs-clerk/cloudflare-env.d.ts +3 -0
- package/templates/nextjs-clerk/components/header.tsx +40 -0
- package/templates/nextjs-clerk/lib/utils.ts +6 -0
- package/templates/nextjs-clerk/middleware.ts +18 -0
- package/templates/nextjs-clerk/next.config.ts +8 -0
- package/templates/nextjs-clerk/open-next.config.ts +6 -0
- package/templates/nextjs-clerk/package.json +31 -0
- package/templates/nextjs-clerk/postcss.config.mjs +8 -0
- package/templates/nextjs-clerk/tsconfig.json +28 -0
- package/templates/nextjs-clerk/wrangler.jsonc +17 -0
- package/templates/nextjs-shadcn/.jack.json +34 -0
- package/templates/nextjs-shadcn/app/dashboard/data.json +614 -0
- package/templates/nextjs-shadcn/app/dashboard/page.tsx +55 -0
- package/templates/nextjs-shadcn/app/globals.css +126 -0
- package/templates/nextjs-shadcn/app/health/route.ts +3 -0
- package/templates/nextjs-shadcn/app/layout.tsx +24 -0
- package/templates/nextjs-shadcn/app/login/page.tsx +19 -0
- package/templates/nextjs-shadcn/app/page.tsx +180 -0
- package/templates/nextjs-shadcn/app/showcase.tsx +1262 -0
- package/templates/nextjs-shadcn/bun.lock +1789 -0
- package/templates/nextjs-shadcn/cloudflare-env.d.ts +4 -0
- package/templates/nextjs-shadcn/components/app-sidebar.tsx +175 -0
- package/templates/nextjs-shadcn/components/chart-area-interactive.tsx +291 -0
- package/templates/nextjs-shadcn/components/data-table.tsx +807 -0
- package/templates/nextjs-shadcn/components/login-form.tsx +95 -0
- package/templates/nextjs-shadcn/components/nav-documents.tsx +92 -0
- package/templates/nextjs-shadcn/components/nav-main.tsx +73 -0
- package/templates/nextjs-shadcn/components/nav-projects.tsx +89 -0
- package/templates/nextjs-shadcn/components/nav-secondary.tsx +42 -0
- package/templates/nextjs-shadcn/components/nav-user.tsx +114 -0
- package/templates/nextjs-shadcn/components/section-cards.tsx +102 -0
- package/templates/nextjs-shadcn/components/site-header.tsx +30 -0
- package/templates/nextjs-shadcn/components/team-switcher.tsx +91 -0
- package/templates/nextjs-shadcn/components/ui/accordion.tsx +66 -0
- package/templates/nextjs-shadcn/components/ui/alert-dialog.tsx +196 -0
- package/templates/nextjs-shadcn/components/ui/alert.tsx +66 -0
- package/templates/nextjs-shadcn/components/ui/aspect-ratio.tsx +11 -0
- package/templates/nextjs-shadcn/components/ui/avatar.tsx +109 -0
- package/templates/nextjs-shadcn/components/ui/badge.tsx +48 -0
- package/templates/nextjs-shadcn/components/ui/breadcrumb.tsx +109 -0
- package/templates/nextjs-shadcn/components/ui/button-group.tsx +83 -0
- package/templates/nextjs-shadcn/components/ui/button.tsx +64 -0
- package/templates/nextjs-shadcn/components/ui/calendar.tsx +220 -0
- package/templates/nextjs-shadcn/components/ui/card.tsx +92 -0
- package/templates/nextjs-shadcn/components/ui/carousel.tsx +241 -0
- package/templates/nextjs-shadcn/components/ui/chart.tsx +357 -0
- package/templates/nextjs-shadcn/components/ui/checkbox.tsx +32 -0
- package/templates/nextjs-shadcn/components/ui/collapsible.tsx +33 -0
- package/templates/nextjs-shadcn/components/ui/combobox.tsx +310 -0
- package/templates/nextjs-shadcn/components/ui/command.tsx +184 -0
- package/templates/nextjs-shadcn/components/ui/context-menu.tsx +252 -0
- package/templates/nextjs-shadcn/components/ui/dialog.tsx +158 -0
- package/templates/nextjs-shadcn/components/ui/direction.tsx +22 -0
- package/templates/nextjs-shadcn/components/ui/drawer.tsx +135 -0
- package/templates/nextjs-shadcn/components/ui/dropdown-menu.tsx +257 -0
- package/templates/nextjs-shadcn/components/ui/empty.tsx +104 -0
- package/templates/nextjs-shadcn/components/ui/field.tsx +248 -0
- package/templates/nextjs-shadcn/components/ui/form.tsx +167 -0
- package/templates/nextjs-shadcn/components/ui/hover-card.tsx +44 -0
- package/templates/nextjs-shadcn/components/ui/input-group.tsx +170 -0
- package/templates/nextjs-shadcn/components/ui/input-otp.tsx +77 -0
- package/templates/nextjs-shadcn/components/ui/input.tsx +21 -0
- package/templates/nextjs-shadcn/components/ui/item.tsx +193 -0
- package/templates/nextjs-shadcn/components/ui/kbd.tsx +28 -0
- package/templates/nextjs-shadcn/components/ui/label.tsx +24 -0
- package/templates/nextjs-shadcn/components/ui/menubar.tsx +276 -0
- package/templates/nextjs-shadcn/components/ui/native-select.tsx +53 -0
- package/templates/nextjs-shadcn/components/ui/navigation-menu.tsx +168 -0
- package/templates/nextjs-shadcn/components/ui/pagination.tsx +127 -0
- package/templates/nextjs-shadcn/components/ui/popover.tsx +89 -0
- package/templates/nextjs-shadcn/components/ui/progress.tsx +31 -0
- package/templates/nextjs-shadcn/components/ui/radio-group.tsx +45 -0
- package/templates/nextjs-shadcn/components/ui/resizable.tsx +53 -0
- package/templates/nextjs-shadcn/components/ui/scroll-area.tsx +58 -0
- package/templates/nextjs-shadcn/components/ui/select.tsx +190 -0
- package/templates/nextjs-shadcn/components/ui/separator.tsx +28 -0
- package/templates/nextjs-shadcn/components/ui/sheet.tsx +143 -0
- package/templates/nextjs-shadcn/components/ui/sidebar.tsx +726 -0
- package/templates/nextjs-shadcn/components/ui/skeleton.tsx +13 -0
- package/templates/nextjs-shadcn/components/ui/slider.tsx +63 -0
- package/templates/nextjs-shadcn/components/ui/sonner.tsx +40 -0
- package/templates/nextjs-shadcn/components/ui/spinner.tsx +16 -0
- package/templates/nextjs-shadcn/components/ui/switch.tsx +35 -0
- package/templates/nextjs-shadcn/components/ui/table.tsx +116 -0
- package/templates/nextjs-shadcn/components/ui/tabs.tsx +91 -0
- package/templates/nextjs-shadcn/components/ui/textarea.tsx +18 -0
- package/templates/nextjs-shadcn/components/ui/toggle-group.tsx +83 -0
- package/templates/nextjs-shadcn/components/ui/toggle.tsx +47 -0
- package/templates/nextjs-shadcn/components/ui/tooltip.tsx +57 -0
- package/templates/nextjs-shadcn/components.json +23 -0
- package/templates/nextjs-shadcn/hooks/use-mobile.ts +19 -0
- package/templates/nextjs-shadcn/lib/utils.ts +6 -0
- package/templates/nextjs-shadcn/next-env.d.ts +6 -0
- package/templates/nextjs-shadcn/next.config.ts +8 -0
- package/templates/nextjs-shadcn/open-next.config.ts +6 -0
- package/templates/nextjs-shadcn/package.json +55 -0
- package/templates/nextjs-shadcn/postcss.config.mjs +8 -0
- package/templates/nextjs-shadcn/tsconfig.json +28 -0
- package/templates/nextjs-shadcn/wrangler.jsonc +23 -0
- package/templates/resend/.jack.json +64 -0
- package/templates/resend/bun.lock +23 -0
- package/templates/resend/package.json +16 -0
- package/templates/resend/schema.sql +13 -0
- package/templates/resend/src/email.ts +165 -0
- package/templates/resend/src/index.ts +108 -0
- package/templates/resend/tsconfig.json +17 -0
- package/templates/resend/wrangler.jsonc +11 -0
- package/templates/saas/.jack.json +1 -1
- package/templates/ai-chat/public/chat.js +0 -149
|
@@ -31,6 +31,13 @@ export function registerResources(
|
|
|
31
31
|
description: "Semantic information about jack's capabilities for AI agents",
|
|
32
32
|
mimeType: "application/json",
|
|
33
33
|
},
|
|
34
|
+
{
|
|
35
|
+
uri: "agents://workflows",
|
|
36
|
+
name: "Workflow Recipes",
|
|
37
|
+
description:
|
|
38
|
+
"Multi-step workflow templates for common tasks like creating APIs with databases, debugging production issues, and setting up cron jobs",
|
|
39
|
+
mimeType: "text/markdown",
|
|
40
|
+
},
|
|
34
41
|
],
|
|
35
42
|
};
|
|
36
43
|
});
|
|
@@ -67,30 +74,15 @@ export function registerResources(
|
|
|
67
74
|
|
|
68
75
|
if (uri === "agents://context") {
|
|
69
76
|
const projectPath = options.projectPath ?? process.cwd();
|
|
70
|
-
const jackPath = join(projectPath, "JACK.md");
|
|
71
77
|
const agentsPath = join(projectPath, "AGENTS.md");
|
|
72
78
|
const claudePath = join(projectPath, "CLAUDE.md");
|
|
73
79
|
|
|
74
80
|
const contents: string[] = [];
|
|
75
81
|
|
|
76
|
-
// Try to read JACK.md first (jack-specific context)
|
|
77
|
-
if (existsSync(jackPath)) {
|
|
78
|
-
try {
|
|
79
|
-
const jackContent = await Bun.file(jackPath).text();
|
|
80
|
-
contents.push("# JACK.md\n\n");
|
|
81
|
-
contents.push(jackContent);
|
|
82
|
-
} catch {
|
|
83
|
-
// Ignore read errors
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
|
|
87
82
|
// Try to read AGENTS.md
|
|
88
83
|
if (existsSync(agentsPath)) {
|
|
89
84
|
try {
|
|
90
85
|
const agentsContent = await Bun.file(agentsPath).text();
|
|
91
|
-
if (contents.length > 0) {
|
|
92
|
-
contents.push("\n\n---\n\n");
|
|
93
|
-
}
|
|
94
86
|
contents.push("# AGENTS.md\n\n");
|
|
95
87
|
contents.push(agentsContent);
|
|
96
88
|
} catch {
|
|
@@ -136,7 +128,7 @@ If connected, prefer \`mcp__jack__*\` tools over CLI:
|
|
|
136
128
|
|
|
137
129
|
Full docs: https://docs.getjack.org/llms-full.txt
|
|
138
130
|
|
|
139
|
-
Check
|
|
131
|
+
Check AGENTS.md in the project root for project-specific instructions.
|
|
140
132
|
`;
|
|
141
133
|
return {
|
|
142
134
|
contents: [
|
|
@@ -160,6 +152,172 @@ Check for JACK.md in the project root for project-specific instructions.
|
|
|
160
152
|
};
|
|
161
153
|
}
|
|
162
154
|
|
|
155
|
+
if (uri === "agents://workflows") {
|
|
156
|
+
const workflows = `# Jack Workflow Recipes
|
|
157
|
+
|
|
158
|
+
Multi-step workflows for common tasks. Each workflow can be executed by an agent team or a single agent working sequentially.
|
|
159
|
+
|
|
160
|
+
---
|
|
161
|
+
|
|
162
|
+
## 1. Create API with Database
|
|
163
|
+
|
|
164
|
+
Goal: Scaffold a new API, add a database, create tables, and verify.
|
|
165
|
+
|
|
166
|
+
\`\`\`
|
|
167
|
+
Step 1: Create project
|
|
168
|
+
jack new my-api --template api
|
|
169
|
+
|
|
170
|
+
Step 2: Add database
|
|
171
|
+
mcp__jack__create_database (or: jack services db create)
|
|
172
|
+
|
|
173
|
+
Step 3: Create schema
|
|
174
|
+
mcp__jack__execute_sql
|
|
175
|
+
sql: "CREATE TABLE items (id INTEGER PRIMARY KEY, name TEXT NOT NULL, created_at TEXT DEFAULT CURRENT_TIMESTAMP)"
|
|
176
|
+
allow_write: true
|
|
177
|
+
|
|
178
|
+
Step 4: Edit src/index.ts — add routes that use c.env.DB
|
|
179
|
+
|
|
180
|
+
Step 5: Deploy
|
|
181
|
+
mcp__jack__deploy_project (or: jack ship)
|
|
182
|
+
|
|
183
|
+
Step 6: Verify
|
|
184
|
+
curl https://<slug>.runjack.xyz/api/items
|
|
185
|
+
\`\`\`
|
|
186
|
+
|
|
187
|
+
---
|
|
188
|
+
|
|
189
|
+
## 2. Debug Production Issue
|
|
190
|
+
|
|
191
|
+
Goal: Identify and fix a bug reported in production.
|
|
192
|
+
|
|
193
|
+
\`\`\`
|
|
194
|
+
Step 1: Check current status
|
|
195
|
+
mcp__jack__get_project_status (or: jack info)
|
|
196
|
+
|
|
197
|
+
Step 2: Collect recent logs
|
|
198
|
+
mcp__jack__tail_logs with max_events: 100, duration_ms: 5000
|
|
199
|
+
|
|
200
|
+
Step 3: Inspect database state if relevant
|
|
201
|
+
mcp__jack__execute_sql
|
|
202
|
+
sql: "SELECT * FROM <table> WHERE <condition>"
|
|
203
|
+
|
|
204
|
+
Step 4: Read and fix the source code
|
|
205
|
+
|
|
206
|
+
Step 5: Deploy fix
|
|
207
|
+
mcp__jack__deploy_project (or: jack ship)
|
|
208
|
+
|
|
209
|
+
Step 6: Verify fix via logs
|
|
210
|
+
mcp__jack__tail_logs with max_events: 20, duration_ms: 3000
|
|
211
|
+
\`\`\`
|
|
212
|
+
|
|
213
|
+
---
|
|
214
|
+
|
|
215
|
+
## 3. Add Scheduled Task (Cron)
|
|
216
|
+
|
|
217
|
+
Goal: Run code on a schedule (cleanup, sync, reports).
|
|
218
|
+
|
|
219
|
+
\`\`\`
|
|
220
|
+
Step 1: Add scheduled handler to src/index.ts
|
|
221
|
+
export default {
|
|
222
|
+
async fetch(request, env) { ... },
|
|
223
|
+
async scheduled(event, env, ctx) {
|
|
224
|
+
// your cron logic here
|
|
225
|
+
},
|
|
226
|
+
};
|
|
227
|
+
|
|
228
|
+
Or with Hono, add a POST /__scheduled route.
|
|
229
|
+
|
|
230
|
+
Step 2: Deploy the handler
|
|
231
|
+
mcp__jack__deploy_project (or: jack ship)
|
|
232
|
+
|
|
233
|
+
Step 3: Create cron schedule
|
|
234
|
+
mcp__jack__create_cron with expression: "0 * * * *"
|
|
235
|
+
(or: jack services cron create "0 * * * *")
|
|
236
|
+
|
|
237
|
+
Step 4: Verify schedule
|
|
238
|
+
mcp__jack__test_cron with expression: "0 * * * *"
|
|
239
|
+
Shows next 5 scheduled times.
|
|
240
|
+
|
|
241
|
+
Step 5: Monitor via logs
|
|
242
|
+
mcp__jack__tail_logs
|
|
243
|
+
\`\`\`
|
|
244
|
+
|
|
245
|
+
---
|
|
246
|
+
|
|
247
|
+
## 4. Add File Storage
|
|
248
|
+
|
|
249
|
+
Goal: Enable file uploads and downloads via R2.
|
|
250
|
+
|
|
251
|
+
\`\`\`
|
|
252
|
+
Step 1: Create storage bucket
|
|
253
|
+
mcp__jack__create_storage_bucket (or: jack services storage create)
|
|
254
|
+
|
|
255
|
+
Step 2: Deploy to activate binding
|
|
256
|
+
mcp__jack__deploy_project (or: jack ship)
|
|
257
|
+
|
|
258
|
+
Step 3: Add upload/download routes to src/index.ts
|
|
259
|
+
Upload: c.env.BUCKET.put(key, body)
|
|
260
|
+
Download: c.env.BUCKET.get(key)
|
|
261
|
+
List: c.env.BUCKET.list()
|
|
262
|
+
|
|
263
|
+
Step 4: Deploy routes
|
|
264
|
+
mcp__jack__deploy_project (or: jack ship)
|
|
265
|
+
\`\`\`
|
|
266
|
+
|
|
267
|
+
---
|
|
268
|
+
|
|
269
|
+
## 5. Add Semantic Search (Vectorize + AI)
|
|
270
|
+
|
|
271
|
+
Goal: Enable vector similarity search using embeddings.
|
|
272
|
+
|
|
273
|
+
\`\`\`
|
|
274
|
+
Step 1: Create vector index
|
|
275
|
+
mcp__jack__create_vectorize_index (or: jack services vectorize create)
|
|
276
|
+
Default: 768 dimensions, cosine metric (matches bge-base-en-v1.5)
|
|
277
|
+
|
|
278
|
+
Step 2: Deploy to activate binding
|
|
279
|
+
mcp__jack__deploy_project (or: jack ship)
|
|
280
|
+
|
|
281
|
+
Step 3: Add indexing route
|
|
282
|
+
Generate embedding: c.env.AI.run("@cf/baai/bge-base-en-v1.5", { text: [input] })
|
|
283
|
+
Insert: c.env.VECTORIZE_INDEX.insert([{ id, values, metadata }])
|
|
284
|
+
|
|
285
|
+
Step 4: Add search route
|
|
286
|
+
Generate query embedding, then:
|
|
287
|
+
c.env.VECTORIZE_INDEX.query(embedding, { topK: 5, returnMetadata: "all" })
|
|
288
|
+
|
|
289
|
+
Step 5: Deploy and test
|
|
290
|
+
mcp__jack__deploy_project (or: jack ship)
|
|
291
|
+
\`\`\`
|
|
292
|
+
|
|
293
|
+
---
|
|
294
|
+
|
|
295
|
+
## Parallel Task Patterns (Agent Teams)
|
|
296
|
+
|
|
297
|
+
For Opus 4.6 Agent Teams, these tasks can run in parallel:
|
|
298
|
+
|
|
299
|
+
**Independent (run simultaneously):**
|
|
300
|
+
- Creating database + creating storage bucket
|
|
301
|
+
- Reading logs + checking project status
|
|
302
|
+
- Multiple SQL queries on different tables
|
|
303
|
+
|
|
304
|
+
**Sequential (must wait for previous):**
|
|
305
|
+
- Create project → then add services
|
|
306
|
+
- Create database → then create tables → then deploy
|
|
307
|
+
- Edit code → then deploy → then verify
|
|
308
|
+
`;
|
|
309
|
+
|
|
310
|
+
return {
|
|
311
|
+
contents: [
|
|
312
|
+
{
|
|
313
|
+
uri,
|
|
314
|
+
mimeType: "text/markdown",
|
|
315
|
+
text: workflows,
|
|
316
|
+
},
|
|
317
|
+
],
|
|
318
|
+
};
|
|
319
|
+
}
|
|
320
|
+
|
|
163
321
|
throw new Error(`Unknown resource URI: ${uri}`);
|
|
164
322
|
});
|
|
165
323
|
}
|
package/src/mcp/server.ts
CHANGED
|
@@ -43,8 +43,31 @@ export async function createMcpServer(options: McpServerOptions = {}) {
|
|
|
43
43
|
return { server, debug };
|
|
44
44
|
}
|
|
45
45
|
|
|
46
|
+
/**
|
|
47
|
+
* Install runtime guards that prevent accidental stdout writes from corrupting
|
|
48
|
+
* the MCP JSON-RPC stdio transport. This catches console.log() and
|
|
49
|
+
* process.stdout.write() but NOT Bun.spawn({ stdout: "inherit" }) which writes
|
|
50
|
+
* directly to fd 1 — that case is handled by the `interactive` flag in hooks.
|
|
51
|
+
*/
|
|
52
|
+
function installStdoutGuards() {
|
|
53
|
+
// Redirect console.log to stderr so accidental calls don't corrupt the stream.
|
|
54
|
+
// We don't wrap process.stdout.write because the MCP SDK writes JSON-RPC
|
|
55
|
+
// messages through it — intercepting those risks breaking the protocol if
|
|
56
|
+
// messages are chunked or newlines are written separately.
|
|
57
|
+
console.log = (...args: unknown[]) => {
|
|
58
|
+
console.error(
|
|
59
|
+
"[jack-mcp] WARNING: console.log intercepted (would corrupt MCP protocol):",
|
|
60
|
+
...args,
|
|
61
|
+
);
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
|
|
46
65
|
export async function startMcpServer(options: McpServerOptions = {}) {
|
|
47
66
|
const { server, debug } = await createMcpServer(options);
|
|
67
|
+
|
|
68
|
+
// Install stdout guards BEFORE connecting transport to prevent corruption
|
|
69
|
+
installStdoutGuards();
|
|
70
|
+
|
|
48
71
|
const transport = new StdioServerTransport();
|
|
49
72
|
|
|
50
73
|
debug("Starting MCP server on stdio transport");
|
package/src/mcp/tools/index.ts
CHANGED
|
@@ -7,6 +7,10 @@ import { JackError, JackErrorCode } from "../../lib/errors.ts";
|
|
|
7
7
|
import { getDeployMode, getProjectId } from "../../lib/project-link.ts";
|
|
8
8
|
import { createProject, deployProject, getProjectStatus } from "../../lib/project-operations.ts";
|
|
9
9
|
import { listAllProjects } from "../../lib/project-resolver.ts";
|
|
10
|
+
import { createCronSchedule } from "../../lib/services/cron-create.ts";
|
|
11
|
+
import { deleteCronSchedule } from "../../lib/services/cron-delete.ts";
|
|
12
|
+
import { listCronSchedules } from "../../lib/services/cron-list.ts";
|
|
13
|
+
import { testCronExpression } from "../../lib/services/cron-test.ts";
|
|
10
14
|
import { createDatabase } from "../../lib/services/db-create.ts";
|
|
11
15
|
import {
|
|
12
16
|
DestructiveOperationError,
|
|
@@ -15,10 +19,6 @@ import {
|
|
|
15
19
|
wrapResultsForMcp,
|
|
16
20
|
} from "../../lib/services/db-execute.ts";
|
|
17
21
|
import { listDatabases } from "../../lib/services/db-list.ts";
|
|
18
|
-
import { createCronSchedule } from "../../lib/services/cron-create.ts";
|
|
19
|
-
import { deleteCronSchedule } from "../../lib/services/cron-delete.ts";
|
|
20
|
-
import { listCronSchedules } from "../../lib/services/cron-list.ts";
|
|
21
|
-
import { testCronExpression } from "../../lib/services/cron-test.ts";
|
|
22
22
|
import {
|
|
23
23
|
assignDomain,
|
|
24
24
|
connectDomain,
|
|
@@ -41,7 +41,12 @@ import { formatErrorResponse, formatSuccessResponse } from "../utils.ts";
|
|
|
41
41
|
// Tool schemas
|
|
42
42
|
const CreateProjectSchema = z.object({
|
|
43
43
|
name: z.string().optional().describe("Project name (auto-generated if not provided)"),
|
|
44
|
-
template: z
|
|
44
|
+
template: z
|
|
45
|
+
.string()
|
|
46
|
+
.optional()
|
|
47
|
+
.describe(
|
|
48
|
+
"Template to use (e.g., 'miniapp', 'api'). Also supports forking: use 'username/slug' for published projects or 'my-project' to fork your own.",
|
|
49
|
+
),
|
|
45
50
|
});
|
|
46
51
|
|
|
47
52
|
const DeployProjectSchema = z.object({
|
|
@@ -49,6 +54,12 @@ const DeployProjectSchema = z.object({
|
|
|
49
54
|
.string()
|
|
50
55
|
.optional()
|
|
51
56
|
.describe("Path to project directory (defaults to current directory)"),
|
|
57
|
+
message: z
|
|
58
|
+
.string()
|
|
59
|
+
.optional()
|
|
60
|
+
.describe(
|
|
61
|
+
"Deploy message describing what changed and why (e.g., 'Add user auth', 'Fix CORS bug')",
|
|
62
|
+
),
|
|
52
63
|
});
|
|
53
64
|
|
|
54
65
|
const GetProjectStatusSchema = z.object({
|
|
@@ -200,6 +211,19 @@ const TailLogsSchema = z.object({
|
|
|
200
211
|
.describe("How long to listen before returning (default: 2000ms, max: 10000ms)"),
|
|
201
212
|
});
|
|
202
213
|
|
|
214
|
+
const RollbackProjectSchema = z.object({
|
|
215
|
+
deployment_id: z
|
|
216
|
+
.string()
|
|
217
|
+
.optional()
|
|
218
|
+
.describe(
|
|
219
|
+
"Specific deployment ID to roll back to (defaults to previous successful deployment)",
|
|
220
|
+
),
|
|
221
|
+
project_path: z
|
|
222
|
+
.string()
|
|
223
|
+
.optional()
|
|
224
|
+
.describe("Path to project directory (defaults to current directory)"),
|
|
225
|
+
});
|
|
226
|
+
|
|
203
227
|
const ListDomainsSchema = z.object({});
|
|
204
228
|
|
|
205
229
|
const ConnectDomainSchema = z.object({
|
|
@@ -220,7 +244,9 @@ const DisconnectDomainSchema = z.object({
|
|
|
220
244
|
});
|
|
221
245
|
|
|
222
246
|
const CreateCronSchema = z.object({
|
|
223
|
-
expression: z
|
|
247
|
+
expression: z
|
|
248
|
+
.string()
|
|
249
|
+
.describe("Cron expression (e.g., '0 * * * *' for hourly, '*/15 * * * *' for every 15 min)"),
|
|
224
250
|
project_path: z
|
|
225
251
|
.string()
|
|
226
252
|
.optional()
|
|
@@ -264,7 +290,7 @@ export function registerTools(server: McpServer, _options: McpServerOptions, deb
|
|
|
264
290
|
{
|
|
265
291
|
name: "create_project",
|
|
266
292
|
description:
|
|
267
|
-
"Create a new
|
|
293
|
+
"Create a new project from a template. Automatically installs dependencies, deploys, and registers the project. Also supports forking: pass a 'username/slug' template to fork a published project, or a project slug to fork your own.",
|
|
268
294
|
inputSchema: {
|
|
269
295
|
type: "object",
|
|
270
296
|
properties: {
|
|
@@ -274,7 +300,8 @@ export function registerTools(server: McpServer, _options: McpServerOptions, deb
|
|
|
274
300
|
},
|
|
275
301
|
template: {
|
|
276
302
|
type: "string",
|
|
277
|
-
description:
|
|
303
|
+
description:
|
|
304
|
+
"Template to use (e.g., 'miniapp', 'api'). Also supports forking: use 'username/slug' for published projects or 'my-project' to fork your own.",
|
|
278
305
|
},
|
|
279
306
|
},
|
|
280
307
|
},
|
|
@@ -282,7 +309,7 @@ export function registerTools(server: McpServer, _options: McpServerOptions, deb
|
|
|
282
309
|
{
|
|
283
310
|
name: "deploy_project",
|
|
284
311
|
description:
|
|
285
|
-
"Deploy an existing project
|
|
312
|
+
"Deploy an existing project. Builds if needed and pushes to production. Always provide a 'message' describing what changed and why (e.g., 'Add user auth', 'Fix CORS bug').",
|
|
286
313
|
inputSchema: {
|
|
287
314
|
type: "object",
|
|
288
315
|
properties: {
|
|
@@ -290,13 +317,18 @@ export function registerTools(server: McpServer, _options: McpServerOptions, deb
|
|
|
290
317
|
type: "string",
|
|
291
318
|
description: "Path to project directory (defaults to current directory)",
|
|
292
319
|
},
|
|
320
|
+
message: {
|
|
321
|
+
type: "string",
|
|
322
|
+
description:
|
|
323
|
+
"Deploy message describing what changed and why (e.g., 'Add user auth', 'Fix CORS bug')",
|
|
324
|
+
},
|
|
293
325
|
},
|
|
294
326
|
},
|
|
295
327
|
},
|
|
296
328
|
{
|
|
297
329
|
name: "get_project_status",
|
|
298
330
|
description:
|
|
299
|
-
"Get
|
|
331
|
+
"Get live deployment state: URL, last deploy time, deploy count, status (live/failed), and deploy source. Call this first to understand what's currently deployed before making changes.",
|
|
300
332
|
inputSchema: {
|
|
301
333
|
type: "object",
|
|
302
334
|
properties: {
|
|
@@ -347,7 +379,7 @@ export function registerTools(server: McpServer, _options: McpServerOptions, deb
|
|
|
347
379
|
{
|
|
348
380
|
name: "tail_logs",
|
|
349
381
|
description:
|
|
350
|
-
"Collect
|
|
382
|
+
"Collect live log events from production. Use after deploying to verify changes work, or to debug errors. Returns JSON log entries with timestamps and messages.",
|
|
351
383
|
inputSchema: {
|
|
352
384
|
type: "object",
|
|
353
385
|
properties: {
|
|
@@ -370,6 +402,27 @@ export function registerTools(server: McpServer, _options: McpServerOptions, deb
|
|
|
370
402
|
},
|
|
371
403
|
},
|
|
372
404
|
},
|
|
405
|
+
{
|
|
406
|
+
name: "rollback_project",
|
|
407
|
+
description:
|
|
408
|
+
"Roll back a managed (jack cloud) project to a previous deployment. " +
|
|
409
|
+
"Defaults to the previous successful deployment if no deployment_id is specified. " +
|
|
410
|
+
"Only rolls back code — database state and secrets are unchanged.",
|
|
411
|
+
inputSchema: {
|
|
412
|
+
type: "object",
|
|
413
|
+
properties: {
|
|
414
|
+
deployment_id: {
|
|
415
|
+
type: "string",
|
|
416
|
+
description:
|
|
417
|
+
"Specific deployment ID to roll back to (defaults to previous successful deployment)",
|
|
418
|
+
},
|
|
419
|
+
project_path: {
|
|
420
|
+
type: "string",
|
|
421
|
+
description: "Path to project directory (defaults to current directory)",
|
|
422
|
+
},
|
|
423
|
+
},
|
|
424
|
+
},
|
|
425
|
+
},
|
|
373
426
|
{
|
|
374
427
|
name: "create_database",
|
|
375
428
|
description:
|
|
@@ -654,13 +707,14 @@ export function registerTools(server: McpServer, _options: McpServerOptions, deb
|
|
|
654
707
|
{
|
|
655
708
|
name: "create_cron",
|
|
656
709
|
description:
|
|
657
|
-
"Create a cron schedule for a managed (Jack Cloud) project. Minimum interval is 15 minutes. The worker must
|
|
710
|
+
"Create a cron schedule for a managed (Jack Cloud) project. Minimum interval is 15 minutes. The worker must handle POST /__scheduled requests — Cloudflare's native scheduled() export does not work with Jack Cloud crons.",
|
|
658
711
|
inputSchema: {
|
|
659
712
|
type: "object",
|
|
660
713
|
properties: {
|
|
661
714
|
expression: {
|
|
662
715
|
type: "string",
|
|
663
|
-
description:
|
|
716
|
+
description:
|
|
717
|
+
"Cron expression (e.g., '0 * * * *' for hourly, '*/15 * * * *' for every 15 min)",
|
|
664
718
|
},
|
|
665
719
|
project_path: {
|
|
666
720
|
type: "string",
|
|
@@ -719,7 +773,8 @@ export function registerTools(server: McpServer, _options: McpServerOptions, deb
|
|
|
719
773
|
trigger_production: {
|
|
720
774
|
type: "boolean",
|
|
721
775
|
default: false,
|
|
722
|
-
description:
|
|
776
|
+
description:
|
|
777
|
+
"Whether to trigger the cron handler on production (requires managed project)",
|
|
723
778
|
},
|
|
724
779
|
},
|
|
725
780
|
required: ["expression"],
|
|
@@ -777,12 +832,13 @@ export function registerTools(server: McpServer, _options: McpServerOptions, deb
|
|
|
777
832
|
|
|
778
833
|
const wrappedDeployProject = withTelemetry(
|
|
779
834
|
"deploy_project",
|
|
780
|
-
async (projectPath?: string) => {
|
|
835
|
+
async (projectPath?: string, message?: string) => {
|
|
781
836
|
const result = await deployProject({
|
|
782
837
|
projectPath,
|
|
783
838
|
interactive: false,
|
|
784
839
|
includeSecrets: false,
|
|
785
840
|
includeSync: false,
|
|
841
|
+
message,
|
|
786
842
|
});
|
|
787
843
|
|
|
788
844
|
// Track business event
|
|
@@ -795,7 +851,7 @@ export function registerTools(server: McpServer, _options: McpServerOptions, deb
|
|
|
795
851
|
{ platform: "mcp" },
|
|
796
852
|
);
|
|
797
853
|
|
|
798
|
-
const result = await wrappedDeployProject(args.project_path);
|
|
854
|
+
const result = await wrappedDeployProject(args.project_path, args.message);
|
|
799
855
|
|
|
800
856
|
return {
|
|
801
857
|
content: [
|
|
@@ -1046,6 +1102,60 @@ export function registerTools(server: McpServer, _options: McpServerOptions, deb
|
|
|
1046
1102
|
};
|
|
1047
1103
|
}
|
|
1048
1104
|
|
|
1105
|
+
case "rollback_project": {
|
|
1106
|
+
const args = RollbackProjectSchema.parse(request.params.arguments ?? {});
|
|
1107
|
+
const projectPath = args.project_path ?? process.cwd();
|
|
1108
|
+
|
|
1109
|
+
const deployMode = await getDeployMode(projectPath);
|
|
1110
|
+
if (deployMode !== "managed") {
|
|
1111
|
+
throw new JackError(
|
|
1112
|
+
JackErrorCode.VALIDATION_ERROR,
|
|
1113
|
+
"Rollback is only available for managed (jack cloud) projects",
|
|
1114
|
+
"For BYOC projects, use wrangler to manage deployments.",
|
|
1115
|
+
);
|
|
1116
|
+
}
|
|
1117
|
+
|
|
1118
|
+
const projectId = await getProjectId(projectPath);
|
|
1119
|
+
if (!projectId) {
|
|
1120
|
+
throw new JackError(
|
|
1121
|
+
JackErrorCode.PROJECT_NOT_FOUND,
|
|
1122
|
+
"Project not found",
|
|
1123
|
+
"Run this from a linked jack cloud project directory (has .jack/project.json).",
|
|
1124
|
+
);
|
|
1125
|
+
}
|
|
1126
|
+
|
|
1127
|
+
// Import rollbackDeployment from control-plane
|
|
1128
|
+
const { rollbackDeployment } = await import("../../lib/control-plane.ts");
|
|
1129
|
+
|
|
1130
|
+
const wrappedRollback = withTelemetry(
|
|
1131
|
+
"rollback_project",
|
|
1132
|
+
async (id: string, deploymentId?: string) => rollbackDeployment(id, deploymentId),
|
|
1133
|
+
{ platform: "mcp" },
|
|
1134
|
+
);
|
|
1135
|
+
|
|
1136
|
+
const result = await wrappedRollback(projectId, args.deployment_id);
|
|
1137
|
+
|
|
1138
|
+
return {
|
|
1139
|
+
content: [
|
|
1140
|
+
{
|
|
1141
|
+
type: "text",
|
|
1142
|
+
text: JSON.stringify(
|
|
1143
|
+
formatSuccessResponse(
|
|
1144
|
+
{
|
|
1145
|
+
...result.deployment,
|
|
1146
|
+
message:
|
|
1147
|
+
"Code rolled back successfully. Database state and secrets are unchanged.",
|
|
1148
|
+
},
|
|
1149
|
+
startTime,
|
|
1150
|
+
),
|
|
1151
|
+
null,
|
|
1152
|
+
2,
|
|
1153
|
+
),
|
|
1154
|
+
},
|
|
1155
|
+
],
|
|
1156
|
+
};
|
|
1157
|
+
}
|
|
1158
|
+
|
|
1049
1159
|
case "create_database": {
|
|
1050
1160
|
const args = CreateDatabaseSchema.parse(request.params.arguments ?? {});
|
|
1051
1161
|
const projectPath = args.project_path ?? process.cwd();
|
|
@@ -1268,7 +1378,13 @@ export function registerTools(server: McpServer, _options: McpServerOptions, deb
|
|
|
1268
1378
|
content: [
|
|
1269
1379
|
{
|
|
1270
1380
|
type: "text",
|
|
1271
|
-
text: JSON.stringify(
|
|
1381
|
+
text: JSON.stringify(
|
|
1382
|
+
formatSuccessResponse(result, startTime, [
|
|
1383
|
+
"Vectorize indexes have eventual consistency. Newly inserted vectors typically take 2-3 minutes to become queryable.",
|
|
1384
|
+
]),
|
|
1385
|
+
null,
|
|
1386
|
+
2,
|
|
1387
|
+
),
|
|
1272
1388
|
},
|
|
1273
1389
|
],
|
|
1274
1390
|
};
|
package/src/mcp/types.ts
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
export interface McpToolResponse<T = unknown> {
|
|
6
6
|
success: boolean;
|
|
7
7
|
data?: T;
|
|
8
|
+
notes?: string[]; // Situational context for AI agents (e.g. eventual consistency caveats)
|
|
8
9
|
error?: {
|
|
9
10
|
code: string; // Machine-readable: 'AUTH_FAILED', 'PROJECT_NOT_FOUND'
|
|
10
11
|
message: string; // Human-readable description
|
package/src/mcp/utils.ts
CHANGED
|
@@ -5,10 +5,11 @@ import { McpErrorCode, type McpToolResponse } from "./types.ts";
|
|
|
5
5
|
/**
|
|
6
6
|
* Format a successful MCP tool response
|
|
7
7
|
*/
|
|
8
|
-
export function formatSuccessResponse<T>(data: T, startTime: number): McpToolResponse<T> {
|
|
8
|
+
export function formatSuccessResponse<T>(data: T, startTime: number, notes?: string[]): McpToolResponse<T> {
|
|
9
9
|
return {
|
|
10
10
|
success: true,
|
|
11
11
|
data,
|
|
12
|
+
...(notes?.length && { notes }),
|
|
12
13
|
meta: {
|
|
13
14
|
duration_ms: Date.now() - startTime,
|
|
14
15
|
jack_version: packageJson.version,
|