@getjack/jack 0.1.6 → 0.1.7

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.
@@ -1,28 +1,28 @@
1
1
  {
2
- "name": "nextjs",
3
- "description": "Next.js App (SSR on Cloudflare)",
4
- "secrets": [],
5
- "capabilities": [],
6
- "intent": {
7
- "keywords": ["next", "nextjs", "react", "ssr", "full-stack", "server components", "rsc"],
8
- "examples": ["next.js app", "server-rendered react", "react ssr"]
9
- },
10
- "agentContext": {
11
- "summary": "A Next.js app deployed with jack. Supports SSR, SSG, and React Server Components.",
12
- "full_text": "## Project Structure\n\n- `app/` - Next.js App Router pages and layouts\n- `public/` - Static assets\n- `open-next.config.ts` - OpenNext configuration\n- `wrangler.jsonc` - Worker configuration\n\n## Commands\n\n- `bun run dev` - Local development\n- `jack ship` - Deploy to production\n- `bun run preview` - Preview production build locally\n\n## Conventions\n\n- Uses App Router (not Pages Router)\n- SSR and SSG work out of the box\n- Server Components supported\n\n## Resources\n\n- [OpenNext Docs](https://opennext.js.org/cloudflare)\n- [Next.js App Router](https://nextjs.org/docs/app)"
13
- },
14
- "hooks": {
15
- "postDeploy": [
16
- {
17
- "action": "clipboard",
18
- "text": "{{url}}",
19
- "message": "Deploy URL copied to clipboard"
20
- },
21
- {
22
- "action": "box",
23
- "title": "Deployed: {{name}}",
24
- "lines": ["URL: {{url}}", "", "Next.js app is live!"]
25
- }
26
- ]
27
- }
2
+ "name": "nextjs",
3
+ "description": "Next.js App (SSR on Cloudflare)",
4
+ "secrets": [],
5
+ "capabilities": [],
6
+ "intent": {
7
+ "keywords": ["next", "nextjs", "react", "ssr", "full-stack", "server components", "rsc"],
8
+ "examples": ["next.js app", "server-rendered react", "react ssr"]
9
+ },
10
+ "agentContext": {
11
+ "summary": "A Next.js app deployed with jack. Supports SSR, SSG, and React Server Components.",
12
+ "full_text": "## Project Structure\n\n- `app/` - Next.js App Router pages and layouts\n- `public/` - Static assets\n- `open-next.config.ts` - OpenNext configuration\n- `wrangler.jsonc` - Worker configuration\n\n## Commands\n\n- `bun run dev` - Local development\n- `jack ship` - Deploy to production\n- `bun run preview` - Preview production build locally\n\n## Conventions\n\n- Uses App Router (not Pages Router)\n- SSR and SSG work out of the box\n- Server Components supported\n\n## Resources\n\n- [OpenNext Docs](https://opennext.js.org/cloudflare)\n- [Next.js App Router](https://nextjs.org/docs/app)"
13
+ },
14
+ "hooks": {
15
+ "postDeploy": [
16
+ {
17
+ "action": "clipboard",
18
+ "text": "{{url}}",
19
+ "message": "Deploy URL copied to clipboard"
20
+ },
21
+ {
22
+ "action": "box",
23
+ "title": "Deployed: {{name}}",
24
+ "lines": ["URL: {{url}}", "", "Next.js app is live!"]
25
+ }
26
+ ]
27
+ }
28
28
  }
@@ -1,9 +1,9 @@
1
1
  * {
2
- box-sizing: border-box;
3
- margin: 0;
4
- padding: 0;
2
+ box-sizing: border-box;
3
+ margin: 0;
4
+ padding: 0;
5
5
  }
6
6
 
7
7
  body {
8
- font-family: system-ui, -apple-system, sans-serif;
8
+ font-family: system-ui, -apple-system, sans-serif;
9
9
  }
@@ -1,19 +1,19 @@
1
- import type { Metadata } from 'next';
2
- import './globals.css';
1
+ import type { Metadata } from "next";
2
+ import "./globals.css";
3
3
 
4
4
  export const metadata: Metadata = {
5
- title: 'jack-template',
6
- description: 'Next.js app built with jack',
5
+ title: "jack-template",
6
+ description: "Next.js app built with jack",
7
7
  };
8
8
 
