@getjack/jack 0.1.2 → 0.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (91) hide show
  1. package/package.json +54 -47
  2. package/src/commands/agents.ts +145 -10
  3. package/src/commands/down.ts +110 -102
  4. package/src/commands/feedback.ts +189 -0
  5. package/src/commands/init.ts +8 -12
  6. package/src/commands/login.ts +88 -0
  7. package/src/commands/logout.ts +14 -0
  8. package/src/commands/logs.ts +21 -0
  9. package/src/commands/mcp.ts +134 -7
  10. package/src/commands/new.ts +43 -17
  11. package/src/commands/open.ts +13 -6
  12. package/src/commands/projects.ts +269 -143
  13. package/src/commands/secrets.ts +413 -0
  14. package/src/commands/services.ts +96 -123
  15. package/src/commands/ship.ts +5 -1
  16. package/src/commands/whoami.ts +31 -0
  17. package/src/index.ts +218 -144
  18. package/src/lib/agent-files.ts +34 -0
  19. package/src/lib/agents.ts +390 -22
  20. package/src/lib/asset-hash.ts +50 -0
  21. package/src/lib/auth/client.ts +115 -0
  22. package/src/lib/auth/constants.ts +5 -0
  23. package/src/lib/auth/guard.ts +57 -0
  24. package/src/lib/auth/index.ts +18 -0
  25. package/src/lib/auth/store.ts +54 -0
  26. package/src/lib/binding-validator.ts +136 -0
  27. package/src/lib/build-helper.ts +211 -0
  28. package/src/lib/cloudflare-api.ts +24 -0
  29. package/src/lib/config.ts +5 -6
  30. package/src/lib/control-plane.ts +295 -0
  31. package/src/lib/debug.ts +3 -1
  32. package/src/lib/deploy-mode.ts +93 -0
  33. package/src/lib/deploy-upload.ts +92 -0
  34. package/src/lib/errors.ts +2 -0
  35. package/src/lib/github.ts +31 -1
  36. package/src/lib/hooks.ts +4 -12
  37. package/src/lib/intent.ts +88 -0
  38. package/src/lib/jsonc.ts +125 -0
  39. package/src/lib/local-paths.test.ts +902 -0
  40. package/src/lib/local-paths.ts +258 -0
  41. package/src/lib/managed-deploy.ts +175 -0
  42. package/src/lib/managed-down.ts +159 -0
  43. package/src/lib/mcp-config.ts +55 -34
  44. package/src/lib/names.ts +9 -29
  45. package/src/lib/project-operations.ts +676 -249
  46. package/src/lib/project-resolver.ts +476 -0
  47. package/src/lib/registry.ts +76 -37
  48. package/src/lib/resources.ts +196 -0
  49. package/src/lib/schema.ts +30 -1
  50. package/src/lib/storage/file-filter.ts +1 -0
  51. package/src/lib/storage/index.ts +5 -1
  52. package/src/lib/telemetry.ts +14 -0
  53. package/src/lib/tty.ts +15 -0
  54. package/src/lib/zip-packager.ts +255 -0
  55. package/src/mcp/resources/index.ts +8 -2
  56. package/src/mcp/server.ts +32 -4
  57. package/src/mcp/tools/index.ts +35 -13
  58. package/src/mcp/types.ts +6 -0
  59. package/src/mcp/utils.ts +1 -1
  60. package/src/templates/index.ts +42 -4
  61. package/src/templates/types.ts +13 -0
  62. package/templates/CLAUDE.md +166 -0
  63. package/templates/api/.jack.json +4 -0
  64. package/templates/api/bun.lock +1 -0
  65. package/templates/api/wrangler.jsonc +5 -0
  66. package/templates/hello/.jack.json +28 -0
  67. package/templates/hello/package.json +10 -0
  68. package/templates/hello/src/index.ts +11 -0
  69. package/templates/hello/tsconfig.json +11 -0
  70. package/templates/hello/wrangler.jsonc +5 -0
  71. package/templates/miniapp/.jack.json +15 -4
  72. package/templates/miniapp/bun.lock +135 -40
  73. package/templates/miniapp/index.html +1 -0
  74. package/templates/miniapp/package.json +3 -1
  75. package/templates/miniapp/public/.well-known/farcaster.json +7 -5
  76. package/templates/miniapp/public/icon.png +0 -0
  77. package/templates/miniapp/public/og.png +0 -0
  78. package/templates/miniapp/schema.sql +8 -0
  79. package/templates/miniapp/src/App.tsx +254 -3
  80. package/templates/miniapp/src/components/ShareSheet.tsx +147 -0
  81. package/templates/miniapp/src/hooks/useAI.ts +35 -0
  82. package/templates/miniapp/src/hooks/useGuestbook.ts +11 -1
  83. package/templates/miniapp/src/hooks/useShare.ts +76 -0
  84. package/templates/miniapp/src/index.css +15 -0
  85. package/templates/miniapp/src/lib/api.ts +2 -1
  86. package/templates/miniapp/src/worker.ts +515 -1
  87. package/templates/miniapp/wrangler.jsonc +15 -3
  88. package/LICENSE +0 -190
  89. package/README.md +0 -55
  90. package/src/commands/cloud.ts +0 -230
  91. package/templates/api/wrangler.toml +0 -3
