@getjack/jack 0.1.2 → 0.1.4
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/README.md +77 -29
- package/package.json +54 -47
- package/src/commands/agents.ts +145 -10
- package/src/commands/down.ts +110 -102
- package/src/commands/feedback.ts +189 -0
- package/src/commands/init.ts +8 -12
- package/src/commands/login.ts +88 -0
- package/src/commands/logout.ts +14 -0
- package/src/commands/logs.ts +21 -0
- package/src/commands/mcp.ts +134 -7
- package/src/commands/new.ts +43 -17
- package/src/commands/open.ts +13 -6
- package/src/commands/projects.ts +269 -143
- package/src/commands/secrets.ts +413 -0
- package/src/commands/services.ts +96 -123
- package/src/commands/ship.ts +5 -1
- package/src/commands/whoami.ts +31 -0
- package/src/index.ts +218 -144
- package/src/lib/agent-files.ts +34 -0
- package/src/lib/agents.ts +390 -22
- package/src/lib/asset-hash.ts +50 -0
- package/src/lib/auth/client.ts +115 -0
- package/src/lib/auth/constants.ts +5 -0
- package/src/lib/auth/guard.ts +57 -0
- package/src/lib/auth/index.ts +18 -0
- package/src/lib/auth/store.ts +54 -0
- package/src/lib/binding-validator.ts +136 -0
- package/src/lib/build-helper.ts +211 -0
- package/src/lib/cloudflare-api.ts +24 -0
- package/src/lib/config.ts +5 -6
- package/src/lib/control-plane.ts +295 -0
- package/src/lib/debug.ts +3 -1
- package/src/lib/deploy-mode.ts +93 -0
- package/src/lib/deploy-upload.ts +92 -0
- package/src/lib/errors.ts +2 -0
- package/src/lib/github.ts +31 -1
- package/src/lib/hooks.ts +4 -12
- package/src/lib/intent.ts +88 -0
- package/src/lib/jsonc.ts +125 -0
- package/src/lib/local-paths.test.ts +902 -0
- package/src/lib/local-paths.ts +258 -0
- package/src/lib/managed-deploy.ts +175 -0
- package/src/lib/managed-down.ts +159 -0
- package/src/lib/mcp-config.ts +55 -34
- package/src/lib/names.ts +9 -29
- package/src/lib/project-operations.ts +676 -249
- package/src/lib/project-resolver.ts +476 -0
- package/src/lib/registry.ts +76 -37
- package/src/lib/resources.ts +196 -0
- package/src/lib/schema.ts +30 -1
- package/src/lib/storage/file-filter.ts +1 -0
- package/src/lib/storage/index.ts +5 -1
- package/src/lib/telemetry.ts +14 -0
- package/src/lib/tty.ts +15 -0
- package/src/lib/zip-packager.ts +255 -0
- package/src/mcp/resources/index.ts +8 -2
- package/src/mcp/server.ts +32 -4
- package/src/mcp/tools/index.ts +35 -13
- package/src/mcp/types.ts +6 -0
- package/src/mcp/utils.ts +1 -1
- package/src/templates/index.ts +42 -4
- package/src/templates/types.ts +13 -0
- package/templates/CLAUDE.md +166 -0
- package/templates/api/.jack.json +4 -0
- package/templates/api/bun.lock +1 -0
- package/templates/api/wrangler.jsonc +5 -0
- package/templates/hello/.jack.json +28 -0
- package/templates/hello/package.json +10 -0
- package/templates/hello/src/index.ts +11 -0
- package/templates/hello/tsconfig.json +11 -0
- package/templates/hello/wrangler.jsonc +5 -0
- package/templates/miniapp/.jack.json +15 -4
- package/templates/miniapp/bun.lock +135 -40
- package/templates/miniapp/index.html +1 -0
- package/templates/miniapp/package.json +3 -1
- package/templates/miniapp/public/.well-known/farcaster.json +7 -5
- package/templates/miniapp/public/icon.png +0 -0
- package/templates/miniapp/public/og.png +0 -0
- package/templates/miniapp/schema.sql +8 -0
- package/templates/miniapp/src/App.tsx +254 -3
- package/templates/miniapp/src/components/ShareSheet.tsx +147 -0
- package/templates/miniapp/src/hooks/useAI.ts +35 -0
- package/templates/miniapp/src/hooks/useGuestbook.ts +11 -1
- package/templates/miniapp/src/hooks/useShare.ts +76 -0
- package/templates/miniapp/src/index.css +15 -0
- package/templates/miniapp/src/lib/api.ts +2 -1
- package/templates/miniapp/src/worker.ts +515 -1
- package/templates/miniapp/wrangler.jsonc +15 -3
- package/LICENSE +0 -190
- package/src/commands/cloud.ts +0 -230
- package/templates/api/wrangler.toml +0 -3
package/src/commands/mcp.ts
CHANGED
|
@@ -1,18 +1,145 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { spawn } from "node:child_process";
|
|
2
|
+
import { error, info, success } from "../lib/output.ts";
|
|
2
3
|
import { startMcpServer } from "../mcp/server.ts";
|
|
3
4
|
|
|
4
5
|
interface McpOptions {
|
|
5
6
|
project?: string;
|
|
7
|
+
debug?: boolean;
|
|
6
8
|
}
|
|
7
9
|
|
|
8
10
|
export default async function mcp(subcommand?: string, options: McpOptions = {}): Promise<void> {
|
|
9
|
-
if (subcommand
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
11
|
+
if (subcommand === "serve") {
|
|
12
|
+
await startMcpServer({
|
|
13
|
+
projectPath: options.project,
|
|
14
|
+
debug: options.debug,
|
|
15
|
+
});
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
if (subcommand === "test") {
|
|
20
|
+
await testMcpServer();
|
|
21
|
+
return;
|
|
13
22
|
}
|
|
14
23
|
|
|
15
|
-
|
|
16
|
-
|
|
24
|
+
error("Unknown subcommand. Use: jack mcp serve or jack mcp test");
|
|
25
|
+
info("Usage:");
|
|
26
|
+
info(" jack mcp serve [--project /path] [--debug] Start MCP server");
|
|
27
|
+
info(" jack mcp test Test MCP server connectivity");
|
|
28
|
+
process.exit(1);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Test MCP server by spawning it and sending test requests
|
|
33
|
+
*/
|
|
34
|
+
async function testMcpServer(): Promise<void> {
|
|
35
|
+
info("Testing MCP server...\n");
|
|
36
|
+
|
|
37
|
+
const proc = spawn("./src/index.ts", ["mcp", "serve"], {
|
|
38
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
17
39
|
});
|
|
40
|
+
|
|
41
|
+
const results: { test: string; passed: boolean; error?: string }[] = [];
|
|
42
|
+
|
|
43
|
+
const sendRequest = (id: number, method: string, params: object = {}): Promise<unknown> => {
|
|
44
|
+
return new Promise((resolve, reject) => {
|
|
45
|
+
const timeout = setTimeout(() => reject(new Error("Timeout")), 10000);
|
|
46
|
+
|
|
47
|
+
const handler = (data: Buffer) => {
|
|
48
|
+
const lines = data.toString().split("\n").filter(Boolean);
|
|
49
|
+
for (const line of lines) {
|
|
50
|
+
try {
|
|
51
|
+
const response = JSON.parse(line);
|
|
52
|
+
if (response.id === id) {
|
|
53
|
+
clearTimeout(timeout);
|
|
54
|
+
proc.stdout.off("data", handler);
|
|
55
|
+
if (response.error) {
|
|
56
|
+
reject(new Error(response.error.message));
|
|
57
|
+
} else {
|
|
58
|
+
resolve(response.result);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
} catch {
|
|
62
|
+
// Not JSON, ignore
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
proc.stdout.on("data", handler);
|
|
68
|
+
proc.stdin.write(`${JSON.stringify({ jsonrpc: "2.0", method, params, id })}\n`);
|
|
69
|
+
});
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
try {
|
|
73
|
+
// Test 1: Initialize
|
|
74
|
+
info("1. Testing initialize...");
|
|
75
|
+
const initResult = (await sendRequest(1, "initialize", {
|
|
76
|
+
protocolVersion: "2024-11-05",
|
|
77
|
+
capabilities: {},
|
|
78
|
+
clientInfo: { name: "jack-mcp-test", version: "1.0" },
|
|
79
|
+
})) as { serverInfo?: { name: string; version: string } };
|
|
80
|
+
if (initResult?.serverInfo?.name === "jack") {
|
|
81
|
+
results.push({ test: "initialize", passed: true });
|
|
82
|
+
success(` ✓ Server info: ${initResult.serverInfo.name} v${initResult.serverInfo.version}`);
|
|
83
|
+
} else {
|
|
84
|
+
results.push({ test: "initialize", passed: false, error: "Invalid response" });
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// Test 2: List tools
|
|
88
|
+
info("2. Testing tools/list...");
|
|
89
|
+
const toolsResult = (await sendRequest(2, "tools/list")) as { tools?: { name: string }[] };
|
|
90
|
+
const toolNames = toolsResult?.tools?.map((t) => t.name) ?? [];
|
|
91
|
+
if (toolNames.length > 0) {
|
|
92
|
+
results.push({ test: "tools/list", passed: true });
|
|
93
|
+
success(` ✓ Found ${toolNames.length} tools: ${toolNames.join(", ")}`);
|
|
94
|
+
} else {
|
|
95
|
+
results.push({ test: "tools/list", passed: false, error: "No tools found" });
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// Test 3: List resources
|
|
99
|
+
info("3. Testing resources/list...");
|
|
100
|
+
const resourcesResult = (await sendRequest(3, "resources/list")) as {
|
|
101
|
+
resources?: { name: string }[];
|
|
102
|
+
};
|
|
103
|
+
const resourceCount = resourcesResult?.resources?.length ?? 0;
|
|
104
|
+
results.push({ test: "resources/list", passed: true });
|
|
105
|
+
success(` ✓ Found ${resourceCount} resource(s)`);
|
|
106
|
+
|
|
107
|
+
// Test 4: Call list_projects tool
|
|
108
|
+
info("4. Testing tools/call (list_projects)...");
|
|
109
|
+
const callResult = (await sendRequest(4, "tools/call", {
|
|
110
|
+
name: "list_projects",
|
|
111
|
+
arguments: {},
|
|
112
|
+
})) as { content?: { text: string }[] };
|
|
113
|
+
const responseText = callResult?.content?.[0]?.text;
|
|
114
|
+
if (responseText) {
|
|
115
|
+
const parsed = JSON.parse(responseText);
|
|
116
|
+
if (parsed.success) {
|
|
117
|
+
results.push({ test: "tools/call", passed: true });
|
|
118
|
+
success(` ✓ list_projects returned ${parsed.data?.length ?? 0} projects`);
|
|
119
|
+
} else {
|
|
120
|
+
results.push({ test: "tools/call", passed: false, error: parsed.error?.message });
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
} catch (err) {
|
|
124
|
+
const errorMsg = err instanceof Error ? err.message : String(err);
|
|
125
|
+
results.push({ test: "unknown", passed: false, error: errorMsg });
|
|
126
|
+
error(` ✗ Error: ${errorMsg}`);
|
|
127
|
+
} finally {
|
|
128
|
+
proc.kill();
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// Summary
|
|
132
|
+
console.log("");
|
|
133
|
+
const passed = results.filter((r) => r.passed).length;
|
|
134
|
+
const failed = results.filter((r) => !r.passed).length;
|
|
135
|
+
|
|
136
|
+
if (failed === 0) {
|
|
137
|
+
success(`All ${passed} tests passed! MCP server is working correctly.`);
|
|
138
|
+
} else {
|
|
139
|
+
error(`${failed}/${results.length} tests failed.`);
|
|
140
|
+
for (const r of results.filter((r) => !r.passed)) {
|
|
141
|
+
error(` - ${r.test}: ${r.error}`);
|
|
142
|
+
}
|
|
143
|
+
process.exit(1);
|
|
144
|
+
}
|
|
18
145
|
}
|
package/src/commands/new.ts
CHANGED
|
@@ -2,22 +2,48 @@ import { getPreferredLaunchAgent, launchAgent } from "../lib/agents.ts";
|
|
|
2
2
|
import { debug } from "../lib/debug.ts";
|
|
3
3
|
import { getErrorDetails } from "../lib/errors.ts";
|
|
4
4
|
import { promptSelect } from "../lib/hooks.ts";
|
|
5
|
+
import { isIntentPhrase } from "../lib/intent.ts";
|
|
5
6
|
import { output, spinner } from "../lib/output.ts";
|
|
6
7
|
import { createProject } from "../lib/project-operations.ts";
|
|
7
8
|
|
|
8
9
|
export default async function newProject(
|
|
9
|
-
|
|
10
|
-
options: { template?: string } = {},
|
|
10
|
+
nameOrPhrase?: string,
|
|
11
|
+
options: { template?: string; intent?: string; managed?: boolean; byo?: boolean; ci?: boolean } = {},
|
|
11
12
|
): Promise<void> {
|
|
12
13
|
// Immediate feedback
|
|
13
14
|
output.start("Starting...");
|
|
14
|
-
debug("newProject called", {
|
|
15
|
-
|
|
15
|
+
debug("newProject called", { nameOrPhrase, options });
|
|
16
|
+
// CI mode: explicit --ci flag, JACK_CI env, or standard CI env
|
|
17
|
+
const isCi =
|
|
18
|
+
options.ci ||
|
|
19
|
+
process.env.JACK_CI === "1" ||
|
|
20
|
+
process.env.JACK_CI === "true" ||
|
|
21
|
+
process.env.CI === "true" ||
|
|
22
|
+
process.env.CI === "1";
|
|
23
|
+
|
|
24
|
+
// Determine if first arg is intent phrase or project name
|
|
25
|
+
let projectName: string | undefined;
|
|
26
|
+
let intentPhrase: string | undefined = options.intent;
|
|
27
|
+
|
|
28
|
+
if (nameOrPhrase) {
|
|
29
|
+
if (options.intent) {
|
|
30
|
+
// Explicit -m flag means first arg is definitely a name
|
|
31
|
+
projectName = nameOrPhrase;
|
|
32
|
+
} else if (isIntentPhrase(nameOrPhrase)) {
|
|
33
|
+
// Detected as intent phrase - name will be auto-generated
|
|
34
|
+
intentPhrase = nameOrPhrase;
|
|
35
|
+
projectName = undefined;
|
|
36
|
+
} else {
|
|
37
|
+
// Treat as project name
|
|
38
|
+
projectName = nameOrPhrase;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
16
41
|
|
|
17
42
|
let result: Awaited<ReturnType<typeof createProject>>;
|
|
18
43
|
try {
|
|
19
|
-
result = await createProject(
|
|
44
|
+
result = await createProject(projectName, {
|
|
20
45
|
template: options.template,
|
|
46
|
+
intent: intentPhrase,
|
|
21
47
|
reporter: {
|
|
22
48
|
start: output.start,
|
|
23
49
|
stop: output.stop,
|
|
@@ -29,6 +55,8 @@ export default async function newProject(
|
|
|
29
55
|
box: output.box,
|
|
30
56
|
},
|
|
31
57
|
interactive: !isCi,
|
|
58
|
+
managed: options.managed,
|
|
59
|
+
byo: options.byo,
|
|
32
60
|
});
|
|
33
61
|
} catch (error) {
|
|
34
62
|
const details = getErrorDetails(error);
|
|
@@ -37,9 +65,9 @@ export default async function newProject(
|
|
|
37
65
|
output.error(details.message);
|
|
38
66
|
}
|
|
39
67
|
|
|
40
|
-
const
|
|
41
|
-
if (
|
|
42
|
-
for (const key of
|
|
68
|
+
const missingSecrets = details.meta?.missingSecrets;
|
|
69
|
+
if (missingSecrets?.length) {
|
|
70
|
+
for (const key of missingSecrets) {
|
|
43
71
|
output.info(` Run: jack secrets add ${key}`);
|
|
44
72
|
}
|
|
45
73
|
}
|
|
@@ -48,7 +76,7 @@ export default async function newProject(
|
|
|
48
76
|
console.error(details.meta.stderr);
|
|
49
77
|
}
|
|
50
78
|
|
|
51
|
-
if (details.suggestion && !details.meta?.reported && !
|
|
79
|
+
if (details.suggestion && !details.meta?.reported && !missingSecrets?.length) {
|
|
52
80
|
output.info(details.suggestion);
|
|
53
81
|
}
|
|
54
82
|
|
|
@@ -63,8 +91,8 @@ export default async function newProject(
|
|
|
63
91
|
console.error("");
|
|
64
92
|
output.info(`Project: ${result.targetDir}`);
|
|
65
93
|
|
|
66
|
-
// Prompt to open preferred agent (only in interactive TTY)
|
|
67
|
-
if (process.stdout.isTTY) {
|
|
94
|
+
// Prompt to open preferred agent (only in interactive TTY, skip in CI mode)
|
|
95
|
+
if (process.stdout.isTTY && !isCi) {
|
|
68
96
|
const preferred = await getPreferredLaunchAgent();
|
|
69
97
|
if (preferred) {
|
|
70
98
|
console.error("");
|
|
@@ -73,12 +101,10 @@ export default async function newProject(
|
|
|
73
101
|
const choice = await promptSelect(["Yes", "No"]);
|
|
74
102
|
|
|
75
103
|
if (choice === 0) {
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
const launchResult = await launchAgent(preferred.launch, result.targetDir);
|
|
104
|
+
const launchResult = await launchAgent(preferred.launch, result.targetDir, {
|
|
105
|
+
projectName: result.projectName,
|
|
106
|
+
url: result.workerUrl,
|
|
107
|
+
});
|
|
82
108
|
if (!launchResult.success) {
|
|
83
109
|
output.warn(`Failed to launch ${preferred.definition.name}`);
|
|
84
110
|
if (launchResult.command?.length) {
|
package/src/commands/open.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { $ } from "bun";
|
|
2
2
|
import { error, info } from "../lib/output.ts";
|
|
3
|
-
import {
|
|
3
|
+
import { resolveProject } from "../lib/project-resolver.ts";
|
|
4
4
|
import { getProjectNameFromDir } from "../lib/storage/index.ts";
|
|
5
5
|
|
|
6
6
|
export interface OpenFlags {
|
|
@@ -22,19 +22,26 @@ export default async function open(projectName?: string, flags: OpenFlags = {}):
|
|
|
22
22
|
}
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
-
//
|
|
26
|
-
const project = await
|
|
25
|
+
// Resolve project from registry and control plane
|
|
26
|
+
const project = await resolveProject(name);
|
|
27
27
|
|
|
28
|
-
// Determine URL based on flags
|
|
28
|
+
// Determine URL based on flags and deploy mode
|
|
29
29
|
let url: string;
|
|
30
30
|
|
|
31
31
|
if (flags.dash) {
|
|
32
|
+
// Dashboard URLs - use Cloudflare dash for now
|
|
32
33
|
url = `https://dash.cloudflare.com/workers/services/view/${name}`;
|
|
33
34
|
} else if (flags.logs) {
|
|
34
35
|
url = `https://dash.cloudflare.com/workers/services/view/${name}/logs`;
|
|
35
36
|
} else {
|
|
36
|
-
// Default: use
|
|
37
|
-
|
|
37
|
+
// Default: use mode-appropriate URL
|
|
38
|
+
if (project?.sources.controlPlane && project.url) {
|
|
39
|
+
// Managed project: use runjack URL
|
|
40
|
+
url = project.url;
|
|
41
|
+
} else {
|
|
42
|
+
// BYO project: use workers.dev URL or stored URL
|
|
43
|
+
url = project?.url || `https://${name}.workers.dev`;
|
|
44
|
+
}
|
|
38
45
|
}
|
|
39
46
|
|
|
40
47
|
// Open browser using platform-specific command
|