9
9
  export default function RootLayout({
10
- children,
10
+ children,
11
11
  }: {
12
- children: React.ReactNode;
12
+ children: React.ReactNode;
13
13
  }) {
14
- return (
15
- <html lang="en">
16
- <body>{children}</body>
17
- </html>
18
- );
14
+ return (
15
+ <html lang="en">
16
+ <body>{children}</body>
17
+ </html>
18
+ );
19
19
  }
@@ -1,8 +1,10 @@
1
1
  export default function Home() {
2
- return (
3
- <main style={{ padding: '2rem', fontFamily: 'system-ui' }}>
4
- <h1>jack-template</h1>
5
- <p>Ship it with <code>jack ship</code></p>
6
- </main>
7
- );
2
+ return (
3
+ <main style={{ padding: "2rem", fontFamily: "system-ui" }}>
4
+ <h1>jack-template</h1>
5
+ <p>
6
+ Ship it with <code>jack ship</code>
7
+ </p>
8
+ </main>
9
+ );
8
10
  }
@@ -1,3 +1,3 @@
1
1
  interface CloudflareEnv {
2
- ASSETS: Fetcher;
2
+ ASSETS: Fetcher;
3
3
  }
@@ -1,5 +1,5 @@
1
- import type { NextConfig } from "next";
2
1
  import { initOpenNextCloudflareForDev } from "@opennextjs/cloudflare";
2
+ import type { NextConfig } from "next";
3
3
 
4
4
  initOpenNextCloudflareForDev();
5
5
 
@@ -2,5 +2,5 @@ import { defineCloudflareConfig } from "@opennextjs/cloudflare";
2
2
  import r2IncrementalCache from "@opennextjs/cloudflare/overrides/incremental-cache/r2-incremental-cache";
3
3
 
4
4
  export default defineCloudflareConfig({
5
- incrementalCache: r2IncrementalCache,
5
+ incrementalCache: r2IncrementalCache,
6
6
  });
@@ -1,24 +1,24 @@
1
1
  {
2
- "name": "jack-template",
3
- "type": "module",
4
- "private": true,
5
- "scripts": {
6
- "dev": "next dev",
7
- "build": "next build",
8
- "preview": "opennextjs-cloudflare build && opennextjs-cloudflare preview",
9
- "deploy": "opennextjs-cloudflare build && opennextjs-cloudflare deploy",
10
- "cf-typegen": "wrangler types --env-interface CloudflareEnv cloudflare-env.d.ts"
11
- },
12
- "dependencies": {
13
- "@opennextjs/cloudflare": "^1.0.0",
14
- "next": "^15.0.0",
15
- "react": "^19.0.0",
16
- "react-dom": "^19.0.0"
17
- },
18
- "devDependencies": {
19
- "@cloudflare/workers-types": "^4.20241205.0",
20
- "@types/react": "^19.0.0",
21
- "@types/react-dom": "^19.0.0",
22
- "typescript": "^5.6.0"
23
- }
2
+ "name": "jack-template",
3
+ "type": "module",
4
+ "private": true,
5
+ "scripts": {
6
+ "dev": "next dev",
7
+ "build": "next build",
8
+ "preview": "opennextjs-cloudflare build && opennextjs-cloudflare preview",
9
+ "deploy": "opennextjs-cloudflare build && opennextjs-cloudflare deploy",
10
+ "cf-typegen": "wrangler types --env-interface CloudflareEnv cloudflare-env.d.ts"
11
+ },
12
+ "dependencies": {
13
+ "@opennextjs/cloudflare": "^1.0.0",
14
+ "next": "^15.0.0",
15
+ "react": "^19.0.0",
16
+ "react-dom": "^19.0.0"
17
+ },
18
+ "devDependencies": {
19
+ "@cloudflare/workers-types": "^4.20241205.0",
20
+ "@types/react": "^19.0.0",
21
+ "@types/react-dom": "^19.0.0",
22
+ "typescript": "^5.6.0"
23
+ }
24
24
  }
