@taptap-maker/init-workspace 0.1.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/dist/cli.js +140 -0
- package/package.json +23 -0
package/dist/cli.js
ADDED
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/cli.ts
|
|
4
|
+
import { createHash } from "crypto";
|
|
5
|
+
import { existsSync, mkdirSync, writeFileSync } from "fs";
|
|
6
|
+
import { get as httpsGet } from "https";
|
|
7
|
+
import { resolve, join, dirname } from "path";
|
|
8
|
+
import { inflateRawSync } from "zlib";
|
|
9
|
+
var C = {
|
|
10
|
+
reset: "\x1B[0m",
|
|
11
|
+
green: "\x1B[32m",
|
|
12
|
+
blue: "\x1B[34m",
|
|
13
|
+
red: "\x1B[31m",
|
|
14
|
+
cyan: "\x1B[36m"
|
|
15
|
+
};
|
|
16
|
+
var info = (msg) => console.log(`${C.blue}\u{1F4CB} ${msg}${C.reset}`);
|
|
17
|
+
var ok = (msg) => console.log(`${C.green}\u2705 ${msg}${C.reset}`);
|
|
18
|
+
var err = (msg) => console.error(`${C.red}\u274C ${msg}${C.reset}`);
|
|
19
|
+
var dl = (msg) => console.log(`${C.cyan}\u2B07\uFE0F ${msg}${C.reset}`);
|
|
20
|
+
function download(url, maxRedirects = 5) {
|
|
21
|
+
return new Promise((resolve2, reject) => {
|
|
22
|
+
httpsGet(url, (res) => {
|
|
23
|
+
if (res.statusCode && res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) {
|
|
24
|
+
if (maxRedirects <= 0) return reject(new Error(`Too many redirects: ${url}`));
|
|
25
|
+
return resolve2(download(res.headers.location, maxRedirects - 1));
|
|
26
|
+
}
|
|
27
|
+
if (res.statusCode && res.statusCode >= 400) {
|
|
28
|
+
return reject(new Error(`HTTP ${res.statusCode}: ${url}`));
|
|
29
|
+
}
|
|
30
|
+
const chunks = [];
|
|
31
|
+
res.on("data", (chunk) => chunks.push(chunk));
|
|
32
|
+
res.on("end", () => resolve2(Buffer.concat(chunks)));
|
|
33
|
+
res.on("error", reject);
|
|
34
|
+
}).on("error", reject);
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
function parseZip(buf) {
|
|
38
|
+
const entries = [];
|
|
39
|
+
let offset = 0;
|
|
40
|
+
while (offset < buf.length - 4) {
|
|
41
|
+
const sig = buf.readUInt32LE(offset);
|
|
42
|
+
if (sig !== 67324752) break;
|
|
43
|
+
const compressionMethod = buf.readUInt16LE(offset + 8);
|
|
44
|
+
const compressedSize = buf.readUInt32LE(offset + 18);
|
|
45
|
+
const filenameLen = buf.readUInt16LE(offset + 26);
|
|
46
|
+
const extraLen = buf.readUInt16LE(offset + 28);
|
|
47
|
+
const filename = buf.toString("utf8", offset + 30, offset + 30 + filenameLen);
|
|
48
|
+
const dataStart = offset + 30 + filenameLen + extraLen;
|
|
49
|
+
const isDirectory = filename.endsWith("/");
|
|
50
|
+
let data;
|
|
51
|
+
if (isDirectory) {
|
|
52
|
+
data = Buffer.alloc(0);
|
|
53
|
+
} else if (compressionMethod === 0) {
|
|
54
|
+
data = buf.subarray(dataStart, dataStart + compressedSize);
|
|
55
|
+
} else if (compressionMethod === 8) {
|
|
56
|
+
data = inflateRawSync(buf.subarray(dataStart, dataStart + compressedSize));
|
|
57
|
+
} else {
|
|
58
|
+
throw new Error(`Unsupported compression method ${compressionMethod} for ${filename}`);
|
|
59
|
+
}
|
|
60
|
+
entries.push({ filename, data, isDirectory });
|
|
61
|
+
offset = dataStart + compressedSize;
|
|
62
|
+
}
|
|
63
|
+
return entries;
|
|
64
|
+
}
|
|
65
|
+
function extractZip(buf, targetDir, opts) {
|
|
66
|
+
const entries = parseZip(buf);
|
|
67
|
+
for (const entry of entries) {
|
|
68
|
+
if (entry.filename === "CLAUDE.md" && opts?.claudeMdDir) {
|
|
69
|
+
mkdirSync(opts.claudeMdDir, { recursive: true });
|
|
70
|
+
writeFileSync(join(opts.claudeMdDir, "CLAUDE.md"), entry.data);
|
|
71
|
+
ok(`Extracted CLAUDE.md \u2192 ${opts.claudeMdDir}/CLAUDE.md`);
|
|
72
|
+
continue;
|
|
73
|
+
}
|
|
74
|
+
const dest = join(targetDir, entry.filename);
|
|
75
|
+
if (entry.isDirectory) {
|
|
76
|
+
mkdirSync(dest, { recursive: true });
|
|
77
|
+
} else {
|
|
78
|
+
mkdirSync(dirname(dest), { recursive: true });
|
|
79
|
+
writeFileSync(dest, entry.data);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
function md5(data) {
|
|
84
|
+
return createHash("md5").update(data).digest("hex");
|
|
85
|
+
}
|
|
86
|
+
var CDN_BASE = "https://urhox-demo-platform.spark.xd.com";
|
|
87
|
+
var AGENT_HOME = process.env["AGENT_HOME_CLAUDE_DIR"] || "/home/Maker/.claude";
|
|
88
|
+
async function main() {
|
|
89
|
+
console.log();
|
|
90
|
+
console.log("\u{1F680} @taptap-maker/init-workspace");
|
|
91
|
+
console.log("\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550");
|
|
92
|
+
console.log();
|
|
93
|
+
const targetPath = resolve(process.argv[2] || process.cwd());
|
|
94
|
+
if (!existsSync(targetPath)) {
|
|
95
|
+
mkdirSync(targetPath, { recursive: true });
|
|
96
|
+
ok(`Created directory: ${targetPath}`);
|
|
97
|
+
} else {
|
|
98
|
+
info(`Directory exists: ${targetPath}`);
|
|
99
|
+
}
|
|
100
|
+
const previewDomain = process.env["TAPCODE_PREVIEW_DOMAIN"] || "";
|
|
101
|
+
const isProduction = previewDomain === "taptap-code.org" || previewDomain === "games.tapapps.cn";
|
|
102
|
+
const pathPrefix = isProduction ? "pd/stable" : "rnd/latest";
|
|
103
|
+
info(
|
|
104
|
+
isProduction ? `Production (TAPCODE_PREVIEW_DOMAIN=${previewDomain}), using stable` : `Development (TAPCODE_PREVIEW_DOMAIN=${previewDomain || "unset"}), using latest`
|
|
105
|
+
);
|
|
106
|
+
const aiDevKitUrl = `${CDN_BASE}/ai-dev-kit/${pathPrefix}/ai-dev-kit.zip`;
|
|
107
|
+
dl(`Downloading ai-dev-kit: ${aiDevKitUrl}`);
|
|
108
|
+
const aiDevKitData = await download(aiDevKitUrl);
|
|
109
|
+
info(`AI Dev Kit MD5: ${md5(aiDevKitData)}`);
|
|
110
|
+
info(`Extracting ai-dev-kit \u2192 ${targetPath}`);
|
|
111
|
+
extractZip(aiDevKitData, targetPath, { claudeMdDir: AGENT_HOME });
|
|
112
|
+
ok("ai-dev-kit extracted");
|
|
113
|
+
const gitignorePath = join(targetPath, ".gitignore");
|
|
114
|
+
try {
|
|
115
|
+
writeFileSync(gitignorePath, ".build/\ndist/\n", "utf8");
|
|
116
|
+
ok("Created .gitignore");
|
|
117
|
+
} catch (e) {
|
|
118
|
+
err(`.gitignore creation failed: ${e}`);
|
|
119
|
+
}
|
|
120
|
+
const skillCreatorUrl = `${CDN_BASE}/skill-creator/${pathPrefix}/skill-creator.zip`;
|
|
121
|
+
dl(`Downloading skill-creator: ${skillCreatorUrl}`);
|
|
122
|
+
try {
|
|
123
|
+
const skillData = await download(skillCreatorUrl);
|
|
124
|
+
info(`Skill Creator MD5: ${md5(skillData)}`);
|
|
125
|
+
const skillsDir = join(targetPath, ".claude", "skills");
|
|
126
|
+
mkdirSync(skillsDir, { recursive: true });
|
|
127
|
+
info(`Extracting skill-creator \u2192 ${skillsDir}`);
|
|
128
|
+
extractZip(skillData, skillsDir);
|
|
129
|
+
ok("skill-creator extracted");
|
|
130
|
+
} catch (e) {
|
|
131
|
+
err(`skill-creator failed (non-critical): ${e}`);
|
|
132
|
+
}
|
|
133
|
+
console.log();
|
|
134
|
+
ok("\u{1F389} Workspace initialization complete!");
|
|
135
|
+
info(`Path: ${targetPath}`);
|
|
136
|
+
}
|
|
137
|
+
main().catch((e) => {
|
|
138
|
+
err(`Initialization failed: ${e}`);
|
|
139
|
+
process.exit(1);
|
|
140
|
+
});
|
package/package.json
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@taptap-maker/init-workspace",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Initialize UrhoX workspace with ai-dev-kit and skills",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"init-workspace": "./dist/cli.js"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"dist"
|
|
11
|
+
],
|
|
12
|
+
"scripts": {
|
|
13
|
+
"build": "tsup",
|
|
14
|
+
"prepublishOnly": "pnpm build"
|
|
15
|
+
},
|
|
16
|
+
"devDependencies": {
|
|
17
|
+
"tsup": "^8.4.0"
|
|
18
|
+
},
|
|
19
|
+
"engines": {
|
|
20
|
+
"node": ">=24"
|
|
21
|
+
},
|
|
22
|
+
"license": "MIT"
|
|
23
|
+
}
|