superlab 0.1.3 → 0.1.5
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 +22 -0
- package/README.zh-CN.md +22 -0
- package/bin/superlab.cjs +56 -2
- package/lib/install.cjs +119 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -68,6 +68,28 @@ superlab init --all
|
|
|
68
68
|
|
|
69
69
|
`--all` is an alias for `--platform both`. Use `--force` if you need to overwrite existing files.
|
|
70
70
|
|
|
71
|
+
## Update
|
|
72
|
+
|
|
73
|
+
Refresh the current project:
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
superlab update
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
Refresh a specific project:
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
superlab update --target /path/to/project
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
Refresh every registered project initialized from this user account:
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
superlab update --all-projects
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
`superlab init` writes `.superlab/install.json` inside each project and registers the project in the user-level registry so `update --all-projects` knows what to refresh.
|
|
92
|
+
|
|
71
93
|
## Language
|
|
72
94
|
|
|
73
95
|
The installer chooses the display language from your system locale. If it detects Chinese locale values, it installs Chinese-facing command and skill text; otherwise it falls back to English.
|
package/README.zh-CN.md
CHANGED
|
@@ -66,6 +66,28 @@ superlab init --all
|
|
|
66
66
|
|
|
67
67
|
`--all` 是 `--platform both` 的别名。如果目标目录已有同名文件,可以加 `--force` 覆盖。
|
|
68
68
|
|
|
69
|
+
## 更新
|
|
70
|
+
|
|
71
|
+
刷新当前项目:
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
superlab update
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
刷新指定项目:
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
superlab update --target /path/to/project
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
刷新当前用户登记过的所有项目:
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
superlab update --all-projects
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
`superlab init` 会在项目内写入 `.superlab/install.json`,并在用户级 registry 里登记项目路径,所以 `update --all-projects` 才知道要刷新哪些项目。
|
|
90
|
+
|
|
69
91
|
## 语言
|
|
70
92
|
|
|
71
93
|
安装器会根据系统 locale 自动猜测展示语言。检测到中文 locale 时会安装中文命令和技能文案;否则默认安装英文文案。
|
package/bin/superlab.cjs
CHANGED
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
const path = require("node:path");
|
|
4
|
-
const {
|
|
4
|
+
const {
|
|
5
|
+
detectLanguage,
|
|
6
|
+
installSuperlab,
|
|
7
|
+
updateAllProjects,
|
|
8
|
+
updateSuperlabProject,
|
|
9
|
+
} = require("../lib/install.cjs");
|
|
5
10
|
const { promptSelect } = require("../lib/init_tui.cjs");
|
|
6
11
|
|
|
7
12
|
function printHelp() {
|
|
@@ -10,10 +15,13 @@ function printHelp() {
|
|
|
10
15
|
Usage:
|
|
11
16
|
superlab init [--target <dir>] [--platform codex|claude|both|all] [--lang en|zh] [--force]
|
|
12
17
|
superlab install [--target <dir>] [--platform codex|claude|both|all] [--lang en|zh] [--force]
|
|
18
|
+
superlab update [--target <dir>]
|
|
19
|
+
superlab update --all-projects
|
|
13
20
|
|
|
14
21
|
Commands:
|
|
15
22
|
init Initialize /lab commands, skills, templates, and scripts in a target
|
|
16
23
|
install Backward-compatible alias for init
|
|
24
|
+
update Refresh an initialized project or all registered projects
|
|
17
25
|
help Show this help message
|
|
18
26
|
`);
|
|
19
27
|
}
|
|
@@ -56,6 +64,31 @@ function parseInstallArgs(argv) {
|
|
|
56
64
|
return options;
|
|
57
65
|
}
|
|
58
66
|
|
|
67
|
+
function parseUpdateArgs(argv) {
|
|
68
|
+
const options = {
|
|
69
|
+
targetDir: process.cwd(),
|
|
70
|
+
allProjects: false,
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
for (let index = 0; index < argv.length; index += 1) {
|
|
74
|
+
const value = argv[index];
|
|
75
|
+
if (value === "--target") {
|
|
76
|
+
options.targetDir = path.resolve(argv[index + 1]);
|
|
77
|
+
index += 1;
|
|
78
|
+
} else if (value === "--all-projects") {
|
|
79
|
+
options.allProjects = true;
|
|
80
|
+
} else {
|
|
81
|
+
throw new Error(`Unknown option: ${value}`);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
if (options.allProjects && argv.includes("--target")) {
|
|
86
|
+
throw new Error("Use either --target or --all-projects, not both.");
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
return options;
|
|
90
|
+
}
|
|
91
|
+
|
|
59
92
|
function shouldUseInteractiveInit(options) {
|
|
60
93
|
if (options.lang && options.platform) {
|
|
61
94
|
return false;
|
|
@@ -107,10 +140,31 @@ async function main() {
|
|
|
107
140
|
return;
|
|
108
141
|
}
|
|
109
142
|
|
|
110
|
-
if (!["init", "install"].includes(command)) {
|
|
143
|
+
if (!["init", "install", "update"].includes(command)) {
|
|
111
144
|
throw new Error(`Unknown command: ${command}`);
|
|
112
145
|
}
|
|
113
146
|
|
|
147
|
+
if (command === "update") {
|
|
148
|
+
const options = parseUpdateArgs(rest);
|
|
149
|
+
if (options.allProjects) {
|
|
150
|
+
const result = updateAllProjects();
|
|
151
|
+
console.log(`updated projects: ${result.updated.length}`);
|
|
152
|
+
for (const project of result.updated) {
|
|
153
|
+
console.log(`updated: ${project}`);
|
|
154
|
+
}
|
|
155
|
+
for (const project of result.skipped) {
|
|
156
|
+
console.log(`skipped: ${project.path} (${project.reason})`);
|
|
157
|
+
}
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
const metadata = updateSuperlabProject({ targetDir: options.targetDir });
|
|
162
|
+
console.log(`superlab updated in ${options.targetDir}`);
|
|
163
|
+
console.log(`platform: ${metadata.platform}`);
|
|
164
|
+
console.log(`language: ${metadata.lang}`);
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
|
|
114
168
|
const parsedOptions = parseInstallArgs(rest);
|
|
115
169
|
const options = await resolveInitOptions(parsedOptions);
|
|
116
170
|
if (options.platform === "all") {
|
package/lib/install.cjs
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
const fs = require("node:fs");
|
|
2
|
+
const os = require("node:os");
|
|
2
3
|
const path = require("node:path");
|
|
3
4
|
const { getLocalizedContent } = require("./i18n.cjs");
|
|
4
5
|
|
|
5
6
|
const REPO_ROOT = path.resolve(__dirname, "..");
|
|
7
|
+
const PACKAGE_VERSION = require(path.join(REPO_ROOT, "package.json")).version;
|
|
6
8
|
|
|
7
9
|
const ASSET_GROUPS = {
|
|
8
10
|
codex: [
|
|
@@ -102,6 +104,72 @@ function chmodScripts(targetDir) {
|
|
|
102
104
|
}
|
|
103
105
|
}
|
|
104
106
|
|
|
107
|
+
function superlabHomeDir({ env = process.env } = {}) {
|
|
108
|
+
if (env.SUPERLAB_HOME) {
|
|
109
|
+
return env.SUPERLAB_HOME;
|
|
110
|
+
}
|
|
111
|
+
return path.join(env.HOME || os.homedir(), ".superlab");
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
function registryFilePath({ env = process.env } = {}) {
|
|
115
|
+
return path.join(superlabHomeDir({ env }), "registry.json");
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
function installMetadataPath(targetDir) {
|
|
119
|
+
return path.join(targetDir, ".superlab", "install.json");
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
function ensureParentDir(filePath) {
|
|
123
|
+
fs.mkdirSync(path.dirname(filePath), { recursive: true });
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
function writeProjectInstallMetadata(targetDir, metadata) {
|
|
127
|
+
const filePath = installMetadataPath(targetDir);
|
|
128
|
+
ensureParentDir(filePath);
|
|
129
|
+
fs.writeFileSync(filePath, JSON.stringify(metadata, null, 2) + "\n");
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
function readProjectInstallMetadata(targetDir) {
|
|
133
|
+
const filePath = installMetadataPath(targetDir);
|
|
134
|
+
if (!fs.existsSync(filePath)) {
|
|
135
|
+
throw new Error(`No superlab installation metadata found in ${targetDir}. Run 'superlab init' first.`);
|
|
136
|
+
}
|
|
137
|
+
return JSON.parse(fs.readFileSync(filePath, "utf8"));
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
function readRegistry({ env = process.env } = {}) {
|
|
141
|
+
const filePath = registryFilePath({ env });
|
|
142
|
+
if (!fs.existsSync(filePath)) {
|
|
143
|
+
return { projects: [] };
|
|
144
|
+
}
|
|
145
|
+
return JSON.parse(fs.readFileSync(filePath, "utf8"));
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
function writeRegistry(registry, { env = process.env } = {}) {
|
|
149
|
+
const filePath = registryFilePath({ env });
|
|
150
|
+
ensureParentDir(filePath);
|
|
151
|
+
fs.writeFileSync(filePath, JSON.stringify(registry, null, 2) + "\n");
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
function registerProjectInstall(targetDir, metadata, { env = process.env } = {}) {
|
|
155
|
+
const registry = readRegistry({ env });
|
|
156
|
+
const normalizedTarget = path.resolve(targetDir);
|
|
157
|
+
const entry = {
|
|
158
|
+
path: normalizedTarget,
|
|
159
|
+
platform: metadata.platform,
|
|
160
|
+
lang: metadata.lang,
|
|
161
|
+
package_version: metadata.package_version,
|
|
162
|
+
updated_at: metadata.updated_at,
|
|
163
|
+
};
|
|
164
|
+
const existingIndex = registry.projects.findIndex((project) => project.path === normalizedTarget);
|
|
165
|
+
if (existingIndex >= 0) {
|
|
166
|
+
registry.projects[existingIndex] = entry;
|
|
167
|
+
} else {
|
|
168
|
+
registry.projects.push(entry);
|
|
169
|
+
}
|
|
170
|
+
writeRegistry(registry, { env });
|
|
171
|
+
}
|
|
172
|
+
|
|
105
173
|
function detectLanguage({ explicitLang, env = process.env } = {}) {
|
|
106
174
|
if (explicitLang) {
|
|
107
175
|
if (!["en", "zh"].includes(explicitLang)) {
|
|
@@ -175,7 +243,7 @@ function localizeInstalledAssets(targetDir, lang) {
|
|
|
175
243
|
}
|
|
176
244
|
}
|
|
177
245
|
|
|
178
|
-
function installSuperlab({ targetDir, platform = "both", force = false, lang } = {}) {
|
|
246
|
+
function installSuperlab({ targetDir, platform = "both", force = false, lang, env = process.env } = {}) {
|
|
179
247
|
const groups = [];
|
|
180
248
|
if (platform === "codex" || platform === "both") {
|
|
181
249
|
groups.push(...ASSET_GROUPS.codex);
|
|
@@ -188,11 +256,60 @@ function installSuperlab({ targetDir, platform = "both", force = false, lang } =
|
|
|
188
256
|
for (const asset of groups) {
|
|
189
257
|
copyDirectory(asset.from, path.join(targetDir, asset.to), force);
|
|
190
258
|
}
|
|
191
|
-
|
|
259
|
+
const resolvedLang = detectLanguage({ explicitLang: lang, env });
|
|
260
|
+
localizeInstalledAssets(targetDir, resolvedLang);
|
|
192
261
|
chmodScripts(targetDir);
|
|
262
|
+
const metadata = {
|
|
263
|
+
target_dir: path.resolve(targetDir),
|
|
264
|
+
platform,
|
|
265
|
+
lang: resolvedLang,
|
|
266
|
+
package_version: PACKAGE_VERSION,
|
|
267
|
+
updated_at: new Date().toISOString(),
|
|
268
|
+
};
|
|
269
|
+
writeProjectInstallMetadata(targetDir, metadata);
|
|
270
|
+
registerProjectInstall(targetDir, metadata, { env });
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
function updateSuperlabProject({ targetDir, env = process.env } = {}) {
|
|
274
|
+
const metadata = readProjectInstallMetadata(targetDir);
|
|
275
|
+
installSuperlab({
|
|
276
|
+
targetDir,
|
|
277
|
+
platform: metadata.platform,
|
|
278
|
+
lang: metadata.lang,
|
|
279
|
+
force: true,
|
|
280
|
+
env,
|
|
281
|
+
});
|
|
282
|
+
return metadata;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
function updateAllProjects({ env = process.env } = {}) {
|
|
286
|
+
const registry = readRegistry({ env });
|
|
287
|
+
const updated = [];
|
|
288
|
+
const skipped = [];
|
|
289
|
+
|
|
290
|
+
for (const project of registry.projects) {
|
|
291
|
+
try {
|
|
292
|
+
if (!fs.existsSync(project.path)) {
|
|
293
|
+
skipped.push({ path: project.path, reason: "missing project path" });
|
|
294
|
+
continue;
|
|
295
|
+
}
|
|
296
|
+
updateSuperlabProject({ targetDir: project.path, env });
|
|
297
|
+
updated.push(project.path);
|
|
298
|
+
} catch (error) {
|
|
299
|
+
skipped.push({ path: project.path, reason: error.message });
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
return { updated, skipped };
|
|
193
304
|
}
|
|
194
305
|
|
|
195
306
|
module.exports = {
|
|
196
307
|
detectLanguage,
|
|
197
308
|
installSuperlab,
|
|
309
|
+
installMetadataPath,
|
|
310
|
+
readProjectInstallMetadata,
|
|
311
|
+
registryFilePath,
|
|
312
|
+
readRegistry,
|
|
313
|
+
updateAllProjects,
|
|
314
|
+
updateSuperlabProject,
|
|
198
315
|
};
|