@@ -1,44 +1,28 @@
1
1
  {
2
- "compilerOptions": {
3
- "target": "ES2022",
4
- "lib": [
5
- "ES2022",
6
- "DOM",
7
- "DOM.Iterable"
8
- ],
9
- "module": "ESNext",
10
- "moduleResolution": "bundler",
11
- "jsx": "preserve",
12
- "strict": true,
13
- "skipLibCheck": true,
14
- "noEmit": true,
15
- "incremental": true,
16
- "esModuleInterop": true,
17
- "resolveJsonModule": true,
18
- "isolatedModules": true,
19
- "paths": {
20
- "@/*": [
21
- "./*"
22
- ]
23
- },
24
- "plugins": [
25
- {
26
- "name": "next"
27
- }
28
- ],
29
- "types": [
30
- "@cloudflare/workers-types"
31
- ],
32
- "allowJs": true
33
- },
34
- "include": [
35
- "next-env.d.ts",
36
- "**/*.ts",
37
- "**/*.tsx",
38
- ".next/types/**/*.ts",
39
- "cloudflare-env.d.ts"
40
- ],
41
- "exclude": [
42
- "node_modules"
43
- ]
2
+ "compilerOptions": {
3
+ "target": "ES2022",
4
+ "lib": ["ES2022", "DOM", "DOM.Iterable"],
5
+ "module": "ESNext",
6
+ "moduleResolution": "bundler",
7
+ "jsx": "preserve",
8
+ "strict": true,
9
+ "skipLibCheck": true,
10
+ "noEmit": true,
11
+ "incremental": true,
12
+ "esModuleInterop": true,
13
+ "resolveJsonModule": true,
14
+ "isolatedModules": true,
15
+ "paths": {
16
+ "@/*": ["./*"]
17
+ },
18
+ "plugins": [
19
+ {
20
+ "name": "next"
21
+ }
22
+ ],
23
+ "types": ["@cloudflare/workers-types"],
24
+ "allowJs": true
25
+ },
26
+ "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts", "cloudflare-env.d.ts"],
27
+ "exclude": ["node_modules"]
44
28
  }
@@ -1,17 +1,17 @@
1
1
  {
2
- "$schema": "node_modules/wrangler/config-schema.json",
3
- "name": "jack-template",
4
- "main": ".open-next/worker.js",
5
- "compatibility_date": "2024-12-30",
6
- "compatibility_flags": ["nodejs_compat"],
7
- "assets": {
8
- "directory": ".open-next/assets",
9
- "binding": "ASSETS"
10
- },
11
- "r2_buckets": [
12
- {
13
- "binding": "NEXT_INC_CACHE_R2_BUCKET",
14
- "bucket_name": "jack-template-cache"
15
- }
16
- ]
2
+ "$schema": "node_modules/wrangler/config-schema.json",
3
+ "name": "jack-template",
4
+ "main": ".open-next/worker.js",
5
+ "compatibility_date": "2024-12-30",
6
+ "compatibility_flags": ["nodejs_compat"],
7
+ "assets": {
8
+ "directory": ".open-next/assets",
9
+ "binding": "ASSETS"
10
+ },
11
+ "r2_buckets": [
12
+ {
13
+ "binding": "NEXT_INC_CACHE_R2_BUCKET",
14
+ "bucket_name": "jack-template-cache"
15
+ }
16
+ ]
17
17
  }
