@puzzmo/cli 1.0.0
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 +75 -0
- package/lib/commands/game/create.d.ts +2 -0
- package/lib/commands/game/create.js +145 -0
- package/lib/commands/game/create.js.map +1 -0
- package/lib/commands/login.d.ts +2 -0
- package/lib/commands/login.js +13 -0
- package/lib/commands/login.js.map +1 -0
- package/lib/commands/upload.d.ts +2 -0
- package/lib/commands/upload.js +87 -0
- package/lib/commands/upload.js.map +1 -0
- package/lib/download/page-downloader.d.ts +2 -0
- package/lib/download/page-downloader.js +94 -0
- package/lib/download/page-downloader.js.map +1 -0
- package/lib/index.d.ts +2 -0
- package/lib/index.js +53 -0
- package/lib/index.js.map +1 -0
- package/lib/lib/api.d.ts +10 -0
- package/lib/lib/api.js +53 -0
- package/lib/lib/api.js.map +1 -0
- package/lib/lib/config.d.ts +13 -0
- package/lib/lib/config.js +29 -0
- package/lib/lib/config.js.map +1 -0
- package/lib/lib/exec.d.ts +15 -0
- package/lib/lib/exec.js +34 -0
- package/lib/lib/exec.js.map +1 -0
- package/lib/lib/package-manager.d.ts +2 -0
- package/lib/lib/package-manager.js +15 -0
- package/lib/lib/package-manager.js.map +1 -0
- package/lib/skills/registry.d.ts +13 -0
- package/lib/skills/registry.js +49 -0
- package/lib/skills/registry.js.map +1 -0
- package/lib/skills/runner.d.ts +4 -0
- package/lib/skills/runner.js +80 -0
- package/lib/skills/runner.js.map +1 -0
- package/lib/tui/pipeline.d.ts +2 -0
- package/lib/tui/pipeline.js +426 -0
- package/lib/tui/pipeline.js.map +1 -0
- package/lib/wizard/agent-detect.d.ts +4 -0
- package/lib/wizard/agent-detect.js +4 -0
- package/lib/wizard/agent-detect.js.map +1 -0
- package/package.json +20 -0
- package/src/commands/game/create.ts +171 -0
- package/src/commands/login.ts +15 -0
- package/src/commands/upload.ts +94 -0
- package/src/download/page-downloader.ts +104 -0
- package/src/index.ts +56 -0
- package/src/lib/api.ts +75 -0
- package/src/lib/config.ts +37 -0
- package/src/lib/exec.ts +38 -0
- package/src/skills/registry.ts +57 -0
- package/src/skills/runner.ts +91 -0
- package/src/tui/pipeline.ts +460 -0
- package/src/wizard/agent-detect.ts +6 -0
- package/tsconfig.json +15 -0
package/README.md
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
# @puzzmo/cli
|
|
2
|
+
|
|
3
|
+
Command-line tool for Puzzmo game developers. Authenticate, upload game builds, and create new game projects.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install -g @puzzmo/cli
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Commands
|
|
12
|
+
|
|
13
|
+
### `puzzmo login <token>`
|
|
14
|
+
|
|
15
|
+
Save a CLI auth token. Generate one from studio.puzzmo.com.
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
puzzmo login pzt-your-token-here
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
### `puzzmo upload <slug> <dir>`
|
|
22
|
+
|
|
23
|
+
Upload a game build directory to Puzzmo.
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
puzzmo upload my-game dist/
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
The command collects all files in the directory, computes a SHA from git (or file contents), and uploads them in batches.
|
|
30
|
+
|
|
31
|
+
### `puzzmo game create [token]`
|
|
32
|
+
|
|
33
|
+
Interactive wizard to create a new Puzzmo game project.
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
puzzmo game create --name my-game --url https://example.com/game/
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
Options:
|
|
40
|
+
|
|
41
|
+
| Option | Description |
|
|
42
|
+
| ----------------- | --------------------------------------------------------- |
|
|
43
|
+
| `[token]` | Optional access token (runs `puzzmo login` automatically) |
|
|
44
|
+
| `--name <name>` | Game name |
|
|
45
|
+
| `--url <url>` | Source URL to import |
|
|
46
|
+
| `--agent <agent>` | LLM agent: `claude`, `codex`, `gemini`, `none` |
|
|
47
|
+
|
|
48
|
+
The wizard:
|
|
49
|
+
|
|
50
|
+
1. Downloads the source HTML page and assets
|
|
51
|
+
2. Detects installed LLM coding agents
|
|
52
|
+
3. Installs migration skills via the Vercel skills ecosystem
|
|
53
|
+
4. Runs each skill through the selected agent with build verification
|
|
54
|
+
5. Commits after each successful step
|
|
55
|
+
|
|
56
|
+
## Configuration
|
|
57
|
+
|
|
58
|
+
Config is stored in `~/.puzzmo/config.json`:
|
|
59
|
+
|
|
60
|
+
```json
|
|
61
|
+
{
|
|
62
|
+
"token": "pzt-...",
|
|
63
|
+
"apiURL": "https://api.puzzmo.com"
|
|
64
|
+
}
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
The token can also be set via the `PUZZMO_TOKEN` environment variable, and the API URL via `PUZZMO_API_URL`.
|
|
68
|
+
|
|
69
|
+
## Also available via
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
yarn create puzzmo game
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
This uses the `create-puzzmo` package which forwards to `puzzmo game create`.
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { detectAgent } from "../../wizard/agent-detect.js";
|
|
4
|
+
import { downloadPage } from "../../download/page-downloader.js";
|
|
5
|
+
import { runCommand, gitCommit } from "../../lib/exec.js";
|
|
6
|
+
import { runSkillsPipelineTUI } from "../../skills/runner.js";
|
|
7
|
+
import { installSkills } from "../../skills/registry.js";
|
|
8
|
+
import { login } from "../login.js";
|
|
9
|
+
/** Parses CLI args into CreateOptions */
|
|
10
|
+
const parseArgs = (args) => {
|
|
11
|
+
const opts = {};
|
|
12
|
+
let i = 0;
|
|
13
|
+
// First positional arg could be access token
|
|
14
|
+
if (args[0] && !args[0].startsWith("--")) {
|
|
15
|
+
opts.accessToken = args[0];
|
|
16
|
+
i = 1;
|
|
17
|
+
}
|
|
18
|
+
while (i < args.length) {
|
|
19
|
+
const arg = args[i];
|
|
20
|
+
if (arg === "--name" && args[i + 1]) {
|
|
21
|
+
opts.name = args[++i];
|
|
22
|
+
}
|
|
23
|
+
else if (arg === "--url" && args[i + 1]) {
|
|
24
|
+
opts.url = args[++i];
|
|
25
|
+
}
|
|
26
|
+
else if (arg === "--agent" && args[i + 1]) {
|
|
27
|
+
opts.agent = args[++i];
|
|
28
|
+
}
|
|
29
|
+
i++;
|
|
30
|
+
}
|
|
31
|
+
return opts;
|
|
32
|
+
};
|
|
33
|
+
/** Interactive text prompt (simple readline-based fallback) */
|
|
34
|
+
const askText = async (message, defaultValue) => {
|
|
35
|
+
const { createInterface } = await import("node:readline");
|
|
36
|
+
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
37
|
+
const prompt = defaultValue ? `${message} (${defaultValue}): ` : `${message}: `;
|
|
38
|
+
return new Promise((resolve) => {
|
|
39
|
+
rl.question(prompt, (answer) => {
|
|
40
|
+
rl.close();
|
|
41
|
+
resolve(answer.trim() || defaultValue || "");
|
|
42
|
+
});
|
|
43
|
+
});
|
|
44
|
+
};
|
|
45
|
+
/** Interactive select prompt */
|
|
46
|
+
const askSelect = async (message, options) => {
|
|
47
|
+
console.log(`\n${message}`);
|
|
48
|
+
const enabled = options.filter((o) => !o.disabled);
|
|
49
|
+
options.forEach((opt) => {
|
|
50
|
+
const prefix = opt.disabled ? " " : ` ${enabled.indexOf(opt) + 1}.`;
|
|
51
|
+
const suffix = opt.disabled ? " (Coming soon)" : "";
|
|
52
|
+
console.log(`${prefix} ${opt.label}${suffix}`);
|
|
53
|
+
});
|
|
54
|
+
const { createInterface } = await import("node:readline");
|
|
55
|
+
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
56
|
+
return new Promise((resolve) => {
|
|
57
|
+
rl.question(`\nChoice (1-${enabled.length}): `, (answer) => {
|
|
58
|
+
rl.close();
|
|
59
|
+
const idx = parseInt(answer.trim(), 10) - 1;
|
|
60
|
+
resolve(enabled[idx]?.value ?? enabled[0].value);
|
|
61
|
+
});
|
|
62
|
+
});
|
|
63
|
+
};
|
|
64
|
+
/** Main game create wizard */
|
|
65
|
+
export const gameCreate = async (args) => {
|
|
66
|
+
const opts = parseArgs(args);
|
|
67
|
+
console.log("\n Puzzmo Game Creator\n");
|
|
68
|
+
// Step 1: Game name
|
|
69
|
+
const name = opts.name || (await askText("Game name"));
|
|
70
|
+
if (!name) {
|
|
71
|
+
console.error("Game name is required");
|
|
72
|
+
process.exit(1);
|
|
73
|
+
}
|
|
74
|
+
// Step 2: Mode selection
|
|
75
|
+
const mode = await askSelect("How would you like to create your game?", [
|
|
76
|
+
{ value: "import", label: "Import an HTML game from a web page" },
|
|
77
|
+
{ value: "new-repo", label: "Create game in a new repo", disabled: true },
|
|
78
|
+
{ value: "add-to-repo", label: "Add a game to this repo", disabled: true },
|
|
79
|
+
]);
|
|
80
|
+
if (mode !== "import") {
|
|
81
|
+
console.log("This mode is not yet supported.");
|
|
82
|
+
process.exit(0);
|
|
83
|
+
}
|
|
84
|
+
// Step 3: Source URL
|
|
85
|
+
const url = opts.url || (await askText("Source URL to import"));
|
|
86
|
+
if (!url) {
|
|
87
|
+
console.error("Source URL is required for import mode");
|
|
88
|
+
process.exit(1);
|
|
89
|
+
}
|
|
90
|
+
// Step 4: Download page
|
|
91
|
+
const gameDir = path.resolve(name);
|
|
92
|
+
console.log(`\nDownloading ${url} into ./${name}/...`);
|
|
93
|
+
await downloadPage(url, gameDir);
|
|
94
|
+
console.log("Download complete.");
|
|
95
|
+
// Step 5: Detect agents
|
|
96
|
+
const agents = detectAgent();
|
|
97
|
+
const agentChoices = [
|
|
98
|
+
...agents.map((a) => ({ value: a.binary, label: `${a.displayName} (${a.path})` })),
|
|
99
|
+
{ value: "none", label: "None - I'll run the skills manually" },
|
|
100
|
+
];
|
|
101
|
+
// Step 6: Ask about agent
|
|
102
|
+
let selectedAgent;
|
|
103
|
+
if (opts.agent) {
|
|
104
|
+
selectedAgent = opts.agent;
|
|
105
|
+
}
|
|
106
|
+
else if (agents.length > 0) {
|
|
107
|
+
selectedAgent = await askSelect("Which LLM agent do you use?", agentChoices);
|
|
108
|
+
}
|
|
109
|
+
else {
|
|
110
|
+
console.log("\nNo LLM agents detected (checked: claude, codex)");
|
|
111
|
+
selectedAgent = "none";
|
|
112
|
+
}
|
|
113
|
+
// Step 7: Login if token provided
|
|
114
|
+
if (opts.accessToken) {
|
|
115
|
+
console.log("\nLogging in...");
|
|
116
|
+
login(opts.accessToken);
|
|
117
|
+
}
|
|
118
|
+
// Step 8: Install skills into the game directory
|
|
119
|
+
if (selectedAgent !== "none") {
|
|
120
|
+
console.log("\nInstalling Puzzmo skills...");
|
|
121
|
+
const count = installSkills(selectedAgent, gameDir);
|
|
122
|
+
console.log(`Installed ${count} skill(s).`);
|
|
123
|
+
}
|
|
124
|
+
// Step 9: Initialize git
|
|
125
|
+
if (!fs.existsSync(path.join(gameDir, ".git"))) {
|
|
126
|
+
runCommand("git init", { cwd: gameDir });
|
|
127
|
+
runCommand("git add -A", { cwd: gameDir });
|
|
128
|
+
gitCommit("Initial game import", { cwd: gameDir });
|
|
129
|
+
}
|
|
130
|
+
// Step 10: Run skills pipeline
|
|
131
|
+
if (selectedAgent !== "none") {
|
|
132
|
+
console.log("\nStarting migration pipeline...\n");
|
|
133
|
+
await runSkillsPipelineTUI(selectedAgent, gameDir);
|
|
134
|
+
}
|
|
135
|
+
// Done
|
|
136
|
+
console.log(`\nDone! Your game is in ./${name}/`);
|
|
137
|
+
console.log(`\nNext steps:`);
|
|
138
|
+
console.log(` cd ${name}`);
|
|
139
|
+
console.log(` npx vite # Start development server`);
|
|
140
|
+
console.log(` npx vite build # Build for production`);
|
|
141
|
+
if (selectedAgent === "none") {
|
|
142
|
+
console.log(`\nTo run migration skills manually, see packages/skills/ for SKILL.md files.`);
|
|
143
|
+
}
|
|
144
|
+
};
|
|
145
|
+
//# sourceMappingURL=create.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create.js","sourceRoot":"","sources":["../../../src/commands/game/create.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { writeConfig, readConfig } from "../lib/config.js";
|
|
2
|
+
/** Saves a CLI token to ~/.puzzmo/config.json */
|
|
3
|
+
export const login = (token) => {
|
|
4
|
+
if (!token.startsWith("pzt-")) {
|
|
5
|
+
console.error("Invalid CLI token. Generate one from studio.puzzmo.com.");
|
|
6
|
+
process.exit(1);
|
|
7
|
+
}
|
|
8
|
+
const config = readConfig();
|
|
9
|
+
config.token = token;
|
|
10
|
+
writeConfig(config);
|
|
11
|
+
console.log("Logged in successfully. Token saved to ~/.puzzmo/config.json");
|
|
12
|
+
};
|
|
13
|
+
//# sourceMappingURL=login.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"login.js","sourceRoot":"","sources":["../../src/commands/login.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAE1D,iDAAiD;AACjD,MAAM,CAAC,MAAM,KAAK,GAAG,CAAC,KAAa,EAAE,EAAE;IACrC,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;QAC9B,OAAO,CAAC,KAAK,CAAC,yDAAyD,CAAC,CAAA;QACxE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;IACjB,CAAC;IAED,MAAM,MAAM,GAAG,UAAU,EAAE,CAAA;IAC3B,MAAM,CAAC,KAAK,GAAG,KAAK,CAAA;IACpB,WAAW,CAAC,MAAM,CAAC,CAAA;IAEnB,OAAO,CAAC,GAAG,CAAC,8DAA8D,CAAC,CAAA;AAC7E,CAAC,CAAA"}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { execSync } from "node:child_process";
|
|
2
|
+
import crypto from "node:crypto";
|
|
3
|
+
import fs from "node:fs";
|
|
4
|
+
import path from "node:path";
|
|
5
|
+
import { uploadFiles } from "../lib/api.js";
|
|
6
|
+
import { getAPIURL, getToken } from "../lib/config.js";
|
|
7
|
+
/** Collects all files in a directory recursively */
|
|
8
|
+
const collectFiles = (dir) => {
|
|
9
|
+
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
10
|
+
const files = [];
|
|
11
|
+
for (const entry of entries) {
|
|
12
|
+
const full = path.join(dir, entry.name);
|
|
13
|
+
if (entry.isDirectory())
|
|
14
|
+
files.push(...collectFiles(full));
|
|
15
|
+
else
|
|
16
|
+
files.push(full);
|
|
17
|
+
}
|
|
18
|
+
return files;
|
|
19
|
+
};
|
|
20
|
+
/** Tries to get the current git SHA, returns null if not in a git repo */
|
|
21
|
+
const getGitSHA = () => {
|
|
22
|
+
try {
|
|
23
|
+
return execSync("git rev-parse HEAD", { encoding: "utf-8" }).trim();
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
/** Hashes all file contents to produce a deterministic SHA */
|
|
30
|
+
const hashFiles = (filePaths) => {
|
|
31
|
+
const hash = crypto.createHash("sha256");
|
|
32
|
+
for (const fp of filePaths.sort()) {
|
|
33
|
+
hash.update(fs.readFileSync(fp));
|
|
34
|
+
}
|
|
35
|
+
return hash.digest("hex").slice(0, 12);
|
|
36
|
+
};
|
|
37
|
+
/** Formats a byte count as a human-readable string */
|
|
38
|
+
const formatBytes = (bytes) => {
|
|
39
|
+
if (bytes < 1024)
|
|
40
|
+
return `${bytes} B`;
|
|
41
|
+
if (bytes < 1024 * 1024)
|
|
42
|
+
return `${(bytes / 1024).toFixed(1)} KB`;
|
|
43
|
+
return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
|
|
44
|
+
};
|
|
45
|
+
/** Uploads game build artifacts to Puzzmo */
|
|
46
|
+
export const upload = async (gameSlug, dir) => {
|
|
47
|
+
const token = getToken();
|
|
48
|
+
if (!token) {
|
|
49
|
+
console.error("Not logged in. Run `puzzmo login <token>` or set PUZZMO_TOKEN.");
|
|
50
|
+
process.exit(1);
|
|
51
|
+
}
|
|
52
|
+
const distDir = path.resolve(dir);
|
|
53
|
+
if (!fs.existsSync(distDir)) {
|
|
54
|
+
console.error(`Directory not found: ${dir}`);
|
|
55
|
+
process.exit(1);
|
|
56
|
+
}
|
|
57
|
+
const files = collectFiles(distDir);
|
|
58
|
+
if (!files.length) {
|
|
59
|
+
console.error(`Directory is empty: ${dir}`);
|
|
60
|
+
process.exit(1);
|
|
61
|
+
}
|
|
62
|
+
// Determine SHA
|
|
63
|
+
const sha = getGitSHA() || hashFiles(files);
|
|
64
|
+
console.log(`\nUploading ${gameSlug} (${sha.slice(0, 8)})`);
|
|
65
|
+
console.log(`Directory: ${distDir}`);
|
|
66
|
+
console.log("");
|
|
67
|
+
let totalBytes = 0;
|
|
68
|
+
for (const file of files) {
|
|
69
|
+
const size = fs.statSync(file).size;
|
|
70
|
+
totalBytes += size;
|
|
71
|
+
const rel = path.relative(distDir, file);
|
|
72
|
+
console.log(` ${rel} (${formatBytes(size)})`);
|
|
73
|
+
}
|
|
74
|
+
const apiURL = getAPIURL();
|
|
75
|
+
const defaultURL = "https://api.puzzmo.com";
|
|
76
|
+
console.log(`\n${files.length} file(s), ${formatBytes(totalBytes)} total`);
|
|
77
|
+
if (apiURL !== defaultURL)
|
|
78
|
+
console.log(`Uploading to ${apiURL}...`);
|
|
79
|
+
else
|
|
80
|
+
console.log("Uploading...");
|
|
81
|
+
const result = await uploadFiles(token, gameSlug, sha, files, distDir, (batch, totalBatches, uploaded) => {
|
|
82
|
+
console.log(` Batch ${batch}/${totalBatches} done (${uploaded} file(s) uploaded)`);
|
|
83
|
+
});
|
|
84
|
+
console.log(`\nDone - ${result.versionID}`);
|
|
85
|
+
console.log(`CDN: ${result.cdnBase}`);
|
|
86
|
+
};
|
|
87
|
+
//# sourceMappingURL=upload.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"upload.js","sourceRoot":"","sources":["../../src/commands/upload.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import https from "node:https";
|
|
4
|
+
import http from "node:http";
|
|
5
|
+
/** Fetch that tolerates expired/self-signed SSL certificates */
|
|
6
|
+
const fetchPage = async (url) => {
|
|
7
|
+
const parsed = new URL(url);
|
|
8
|
+
const isHttps = parsed.protocol === "https:";
|
|
9
|
+
return new Promise((resolve, reject) => {
|
|
10
|
+
const mod = isHttps ? https : http;
|
|
11
|
+
const opts = isHttps ? { rejectUnauthorized: false } : {};
|
|
12
|
+
const req = mod.get(url, opts, (res) => {
|
|
13
|
+
const chunks = [];
|
|
14
|
+
res.on("data", (chunk) => chunks.push(chunk));
|
|
15
|
+
res.on("end", () => {
|
|
16
|
+
const buffer = Buffer.concat(chunks);
|
|
17
|
+
const ab = new ArrayBuffer(buffer.byteLength);
|
|
18
|
+
const view = new Uint8Array(ab);
|
|
19
|
+
view.set(buffer);
|
|
20
|
+
resolve({
|
|
21
|
+
ok: (res.statusCode ?? 0) >= 200 && (res.statusCode ?? 0) < 300,
|
|
22
|
+
status: res.statusCode ?? 0,
|
|
23
|
+
text: async () => buffer.toString("utf-8"),
|
|
24
|
+
arrayBuffer: async () => ab,
|
|
25
|
+
});
|
|
26
|
+
});
|
|
27
|
+
});
|
|
28
|
+
req.on("error", reject);
|
|
29
|
+
});
|
|
30
|
+
};
|
|
31
|
+
/** Downloads an HTML page and its referenced assets into a src/ directory */
|
|
32
|
+
export const downloadPage = async (url, outputDir) => {
|
|
33
|
+
const srcDir = path.join(outputDir, "src");
|
|
34
|
+
fs.mkdirSync(srcDir, { recursive: true });
|
|
35
|
+
// Download the HTML
|
|
36
|
+
const response = await fetchPage(url);
|
|
37
|
+
if (!response.ok)
|
|
38
|
+
throw new Error(`Failed to fetch ${url}: ${response.status}`);
|
|
39
|
+
let html = await response.text();
|
|
40
|
+
const baseURL = new URL(url);
|
|
41
|
+
const downloaded = new Set();
|
|
42
|
+
// Find referenced assets (src, href, url())
|
|
43
|
+
const assetRefs = extractAssetRefs(html);
|
|
44
|
+
for (const ref of assetRefs) {
|
|
45
|
+
if (downloaded.has(ref))
|
|
46
|
+
continue;
|
|
47
|
+
if (ref.startsWith("data:") || ref.startsWith("#") || ref.startsWith("javascript:"))
|
|
48
|
+
continue;
|
|
49
|
+
try {
|
|
50
|
+
const assetURL = new URL(ref, baseURL);
|
|
51
|
+
// Only download same-origin assets
|
|
52
|
+
if (assetURL.origin !== baseURL.origin)
|
|
53
|
+
continue;
|
|
54
|
+
const assetPath = assetURL.pathname.replace(/^\//, "");
|
|
55
|
+
if (!assetPath)
|
|
56
|
+
continue;
|
|
57
|
+
const localPath = path.join(srcDir, assetPath);
|
|
58
|
+
fs.mkdirSync(path.dirname(localPath), { recursive: true });
|
|
59
|
+
const assetResponse = await fetchPage(assetURL.href);
|
|
60
|
+
if (!assetResponse.ok)
|
|
61
|
+
continue;
|
|
62
|
+
const ab = await assetResponse.arrayBuffer();
|
|
63
|
+
fs.writeFileSync(localPath, new Uint8Array(ab));
|
|
64
|
+
// Rewrite reference in HTML to local path
|
|
65
|
+
html = html.replaceAll(ref, assetPath);
|
|
66
|
+
downloaded.add(ref);
|
|
67
|
+
}
|
|
68
|
+
catch {
|
|
69
|
+
// Skip assets that fail to download
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
// Write the HTML file
|
|
73
|
+
fs.writeFileSync(path.join(srcDir, "index.html"), html);
|
|
74
|
+
console.log(` Saved index.html + ${downloaded.size} asset(s) to ${path.relative(process.cwd(), srcDir)}/`);
|
|
75
|
+
};
|
|
76
|
+
/** Extracts asset references from HTML using regex */
|
|
77
|
+
const extractAssetRefs = (html) => {
|
|
78
|
+
const refs = [];
|
|
79
|
+
// src="..." and href="..."
|
|
80
|
+
const attrRegex = /(?:src|href)=["']([^"']+)["']/gi;
|
|
81
|
+
let match;
|
|
82
|
+
while ((match = attrRegex.exec(html)) !== null) {
|
|
83
|
+
if (match[1])
|
|
84
|
+
refs.push(match[1]);
|
|
85
|
+
}
|
|
86
|
+
// url("...") in CSS
|
|
87
|
+
const urlRegex = /url\(["']?([^"')]+)["']?\)/gi;
|
|
88
|
+
while ((match = urlRegex.exec(html)) !== null) {
|
|
89
|
+
if (match[1])
|
|
90
|
+
refs.push(match[1]);
|
|
91
|
+
}
|
|
92
|
+
return [...new Set(refs)];
|
|
93
|
+
};
|
|
94
|
+
//# sourceMappingURL=page-downloader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"page-downloader.js","sourceRoot":"","sources":["../../src/download/page-downloader.ts"],"names":[],"mappings":"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"}
|
package/lib/index.d.ts
ADDED
package/lib/index.js
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { login } from "./commands/login.js";
|
|
3
|
+
import { upload } from "./commands/upload.js";
|
|
4
|
+
import { gameCreate } from "./commands/game/create.js";
|
|
5
|
+
const [command, ...args] = process.argv.slice(2);
|
|
6
|
+
const printUsage = () => {
|
|
7
|
+
console.log(`Usage:
|
|
8
|
+
puzzmo login <token> Save a CLI auth token
|
|
9
|
+
puzzmo upload <slug> <dir> Upload game build from <dir>
|
|
10
|
+
puzzmo game create [token] Create a new Puzzmo game project`);
|
|
11
|
+
};
|
|
12
|
+
const run = async () => {
|
|
13
|
+
switch (command) {
|
|
14
|
+
case "login": {
|
|
15
|
+
const token = args[0];
|
|
16
|
+
if (!token) {
|
|
17
|
+
console.error("Usage: puzzmo login <token>");
|
|
18
|
+
process.exit(1);
|
|
19
|
+
}
|
|
20
|
+
login(token);
|
|
21
|
+
break;
|
|
22
|
+
}
|
|
23
|
+
case "upload": {
|
|
24
|
+
const gameSlug = args[0];
|
|
25
|
+
const dir = args[1];
|
|
26
|
+
if (!gameSlug || !dir) {
|
|
27
|
+
console.error("Usage: puzzmo upload <gameSlug> <dir>");
|
|
28
|
+
process.exit(1);
|
|
29
|
+
}
|
|
30
|
+
await upload(gameSlug, dir);
|
|
31
|
+
break;
|
|
32
|
+
}
|
|
33
|
+
case "game": {
|
|
34
|
+
const [subcommand, ...subArgs] = args;
|
|
35
|
+
if (subcommand === "create") {
|
|
36
|
+
await gameCreate(subArgs);
|
|
37
|
+
}
|
|
38
|
+
else {
|
|
39
|
+
console.error("Usage: puzzmo game create [token] [--name <name>] [--url <url>] [--agent <agent>]");
|
|
40
|
+
process.exit(1);
|
|
41
|
+
}
|
|
42
|
+
break;
|
|
43
|
+
}
|
|
44
|
+
default:
|
|
45
|
+
printUsage();
|
|
46
|
+
break;
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
run().catch((err) => {
|
|
50
|
+
console.error(err.message || err);
|
|
51
|
+
process.exit(1);
|
|
52
|
+
});
|
|
53
|
+
//# sourceMappingURL=index.js.map
|
package/lib/index.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,KAAK,EAAE,MAAM,qBAAqB,CAAA;AAC3C,OAAO,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAA;AAC7C,OAAO,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAA;AAEtD,MAAM,CAAC,OAAO,EAAE,GAAG,IAAI,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAA;AAEhD,MAAM,UAAU,GAAG,GAAG,EAAE;IACtB,OAAO,CAAC,GAAG,CAAC;;;mEAGqD,CAAC,CAAA;AACpE,CAAC,CAAA;AAED,MAAM,GAAG,GAAG,KAAK,IAAI,EAAE;IACrB,QAAQ,OAAO,EAAE,CAAC;QAChB,KAAK,OAAO,CAAC,CAAC,CAAC;YACb,MAAM,KAAK,GAAG,IAAI,CAAC,CAAC,CAAC,CAAA;YACrB,IAAI,CAAC,KAAK,EAAE,CAAC;gBACX,OAAO,CAAC,KAAK,CAAC,6BAA6B,CAAC,CAAA;gBAC5C,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;YACjB,CAAC;YACD,KAAK,CAAC,KAAK,CAAC,CAAA;YACZ,MAAK;QACP,CAAC;QACD,KAAK,QAAQ,CAAC,CAAC,CAAC;YACd,MAAM,QAAQ,GAAG,IAAI,CAAC,CAAC,CAAC,CAAA;YACxB,MAAM,GAAG,GAAG,IAAI,CAAC,CAAC,CAAC,CAAA;YACnB,IAAI,CAAC,QAAQ,IAAI,CAAC,GAAG,EAAE,CAAC;gBACtB,OAAO,CAAC,KAAK,CAAC,uCAAuC,CAAC,CAAA;gBACtD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;YACjB,CAAC;YACD,MAAM,MAAM,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAA;YAC3B,MAAK;QACP,CAAC;QACD,KAAK,MAAM,CAAC,CAAC,CAAC;YACZ,MAAM,CAAC,UAAU,EAAE,GAAG,OAAO,CAAC,GAAG,IAAI,CAAA;YACrC,IAAI,UAAU,KAAK,QAAQ,EAAE,CAAC;gBAC5B,MAAM,UAAU,CAAC,OAAO,CAAC,CAAA;YAC3B,CAAC;iBAAM,CAAC;gBACN,OAAO,CAAC,KAAK,CAAC,mFAAmF,CAAC,CAAA;gBAClG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;YACjB,CAAC;YACD,MAAK;QACP,CAAC;QACD;YACE,UAAU,EAAE,CAAA;YACZ,MAAK;IACT,CAAC;AACH,CAAC,CAAA;AAED,GAAG,EAAE,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;IAClB,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,IAAI,GAAG,CAAC,CAAA;IACjC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;AACjB,CAAC,CAAC,CAAA"}
|
package/lib/lib/api.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
type CompleteResponse = {
|
|
2
|
+
cdnBase: string;
|
|
3
|
+
versionID: string;
|
|
4
|
+
error?: string;
|
|
5
|
+
};
|
|
6
|
+
/** Callback for reporting batch upload progress */
|
|
7
|
+
export type UploadProgress = (batch: number, totalBatches: number, uploaded: number) => void;
|
|
8
|
+
/** Multi-step upload: init -> batched file uploads -> complete */
|
|
9
|
+
export declare const uploadFiles: (token: string, gameSlug: string, sha: string, filePaths: string[], baseDir: string, onProgress?: UploadProgress) => Promise<CompleteResponse>;
|
|
10
|
+
export {};
|
package/lib/lib/api.js
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { getAPIURL } from "./config.js";
|
|
4
|
+
const BATCH_SIZE = 10;
|
|
5
|
+
/** Sends a JSON POST request */
|
|
6
|
+
const jsonPost = async (url, token, body) => {
|
|
7
|
+
const res = await fetch(url, {
|
|
8
|
+
method: "POST",
|
|
9
|
+
headers: { Authorization: `Bearer ${token}`, "Content-Type": "application/json" },
|
|
10
|
+
body: JSON.stringify(body),
|
|
11
|
+
});
|
|
12
|
+
const json = await res.json();
|
|
13
|
+
if (!res.ok)
|
|
14
|
+
throw new Error(`Server error (${res.status}): ${json.error || "Unknown error"}`);
|
|
15
|
+
return json;
|
|
16
|
+
};
|
|
17
|
+
/** Uploads a single file as raw binary with filename in query param */
|
|
18
|
+
const uploadFile = async (url, token, filePath, baseDir) => {
|
|
19
|
+
const relativePath = path.relative(baseDir, filePath);
|
|
20
|
+
const content = fs.readFileSync(filePath);
|
|
21
|
+
const res = await fetch(`${url}?name=${encodeURIComponent(relativePath)}`, {
|
|
22
|
+
method: "POST",
|
|
23
|
+
headers: {
|
|
24
|
+
Authorization: `Bearer ${token}`,
|
|
25
|
+
"Content-Type": "application/octet-stream",
|
|
26
|
+
},
|
|
27
|
+
body: content,
|
|
28
|
+
});
|
|
29
|
+
const json = await res.json();
|
|
30
|
+
if (!res.ok)
|
|
31
|
+
throw new Error(`Server error (${res.status}): ${json.error || "Unknown error"}`);
|
|
32
|
+
return json;
|
|
33
|
+
};
|
|
34
|
+
/** Multi-step upload: init -> batched file uploads -> complete */
|
|
35
|
+
export const uploadFiles = async (token, gameSlug, sha, filePaths, baseDir, onProgress) => {
|
|
36
|
+
const apiURL = getAPIURL();
|
|
37
|
+
// Step 1: Init session
|
|
38
|
+
const init = (await jsonPost(`${apiURL}/cliUpload`, token, { gameSlug, sha }));
|
|
39
|
+
// Step 2: Upload files in concurrent batches
|
|
40
|
+
const fileURL = `${apiURL}/cliUpload/${init.sessionID}/file`;
|
|
41
|
+
const totalBatches = Math.ceil(filePaths.length / BATCH_SIZE);
|
|
42
|
+
let totalUploaded = 0;
|
|
43
|
+
for (let i = 0; i < filePaths.length; i += BATCH_SIZE) {
|
|
44
|
+
const batch = filePaths.slice(i, i + BATCH_SIZE);
|
|
45
|
+
const batchNum = Math.floor(i / BATCH_SIZE) + 1;
|
|
46
|
+
await Promise.all(batch.map((fp) => uploadFile(fileURL, token, fp, baseDir)));
|
|
47
|
+
totalUploaded += batch.length;
|
|
48
|
+
onProgress?.(batchNum, totalBatches, totalUploaded);
|
|
49
|
+
}
|
|
50
|
+
// Step 3: Complete
|
|
51
|
+
return (await jsonPost(`${apiURL}/cliUpload/${init.sessionID}/complete`, token, {}));
|
|
52
|
+
};
|
|
53
|
+
//# sourceMappingURL=api.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api.js","sourceRoot":"","sources":["../../src/lib/api.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
type Config = {
|
|
2
|
+
token?: string;
|
|
3
|
+
apiURL?: string;
|
|
4
|
+
};
|
|
5
|
+
/** Reads the CLI config from ~/.puzzmo/config.json */
|
|
6
|
+
export declare const readConfig: () => Config;
|
|
7
|
+
/** Writes the CLI config to ~/.puzzmo/config.json */
|
|
8
|
+
export declare const writeConfig: (config: Config) => void;
|
|
9
|
+
/** Returns the auth token from config or PUZZMO_TOKEN env var */
|
|
10
|
+
export declare const getToken: () => string | undefined;
|
|
11
|
+
/** Returns the API base URL */
|
|
12
|
+
export declare const getAPIURL: () => string;
|
|
13
|
+
export {};
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import os from "node:os";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
const configDir = path.join(os.homedir(), ".puzzmo");
|
|
5
|
+
const configPath = path.join(configDir, "config.json");
|
|
6
|
+
/** Reads the CLI config from ~/.puzzmo/config.json */
|
|
7
|
+
export const readConfig = () => {
|
|
8
|
+
try {
|
|
9
|
+
const raw = fs.readFileSync(configPath, "utf-8");
|
|
10
|
+
return JSON.parse(raw);
|
|
11
|
+
}
|
|
12
|
+
catch {
|
|
13
|
+
return {};
|
|
14
|
+
}
|
|
15
|
+
};
|
|
16
|
+
/** Writes the CLI config to ~/.puzzmo/config.json */
|
|
17
|
+
export const writeConfig = (config) => {
|
|
18
|
+
fs.mkdirSync(configDir, { recursive: true });
|
|
19
|
+
fs.writeFileSync(configPath, JSON.stringify(config, null, 2) + "\n");
|
|
20
|
+
};
|
|
21
|
+
/** Returns the auth token from config or PUZZMO_TOKEN env var */
|
|
22
|
+
export const getToken = () => {
|
|
23
|
+
return process.env.PUZZMO_TOKEN || readConfig().token;
|
|
24
|
+
};
|
|
25
|
+
/** Returns the API base URL */
|
|
26
|
+
export const getAPIURL = () => {
|
|
27
|
+
return process.env.PUZZMO_API_URL || readConfig().apiURL || "https://api.puzzmo.com";
|
|
28
|
+
};
|
|
29
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/lib/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAA;AACxB,OAAO,EAAE,MAAM,SAAS,CAAA;AACxB,OAAO,IAAI,MAAM,WAAW,CAAA;AAE5B,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,SAAS,CAAC,CAAA;AACpD,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,aAAa,CAAC,CAAA;AAOtD,sDAAsD;AACtD,MAAM,CAAC,MAAM,UAAU,GAAG,GAAW,EAAE;IACrC,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,EAAE,CAAC,YAAY,CAAC,UAAU,EAAE,OAAO,CAAC,CAAA;QAChD,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAA;IACxB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAA;IACX,CAAC;AACH,CAAC,CAAA;AAED,qDAAqD;AACrD,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,MAAc,EAAE,EAAE;IAC5C,EAAE,CAAC,SAAS,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;IAC5C,EAAE,CAAC,aAAa,CAAC,UAAU,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,CAAC,CAAA;AACtE,CAAC,CAAA;AAED,iEAAiE;AACjE,MAAM,CAAC,MAAM,QAAQ,GAAG,GAAuB,EAAE;IAC/C,OAAO,OAAO,CAAC,GAAG,CAAC,YAAY,IAAI,UAAU,EAAE,CAAC,KAAK,CAAA;AACvD,CAAC,CAAA;AAED,+BAA+B;AAC/B,MAAM,CAAC,MAAM,SAAS,GAAG,GAAW,EAAE;IACpC,OAAO,OAAO,CAAC,GAAG,CAAC,cAAc,IAAI,UAAU,EAAE,CAAC,MAAM,IAAI,wBAAwB,CAAA;AACtF,CAAC,CAAA"}
|