package/src/index.ts CHANGED
@@ -2,6 +2,8 @@
2
2
  import meow from "meow";
3
3
  import pkg from "../package.json";
4
4
  import { enableDebug } from "./lib/debug.ts";
5
+ import { isJackError } from "./lib/errors.ts";
6
+ import { info, error as printError } from "./lib/output.ts";
5
7
  import { identify, shutdown, withTelemetry } from "./lib/telemetry.ts";
6
8
 
7
9
  const cli = meow(
@@ -11,41 +13,37 @@ const cli = meow(
11
13
  Usage
12
14
  $ jack <command> [options]
13
15
 
14
- Commands
15
- init Jack in (one-time setup)
16
+ Getting Started
17
+ init Set up jack (run once)
16
18
  new [name] Create and deploy a project
17
- ship Push to production
19
+ vibe "<phrase>" Create from an idea
20
+ ship Push changes to production
21
+
22
+ Projects
23
+ open [name] Open in browser
18
24
  logs Stream live logs
19
- agents Manage AI agent templates
20
- sync Sync to cloud storage
21
- clone <project> Pull project from cloud
22
- cloud Manage cloud storage
23
25
  down [name] Undeploy from cloud
24
- open [name] Open project in browser
25
- projects Manage project registry
26
- services Manage project services
27
- mcp serve Start MCP server for AI agents
28
- telemetry Manage anonymous usage data
29
- about The story behind jack
26
+ ls List all projects
27
+ info [name] Show project details
28
+
29
+ Cloud & Sync
30
+ clone <project> Pull from cloud backup
31
+ sync Sync to cloud storage
30
32
 
31
- Aliases
32
- ls List all projects (jack projects list)
33
- info [name] Show project details (jack projects info)
33
+ Account
34
+ login Sign in
35
+ logout Sign out
36
+ whoami Show current user
34
37
 
35
- Options
36
- -t, --template Template: miniapp (default), api, or user/repo
37
- -d, --debug Show timing and debug logs
38
- --verbose Show detailed output
39
- --dry-run Preview changes without applying
40
- --force Force operation
41
- --as <name> Clone to different directory name
42
- --dash Open cloud dashboard
43
- --logs Open logs page
44
- --yes Skip confirmation prompts
45
- --local Filter by local projects
46
- --deployed Filter by deployed projects
47
- --cloud Filter by cloud-backed projects
48
- --skip-mcp Skip MCP config installation during init
38
+ Advanced
39
+ agents Manage AI agent configs
40
+ secrets Manage project secrets
41
+ services Manage databases
42
+ mcp MCP server for AI agents
43
+ telemetry Usage data settings
44
+ feedback Share feedback or report issues
45
+
46
+ Run 'jack <command> --help' for command-specific options.
49
47
 
50
48
  Examples
51
49
  $ jack init Set up once
@@ -59,6 +57,10 @@ const cli = meow(
59
57
  type: "string",
60
58
  shortFlag: "t",
61
59
  },
60
+ message: {
61
+ type: "string",
62
+ shortFlag: "m",
63
+ },
62
64
  debug: {
63
65
  type: "boolean",
64
66
  shortFlag: "d",
@@ -111,6 +113,18 @@ const cli = meow(
111
113
  type: "boolean",
112
114
  default: false,
113
115
  },
116
+ managed: {
117
+ type: "boolean",
118
+ default: false,
119
+ },
120
+ byo: {
121
+ type: "boolean",
122
+ default: false,
123
+ },
124
+ ci: {
125
+ type: "boolean",
126
+ default: false,
127
+ },
114
128
  },
115
129
  },
116
130
  );
