teamix-evo 0.3.0 → 0.4.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 +16 -16
- package/dist/core/index.d.ts +59 -29
- package/dist/core/index.js +296 -256
- package/dist/core/index.js.map +1 -1
- package/dist/index.js +1051 -403
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
package/dist/index.js
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
// src/index.ts
|
|
4
|
-
import { Command as
|
|
5
|
-
import { createRequire as
|
|
4
|
+
import { Command as Command28 } from "commander";
|
|
5
|
+
import { createRequire as createRequire8 } from "module";
|
|
6
6
|
|
|
7
|
-
// src/commands/
|
|
7
|
+
// src/commands/tokens/index.ts
|
|
8
8
|
import { Command as Command6 } from "commander";
|
|
9
9
|
|
|
10
|
-
// src/commands/
|
|
10
|
+
// src/commands/tokens/init.ts
|
|
11
11
|
import { Command } from "commander";
|
|
12
12
|
|
|
13
13
|
// src/ide/QoderAdapter.ts
|
|
@@ -66,14 +66,13 @@ function detectIde() {
|
|
|
66
66
|
return new QoderAdapter();
|
|
67
67
|
}
|
|
68
68
|
|
|
69
|
-
// src/core/
|
|
70
|
-
import * as
|
|
69
|
+
// src/core/tokens-init.ts
|
|
70
|
+
import * as path8 from "path";
|
|
71
71
|
import * as fs6 from "fs/promises";
|
|
72
72
|
import { createRequire as createRequire2 } from "module";
|
|
73
73
|
import {
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
mergeDefaultAndVariant
|
|
74
|
+
loadTokensPackageManifest,
|
|
75
|
+
getVariantEntry
|
|
77
76
|
} from "@teamix-evo/registry";
|
|
78
77
|
|
|
79
78
|
// src/utils/fs.ts
|
|
@@ -158,71 +157,22 @@ function computeHash(content) {
|
|
|
158
157
|
return `sha256:${hash}`;
|
|
159
158
|
}
|
|
160
159
|
|
|
161
|
-
// src/core/design-pack-classify.ts
|
|
162
|
-
import * as path4 from "path";
|
|
163
|
-
var TEAMIX_DIR = ".teamix-evo/design";
|
|
164
|
-
var TOKENS_DIR = ".teamix-evo/tokens";
|
|
165
|
-
var TOKENS_PACK_PREFIX = "foundations/tokens/";
|
|
166
|
-
var ROOT_MANAGED_FILES = {
|
|
167
|
-
"DESIGN.md": { target: "DESIGN.md", managedRegions: ["core"] },
|
|
168
|
-
"AGENTS.md": { target: "AGENTS.md", managedRegions: ["teamix-evo"] },
|
|
169
|
-
"CLAUDE.md": { target: "CLAUDE.md", managedRegions: ["teamix-evo"] }
|
|
170
|
-
};
|
|
171
|
-
var FROZEN_FILES = /* @__PURE__ */ new Set([
|
|
172
|
-
"foundations/tokens/tokens.overrides.css"
|
|
173
|
-
]);
|
|
174
|
-
function classifyPackFile(relPath) {
|
|
175
|
-
if (path4.basename(relPath) === "README.md") {
|
|
176
|
-
return null;
|
|
177
|
-
}
|
|
178
|
-
const rootManaged = ROOT_MANAGED_FILES[relPath];
|
|
179
|
-
if (rootManaged) {
|
|
180
|
-
return {
|
|
181
|
-
target: rootManaged.target,
|
|
182
|
-
strategy: "managed",
|
|
183
|
-
managedRegions: rootManaged.managedRegions,
|
|
184
|
-
isFrozen: false
|
|
185
|
-
};
|
|
186
|
-
}
|
|
187
|
-
if (relPath.startsWith(TOKENS_PACK_PREFIX)) {
|
|
188
|
-
const rel2 = relPath.slice(TOKENS_PACK_PREFIX.length);
|
|
189
|
-
const target = path4.posix.join(TOKENS_DIR, rel2);
|
|
190
|
-
if (FROZEN_FILES.has(relPath)) {
|
|
191
|
-
return { target, strategy: "frozen", isFrozen: true };
|
|
192
|
-
}
|
|
193
|
-
return { target, strategy: "regenerable", isFrozen: false };
|
|
194
|
-
}
|
|
195
|
-
if (FROZEN_FILES.has(relPath)) {
|
|
196
|
-
return {
|
|
197
|
-
target: path4.posix.join(TEAMIX_DIR, relPath),
|
|
198
|
-
strategy: "frozen",
|
|
199
|
-
isFrozen: true
|
|
200
|
-
};
|
|
201
|
-
}
|
|
202
|
-
return {
|
|
203
|
-
target: path4.posix.join(TEAMIX_DIR, relPath),
|
|
204
|
-
strategy: "regenerable",
|
|
205
|
-
isFrozen: false
|
|
206
|
-
};
|
|
207
|
-
}
|
|
208
|
-
|
|
209
160
|
// src/core/state.ts
|
|
210
|
-
import * as
|
|
161
|
+
import * as path4 from "path";
|
|
211
162
|
import {
|
|
212
163
|
validateConfig,
|
|
213
164
|
validateInstalled,
|
|
214
165
|
validateSkillsLock,
|
|
215
|
-
|
|
166
|
+
TokensPackLockSchema
|
|
216
167
|
} from "@teamix-evo/registry";
|
|
217
|
-
var
|
|
168
|
+
var TEAMIX_DIR = ".teamix-evo";
|
|
218
169
|
var CONFIG_FILE = "config.json";
|
|
219
170
|
var MANIFEST_FILE = "manifest.json";
|
|
220
|
-
var
|
|
221
|
-
var DESIGN_LOCK_FILE = "pack.lock.json";
|
|
171
|
+
var TOKENS_LOCK_FILE = "tokens-lock.json";
|
|
222
172
|
var SKILLS_DIR = "skills";
|
|
223
173
|
var SKILLS_LOCK_FILE = "manifest.lock.json";
|
|
224
174
|
function getTeamixDir(projectRoot) {
|
|
225
|
-
return
|
|
175
|
+
return path4.join(projectRoot, TEAMIX_DIR);
|
|
226
176
|
}
|
|
227
177
|
async function ensureTeamixDir(projectRoot) {
|
|
228
178
|
const dir = getTeamixDir(projectRoot);
|
|
@@ -230,84 +180,85 @@ async function ensureTeamixDir(projectRoot) {
|
|
|
230
180
|
return dir;
|
|
231
181
|
}
|
|
232
182
|
async function readProjectConfig(projectRoot) {
|
|
233
|
-
const configPath =
|
|
183
|
+
const configPath = path4.join(projectRoot, TEAMIX_DIR, CONFIG_FILE);
|
|
234
184
|
const raw = await readFileOrNull(configPath);
|
|
235
185
|
if (raw === null) return null;
|
|
186
|
+
let data;
|
|
236
187
|
try {
|
|
237
|
-
|
|
238
|
-
const result = validateConfig(data);
|
|
239
|
-
if (!result.success) {
|
|
240
|
-
logger.warn(`Invalid config.json: ${result.error}`);
|
|
241
|
-
return null;
|
|
242
|
-
}
|
|
243
|
-
return result.data;
|
|
188
|
+
data = JSON.parse(raw);
|
|
244
189
|
} catch (err) {
|
|
245
|
-
|
|
246
|
-
|
|
190
|
+
throw new Error(
|
|
191
|
+
`Corrupted config.json (${err.message}). Fix the JSON manually or remove the file to start fresh; refusing to clobber prior config.`
|
|
192
|
+
);
|
|
193
|
+
}
|
|
194
|
+
const result = validateConfig(data);
|
|
195
|
+
if (!result.success) {
|
|
196
|
+
throw new Error(
|
|
197
|
+
`Invalid config.json schema: ${result.error}. Fix the file manually or remove it to start fresh.`
|
|
198
|
+
);
|
|
247
199
|
}
|
|
200
|
+
return result.data;
|
|
248
201
|
}
|
|
249
202
|
async function writeProjectConfig(projectRoot, config) {
|
|
250
|
-
const configPath =
|
|
203
|
+
const configPath = path4.join(projectRoot, TEAMIX_DIR, CONFIG_FILE);
|
|
251
204
|
await writeFileSafe(configPath, JSON.stringify(config, null, 2) + "\n");
|
|
252
205
|
logger.debug(`Wrote config \u2192 ${configPath}`);
|
|
253
206
|
}
|
|
254
207
|
async function readInstalledManifest(projectRoot) {
|
|
255
|
-
const manifestPath =
|
|
208
|
+
const manifestPath = path4.join(projectRoot, TEAMIX_DIR, MANIFEST_FILE);
|
|
256
209
|
const raw = await readFileOrNull(manifestPath);
|
|
257
210
|
if (raw === null) return null;
|
|
211
|
+
let data;
|
|
258
212
|
try {
|
|
259
|
-
|
|
260
|
-
const result = validateInstalled(data);
|
|
261
|
-
if (!result.success) {
|
|
262
|
-
logger.warn(`Invalid manifest.json: ${result.error}`);
|
|
263
|
-
return null;
|
|
264
|
-
}
|
|
265
|
-
return result.data;
|
|
213
|
+
data = JSON.parse(raw);
|
|
266
214
|
} catch (err) {
|
|
267
|
-
|
|
268
|
-
|
|
215
|
+
throw new Error(
|
|
216
|
+
`Corrupted manifest.json (${err.message}). Fix the JSON manually or remove the file to start fresh; refusing to clobber prior install records.`
|
|
217
|
+
);
|
|
269
218
|
}
|
|
219
|
+
const result = validateInstalled(data);
|
|
220
|
+
if (!result.success) {
|
|
221
|
+
throw new Error(
|
|
222
|
+
`Invalid manifest.json schema: ${result.error}. Fix the file manually or remove it to start fresh.`
|
|
223
|
+
);
|
|
224
|
+
}
|
|
225
|
+
return result.data;
|
|
270
226
|
}
|
|
271
227
|
async function writeInstalledManifest(projectRoot, manifest) {
|
|
272
|
-
const manifestPath =
|
|
228
|
+
const manifestPath = path4.join(projectRoot, TEAMIX_DIR, MANIFEST_FILE);
|
|
273
229
|
await writeFileSafe(manifestPath, JSON.stringify(manifest, null, 2) + "\n");
|
|
274
230
|
logger.debug(`Wrote manifest \u2192 ${manifestPath}`);
|
|
275
231
|
}
|
|
276
|
-
async function
|
|
277
|
-
const lockPath =
|
|
278
|
-
projectRoot,
|
|
279
|
-
TEAMIX_DIR2,
|
|
280
|
-
DESIGN_DIR,
|
|
281
|
-
DESIGN_LOCK_FILE
|
|
282
|
-
);
|
|
232
|
+
async function readTokensLock(projectRoot) {
|
|
233
|
+
const lockPath = path4.join(projectRoot, TEAMIX_DIR, TOKENS_LOCK_FILE);
|
|
283
234
|
const raw = await readFileOrNull(lockPath);
|
|
284
235
|
if (raw === null) return null;
|
|
285
236
|
try {
|
|
286
|
-
const parsed =
|
|
237
|
+
const parsed = TokensPackLockSchema.safeParse(JSON.parse(raw));
|
|
287
238
|
if (!parsed.success) {
|
|
288
|
-
logger.warn(`Invalid
|
|
239
|
+
logger.warn(`Invalid tokens-lock.json: ${parsed.error.message}`);
|
|
289
240
|
return null;
|
|
290
241
|
}
|
|
291
242
|
return parsed.data;
|
|
292
243
|
} catch (err) {
|
|
293
244
|
logger.warn(
|
|
294
|
-
`Failed to parse
|
|
245
|
+
`Failed to parse tokens-lock.json: ${err.message}`
|
|
295
246
|
);
|
|
296
247
|
return null;
|
|
297
248
|
}
|
|
298
249
|
}
|
|
299
|
-
async function
|
|
300
|
-
const lock = await
|
|
250
|
+
async function readTokensVariant(projectRoot) {
|
|
251
|
+
const lock = await readTokensLock(projectRoot);
|
|
301
252
|
return lock?.variant.name ?? null;
|
|
302
253
|
}
|
|
303
254
|
function getSkillsSourceDir(projectRoot, skillName) {
|
|
304
|
-
const base =
|
|
305
|
-
return skillName ?
|
|
255
|
+
const base = path4.join(projectRoot, TEAMIX_DIR, SKILLS_DIR);
|
|
256
|
+
return skillName ? path4.join(base, skillName) : base;
|
|
306
257
|
}
|
|
307
258
|
async function readSkillsLock(projectRoot) {
|
|
308
|
-
const lockPath =
|
|
259
|
+
const lockPath = path4.join(
|
|
309
260
|
projectRoot,
|
|
310
|
-
|
|
261
|
+
TEAMIX_DIR,
|
|
311
262
|
SKILLS_DIR,
|
|
312
263
|
SKILLS_LOCK_FILE
|
|
313
264
|
);
|
|
@@ -329,9 +280,9 @@ async function readSkillsLock(projectRoot) {
|
|
|
329
280
|
}
|
|
330
281
|
}
|
|
331
282
|
async function writeSkillsLock(projectRoot, lock) {
|
|
332
|
-
const lockPath =
|
|
283
|
+
const lockPath = path4.join(
|
|
333
284
|
projectRoot,
|
|
334
|
-
|
|
285
|
+
TEAMIX_DIR,
|
|
335
286
|
SKILLS_DIR,
|
|
336
287
|
SKILLS_LOCK_FILE
|
|
337
288
|
);
|
|
@@ -340,21 +291,21 @@ async function writeSkillsLock(projectRoot, lock) {
|
|
|
340
291
|
}
|
|
341
292
|
|
|
342
293
|
// src/core/skills-client.ts
|
|
343
|
-
import * as
|
|
294
|
+
import * as path5 from "path";
|
|
344
295
|
import * as fs2 from "fs/promises";
|
|
345
296
|
import { createRequire } from "module";
|
|
346
297
|
import { loadSkillsPackageManifest } from "@teamix-evo/registry";
|
|
347
298
|
var require2 = createRequire(import.meta.url);
|
|
348
299
|
function resolvePackageRoot(packageName) {
|
|
349
300
|
const pkgJsonPath = require2.resolve(`${packageName}/package.json`);
|
|
350
|
-
return
|
|
301
|
+
return path5.dirname(pkgJsonPath);
|
|
351
302
|
}
|
|
352
303
|
async function loadSkillsData(packageName) {
|
|
353
304
|
const packageRoot = resolvePackageRoot(packageName);
|
|
354
305
|
logger.debug(`Resolved skills package root: ${packageRoot}`);
|
|
355
306
|
const manifest = await loadSkillsPackageManifest(packageRoot);
|
|
356
307
|
let data = {};
|
|
357
|
-
const dataPath =
|
|
308
|
+
const dataPath = path5.join(packageRoot, "_data.json");
|
|
358
309
|
try {
|
|
359
310
|
const raw = await fs2.readFile(dataPath, "utf-8");
|
|
360
311
|
data = JSON.parse(raw);
|
|
@@ -368,7 +319,7 @@ async function loadSkillsData(packageName) {
|
|
|
368
319
|
}
|
|
369
320
|
|
|
370
321
|
// src/core/skills-installer.ts
|
|
371
|
-
import * as
|
|
322
|
+
import * as path7 from "path";
|
|
372
323
|
import * as fs5 from "fs/promises";
|
|
373
324
|
import { replaceManagedRegion } from "@teamix-evo/registry";
|
|
374
325
|
|
|
@@ -401,13 +352,13 @@ async function loadTemplateFile(filePath) {
|
|
|
401
352
|
}
|
|
402
353
|
|
|
403
354
|
// src/utils/path.ts
|
|
404
|
-
import * as
|
|
355
|
+
import * as path6 from "path";
|
|
405
356
|
import * as fs4 from "fs/promises";
|
|
406
357
|
async function walkDir(dir) {
|
|
407
358
|
const files = [];
|
|
408
359
|
const entries = await fs4.readdir(dir, { withFileTypes: true });
|
|
409
360
|
for (const entry of entries) {
|
|
410
|
-
const fullPath =
|
|
361
|
+
const fullPath = path6.join(dir, entry.name);
|
|
411
362
|
if (entry.isDirectory()) {
|
|
412
363
|
files.push(...await walkDir(fullPath));
|
|
413
364
|
} else if (entry.isFile()) {
|
|
@@ -450,12 +401,12 @@ async function installSkills(options) {
|
|
|
450
401
|
}
|
|
451
402
|
async function writeSkillSource(skill, options) {
|
|
452
403
|
const { data, packageRoot, projectRoot } = options;
|
|
453
|
-
const sourceAbs =
|
|
404
|
+
const sourceAbs = path7.resolve(packageRoot, skill.source);
|
|
454
405
|
const targetDir = getSkillsSourceDir(projectRoot, skill.name);
|
|
455
406
|
const stat4 = await fs5.stat(sourceAbs);
|
|
456
407
|
const records = [];
|
|
457
408
|
if (stat4.isFile()) {
|
|
458
|
-
const targetFile =
|
|
409
|
+
const targetFile = path7.join(targetDir, "SKILL.md");
|
|
459
410
|
const content = await renderSkillContent(sourceAbs, skill, data);
|
|
460
411
|
await writeFileSafe(targetFile, content);
|
|
461
412
|
records.push(makeSourceRecord(skill, targetFile, content));
|
|
@@ -465,14 +416,14 @@ async function writeSkillSource(skill, options) {
|
|
|
465
416
|
await ensureDir(targetDir);
|
|
466
417
|
const entries = await walkDir(sourceAbs);
|
|
467
418
|
for (const entry of entries) {
|
|
468
|
-
const rel2 =
|
|
469
|
-
let targetFile =
|
|
419
|
+
const rel2 = path7.relative(sourceAbs, entry);
|
|
420
|
+
let targetFile = path7.join(targetDir, rel2);
|
|
470
421
|
if (skill.template && targetFile.endsWith(".hbs")) {
|
|
471
422
|
targetFile = targetFile.slice(0, -4);
|
|
472
423
|
}
|
|
473
424
|
const content = skill.template && entry.endsWith(".hbs") ? renderTemplate(await loadTemplateFile(entry), { ...data, skill }) : await fs5.readFile(entry, "utf-8");
|
|
474
425
|
await writeFileSafe(targetFile, content);
|
|
475
|
-
const relWritten =
|
|
426
|
+
const relWritten = path7.relative(targetDir, targetFile);
|
|
476
427
|
records.push(makeSourceRecord(skill, targetFile, content, relWritten));
|
|
477
428
|
logger.debug(` Wrote source: ${targetFile}`);
|
|
478
429
|
}
|
|
@@ -486,11 +437,19 @@ async function mirrorSkillToIde(skill, ide, scope, projectRoot) {
|
|
|
486
437
|
const sourceFiles = await walkDir(sourceDir);
|
|
487
438
|
await ensureDir(targetDir);
|
|
488
439
|
for (const src of sourceFiles) {
|
|
489
|
-
const rel2 =
|
|
490
|
-
const targetFile =
|
|
491
|
-
const
|
|
492
|
-
await
|
|
493
|
-
|
|
440
|
+
const rel2 = path7.relative(sourceDir, src);
|
|
441
|
+
const targetFile = path7.join(targetDir, rel2);
|
|
442
|
+
const sourceContent = await fs5.readFile(src, "utf-8");
|
|
443
|
+
const existing = await readFileOrNull(targetFile);
|
|
444
|
+
if (existing !== null && existing !== sourceContent) {
|
|
445
|
+
logger.warn(
|
|
446
|
+
`Mirror drift detected at ${targetFile} \u2014 overwriting from source. Edit ${src} (not the mirror) and re-run \`teamix-evo skills sync\`.`
|
|
447
|
+
);
|
|
448
|
+
}
|
|
449
|
+
await writeFileSafe(targetFile, sourceContent);
|
|
450
|
+
records.push(
|
|
451
|
+
makeMirrorRecord(skill, targetFile, sourceContent, ide, scope, rel2)
|
|
452
|
+
);
|
|
494
453
|
logger.debug(` Mirrored ${ide}:${scope}: ${targetFile}`);
|
|
495
454
|
}
|
|
496
455
|
return records;
|
|
@@ -549,7 +508,7 @@ async function updateSkills(options) {
|
|
|
549
508
|
}
|
|
550
509
|
async function rewriteSkillSource(skill, options, summary) {
|
|
551
510
|
const { data, packageRoot, projectRoot } = options;
|
|
552
|
-
const sourceAbs =
|
|
511
|
+
const sourceAbs = path7.resolve(packageRoot, skill.source);
|
|
553
512
|
const targetDir = getSkillsSourceDir(projectRoot, skill.name);
|
|
554
513
|
const stat4 = await fs5.stat(sourceAbs);
|
|
555
514
|
if (!stat4.isFile()) {
|
|
@@ -557,8 +516,8 @@ async function rewriteSkillSource(skill, options, summary) {
|
|
|
557
516
|
const entries = await walkDir(sourceAbs);
|
|
558
517
|
const records = [];
|
|
559
518
|
for (const entry of entries) {
|
|
560
|
-
const rel2 =
|
|
561
|
-
let targetFile2 =
|
|
519
|
+
const rel2 = path7.relative(sourceAbs, entry);
|
|
520
|
+
let targetFile2 = path7.join(targetDir, rel2);
|
|
562
521
|
if (skill.template && targetFile2.endsWith(".hbs")) {
|
|
563
522
|
targetFile2 = targetFile2.slice(0, -4);
|
|
564
523
|
}
|
|
@@ -571,12 +530,12 @@ async function rewriteSkillSource(skill, options, summary) {
|
|
|
571
530
|
summary.created++;
|
|
572
531
|
}
|
|
573
532
|
await writeFileSafe(targetFile2, content);
|
|
574
|
-
const relWritten =
|
|
533
|
+
const relWritten = path7.relative(targetDir, targetFile2);
|
|
575
534
|
records.push(makeSourceRecord(skill, targetFile2, content, relWritten));
|
|
576
535
|
}
|
|
577
536
|
return records;
|
|
578
537
|
}
|
|
579
|
-
const targetFile =
|
|
538
|
+
const targetFile = path7.join(targetDir, "SKILL.md");
|
|
580
539
|
const newContent = await renderSkillContent(sourceAbs, skill, data);
|
|
581
540
|
const exists = await fileExists(targetFile);
|
|
582
541
|
if (skill.updateStrategy === "frozen") {
|
|
@@ -651,14 +610,20 @@ async function syncSkillsToIdes(options) {
|
|
|
651
610
|
await ensureDir(targetDir);
|
|
652
611
|
const sourceFiles = await walkDir(sourceDir);
|
|
653
612
|
for (const src of sourceFiles) {
|
|
654
|
-
const rel2 =
|
|
655
|
-
const targetFile =
|
|
656
|
-
const
|
|
657
|
-
await
|
|
613
|
+
const rel2 = path7.relative(sourceDir, src);
|
|
614
|
+
const targetFile = path7.join(targetDir, rel2);
|
|
615
|
+
const sourceContent = await fs5.readFile(src, "utf-8");
|
|
616
|
+
const existing = await readFileOrNull(targetFile);
|
|
617
|
+
if (existing !== null && existing !== sourceContent) {
|
|
618
|
+
logger.warn(
|
|
619
|
+
`Mirror drift detected at ${targetFile} \u2014 overwriting from source. Edit ${src} (not the mirror) and re-run \`teamix-evo skills sync\`.`
|
|
620
|
+
);
|
|
621
|
+
}
|
|
622
|
+
await writeFileSafe(targetFile, sourceContent);
|
|
658
623
|
out.push({
|
|
659
624
|
id: rel2 === "SKILL.md" ? skill.id : `${skill.id}:${rel2}`,
|
|
660
625
|
target: targetFile,
|
|
661
|
-
hash: computeHash(
|
|
626
|
+
hash: computeHash(sourceContent),
|
|
662
627
|
strategy: skill.updateStrategy,
|
|
663
628
|
ide,
|
|
664
629
|
scope
|
|
@@ -680,12 +645,18 @@ async function removeSkillFiles(records) {
|
|
|
680
645
|
}
|
|
681
646
|
}
|
|
682
647
|
}
|
|
683
|
-
const
|
|
684
|
-
for (const
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
648
|
+
const startDirs = new Set(records.map((r) => path7.dirname(r.target)));
|
|
649
|
+
for (const startDir of startDirs) {
|
|
650
|
+
let dir = startDir;
|
|
651
|
+
for (let depth = 0; depth < 8; depth++) {
|
|
652
|
+
try {
|
|
653
|
+
const entries = await fs5.readdir(dir);
|
|
654
|
+
if (entries.length !== 0) break;
|
|
655
|
+
await fs5.rmdir(dir);
|
|
656
|
+
} catch {
|
|
657
|
+
break;
|
|
658
|
+
}
|
|
659
|
+
dir = path7.dirname(dir);
|
|
689
660
|
}
|
|
690
661
|
}
|
|
691
662
|
return removed;
|
|
@@ -714,7 +685,7 @@ async function runSkillsAdd(options) {
|
|
|
714
685
|
throw new Error("Scope must be specified (project | global).");
|
|
715
686
|
}
|
|
716
687
|
const { manifest, data, packageRoot } = await loadSkillsData(packageName);
|
|
717
|
-
const
|
|
688
|
+
const currentTokensVariant = await readTokensVariant(projectRoot);
|
|
718
689
|
if (isIncremental) {
|
|
719
690
|
const known = new Set(manifest.skills.map((s) => s.id));
|
|
720
691
|
const unknown = requestedNames.filter((n) => !known.has(n));
|
|
@@ -745,15 +716,15 @@ async function runSkillsAdd(options) {
|
|
|
745
716
|
skippedSkillIds = [];
|
|
746
717
|
onlyIds = manifest.skills.filter((s) => {
|
|
747
718
|
if (!s.variant) return true;
|
|
748
|
-
if (!
|
|
719
|
+
if (!currentTokensVariant) {
|
|
749
720
|
logger.debug(
|
|
750
|
-
`Skipping variant-bound skill "${s.id}" (variant=${s.variant}): no
|
|
721
|
+
`Skipping variant-bound skill "${s.id}" (variant=${s.variant}): no tokens variant installed; will be picked up when "tokens init" runs.`
|
|
751
722
|
);
|
|
752
723
|
return false;
|
|
753
724
|
}
|
|
754
|
-
if (s.variant !==
|
|
725
|
+
if (s.variant !== currentTokensVariant) {
|
|
755
726
|
logger.debug(
|
|
756
|
-
`Skipping variant-bound skill "${s.id}" (variant=${s.variant}): current
|
|
727
|
+
`Skipping variant-bound skill "${s.id}" (variant=${s.variant}): current tokens variant is "${currentTokensVariant}".`
|
|
757
728
|
);
|
|
758
729
|
return false;
|
|
759
730
|
}
|
|
@@ -856,85 +827,108 @@ function mergeInstalledResources(existing, next) {
|
|
|
856
827
|
return [...map.values()];
|
|
857
828
|
}
|
|
858
829
|
|
|
859
|
-
// src/core/
|
|
860
|
-
var BASELINE_DESIGN_RULES_SKILL = "teamix-evo-design-rules";
|
|
830
|
+
// src/core/tokens-init.ts
|
|
861
831
|
var DEFAULT_SKILLS_PACKAGE2 = "@teamix-evo/skills";
|
|
862
832
|
var DEFAULT_AUTO_SKILL_IDES = ["qoder", "claude"];
|
|
863
833
|
var DEFAULT_AUTO_SKILL_SCOPE = "project";
|
|
864
|
-
var
|
|
834
|
+
var DEFAULT_TOKENS_PACKAGE = "@teamix-evo/tokens";
|
|
835
|
+
var CONSUMER_TOKENS_DIR = "tokens";
|
|
836
|
+
var CONSUMER_THEME_FILE = "tokens.theme.css";
|
|
837
|
+
var CONSUMER_OVERRIDES_FILE = "tokens.overrides.css";
|
|
838
|
+
var EMPTY_OVERRIDES_TEMPLATE = `/* User-owned token overrides \u2014 frozen on subsequent installs. */
|
|
839
|
+
/* See @teamix-evo/tokens variant theme.css for available CSS custom properties. */
|
|
840
|
+
`;
|
|
865
841
|
var require3 = createRequire2(import.meta.url);
|
|
866
|
-
async function
|
|
842
|
+
async function runTokensInit(options) {
|
|
867
843
|
const { projectRoot, variant, ide } = options;
|
|
868
|
-
const packageName = options.packageName ??
|
|
844
|
+
const packageName = options.packageName ?? DEFAULT_TOKENS_PACKAGE;
|
|
869
845
|
await ensureTeamixDir(projectRoot);
|
|
870
846
|
const existingConfig = await readProjectConfig(projectRoot);
|
|
871
|
-
if (existingConfig?.packages?.
|
|
847
|
+
if (existingConfig?.packages?.tokens) {
|
|
848
|
+
const existingVariant = existingConfig.packages.tokens.variant;
|
|
849
|
+
if (existingVariant === variant) {
|
|
850
|
+
return { status: "already-initialized", existingVariant };
|
|
851
|
+
}
|
|
872
852
|
return {
|
|
873
|
-
status: "
|
|
874
|
-
existingVariant
|
|
853
|
+
status: "variant-mismatch",
|
|
854
|
+
existingVariant,
|
|
855
|
+
requestedVariant: variant
|
|
875
856
|
};
|
|
876
857
|
}
|
|
877
|
-
const packageRoot = options.packageRoot ??
|
|
878
|
-
const catalog = await
|
|
879
|
-
const variantEntry = catalog
|
|
858
|
+
const packageRoot = options.packageRoot ?? resolveTokensPackageRoot(packageName);
|
|
859
|
+
const catalog = await loadTokensPackageManifest(packageRoot);
|
|
860
|
+
const variantEntry = getVariantEntry(catalog, variant);
|
|
880
861
|
if (!variantEntry) {
|
|
881
862
|
const known = catalog.variants.map((v) => v.name).join(", ");
|
|
882
863
|
throw new Error(
|
|
883
|
-
`
|
|
864
|
+
`Tokens variant not found: "${variant}". Known variants: ${known || "(none)"}. Hint: run "teamix-evo tokens list-variants" to see all.`
|
|
884
865
|
);
|
|
885
866
|
}
|
|
886
|
-
const defaultDir = path9.join(packageRoot, "default");
|
|
887
|
-
const variantDir = path9.join(packageRoot, "variants", variant);
|
|
888
|
-
const defaultPack = await loadDesignPack(defaultDir);
|
|
889
|
-
const variantPack = await loadDesignPack(variantDir);
|
|
890
|
-
const merge = await mergeDefaultAndVariant(defaultDir, variantDir);
|
|
891
867
|
const installed = [];
|
|
892
|
-
for (const
|
|
893
|
-
const result = await
|
|
868
|
+
for (const fileRel of variantEntry.files) {
|
|
869
|
+
const result = await installVariantFile(fileRel, packageRoot, projectRoot);
|
|
894
870
|
if (result) installed.push(result);
|
|
895
871
|
}
|
|
872
|
+
const overridesAbs = path8.join(
|
|
873
|
+
projectRoot,
|
|
874
|
+
CONSUMER_TOKENS_DIR,
|
|
875
|
+
CONSUMER_OVERRIDES_FILE
|
|
876
|
+
);
|
|
877
|
+
if (!await fileExists(overridesAbs)) {
|
|
878
|
+
await writeFileSafe(overridesAbs, EMPTY_OVERRIDES_TEMPLATE);
|
|
879
|
+
}
|
|
880
|
+
const overridesContent = await fs6.readFile(overridesAbs, "utf-8");
|
|
881
|
+
installed.push({
|
|
882
|
+
id: `tokens:${CONSUMER_OVERRIDES_FILE}`,
|
|
883
|
+
target: path8.posix.join(CONSUMER_TOKENS_DIR, CONSUMER_OVERRIDES_FILE),
|
|
884
|
+
hash: computeHash(overridesContent),
|
|
885
|
+
strategy: "frozen"
|
|
886
|
+
});
|
|
896
887
|
const lock = {
|
|
897
888
|
schemaVersion: 1,
|
|
898
|
-
default: { version: defaultPack.version, from: packageName },
|
|
899
889
|
variant: {
|
|
900
|
-
name:
|
|
901
|
-
displayName:
|
|
902
|
-
version:
|
|
890
|
+
name: variantEntry.name,
|
|
891
|
+
displayName: variantEntry.displayName,
|
|
892
|
+
version: variantEntry.version,
|
|
903
893
|
from: packageName
|
|
904
894
|
},
|
|
905
|
-
|
|
895
|
+
packageVersion: catalog.version,
|
|
896
|
+
linked: variantEntry.linked,
|
|
906
897
|
installedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
907
898
|
};
|
|
908
899
|
await writeFileSafe(
|
|
909
|
-
|
|
900
|
+
path8.join(projectRoot, ".teamix-evo", "tokens-lock.json"),
|
|
910
901
|
JSON.stringify(lock, null, 2) + "\n"
|
|
911
902
|
);
|
|
912
903
|
const config = {
|
|
913
904
|
$schema: "https://teamix-evo.dev/schema/config/v1.json",
|
|
914
905
|
schemaVersion: 1,
|
|
915
|
-
ide,
|
|
906
|
+
ide: existingConfig?.ide ?? ide,
|
|
916
907
|
packages: {
|
|
917
|
-
|
|
908
|
+
...existingConfig?.packages ?? {},
|
|
909
|
+
tokens: {
|
|
918
910
|
variant,
|
|
919
|
-
version:
|
|
911
|
+
version: variantEntry.version,
|
|
920
912
|
tailwind: "v4"
|
|
921
913
|
}
|
|
922
914
|
}
|
|
923
915
|
};
|
|
924
916
|
await writeProjectConfig(projectRoot, config);
|
|
925
|
-
const
|
|
917
|
+
const prior = await readInstalledManifest(projectRoot) ?? {
|
|
926
918
|
schemaVersion: 1,
|
|
927
|
-
installed: [
|
|
928
|
-
{
|
|
929
|
-
package: packageName,
|
|
930
|
-
variant,
|
|
931
|
-
version: variantPack.version,
|
|
932
|
-
installedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
933
|
-
resources: installed
|
|
934
|
-
}
|
|
935
|
-
]
|
|
919
|
+
installed: []
|
|
936
920
|
};
|
|
937
|
-
|
|
921
|
+
const tokensIdx = prior.installed.findIndex((p) => p.package === packageName);
|
|
922
|
+
const tokensEntry = {
|
|
923
|
+
package: packageName,
|
|
924
|
+
variant,
|
|
925
|
+
version: variantEntry.version,
|
|
926
|
+
installedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
927
|
+
resources: installed
|
|
928
|
+
};
|
|
929
|
+
if (tokensIdx >= 0) prior.installed[tokensIdx] = tokensEntry;
|
|
930
|
+
else prior.installed.push(tokensEntry);
|
|
931
|
+
await writeInstalledManifest(projectRoot, prior);
|
|
938
932
|
const skills = await tryAutoInstallVariantSkills({
|
|
939
933
|
projectRoot,
|
|
940
934
|
variant,
|
|
@@ -944,21 +938,16 @@ async function runDesignInit(options) {
|
|
|
944
938
|
status: "installed",
|
|
945
939
|
packageName,
|
|
946
940
|
variant,
|
|
947
|
-
version:
|
|
941
|
+
version: variantEntry.version,
|
|
948
942
|
count: installed.length,
|
|
949
943
|
resources: installed,
|
|
950
|
-
merge: {
|
|
951
|
-
overrides: merge.overrides,
|
|
952
|
-
variantAdds: merge.variantAdds,
|
|
953
|
-
defaultPassThrough: merge.defaultPassThrough
|
|
954
|
-
},
|
|
955
944
|
skills
|
|
956
945
|
};
|
|
957
946
|
}
|
|
958
947
|
async function tryAutoInstallVariantSkills(args) {
|
|
959
948
|
const { projectRoot, variant, ide } = args;
|
|
960
|
-
const variantSkillId =
|
|
961
|
-
const desired = [
|
|
949
|
+
const variantSkillId = `teamix-evo-design-${variant}`;
|
|
950
|
+
const desired = [variantSkillId];
|
|
962
951
|
let manifestSkillIds;
|
|
963
952
|
try {
|
|
964
953
|
const { manifest } = await loadSkillsData(DEFAULT_SKILLS_PACKAGE2);
|
|
@@ -978,7 +967,9 @@ async function tryAutoInstallVariantSkills(args) {
|
|
|
978
967
|
const missing = desired.filter((id) => !manifestSkillIds.has(id));
|
|
979
968
|
if (missing.length > 0) {
|
|
980
969
|
logger.warn(
|
|
981
|
-
`Skills auto-install: not found in manifest, skipping: ${missing.join(
|
|
970
|
+
`Skills auto-install: not found in manifest, skipping: ${missing.join(
|
|
971
|
+
", "
|
|
972
|
+
)}.`
|
|
982
973
|
);
|
|
983
974
|
}
|
|
984
975
|
if (present.length === 0) {
|
|
@@ -1023,38 +1014,60 @@ async function tryAutoInstallVariantSkills(args) {
|
|
|
1023
1014
|
};
|
|
1024
1015
|
}
|
|
1025
1016
|
}
|
|
1026
|
-
async function
|
|
1027
|
-
const
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1017
|
+
async function installVariantFile(fileRelToPackage, packageRoot, projectRoot) {
|
|
1018
|
+
const sourceAbs = path8.join(packageRoot, fileRelToPackage);
|
|
1019
|
+
const base = path8.basename(fileRelToPackage);
|
|
1020
|
+
if (base === "theme.css") {
|
|
1021
|
+
const targetRel = path8.posix.join(
|
|
1022
|
+
CONSUMER_TOKENS_DIR,
|
|
1023
|
+
CONSUMER_THEME_FILE
|
|
1024
|
+
);
|
|
1025
|
+
const targetAbs = path8.join(projectRoot, targetRel);
|
|
1026
|
+
const content = await fs6.readFile(sourceAbs, "utf-8");
|
|
1027
|
+
await writeFileSafe(targetAbs, content);
|
|
1032
1028
|
return {
|
|
1033
|
-
id: `
|
|
1034
|
-
target:
|
|
1035
|
-
hash: computeHash(
|
|
1036
|
-
strategy:
|
|
1029
|
+
id: `tokens:${CONSUMER_THEME_FILE}`,
|
|
1030
|
+
target: targetRel,
|
|
1031
|
+
hash: computeHash(content),
|
|
1032
|
+
strategy: "regenerable"
|
|
1037
1033
|
};
|
|
1038
1034
|
}
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1035
|
+
if (base === "overrides.css" || base === "tokens.overrides.css") {
|
|
1036
|
+
const targetRel = path8.posix.join(
|
|
1037
|
+
CONSUMER_TOKENS_DIR,
|
|
1038
|
+
CONSUMER_OVERRIDES_FILE
|
|
1039
|
+
);
|
|
1040
|
+
const targetAbs = path8.join(projectRoot, targetRel);
|
|
1041
|
+
if (await fileExists(targetAbs)) {
|
|
1042
|
+
const existing = await fs6.readFile(targetAbs, "utf-8");
|
|
1043
|
+
return {
|
|
1044
|
+
id: `tokens:${CONSUMER_OVERRIDES_FILE}`,
|
|
1045
|
+
target: targetRel,
|
|
1046
|
+
hash: computeHash(existing),
|
|
1047
|
+
strategy: "frozen"
|
|
1048
|
+
};
|
|
1049
|
+
}
|
|
1050
|
+
const content = await fs6.readFile(sourceAbs, "utf-8");
|
|
1051
|
+
await writeFileSafe(targetAbs, content);
|
|
1052
|
+
return {
|
|
1053
|
+
id: `tokens:${CONSUMER_OVERRIDES_FILE}`,
|
|
1054
|
+
target: targetRel,
|
|
1055
|
+
hash: computeHash(content),
|
|
1056
|
+
strategy: "frozen"
|
|
1057
|
+
};
|
|
1058
|
+
}
|
|
1059
|
+
return null;
|
|
1047
1060
|
}
|
|
1048
|
-
function
|
|
1061
|
+
function resolveTokensPackageRoot(packageName) {
|
|
1049
1062
|
const pkgJson = require3.resolve(`${packageName}/package.json`);
|
|
1050
|
-
return
|
|
1063
|
+
return path8.dirname(pkgJson);
|
|
1051
1064
|
}
|
|
1052
|
-
async function
|
|
1053
|
-
const root = packageRoot ??
|
|
1054
|
-
const catalog = await
|
|
1065
|
+
async function listTokenVariants(packageName = DEFAULT_TOKENS_PACKAGE, packageRoot) {
|
|
1066
|
+
const root = packageRoot ?? resolveTokensPackageRoot(packageName);
|
|
1067
|
+
const catalog = await loadTokensPackageManifest(root);
|
|
1055
1068
|
return {
|
|
1056
1069
|
packageName,
|
|
1057
|
-
|
|
1070
|
+
packageVersion: catalog.version,
|
|
1058
1071
|
variants: catalog.variants.map((v) => ({
|
|
1059
1072
|
name: v.name,
|
|
1060
1073
|
displayName: v.displayName,
|
|
@@ -1065,7 +1078,7 @@ async function listDesignVariants(packageName = DEFAULT_DESIGN_PACKAGE, packageR
|
|
|
1065
1078
|
};
|
|
1066
1079
|
}
|
|
1067
1080
|
|
|
1068
|
-
// src/commands/
|
|
1081
|
+
// src/commands/tokens/init.ts
|
|
1069
1082
|
var initCommand = new Command("init").description("\u521D\u59CB\u5316\u8BBE\u8BA1\u4F53\u7CFB\u8D44\u6E90\uFF08\u5FC5\u987B\u663E\u5F0F\u6307\u5B9A\u4E1A\u52A1\u53D8\u4F53\uFF09").argument("<variant>", '\u4E1A\u52A1\u53D8\u4F53\u540D\u79F0\uFF08\u5982 "opentrek"\u3001"uni-manager"\uFF09').action(async (variant) => {
|
|
1070
1083
|
try {
|
|
1071
1084
|
const ide = detectIde();
|
|
@@ -1075,15 +1088,28 @@ var initCommand = new Command("init").description("\u521D\u59CB\u5316\u8BBE\u8BA
|
|
|
1075
1088
|
logger.debug(`IDE: ${ide.name}`);
|
|
1076
1089
|
logger.info(`Loading variant "${variant}"...`);
|
|
1077
1090
|
logger.info("Installing resources...");
|
|
1078
|
-
const result = await
|
|
1091
|
+
const result = await runTokensInit({
|
|
1079
1092
|
projectRoot,
|
|
1080
1093
|
variant,
|
|
1081
1094
|
ide: ide.name
|
|
1082
1095
|
});
|
|
1083
1096
|
if (result.status === "already-initialized") {
|
|
1084
|
-
logger.
|
|
1085
|
-
`Design system already initialized (variant: ${result.existingVariant}). Use "teamix-evo
|
|
1097
|
+
logger.info(
|
|
1098
|
+
`Design system already initialized (variant: ${result.existingVariant}). Use "teamix-evo tokens update" to refresh resources.`
|
|
1099
|
+
);
|
|
1100
|
+
return;
|
|
1101
|
+
}
|
|
1102
|
+
if (result.status === "variant-mismatch") {
|
|
1103
|
+
logger.error(
|
|
1104
|
+
`Cannot switch tokens variant in place. Currently installed: "${result.existingVariant}"; requested: "${result.requestedVariant}".`
|
|
1105
|
+
);
|
|
1106
|
+
logger.info("To switch variants:");
|
|
1107
|
+
logger.info(" 1. teamix-evo tokens uninstall --yes");
|
|
1108
|
+
logger.info(` 2. teamix-evo tokens init ${result.requestedVariant}`);
|
|
1109
|
+
logger.info(
|
|
1110
|
+
"Note: tokens.overrides.css (frozen) is preserved across uninstall/init by default."
|
|
1086
1111
|
);
|
|
1112
|
+
process.exitCode = 1;
|
|
1087
1113
|
return;
|
|
1088
1114
|
}
|
|
1089
1115
|
logger.success(
|
|
@@ -1092,9 +1118,6 @@ var initCommand = new Command("init").description("\u521D\u59CB\u5316\u8BBE\u8BA
|
|
|
1092
1118
|
logger.info(` Variant: ${result.variant}`);
|
|
1093
1119
|
logger.info(` Tailwind: v4`);
|
|
1094
1120
|
logger.info(` Resources: ${result.count} files installed`);
|
|
1095
|
-
logger.info(
|
|
1096
|
-
` Merge: ${result.merge.overrides.length} overrides / ${result.merge.variantAdds.length} variant-only / ${result.merge.defaultPassThrough.length} default-passthrough`
|
|
1097
|
-
);
|
|
1098
1121
|
if (result.skills) {
|
|
1099
1122
|
const { addedSkillIds, skippedSkillIds, missing } = result.skills;
|
|
1100
1123
|
if (addedSkillIds.length > 0) {
|
|
@@ -1114,9 +1137,9 @@ var initCommand = new Command("init").description("\u521D\u59CB\u5316\u8BBE\u8BA
|
|
|
1114
1137
|
}
|
|
1115
1138
|
}
|
|
1116
1139
|
logger.info("");
|
|
1117
|
-
logger.info('Run "teamix-evo
|
|
1140
|
+
logger.info('Run "teamix-evo tokens update" to update resources later.');
|
|
1118
1141
|
logger.info(
|
|
1119
|
-
'Run "teamix-evo
|
|
1142
|
+
'Run "teamix-evo tokens list-variants" to see all available variants.'
|
|
1120
1143
|
);
|
|
1121
1144
|
} catch (err) {
|
|
1122
1145
|
logger.error(`Failed to initialize: ${err.message}`);
|
|
@@ -1125,43 +1148,191 @@ var initCommand = new Command("init").description("\u521D\u59CB\u5316\u8BBE\u8BA
|
|
|
1125
1148
|
}
|
|
1126
1149
|
});
|
|
1127
1150
|
|
|
1128
|
-
// src/commands/
|
|
1151
|
+
// src/commands/tokens/update.ts
|
|
1129
1152
|
import { Command as Command2 } from "commander";
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1153
|
+
|
|
1154
|
+
// src/core/tokens-update.ts
|
|
1155
|
+
import * as path9 from "path";
|
|
1156
|
+
import * as fs7 from "fs/promises";
|
|
1157
|
+
import { createRequire as createRequire3 } from "module";
|
|
1158
|
+
import {
|
|
1159
|
+
loadTokensPackageManifest as loadTokensPackageManifest2,
|
|
1160
|
+
getVariantEntry as getVariantEntry2
|
|
1161
|
+
} from "@teamix-evo/registry";
|
|
1162
|
+
var DEFAULT_TOKENS_PACKAGE2 = "@teamix-evo/tokens";
|
|
1163
|
+
var CONSUMER_TOKENS_DIR2 = "tokens";
|
|
1164
|
+
var CONSUMER_THEME_FILE2 = "tokens.theme.css";
|
|
1165
|
+
var require4 = createRequire3(import.meta.url);
|
|
1166
|
+
async function runTokensUpdate(options) {
|
|
1167
|
+
const { projectRoot } = options;
|
|
1168
|
+
const packageName = options.packageName ?? DEFAULT_TOKENS_PACKAGE2;
|
|
1169
|
+
const config = await readProjectConfig(projectRoot);
|
|
1170
|
+
if (!config?.packages?.tokens) {
|
|
1171
|
+
return { status: "not-initialized" };
|
|
1172
|
+
}
|
|
1173
|
+
const currentVariant = config.packages.tokens.variant;
|
|
1174
|
+
const currentVersion = config.packages.tokens.version;
|
|
1175
|
+
const packageRoot = options.packageRoot ?? resolveTokensPackageRoot2(packageName);
|
|
1176
|
+
const catalog = await loadTokensPackageManifest2(packageRoot);
|
|
1177
|
+
const variantEntry = getVariantEntry2(catalog, currentVariant);
|
|
1178
|
+
if (!variantEntry) {
|
|
1179
|
+
throw new Error(
|
|
1180
|
+
`Currently installed variant "${currentVariant}" no longer exists in ${packageName}@${catalog.version}. Available: ${catalog.variants.map((v) => v.name).join(", ")}. Run \`teamix-evo tokens uninstall\` then \`teamix-evo tokens init <variant>\` to switch.`
|
|
1181
|
+
);
|
|
1182
|
+
}
|
|
1183
|
+
if (variantEntry.version === currentVersion) {
|
|
1184
|
+
await rewriteRegenerableFiles(variantEntry.files, packageRoot, projectRoot);
|
|
1185
|
+
return {
|
|
1186
|
+
status: "up-to-date",
|
|
1187
|
+
packageName,
|
|
1188
|
+
variant: currentVariant,
|
|
1189
|
+
version: currentVersion
|
|
1190
|
+
};
|
|
1191
|
+
}
|
|
1192
|
+
const rewritten = await rewriteRegenerableFiles(
|
|
1193
|
+
variantEntry.files,
|
|
1194
|
+
packageRoot,
|
|
1195
|
+
projectRoot
|
|
1133
1196
|
);
|
|
1134
|
-
|
|
1135
|
-
|
|
1197
|
+
const preserved = [];
|
|
1198
|
+
const overridesAbs = path9.join(
|
|
1199
|
+
projectRoot,
|
|
1200
|
+
CONSUMER_TOKENS_DIR2,
|
|
1201
|
+
"tokens.overrides.css"
|
|
1136
1202
|
);
|
|
1137
|
-
|
|
1138
|
-
|
|
1203
|
+
if (await fileExists(overridesAbs)) preserved.push("tokens.overrides.css");
|
|
1204
|
+
const lock = {
|
|
1205
|
+
schemaVersion: 1,
|
|
1206
|
+
variant: {
|
|
1207
|
+
name: variantEntry.name,
|
|
1208
|
+
displayName: variantEntry.displayName,
|
|
1209
|
+
version: variantEntry.version,
|
|
1210
|
+
from: packageName
|
|
1211
|
+
},
|
|
1212
|
+
packageVersion: catalog.version,
|
|
1213
|
+
linked: variantEntry.linked,
|
|
1214
|
+
installedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
1215
|
+
};
|
|
1216
|
+
await writeFileSafe(
|
|
1217
|
+
path9.join(projectRoot, ".teamix-evo", "tokens-lock.json"),
|
|
1218
|
+
JSON.stringify(lock, null, 2) + "\n"
|
|
1139
1219
|
);
|
|
1140
|
-
|
|
1220
|
+
config.packages.tokens.version = variantEntry.version;
|
|
1221
|
+
await writeProjectConfig(projectRoot, config);
|
|
1222
|
+
const prior = await readInstalledManifest(projectRoot) ?? {
|
|
1223
|
+
schemaVersion: 1,
|
|
1224
|
+
installed: []
|
|
1225
|
+
};
|
|
1226
|
+
const idx = prior.installed.findIndex((p) => p.package === packageName);
|
|
1227
|
+
if (idx >= 0) {
|
|
1228
|
+
prior.installed[idx].version = variantEntry.version;
|
|
1229
|
+
prior.installed[idx].installedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
1230
|
+
for (const r of prior.installed[idx].resources) {
|
|
1231
|
+
if (r.strategy === "regenerable") {
|
|
1232
|
+
const abs = path9.isAbsolute(r.target) ? r.target : path9.join(projectRoot, r.target);
|
|
1233
|
+
if (await fileExists(abs)) {
|
|
1234
|
+
r.hash = computeHash(await fs7.readFile(abs, "utf-8"));
|
|
1235
|
+
}
|
|
1236
|
+
}
|
|
1237
|
+
}
|
|
1238
|
+
await writeInstalledManifest(projectRoot, prior);
|
|
1239
|
+
}
|
|
1240
|
+
return {
|
|
1241
|
+
status: "updated",
|
|
1242
|
+
packageName,
|
|
1243
|
+
variant: currentVariant,
|
|
1244
|
+
from: currentVersion,
|
|
1245
|
+
to: variantEntry.version,
|
|
1246
|
+
rewritten,
|
|
1247
|
+
preserved
|
|
1248
|
+
};
|
|
1249
|
+
}
|
|
1250
|
+
async function rewriteRegenerableFiles(files, packageRoot, projectRoot) {
|
|
1251
|
+
const written = [];
|
|
1252
|
+
for (const fileRel of files) {
|
|
1253
|
+
const base = path9.basename(fileRel);
|
|
1254
|
+
if (base !== "theme.css") continue;
|
|
1255
|
+
const sourceAbs = path9.join(packageRoot, fileRel);
|
|
1256
|
+
const targetAbs = path9.join(
|
|
1257
|
+
projectRoot,
|
|
1258
|
+
CONSUMER_TOKENS_DIR2,
|
|
1259
|
+
CONSUMER_THEME_FILE2
|
|
1260
|
+
);
|
|
1261
|
+
const content = await fs7.readFile(sourceAbs, "utf-8");
|
|
1262
|
+
await writeFileSafe(targetAbs, content);
|
|
1263
|
+
written.push(CONSUMER_THEME_FILE2);
|
|
1264
|
+
}
|
|
1265
|
+
return written;
|
|
1266
|
+
}
|
|
1267
|
+
function resolveTokensPackageRoot2(packageName) {
|
|
1268
|
+
const pkgJson = require4.resolve(`${packageName}/package.json`);
|
|
1269
|
+
return path9.dirname(pkgJson);
|
|
1270
|
+
}
|
|
1271
|
+
|
|
1272
|
+
// src/commands/tokens/update.ts
|
|
1273
|
+
var updateCommand = new Command2("update").description(
|
|
1274
|
+
"\u5237\u65B0 design tokens\uFF08regenerable \u8986\u76D6\u3001frozen \u4FDD\u7559 \u2014 ADR 0003 \u4E09\u6001\uFF09"
|
|
1275
|
+
).action(async () => {
|
|
1276
|
+
try {
|
|
1277
|
+
const ide = detectIde();
|
|
1278
|
+
const projectRoot = ide.getProjectRoot();
|
|
1279
|
+
const result = await runTokensUpdate({ projectRoot });
|
|
1280
|
+
if (result.status === "not-initialized") {
|
|
1281
|
+
logger.error(
|
|
1282
|
+
"No tokens variant installed. Run `teamix-evo tokens init <variant>` first."
|
|
1283
|
+
);
|
|
1284
|
+
process.exitCode = 1;
|
|
1285
|
+
return;
|
|
1286
|
+
}
|
|
1287
|
+
if (result.status === "up-to-date") {
|
|
1288
|
+
logger.success(
|
|
1289
|
+
`Already at latest: ${result.packageName} (${result.variant} v${result.version})`
|
|
1290
|
+
);
|
|
1291
|
+
logger.info(
|
|
1292
|
+
" Regenerable files refreshed in case of manual edits."
|
|
1293
|
+
);
|
|
1294
|
+
return;
|
|
1295
|
+
}
|
|
1296
|
+
logger.success(
|
|
1297
|
+
`Updated ${result.packageName} (${result.variant}): v${result.from} \u2192 v${result.to}`
|
|
1298
|
+
);
|
|
1299
|
+
if (result.rewritten.length > 0) {
|
|
1300
|
+
logger.info(` Rewrote: ${result.rewritten.join(", ")}`);
|
|
1301
|
+
}
|
|
1302
|
+
if (result.preserved.length > 0) {
|
|
1303
|
+
logger.info(
|
|
1304
|
+
` Preserved: ${result.preserved.join(", ")} (frozen \u2014 your customizations kept)`
|
|
1305
|
+
);
|
|
1306
|
+
}
|
|
1307
|
+
} catch (err) {
|
|
1308
|
+
logger.error(`Failed to update tokens: ${err.message}`);
|
|
1309
|
+
logger.debug(err.stack ?? "");
|
|
1310
|
+
process.exitCode = 1;
|
|
1311
|
+
}
|
|
1141
1312
|
});
|
|
1142
1313
|
|
|
1143
|
-
// src/commands/
|
|
1314
|
+
// src/commands/tokens/list.ts
|
|
1144
1315
|
import { Command as Command3 } from "commander";
|
|
1145
1316
|
var listCommand = new Command3("list").description("\u5217\u51FA\u5DF2\u5B89\u88C5\u7684\u8BBE\u8BA1\u53D8\u4F53").action(async () => {
|
|
1146
1317
|
try {
|
|
1147
1318
|
const ide = detectIde();
|
|
1148
1319
|
const projectRoot = ide.getProjectRoot();
|
|
1149
1320
|
const config = await readProjectConfig(projectRoot);
|
|
1150
|
-
if (!config?.packages?.
|
|
1151
|
-
logger.info("No
|
|
1152
|
-
logger.info('Run "teamix-evo
|
|
1321
|
+
if (!config?.packages?.tokens) {
|
|
1322
|
+
logger.info("No tokens variant installed.");
|
|
1323
|
+
logger.info('Run "teamix-evo tokens init [variant]" to get started.');
|
|
1153
1324
|
return;
|
|
1154
1325
|
}
|
|
1155
|
-
const { variant, version: version2 } = config.packages.
|
|
1156
|
-
logger.info("Installed
|
|
1157
|
-
logger.info(` Package: @teamix-evo/
|
|
1326
|
+
const { variant, version: version2 } = config.packages.tokens;
|
|
1327
|
+
logger.info("Installed tokens variant:");
|
|
1328
|
+
logger.info(` Package: @teamix-evo/tokens`);
|
|
1158
1329
|
logger.info(` Variant: ${variant}`);
|
|
1159
1330
|
logger.info(` Version: ${version2}`);
|
|
1160
1331
|
logger.info(` IDE: ${config.ide}`);
|
|
1161
1332
|
const manifest = await readInstalledManifest(projectRoot);
|
|
1162
1333
|
if (manifest) {
|
|
1163
1334
|
const pkg = manifest.installed.find(
|
|
1164
|
-
(p) => p.package === "@teamix-evo/
|
|
1335
|
+
(p) => p.package === "@teamix-evo/tokens" && p.variant === variant
|
|
1165
1336
|
);
|
|
1166
1337
|
if (pkg) {
|
|
1167
1338
|
logger.info(` Resources: ${pkg.resources.length} files`);
|
|
@@ -1176,20 +1347,17 @@ var listCommand = new Command3("list").description("\u5217\u51FA\u5DF2\u5B89\u88
|
|
|
1176
1347
|
}
|
|
1177
1348
|
});
|
|
1178
1349
|
|
|
1179
|
-
// src/commands/
|
|
1350
|
+
// src/commands/tokens/list-variants.ts
|
|
1180
1351
|
import { Command as Command4 } from "commander";
|
|
1181
|
-
var listVariantsCommand = new Command4("list-variants").description("\u5217\u51FA @teamix-evo/
|
|
1352
|
+
var listVariantsCommand = new Command4("list-variants").description("\u5217\u51FA @teamix-evo/tokens \u5305\u5185\u63D0\u4F9B\u7684\u6240\u6709\u53D8\u4F53").action(async () => {
|
|
1182
1353
|
try {
|
|
1183
|
-
const result = await
|
|
1184
|
-
logger.info(
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
if (result.defaultDescription) {
|
|
1188
|
-
logger.info(` ${result.defaultDescription}`);
|
|
1189
|
-
}
|
|
1354
|
+
const result = await listTokenVariants();
|
|
1355
|
+
logger.info(
|
|
1356
|
+
`Available variants in ${result.packageName} v${result.packageVersion}:`
|
|
1357
|
+
);
|
|
1190
1358
|
logger.info("");
|
|
1191
1359
|
if (result.variants.length === 0) {
|
|
1192
|
-
logger.info(" (no variants
|
|
1360
|
+
logger.info(" (no variants advertised in manifest.json)");
|
|
1193
1361
|
return;
|
|
1194
1362
|
}
|
|
1195
1363
|
for (const v of result.variants) {
|
|
@@ -1198,12 +1366,13 @@ var listVariantsCommand = new Command4("list-variants").description("\u5217\u51F
|
|
|
1198
1366
|
if (v.linked) {
|
|
1199
1367
|
const links = [];
|
|
1200
1368
|
if (v.linked["biz-ui"]) links.push(`biz-ui: ${v.linked["biz-ui"]}`);
|
|
1201
|
-
if (v.linked.templates)
|
|
1369
|
+
if (v.linked.templates)
|
|
1370
|
+
links.push(`templates: ${v.linked.templates}`);
|
|
1202
1371
|
if (links.length) logger.info(` linked: ${links.join(" / ")}`);
|
|
1203
1372
|
}
|
|
1204
1373
|
logger.info("");
|
|
1205
1374
|
}
|
|
1206
|
-
logger.info("Install a variant: teamix-evo
|
|
1375
|
+
logger.info("Install a variant: teamix-evo tokens init <name>");
|
|
1207
1376
|
} catch (err) {
|
|
1208
1377
|
logger.error(`Failed to list variants: ${err.message}`);
|
|
1209
1378
|
logger.debug(err.stack ?? "");
|
|
@@ -1211,37 +1380,42 @@ var listVariantsCommand = new Command4("list-variants").description("\u5217\u51F
|
|
|
1211
1380
|
}
|
|
1212
1381
|
});
|
|
1213
1382
|
|
|
1214
|
-
// src/commands/
|
|
1383
|
+
// src/commands/tokens/uninstall.ts
|
|
1215
1384
|
import { Command as Command5 } from "commander";
|
|
1216
|
-
import * as
|
|
1385
|
+
import * as fs8 from "fs/promises";
|
|
1217
1386
|
import * as path10 from "path";
|
|
1218
1387
|
import * as prompts from "@clack/prompts";
|
|
1219
|
-
var
|
|
1220
|
-
var uninstallCommand = new Command5("uninstall").description(
|
|
1388
|
+
var TOKENS_PACKAGE = "@teamix-evo/tokens";
|
|
1389
|
+
var uninstallCommand = new Command5("uninstall").description(
|
|
1390
|
+
"\u5378\u8F7D\u5DF2\u88C5\u7684 tokens \u53D8\u4F53\uFF08\u9ED8\u8BA4\u4FDD\u7559 frozen \u6587\u4EF6\u5982 tokens.overrides.css\uFF1B--purge \u624D\u4E00\u5E76\u5220\uFF09"
|
|
1391
|
+
).option("-y, --yes", "\u8DF3\u8FC7\u786E\u8BA4").option(
|
|
1221
1392
|
"--keep-files",
|
|
1222
|
-
"\u4EC5\u6E05\u7406 .teamix-evo \u4E2D\u7684\u8BB0\u8D26\u4FE1\u606F\uFF0C\u4E0D\u5220\u9664\
|
|
1393
|
+
"\u4EC5\u6E05\u7406 .teamix-evo \u4E2D\u7684\u8BB0\u8D26\u4FE1\u606F\uFF0C\u4E0D\u5220\u9664\u4EFB\u4F55\u843D\u5730\u8D44\u6E90\u6587\u4EF6"
|
|
1394
|
+
).option(
|
|
1395
|
+
"--purge",
|
|
1396
|
+
"\u540C\u65F6\u5220\u9664 frozen \u6587\u4EF6\uFF08\u9ED8\u8BA4 frozen / managed \u90FD\u4FDD\u7559 \u2014 ADR 0003\uFF09"
|
|
1223
1397
|
).action(async (opts) => {
|
|
1224
1398
|
try {
|
|
1225
1399
|
const ide = detectIde();
|
|
1226
1400
|
const projectRoot = ide.getProjectRoot();
|
|
1227
1401
|
const config = await readProjectConfig(projectRoot);
|
|
1228
|
-
if (!config?.packages?.
|
|
1229
|
-
logger.info("
|
|
1402
|
+
if (!config?.packages?.tokens) {
|
|
1403
|
+
logger.info("No tokens variant installed. Nothing to do.");
|
|
1230
1404
|
return;
|
|
1231
1405
|
}
|
|
1232
1406
|
const installedManifest = await readInstalledManifest(projectRoot);
|
|
1233
1407
|
const pkg = installedManifest?.installed.find(
|
|
1234
|
-
(p) => p.package ===
|
|
1408
|
+
(p) => p.package === TOKENS_PACKAGE
|
|
1235
1409
|
);
|
|
1236
1410
|
const resources = pkg?.resources ?? [];
|
|
1237
|
-
const removable = opts.keepFiles ? [] : resources.filter((r) => r.strategy !== "managed");
|
|
1411
|
+
const removable = opts.keepFiles ? [] : opts.purge ? resources.filter((r) => r.strategy !== "managed") : resources.filter((r) => r.strategy === "regenerable");
|
|
1238
1412
|
const kept = resources.length - removable.length;
|
|
1239
1413
|
logger.info(
|
|
1240
1414
|
`Will remove ${removable.length} file(s); keep ${kept} managed file(s).`
|
|
1241
1415
|
);
|
|
1242
1416
|
if (!opts.yes) {
|
|
1243
1417
|
const confirm4 = await prompts.confirm({
|
|
1244
|
-
message: "\u786E\u8BA4\u5378\u8F7D\
|
|
1418
|
+
message: "\u786E\u8BA4\u5378\u8F7D tokens \u53D8\u4F53\uFF1F",
|
|
1245
1419
|
initialValue: false
|
|
1246
1420
|
});
|
|
1247
1421
|
if (prompts.isCancel(confirm4) || !confirm4) {
|
|
@@ -1253,7 +1427,7 @@ var uninstallCommand = new Command5("uninstall").description("\u5378\u8F7D\u8BBE
|
|
|
1253
1427
|
for (const r of removable) {
|
|
1254
1428
|
const target = path10.isAbsolute(r.target) ? r.target : path10.join(projectRoot, r.target);
|
|
1255
1429
|
try {
|
|
1256
|
-
await
|
|
1430
|
+
await fs8.unlink(target);
|
|
1257
1431
|
removed++;
|
|
1258
1432
|
} catch (err) {
|
|
1259
1433
|
if (err.code !== "ENOENT") {
|
|
@@ -1265,18 +1439,31 @@ var uninstallCommand = new Command5("uninstall").description("\u5378\u8F7D\u8BBE
|
|
|
1265
1439
|
}
|
|
1266
1440
|
if (installedManifest) {
|
|
1267
1441
|
installedManifest.installed = installedManifest.installed.filter(
|
|
1268
|
-
(p) => p.package !==
|
|
1442
|
+
(p) => p.package !== TOKENS_PACKAGE
|
|
1269
1443
|
);
|
|
1270
1444
|
await writeInstalledManifest(projectRoot, installedManifest);
|
|
1271
1445
|
}
|
|
1272
|
-
delete config.packages.
|
|
1446
|
+
delete config.packages.tokens;
|
|
1273
1447
|
await writeProjectConfig(projectRoot, config);
|
|
1274
|
-
|
|
1448
|
+
const lockPath = path10.join(
|
|
1449
|
+
projectRoot,
|
|
1450
|
+
".teamix-evo",
|
|
1451
|
+
"tokens-lock.json"
|
|
1452
|
+
);
|
|
1453
|
+
try {
|
|
1454
|
+
await fs8.unlink(lockPath);
|
|
1455
|
+
} catch (err) {
|
|
1456
|
+
if (err.code !== "ENOENT") {
|
|
1457
|
+
logger.warn(
|
|
1458
|
+
`Failed to remove tokens-lock.json: ${err.message}`
|
|
1459
|
+
);
|
|
1460
|
+
}
|
|
1461
|
+
}
|
|
1462
|
+
logger.success(`Uninstalled ${TOKENS_PACKAGE}`);
|
|
1275
1463
|
logger.info(` Removed: ${removed} files`);
|
|
1276
1464
|
if (kept > 0) {
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
);
|
|
1465
|
+
const note = opts.purge ? "managed (you may delete manually)" : "frozen / managed (preserved \u2014 ADR 0003; --purge to force)";
|
|
1466
|
+
logger.info(` Kept: ${kept} files \u2014 ${note}`);
|
|
1280
1467
|
}
|
|
1281
1468
|
} catch (err) {
|
|
1282
1469
|
logger.error(`Failed to uninstall: ${err.message}`);
|
|
@@ -1285,15 +1472,13 @@ var uninstallCommand = new Command5("uninstall").description("\u5378\u8F7D\u8BBE
|
|
|
1285
1472
|
}
|
|
1286
1473
|
});
|
|
1287
1474
|
|
|
1288
|
-
// src/commands/
|
|
1289
|
-
var
|
|
1290
|
-
|
|
1291
|
-
);
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
designCommand.addCommand(listVariantsCommand);
|
|
1296
|
-
designCommand.addCommand(uninstallCommand);
|
|
1475
|
+
// src/commands/tokens/index.ts
|
|
1476
|
+
var tokensCommand = new Command6("tokens").description("\u7BA1\u7406 design tokens(\u53D8\u4F53\u7EA7 theme.css \u7B49)");
|
|
1477
|
+
tokensCommand.addCommand(initCommand);
|
|
1478
|
+
tokensCommand.addCommand(updateCommand);
|
|
1479
|
+
tokensCommand.addCommand(listCommand);
|
|
1480
|
+
tokensCommand.addCommand(listVariantsCommand);
|
|
1481
|
+
tokensCommand.addCommand(uninstallCommand);
|
|
1297
1482
|
|
|
1298
1483
|
// src/commands/skills/index.ts
|
|
1299
1484
|
import { Command as Command13 } from "commander";
|
|
@@ -1304,23 +1489,29 @@ import * as prompts2 from "@clack/prompts";
|
|
|
1304
1489
|
|
|
1305
1490
|
// src/utils/global-root.ts
|
|
1306
1491
|
import { existsSync } from "fs";
|
|
1307
|
-
import * as
|
|
1492
|
+
import * as fs9 from "fs/promises";
|
|
1308
1493
|
import * as os3 from "os";
|
|
1309
1494
|
import * as path11 from "path";
|
|
1310
1495
|
var GLOBAL_META_DIR = ".teamix-evo-global";
|
|
1311
|
-
var
|
|
1496
|
+
var TEAMIX_DIR2 = ".teamix-evo";
|
|
1312
1497
|
var CONFIG_FILE2 = "config.json";
|
|
1313
1498
|
function getGlobalMetaRoot() {
|
|
1314
1499
|
return path11.join(os3.homedir(), GLOBAL_META_DIR);
|
|
1315
1500
|
}
|
|
1316
1501
|
function isTeamixEvoProject(dir) {
|
|
1317
|
-
return existsSync(path11.join(dir,
|
|
1502
|
+
return existsSync(path11.join(dir, TEAMIX_DIR2, CONFIG_FILE2));
|
|
1318
1503
|
}
|
|
1319
1504
|
async function ensureGlobalMetaRoot() {
|
|
1320
1505
|
const root = getGlobalMetaRoot();
|
|
1321
|
-
await
|
|
1506
|
+
await fs9.mkdir(root, { recursive: true });
|
|
1322
1507
|
return root;
|
|
1323
1508
|
}
|
|
1509
|
+
function resolveSkillsMaintenanceRoot(cwd) {
|
|
1510
|
+
if (isTeamixEvoProject(cwd)) return cwd;
|
|
1511
|
+
const globalRoot = getGlobalMetaRoot();
|
|
1512
|
+
if (isTeamixEvoProject(globalRoot)) return globalRoot;
|
|
1513
|
+
return cwd;
|
|
1514
|
+
}
|
|
1324
1515
|
|
|
1325
1516
|
// src/commands/skills/add.ts
|
|
1326
1517
|
var addCommand = new Command7("add").description(
|
|
@@ -1467,17 +1658,27 @@ var listCommand2 = new Command8("list").alias("ls").description(
|
|
|
1467
1658
|
).option("--installed", "\u4EC5\u5C55\u793A\u5DF2\u5B89\u88C5\u7684 skill\uFF08\u9690\u85CF\u672A\u5B89\u88C5\u9879\uFF09").action(async (opts) => {
|
|
1468
1659
|
try {
|
|
1469
1660
|
const ide = detectIde();
|
|
1470
|
-
const
|
|
1661
|
+
const cwd = ide.getProjectRoot();
|
|
1662
|
+
const projectRoot = resolveSkillsMaintenanceRoot(cwd);
|
|
1663
|
+
if (projectRoot !== cwd) {
|
|
1664
|
+
logger.info(`Using global skills meta root: ${projectRoot}`);
|
|
1665
|
+
}
|
|
1471
1666
|
const config = await readProjectConfig(projectRoot);
|
|
1472
1667
|
const installedManifest = await readInstalledManifest(projectRoot);
|
|
1473
1668
|
const pkg = installedManifest?.installed.find(
|
|
1474
1669
|
(p) => p.package === SKILLS_PACKAGE
|
|
1475
1670
|
);
|
|
1671
|
+
const skillsLock = await readSkillsLock(projectRoot);
|
|
1476
1672
|
const installedBySkill = /* @__PURE__ */ new Map();
|
|
1477
1673
|
for (const r of pkg?.resources ?? []) {
|
|
1478
1674
|
const skillId = r.id.split(":")[0];
|
|
1479
1675
|
installedBySkill.set(skillId, (installedBySkill.get(skillId) ?? 0) + 1);
|
|
1480
1676
|
}
|
|
1677
|
+
for (const skillId of Object.keys(skillsLock?.skills ?? {})) {
|
|
1678
|
+
if (!installedBySkill.has(skillId)) {
|
|
1679
|
+
installedBySkill.set(skillId, 1);
|
|
1680
|
+
}
|
|
1681
|
+
}
|
|
1481
1682
|
if (opts.installed) {
|
|
1482
1683
|
if (!config?.packages?.skills || !pkg) {
|
|
1483
1684
|
logger.info("No skills installed.");
|
|
@@ -1500,9 +1701,13 @@ var listCommand2 = new Command8("list").alias("ls").description(
|
|
|
1500
1701
|
const skills = [...manifest.skills].sort(
|
|
1501
1702
|
(a, b) => a.id.localeCompare(b.id)
|
|
1502
1703
|
);
|
|
1503
|
-
const isInstalled =
|
|
1504
|
-
if (isInstalled) {
|
|
1704
|
+
const isInstalled = installedBySkill.size > 0;
|
|
1705
|
+
if (isInstalled && config?.packages?.skills && pkg) {
|
|
1505
1706
|
printInstalledHeader(config.packages.skills, pkg.installedAt);
|
|
1707
|
+
} else if (isInstalled) {
|
|
1708
|
+
logger.info(
|
|
1709
|
+
`Installed (${installedBySkill.size} skill(s)) \u2014 config or manifest record missing; run "teamix-evo skills doctor" to repair.`
|
|
1710
|
+
);
|
|
1506
1711
|
} else {
|
|
1507
1712
|
logger.info("Skills package not yet added.");
|
|
1508
1713
|
logger.info(
|
|
@@ -1548,7 +1753,11 @@ var FLAT_VARIANT2 = "_flat";
|
|
|
1548
1753
|
var updateCommand2 = new Command9("update").description("\u66F4\u65B0\u5DF2\u5B89\u88C5\u7684 teamix-evo skills").action(async () => {
|
|
1549
1754
|
try {
|
|
1550
1755
|
const ide = detectIde();
|
|
1551
|
-
const
|
|
1756
|
+
const cwd = ide.getProjectRoot();
|
|
1757
|
+
const projectRoot = resolveSkillsMaintenanceRoot(cwd);
|
|
1758
|
+
if (projectRoot !== cwd) {
|
|
1759
|
+
logger.info(`Using global skills meta root: ${projectRoot}`);
|
|
1760
|
+
}
|
|
1552
1761
|
const config = await readProjectConfig(projectRoot);
|
|
1553
1762
|
if (!config?.packages?.skills) {
|
|
1554
1763
|
logger.error('Skills not added. Run "teamix-evo skills add" first.');
|
|
@@ -1635,12 +1844,21 @@ var updateCommand2 = new Command9("update").description("\u66F4\u65B0\u5DF2\u5B8
|
|
|
1635
1844
|
import { Command as Command10 } from "commander";
|
|
1636
1845
|
import * as prompts3 from "@clack/prompts";
|
|
1637
1846
|
import * as path12 from "path";
|
|
1638
|
-
import * as
|
|
1847
|
+
import * as fs10 from "fs/promises";
|
|
1639
1848
|
var SKILLS_PACKAGE3 = "@teamix-evo/skills";
|
|
1640
|
-
var uninstallCommand2 = new Command10("uninstall").description(
|
|
1849
|
+
var uninstallCommand2 = new Command10("uninstall").description(
|
|
1850
|
+
"\u5378\u8F7D\u5DF2\u5B89\u88C5\u7684 teamix-evo skills\uFF1B\u4E0D\u4F20 ids \u5219\u5378\u8F7D\u6574\u5305\uFF0C\u4F20 ids \u5219\u6309 skill \u5220\u9664"
|
|
1851
|
+
).argument(
|
|
1852
|
+
"[ids...]",
|
|
1853
|
+
"\u53EF\u9009\uFF1A\u4EC5\u5378\u8F7D\u6307\u5B9A skill id\uFF1B\u7701\u7565\u5219\u5378\u8F7D\u6574\u4E2A skills \u5305"
|
|
1854
|
+
).option("-y, --yes", "\u8DF3\u8FC7\u786E\u8BA4").action(async (ids, opts) => {
|
|
1641
1855
|
try {
|
|
1642
1856
|
const ide = detectIde();
|
|
1643
|
-
const
|
|
1857
|
+
const cwd = ide.getProjectRoot();
|
|
1858
|
+
const projectRoot = resolveSkillsMaintenanceRoot(cwd);
|
|
1859
|
+
if (projectRoot !== cwd) {
|
|
1860
|
+
logger.info(`Using global skills meta root: ${projectRoot}`);
|
|
1861
|
+
}
|
|
1644
1862
|
const config = await readProjectConfig(projectRoot);
|
|
1645
1863
|
if (!config?.packages?.skills) {
|
|
1646
1864
|
logger.info("Skills are not installed. Nothing to do.");
|
|
@@ -1651,53 +1869,167 @@ var uninstallCommand2 = new Command10("uninstall").description("\u5378\u8F7D\u5D
|
|
|
1651
1869
|
(p) => p.package === SKILLS_PACKAGE3
|
|
1652
1870
|
);
|
|
1653
1871
|
const resources = pkg?.resources ?? [];
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
|
|
1872
|
+
if (ids.length === 0) {
|
|
1873
|
+
await runFullUninstall({
|
|
1874
|
+
projectRoot,
|
|
1875
|
+
config,
|
|
1876
|
+
installedManifest,
|
|
1877
|
+
pkg,
|
|
1878
|
+
resources,
|
|
1879
|
+
opts
|
|
1661
1880
|
});
|
|
1662
|
-
|
|
1663
|
-
logger.info("Cancelled.");
|
|
1664
|
-
return;
|
|
1665
|
-
}
|
|
1666
|
-
}
|
|
1667
|
-
const removed = await removeSkillFiles(resources);
|
|
1668
|
-
logger.debug(`Removed ${removed.length} files`);
|
|
1669
|
-
const skillsRoot = getSkillsSourceDir(projectRoot);
|
|
1670
|
-
try {
|
|
1671
|
-
await fs9.rm(skillsRoot, { recursive: true, force: true });
|
|
1672
|
-
logger.debug(`Removed source dir ${skillsRoot}`);
|
|
1673
|
-
} catch (err) {
|
|
1674
|
-
logger.warn(
|
|
1675
|
-
`Failed to remove ${skillsRoot}: ${err.message}`
|
|
1676
|
-
);
|
|
1677
|
-
}
|
|
1678
|
-
if (installedManifest && pkg) {
|
|
1679
|
-
installedManifest.installed = installedManifest.installed.filter(
|
|
1680
|
-
(p) => p.package !== SKILLS_PACKAGE3
|
|
1681
|
-
);
|
|
1682
|
-
await writeInstalledManifest(projectRoot, installedManifest);
|
|
1881
|
+
return;
|
|
1683
1882
|
}
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1883
|
+
await runPartialUninstall({
|
|
1884
|
+
projectRoot,
|
|
1885
|
+
installedManifest,
|
|
1886
|
+
pkg,
|
|
1887
|
+
resources,
|
|
1888
|
+
ids,
|
|
1889
|
+
opts
|
|
1890
|
+
});
|
|
1689
1891
|
} catch (err) {
|
|
1690
1892
|
logger.error(`Failed to uninstall: ${err.message}`);
|
|
1691
1893
|
logger.debug(err.stack ?? "");
|
|
1692
1894
|
process.exitCode = 1;
|
|
1693
1895
|
}
|
|
1694
1896
|
});
|
|
1897
|
+
async function runFullUninstall(args) {
|
|
1898
|
+
const { projectRoot, config, installedManifest, pkg, resources, opts } = args;
|
|
1899
|
+
logger.info(
|
|
1900
|
+
`Will remove ${resources.length} skill file(s) installed by ${SKILLS_PACKAGE3}.`
|
|
1901
|
+
);
|
|
1902
|
+
if (!opts.yes) {
|
|
1903
|
+
const confirm4 = await prompts3.confirm({
|
|
1904
|
+
message: "\u786E\u8BA4\u5378\u8F7D\uFF1F\u6B64\u64CD\u4F5C\u4F1A\u5220\u9664\u4E0A\u8FF0\u6587\u4EF6\u3002",
|
|
1905
|
+
initialValue: false
|
|
1906
|
+
});
|
|
1907
|
+
if (prompts3.isCancel(confirm4) || !confirm4) {
|
|
1908
|
+
logger.info("Cancelled.");
|
|
1909
|
+
return;
|
|
1910
|
+
}
|
|
1911
|
+
}
|
|
1912
|
+
const removed = await removeSkillFiles(resources);
|
|
1913
|
+
logger.debug(`Removed ${removed.length} files`);
|
|
1914
|
+
const skillsRoot = getSkillsSourceDir(projectRoot);
|
|
1915
|
+
try {
|
|
1916
|
+
await fs10.rm(skillsRoot, { recursive: true, force: true });
|
|
1917
|
+
logger.debug(`Removed source dir ${skillsRoot}`);
|
|
1918
|
+
} catch (err) {
|
|
1919
|
+
logger.warn(
|
|
1920
|
+
`Failed to remove ${skillsRoot}: ${err.message}`
|
|
1921
|
+
);
|
|
1922
|
+
}
|
|
1923
|
+
if (installedManifest && pkg) {
|
|
1924
|
+
installedManifest.installed = installedManifest.installed.filter(
|
|
1925
|
+
(p) => p.package !== SKILLS_PACKAGE3
|
|
1926
|
+
);
|
|
1927
|
+
await writeInstalledManifest(projectRoot, installedManifest);
|
|
1928
|
+
}
|
|
1929
|
+
delete config.packages.skills;
|
|
1930
|
+
await writeProjectConfig(projectRoot, config);
|
|
1931
|
+
logger.success(`Uninstalled ${SKILLS_PACKAGE3}`);
|
|
1932
|
+
logger.info(` Removed: ${removed.length} files`);
|
|
1933
|
+
logger.info(` Source: ${path12.relative(projectRoot, skillsRoot)} (cleaned)`);
|
|
1934
|
+
}
|
|
1935
|
+
async function runPartialUninstall(args) {
|
|
1936
|
+
const { projectRoot, installedManifest, pkg, resources, ids, opts } = args;
|
|
1937
|
+
const grouped = groupBySkillId(resources);
|
|
1938
|
+
const requested = dedupe(ids);
|
|
1939
|
+
const matched = requested.filter((id) => grouped.has(id));
|
|
1940
|
+
const missing = requested.filter((id) => !grouped.has(id));
|
|
1941
|
+
if (missing.length > 0) {
|
|
1942
|
+
logger.warn(`Not installed (skipped): ${missing.join(", ")}`);
|
|
1943
|
+
}
|
|
1944
|
+
if (matched.length === 0) {
|
|
1945
|
+
logger.info("Nothing to remove.");
|
|
1946
|
+
return;
|
|
1947
|
+
}
|
|
1948
|
+
const toRemove = matched.flatMap(
|
|
1949
|
+
(id) => grouped.get(id) ?? []
|
|
1950
|
+
);
|
|
1951
|
+
logger.info(
|
|
1952
|
+
`Will remove ${matched.length} skill(s): ${matched.join(", ")} (${toRemove.length} file(s)).`
|
|
1953
|
+
);
|
|
1954
|
+
if (!opts.yes) {
|
|
1955
|
+
const confirm4 = await prompts3.confirm({
|
|
1956
|
+
message: "\u786E\u8BA4\u5378\u8F7D\uFF1F\u6B64\u64CD\u4F5C\u4F1A\u5220\u9664\u4E0A\u8FF0\u6587\u4EF6\u3002",
|
|
1957
|
+
initialValue: false
|
|
1958
|
+
});
|
|
1959
|
+
if (prompts3.isCancel(confirm4) || !confirm4) {
|
|
1960
|
+
logger.info("Cancelled.");
|
|
1961
|
+
return;
|
|
1962
|
+
}
|
|
1963
|
+
}
|
|
1964
|
+
const removed = await removeSkillFiles(toRemove);
|
|
1965
|
+
logger.debug(`Removed ${removed.length} files`);
|
|
1966
|
+
for (const id of matched) {
|
|
1967
|
+
const dir = getSkillsSourceDir(projectRoot, id);
|
|
1968
|
+
try {
|
|
1969
|
+
await fs10.rm(dir, { recursive: true, force: true });
|
|
1970
|
+
logger.debug(`Removed source dir ${dir}`);
|
|
1971
|
+
} catch (err) {
|
|
1972
|
+
logger.warn(`Failed to remove ${dir}: ${err.message}`);
|
|
1973
|
+
}
|
|
1974
|
+
}
|
|
1975
|
+
const lock = await readSkillsLock(projectRoot);
|
|
1976
|
+
if (lock) {
|
|
1977
|
+
for (const id of matched) delete lock.skills[id];
|
|
1978
|
+
await writeSkillsLock(projectRoot, lock);
|
|
1979
|
+
}
|
|
1980
|
+
if (installedManifest && pkg) {
|
|
1981
|
+
pkg.resources = resources.filter((r) => !matched.includes(skillIdOf(r)));
|
|
1982
|
+
await writeInstalledManifest(projectRoot, installedManifest);
|
|
1983
|
+
}
|
|
1984
|
+
logger.success(
|
|
1985
|
+
`Removed ${matched.length} skill(s): ${matched.join(", ")}`
|
|
1986
|
+
);
|
|
1987
|
+
logger.info(` Files: ${removed.length}`);
|
|
1988
|
+
if (missing.length > 0) {
|
|
1989
|
+
logger.info(` Skipped: ${missing.join(", ")} (not installed)`);
|
|
1990
|
+
}
|
|
1991
|
+
}
|
|
1992
|
+
function skillIdOf(r) {
|
|
1993
|
+
return r.id.split(":")[0];
|
|
1994
|
+
}
|
|
1995
|
+
function groupBySkillId(records) {
|
|
1996
|
+
const map = /* @__PURE__ */ new Map();
|
|
1997
|
+
for (const r of records) {
|
|
1998
|
+
const id = skillIdOf(r);
|
|
1999
|
+
const bucket = map.get(id);
|
|
2000
|
+
if (bucket) bucket.push(r);
|
|
2001
|
+
else map.set(id, [r]);
|
|
2002
|
+
}
|
|
2003
|
+
return map;
|
|
2004
|
+
}
|
|
2005
|
+
function dedupe(values) {
|
|
2006
|
+
return Array.from(new Set(values));
|
|
2007
|
+
}
|
|
1695
2008
|
|
|
1696
2009
|
// src/commands/skills/sync.ts
|
|
1697
2010
|
import { Command as Command11 } from "commander";
|
|
1698
2011
|
|
|
1699
2012
|
// src/core/skills-sync.ts
|
|
1700
|
-
import * as
|
|
2013
|
+
import * as path13 from "path";
|
|
2014
|
+
import * as fs11 from "fs/promises";
|
|
2015
|
+
import { createRequire as createRequire4 } from "module";
|
|
2016
|
+
import { loadSkillsPackageManifest as loadSkillsPackageManifest2 } from "@teamix-evo/registry";
|
|
2017
|
+
var require5 = createRequire4(import.meta.url);
|
|
2018
|
+
async function readSkillMetaFromUpstream(skillId) {
|
|
2019
|
+
try {
|
|
2020
|
+
const pkgJson = require5.resolve("@teamix-evo/skills/package.json");
|
|
2021
|
+
const packageRoot = path13.dirname(pkgJson);
|
|
2022
|
+
const manifest = await loadSkillsPackageManifest2(packageRoot);
|
|
2023
|
+
const entry = manifest.skills.find((s) => s.id === skillId);
|
|
2024
|
+
if (!entry) return null;
|
|
2025
|
+
return {
|
|
2026
|
+
updateStrategy: entry.updateStrategy,
|
|
2027
|
+
managedRegions: entry.managedRegions
|
|
2028
|
+
};
|
|
2029
|
+
} catch {
|
|
2030
|
+
return null;
|
|
2031
|
+
}
|
|
2032
|
+
}
|
|
1701
2033
|
var SKILLS_PACKAGE_DEFAULT = "@teamix-evo/skills";
|
|
1702
2034
|
async function runSkillsSync(options) {
|
|
1703
2035
|
const { projectRoot, names } = options;
|
|
@@ -1731,13 +2063,15 @@ async function runSkillsSync(options) {
|
|
|
1731
2063
|
logger.warn(`Skill "${skillId}" has no IDE mirror targets; skipped.`);
|
|
1732
2064
|
continue;
|
|
1733
2065
|
}
|
|
2066
|
+
const upstreamMeta = await readSkillMetaFromUpstream(skillId);
|
|
1734
2067
|
const result = await syncSkillsToIdes({
|
|
1735
2068
|
projectRoot,
|
|
1736
2069
|
skills: [
|
|
1737
2070
|
{
|
|
1738
2071
|
id: skillId,
|
|
1739
2072
|
name: skillId,
|
|
1740
|
-
updateStrategy: "regenerable"
|
|
2073
|
+
updateStrategy: upstreamMeta?.updateStrategy ?? "regenerable",
|
|
2074
|
+
managedRegions: upstreamMeta?.managedRegions
|
|
1741
2075
|
}
|
|
1742
2076
|
],
|
|
1743
2077
|
ides,
|
|
@@ -1764,7 +2098,7 @@ async function runSkillsSync(options) {
|
|
|
1764
2098
|
}
|
|
1765
2099
|
async function dirExists(p) {
|
|
1766
2100
|
try {
|
|
1767
|
-
const stat4 = await
|
|
2101
|
+
const stat4 = await fs11.stat(p);
|
|
1768
2102
|
return stat4.isDirectory();
|
|
1769
2103
|
} catch {
|
|
1770
2104
|
return false;
|
|
@@ -1796,7 +2130,11 @@ var syncCommand = new Command11("sync").description(
|
|
|
1796
2130
|
).action(async (names, opts) => {
|
|
1797
2131
|
try {
|
|
1798
2132
|
const ide = detectIde();
|
|
1799
|
-
const
|
|
2133
|
+
const cwd = ide.getProjectRoot();
|
|
2134
|
+
const projectRoot = resolveSkillsMaintenanceRoot(cwd);
|
|
2135
|
+
if (projectRoot !== cwd) {
|
|
2136
|
+
logger.info(`Using global skills meta root: ${projectRoot}`);
|
|
2137
|
+
}
|
|
1800
2138
|
const ides = opts.ide ? parseIdeList2(opts.ide) : void 0;
|
|
1801
2139
|
const scope = opts.scope ? parseScope2(opts.scope) : void 0;
|
|
1802
2140
|
const result = await runSkillsSync({
|
|
@@ -1854,8 +2192,8 @@ function parseScope2(input) {
|
|
|
1854
2192
|
import { Command as Command12 } from "commander";
|
|
1855
2193
|
|
|
1856
2194
|
// src/core/skills-doctor.ts
|
|
1857
|
-
import * as
|
|
1858
|
-
import * as
|
|
2195
|
+
import * as path14 from "path";
|
|
2196
|
+
import * as fs12 from "fs/promises";
|
|
1859
2197
|
async function runSkillsDoctor(options) {
|
|
1860
2198
|
const { projectRoot } = options;
|
|
1861
2199
|
const lock = await readSkillsLock(projectRoot);
|
|
@@ -1877,8 +2215,8 @@ async function runSkillsDoctor(options) {
|
|
|
1877
2215
|
const sourceFiles = await walkDir(sourceDir);
|
|
1878
2216
|
const sourceContents = /* @__PURE__ */ new Map();
|
|
1879
2217
|
for (const f of sourceFiles) {
|
|
1880
|
-
const rel2 =
|
|
1881
|
-
sourceContents.set(rel2, await
|
|
2218
|
+
const rel2 = path14.relative(sourceDir, f);
|
|
2219
|
+
sourceContents.set(rel2, await fs12.readFile(f, "utf-8"));
|
|
1882
2220
|
}
|
|
1883
2221
|
for (const ide of entry.mirroredTo) {
|
|
1884
2222
|
const adapter = getAdapter(ide);
|
|
@@ -1899,7 +2237,7 @@ async function runSkillsDoctor(options) {
|
|
|
1899
2237
|
continue;
|
|
1900
2238
|
}
|
|
1901
2239
|
for (const [rel2, sourceContent] of sourceContents.entries()) {
|
|
1902
|
-
const mirrorFile =
|
|
2240
|
+
const mirrorFile = path14.join(mirrorDir, rel2);
|
|
1903
2241
|
if (!await fileExists(mirrorFile)) {
|
|
1904
2242
|
findings.push({
|
|
1905
2243
|
kind: "missing-mirror",
|
|
@@ -1911,7 +2249,7 @@ async function runSkillsDoctor(options) {
|
|
|
1911
2249
|
});
|
|
1912
2250
|
continue;
|
|
1913
2251
|
}
|
|
1914
|
-
const mirrorContent = await
|
|
2252
|
+
const mirrorContent = await fs12.readFile(mirrorFile, "utf-8");
|
|
1915
2253
|
if (computeHash(mirrorContent) !== computeHash(sourceContent)) {
|
|
1916
2254
|
findings.push({
|
|
1917
2255
|
kind: "mirror-drift",
|
|
@@ -1932,7 +2270,7 @@ async function runSkillsDoctor(options) {
|
|
|
1932
2270
|
}
|
|
1933
2271
|
async function dirExists2(p) {
|
|
1934
2272
|
try {
|
|
1935
|
-
const stat4 = await
|
|
2273
|
+
const stat4 = await fs12.stat(p);
|
|
1936
2274
|
return stat4.isDirectory();
|
|
1937
2275
|
} catch {
|
|
1938
2276
|
return false;
|
|
@@ -1945,7 +2283,11 @@ var doctorCommand = new Command12("doctor").description(
|
|
|
1945
2283
|
).action(async () => {
|
|
1946
2284
|
try {
|
|
1947
2285
|
const ide = detectIde();
|
|
1948
|
-
const
|
|
2286
|
+
const cwd = ide.getProjectRoot();
|
|
2287
|
+
const projectRoot = resolveSkillsMaintenanceRoot(cwd);
|
|
2288
|
+
if (projectRoot !== cwd) {
|
|
2289
|
+
logger.info(`Using global skills meta root: ${projectRoot}`);
|
|
2290
|
+
}
|
|
1949
2291
|
const result = await runSkillsDoctor({ projectRoot });
|
|
1950
2292
|
if (result.status === "no-skills") {
|
|
1951
2293
|
logger.info(
|
|
@@ -1993,6 +2335,35 @@ import { Command as Command14 } from "commander";
|
|
|
1993
2335
|
import * as prompts4 from "@clack/prompts";
|
|
1994
2336
|
|
|
1995
2337
|
// src/core/ui-init.ts
|
|
2338
|
+
import * as fs13 from "fs/promises";
|
|
2339
|
+
import { createRequire as createRequire5 } from "module";
|
|
2340
|
+
import * as path15 from "path";
|
|
2341
|
+
var require6 = createRequire5(import.meta.url);
|
|
2342
|
+
async function deployPreferencesCss(projectRoot) {
|
|
2343
|
+
const targetDir = path15.join(projectRoot, "src");
|
|
2344
|
+
const targetPath = path15.join(targetDir, "preferences.css");
|
|
2345
|
+
try {
|
|
2346
|
+
await fs13.access(targetPath);
|
|
2347
|
+
logger.debug(`preferences.css already exists at ${targetPath}, skipping`);
|
|
2348
|
+
return "skipped";
|
|
2349
|
+
} catch {
|
|
2350
|
+
}
|
|
2351
|
+
let sourcePath;
|
|
2352
|
+
try {
|
|
2353
|
+
const uiPkgJson = require6.resolve("@teamix-evo/ui/package.json");
|
|
2354
|
+
sourcePath = path15.join(path15.dirname(uiPkgJson), "src", "preferences.css");
|
|
2355
|
+
await fs13.access(sourcePath);
|
|
2356
|
+
} catch {
|
|
2357
|
+
logger.debug(
|
|
2358
|
+
"Could not resolve @teamix-evo/ui/src/preferences.css; skipping deploy"
|
|
2359
|
+
);
|
|
2360
|
+
return "source-missing";
|
|
2361
|
+
}
|
|
2362
|
+
await fs13.mkdir(targetDir, { recursive: true });
|
|
2363
|
+
const content = await fs13.readFile(sourcePath, "utf-8");
|
|
2364
|
+
await fs13.writeFile(targetPath, content, "utf-8");
|
|
2365
|
+
return "deployed";
|
|
2366
|
+
}
|
|
1996
2367
|
var DEFAULT_UI_ALIASES = {
|
|
1997
2368
|
components: "src/components/ui",
|
|
1998
2369
|
hooks: "src/hooks",
|
|
@@ -2036,12 +2407,14 @@ async function runUiInit(options) {
|
|
|
2036
2407
|
rsc
|
|
2037
2408
|
};
|
|
2038
2409
|
await writeProjectConfig(projectRoot, config);
|
|
2410
|
+
const preferencesCss = await deployPreferencesCss(projectRoot);
|
|
2039
2411
|
return {
|
|
2040
2412
|
status: "installed",
|
|
2041
2413
|
aliases,
|
|
2042
2414
|
iconLibrary,
|
|
2043
2415
|
tsx,
|
|
2044
|
-
rsc
|
|
2416
|
+
rsc,
|
|
2417
|
+
preferencesCss
|
|
2045
2418
|
};
|
|
2046
2419
|
}
|
|
2047
2420
|
|
|
@@ -2078,6 +2451,14 @@ var initCommand2 = new Command14("init").description(
|
|
|
2078
2451
|
logger.info(` lib: ${result.aliases.lib}`);
|
|
2079
2452
|
logger.info(` iconLibrary: ${result.iconLibrary}`);
|
|
2080
2453
|
logger.info(` tsx: ${result.tsx}, rsc: ${result.rsc}`);
|
|
2454
|
+
if (result.preferencesCss === "deployed") {
|
|
2455
|
+
logger.info(" preferences.css: deployed \u2192 src/preferences.css");
|
|
2456
|
+
logger.info(
|
|
2457
|
+
" \u5728 src/index.css \u9876\u90E8\u52A0 `@import './preferences.css';` \u542F\u7528 shadcn \u5168\u5C40\u504F\u597D"
|
|
2458
|
+
);
|
|
2459
|
+
} else if (result.preferencesCss === "skipped") {
|
|
2460
|
+
logger.info(" preferences.css: \u5DF2\u5B58\u5728,\u4FDD\u7559\u7528\u6237\u7248\u672C");
|
|
2461
|
+
}
|
|
2081
2462
|
logger.info("");
|
|
2082
2463
|
logger.info("Next: `npx teamix-evo ui add button`");
|
|
2083
2464
|
} catch (err) {
|
|
@@ -2156,23 +2537,23 @@ async function resolveConfig(opts) {
|
|
|
2156
2537
|
import { Command as Command15 } from "commander";
|
|
2157
2538
|
|
|
2158
2539
|
// src/core/ui-client.ts
|
|
2159
|
-
import * as
|
|
2160
|
-
import * as
|
|
2161
|
-
import { createRequire as
|
|
2540
|
+
import * as path16 from "path";
|
|
2541
|
+
import * as fs14 from "fs/promises";
|
|
2542
|
+
import { createRequire as createRequire6 } from "module";
|
|
2162
2543
|
import { loadUiPackageManifest } from "@teamix-evo/registry";
|
|
2163
|
-
var
|
|
2544
|
+
var require7 = createRequire6(import.meta.url);
|
|
2164
2545
|
function resolvePackageRoot2(packageName) {
|
|
2165
|
-
const pkgJsonPath =
|
|
2166
|
-
return
|
|
2546
|
+
const pkgJsonPath = require7.resolve(`${packageName}/package.json`);
|
|
2547
|
+
return path16.dirname(pkgJsonPath);
|
|
2167
2548
|
}
|
|
2168
2549
|
async function loadUiData(packageName) {
|
|
2169
2550
|
const packageRoot = resolvePackageRoot2(packageName);
|
|
2170
2551
|
logger.debug(`Resolved ui package root: ${packageRoot}`);
|
|
2171
2552
|
const manifest = await loadUiPackageManifest(packageRoot);
|
|
2172
2553
|
let data = {};
|
|
2173
|
-
const dataPath =
|
|
2554
|
+
const dataPath = path16.join(packageRoot, "_data.json");
|
|
2174
2555
|
try {
|
|
2175
|
-
const raw = await
|
|
2556
|
+
const raw = await fs14.readFile(dataPath, "utf-8");
|
|
2176
2557
|
data = JSON.parse(raw);
|
|
2177
2558
|
} catch (err) {
|
|
2178
2559
|
if (err.code !== "ENOENT") {
|
|
@@ -2184,8 +2565,8 @@ async function loadUiData(packageName) {
|
|
|
2184
2565
|
}
|
|
2185
2566
|
|
|
2186
2567
|
// src/core/ui-installer.ts
|
|
2187
|
-
import * as
|
|
2188
|
-
import * as
|
|
2568
|
+
import * as path17 from "path";
|
|
2569
|
+
import * as fs15 from "fs/promises";
|
|
2189
2570
|
import { resolveUiEntryOrder } from "@teamix-evo/registry";
|
|
2190
2571
|
|
|
2191
2572
|
// src/utils/transform-imports.ts
|
|
@@ -2225,12 +2606,12 @@ function aliasToImportPath(alias) {
|
|
|
2225
2606
|
}
|
|
2226
2607
|
|
|
2227
2608
|
// src/core/ui-installer.ts
|
|
2228
|
-
var DESIGN_COMPONENTS_DIR = ".teamix-evo/design/components";
|
|
2229
2609
|
async function installUiEntries(options) {
|
|
2230
2610
|
const {
|
|
2231
2611
|
projectRoot,
|
|
2232
2612
|
manifest,
|
|
2233
2613
|
packageRoot,
|
|
2614
|
+
entryPackageRoot,
|
|
2234
2615
|
aliases,
|
|
2235
2616
|
requested,
|
|
2236
2617
|
skipExisting = true
|
|
@@ -2239,7 +2620,6 @@ async function installUiEntries(options) {
|
|
|
2239
2620
|
const idToEntry = new Map(manifest.entries.map((e) => [e.id, e]));
|
|
2240
2621
|
const resources = [];
|
|
2241
2622
|
const npmDeps = {};
|
|
2242
|
-
const metaFiles = [];
|
|
2243
2623
|
let written = 0;
|
|
2244
2624
|
let skipped = 0;
|
|
2245
2625
|
for (const id of orderedIds) {
|
|
@@ -2258,8 +2638,9 @@ async function installUiEntries(options) {
|
|
|
2258
2638
|
skipped++;
|
|
2259
2639
|
continue;
|
|
2260
2640
|
}
|
|
2261
|
-
const
|
|
2262
|
-
const
|
|
2641
|
+
const rootForEntry = entryPackageRoot?.get(entry.id) ?? packageRoot;
|
|
2642
|
+
const sourceAbs = path17.resolve(rootForEntry, file.source);
|
|
2643
|
+
const raw = await fs15.readFile(sourceAbs, "utf-8");
|
|
2263
2644
|
const transformed = rewriteImports(raw, aliases);
|
|
2264
2645
|
await writeFileSafe(targetAbs, transformed);
|
|
2265
2646
|
written++;
|
|
@@ -2271,32 +2652,13 @@ async function installUiEntries(options) {
|
|
|
2271
2652
|
strategy: entry.updateStrategy ?? "frozen"
|
|
2272
2653
|
});
|
|
2273
2654
|
}
|
|
2274
|
-
if (entry.meta) {
|
|
2275
|
-
const metaSourceAbs = path15.resolve(packageRoot, entry.meta);
|
|
2276
|
-
const metaContent = await fs13.readFile(metaSourceAbs, "utf-8");
|
|
2277
|
-
const metaTargetAbs = path15.join(
|
|
2278
|
-
projectRoot,
|
|
2279
|
-
DESIGN_COMPONENTS_DIR,
|
|
2280
|
-
`${entry.id}.meta.md`
|
|
2281
|
-
);
|
|
2282
|
-
await writeFileSafe(metaTargetAbs, metaContent);
|
|
2283
|
-
metaFiles.push(metaTargetAbs);
|
|
2284
|
-
resources.push({
|
|
2285
|
-
id: `${entry.id}:meta`,
|
|
2286
|
-
target: metaTargetAbs,
|
|
2287
|
-
hash: computeHash(metaContent),
|
|
2288
|
-
strategy: "regenerable"
|
|
2289
|
-
});
|
|
2290
|
-
logger.info(` meta: ${rel(projectRoot, metaTargetAbs)}`);
|
|
2291
|
-
}
|
|
2292
2655
|
}
|
|
2293
2656
|
return {
|
|
2294
2657
|
orderedIds,
|
|
2295
2658
|
resources,
|
|
2296
2659
|
npmDependencies: npmDeps,
|
|
2297
2660
|
written,
|
|
2298
|
-
skipped
|
|
2299
|
-
metaFiles
|
|
2661
|
+
skipped
|
|
2300
2662
|
};
|
|
2301
2663
|
}
|
|
2302
2664
|
function resolveTargetPath(projectRoot, aliases, entry, file) {
|
|
@@ -2306,10 +2668,10 @@ function resolveTargetPath(projectRoot, aliases, entry, file) {
|
|
|
2306
2668
|
`Entry "${entry.id}" requires alias "${file.targetAlias}" but it is not configured.`
|
|
2307
2669
|
);
|
|
2308
2670
|
}
|
|
2309
|
-
return
|
|
2671
|
+
return path17.join(projectRoot, aliasDir, file.targetName);
|
|
2310
2672
|
}
|
|
2311
2673
|
function rel(projectRoot, abs) {
|
|
2312
|
-
return
|
|
2674
|
+
return path17.relative(projectRoot, abs);
|
|
2313
2675
|
}
|
|
2314
2676
|
|
|
2315
2677
|
// src/core/ui-add.ts
|
|
@@ -2371,7 +2733,6 @@ async function runUiAdd(options) {
|
|
|
2371
2733
|
orderedIds: result.orderedIds,
|
|
2372
2734
|
written: result.written,
|
|
2373
2735
|
skipped: result.skipped,
|
|
2374
|
-
metaFiles: result.metaFiles,
|
|
2375
2736
|
npmDependencies: result.npmDependencies,
|
|
2376
2737
|
resources: result.resources
|
|
2377
2738
|
};
|
|
@@ -2397,7 +2758,7 @@ var addCommand2 = new Command15("add").description(
|
|
|
2397
2758
|
overwrite: opts.overwrite
|
|
2398
2759
|
});
|
|
2399
2760
|
logger.success(
|
|
2400
|
-
`UI add complete: ${result.written} written, ${result.skipped} skipped
|
|
2761
|
+
`UI add complete: ${result.written} written, ${result.skipped} skipped.`
|
|
2401
2762
|
);
|
|
2402
2763
|
logger.info("");
|
|
2403
2764
|
logger.info(`Resolved order: ${result.orderedIds.join(" \u2192 ")}`);
|
|
@@ -2409,12 +2770,6 @@ var addCommand2 = new Command15("add").description(
|
|
|
2409
2770
|
logger.info(` pnpm add ${installCmd}`);
|
|
2410
2771
|
logger.info(` # or: npm install ${installCmd}`);
|
|
2411
2772
|
}
|
|
2412
|
-
if (result.metaFiles.length > 0) {
|
|
2413
|
-
logger.info("");
|
|
2414
|
-
logger.info(
|
|
2415
|
-
"Component meta dropped under .teamix-evo/design/components/ (AI-readable)."
|
|
2416
|
-
);
|
|
2417
|
-
}
|
|
2418
2773
|
} catch (err) {
|
|
2419
2774
|
const message = err.message;
|
|
2420
2775
|
if (message.startsWith("UI not initialized")) {
|
|
@@ -2514,22 +2869,23 @@ uiCommand.addCommand(addCommand2);
|
|
|
2514
2869
|
uiCommand.addCommand(listCommand3);
|
|
2515
2870
|
|
|
2516
2871
|
// src/commands/biz-ui/index.ts
|
|
2517
|
-
import { Command as
|
|
2872
|
+
import { Command as Command21 } from "commander";
|
|
2518
2873
|
|
|
2519
2874
|
// src/commands/biz-ui/add.ts
|
|
2520
2875
|
import { Command as Command18 } from "commander";
|
|
2521
2876
|
|
|
2522
2877
|
// src/core/variant-ui-add.ts
|
|
2523
|
-
import * as
|
|
2524
|
-
import { createRequire as
|
|
2878
|
+
import * as path18 from "path";
|
|
2879
|
+
import { createRequire as createRequire7 } from "module";
|
|
2525
2880
|
import {
|
|
2881
|
+
loadUiPackageManifest as loadUiPackageManifest2,
|
|
2526
2882
|
loadVariantUiPackageCatalog,
|
|
2527
2883
|
loadVariantUiPackageManifest
|
|
2528
2884
|
} from "@teamix-evo/registry";
|
|
2529
|
-
var
|
|
2885
|
+
var require8 = createRequire7(import.meta.url);
|
|
2530
2886
|
function resolvePackageRoot3(packageName) {
|
|
2531
|
-
const pkgJsonPath =
|
|
2532
|
-
return
|
|
2887
|
+
const pkgJsonPath = require8.resolve(`${packageName}/package.json`);
|
|
2888
|
+
return path18.dirname(pkgJsonPath);
|
|
2533
2889
|
}
|
|
2534
2890
|
async function runVariantUiAdd(packageName, options) {
|
|
2535
2891
|
const { projectRoot, variant, ids, overwrite } = options;
|
|
@@ -2552,27 +2908,42 @@ async function runVariantUiAdd(packageName, options) {
|
|
|
2552
2908
|
`Variant "${variant}" not found in ${fullPackageName}. Known variants: ${known}. Hint: \`teamix-evo ${packageName} list-variants\` shows all.`
|
|
2553
2909
|
);
|
|
2554
2910
|
}
|
|
2555
|
-
const variantDir =
|
|
2911
|
+
const variantDir = path18.join(packageRoot, "variants", variant);
|
|
2556
2912
|
const variantManifest = await loadVariantUiPackageManifest(variantDir);
|
|
2557
2913
|
const knownIds = new Set(variantManifest.entries.map((e) => e.id));
|
|
2558
2914
|
const unknown = ids.filter((id) => !knownIds.has(id));
|
|
2559
2915
|
if (unknown.length > 0) {
|
|
2560
2916
|
throw new Error(
|
|
2561
|
-
`Unknown entry id(s) in ${packageName}#${variant}: ${unknown.map((s) => `"${s}"`).join(", ")}. Run \`teamix-evo ${packageName} list --variant ${variant}\`
|
|
2917
|
+
`Unknown entry id(s) in ${packageName}#${variant}: ${unknown.map((s) => `"${s}"`).join(", ")}. Run \`teamix-evo ${packageName} list-variants\` to see this package's variants, or \`teamix-evo ${packageName} list --variant ${variant}\` for its entries.`
|
|
2562
2918
|
);
|
|
2563
2919
|
}
|
|
2920
|
+
const uiPackageRoot = resolvePackageRoot3("@teamix-evo/ui");
|
|
2921
|
+
const uiManifest = await loadUiPackageManifest2(uiPackageRoot);
|
|
2922
|
+
const entryPackageRoot = /* @__PURE__ */ new Map();
|
|
2923
|
+
const mergedEntries = [];
|
|
2924
|
+
for (const e of variantManifest.entries) {
|
|
2925
|
+
entryPackageRoot.set(e.id, variantDir);
|
|
2926
|
+
mergedEntries.push(e);
|
|
2927
|
+
}
|
|
2928
|
+
for (const e of uiManifest.entries) {
|
|
2929
|
+
if (entryPackageRoot.has(e.id)) continue;
|
|
2930
|
+
entryPackageRoot.set(e.id, uiPackageRoot);
|
|
2931
|
+
mergedEntries.push(e);
|
|
2932
|
+
}
|
|
2564
2933
|
const adaptedManifest = {
|
|
2565
2934
|
schemaVersion: 1,
|
|
2566
2935
|
package: "ui",
|
|
2567
2936
|
version: variantManifest.version,
|
|
2568
2937
|
engines: variantManifest.engines,
|
|
2569
|
-
entries:
|
|
2938
|
+
entries: mergedEntries
|
|
2570
2939
|
};
|
|
2571
2940
|
const result = await installUiEntries({
|
|
2572
2941
|
projectRoot,
|
|
2573
2942
|
manifest: adaptedManifest,
|
|
2574
2943
|
packageRoot: variantDir,
|
|
2575
|
-
//
|
|
2944
|
+
// default for variant entries
|
|
2945
|
+
entryPackageRoot,
|
|
2946
|
+
// ui entries resolve from uiPackageRoot
|
|
2576
2947
|
aliases: uiCfg.aliases,
|
|
2577
2948
|
requested: ids,
|
|
2578
2949
|
skipExisting: !overwrite
|
|
@@ -2604,7 +2975,6 @@ async function runVariantUiAdd(packageName, options) {
|
|
|
2604
2975
|
orderedIds: result.orderedIds,
|
|
2605
2976
|
written: result.written,
|
|
2606
2977
|
skipped: result.skipped,
|
|
2607
|
-
metaFiles: result.metaFiles,
|
|
2608
2978
|
npmDependencies: result.npmDependencies,
|
|
2609
2979
|
resources: result.resources
|
|
2610
2980
|
};
|
|
@@ -2641,6 +3011,36 @@ async function listBizUiVariants(packageRoot) {
|
|
|
2641
3011
|
async function listTemplatesVariants(packageRoot) {
|
|
2642
3012
|
return listVariantUi("templates", packageRoot);
|
|
2643
3013
|
}
|
|
3014
|
+
async function listVariantUiEntries(packageName, variant, packageRoot) {
|
|
3015
|
+
const fullPackageName = `@teamix-evo/${packageName}`;
|
|
3016
|
+
const root = packageRoot ?? resolvePackageRoot3(fullPackageName);
|
|
3017
|
+
const catalog = await loadVariantUiPackageCatalog(root);
|
|
3018
|
+
if (!catalog.variants.some((v) => v.name === variant)) {
|
|
3019
|
+
const known = catalog.variants.map((v) => v.name).join(", ");
|
|
3020
|
+
throw new Error(
|
|
3021
|
+
`Variant "${variant}" not found in ${fullPackageName}. Known: ${known}.`
|
|
3022
|
+
);
|
|
3023
|
+
}
|
|
3024
|
+
const variantDir = path18.join(root, "variants", variant);
|
|
3025
|
+
const variantManifest = await loadVariantUiPackageManifest(variantDir);
|
|
3026
|
+
return {
|
|
3027
|
+
packageName: fullPackageName,
|
|
3028
|
+
variant,
|
|
3029
|
+
entries: variantManifest.entries.map((e) => ({
|
|
3030
|
+
id: e.id,
|
|
3031
|
+
name: e.name,
|
|
3032
|
+
type: e.type,
|
|
3033
|
+
description: e.description,
|
|
3034
|
+
registryDependencies: e.registryDependencies ?? []
|
|
3035
|
+
}))
|
|
3036
|
+
};
|
|
3037
|
+
}
|
|
3038
|
+
async function listBizUiEntries(variant, packageRoot) {
|
|
3039
|
+
return listVariantUiEntries("biz-ui", variant, packageRoot);
|
|
3040
|
+
}
|
|
3041
|
+
async function listTemplatesEntries(variant, packageRoot) {
|
|
3042
|
+
return listVariantUiEntries("templates", variant, packageRoot);
|
|
3043
|
+
}
|
|
2644
3044
|
|
|
2645
3045
|
// src/commands/biz-ui/add.ts
|
|
2646
3046
|
var addCommand3 = new Command18("add").description(
|
|
@@ -2665,7 +3065,7 @@ var addCommand3 = new Command18("add").description(
|
|
|
2665
3065
|
overwrite: opts.overwrite
|
|
2666
3066
|
});
|
|
2667
3067
|
logger.success(
|
|
2668
|
-
`biz-ui add complete: ${result.written} written, ${result.skipped} skipped
|
|
3068
|
+
`biz-ui add complete: ${result.written} written, ${result.skipped} skipped.`
|
|
2669
3069
|
);
|
|
2670
3070
|
logger.info("");
|
|
2671
3071
|
logger.info(`Variant: ${result.variant}`);
|
|
@@ -2685,9 +3085,35 @@ var addCommand3 = new Command18("add").description(
|
|
|
2685
3085
|
}
|
|
2686
3086
|
);
|
|
2687
3087
|
|
|
2688
|
-
// src/commands/biz-ui/list
|
|
3088
|
+
// src/commands/biz-ui/list.ts
|
|
2689
3089
|
import { Command as Command19 } from "commander";
|
|
2690
|
-
var
|
|
3090
|
+
var listCommand4 = new Command19("list").description("\u5217\u51FA\u6307\u5B9A\u53D8\u4F53\u4E0B\u7684 biz-ui entries").requiredOption("--variant <name>", "\u53D8\u4F53\u540D\uFF08\u5982 opentrek / uni-manager\uFF09").action(async (opts) => {
|
|
3091
|
+
try {
|
|
3092
|
+
const result = await listBizUiEntries(opts.variant);
|
|
3093
|
+
logger.info(`${result.packageName}#${result.variant} entries:`);
|
|
3094
|
+
logger.info("");
|
|
3095
|
+
if (result.entries.length === 0) {
|
|
3096
|
+
logger.info(" (no entries \u2014 variant skeleton, awaiting components)");
|
|
3097
|
+
return;
|
|
3098
|
+
}
|
|
3099
|
+
for (const e of result.entries) {
|
|
3100
|
+
const deps = e.registryDependencies.length ? ` [deps: ${e.registryDependencies.join(", ")}]` : "";
|
|
3101
|
+
logger.info(` ${e.id} (${e.type})${deps}`);
|
|
3102
|
+
if (e.description) logger.info(` ${e.description}`);
|
|
3103
|
+
logger.info("");
|
|
3104
|
+
}
|
|
3105
|
+
logger.info(
|
|
3106
|
+
`Install: teamix-evo biz-ui add <id> --variant ${result.variant}`
|
|
3107
|
+
);
|
|
3108
|
+
} catch (err) {
|
|
3109
|
+
logger.error(`Failed: ${err.message}`);
|
|
3110
|
+
process.exitCode = 1;
|
|
3111
|
+
}
|
|
3112
|
+
});
|
|
3113
|
+
|
|
3114
|
+
// src/commands/biz-ui/list-variants.ts
|
|
3115
|
+
import { Command as Command20 } from "commander";
|
|
3116
|
+
var listVariantsCommand2 = new Command20("list-variants").description("\u5217\u51FA @teamix-evo/biz-ui \u5305\u5185\u63D0\u4F9B\u7684\u6240\u6709\u4E1A\u52A1\u53D8\u4F53").action(async () => {
|
|
2691
3117
|
try {
|
|
2692
3118
|
const result = await listBizUiVariants();
|
|
2693
3119
|
logger.info(`Available biz-ui variants in ${result.packageName}:`);
|
|
@@ -2709,18 +3135,19 @@ var listVariantsCommand2 = new Command19("list-variants").description("\u5217\u5
|
|
|
2709
3135
|
});
|
|
2710
3136
|
|
|
2711
3137
|
// src/commands/biz-ui/index.ts
|
|
2712
|
-
var bizUiCommand = new
|
|
3138
|
+
var bizUiCommand = new Command21("biz-ui").description(
|
|
2713
3139
|
"\u7BA1\u7406\u4E1A\u52A1 UI \u7EC4\u4EF6(\u53D8\u4F53\u611F\u77E5 \u2014 \u4E0E design / templates \u540C\u53D8\u4F53\u540D\u7A7A\u95F4)"
|
|
2714
3140
|
);
|
|
2715
3141
|
bizUiCommand.addCommand(addCommand3);
|
|
3142
|
+
bizUiCommand.addCommand(listCommand4);
|
|
2716
3143
|
bizUiCommand.addCommand(listVariantsCommand2);
|
|
2717
3144
|
|
|
2718
3145
|
// src/commands/templates/index.ts
|
|
2719
|
-
import { Command as
|
|
3146
|
+
import { Command as Command25 } from "commander";
|
|
2720
3147
|
|
|
2721
3148
|
// src/commands/templates/add.ts
|
|
2722
|
-
import { Command as
|
|
2723
|
-
var addCommand4 = new
|
|
3149
|
+
import { Command as Command22 } from "commander";
|
|
3150
|
+
var addCommand4 = new Command22("add").description(
|
|
2724
3151
|
"\u5B89\u88C5\u4E00\u4E2A\u6216\u591A\u4E2A\u9875\u9762\u6A21\u677F(\u6309 id,\u81EA\u52A8\u5C55\u5F00 ui \u5305\u7684 registryDependencies)"
|
|
2725
3152
|
).argument("<ids...>", '\u6A21\u677F id \u5217\u8868,\u5982 "list-detail-page"').option("--variant <name>", '\u53D8\u4F53 id(\u5FC5\u586B,\u5982 "opentrek"\u3001"uni-manager")').option("--overwrite", "\u5373\u4F7F\u76EE\u6807\u6587\u4EF6\u5DF2\u5B58\u5728\u4E5F\u8986\u76D6").action(
|
|
2726
3153
|
async (ids, opts) => {
|
|
@@ -2742,7 +3169,7 @@ var addCommand4 = new Command21("add").description(
|
|
|
2742
3169
|
overwrite: opts.overwrite
|
|
2743
3170
|
});
|
|
2744
3171
|
logger.success(
|
|
2745
|
-
`templates add complete: ${result.written} written, ${result.skipped} skipped
|
|
3172
|
+
`templates add complete: ${result.written} written, ${result.skipped} skipped.`
|
|
2746
3173
|
);
|
|
2747
3174
|
logger.info("");
|
|
2748
3175
|
logger.info(`Variant: ${result.variant}`);
|
|
@@ -2762,9 +3189,35 @@ var addCommand4 = new Command21("add").description(
|
|
|
2762
3189
|
}
|
|
2763
3190
|
);
|
|
2764
3191
|
|
|
3192
|
+
// src/commands/templates/list.ts
|
|
3193
|
+
import { Command as Command23 } from "commander";
|
|
3194
|
+
var listCommand5 = new Command23("list").description("\u5217\u51FA\u6307\u5B9A\u53D8\u4F53\u4E0B\u7684 templates entries").requiredOption("--variant <name>", "\u53D8\u4F53\u540D\uFF08\u5982 opentrek / uni-manager\uFF09").action(async (opts) => {
|
|
3195
|
+
try {
|
|
3196
|
+
const result = await listTemplatesEntries(opts.variant);
|
|
3197
|
+
logger.info(`${result.packageName}#${result.variant} entries:`);
|
|
3198
|
+
logger.info("");
|
|
3199
|
+
if (result.entries.length === 0) {
|
|
3200
|
+
logger.info(" (no entries \u2014 variant skeleton, awaiting templates)");
|
|
3201
|
+
return;
|
|
3202
|
+
}
|
|
3203
|
+
for (const e of result.entries) {
|
|
3204
|
+
const deps = e.registryDependencies.length ? ` [deps: ${e.registryDependencies.join(", ")}]` : "";
|
|
3205
|
+
logger.info(` ${e.id} (${e.type})${deps}`);
|
|
3206
|
+
if (e.description) logger.info(` ${e.description}`);
|
|
3207
|
+
logger.info("");
|
|
3208
|
+
}
|
|
3209
|
+
logger.info(
|
|
3210
|
+
`Install: teamix-evo templates add <id> --variant ${result.variant}`
|
|
3211
|
+
);
|
|
3212
|
+
} catch (err) {
|
|
3213
|
+
logger.error(`Failed: ${err.message}`);
|
|
3214
|
+
process.exitCode = 1;
|
|
3215
|
+
}
|
|
3216
|
+
});
|
|
3217
|
+
|
|
2765
3218
|
// src/commands/templates/list-variants.ts
|
|
2766
|
-
import { Command as
|
|
2767
|
-
var listVariantsCommand3 = new
|
|
3219
|
+
import { Command as Command24 } from "commander";
|
|
3220
|
+
var listVariantsCommand3 = new Command24("list-variants").description("\u5217\u51FA @teamix-evo/templates \u5305\u5185\u63D0\u4F9B\u7684\u6240\u6709\u9875\u9762\u6A21\u677F\u53D8\u4F53").action(async () => {
|
|
2768
3221
|
try {
|
|
2769
3222
|
const result = await listTemplatesVariants();
|
|
2770
3223
|
logger.info(`Available templates variants in ${result.packageName}:`);
|
|
@@ -2786,21 +3239,216 @@ var listVariantsCommand3 = new Command22("list-variants").description("\u5217\u5
|
|
|
2786
3239
|
});
|
|
2787
3240
|
|
|
2788
3241
|
// src/commands/templates/index.ts
|
|
2789
|
-
var templatesCommand = new
|
|
3242
|
+
var templatesCommand = new Command25("templates").description(
|
|
2790
3243
|
"\u7BA1\u7406\u9875\u9762\u6A21\u677F(\u53D8\u4F53\u611F\u77E5 \u2014 \u4E0E design / biz-ui \u540C\u53D8\u4F53\u540D\u7A7A\u95F4)"
|
|
2791
3244
|
);
|
|
2792
3245
|
templatesCommand.addCommand(addCommand4);
|
|
3246
|
+
templatesCommand.addCommand(listCommand5);
|
|
2793
3247
|
templatesCommand.addCommand(listVariantsCommand3);
|
|
2794
3248
|
|
|
3249
|
+
// src/commands/logs/index.ts
|
|
3250
|
+
import { Command as Command27 } from "commander";
|
|
3251
|
+
|
|
3252
|
+
// src/commands/logs/analyze.ts
|
|
3253
|
+
import { Command as Command26 } from "commander";
|
|
3254
|
+
import { readFileSync, readdirSync, existsSync as existsSync2, statSync } from "fs";
|
|
3255
|
+
import { resolve as resolve3, join as join17 } from "path";
|
|
3256
|
+
var DATE_DIR_RE = /^\d{4}-\d{2}-\d{2}$/;
|
|
3257
|
+
var logsAnalyzeCommand = new Command26("analyze").description(
|
|
3258
|
+
"\u6C47\u603B vibe-logger \u8F93\u51FA (.log/ai/**/*.jsonl) \u2014 \u5DE5\u5177 / \u5305\u6807\u7B7E / MCP \u8C03\u7528\u9891\u7387,\u8F85\u52A9\u751F\u6001\u4F18\u5316"
|
|
3259
|
+
).option("--dir <path>", "log \u76EE\u5F55 (\u9ED8\u8BA4 <project>/.log/ai)").option(
|
|
3260
|
+
"--days <n>",
|
|
3261
|
+
"\u53EA\u770B\u6700\u8FD1 N \u5929\u7684\u76EE\u5F55 (\u9ED8\u8BA4\u5168\u90E8;\u6309\u76EE\u5F55\u540D YYYY-MM-DD \u6BD4\u5BF9,\u4E0D\u89E3\u6790\u8BB0\u5F55 ts)"
|
|
3262
|
+
).option("--top <n>", "\u6BCF\u4E2A\u6392\u884C\u5C55\u793A\u524D N \u9879 (\u9ED8\u8BA4 10)", "10").option("--json", "\u4EE5 JSON \u8F93\u51FA (CI/\u5DE5\u5177\u53CB\u597D)").action((opts) => {
|
|
3263
|
+
const baseDir = resolve3(opts.dir ?? join17(process.cwd(), ".log", "ai"));
|
|
3264
|
+
if (!existsSync2(baseDir)) {
|
|
3265
|
+
logger.warn(`No log directory at ${baseDir}.`);
|
|
3266
|
+
logger.info(
|
|
3267
|
+
"\u8FD0\u884C vibe-logger hook \u89E6\u53D1\u540E\u4F1A\u5728\u6B64\u76EE\u5F55\u751F\u6210 JSONL \u2014 \u89C1 .claude/scripts/vibe-logger.mjs"
|
|
3268
|
+
);
|
|
3269
|
+
return;
|
|
3270
|
+
}
|
|
3271
|
+
const dayLimit = parseIntOrUndef(opts.days);
|
|
3272
|
+
const top = parseIntOrUndef(opts.top) ?? 10;
|
|
3273
|
+
const dayDirs = readdirSync(baseDir, { withFileTypes: true }).filter((e) => e.isDirectory() && DATE_DIR_RE.test(e.name)).map((e) => e.name).sort().reverse();
|
|
3274
|
+
const selected = dayLimit !== void 0 ? dayDirs.slice(0, dayLimit) : dayDirs;
|
|
3275
|
+
const records = [];
|
|
3276
|
+
for (const day of selected) {
|
|
3277
|
+
const dayPath = join17(baseDir, day);
|
|
3278
|
+
let entries;
|
|
3279
|
+
try {
|
|
3280
|
+
entries = readdirSync(dayPath);
|
|
3281
|
+
} catch {
|
|
3282
|
+
continue;
|
|
3283
|
+
}
|
|
3284
|
+
for (const entry of entries) {
|
|
3285
|
+
if (!entry.endsWith(".jsonl")) continue;
|
|
3286
|
+
const fp = join17(dayPath, entry);
|
|
3287
|
+
try {
|
|
3288
|
+
if (!statSync(fp).isFile()) continue;
|
|
3289
|
+
} catch {
|
|
3290
|
+
continue;
|
|
3291
|
+
}
|
|
3292
|
+
const text2 = readFileSync(fp, "utf8");
|
|
3293
|
+
for (const line of text2.split("\n")) {
|
|
3294
|
+
if (!line.trim()) continue;
|
|
3295
|
+
try {
|
|
3296
|
+
records.push(JSON.parse(line));
|
|
3297
|
+
} catch {
|
|
3298
|
+
}
|
|
3299
|
+
}
|
|
3300
|
+
}
|
|
3301
|
+
}
|
|
3302
|
+
const report = buildReport(records, top);
|
|
3303
|
+
if (opts.json) {
|
|
3304
|
+
process.stdout.write(JSON.stringify(report, null, 2) + "\n");
|
|
3305
|
+
return;
|
|
3306
|
+
}
|
|
3307
|
+
printReport(baseDir, selected.length, report);
|
|
3308
|
+
});
|
|
3309
|
+
function buildReport(records, top) {
|
|
3310
|
+
const byAgent = {};
|
|
3311
|
+
const byEvent = {};
|
|
3312
|
+
const tools = /* @__PURE__ */ new Map();
|
|
3313
|
+
const tags = /* @__PURE__ */ new Map();
|
|
3314
|
+
const mcp = /* @__PURE__ */ new Map();
|
|
3315
|
+
const sessions = /* @__PURE__ */ new Set();
|
|
3316
|
+
const filesTouched = /* @__PURE__ */ new Set();
|
|
3317
|
+
const errors = [];
|
|
3318
|
+
let from = null;
|
|
3319
|
+
let to = null;
|
|
3320
|
+
for (const r of records) {
|
|
3321
|
+
if (!from || r.ts < from) from = r.ts;
|
|
3322
|
+
if (!to || r.ts > to) to = r.ts;
|
|
3323
|
+
byAgent[r.agent] = (byAgent[r.agent] ?? 0) + 1;
|
|
3324
|
+
byEvent[r.event] = (byEvent[r.event] ?? 0) + 1;
|
|
3325
|
+
sessions.add(`${r.agent}::${r.session}`);
|
|
3326
|
+
if (r.file) filesTouched.add(r.file);
|
|
3327
|
+
if (r.tool) {
|
|
3328
|
+
tools.set(r.tool, (tools.get(r.tool) ?? 0) + 1);
|
|
3329
|
+
if (r.tool.startsWith("mcp__")) {
|
|
3330
|
+
const name = r.tool.replace(/^mcp__[^_]+__/, "");
|
|
3331
|
+
const slot = mcp.get(name) ?? { count: 0, keys: /* @__PURE__ */ new Set() };
|
|
3332
|
+
slot.count += 1;
|
|
3333
|
+
for (const k of r.mcpArgs ?? []) slot.keys.add(k);
|
|
3334
|
+
mcp.set(name, slot);
|
|
3335
|
+
}
|
|
3336
|
+
}
|
|
3337
|
+
for (const tag of r.tags ?? []) {
|
|
3338
|
+
tags.set(tag, (tags.get(tag) ?? 0) + 1);
|
|
3339
|
+
}
|
|
3340
|
+
if (r.error) {
|
|
3341
|
+
errors.push({
|
|
3342
|
+
ts: r.ts,
|
|
3343
|
+
tool: r.tool,
|
|
3344
|
+
file: r.file,
|
|
3345
|
+
session: r.session
|
|
3346
|
+
});
|
|
3347
|
+
}
|
|
3348
|
+
}
|
|
3349
|
+
const topTools = sortAndSlice(tools, top).map(([tool, count]) => ({
|
|
3350
|
+
tool,
|
|
3351
|
+
count
|
|
3352
|
+
}));
|
|
3353
|
+
const topTags = sortAndSlice(tags, top).map(([tag, count]) => ({
|
|
3354
|
+
tag,
|
|
3355
|
+
count
|
|
3356
|
+
}));
|
|
3357
|
+
const topMcp = [...mcp.entries()].sort((a, b) => b[1].count - a[1].count).slice(0, top).map(([name, v]) => ({
|
|
3358
|
+
name,
|
|
3359
|
+
count: v.count,
|
|
3360
|
+
argKeys: [...v.keys].sort()
|
|
3361
|
+
}));
|
|
3362
|
+
const recentErrors = errors.slice(-10);
|
|
3363
|
+
return {
|
|
3364
|
+
range: { from, to },
|
|
3365
|
+
totals: {
|
|
3366
|
+
records: records.length,
|
|
3367
|
+
sessions: sessions.size,
|
|
3368
|
+
errors: errors.length,
|
|
3369
|
+
files: filesTouched.size
|
|
3370
|
+
},
|
|
3371
|
+
byAgent,
|
|
3372
|
+
byEvent,
|
|
3373
|
+
topTools,
|
|
3374
|
+
topTags,
|
|
3375
|
+
topMcp,
|
|
3376
|
+
recentErrors
|
|
3377
|
+
};
|
|
3378
|
+
}
|
|
3379
|
+
function sortAndSlice(m, top) {
|
|
3380
|
+
return [...m.entries()].sort((a, b) => b[1] - a[1]).slice(0, top);
|
|
3381
|
+
}
|
|
3382
|
+
function printReport(baseDir, dayCount, r) {
|
|
3383
|
+
logger.info(`vibe-logger \u5206\u6790\u62A5\u544A`);
|
|
3384
|
+
logger.info(` \u76EE\u5F55: ${baseDir}`);
|
|
3385
|
+
logger.info(` \u5929\u6570: ${dayCount}`);
|
|
3386
|
+
logger.info(` \u65F6\u95F4: ${r.range.from ?? "-"} \u2192 ${r.range.to ?? "-"}`);
|
|
3387
|
+
logger.info("");
|
|
3388
|
+
logger.info(
|
|
3389
|
+
`Totals records=${r.totals.records} sessions=${r.totals.sessions} errors=${r.totals.errors} files=${r.totals.files}`
|
|
3390
|
+
);
|
|
3391
|
+
logger.info(`By agent ${formatKv(r.byAgent)}`);
|
|
3392
|
+
logger.info(`By event ${formatKv(r.byEvent)}`);
|
|
3393
|
+
logger.info("");
|
|
3394
|
+
logger.info("Top tools:");
|
|
3395
|
+
for (const { tool, count } of r.topTools) {
|
|
3396
|
+
logger.info(` ${pad(count, 5)} ${tool}`);
|
|
3397
|
+
}
|
|
3398
|
+
if (r.topTags.length) {
|
|
3399
|
+
logger.info("");
|
|
3400
|
+
logger.info("Top package tags (which package the AI touched):");
|
|
3401
|
+
for (const { tag, count } of r.topTags) {
|
|
3402
|
+
logger.info(` ${pad(count, 5)} ${tag}`);
|
|
3403
|
+
}
|
|
3404
|
+
}
|
|
3405
|
+
if (r.topMcp.length) {
|
|
3406
|
+
logger.info("");
|
|
3407
|
+
logger.info("Top MCP tools:");
|
|
3408
|
+
for (const { name, count, argKeys } of r.topMcp) {
|
|
3409
|
+
const keys = argKeys.length ? ` args: ${argKeys.join(", ")}` : "";
|
|
3410
|
+
logger.info(` ${pad(count, 5)} ${name}${keys}`);
|
|
3411
|
+
}
|
|
3412
|
+
}
|
|
3413
|
+
if (r.recentErrors.length) {
|
|
3414
|
+
logger.info("");
|
|
3415
|
+
logger.info(`Recent errors (last ${r.recentErrors.length}):`);
|
|
3416
|
+
for (const e of r.recentErrors) {
|
|
3417
|
+
logger.info(
|
|
3418
|
+
` ${e.ts} session=${e.session} tool=${e.tool ?? "-"} file=${e.file ?? "-"}`
|
|
3419
|
+
);
|
|
3420
|
+
}
|
|
3421
|
+
}
|
|
3422
|
+
}
|
|
3423
|
+
function formatKv(o) {
|
|
3424
|
+
return Object.entries(o).sort((a, b) => b[1] - a[1]).map(([k, v]) => `${k}=${v}`).join(" ");
|
|
3425
|
+
}
|
|
3426
|
+
function pad(n, width) {
|
|
3427
|
+
const s = String(n);
|
|
3428
|
+
return s.length >= width ? s : " ".repeat(width - s.length) + s;
|
|
3429
|
+
}
|
|
3430
|
+
function parseIntOrUndef(v) {
|
|
3431
|
+
if (v === void 0) return void 0;
|
|
3432
|
+
const n = Number.parseInt(v, 10);
|
|
3433
|
+
return Number.isFinite(n) && n > 0 ? n : void 0;
|
|
3434
|
+
}
|
|
3435
|
+
|
|
3436
|
+
// src/commands/logs/index.ts
|
|
3437
|
+
var logsCommand = new Command27("logs").description(
|
|
3438
|
+
"\u67E5\u8BE2 vibe-logger \u8F93\u51FA (.log/ai/**/*.jsonl) \u2014 AI \u8C03\u7528\u94FE\u5206\u6790"
|
|
3439
|
+
);
|
|
3440
|
+
logsCommand.addCommand(logsAnalyzeCommand);
|
|
3441
|
+
|
|
2795
3442
|
// src/index.ts
|
|
2796
|
-
var
|
|
2797
|
-
var { version } =
|
|
2798
|
-
var program = new
|
|
3443
|
+
var require9 = createRequire8(import.meta.url);
|
|
3444
|
+
var { version } = require9("../package.json");
|
|
3445
|
+
var program = new Command28();
|
|
2799
3446
|
program.name("teamix-evo").description("Where ideas evolve. \u2014 AI Coding \u5957\u4EF6").version(version);
|
|
2800
|
-
program.addCommand(
|
|
3447
|
+
program.addCommand(tokensCommand);
|
|
2801
3448
|
program.addCommand(skillsCommand);
|
|
2802
3449
|
program.addCommand(uiCommand);
|
|
2803
3450
|
program.addCommand(bizUiCommand);
|
|
2804
3451
|
program.addCommand(templatesCommand);
|
|
3452
|
+
program.addCommand(logsCommand);
|
|
2805
3453
|
program.parse();
|
|
2806
3454
|
//# sourceMappingURL=index.js.map
|