@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.
Files changed (197) hide show
  1. package/package.json +1 -1
  2. package/src/commands/deploys.ts +95 -0
  3. package/src/commands/link.ts +8 -0
  4. package/src/commands/mcp.ts +179 -4
  5. package/src/commands/rollback.ts +53 -0
  6. package/src/commands/services.ts +100 -20
  7. package/src/commands/ship.ts +30 -3
  8. package/src/commands/tokens.ts +134 -0
  9. package/src/commands/whoami.ts +51 -12
  10. package/src/index.ts +33 -0
  11. package/src/lib/agent-files.ts +54 -4
  12. package/src/lib/agent-integration.ts +4 -166
  13. package/src/lib/auth/client.ts +11 -1
  14. package/src/lib/auth/guard.ts +1 -1
  15. package/src/lib/auth/store.ts +3 -0
  16. package/src/lib/claude-hooks-installer.ts +55 -0
  17. package/src/lib/control-plane.ts +78 -40
  18. package/src/lib/debug.ts +2 -1
  19. package/src/lib/deploy-upload.ts +6 -0
  20. package/src/lib/hooks.ts +3 -1
  21. package/src/lib/managed-deploy.ts +12 -9
  22. package/src/lib/project-link.ts +6 -0
  23. package/src/lib/project-operations.ts +68 -22
  24. package/src/lib/services/token-operations.ts +84 -0
  25. package/src/lib/telemetry.ts +6 -0
  26. package/src/mcp/README.md +1 -1
  27. package/src/mcp/resources/index.ts +174 -16
  28. package/src/mcp/server.ts +23 -0
  29. package/src/mcp/tools/index.ts +133 -17
  30. package/src/mcp/types.ts +1 -0
  31. package/src/mcp/utils.ts +2 -1
  32. package/src/templates/index.ts +25 -73
  33. package/templates/CLAUDE.md +41 -0
  34. package/templates/ai-chat/.jack.json +10 -5
  35. package/templates/ai-chat/bun.lock +50 -1
  36. package/templates/ai-chat/package.json +5 -0
  37. package/templates/ai-chat/public/app.js +73 -0
  38. package/templates/ai-chat/public/index.html +14 -197
  39. package/templates/ai-chat/schema.sql +14 -0
  40. package/templates/ai-chat/src/index.ts +86 -102
  41. package/templates/ai-chat/wrangler.jsonc +8 -1
  42. package/templates/cron/.jack.json +66 -0
  43. package/templates/cron/bun.lock +23 -0
  44. package/templates/cron/package.json +16 -0
  45. package/templates/cron/schema.sql +24 -0
  46. package/templates/cron/src/index.ts +117 -0
  47. package/templates/cron/src/jobs.ts +139 -0
  48. package/templates/cron/src/webhooks.ts +95 -0
  49. package/templates/cron/tsconfig.json +17 -0
  50. package/templates/cron/wrangler.jsonc +11 -0
  51. package/templates/miniapp/.jack.json +1 -1
  52. package/templates/nextjs/.jack.json +1 -1
  53. package/templates/nextjs-auth/.jack.json +44 -0
  54. package/templates/nextjs-auth/app/api/auth/[...all]/route.ts +11 -0
  55. package/templates/nextjs-auth/app/dashboard/loading.tsx +53 -0
  56. package/templates/nextjs-auth/app/dashboard/page.tsx +73 -0
  57. package/templates/nextjs-auth/app/error.tsx +44 -0
  58. package/templates/nextjs-auth/app/globals.css +1 -0
  59. package/templates/nextjs-auth/app/health/route.ts +3 -0
  60. package/templates/nextjs-auth/app/layout.tsx +24 -0
  61. package/templates/nextjs-auth/app/login/page.tsx +10 -0
  62. package/templates/nextjs-auth/app/page.tsx +86 -0
  63. package/templates/nextjs-auth/app/signup/page.tsx +10 -0
  64. package/templates/nextjs-auth/bun.lock +1065 -0
  65. package/templates/nextjs-auth/cloudflare-env.d.ts +8 -0
  66. package/templates/nextjs-auth/components/auth-form.tsx +191 -0
  67. package/templates/nextjs-auth/components/header.tsx +50 -0
  68. package/templates/nextjs-auth/components/user-menu.tsx +23 -0
  69. package/templates/nextjs-auth/lib/auth-client.ts +3 -0
  70. package/templates/nextjs-auth/lib/auth.ts +43 -0
  71. package/templates/nextjs-auth/lib/utils.ts +6 -0
  72. package/templates/nextjs-auth/middleware.ts +33 -0
  73. package/templates/nextjs-auth/next.config.ts +8 -0
  74. package/templates/nextjs-auth/open-next.config.ts +6 -0
  75. package/templates/nextjs-auth/package.json +33 -0
  76. package/templates/nextjs-auth/postcss.config.mjs +8 -0
  77. package/templates/nextjs-auth/schema.sql +49 -0
  78. package/templates/nextjs-auth/tsconfig.json +28 -0
  79. package/templates/nextjs-auth/wrangler.jsonc +23 -0
  80. package/templates/nextjs-clerk/.jack.json +54 -0
  81. package/templates/nextjs-clerk/app/dashboard/page.tsx +69 -0
  82. package/templates/nextjs-clerk/app/globals.css +1 -0
  83. package/templates/nextjs-clerk/app/health/route.ts +3 -0
  84. package/templates/nextjs-clerk/app/layout.tsx +26 -0
  85. package/templates/nextjs-clerk/app/page.tsx +86 -0
  86. package/templates/nextjs-clerk/app/sign-in/[[...sign-in]]/page.tsx +9 -0
  87. package/templates/nextjs-clerk/app/sign-up/[[...sign-up]]/page.tsx +9 -0
  88. package/templates/nextjs-clerk/bun.lock +1055 -0
  89. package/templates/nextjs-clerk/cloudflare-env.d.ts +3 -0
  90. package/templates/nextjs-clerk/components/header.tsx +40 -0
  91. package/templates/nextjs-clerk/lib/utils.ts +6 -0
  92. package/templates/nextjs-clerk/middleware.ts +18 -0
  93. package/templates/nextjs-clerk/next.config.ts +8 -0
  94. package/templates/nextjs-clerk/open-next.config.ts +6 -0
  95. package/templates/nextjs-clerk/package.json +31 -0
  96. package/templates/nextjs-clerk/postcss.config.mjs +8 -0
  97. package/templates/nextjs-clerk/tsconfig.json +28 -0
  98. package/templates/nextjs-clerk/wrangler.jsonc +17 -0
  99. package/templates/nextjs-shadcn/.jack.json +34 -0
  100. package/templates/nextjs-shadcn/app/dashboard/data.json +614 -0
  101. package/templates/nextjs-shadcn/app/dashboard/page.tsx +55 -0
  102. package/templates/nextjs-shadcn/app/globals.css +126 -0
  103. package/templates/nextjs-shadcn/app/health/route.ts +3 -0
  104. package/templates/nextjs-shadcn/app/layout.tsx +24 -0
  105. package/templates/nextjs-shadcn/app/login/page.tsx +19 -0
  106. package/templates/nextjs-shadcn/app/page.tsx +180 -0
  107. package/templates/nextjs-shadcn/app/showcase.tsx +1262 -0
  108. package/templates/nextjs-shadcn/bun.lock +1789 -0
  109. package/templates/nextjs-shadcn/cloudflare-env.d.ts +4 -0
  110. package/templates/nextjs-shadcn/components/app-sidebar.tsx +175 -0
  111. package/templates/nextjs-shadcn/components/chart-area-interactive.tsx +291 -0
  112. package/templates/nextjs-shadcn/components/data-table.tsx +807 -0
  113. package/templates/nextjs-shadcn/components/login-form.tsx +95 -0
  114. package/templates/nextjs-shadcn/components/nav-documents.tsx +92 -0
  115. package/templates/nextjs-shadcn/components/nav-main.tsx +73 -0
  116. package/templates/nextjs-shadcn/components/nav-projects.tsx +89 -0
  117. package/templates/nextjs-shadcn/components/nav-secondary.tsx +42 -0
  118. package/templates/nextjs-shadcn/components/nav-user.tsx +114 -0
  119. package/templates/nextjs-shadcn/components/section-cards.tsx +102 -0
  120. package/templates/nextjs-shadcn/components/site-header.tsx +30 -0
  121. package/templates/nextjs-shadcn/components/team-switcher.tsx +91 -0
  122. package/templates/nextjs-shadcn/components/ui/accordion.tsx +66 -0
  123. package/templates/nextjs-shadcn/components/ui/alert-dialog.tsx +196 -0
  124. package/templates/nextjs-shadcn/components/ui/alert.tsx +66 -0
  125. package/templates/nextjs-shadcn/components/ui/aspect-ratio.tsx +11 -0
  126. package/templates/nextjs-shadcn/components/ui/avatar.tsx +109 -0
  127. package/templates/nextjs-shadcn/components/ui/badge.tsx +48 -0
  128. package/templates/nextjs-shadcn/components/ui/breadcrumb.tsx +109 -0
  129. package/templates/nextjs-shadcn/components/ui/button-group.tsx +83 -0
  130. package/templates/nextjs-shadcn/components/ui/button.tsx +64 -0
  131. package/templates/nextjs-shadcn/components/ui/calendar.tsx +220 -0
  132. package/templates/nextjs-shadcn/components/ui/card.tsx +92 -0
  133. package/templates/nextjs-shadcn/components/ui/carousel.tsx +241 -0
  134. package/templates/nextjs-shadcn/components/ui/chart.tsx +357 -0
  135. package/templates/nextjs-shadcn/components/ui/checkbox.tsx +32 -0
  136. package/templates/nextjs-shadcn/components/ui/collapsible.tsx +33 -0
  137. package/templates/nextjs-shadcn/components/ui/combobox.tsx +310 -0
  138. package/templates/nextjs-shadcn/components/ui/command.tsx +184 -0
  139. package/templates/nextjs-shadcn/components/ui/context-menu.tsx +252 -0
  140. package/templates/nextjs-shadcn/components/ui/dialog.tsx +158 -0
  141. package/templates/nextjs-shadcn/components/ui/direction.tsx +22 -0
  142. package/templates/nextjs-shadcn/components/ui/drawer.tsx +135 -0
  143. package/templates/nextjs-shadcn/components/ui/dropdown-menu.tsx +257 -0
  144. package/templates/nextjs-shadcn/components/ui/empty.tsx +104 -0
  145. package/templates/nextjs-shadcn/components/ui/field.tsx +248 -0
  146. package/templates/nextjs-shadcn/components/ui/form.tsx +167 -0
  147. package/templates/nextjs-shadcn/components/ui/hover-card.tsx +44 -0
  148. package/templates/nextjs-shadcn/components/ui/input-group.tsx +170 -0
  149. package/templates/nextjs-shadcn/components/ui/input-otp.tsx +77 -0
  150. package/templates/nextjs-shadcn/components/ui/input.tsx +21 -0
  151. package/templates/nextjs-shadcn/components/ui/item.tsx +193 -0
  152. package/templates/nextjs-shadcn/components/ui/kbd.tsx +28 -0
  153. package/templates/nextjs-shadcn/components/ui/label.tsx +24 -0
  154. package/templates/nextjs-shadcn/components/ui/menubar.tsx +276 -0
  155. package/templates/nextjs-shadcn/components/ui/native-select.tsx +53 -0
  156. package/templates/nextjs-shadcn/components/ui/navigation-menu.tsx +168 -0
  157. package/templates/nextjs-shadcn/components/ui/pagination.tsx +127 -0
  158. package/templates/nextjs-shadcn/components/ui/popover.tsx +89 -0
  159. package/templates/nextjs-shadcn/components/ui/progress.tsx +31 -0
  160. package/templates/nextjs-shadcn/components/ui/radio-group.tsx +45 -0
  161. package/templates/nextjs-shadcn/components/ui/resizable.tsx +53 -0
  162. package/templates/nextjs-shadcn/components/ui/scroll-area.tsx +58 -0
  163. package/templates/nextjs-shadcn/components/ui/select.tsx +190 -0
  164. package/templates/nextjs-shadcn/components/ui/separator.tsx +28 -0
  165. package/templates/nextjs-shadcn/components/ui/sheet.tsx +143 -0
  166. package/templates/nextjs-shadcn/components/ui/sidebar.tsx +726 -0
  167. package/templates/nextjs-shadcn/components/ui/skeleton.tsx +13 -0
  168. package/templates/nextjs-shadcn/components/ui/slider.tsx +63 -0
  169. package/templates/nextjs-shadcn/components/ui/sonner.tsx +40 -0
  170. package/templates/nextjs-shadcn/components/ui/spinner.tsx +16 -0
  171. package/templates/nextjs-shadcn/components/ui/switch.tsx +35 -0
  172. package/templates/nextjs-shadcn/components/ui/table.tsx +116 -0
  173. package/templates/nextjs-shadcn/components/ui/tabs.tsx +91 -0
  174. package/templates/nextjs-shadcn/components/ui/textarea.tsx +18 -0
  175. package/templates/nextjs-shadcn/components/ui/toggle-group.tsx +83 -0
  176. package/templates/nextjs-shadcn/components/ui/toggle.tsx +47 -0
  177. package/templates/nextjs-shadcn/components/ui/tooltip.tsx +57 -0
  178. package/templates/nextjs-shadcn/components.json +23 -0
  179. package/templates/nextjs-shadcn/hooks/use-mobile.ts +19 -0
  180. package/templates/nextjs-shadcn/lib/utils.ts +6 -0
  181. package/templates/nextjs-shadcn/next-env.d.ts +6 -0
  182. package/templates/nextjs-shadcn/next.config.ts +8 -0
  183. package/templates/nextjs-shadcn/open-next.config.ts +6 -0
  184. package/templates/nextjs-shadcn/package.json +55 -0
  185. package/templates/nextjs-shadcn/postcss.config.mjs +8 -0
  186. package/templates/nextjs-shadcn/tsconfig.json +28 -0
  187. package/templates/nextjs-shadcn/wrangler.jsonc +23 -0
  188. package/templates/resend/.jack.json +64 -0
  189. package/templates/resend/bun.lock +23 -0
  190. package/templates/resend/package.json +16 -0
  191. package/templates/resend/schema.sql +13 -0
  192. package/templates/resend/src/email.ts +165 -0
  193. package/templates/resend/src/index.ts +108 -0
  194. package/templates/resend/tsconfig.json +17 -0
  195. package/templates/resend/wrangler.jsonc +11 -0
  196. package/templates/saas/.jack.json +1 -1
  197. 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 for JACK.md in the project root for project-specific instructions.
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");
@@ -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.string().optional().describe("Template to use (e.g., 'miniapp', 'api')"),
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.string().describe("Cron expression (e.g., '0 * * * *' for hourly, '*/15 * * * *' for every 15 min)"),
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 Cloudflare Workers project from a template. Automatically installs dependencies, deploys to Cloudflare, and registers the project.",
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: "Template to use (e.g., 'miniapp', 'api')",
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 to Cloudflare Workers. Builds the project if needed and pushes to production.",
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 detailed status information for a specific project, including deployment status, local path, and backup status.",
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 a short sample of live log events (JSON) from a managed (jack cloud) project. Useful for agentic debugging.",
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 have a scheduled() handler or POST /__scheduled route.",
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: "Cron expression (e.g., '0 * * * *' for hourly, '*/15 * * * *' for every 15 min)",
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: "Whether to trigger the cron handler on production (requires managed project)",
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(formatSuccessResponse(result, startTime), null, 2),
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,