package/src/lib/github.ts DELETED
@@ -1,151 +0,0 @@
1
- import { mkdtemp, readFile, readdir, rm } from "node:fs/promises";
2
- import { tmpdir } from "node:os";
3
- import { join } from "node:path";
4
- import { $ } from "bun";
5
- import type { AgentContext, Capability, Template, TemplateHooks } from "../templates/types";
6
- import { parseJsonc } from "./jsonc.ts";
7
- import type { ServiceTypeKey } from "./services/index.ts";
8
-
9
- /**
10
- * Parse GitHub input: "user/repo" or "https://github.com/user/repo"
11
- */
12
- function parseGitHubInput(input: string): { owner: string; repo: string } {
13
- // Full URL: https://github.com/user/repo
14
- const urlMatch = input.match(/github\.com\/([^\/]+)\/([^\/\s]+)/);
15
- if (urlMatch?.[1] && urlMatch[2]) {
16
- return { owner: urlMatch[1], repo: urlMatch[2].replace(/\.git$/, "") };
17
- }
18
-
19
- // Shorthand: user/repo
20
- const shortMatch = input.match(/^([^\/]+)\/([^\/]+)$/);
21
- if (shortMatch?.[1] && shortMatch[2]) {
22
- return { owner: shortMatch[1], repo: shortMatch[2] };
23
- }
24
-
25
- throw new Error(
26
- `Invalid GitHub URL: ${input}\n\nExpected: user/repo or https://github.com/user/repo`,
27
- );
28
- }
29
-
30
- /**
31
- * Recursively read all files in a directory
32
- */
33
- async function readDirRecursive(dir: string, base = ""): Promise<Record<string, string>> {
34
- const files: Record<string, string> = {};
35
- const entries = await readdir(dir, { withFileTypes: true });
36
-
37
- for (const entry of entries) {
38
- const relativePath = base ? `${base}/${entry.name}` : entry.name;
39
- const fullPath = join(dir, entry.name);
40
-
41
- if (entry.isDirectory()) {
42
- // Skip common non-source directories
43
- if (["node_modules", ".git", ".wrangler"].includes(entry.name)) continue;
44
- Object.assign(files, await readDirRecursive(fullPath, relativePath));
45
- } else {
46
- // Read file content
47
- const content = await readFile(fullPath, "utf-8");
48
- files[relativePath] = content;
49
- }
50
- }
51
-
52
- return files;
53
- }
54
-
55
- /**
56
- * Fetch template from GitHub tarball API
57
- */
58
- export async function fetchFromGitHub(input: string): Promise<Template> {
59
- const { owner, repo } = parseGitHubInput(input);
60
- const tarballUrl = `https://api.github.com/repos/${owner}/${repo}/tarball`;
61
-
62
- // Fetch tarball
63
- const headers: Record<string, string> = {
64
- "User-Agent": "jack-cli",
65
- };
66
- if (process.env.GITHUB_TOKEN) {
67
- headers.Authorization = `Bearer ${process.env.GITHUB_TOKEN}`;
68
- }
69
-
70
- const response = await fetch(tarballUrl, { headers, redirect: "follow" });
71
-
72
- if (!response.ok) {
73
- if (response.status === 404) {
74
- throw new Error(
75
- `Repository not found: ${owner}/${repo}\n\nMake sure it exists and is public.`,
76
- );
77
- }
78
- if (response.status === 403) {
79
- throw new Error(
80
- "GitHub rate limit exceeded.\n\nSet GITHUB_TOKEN to continue:\n export GITHUB_TOKEN=ghp_xxxxx\n\nGet a token at: https://github.com/settings/tokens",
81
- );
82
- }
83
- throw new Error(`Failed to fetch template: ${response.statusText}`);
84
- }
85
-
86
- // Create temp directory
87
- const tempDir = await mkdtemp(join(tmpdir(), "jack-template-"));
88
- const tarPath = join(tempDir, "template.tar.gz");
89
-
90
- try {
91
- // Write tarball to temp file
92
- const buffer = await response.arrayBuffer();
93
- await Bun.write(tarPath, buffer);
94
-
95
- // Extract tarball
96
- await $`tar -xzf ${tarPath} -C ${tempDir}`.quiet();
97
-
98
- // Find extracted directory (GitHub tarballs have a prefix like "user-repo-sha")
99
- const entries = await readdir(tempDir);
100
- const extractedDir = entries.find((e) => e !== "template.tar.gz");
101
- if (!extractedDir) {
102
- throw new Error("Failed to extract template: no directory found");
103
- }
104
-
105
- // Read all files
106
- const files = await readDirRecursive(join(tempDir, extractedDir));
107
-
108
- // Warn if it doesn't look like a worker
109
- const hasWorkerFiles = files["wrangler.toml"] || files["worker.ts"] || files["src/index.ts"];
110
- if (!hasWorkerFiles) {
111
- console.warn("\n⚠ This doesn't look like a Cloudflare Worker");
112
- console.warn(" (no wrangler.toml or worker entry point found)\n");
113
- }
114
-
115
- // Read .jack.json metadata if it exists
116
- const jackJsonContent = files[".jack.json"];
117
- if (jackJsonContent) {
118
- try {
119
- const metadata = parseJsonc(jackJsonContent) as {
120
- description?: string;
121
- secrets?: string[];
122
- capabilities?: Capability[];
123
- requires?: ServiceTypeKey[];
124
- hooks?: TemplateHooks;
125
- agentContext?: AgentContext;
126
- };
127
- // Remove .jack.json from files (not needed in project)
128
- const { ".jack.json": _, ...filesWithoutJackJson } = files;
129
- return {
130
- description: metadata.description || `GitHub: ${owner}/${repo}`,
131
- secrets: metadata.secrets,
132
- capabilities: metadata.capabilities,
133
- requires: metadata.requires,
134
- hooks: metadata.hooks,
135
- agentContext: metadata.agentContext,
136
- files: filesWithoutJackJson,
137
- };
138
- } catch {
139
- // Invalid JSON, fall through to default
140
- }
141
- }
142
-
143
- return {
144
- description: `GitHub: ${owner}/${repo}`,
145
- files,
146
- };
147
- } finally {
148
- // Cleanup
149
- await rm(tempDir, { recursive: true, force: true });
150
- }
151
- }