@getjack/jack 0.1.6 → 0.1.8
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 +6 -2
- package/src/commands/down.ts +20 -3
- package/src/commands/mcp.ts +17 -1
- package/src/commands/publish.ts +50 -0
- package/src/commands/ship.ts +4 -3
- package/src/index.ts +7 -0
- package/src/lib/agent-files.ts +0 -2
- package/src/lib/binding-validator.ts +9 -4
- package/src/lib/build-helper.ts +67 -45
- package/src/lib/config-generator.ts +120 -0
- package/src/lib/config.ts +2 -1
- package/src/lib/control-plane.ts +61 -0
- package/src/lib/managed-deploy.ts +10 -2
- package/src/lib/mcp-config.ts +2 -1
- package/src/lib/output.ts +21 -1
- package/src/lib/project-detection.ts +431 -0
- package/src/lib/project-link.test.ts +4 -5
- package/src/lib/project-link.ts +5 -3
- package/src/lib/project-operations.ts +334 -35
- package/src/lib/project-resolver.ts +9 -2
- package/src/lib/secrets.ts +1 -2
- package/src/lib/storage/file-filter.ts +5 -0
- package/src/lib/telemetry-config.ts +3 -3
- package/src/lib/telemetry.ts +4 -0
- package/src/lib/zip-packager.ts +8 -0
- package/src/mcp/test-utils.ts +112 -0
- package/src/templates/index.ts +137 -7
- package/templates/nextjs/.jack.json +26 -26
- package/templates/nextjs/app/globals.css +4 -4
- package/templates/nextjs/app/layout.tsx +11 -11
- package/templates/nextjs/app/page.tsx +8 -6
- package/templates/nextjs/cloudflare-env.d.ts +1 -1
- package/templates/nextjs/next.config.ts +1 -1
- package/templates/nextjs/open-next.config.ts +1 -1
- package/templates/nextjs/package.json +22 -22
- package/templates/nextjs/tsconfig.json +26 -42
- package/templates/nextjs/wrangler.jsonc +15 -15
- package/src/lib/github.ts +0 -151
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
|
-
}
|