superlab 0.1.4 → 0.1.6
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 +119 -3
- package/lib/install.cjs +272 -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,14 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
const path = require("node:path");
|
|
4
|
-
const {
|
|
4
|
+
const {
|
|
5
|
+
PACKAGE_VERSION,
|
|
6
|
+
detectLanguage,
|
|
7
|
+
getProjectVersionInfo,
|
|
8
|
+
installSuperlab,
|
|
9
|
+
updateAllProjects,
|
|
10
|
+
updateSuperlabProject,
|
|
11
|
+
} = require("../lib/install.cjs");
|
|
5
12
|
const { promptSelect } = require("../lib/init_tui.cjs");
|
|
6
13
|
|
|
7
14
|
function printHelp() {
|
|
@@ -10,10 +17,15 @@ function printHelp() {
|
|
|
10
17
|
Usage:
|
|
11
18
|
superlab init [--target <dir>] [--platform codex|claude|both|all] [--lang en|zh] [--force]
|
|
12
19
|
superlab install [--target <dir>] [--platform codex|claude|both|all] [--lang en|zh] [--force]
|
|
20
|
+
superlab update [--target <dir>]
|
|
21
|
+
superlab update --all-projects
|
|
22
|
+
superlab version [--target <dir>] [--global|--project]
|
|
13
23
|
|
|
14
24
|
Commands:
|
|
15
25
|
init Initialize /lab commands, skills, templates, and scripts in a target
|
|
16
26
|
install Backward-compatible alias for init
|
|
27
|
+
update Refresh an initialized project or all registered projects
|
|
28
|
+
version Show installed CLI version and project asset version
|
|
17
29
|
help Show this help message
|
|
18
30
|
`);
|
|
19
31
|
}
|
|
@@ -56,6 +68,81 @@ function parseInstallArgs(argv) {
|
|
|
56
68
|
return options;
|
|
57
69
|
}
|
|
58
70
|
|
|
71
|
+
function parseUpdateArgs(argv) {
|
|
72
|
+
const options = {
|
|
73
|
+
targetDir: process.cwd(),
|
|
74
|
+
allProjects: false,
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
for (let index = 0; index < argv.length; index += 1) {
|
|
78
|
+
const value = argv[index];
|
|
79
|
+
if (value === "--target") {
|
|
80
|
+
options.targetDir = path.resolve(argv[index + 1]);
|
|
81
|
+
index += 1;
|
|
82
|
+
} else if (value === "--all-projects") {
|
|
83
|
+
options.allProjects = true;
|
|
84
|
+
} else {
|
|
85
|
+
throw new Error(`Unknown option: ${value}`);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
if (options.allProjects && argv.includes("--target")) {
|
|
90
|
+
throw new Error("Use either --target or --all-projects, not both.");
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
return options;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function parseVersionArgs(argv) {
|
|
97
|
+
const options = {
|
|
98
|
+
targetDir: process.cwd(),
|
|
99
|
+
globalOnly: false,
|
|
100
|
+
projectOnly: false,
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
for (let index = 0; index < argv.length; index += 1) {
|
|
104
|
+
const value = argv[index];
|
|
105
|
+
if (value === "--target") {
|
|
106
|
+
options.targetDir = path.resolve(argv[index + 1]);
|
|
107
|
+
index += 1;
|
|
108
|
+
} else if (value === "--global") {
|
|
109
|
+
options.globalOnly = true;
|
|
110
|
+
} else if (value === "--project") {
|
|
111
|
+
options.projectOnly = true;
|
|
112
|
+
} else {
|
|
113
|
+
throw new Error(`Unknown option: ${value}`);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
if (options.globalOnly && options.projectOnly) {
|
|
118
|
+
throw new Error("Use either --global or --project, not both.");
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
return options;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
function printVersion(options) {
|
|
125
|
+
const lines = [];
|
|
126
|
+
if (!options.projectOnly) {
|
|
127
|
+
lines.push(`cli: ${PACKAGE_VERSION}`);
|
|
128
|
+
}
|
|
129
|
+
if (!options.globalOnly) {
|
|
130
|
+
const projectInfo = getProjectVersionInfo({ targetDir: options.targetDir });
|
|
131
|
+
if (projectInfo.status === "managed") {
|
|
132
|
+
lines.push(`project: ${projectInfo.package_version}`);
|
|
133
|
+
lines.push(`platform: ${projectInfo.platform}`);
|
|
134
|
+
lines.push(`language: ${projectInfo.lang}`);
|
|
135
|
+
} else if (projectInfo.status === "legacy") {
|
|
136
|
+
lines.push("project: legacy");
|
|
137
|
+
lines.push(`platform: ${projectInfo.platform}`);
|
|
138
|
+
lines.push(`language: ${projectInfo.lang}`);
|
|
139
|
+
} else {
|
|
140
|
+
lines.push("project: not initialized");
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
console.log(lines.join("\n"));
|
|
144
|
+
}
|
|
145
|
+
|
|
59
146
|
function shouldUseInteractiveInit(options) {
|
|
60
147
|
if (options.lang && options.platform) {
|
|
61
148
|
return false;
|
|
@@ -107,16 +194,45 @@ async function main() {
|
|
|
107
194
|
return;
|
|
108
195
|
}
|
|
109
196
|
|
|
110
|
-
if (!["init", "install"].includes(command)) {
|
|
197
|
+
if (!["init", "install", "update", "version"].includes(command)) {
|
|
111
198
|
throw new Error(`Unknown command: ${command}`);
|
|
112
199
|
}
|
|
113
200
|
|
|
201
|
+
if (command === "version") {
|
|
202
|
+
printVersion(parseVersionArgs(rest));
|
|
203
|
+
return;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
if (command === "update") {
|
|
207
|
+
const options = parseUpdateArgs(rest);
|
|
208
|
+
if (options.allProjects) {
|
|
209
|
+
const result = updateAllProjects();
|
|
210
|
+
console.log(`updated projects: ${result.updated.length}`);
|
|
211
|
+
for (const project of result.updated) {
|
|
212
|
+
console.log(`updated: ${project}`);
|
|
213
|
+
}
|
|
214
|
+
for (const project of result.skipped) {
|
|
215
|
+
console.log(`skipped: ${project.path} (${project.reason})`);
|
|
216
|
+
}
|
|
217
|
+
return;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
const metadata = updateSuperlabProject({ targetDir: options.targetDir });
|
|
221
|
+
console.log(`superlab updated in ${options.targetDir}`);
|
|
222
|
+
console.log(`platform: ${metadata.platform}`);
|
|
223
|
+
console.log(`language: ${metadata.lang}`);
|
|
224
|
+
if (metadata.migration) {
|
|
225
|
+
console.log(`migration: ${metadata.migration}`);
|
|
226
|
+
}
|
|
227
|
+
return;
|
|
228
|
+
}
|
|
229
|
+
|
|
114
230
|
const parsedOptions = parseInstallArgs(rest);
|
|
115
231
|
const options = await resolveInitOptions(parsedOptions);
|
|
116
232
|
if (options.platform === "all") {
|
|
117
233
|
options.platform = "both";
|
|
118
234
|
}
|
|
119
|
-
installSuperlab(options);
|
|
235
|
+
installSuperlab({ ...options, registerProject: true });
|
|
120
236
|
console.log(`superlab installed into ${options.targetDir}`);
|
|
121
237
|
console.log(`platform: ${options.platform}`);
|
|
122
238
|
console.log(`language: ${options.lang}`);
|
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,152 @@ 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 detectLegacyPlatform(targetDir) {
|
|
141
|
+
const hasCodex =
|
|
142
|
+
fs.existsSync(path.join(targetDir, ".codex", "prompts")) ||
|
|
143
|
+
fs.existsSync(path.join(targetDir, ".codex", "skills", "lab"));
|
|
144
|
+
const hasClaude =
|
|
145
|
+
fs.existsSync(path.join(targetDir, ".claude", "commands", "lab")) ||
|
|
146
|
+
fs.existsSync(path.join(targetDir, ".claude", "skills", "lab"));
|
|
147
|
+
|
|
148
|
+
if (hasCodex && hasClaude) {
|
|
149
|
+
return "both";
|
|
150
|
+
}
|
|
151
|
+
if (hasCodex) {
|
|
152
|
+
return "codex";
|
|
153
|
+
}
|
|
154
|
+
if (hasClaude) {
|
|
155
|
+
return "claude";
|
|
156
|
+
}
|
|
157
|
+
return null;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
function looksChinese(text) {
|
|
161
|
+
return /[\u3400-\u9fff]/.test(text);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
function detectLegacyLanguage(targetDir) {
|
|
165
|
+
const workflowConfigPath = path.join(targetDir, ".superlab", "config", "workflow.json");
|
|
166
|
+
if (fs.existsSync(workflowConfigPath)) {
|
|
167
|
+
try {
|
|
168
|
+
const config = JSON.parse(fs.readFileSync(workflowConfigPath, "utf8"));
|
|
169
|
+
if (config.workflow_language === "zh" || config.workflow_language === "en") {
|
|
170
|
+
return config.workflow_language;
|
|
171
|
+
}
|
|
172
|
+
} catch {
|
|
173
|
+
// Fall through to file-content heuristics.
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
const probeFiles = [
|
|
178
|
+
path.join(targetDir, ".codex", "prompts", "lab-idea.md"),
|
|
179
|
+
path.join(targetDir, ".claude", "commands", "lab", "idea.md"),
|
|
180
|
+
path.join(targetDir, ".superlab", "templates", "idea.md"),
|
|
181
|
+
];
|
|
182
|
+
|
|
183
|
+
for (const probeFile of probeFiles) {
|
|
184
|
+
if (!fs.existsSync(probeFile)) {
|
|
185
|
+
continue;
|
|
186
|
+
}
|
|
187
|
+
const content = fs.readFileSync(probeFile, "utf8");
|
|
188
|
+
return looksChinese(content) ? "zh" : "en";
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
return "en";
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
function detectLegacyInstallMetadata(targetDir) {
|
|
195
|
+
const platform = detectLegacyPlatform(targetDir);
|
|
196
|
+
if (!platform) {
|
|
197
|
+
return null;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
return {
|
|
201
|
+
target_dir: path.resolve(targetDir),
|
|
202
|
+
platform,
|
|
203
|
+
lang: detectLegacyLanguage(targetDir),
|
|
204
|
+
package_version: "legacy",
|
|
205
|
+
updated_at: null,
|
|
206
|
+
legacy: true,
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
function readRegistry({ env = process.env } = {}) {
|
|
211
|
+
const filePath = registryFilePath({ env });
|
|
212
|
+
if (!fs.existsSync(filePath)) {
|
|
213
|
+
return { projects: [] };
|
|
214
|
+
}
|
|
215
|
+
return JSON.parse(fs.readFileSync(filePath, "utf8"));
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
function writeRegistry(registry, { env = process.env } = {}) {
|
|
219
|
+
const filePath = registryFilePath({ env });
|
|
220
|
+
ensureParentDir(filePath);
|
|
221
|
+
fs.writeFileSync(filePath, JSON.stringify(registry, null, 2) + "\n");
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
function registerProjectInstall(targetDir, metadata, { env = process.env } = {}) {
|
|
225
|
+
const registry = readRegistry({ env });
|
|
226
|
+
const normalizedTarget = path.resolve(targetDir);
|
|
227
|
+
const entry = {
|
|
228
|
+
path: normalizedTarget,
|
|
229
|
+
platform: metadata.platform,
|
|
230
|
+
lang: metadata.lang,
|
|
231
|
+
package_version: metadata.package_version,
|
|
232
|
+
updated_at: metadata.updated_at,
|
|
233
|
+
};
|
|
234
|
+
const existingIndex = registry.projects.findIndex((project) => project.path === normalizedTarget);
|
|
235
|
+
if (existingIndex >= 0) {
|
|
236
|
+
registry.projects[existingIndex] = entry;
|
|
237
|
+
} else {
|
|
238
|
+
registry.projects.push(entry);
|
|
239
|
+
}
|
|
240
|
+
writeRegistry(registry, { env });
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
function isTemporaryTestPath(targetDir) {
|
|
244
|
+
const resolvedTarget = path.resolve(targetDir);
|
|
245
|
+
const tmpRoot = path.resolve(os.tmpdir());
|
|
246
|
+
const relativeToTmp = path.relative(tmpRoot, resolvedTarget);
|
|
247
|
+
if (relativeToTmp.startsWith("..") || path.isAbsolute(relativeToTmp)) {
|
|
248
|
+
return false;
|
|
249
|
+
}
|
|
250
|
+
return path.basename(resolvedTarget).startsWith("superlab-");
|
|
251
|
+
}
|
|
252
|
+
|
|
105
253
|
function detectLanguage({ explicitLang, env = process.env } = {}) {
|
|
106
254
|
if (explicitLang) {
|
|
107
255
|
if (!["en", "zh"].includes(explicitLang)) {
|
|
@@ -175,7 +323,14 @@ function localizeInstalledAssets(targetDir, lang) {
|
|
|
175
323
|
}
|
|
176
324
|
}
|
|
177
325
|
|
|
178
|
-
function installSuperlab({
|
|
326
|
+
function installSuperlab({
|
|
327
|
+
targetDir,
|
|
328
|
+
platform = "both",
|
|
329
|
+
force = false,
|
|
330
|
+
lang,
|
|
331
|
+
env = process.env,
|
|
332
|
+
registerProject = false,
|
|
333
|
+
} = {}) {
|
|
179
334
|
const groups = [];
|
|
180
335
|
if (platform === "codex" || platform === "both") {
|
|
181
336
|
groups.push(...ASSET_GROUPS.codex);
|
|
@@ -188,11 +343,126 @@ function installSuperlab({ targetDir, platform = "both", force = false, lang } =
|
|
|
188
343
|
for (const asset of groups) {
|
|
189
344
|
copyDirectory(asset.from, path.join(targetDir, asset.to), force);
|
|
190
345
|
}
|
|
191
|
-
|
|
346
|
+
const resolvedLang = detectLanguage({ explicitLang: lang, env });
|
|
347
|
+
localizeInstalledAssets(targetDir, resolvedLang);
|
|
192
348
|
chmodScripts(targetDir);
|
|
349
|
+
const metadata = {
|
|
350
|
+
target_dir: path.resolve(targetDir),
|
|
351
|
+
platform,
|
|
352
|
+
lang: resolvedLang,
|
|
353
|
+
package_version: PACKAGE_VERSION,
|
|
354
|
+
updated_at: new Date().toISOString(),
|
|
355
|
+
};
|
|
356
|
+
writeProjectInstallMetadata(targetDir, metadata);
|
|
357
|
+
if (registerProject) {
|
|
358
|
+
registerProjectInstall(targetDir, metadata, { env });
|
|
359
|
+
}
|
|
360
|
+
return metadata;
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
function updateSuperlabProject({ targetDir, env = process.env } = {}) {
|
|
364
|
+
let metadata;
|
|
365
|
+
let migratedLegacy = false;
|
|
366
|
+
try {
|
|
367
|
+
metadata = readProjectInstallMetadata(targetDir);
|
|
368
|
+
} catch (error) {
|
|
369
|
+
metadata = detectLegacyInstallMetadata(targetDir);
|
|
370
|
+
if (!metadata) {
|
|
371
|
+
throw error;
|
|
372
|
+
}
|
|
373
|
+
migratedLegacy = true;
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
const installedMetadata = installSuperlab({
|
|
377
|
+
targetDir,
|
|
378
|
+
platform: metadata.platform,
|
|
379
|
+
lang: metadata.lang,
|
|
380
|
+
force: true,
|
|
381
|
+
env,
|
|
382
|
+
registerProject: true,
|
|
383
|
+
});
|
|
384
|
+
if (migratedLegacy) {
|
|
385
|
+
installedMetadata.migration = "legacy project metadata reconstructed";
|
|
386
|
+
}
|
|
387
|
+
return installedMetadata;
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
function updateAllProjects({ env = process.env } = {}) {
|
|
391
|
+
const registry = readRegistry({ env });
|
|
392
|
+
const updated = [];
|
|
393
|
+
const skipped = [];
|
|
394
|
+
const retained = [];
|
|
395
|
+
|
|
396
|
+
for (const project of registry.projects) {
|
|
397
|
+
try {
|
|
398
|
+
if (isTemporaryTestPath(project.path)) {
|
|
399
|
+
skipped.push({ path: project.path, reason: "temporary path pruned from registry" });
|
|
400
|
+
continue;
|
|
401
|
+
}
|
|
402
|
+
if (!fs.existsSync(project.path)) {
|
|
403
|
+
skipped.push({ path: project.path, reason: "missing project path" });
|
|
404
|
+
continue;
|
|
405
|
+
}
|
|
406
|
+
const metadata = updateSuperlabProject({ targetDir: project.path, env });
|
|
407
|
+
updated.push(project.path);
|
|
408
|
+
retained.push({
|
|
409
|
+
path: path.resolve(project.path),
|
|
410
|
+
platform: metadata.platform,
|
|
411
|
+
lang: metadata.lang,
|
|
412
|
+
package_version: metadata.package_version,
|
|
413
|
+
updated_at: metadata.updated_at,
|
|
414
|
+
});
|
|
415
|
+
} catch (error) {
|
|
416
|
+
skipped.push({ path: project.path, reason: error.message });
|
|
417
|
+
if (fs.existsSync(project.path)) {
|
|
418
|
+
retained.push(project);
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
writeRegistry({ projects: retained }, { env });
|
|
424
|
+
return { updated, skipped };
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
function getProjectVersionInfo({ targetDir } = {}) {
|
|
428
|
+
try {
|
|
429
|
+
const metadata = readProjectInstallMetadata(targetDir);
|
|
430
|
+
return {
|
|
431
|
+
status: "managed",
|
|
432
|
+
package_version: metadata.package_version,
|
|
433
|
+
platform: metadata.platform,
|
|
434
|
+
lang: metadata.lang,
|
|
435
|
+
};
|
|
436
|
+
} catch {
|
|
437
|
+
const legacyMetadata = detectLegacyInstallMetadata(targetDir);
|
|
438
|
+
if (!legacyMetadata) {
|
|
439
|
+
return {
|
|
440
|
+
status: "missing",
|
|
441
|
+
package_version: null,
|
|
442
|
+
platform: null,
|
|
443
|
+
lang: null,
|
|
444
|
+
};
|
|
445
|
+
}
|
|
446
|
+
return {
|
|
447
|
+
status: "legacy",
|
|
448
|
+
package_version: "legacy",
|
|
449
|
+
platform: legacyMetadata.platform,
|
|
450
|
+
lang: legacyMetadata.lang,
|
|
451
|
+
};
|
|
452
|
+
}
|
|
193
453
|
}
|
|
194
454
|
|
|
195
455
|
module.exports = {
|
|
456
|
+
PACKAGE_VERSION,
|
|
196
457
|
detectLanguage,
|
|
458
|
+
detectLegacyInstallMetadata,
|
|
197
459
|
installSuperlab,
|
|
460
|
+
installMetadataPath,
|
|
461
|
+
isTemporaryTestPath,
|
|
462
|
+
getProjectVersionInfo,
|
|
463
|
+
readProjectInstallMetadata,
|
|
464
|
+
registryFilePath,
|
|
465
|
+
readRegistry,
|
|
466
|
+
updateAllProjects,
|
|
467
|
+
updateSuperlabProject,
|
|
198
468
|
};
|