@@ -131,122 +145,182 @@ identify({
131
145
  is_ci: !!process.env.CI,
132
146
  });
133
147
 
134
- switch (command) {
135
- case "init": {
136
- const { default: init } = await import("./commands/init.ts");
137
- await withTelemetry("init", init)({ skipMcp: cli.flags.skipMcp });
138
- break;
139
- }
140
- case "new":
141
- case "in": {
142
- const { default: newProject } = await import("./commands/new.ts");
143
- await withTelemetry("new", newProject)(args[0], { template: cli.flags.template });
144
- break;
145
- }
146
- case "ship":
147
- case "push":
148
- case "up":
149
- case "deploy": {
150
- const { default: ship } = await import("./commands/ship.ts");
151
- await withTelemetry("ship", ship)();
152
- break;
153
- }
154
- case "logs":
155
- case "tail": {
156
- const { default: logs } = await import("./commands/logs.ts");
157
- await withTelemetry("logs", logs)();
158
- break;
159
- }
160
- case "agents": {
161
- const { default: agents } = await import("./commands/agents.ts");
162
- await withTelemetry("agents", agents)(args[0], args.slice(1));
163
- break;
164
- }
165
- case "sync": {
166
- const { default: sync } = await import("./commands/sync.ts");
167
- await withTelemetry(
168
- "sync",
169
- sync,
170
- )({
171
- verbose: cli.flags.verbose,
172
- dryRun: cli.flags.dryRun,
173
- force: cli.flags.force,
174
- });
175
- break;
176
- }
177
- case "clone": {
178
- const { default: clone } = await import("./commands/clone.ts");
179
- await withTelemetry("clone", clone)(args[0], { as: cli.flags.as });
180
- break;
181
- }
182
- case "cloud": {
183
- const { default: cloud } = await import("./commands/cloud.ts");
184
- await withTelemetry("cloud", cloud)(args[0], args.slice(1));
185
- break;
186
- }
187
- case "telemetry": {
188
- const { default: telemetry } = await import("./commands/telemetry.ts");
189
- await telemetry(args[0]);
190
- break;
191
- }
192
- case "about": {
193
- const { default: about } = await import("./commands/about.ts");
194
- await withTelemetry("about", about)();
195
- break;
196
- }
197
- case "hack": {
198
- const { default: hack } = await import("./commands/hack.ts");
199
- await withTelemetry("hack", hack)();
200
- break;
201
- }
202
- case "down": {
203
- const { default: down } = await import("./commands/down.ts");
204
- await withTelemetry("down", down)(args[0], { force: cli.flags.force });
205
- break;
206
- }
207
- case "open": {
208
- const { default: open } = await import("./commands/open.ts");
209
- await withTelemetry("open", open)(args[0], { dash: cli.flags.dash, logs: cli.flags.logs });
210
- break;
211
- }
212
- case "projects": {
213
- const { default: projects } = await import("./commands/projects.ts");
214
- const projectArgs = [...args.slice(1)];
215
- if (cli.flags.local) projectArgs.push("--local");
216
- if (cli.flags.deployed) projectArgs.push("--deployed");
217
- if (cli.flags.cloud) projectArgs.push("--cloud");
218
- await withTelemetry("projects", projects)(args[0], projectArgs);
219
- break;
220
- }
221
- case "services": {
222
- const { default: services } = await import("./commands/services.ts");
223
- await withTelemetry("services", services)(args[0], args.slice(1), {
224
- project: cli.flags.project,
225
- });
226
- break;
227
- }
228
- case "mcp": {
229
- const { default: mcp } = await import("./commands/mcp.ts");
230
- // Note: Don't use withTelemetry wrapper for MCP serve - it runs indefinitely
231
- await mcp(args[0], { project: cli.flags.project });
232
- break;
233
- }
234
- case "ls": {
235
- const { default: projects } = await import("./commands/projects.ts");
236
- const lsArgs: string[] = [];
237
- if (cli.flags.local) lsArgs.push("--local");
238
- if (cli.flags.deployed) lsArgs.push("--deployed");
239
- if (cli.flags.cloud) lsArgs.push("--cloud");
240
- await withTelemetry("projects", projects)("list", lsArgs);
241
- break;
148
+ try {
149
+ switch (command) {
150
+ case "init": {
151
+ const { default: init } = await import("./commands/init.ts");
152
+ await withTelemetry("init", init)({ skipMcp: cli.flags.skipMcp });
153
+ break;
154
+ }
155
+ case "new":
156
+ case "in": {
157
+ const { default: newProject } = await import("./commands/new.ts");
158
+ await withTelemetry("new", newProject)(args[0], {
159
+ template: cli.flags.template,
160
+ intent: cli.flags.message,
161
+ managed: cli.flags.managed,
162
+ byo: cli.flags.byo,
163
+ ci: cli.flags.ci,
164
+ });
165
+ break;
166
+ }
167
+ case "vibe": {
168
+ const { default: newProject } = await import("./commands/new.ts");
169
+ // vibe always treats first arg as intent phrase
170
+ await withTelemetry("vibe", newProject)(undefined, {
171
+ template: cli.flags.template,
172
+ intent: args[0],
173
+ });
174
+ break;
175
+ }
176
+ case "ship":
177
+ case "push":
178
+ case "up":
179
+ case "deploy": {
180
+ const { default: ship } = await import("./commands/ship.ts");
181
+ await withTelemetry(
182
+ "ship",
183
+ ship,
184
+ )({
185
+ managed: cli.flags.managed,
186
+ byo: cli.flags.byo,
187
+ });
188
+ break;
189
+ }
190
+ case "logs":
191
+ case "tail": {
192
+ const { default: logs } = await import("./commands/logs.ts");
193
+ await withTelemetry("logs", logs)();
194
+ break;
195
+ }
196
+ case "agents": {
197
+ const { default: agents } = await import("./commands/agents.ts");
198
+ await withTelemetry("agents", agents)(args[0], args.slice(1), {
199
+ project: cli.flags.project,
200
+ });
201
+ break;
202
+ }
203
+ case "sync": {
204
+ const { default: sync } = await import("./commands/sync.ts");
205
+ await withTelemetry(
206
+ "sync",
207
+ sync,
208
+ )({
209
+ verbose: cli.flags.verbose,
210
+ dryRun: cli.flags.dryRun,
211
+ force: cli.flags.force,
212
+ });
213
+ break;
214
+ }
215
+ case "clone": {
216
+ const { default: clone } = await import("./commands/clone.ts");
217
+ await withTelemetry("clone", clone)(args[0], { as: cli.flags.as });
218
+ break;
219
+ }
220
+ case "telemetry": {
221
+ const { default: telemetry } = await import("./commands/telemetry.ts");
222
+ await telemetry(args[0]);
223
+ break;
224
+ }
225
+ case "about": {
226
+ const { default: about } = await import("./commands/about.ts");
227
+ await withTelemetry("about", about)();
228
+ break;
229
+ }
230
+ case "hack": {
231
+ const { default: hack } = await import("./commands/hack.ts");
232
+ await withTelemetry("hack", hack)();
233
+ break;
234
+ }
235
+ case "down": {
236
+ const { default: down } = await import("./commands/down.ts");
237
+ await withTelemetry("down", down)(args[0], { force: cli.flags.force });
238
+ break;
239
+ }
240
+ case "open": {
241
+ const { default: open } = await import("./commands/open.ts");
242
+ await withTelemetry("open", open)(args[0], { dash: cli.flags.dash, logs: cli.flags.logs });
243
+ break;
244
+ }
245
+ case "projects": {
246
+ const { default: projects } = await import("./commands/projects.ts");
247
+ const projectArgs = [...args.slice(1)];
248
+ if (cli.flags.local) projectArgs.push("--local");
249
+ if (cli.flags.deployed) projectArgs.push("--deployed");
250
+ if (cli.flags.cloud) projectArgs.push("--cloud");
251
+ if (cli.flags.yes) projectArgs.push("--yes");
252
+ if (cli.flags.force) projectArgs.push("--force");
253
+ await withTelemetry("projects", projects)(args[0], projectArgs);
254
+ break;
255
+ }
256
+ case "services": {
257
+ const { default: services } = await import("./commands/services.ts");
258
+ await withTelemetry("services", services)(args[0], args.slice(1), {
259
+ project: cli.flags.project,
260
+ });
261
+ break;
262
+ }
263
+ case "secrets": {
264
+ const { default: secrets } = await import("./commands/secrets.ts");
265
+ await withTelemetry("secrets", secrets)(args[0], args.slice(1), {
266
+ project: cli.flags.project,
267
+ });
268
+ break;
269
+ }
270
+ case "mcp": {
271
+ const { default: mcp } = await import("./commands/mcp.ts");
272
+ // Note: Don't use withTelemetry wrapper for MCP serve - it runs indefinitely
273
+ await mcp(args[0], { project: cli.flags.project, debug: cli.flags.debug });
274
+ break;
275
+ }
276
+ case "ls": {
277
+ const { default: projects } = await import("./commands/projects.ts");
278
+ const lsArgs: string[] = [];
279
+ if (cli.flags.local) lsArgs.push("--local");
280
+ if (cli.flags.deployed) lsArgs.push("--deployed");
281
+ if (cli.flags.cloud) lsArgs.push("--cloud");
282
+ await withTelemetry("projects", projects)("list", lsArgs);
283
+ break;
284
+ }
285
+ case "info": {
286
+ const { default: projects } = await import("./commands/projects.ts");
287
+ await withTelemetry("projects", projects)("info", args);
288
+ break;
289
+ }
290
+ case "login": {
291
+ const { default: login } = await import("./commands/login.ts");
292
+ await withTelemetry("login", login)();
293
+ break;
294
+ }
295
+ case "logout": {
296
+ const { default: logout } = await import("./commands/logout.ts");
297
+ await withTelemetry("logout", logout)();
298
+ break;
299
+ }
300
+ case "whoami": {
301
+ const { default: whoami } = await import("./commands/whoami.ts");
302
+ await withTelemetry("whoami", whoami)();
303
+ break;
304
+ }
305
+ case "feedback": {
306
+ const { default: feedback } = await import("./commands/feedback.ts");
307
+ await withTelemetry("feedback", feedback)();
308
+ break;
309
+ }
310
+ default:
311
+ cli.showHelp(command ? 1 : 0);
242
312
  }
243
- case "info": {
244
- const { default: projects } = await import("./commands/projects.ts");
245
- await withTelemetry("projects", projects)("info", args);
246
- break;
313
+ } catch (err) {
314
+ if (isJackError(err)) {
315
+ printError(err.message);
316
+ if (err.suggestion) {
317
+ info(err.suggestion);
318
+ }
319
+ await shutdown();
320
+ process.exit(err.meta?.exitCode ?? 1);
247
321
  }
248
- default:
249
- cli.showHelp(command ? 1 : 0);
322
+ // Re-throw non-JackError errors for stack trace
323
+ throw err;
250
324
  }
251
325
 
252
326
  await shutdown();
@@ -102,3 +102,37 @@ export async function generateAgentFiles(
102
102
  }
103
103
  }
104
104
  }
105
+
106
+ /**
107
+ * Regenerate agent context files, overwriting existing files
108
+ * Used by `jack agents refresh` to update files from template
109
+ */
110
+ export async function regenerateAgentFiles(
111
+ projectDir: string,
112
+ projectName: string,
113
+ template: Template,
114
+ agents: Array<{ id: string; config: AgentConfig; definition: AgentDefinition }>,
115
+ ): Promise<string[]> {
116
+ const writtenSharedFiles = new Set<string>();
117
+ const updatedFiles: string[] = [];
118
+
119
+ for (const { definition } of agents) {
120
+ for (const file of definition.projectFiles) {
121
+ // Skip shared files if already written
122
+ if (file.shared && writtenSharedFiles.has(file.path)) {
123
+ continue;
124
+ }
125
+
126
+ const filePath = join(projectDir, file.path);
127
+ const content = generateFileContent(file.template, projectName, template);
128
+ await Bun.write(filePath, content);
129
+ updatedFiles.push(file.path);
130
+
131
+ if (file.shared) {
132
+ writtenSharedFiles.add(file.path);
133
+ }
134
+ }
135
+ }
136
+
137
+ return updatedFiles;
138
+ }