teamix-evo 0.3.1 → 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 +888 -366
- package/dist/index.js.map +1 -1
- package/package.json +5 -5
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
|
+
);
|
|
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
|
+
);
|
|
269
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,21 +1489,21 @@ 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
|
}
|
|
1324
1509
|
function resolveSkillsMaintenanceRoot(cwd) {
|
|
@@ -1483,11 +1668,17 @@ var listCommand2 = new Command8("list").alias("ls").description(
|
|
|
1483
1668
|
const pkg = installedManifest?.installed.find(
|
|
1484
1669
|
(p) => p.package === SKILLS_PACKAGE
|
|
1485
1670
|
);
|
|
1671
|
+
const skillsLock = await readSkillsLock(projectRoot);
|
|
1486
1672
|
const installedBySkill = /* @__PURE__ */ new Map();
|
|
1487
1673
|
for (const r of pkg?.resources ?? []) {
|
|
1488
1674
|
const skillId = r.id.split(":")[0];
|
|
1489
1675
|
installedBySkill.set(skillId, (installedBySkill.get(skillId) ?? 0) + 1);
|
|
1490
1676
|
}
|
|
1677
|
+
for (const skillId of Object.keys(skillsLock?.skills ?? {})) {
|
|
1678
|
+
if (!installedBySkill.has(skillId)) {
|
|
1679
|
+
installedBySkill.set(skillId, 1);
|
|
1680
|
+
}
|
|
1681
|
+
}
|
|
1491
1682
|
if (opts.installed) {
|
|
1492
1683
|
if (!config?.packages?.skills || !pkg) {
|
|
1493
1684
|
logger.info("No skills installed.");
|
|
@@ -1510,9 +1701,13 @@ var listCommand2 = new Command8("list").alias("ls").description(
|
|
|
1510
1701
|
const skills = [...manifest.skills].sort(
|
|
1511
1702
|
(a, b) => a.id.localeCompare(b.id)
|
|
1512
1703
|
);
|
|
1513
|
-
const isInstalled =
|
|
1514
|
-
if (isInstalled) {
|
|
1704
|
+
const isInstalled = installedBySkill.size > 0;
|
|
1705
|
+
if (isInstalled && config?.packages?.skills && pkg) {
|
|
1515
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
|
+
);
|
|
1516
1711
|
} else {
|
|
1517
1712
|
logger.info("Skills package not yet added.");
|
|
1518
1713
|
logger.info(
|
|
@@ -1649,7 +1844,7 @@ var updateCommand2 = new Command9("update").description("\u66F4\u65B0\u5DF2\u5B8
|
|
|
1649
1844
|
import { Command as Command10 } from "commander";
|
|
1650
1845
|
import * as prompts3 from "@clack/prompts";
|
|
1651
1846
|
import * as path12 from "path";
|
|
1652
|
-
import * as
|
|
1847
|
+
import * as fs10 from "fs/promises";
|
|
1653
1848
|
var SKILLS_PACKAGE3 = "@teamix-evo/skills";
|
|
1654
1849
|
var uninstallCommand2 = new Command10("uninstall").description(
|
|
1655
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"
|
|
@@ -1718,7 +1913,7 @@ async function runFullUninstall(args) {
|
|
|
1718
1913
|
logger.debug(`Removed ${removed.length} files`);
|
|
1719
1914
|
const skillsRoot = getSkillsSourceDir(projectRoot);
|
|
1720
1915
|
try {
|
|
1721
|
-
await
|
|
1916
|
+
await fs10.rm(skillsRoot, { recursive: true, force: true });
|
|
1722
1917
|
logger.debug(`Removed source dir ${skillsRoot}`);
|
|
1723
1918
|
} catch (err) {
|
|
1724
1919
|
logger.warn(
|
|
@@ -1771,7 +1966,7 @@ async function runPartialUninstall(args) {
|
|
|
1771
1966
|
for (const id of matched) {
|
|
1772
1967
|
const dir = getSkillsSourceDir(projectRoot, id);
|
|
1773
1968
|
try {
|
|
1774
|
-
await
|
|
1969
|
+
await fs10.rm(dir, { recursive: true, force: true });
|
|
1775
1970
|
logger.debug(`Removed source dir ${dir}`);
|
|
1776
1971
|
} catch (err) {
|
|
1777
1972
|
logger.warn(`Failed to remove ${dir}: ${err.message}`);
|
|
@@ -1815,7 +2010,26 @@ function dedupe(values) {
|
|
|
1815
2010
|
import { Command as Command11 } from "commander";
|
|
1816
2011
|
|
|
1817
2012
|
// src/core/skills-sync.ts
|
|
1818
|
-
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
|
+
}
|
|
1819
2033
|
var SKILLS_PACKAGE_DEFAULT = "@teamix-evo/skills";
|
|
1820
2034
|
async function runSkillsSync(options) {
|
|
1821
2035
|
const { projectRoot, names } = options;
|
|
@@ -1849,13 +2063,15 @@ async function runSkillsSync(options) {
|
|
|
1849
2063
|
logger.warn(`Skill "${skillId}" has no IDE mirror targets; skipped.`);
|
|
1850
2064
|
continue;
|
|
1851
2065
|
}
|
|
2066
|
+
const upstreamMeta = await readSkillMetaFromUpstream(skillId);
|
|
1852
2067
|
const result = await syncSkillsToIdes({
|
|
1853
2068
|
projectRoot,
|
|
1854
2069
|
skills: [
|
|
1855
2070
|
{
|
|
1856
2071
|
id: skillId,
|
|
1857
2072
|
name: skillId,
|
|
1858
|
-
updateStrategy: "regenerable"
|
|
2073
|
+
updateStrategy: upstreamMeta?.updateStrategy ?? "regenerable",
|
|
2074
|
+
managedRegions: upstreamMeta?.managedRegions
|
|
1859
2075
|
}
|
|
1860
2076
|
],
|
|
1861
2077
|
ides,
|
|
@@ -1882,7 +2098,7 @@ async function runSkillsSync(options) {
|
|
|
1882
2098
|
}
|
|
1883
2099
|
async function dirExists(p) {
|
|
1884
2100
|
try {
|
|
1885
|
-
const stat4 = await
|
|
2101
|
+
const stat4 = await fs11.stat(p);
|
|
1886
2102
|
return stat4.isDirectory();
|
|
1887
2103
|
} catch {
|
|
1888
2104
|
return false;
|
|
@@ -1976,8 +2192,8 @@ function parseScope2(input) {
|
|
|
1976
2192
|
import { Command as Command12 } from "commander";
|
|
1977
2193
|
|
|
1978
2194
|
// src/core/skills-doctor.ts
|
|
1979
|
-
import * as
|
|
1980
|
-
import * as
|
|
2195
|
+
import * as path14 from "path";
|
|
2196
|
+
import * as fs12 from "fs/promises";
|
|
1981
2197
|
async function runSkillsDoctor(options) {
|
|
1982
2198
|
const { projectRoot } = options;
|
|
1983
2199
|
const lock = await readSkillsLock(projectRoot);
|
|
@@ -1999,8 +2215,8 @@ async function runSkillsDoctor(options) {
|
|
|
1999
2215
|
const sourceFiles = await walkDir(sourceDir);
|
|
2000
2216
|
const sourceContents = /* @__PURE__ */ new Map();
|
|
2001
2217
|
for (const f of sourceFiles) {
|
|
2002
|
-
const rel2 =
|
|
2003
|
-
sourceContents.set(rel2, await
|
|
2218
|
+
const rel2 = path14.relative(sourceDir, f);
|
|
2219
|
+
sourceContents.set(rel2, await fs12.readFile(f, "utf-8"));
|
|
2004
2220
|
}
|
|
2005
2221
|
for (const ide of entry.mirroredTo) {
|
|
2006
2222
|
const adapter = getAdapter(ide);
|
|
@@ -2021,7 +2237,7 @@ async function runSkillsDoctor(options) {
|
|
|
2021
2237
|
continue;
|
|
2022
2238
|
}
|
|
2023
2239
|
for (const [rel2, sourceContent] of sourceContents.entries()) {
|
|
2024
|
-
const mirrorFile =
|
|
2240
|
+
const mirrorFile = path14.join(mirrorDir, rel2);
|
|
2025
2241
|
if (!await fileExists(mirrorFile)) {
|
|
2026
2242
|
findings.push({
|
|
2027
2243
|
kind: "missing-mirror",
|
|
@@ -2033,7 +2249,7 @@ async function runSkillsDoctor(options) {
|
|
|
2033
2249
|
});
|
|
2034
2250
|
continue;
|
|
2035
2251
|
}
|
|
2036
|
-
const mirrorContent = await
|
|
2252
|
+
const mirrorContent = await fs12.readFile(mirrorFile, "utf-8");
|
|
2037
2253
|
if (computeHash(mirrorContent) !== computeHash(sourceContent)) {
|
|
2038
2254
|
findings.push({
|
|
2039
2255
|
kind: "mirror-drift",
|
|
@@ -2054,7 +2270,7 @@ async function runSkillsDoctor(options) {
|
|
|
2054
2270
|
}
|
|
2055
2271
|
async function dirExists2(p) {
|
|
2056
2272
|
try {
|
|
2057
|
-
const stat4 = await
|
|
2273
|
+
const stat4 = await fs12.stat(p);
|
|
2058
2274
|
return stat4.isDirectory();
|
|
2059
2275
|
} catch {
|
|
2060
2276
|
return false;
|
|
@@ -2119,6 +2335,35 @@ import { Command as Command14 } from "commander";
|
|
|
2119
2335
|
import * as prompts4 from "@clack/prompts";
|
|
2120
2336
|
|
|
2121
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
|
+
}
|
|
2122
2367
|
var DEFAULT_UI_ALIASES = {
|
|
2123
2368
|
components: "src/components/ui",
|
|
2124
2369
|
hooks: "src/hooks",
|
|
@@ -2162,12 +2407,14 @@ async function runUiInit(options) {
|
|
|
2162
2407
|
rsc
|
|
2163
2408
|
};
|
|
2164
2409
|
await writeProjectConfig(projectRoot, config);
|
|
2410
|
+
const preferencesCss = await deployPreferencesCss(projectRoot);
|
|
2165
2411
|
return {
|
|
2166
2412
|
status: "installed",
|
|
2167
2413
|
aliases,
|
|
2168
2414
|
iconLibrary,
|
|
2169
2415
|
tsx,
|
|
2170
|
-
rsc
|
|
2416
|
+
rsc,
|
|
2417
|
+
preferencesCss
|
|
2171
2418
|
};
|
|
2172
2419
|
}
|
|
2173
2420
|
|
|
@@ -2204,6 +2451,14 @@ var initCommand2 = new Command14("init").description(
|
|
|
2204
2451
|
logger.info(` lib: ${result.aliases.lib}`);
|
|
2205
2452
|
logger.info(` iconLibrary: ${result.iconLibrary}`);
|
|
2206
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
|
+
}
|
|
2207
2462
|
logger.info("");
|
|
2208
2463
|
logger.info("Next: `npx teamix-evo ui add button`");
|
|
2209
2464
|
} catch (err) {
|
|
@@ -2282,23 +2537,23 @@ async function resolveConfig(opts) {
|
|
|
2282
2537
|
import { Command as Command15 } from "commander";
|
|
2283
2538
|
|
|
2284
2539
|
// src/core/ui-client.ts
|
|
2285
|
-
import * as
|
|
2286
|
-
import * as
|
|
2287
|
-
import { createRequire as
|
|
2540
|
+
import * as path16 from "path";
|
|
2541
|
+
import * as fs14 from "fs/promises";
|
|
2542
|
+
import { createRequire as createRequire6 } from "module";
|
|
2288
2543
|
import { loadUiPackageManifest } from "@teamix-evo/registry";
|
|
2289
|
-
var
|
|
2544
|
+
var require7 = createRequire6(import.meta.url);
|
|
2290
2545
|
function resolvePackageRoot2(packageName) {
|
|
2291
|
-
const pkgJsonPath =
|
|
2292
|
-
return
|
|
2546
|
+
const pkgJsonPath = require7.resolve(`${packageName}/package.json`);
|
|
2547
|
+
return path16.dirname(pkgJsonPath);
|
|
2293
2548
|
}
|
|
2294
2549
|
async function loadUiData(packageName) {
|
|
2295
2550
|
const packageRoot = resolvePackageRoot2(packageName);
|
|
2296
2551
|
logger.debug(`Resolved ui package root: ${packageRoot}`);
|
|
2297
2552
|
const manifest = await loadUiPackageManifest(packageRoot);
|
|
2298
2553
|
let data = {};
|
|
2299
|
-
const dataPath =
|
|
2554
|
+
const dataPath = path16.join(packageRoot, "_data.json");
|
|
2300
2555
|
try {
|
|
2301
|
-
const raw = await
|
|
2556
|
+
const raw = await fs14.readFile(dataPath, "utf-8");
|
|
2302
2557
|
data = JSON.parse(raw);
|
|
2303
2558
|
} catch (err) {
|
|
2304
2559
|
if (err.code !== "ENOENT") {
|
|
@@ -2310,8 +2565,8 @@ async function loadUiData(packageName) {
|
|
|
2310
2565
|
}
|
|
2311
2566
|
|
|
2312
2567
|
// src/core/ui-installer.ts
|
|
2313
|
-
import * as
|
|
2314
|
-
import * as
|
|
2568
|
+
import * as path17 from "path";
|
|
2569
|
+
import * as fs15 from "fs/promises";
|
|
2315
2570
|
import { resolveUiEntryOrder } from "@teamix-evo/registry";
|
|
2316
2571
|
|
|
2317
2572
|
// src/utils/transform-imports.ts
|
|
@@ -2351,12 +2606,12 @@ function aliasToImportPath(alias) {
|
|
|
2351
2606
|
}
|
|
2352
2607
|
|
|
2353
2608
|
// src/core/ui-installer.ts
|
|
2354
|
-
var DESIGN_COMPONENTS_DIR = ".teamix-evo/design/components";
|
|
2355
2609
|
async function installUiEntries(options) {
|
|
2356
2610
|
const {
|
|
2357
2611
|
projectRoot,
|
|
2358
2612
|
manifest,
|
|
2359
2613
|
packageRoot,
|
|
2614
|
+
entryPackageRoot,
|
|
2360
2615
|
aliases,
|
|
2361
2616
|
requested,
|
|
2362
2617
|
skipExisting = true
|
|
@@ -2365,7 +2620,6 @@ async function installUiEntries(options) {
|
|
|
2365
2620
|
const idToEntry = new Map(manifest.entries.map((e) => [e.id, e]));
|
|
2366
2621
|
const resources = [];
|
|
2367
2622
|
const npmDeps = {};
|
|
2368
|
-
const metaFiles = [];
|
|
2369
2623
|
let written = 0;
|
|
2370
2624
|
let skipped = 0;
|
|
2371
2625
|
for (const id of orderedIds) {
|
|
@@ -2384,8 +2638,9 @@ async function installUiEntries(options) {
|
|
|
2384
2638
|
skipped++;
|
|
2385
2639
|
continue;
|
|
2386
2640
|
}
|
|
2387
|
-
const
|
|
2388
|
-
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");
|
|
2389
2644
|
const transformed = rewriteImports(raw, aliases);
|
|
2390
2645
|
await writeFileSafe(targetAbs, transformed);
|
|
2391
2646
|
written++;
|
|
@@ -2397,32 +2652,13 @@ async function installUiEntries(options) {
|
|
|
2397
2652
|
strategy: entry.updateStrategy ?? "frozen"
|
|
2398
2653
|
});
|
|
2399
2654
|
}
|
|
2400
|
-
if (entry.meta) {
|
|
2401
|
-
const metaSourceAbs = path15.resolve(packageRoot, entry.meta);
|
|
2402
|
-
const metaContent = await fs13.readFile(metaSourceAbs, "utf-8");
|
|
2403
|
-
const metaTargetAbs = path15.join(
|
|
2404
|
-
projectRoot,
|
|
2405
|
-
DESIGN_COMPONENTS_DIR,
|
|
2406
|
-
`${entry.id}.meta.md`
|
|
2407
|
-
);
|
|
2408
|
-
await writeFileSafe(metaTargetAbs, metaContent);
|
|
2409
|
-
metaFiles.push(metaTargetAbs);
|
|
2410
|
-
resources.push({
|
|
2411
|
-
id: `${entry.id}:meta`,
|
|
2412
|
-
target: metaTargetAbs,
|
|
2413
|
-
hash: computeHash(metaContent),
|
|
2414
|
-
strategy: "regenerable"
|
|
2415
|
-
});
|
|
2416
|
-
logger.info(` meta: ${rel(projectRoot, metaTargetAbs)}`);
|
|
2417
|
-
}
|
|
2418
2655
|
}
|
|
2419
2656
|
return {
|
|
2420
2657
|
orderedIds,
|
|
2421
2658
|
resources,
|
|
2422
2659
|
npmDependencies: npmDeps,
|
|
2423
2660
|
written,
|
|
2424
|
-
skipped
|
|
2425
|
-
metaFiles
|
|
2661
|
+
skipped
|
|
2426
2662
|
};
|
|
2427
2663
|
}
|
|
2428
2664
|
function resolveTargetPath(projectRoot, aliases, entry, file) {
|
|
@@ -2432,10 +2668,10 @@ function resolveTargetPath(projectRoot, aliases, entry, file) {
|
|
|
2432
2668
|
`Entry "${entry.id}" requires alias "${file.targetAlias}" but it is not configured.`
|
|
2433
2669
|
);
|
|
2434
2670
|
}
|
|
2435
|
-
return
|
|
2671
|
+
return path17.join(projectRoot, aliasDir, file.targetName);
|
|
2436
2672
|
}
|
|
2437
2673
|
function rel(projectRoot, abs) {
|
|
2438
|
-
return
|
|
2674
|
+
return path17.relative(projectRoot, abs);
|
|
2439
2675
|
}
|
|
2440
2676
|
|
|
2441
2677
|
// src/core/ui-add.ts
|
|
@@ -2497,7 +2733,6 @@ async function runUiAdd(options) {
|
|
|
2497
2733
|
orderedIds: result.orderedIds,
|
|
2498
2734
|
written: result.written,
|
|
2499
2735
|
skipped: result.skipped,
|
|
2500
|
-
metaFiles: result.metaFiles,
|
|
2501
2736
|
npmDependencies: result.npmDependencies,
|
|
2502
2737
|
resources: result.resources
|
|
2503
2738
|
};
|
|
@@ -2523,7 +2758,7 @@ var addCommand2 = new Command15("add").description(
|
|
|
2523
2758
|
overwrite: opts.overwrite
|
|
2524
2759
|
});
|
|
2525
2760
|
logger.success(
|
|
2526
|
-
`UI add complete: ${result.written} written, ${result.skipped} skipped
|
|
2761
|
+
`UI add complete: ${result.written} written, ${result.skipped} skipped.`
|
|
2527
2762
|
);
|
|
2528
2763
|
logger.info("");
|
|
2529
2764
|
logger.info(`Resolved order: ${result.orderedIds.join(" \u2192 ")}`);
|
|
@@ -2535,12 +2770,6 @@ var addCommand2 = new Command15("add").description(
|
|
|
2535
2770
|
logger.info(` pnpm add ${installCmd}`);
|
|
2536
2771
|
logger.info(` # or: npm install ${installCmd}`);
|
|
2537
2772
|
}
|
|
2538
|
-
if (result.metaFiles.length > 0) {
|
|
2539
|
-
logger.info("");
|
|
2540
|
-
logger.info(
|
|
2541
|
-
"Component meta dropped under .teamix-evo/design/components/ (AI-readable)."
|
|
2542
|
-
);
|
|
2543
|
-
}
|
|
2544
2773
|
} catch (err) {
|
|
2545
2774
|
const message = err.message;
|
|
2546
2775
|
if (message.startsWith("UI not initialized")) {
|
|
@@ -2640,22 +2869,23 @@ uiCommand.addCommand(addCommand2);
|
|
|
2640
2869
|
uiCommand.addCommand(listCommand3);
|
|
2641
2870
|
|
|
2642
2871
|
// src/commands/biz-ui/index.ts
|
|
2643
|
-
import { Command as
|
|
2872
|
+
import { Command as Command21 } from "commander";
|
|
2644
2873
|
|
|
2645
2874
|
// src/commands/biz-ui/add.ts
|
|
2646
2875
|
import { Command as Command18 } from "commander";
|
|
2647
2876
|
|
|
2648
2877
|
// src/core/variant-ui-add.ts
|
|
2649
|
-
import * as
|
|
2650
|
-
import { createRequire as
|
|
2878
|
+
import * as path18 from "path";
|
|
2879
|
+
import { createRequire as createRequire7 } from "module";
|
|
2651
2880
|
import {
|
|
2881
|
+
loadUiPackageManifest as loadUiPackageManifest2,
|
|
2652
2882
|
loadVariantUiPackageCatalog,
|
|
2653
2883
|
loadVariantUiPackageManifest
|
|
2654
2884
|
} from "@teamix-evo/registry";
|
|
2655
|
-
var
|
|
2885
|
+
var require8 = createRequire7(import.meta.url);
|
|
2656
2886
|
function resolvePackageRoot3(packageName) {
|
|
2657
|
-
const pkgJsonPath =
|
|
2658
|
-
return
|
|
2887
|
+
const pkgJsonPath = require8.resolve(`${packageName}/package.json`);
|
|
2888
|
+
return path18.dirname(pkgJsonPath);
|
|
2659
2889
|
}
|
|
2660
2890
|
async function runVariantUiAdd(packageName, options) {
|
|
2661
2891
|
const { projectRoot, variant, ids, overwrite } = options;
|
|
@@ -2678,27 +2908,42 @@ async function runVariantUiAdd(packageName, options) {
|
|
|
2678
2908
|
`Variant "${variant}" not found in ${fullPackageName}. Known variants: ${known}. Hint: \`teamix-evo ${packageName} list-variants\` shows all.`
|
|
2679
2909
|
);
|
|
2680
2910
|
}
|
|
2681
|
-
const variantDir =
|
|
2911
|
+
const variantDir = path18.join(packageRoot, "variants", variant);
|
|
2682
2912
|
const variantManifest = await loadVariantUiPackageManifest(variantDir);
|
|
2683
2913
|
const knownIds = new Set(variantManifest.entries.map((e) => e.id));
|
|
2684
2914
|
const unknown = ids.filter((id) => !knownIds.has(id));
|
|
2685
2915
|
if (unknown.length > 0) {
|
|
2686
2916
|
throw new Error(
|
|
2687
|
-
`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.`
|
|
2688
2918
|
);
|
|
2689
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
|
+
}
|
|
2690
2933
|
const adaptedManifest = {
|
|
2691
2934
|
schemaVersion: 1,
|
|
2692
2935
|
package: "ui",
|
|
2693
2936
|
version: variantManifest.version,
|
|
2694
2937
|
engines: variantManifest.engines,
|
|
2695
|
-
entries:
|
|
2938
|
+
entries: mergedEntries
|
|
2696
2939
|
};
|
|
2697
2940
|
const result = await installUiEntries({
|
|
2698
2941
|
projectRoot,
|
|
2699
2942
|
manifest: adaptedManifest,
|
|
2700
2943
|
packageRoot: variantDir,
|
|
2701
|
-
//
|
|
2944
|
+
// default for variant entries
|
|
2945
|
+
entryPackageRoot,
|
|
2946
|
+
// ui entries resolve from uiPackageRoot
|
|
2702
2947
|
aliases: uiCfg.aliases,
|
|
2703
2948
|
requested: ids,
|
|
2704
2949
|
skipExisting: !overwrite
|
|
@@ -2730,7 +2975,6 @@ async function runVariantUiAdd(packageName, options) {
|
|
|
2730
2975
|
orderedIds: result.orderedIds,
|
|
2731
2976
|
written: result.written,
|
|
2732
2977
|
skipped: result.skipped,
|
|
2733
|
-
metaFiles: result.metaFiles,
|
|
2734
2978
|
npmDependencies: result.npmDependencies,
|
|
2735
2979
|
resources: result.resources
|
|
2736
2980
|
};
|
|
@@ -2767,6 +3011,36 @@ async function listBizUiVariants(packageRoot) {
|
|
|
2767
3011
|
async function listTemplatesVariants(packageRoot) {
|
|
2768
3012
|
return listVariantUi("templates", packageRoot);
|
|
2769
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
|
+
}
|
|
2770
3044
|
|
|
2771
3045
|
// src/commands/biz-ui/add.ts
|
|
2772
3046
|
var addCommand3 = new Command18("add").description(
|
|
@@ -2791,7 +3065,7 @@ var addCommand3 = new Command18("add").description(
|
|
|
2791
3065
|
overwrite: opts.overwrite
|
|
2792
3066
|
});
|
|
2793
3067
|
logger.success(
|
|
2794
|
-
`biz-ui add complete: ${result.written} written, ${result.skipped} skipped
|
|
3068
|
+
`biz-ui add complete: ${result.written} written, ${result.skipped} skipped.`
|
|
2795
3069
|
);
|
|
2796
3070
|
logger.info("");
|
|
2797
3071
|
logger.info(`Variant: ${result.variant}`);
|
|
@@ -2811,9 +3085,35 @@ var addCommand3 = new Command18("add").description(
|
|
|
2811
3085
|
}
|
|
2812
3086
|
);
|
|
2813
3087
|
|
|
2814
|
-
// src/commands/biz-ui/list
|
|
3088
|
+
// src/commands/biz-ui/list.ts
|
|
2815
3089
|
import { Command as Command19 } from "commander";
|
|
2816
|
-
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 () => {
|
|
2817
3117
|
try {
|
|
2818
3118
|
const result = await listBizUiVariants();
|
|
2819
3119
|
logger.info(`Available biz-ui variants in ${result.packageName}:`);
|
|
@@ -2835,18 +3135,19 @@ var listVariantsCommand2 = new Command19("list-variants").description("\u5217\u5
|
|
|
2835
3135
|
});
|
|
2836
3136
|
|
|
2837
3137
|
// src/commands/biz-ui/index.ts
|
|
2838
|
-
var bizUiCommand = new
|
|
3138
|
+
var bizUiCommand = new Command21("biz-ui").description(
|
|
2839
3139
|
"\u7BA1\u7406\u4E1A\u52A1 UI \u7EC4\u4EF6(\u53D8\u4F53\u611F\u77E5 \u2014 \u4E0E design / templates \u540C\u53D8\u4F53\u540D\u7A7A\u95F4)"
|
|
2840
3140
|
);
|
|
2841
3141
|
bizUiCommand.addCommand(addCommand3);
|
|
3142
|
+
bizUiCommand.addCommand(listCommand4);
|
|
2842
3143
|
bizUiCommand.addCommand(listVariantsCommand2);
|
|
2843
3144
|
|
|
2844
3145
|
// src/commands/templates/index.ts
|
|
2845
|
-
import { Command as
|
|
3146
|
+
import { Command as Command25 } from "commander";
|
|
2846
3147
|
|
|
2847
3148
|
// src/commands/templates/add.ts
|
|
2848
|
-
import { Command as
|
|
2849
|
-
var addCommand4 = new
|
|
3149
|
+
import { Command as Command22 } from "commander";
|
|
3150
|
+
var addCommand4 = new Command22("add").description(
|
|
2850
3151
|
"\u5B89\u88C5\u4E00\u4E2A\u6216\u591A\u4E2A\u9875\u9762\u6A21\u677F(\u6309 id,\u81EA\u52A8\u5C55\u5F00 ui \u5305\u7684 registryDependencies)"
|
|
2851
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(
|
|
2852
3153
|
async (ids, opts) => {
|
|
@@ -2868,7 +3169,7 @@ var addCommand4 = new Command21("add").description(
|
|
|
2868
3169
|
overwrite: opts.overwrite
|
|
2869
3170
|
});
|
|
2870
3171
|
logger.success(
|
|
2871
|
-
`templates add complete: ${result.written} written, ${result.skipped} skipped
|
|
3172
|
+
`templates add complete: ${result.written} written, ${result.skipped} skipped.`
|
|
2872
3173
|
);
|
|
2873
3174
|
logger.info("");
|
|
2874
3175
|
logger.info(`Variant: ${result.variant}`);
|
|
@@ -2888,9 +3189,35 @@ var addCommand4 = new Command21("add").description(
|
|
|
2888
3189
|
}
|
|
2889
3190
|
);
|
|
2890
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
|
+
|
|
2891
3218
|
// src/commands/templates/list-variants.ts
|
|
2892
|
-
import { Command as
|
|
2893
|
-
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 () => {
|
|
2894
3221
|
try {
|
|
2895
3222
|
const result = await listTemplatesVariants();
|
|
2896
3223
|
logger.info(`Available templates variants in ${result.packageName}:`);
|
|
@@ -2912,21 +3239,216 @@ var listVariantsCommand3 = new Command22("list-variants").description("\u5217\u5
|
|
|
2912
3239
|
});
|
|
2913
3240
|
|
|
2914
3241
|
// src/commands/templates/index.ts
|
|
2915
|
-
var templatesCommand = new
|
|
3242
|
+
var templatesCommand = new Command25("templates").description(
|
|
2916
3243
|
"\u7BA1\u7406\u9875\u9762\u6A21\u677F(\u53D8\u4F53\u611F\u77E5 \u2014 \u4E0E design / biz-ui \u540C\u53D8\u4F53\u540D\u7A7A\u95F4)"
|
|
2917
3244
|
);
|
|
2918
3245
|
templatesCommand.addCommand(addCommand4);
|
|
3246
|
+
templatesCommand.addCommand(listCommand5);
|
|
2919
3247
|
templatesCommand.addCommand(listVariantsCommand3);
|
|
2920
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
|
+
|
|
2921
3442
|
// src/index.ts
|
|
2922
|
-
var
|
|
2923
|
-
var { version } =
|
|
2924
|
-
var program = new
|
|
3443
|
+
var require9 = createRequire8(import.meta.url);
|
|
3444
|
+
var { version } = require9("../package.json");
|
|
3445
|
+
var program = new Command28();
|
|
2925
3446
|
program.name("teamix-evo").description("Where ideas evolve. \u2014 AI Coding \u5957\u4EF6").version(version);
|
|
2926
|
-
program.addCommand(
|
|
3447
|
+
program.addCommand(tokensCommand);
|
|
2927
3448
|
program.addCommand(skillsCommand);
|
|
2928
3449
|
program.addCommand(uiCommand);
|
|
2929
3450
|
program.addCommand(bizUiCommand);
|
|
2930
3451
|
program.addCommand(templatesCommand);
|
|
3452
|
+
program.addCommand(logsCommand);
|
|
2931
3453
|
program.parse();
|
|
2932
3454
|
//# sourceMappingURL=index.js.map
|