teamix-evo 0.3.1 → 0.4.1
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 +32 -31
- package/dist/core/index.d.ts +71 -29
- package/dist/core/index.js +357 -255
- package/dist/core/index.js.map +1 -1
- package/dist/index.js +1394 -480
- package/dist/index.js.map +1 -1
- package/package.json +6 -6
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 Command29 } from "commander";
|
|
5
|
+
import { createRequire as createRequire7 } 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/
|
|
69
|
+
// src/core/tokens-init.ts
|
|
70
70
|
import * as path9 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,9 +319,12 @@ 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
|
-
import {
|
|
324
|
+
import {
|
|
325
|
+
replaceManagedRegion,
|
|
326
|
+
hasManagedRegion
|
|
327
|
+
} from "@teamix-evo/registry";
|
|
374
328
|
|
|
375
329
|
// src/utils/template.ts
|
|
376
330
|
import Handlebars from "handlebars";
|
|
@@ -401,13 +355,13 @@ async function loadTemplateFile(filePath) {
|
|
|
401
355
|
}
|
|
402
356
|
|
|
403
357
|
// src/utils/path.ts
|
|
404
|
-
import * as
|
|
358
|
+
import * as path6 from "path";
|
|
405
359
|
import * as fs4 from "fs/promises";
|
|
406
360
|
async function walkDir(dir) {
|
|
407
361
|
const files = [];
|
|
408
362
|
const entries = await fs4.readdir(dir, { withFileTypes: true });
|
|
409
363
|
for (const entry of entries) {
|
|
410
|
-
const fullPath =
|
|
364
|
+
const fullPath = path6.join(dir, entry.name);
|
|
411
365
|
if (entry.isDirectory()) {
|
|
412
366
|
files.push(...await walkDir(fullPath));
|
|
413
367
|
} else if (entry.isFile()) {
|
|
@@ -450,12 +404,12 @@ async function installSkills(options) {
|
|
|
450
404
|
}
|
|
451
405
|
async function writeSkillSource(skill, options) {
|
|
452
406
|
const { data, packageRoot, projectRoot } = options;
|
|
453
|
-
const sourceAbs =
|
|
407
|
+
const sourceAbs = path7.resolve(packageRoot, skill.source);
|
|
454
408
|
const targetDir = getSkillsSourceDir(projectRoot, skill.name);
|
|
455
409
|
const stat4 = await fs5.stat(sourceAbs);
|
|
456
410
|
const records = [];
|
|
457
411
|
if (stat4.isFile()) {
|
|
458
|
-
const targetFile =
|
|
412
|
+
const targetFile = path7.join(targetDir, "SKILL.md");
|
|
459
413
|
const content = await renderSkillContent(sourceAbs, skill, data);
|
|
460
414
|
await writeFileSafe(targetFile, content);
|
|
461
415
|
records.push(makeSourceRecord(skill, targetFile, content));
|
|
@@ -465,14 +419,14 @@ async function writeSkillSource(skill, options) {
|
|
|
465
419
|
await ensureDir(targetDir);
|
|
466
420
|
const entries = await walkDir(sourceAbs);
|
|
467
421
|
for (const entry of entries) {
|
|
468
|
-
const rel2 =
|
|
469
|
-
let targetFile =
|
|
422
|
+
const rel2 = path7.relative(sourceAbs, entry);
|
|
423
|
+
let targetFile = path7.join(targetDir, rel2);
|
|
470
424
|
if (skill.template && targetFile.endsWith(".hbs")) {
|
|
471
425
|
targetFile = targetFile.slice(0, -4);
|
|
472
426
|
}
|
|
473
427
|
const content = skill.template && entry.endsWith(".hbs") ? renderTemplate(await loadTemplateFile(entry), { ...data, skill }) : await fs5.readFile(entry, "utf-8");
|
|
474
428
|
await writeFileSafe(targetFile, content);
|
|
475
|
-
const relWritten =
|
|
429
|
+
const relWritten = path7.relative(targetDir, targetFile);
|
|
476
430
|
records.push(makeSourceRecord(skill, targetFile, content, relWritten));
|
|
477
431
|
logger.debug(` Wrote source: ${targetFile}`);
|
|
478
432
|
}
|
|
@@ -486,15 +440,66 @@ async function mirrorSkillToIde(skill, ide, scope, projectRoot) {
|
|
|
486
440
|
const sourceFiles = await walkDir(sourceDir);
|
|
487
441
|
await ensureDir(targetDir);
|
|
488
442
|
for (const src of sourceFiles) {
|
|
489
|
-
const rel2 =
|
|
490
|
-
const targetFile =
|
|
491
|
-
const
|
|
492
|
-
await
|
|
493
|
-
|
|
443
|
+
const rel2 = path7.relative(sourceDir, src);
|
|
444
|
+
const targetFile = path7.join(targetDir, rel2);
|
|
445
|
+
const sourceContent = await fs5.readFile(src, "utf-8");
|
|
446
|
+
const writtenContent = await writeMirrorContent(
|
|
447
|
+
targetFile,
|
|
448
|
+
sourceContent,
|
|
449
|
+
skill.managedRegions,
|
|
450
|
+
src
|
|
451
|
+
);
|
|
452
|
+
records.push(
|
|
453
|
+
makeMirrorRecord(skill, targetFile, writtenContent, ide, scope, rel2)
|
|
454
|
+
);
|
|
494
455
|
logger.debug(` Mirrored ${ide}:${scope}: ${targetFile}`);
|
|
495
456
|
}
|
|
496
457
|
return records;
|
|
497
458
|
}
|
|
459
|
+
async function writeMirrorContent(targetFile, sourceContent, managedRegions, sourceFile) {
|
|
460
|
+
const existing = await readFileOrNull(targetFile);
|
|
461
|
+
if (existing === null) {
|
|
462
|
+
await writeFileSafe(targetFile, sourceContent);
|
|
463
|
+
return sourceContent;
|
|
464
|
+
}
|
|
465
|
+
const regions = managedRegions ?? [];
|
|
466
|
+
const matchedRegions = regions.filter((id) => hasManagedRegion(existing, id));
|
|
467
|
+
if (matchedRegions.length === 0) {
|
|
468
|
+
if (existing !== sourceContent) {
|
|
469
|
+
logger.warn(
|
|
470
|
+
`Mirror drift detected at ${targetFile} \u2014 overwriting from source. Edit ${sourceFile} (not the mirror) and re-run \`teamix-evo skills sync\`.`
|
|
471
|
+
);
|
|
472
|
+
await writeFileSafe(targetFile, sourceContent);
|
|
473
|
+
return sourceContent;
|
|
474
|
+
}
|
|
475
|
+
return existing;
|
|
476
|
+
}
|
|
477
|
+
let merged = existing;
|
|
478
|
+
for (const id of matchedRegions) {
|
|
479
|
+
const newRegion = extractRegionBody(sourceContent, id);
|
|
480
|
+
if (newRegion === null) continue;
|
|
481
|
+
try {
|
|
482
|
+
merged = replaceManagedRegion(merged, id, newRegion);
|
|
483
|
+
} catch {
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
if (merged !== existing) {
|
|
487
|
+
await writeFileSafe(targetFile, merged);
|
|
488
|
+
}
|
|
489
|
+
return merged;
|
|
490
|
+
}
|
|
491
|
+
function extractRegionBody(content, id) {
|
|
492
|
+
const re = new RegExp(
|
|
493
|
+
`<!-- teamix-evo:managed:start id="${escapeRegExp(
|
|
494
|
+
id
|
|
495
|
+
)}" -->([\\s\\S]*?)<!-- teamix-evo:managed:end id="${escapeRegExp(
|
|
496
|
+
id
|
|
497
|
+
)}" -->`
|
|
498
|
+
);
|
|
499
|
+
const m = content.match(re);
|
|
500
|
+
if (!m) return null;
|
|
501
|
+
return m[1].replace(/^\n/, "").replace(/\n$/, "");
|
|
502
|
+
}
|
|
498
503
|
async function renderSkillContent(sourceAbs, skill, data) {
|
|
499
504
|
if (skill.template ?? sourceAbs.endsWith(".hbs")) {
|
|
500
505
|
const tpl = await loadTemplateFile(sourceAbs);
|
|
@@ -549,7 +554,7 @@ async function updateSkills(options) {
|
|
|
549
554
|
}
|
|
550
555
|
async function rewriteSkillSource(skill, options, summary) {
|
|
551
556
|
const { data, packageRoot, projectRoot } = options;
|
|
552
|
-
const sourceAbs =
|
|
557
|
+
const sourceAbs = path7.resolve(packageRoot, skill.source);
|
|
553
558
|
const targetDir = getSkillsSourceDir(projectRoot, skill.name);
|
|
554
559
|
const stat4 = await fs5.stat(sourceAbs);
|
|
555
560
|
if (!stat4.isFile()) {
|
|
@@ -557,8 +562,8 @@ async function rewriteSkillSource(skill, options, summary) {
|
|
|
557
562
|
const entries = await walkDir(sourceAbs);
|
|
558
563
|
const records = [];
|
|
559
564
|
for (const entry of entries) {
|
|
560
|
-
const rel2 =
|
|
561
|
-
let targetFile2 =
|
|
565
|
+
const rel2 = path7.relative(sourceAbs, entry);
|
|
566
|
+
let targetFile2 = path7.join(targetDir, rel2);
|
|
562
567
|
if (skill.template && targetFile2.endsWith(".hbs")) {
|
|
563
568
|
targetFile2 = targetFile2.slice(0, -4);
|
|
564
569
|
}
|
|
@@ -571,12 +576,12 @@ async function rewriteSkillSource(skill, options, summary) {
|
|
|
571
576
|
summary.created++;
|
|
572
577
|
}
|
|
573
578
|
await writeFileSafe(targetFile2, content);
|
|
574
|
-
const relWritten =
|
|
579
|
+
const relWritten = path7.relative(targetDir, targetFile2);
|
|
575
580
|
records.push(makeSourceRecord(skill, targetFile2, content, relWritten));
|
|
576
581
|
}
|
|
577
582
|
return records;
|
|
578
583
|
}
|
|
579
|
-
const targetFile =
|
|
584
|
+
const targetFile = path7.join(targetDir, "SKILL.md");
|
|
580
585
|
const newContent = await renderSkillContent(sourceAbs, skill, data);
|
|
581
586
|
const exists = await fileExists(targetFile);
|
|
582
587
|
if (skill.updateStrategy === "frozen") {
|
|
@@ -651,14 +656,19 @@ async function syncSkillsToIdes(options) {
|
|
|
651
656
|
await ensureDir(targetDir);
|
|
652
657
|
const sourceFiles = await walkDir(sourceDir);
|
|
653
658
|
for (const src of sourceFiles) {
|
|
654
|
-
const rel2 =
|
|
655
|
-
const targetFile =
|
|
656
|
-
const
|
|
657
|
-
await
|
|
659
|
+
const rel2 = path7.relative(sourceDir, src);
|
|
660
|
+
const targetFile = path7.join(targetDir, rel2);
|
|
661
|
+
const sourceContent = await fs5.readFile(src, "utf-8");
|
|
662
|
+
const writtenContent = await writeMirrorContent(
|
|
663
|
+
targetFile,
|
|
664
|
+
sourceContent,
|
|
665
|
+
skill.managedRegions,
|
|
666
|
+
src
|
|
667
|
+
);
|
|
658
668
|
out.push({
|
|
659
669
|
id: rel2 === "SKILL.md" ? skill.id : `${skill.id}:${rel2}`,
|
|
660
670
|
target: targetFile,
|
|
661
|
-
hash: computeHash(
|
|
671
|
+
hash: computeHash(writtenContent),
|
|
662
672
|
strategy: skill.updateStrategy,
|
|
663
673
|
ide,
|
|
664
674
|
scope
|
|
@@ -680,17 +690,46 @@ async function removeSkillFiles(records) {
|
|
|
680
690
|
}
|
|
681
691
|
}
|
|
682
692
|
}
|
|
683
|
-
const
|
|
684
|
-
for (const
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
693
|
+
const startDirs = new Set(records.map((r) => path7.dirname(r.target)));
|
|
694
|
+
for (const startDir of startDirs) {
|
|
695
|
+
let dir = startDir;
|
|
696
|
+
for (let depth = 0; depth < 8; depth++) {
|
|
697
|
+
try {
|
|
698
|
+
const entries = await fs5.readdir(dir);
|
|
699
|
+
if (entries.length !== 0) break;
|
|
700
|
+
await fs5.rmdir(dir);
|
|
701
|
+
} catch {
|
|
702
|
+
break;
|
|
703
|
+
}
|
|
704
|
+
dir = path7.dirname(dir);
|
|
689
705
|
}
|
|
690
706
|
}
|
|
691
707
|
return removed;
|
|
692
708
|
}
|
|
693
709
|
|
|
710
|
+
// src/utils/mcp.ts
|
|
711
|
+
import * as path8 from "path";
|
|
712
|
+
var MCP_JSON_CONTENT = {
|
|
713
|
+
mcpServers: {
|
|
714
|
+
"teamix-evo": {
|
|
715
|
+
command: "npx",
|
|
716
|
+
args: ["-y", "@teamix-evo/mcp"]
|
|
717
|
+
}
|
|
718
|
+
}
|
|
719
|
+
};
|
|
720
|
+
async function ensureMcpJson(projectRoot) {
|
|
721
|
+
const mcpPath = path8.join(projectRoot, ".mcp.json");
|
|
722
|
+
if (await fileExists(mcpPath)) return "exists";
|
|
723
|
+
try {
|
|
724
|
+
await writeFileSafe(mcpPath, JSON.stringify(MCP_JSON_CONTENT, null, 2) + "\n");
|
|
725
|
+
logger.debug(`Wrote .mcp.json \u2192 ${mcpPath}`);
|
|
726
|
+
return "created";
|
|
727
|
+
} catch (err) {
|
|
728
|
+
logger.warn(`Failed to write .mcp.json: ${err.message}`);
|
|
729
|
+
return "failed";
|
|
730
|
+
}
|
|
731
|
+
}
|
|
732
|
+
|
|
694
733
|
// src/core/skills-add.ts
|
|
695
734
|
var DEFAULT_SKILLS_PACKAGE = "@teamix-evo/skills";
|
|
696
735
|
var FLAT_VARIANT = "_flat";
|
|
@@ -702,9 +741,6 @@ async function runSkillsAdd(options) {
|
|
|
702
741
|
await ensureTeamixDir(projectRoot);
|
|
703
742
|
const existingConfig = await readProjectConfig(projectRoot);
|
|
704
743
|
const existingSkillsCfg = existingConfig?.packages?.skills;
|
|
705
|
-
if (!isIncremental && existingSkillsCfg) {
|
|
706
|
-
return { status: "already-added" };
|
|
707
|
-
}
|
|
708
744
|
const ides = options.ides && options.ides.length > 0 ? [...options.ides] : existingSkillsCfg?.ides ? [...existingSkillsCfg.ides] : [];
|
|
709
745
|
const scope = options.scope ?? existingSkillsCfg?.scope;
|
|
710
746
|
if (ides.length === 0) {
|
|
@@ -714,7 +750,7 @@ async function runSkillsAdd(options) {
|
|
|
714
750
|
throw new Error("Scope must be specified (project | global).");
|
|
715
751
|
}
|
|
716
752
|
const { manifest, data, packageRoot } = await loadSkillsData(packageName);
|
|
717
|
-
const
|
|
753
|
+
const currentTokensVariant = await readTokensVariant(projectRoot);
|
|
718
754
|
if (isIncremental) {
|
|
719
755
|
const known = new Set(manifest.skills.map((s) => s.id));
|
|
720
756
|
const unknown = requestedNames.filter((n) => !known.has(n));
|
|
@@ -742,23 +778,27 @@ async function runSkillsAdd(options) {
|
|
|
742
778
|
skippedSkillIds = requestedNames.filter((n) => existingSkillIds.has(n));
|
|
743
779
|
onlyIds = requestedNames.filter((n) => !existingSkillIds.has(n));
|
|
744
780
|
} else {
|
|
745
|
-
|
|
746
|
-
onlyIds = manifest.skills.filter((s) => {
|
|
781
|
+
const candidateIds = manifest.skills.filter((s) => {
|
|
747
782
|
if (!s.variant) return true;
|
|
748
|
-
if (!
|
|
783
|
+
if (!currentTokensVariant) {
|
|
749
784
|
logger.debug(
|
|
750
|
-
`Skipping variant-bound skill "${s.id}" (variant=${s.variant}): no
|
|
785
|
+
`Skipping variant-bound skill "${s.id}" (variant=${s.variant}): no tokens variant installed; will be picked up when "tokens init" runs.`
|
|
751
786
|
);
|
|
752
787
|
return false;
|
|
753
788
|
}
|
|
754
|
-
if (s.variant !==
|
|
789
|
+
if (s.variant !== currentTokensVariant) {
|
|
755
790
|
logger.debug(
|
|
756
|
-
`Skipping variant-bound skill "${s.id}" (variant=${s.variant}): current
|
|
791
|
+
`Skipping variant-bound skill "${s.id}" (variant=${s.variant}): current tokens variant is "${currentTokensVariant}".`
|
|
757
792
|
);
|
|
758
793
|
return false;
|
|
759
794
|
}
|
|
760
795
|
return true;
|
|
761
796
|
}).map((s) => s.id);
|
|
797
|
+
skippedSkillIds = candidateIds.filter((id) => existingSkillIds.has(id));
|
|
798
|
+
onlyIds = candidateIds.filter((id) => !existingSkillIds.has(id));
|
|
799
|
+
}
|
|
800
|
+
if (!isIncremental && existingSkillsCfg && onlyIds.length === 0) {
|
|
801
|
+
return { status: "already-added" };
|
|
762
802
|
}
|
|
763
803
|
if (isIncremental && onlyIds.length === 0) {
|
|
764
804
|
return {
|
|
@@ -835,6 +875,7 @@ async function runSkillsAdd(options) {
|
|
|
835
875
|
};
|
|
836
876
|
}
|
|
837
877
|
await writeSkillsLock(projectRoot, lock);
|
|
878
|
+
await ensureMcpJson(projectRoot);
|
|
838
879
|
return {
|
|
839
880
|
status: "installed",
|
|
840
881
|
packageName,
|
|
@@ -856,85 +897,110 @@ function mergeInstalledResources(existing, next) {
|
|
|
856
897
|
return [...map.values()];
|
|
857
898
|
}
|
|
858
899
|
|
|
859
|
-
// src/core/
|
|
860
|
-
var BASELINE_DESIGN_RULES_SKILL = "teamix-evo-design-rules";
|
|
900
|
+
// src/core/tokens-init.ts
|
|
861
901
|
var DEFAULT_SKILLS_PACKAGE2 = "@teamix-evo/skills";
|
|
862
902
|
var DEFAULT_AUTO_SKILL_IDES = ["qoder", "claude"];
|
|
863
903
|
var DEFAULT_AUTO_SKILL_SCOPE = "project";
|
|
864
|
-
var
|
|
904
|
+
var DEFAULT_TOKENS_PACKAGE = "@teamix-evo/tokens";
|
|
905
|
+
var CONSUMER_TOKENS_DIR = "tokens";
|
|
906
|
+
var CONSUMER_THEME_FILE = "tokens.theme.css";
|
|
907
|
+
var CONSUMER_OVERRIDES_FILE = "tokens.overrides.css";
|
|
908
|
+
var EMPTY_OVERRIDES_TEMPLATE = `/* User-owned token overrides \u2014 frozen on subsequent installs. */
|
|
909
|
+
/* See @teamix-evo/tokens variant theme.css for available CSS custom properties. */
|
|
910
|
+
`;
|
|
865
911
|
var require3 = createRequire2(import.meta.url);
|
|
866
|
-
async function
|
|
912
|
+
async function runTokensInit(options) {
|
|
867
913
|
const { projectRoot, variant, ide } = options;
|
|
868
|
-
const packageName = options.packageName ??
|
|
914
|
+
const packageName = options.packageName ?? DEFAULT_TOKENS_PACKAGE;
|
|
869
915
|
await ensureTeamixDir(projectRoot);
|
|
870
|
-
const
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
status: "already-initialized",
|
|
874
|
-
existingVariant: existingConfig.packages.design.variant
|
|
875
|
-
};
|
|
876
|
-
}
|
|
877
|
-
const packageRoot = options.packageRoot ?? resolveDesignPackageRoot(packageName);
|
|
878
|
-
const catalog = await loadDesignPackageManifest(packageRoot);
|
|
879
|
-
const variantEntry = catalog.variants.find((v) => v.name === variant);
|
|
916
|
+
const packageRoot = options.packageRoot ?? resolveTokensPackageRoot(packageName);
|
|
917
|
+
const catalog = await loadTokensPackageManifest(packageRoot);
|
|
918
|
+
const variantEntry = getVariantEntry(catalog, variant);
|
|
880
919
|
if (!variantEntry) {
|
|
881
920
|
const known = catalog.variants.map((v) => v.name).join(", ");
|
|
882
921
|
throw new Error(
|
|
883
|
-
`
|
|
922
|
+
`Unknown variant "${variant}". Available variants: ${known || "(none)"}.
|
|
923
|
+
Run \`teamix-evo tokens list-variants\` to see all options.`
|
|
884
924
|
);
|
|
885
925
|
}
|
|
886
|
-
const
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
926
|
+
const existingConfig = await readProjectConfig(projectRoot);
|
|
927
|
+
if (existingConfig?.packages?.tokens) {
|
|
928
|
+
const existingVariant = existingConfig.packages.tokens.variant;
|
|
929
|
+
if (existingVariant === variant) {
|
|
930
|
+
return { status: "already-initialized", existingVariant };
|
|
931
|
+
}
|
|
932
|
+
return {
|
|
933
|
+
status: "variant-mismatch",
|
|
934
|
+
existingVariant,
|
|
935
|
+
requestedVariant: variant
|
|
936
|
+
};
|
|
937
|
+
}
|
|
891
938
|
const installed = [];
|
|
892
|
-
for (const
|
|
893
|
-
const result = await
|
|
939
|
+
for (const fileRel of variantEntry.files) {
|
|
940
|
+
const result = await installVariantFile(fileRel, packageRoot, projectRoot);
|
|
894
941
|
if (result) installed.push(result);
|
|
895
942
|
}
|
|
943
|
+
const overridesAbs = path9.join(
|
|
944
|
+
projectRoot,
|
|
945
|
+
CONSUMER_TOKENS_DIR,
|
|
946
|
+
CONSUMER_OVERRIDES_FILE
|
|
947
|
+
);
|
|
948
|
+
if (!await fileExists(overridesAbs)) {
|
|
949
|
+
await writeFileSafe(overridesAbs, EMPTY_OVERRIDES_TEMPLATE);
|
|
950
|
+
}
|
|
951
|
+
const overridesContent = await fs6.readFile(overridesAbs, "utf-8");
|
|
952
|
+
installed.push({
|
|
953
|
+
id: `tokens:${CONSUMER_OVERRIDES_FILE}`,
|
|
954
|
+
target: path9.posix.join(CONSUMER_TOKENS_DIR, CONSUMER_OVERRIDES_FILE),
|
|
955
|
+
hash: computeHash(overridesContent),
|
|
956
|
+
strategy: "frozen"
|
|
957
|
+
});
|
|
896
958
|
const lock = {
|
|
897
959
|
schemaVersion: 1,
|
|
898
|
-
default: { version: defaultPack.version, from: packageName },
|
|
899
960
|
variant: {
|
|
900
|
-
name:
|
|
901
|
-
displayName:
|
|
902
|
-
version:
|
|
961
|
+
name: variantEntry.name,
|
|
962
|
+
displayName: variantEntry.displayName,
|
|
963
|
+
version: variantEntry.version,
|
|
903
964
|
from: packageName
|
|
904
965
|
},
|
|
905
|
-
|
|
966
|
+
packageVersion: catalog.version,
|
|
967
|
+
linked: variantEntry.linked,
|
|
906
968
|
installedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
907
969
|
};
|
|
908
970
|
await writeFileSafe(
|
|
909
|
-
path9.join(projectRoot, ".teamix-evo", "
|
|
971
|
+
path9.join(projectRoot, ".teamix-evo", "tokens-lock.json"),
|
|
910
972
|
JSON.stringify(lock, null, 2) + "\n"
|
|
911
973
|
);
|
|
912
974
|
const config = {
|
|
913
975
|
$schema: "https://teamix-evo.dev/schema/config/v1.json",
|
|
914
976
|
schemaVersion: 1,
|
|
915
|
-
ide,
|
|
977
|
+
ide: existingConfig?.ide ?? ide,
|
|
916
978
|
packages: {
|
|
917
|
-
|
|
979
|
+
...existingConfig?.packages ?? {},
|
|
980
|
+
tokens: {
|
|
918
981
|
variant,
|
|
919
|
-
version:
|
|
982
|
+
version: variantEntry.version,
|
|
920
983
|
tailwind: "v4"
|
|
921
984
|
}
|
|
922
985
|
}
|
|
923
986
|
};
|
|
924
987
|
await writeProjectConfig(projectRoot, config);
|
|
925
|
-
const
|
|
988
|
+
const prior = await readInstalledManifest(projectRoot) ?? {
|
|
926
989
|
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
|
-
]
|
|
990
|
+
installed: []
|
|
936
991
|
};
|
|
937
|
-
|
|
992
|
+
const tokensIdx = prior.installed.findIndex((p) => p.package === packageName);
|
|
993
|
+
const tokensEntry = {
|
|
994
|
+
package: packageName,
|
|
995
|
+
variant,
|
|
996
|
+
version: variantEntry.version,
|
|
997
|
+
installedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
998
|
+
resources: installed
|
|
999
|
+
};
|
|
1000
|
+
if (tokensIdx >= 0) prior.installed[tokensIdx] = tokensEntry;
|
|
1001
|
+
else prior.installed.push(tokensEntry);
|
|
1002
|
+
await writeInstalledManifest(projectRoot, prior);
|
|
1003
|
+
await ensureMcpJson(projectRoot);
|
|
938
1004
|
const skills = await tryAutoInstallVariantSkills({
|
|
939
1005
|
projectRoot,
|
|
940
1006
|
variant,
|
|
@@ -944,21 +1010,16 @@ async function runDesignInit(options) {
|
|
|
944
1010
|
status: "installed",
|
|
945
1011
|
packageName,
|
|
946
1012
|
variant,
|
|
947
|
-
version:
|
|
1013
|
+
version: variantEntry.version,
|
|
948
1014
|
count: installed.length,
|
|
949
1015
|
resources: installed,
|
|
950
|
-
merge: {
|
|
951
|
-
overrides: merge.overrides,
|
|
952
|
-
variantAdds: merge.variantAdds,
|
|
953
|
-
defaultPassThrough: merge.defaultPassThrough
|
|
954
|
-
},
|
|
955
1016
|
skills
|
|
956
1017
|
};
|
|
957
1018
|
}
|
|
958
1019
|
async function tryAutoInstallVariantSkills(args) {
|
|
959
1020
|
const { projectRoot, variant, ide } = args;
|
|
960
|
-
const variantSkillId =
|
|
961
|
-
const desired = [
|
|
1021
|
+
const variantSkillId = `teamix-evo-design-${variant}`;
|
|
1022
|
+
const desired = [variantSkillId];
|
|
962
1023
|
let manifestSkillIds;
|
|
963
1024
|
try {
|
|
964
1025
|
const { manifest } = await loadSkillsData(DEFAULT_SKILLS_PACKAGE2);
|
|
@@ -978,7 +1039,9 @@ async function tryAutoInstallVariantSkills(args) {
|
|
|
978
1039
|
const missing = desired.filter((id) => !manifestSkillIds.has(id));
|
|
979
1040
|
if (missing.length > 0) {
|
|
980
1041
|
logger.warn(
|
|
981
|
-
`Skills auto-install: not found in manifest, skipping: ${missing.join(
|
|
1042
|
+
`Skills auto-install: not found in manifest, skipping: ${missing.join(
|
|
1043
|
+
", "
|
|
1044
|
+
)}.`
|
|
982
1045
|
);
|
|
983
1046
|
}
|
|
984
1047
|
if (present.length === 0) {
|
|
@@ -1023,38 +1086,60 @@ async function tryAutoInstallVariantSkills(args) {
|
|
|
1023
1086
|
};
|
|
1024
1087
|
}
|
|
1025
1088
|
}
|
|
1026
|
-
async function
|
|
1027
|
-
const
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1089
|
+
async function installVariantFile(fileRelToPackage, packageRoot, projectRoot) {
|
|
1090
|
+
const sourceAbs = path9.join(packageRoot, fileRelToPackage);
|
|
1091
|
+
const base = path9.basename(fileRelToPackage);
|
|
1092
|
+
if (base === "theme.css") {
|
|
1093
|
+
const targetRel = path9.posix.join(
|
|
1094
|
+
CONSUMER_TOKENS_DIR,
|
|
1095
|
+
CONSUMER_THEME_FILE
|
|
1096
|
+
);
|
|
1097
|
+
const targetAbs = path9.join(projectRoot, targetRel);
|
|
1098
|
+
const content = await fs6.readFile(sourceAbs, "utf-8");
|
|
1099
|
+
await writeFileSafe(targetAbs, content);
|
|
1032
1100
|
return {
|
|
1033
|
-
id: `
|
|
1034
|
-
target:
|
|
1035
|
-
hash: computeHash(
|
|
1036
|
-
strategy:
|
|
1101
|
+
id: `tokens:${CONSUMER_THEME_FILE}`,
|
|
1102
|
+
target: targetRel,
|
|
1103
|
+
hash: computeHash(content),
|
|
1104
|
+
strategy: "regenerable"
|
|
1037
1105
|
};
|
|
1038
1106
|
}
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1107
|
+
if (base === "overrides.css" || base === "tokens.overrides.css") {
|
|
1108
|
+
const targetRel = path9.posix.join(
|
|
1109
|
+
CONSUMER_TOKENS_DIR,
|
|
1110
|
+
CONSUMER_OVERRIDES_FILE
|
|
1111
|
+
);
|
|
1112
|
+
const targetAbs = path9.join(projectRoot, targetRel);
|
|
1113
|
+
if (await fileExists(targetAbs)) {
|
|
1114
|
+
const existing = await fs6.readFile(targetAbs, "utf-8");
|
|
1115
|
+
return {
|
|
1116
|
+
id: `tokens:${CONSUMER_OVERRIDES_FILE}`,
|
|
1117
|
+
target: targetRel,
|
|
1118
|
+
hash: computeHash(existing),
|
|
1119
|
+
strategy: "frozen"
|
|
1120
|
+
};
|
|
1121
|
+
}
|
|
1122
|
+
const content = await fs6.readFile(sourceAbs, "utf-8");
|
|
1123
|
+
await writeFileSafe(targetAbs, content);
|
|
1124
|
+
return {
|
|
1125
|
+
id: `tokens:${CONSUMER_OVERRIDES_FILE}`,
|
|
1126
|
+
target: targetRel,
|
|
1127
|
+
hash: computeHash(content),
|
|
1128
|
+
strategy: "frozen"
|
|
1129
|
+
};
|
|
1130
|
+
}
|
|
1131
|
+
return null;
|
|
1047
1132
|
}
|
|
1048
|
-
function
|
|
1133
|
+
function resolveTokensPackageRoot(packageName) {
|
|
1049
1134
|
const pkgJson = require3.resolve(`${packageName}/package.json`);
|
|
1050
1135
|
return path9.dirname(pkgJson);
|
|
1051
1136
|
}
|
|
1052
|
-
async function
|
|
1053
|
-
const root = packageRoot ??
|
|
1054
|
-
const catalog = await
|
|
1137
|
+
async function listTokenVariants(packageName = DEFAULT_TOKENS_PACKAGE, packageRoot) {
|
|
1138
|
+
const root = packageRoot ?? resolveTokensPackageRoot(packageName);
|
|
1139
|
+
const catalog = await loadTokensPackageManifest(root);
|
|
1055
1140
|
return {
|
|
1056
1141
|
packageName,
|
|
1057
|
-
|
|
1142
|
+
packageVersion: catalog.version,
|
|
1058
1143
|
variants: catalog.variants.map((v) => ({
|
|
1059
1144
|
name: v.name,
|
|
1060
1145
|
displayName: v.displayName,
|
|
@@ -1065,25 +1150,73 @@ async function listDesignVariants(packageName = DEFAULT_DESIGN_PACKAGE, packageR
|
|
|
1065
1150
|
};
|
|
1066
1151
|
}
|
|
1067
1152
|
|
|
1068
|
-
// src/
|
|
1153
|
+
// src/utils/global-root.ts
|
|
1154
|
+
import { existsSync } from "fs";
|
|
1155
|
+
import * as fs7 from "fs/promises";
|
|
1156
|
+
import * as os3 from "os";
|
|
1157
|
+
import * as path10 from "path";
|
|
1158
|
+
var GLOBAL_META_DIR = ".teamix-evo-global";
|
|
1159
|
+
var TEAMIX_DIR2 = ".teamix-evo";
|
|
1160
|
+
var CONFIG_FILE2 = "config.json";
|
|
1161
|
+
function getGlobalMetaRoot() {
|
|
1162
|
+
return path10.join(os3.homedir(), GLOBAL_META_DIR);
|
|
1163
|
+
}
|
|
1164
|
+
function isTeamixEvoProject(dir) {
|
|
1165
|
+
return existsSync(path10.join(dir, TEAMIX_DIR2, CONFIG_FILE2));
|
|
1166
|
+
}
|
|
1167
|
+
async function ensureGlobalMetaRoot() {
|
|
1168
|
+
const root = getGlobalMetaRoot();
|
|
1169
|
+
await fs7.mkdir(root, { recursive: true });
|
|
1170
|
+
return root;
|
|
1171
|
+
}
|
|
1172
|
+
function hasPackageJson(projectRoot) {
|
|
1173
|
+
return existsSync(path10.join(projectRoot, "package.json"));
|
|
1174
|
+
}
|
|
1175
|
+
function resolveSkillsMaintenanceRoot(cwd) {
|
|
1176
|
+
if (isTeamixEvoProject(cwd)) return cwd;
|
|
1177
|
+
const globalRoot = getGlobalMetaRoot();
|
|
1178
|
+
if (isTeamixEvoProject(globalRoot)) return globalRoot;
|
|
1179
|
+
return cwd;
|
|
1180
|
+
}
|
|
1181
|
+
|
|
1182
|
+
// src/commands/tokens/init.ts
|
|
1069
1183
|
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
1184
|
try {
|
|
1071
1185
|
const ide = detectIde();
|
|
1072
1186
|
const projectRoot = ide.getProjectRoot();
|
|
1187
|
+
if (!hasPackageJson(projectRoot)) {
|
|
1188
|
+
logger.error(
|
|
1189
|
+
"No package.json found in current directory. Please run this command in a valid project root."
|
|
1190
|
+
);
|
|
1191
|
+
process.exit(1);
|
|
1192
|
+
}
|
|
1073
1193
|
logger.info(`Initializing design system: variant="${variant}"`);
|
|
1074
1194
|
logger.debug(`Project root: ${projectRoot}`);
|
|
1075
1195
|
logger.debug(`IDE: ${ide.name}`);
|
|
1076
1196
|
logger.info(`Loading variant "${variant}"...`);
|
|
1077
1197
|
logger.info("Installing resources...");
|
|
1078
|
-
const result = await
|
|
1198
|
+
const result = await runTokensInit({
|
|
1079
1199
|
projectRoot,
|
|
1080
1200
|
variant,
|
|
1081
1201
|
ide: ide.name
|
|
1082
1202
|
});
|
|
1083
1203
|
if (result.status === "already-initialized") {
|
|
1084
|
-
logger.
|
|
1085
|
-
`Design system already initialized (variant: ${result.existingVariant}). Use "teamix-evo
|
|
1204
|
+
logger.info(
|
|
1205
|
+
`Design system already initialized (variant: ${result.existingVariant}). Use "teamix-evo tokens update" to refresh resources.`
|
|
1206
|
+
);
|
|
1207
|
+
return;
|
|
1208
|
+
}
|
|
1209
|
+
if (result.status === "variant-mismatch") {
|
|
1210
|
+
logger.error(
|
|
1211
|
+
`Cannot switch tokens variant in place. Currently installed: "${result.existingVariant}"; requested: "${result.requestedVariant}".`
|
|
1212
|
+
);
|
|
1213
|
+
logger.info("To switch variants:");
|
|
1214
|
+
logger.info(" 1. teamix-evo tokens uninstall --yes");
|
|
1215
|
+
logger.info(` 2. teamix-evo tokens init ${result.requestedVariant}`);
|
|
1216
|
+
logger.info(
|
|
1217
|
+
"Note: tokens.overrides.css (frozen) is preserved across uninstall/init by default."
|
|
1086
1218
|
);
|
|
1219
|
+
process.exitCode = 1;
|
|
1087
1220
|
return;
|
|
1088
1221
|
}
|
|
1089
1222
|
logger.success(
|
|
@@ -1092,9 +1225,6 @@ var initCommand = new Command("init").description("\u521D\u59CB\u5316\u8BBE\u8BA
|
|
|
1092
1225
|
logger.info(` Variant: ${result.variant}`);
|
|
1093
1226
|
logger.info(` Tailwind: v4`);
|
|
1094
1227
|
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
1228
|
if (result.skills) {
|
|
1099
1229
|
const { addedSkillIds, skippedSkillIds, missing } = result.skills;
|
|
1100
1230
|
if (addedSkillIds.length > 0) {
|
|
@@ -1114,9 +1244,9 @@ var initCommand = new Command("init").description("\u521D\u59CB\u5316\u8BBE\u8BA
|
|
|
1114
1244
|
}
|
|
1115
1245
|
}
|
|
1116
1246
|
logger.info("");
|
|
1117
|
-
logger.info('Run "teamix-evo
|
|
1247
|
+
logger.info('Run "teamix-evo tokens update" to update resources later.');
|
|
1118
1248
|
logger.info(
|
|
1119
|
-
'Run "teamix-evo
|
|
1249
|
+
'Run "teamix-evo tokens list-variants" to see all available variants.'
|
|
1120
1250
|
);
|
|
1121
1251
|
} catch (err) {
|
|
1122
1252
|
logger.error(`Failed to initialize: ${err.message}`);
|
|
@@ -1125,43 +1255,191 @@ var initCommand = new Command("init").description("\u521D\u59CB\u5316\u8BBE\u8BA
|
|
|
1125
1255
|
}
|
|
1126
1256
|
});
|
|
1127
1257
|
|
|
1128
|
-
// src/commands/
|
|
1258
|
+
// src/commands/tokens/update.ts
|
|
1129
1259
|
import { Command as Command2 } from "commander";
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1260
|
+
|
|
1261
|
+
// src/core/tokens-update.ts
|
|
1262
|
+
import * as path11 from "path";
|
|
1263
|
+
import * as fs8 from "fs/promises";
|
|
1264
|
+
import { createRequire as createRequire3 } from "module";
|
|
1265
|
+
import {
|
|
1266
|
+
loadTokensPackageManifest as loadTokensPackageManifest2,
|
|
1267
|
+
getVariantEntry as getVariantEntry2
|
|
1268
|
+
} from "@teamix-evo/registry";
|
|
1269
|
+
var DEFAULT_TOKENS_PACKAGE2 = "@teamix-evo/tokens";
|
|
1270
|
+
var CONSUMER_TOKENS_DIR2 = "tokens";
|
|
1271
|
+
var CONSUMER_THEME_FILE2 = "tokens.theme.css";
|
|
1272
|
+
var require4 = createRequire3(import.meta.url);
|
|
1273
|
+
async function runTokensUpdate(options) {
|
|
1274
|
+
const { projectRoot } = options;
|
|
1275
|
+
const packageName = options.packageName ?? DEFAULT_TOKENS_PACKAGE2;
|
|
1276
|
+
const config = await readProjectConfig(projectRoot);
|
|
1277
|
+
if (!config?.packages?.tokens) {
|
|
1278
|
+
return { status: "not-initialized" };
|
|
1279
|
+
}
|
|
1280
|
+
const currentVariant = config.packages.tokens.variant;
|
|
1281
|
+
const currentVersion = config.packages.tokens.version;
|
|
1282
|
+
const packageRoot = options.packageRoot ?? resolveTokensPackageRoot2(packageName);
|
|
1283
|
+
const catalog = await loadTokensPackageManifest2(packageRoot);
|
|
1284
|
+
const variantEntry = getVariantEntry2(catalog, currentVariant);
|
|
1285
|
+
if (!variantEntry) {
|
|
1286
|
+
throw new Error(
|
|
1287
|
+
`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.`
|
|
1288
|
+
);
|
|
1289
|
+
}
|
|
1290
|
+
if (variantEntry.version === currentVersion) {
|
|
1291
|
+
await rewriteRegenerableFiles(variantEntry.files, packageRoot, projectRoot);
|
|
1292
|
+
return {
|
|
1293
|
+
status: "up-to-date",
|
|
1294
|
+
packageName,
|
|
1295
|
+
variant: currentVariant,
|
|
1296
|
+
version: currentVersion
|
|
1297
|
+
};
|
|
1298
|
+
}
|
|
1299
|
+
const rewritten = await rewriteRegenerableFiles(
|
|
1300
|
+
variantEntry.files,
|
|
1301
|
+
packageRoot,
|
|
1302
|
+
projectRoot
|
|
1133
1303
|
);
|
|
1134
|
-
|
|
1135
|
-
|
|
1304
|
+
const preserved = [];
|
|
1305
|
+
const overridesAbs = path11.join(
|
|
1306
|
+
projectRoot,
|
|
1307
|
+
CONSUMER_TOKENS_DIR2,
|
|
1308
|
+
"tokens.overrides.css"
|
|
1136
1309
|
);
|
|
1137
|
-
|
|
1138
|
-
|
|
1310
|
+
if (await fileExists(overridesAbs)) preserved.push("tokens.overrides.css");
|
|
1311
|
+
const lock = {
|
|
1312
|
+
schemaVersion: 1,
|
|
1313
|
+
variant: {
|
|
1314
|
+
name: variantEntry.name,
|
|
1315
|
+
displayName: variantEntry.displayName,
|
|
1316
|
+
version: variantEntry.version,
|
|
1317
|
+
from: packageName
|
|
1318
|
+
},
|
|
1319
|
+
packageVersion: catalog.version,
|
|
1320
|
+
linked: variantEntry.linked,
|
|
1321
|
+
installedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
1322
|
+
};
|
|
1323
|
+
await writeFileSafe(
|
|
1324
|
+
path11.join(projectRoot, ".teamix-evo", "tokens-lock.json"),
|
|
1325
|
+
JSON.stringify(lock, null, 2) + "\n"
|
|
1139
1326
|
);
|
|
1140
|
-
|
|
1327
|
+
config.packages.tokens.version = variantEntry.version;
|
|
1328
|
+
await writeProjectConfig(projectRoot, config);
|
|
1329
|
+
const prior = await readInstalledManifest(projectRoot) ?? {
|
|
1330
|
+
schemaVersion: 1,
|
|
1331
|
+
installed: []
|
|
1332
|
+
};
|
|
1333
|
+
const idx = prior.installed.findIndex((p) => p.package === packageName);
|
|
1334
|
+
if (idx >= 0) {
|
|
1335
|
+
prior.installed[idx].version = variantEntry.version;
|
|
1336
|
+
prior.installed[idx].installedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
1337
|
+
for (const r of prior.installed[idx].resources) {
|
|
1338
|
+
if (r.strategy === "regenerable") {
|
|
1339
|
+
const abs = path11.isAbsolute(r.target) ? r.target : path11.join(projectRoot, r.target);
|
|
1340
|
+
if (await fileExists(abs)) {
|
|
1341
|
+
r.hash = computeHash(await fs8.readFile(abs, "utf-8"));
|
|
1342
|
+
}
|
|
1343
|
+
}
|
|
1344
|
+
}
|
|
1345
|
+
await writeInstalledManifest(projectRoot, prior);
|
|
1346
|
+
}
|
|
1347
|
+
return {
|
|
1348
|
+
status: "updated",
|
|
1349
|
+
packageName,
|
|
1350
|
+
variant: currentVariant,
|
|
1351
|
+
from: currentVersion,
|
|
1352
|
+
to: variantEntry.version,
|
|
1353
|
+
rewritten,
|
|
1354
|
+
preserved
|
|
1355
|
+
};
|
|
1356
|
+
}
|
|
1357
|
+
async function rewriteRegenerableFiles(files, packageRoot, projectRoot) {
|
|
1358
|
+
const written = [];
|
|
1359
|
+
for (const fileRel of files) {
|
|
1360
|
+
const base = path11.basename(fileRel);
|
|
1361
|
+
if (base !== "theme.css") continue;
|
|
1362
|
+
const sourceAbs = path11.join(packageRoot, fileRel);
|
|
1363
|
+
const targetAbs = path11.join(
|
|
1364
|
+
projectRoot,
|
|
1365
|
+
CONSUMER_TOKENS_DIR2,
|
|
1366
|
+
CONSUMER_THEME_FILE2
|
|
1367
|
+
);
|
|
1368
|
+
const content = await fs8.readFile(sourceAbs, "utf-8");
|
|
1369
|
+
await writeFileSafe(targetAbs, content);
|
|
1370
|
+
written.push(CONSUMER_THEME_FILE2);
|
|
1371
|
+
}
|
|
1372
|
+
return written;
|
|
1373
|
+
}
|
|
1374
|
+
function resolveTokensPackageRoot2(packageName) {
|
|
1375
|
+
const pkgJson = require4.resolve(`${packageName}/package.json`);
|
|
1376
|
+
return path11.dirname(pkgJson);
|
|
1377
|
+
}
|
|
1378
|
+
|
|
1379
|
+
// src/commands/tokens/update.ts
|
|
1380
|
+
var updateCommand = new Command2("update").description(
|
|
1381
|
+
"\u5237\u65B0 design tokens\uFF08regenerable \u8986\u76D6\u3001frozen \u4FDD\u7559 \u2014 ADR 0003 \u4E09\u6001\uFF09"
|
|
1382
|
+
).action(async () => {
|
|
1383
|
+
try {
|
|
1384
|
+
const ide = detectIde();
|
|
1385
|
+
const projectRoot = ide.getProjectRoot();
|
|
1386
|
+
const result = await runTokensUpdate({ projectRoot });
|
|
1387
|
+
if (result.status === "not-initialized") {
|
|
1388
|
+
logger.error(
|
|
1389
|
+
"No tokens variant installed. Run `teamix-evo tokens init <variant>` first."
|
|
1390
|
+
);
|
|
1391
|
+
process.exitCode = 1;
|
|
1392
|
+
return;
|
|
1393
|
+
}
|
|
1394
|
+
if (result.status === "up-to-date") {
|
|
1395
|
+
logger.success(
|
|
1396
|
+
`Already at latest: ${result.packageName} (${result.variant} v${result.version})`
|
|
1397
|
+
);
|
|
1398
|
+
logger.info(
|
|
1399
|
+
" Regenerable files refreshed in case of manual edits."
|
|
1400
|
+
);
|
|
1401
|
+
return;
|
|
1402
|
+
}
|
|
1403
|
+
logger.success(
|
|
1404
|
+
`Updated ${result.packageName} (${result.variant}): v${result.from} \u2192 v${result.to}`
|
|
1405
|
+
);
|
|
1406
|
+
if (result.rewritten.length > 0) {
|
|
1407
|
+
logger.info(` Rewrote: ${result.rewritten.join(", ")}`);
|
|
1408
|
+
}
|
|
1409
|
+
if (result.preserved.length > 0) {
|
|
1410
|
+
logger.info(
|
|
1411
|
+
` Preserved: ${result.preserved.join(", ")} (frozen \u2014 your customizations kept)`
|
|
1412
|
+
);
|
|
1413
|
+
}
|
|
1414
|
+
} catch (err) {
|
|
1415
|
+
logger.error(`Failed to update tokens: ${err.message}`);
|
|
1416
|
+
logger.debug(err.stack ?? "");
|
|
1417
|
+
process.exitCode = 1;
|
|
1418
|
+
}
|
|
1141
1419
|
});
|
|
1142
1420
|
|
|
1143
|
-
// src/commands/
|
|
1421
|
+
// src/commands/tokens/list.ts
|
|
1144
1422
|
import { Command as Command3 } from "commander";
|
|
1145
1423
|
var listCommand = new Command3("list").description("\u5217\u51FA\u5DF2\u5B89\u88C5\u7684\u8BBE\u8BA1\u53D8\u4F53").action(async () => {
|
|
1146
1424
|
try {
|
|
1147
1425
|
const ide = detectIde();
|
|
1148
1426
|
const projectRoot = ide.getProjectRoot();
|
|
1149
1427
|
const config = await readProjectConfig(projectRoot);
|
|
1150
|
-
if (!config?.packages?.
|
|
1151
|
-
logger.info("No
|
|
1152
|
-
logger.info('Run "teamix-evo
|
|
1428
|
+
if (!config?.packages?.tokens) {
|
|
1429
|
+
logger.info("No tokens variant installed.");
|
|
1430
|
+
logger.info('Run "teamix-evo tokens init [variant]" to get started.');
|
|
1153
1431
|
return;
|
|
1154
1432
|
}
|
|
1155
|
-
const { variant, version: version2 } = config.packages.
|
|
1156
|
-
logger.info("Installed
|
|
1157
|
-
logger.info(` Package: @teamix-evo/
|
|
1433
|
+
const { variant, version: version2 } = config.packages.tokens;
|
|
1434
|
+
logger.info("Installed tokens variant:");
|
|
1435
|
+
logger.info(` Package: @teamix-evo/tokens`);
|
|
1158
1436
|
logger.info(` Variant: ${variant}`);
|
|
1159
1437
|
logger.info(` Version: ${version2}`);
|
|
1160
1438
|
logger.info(` IDE: ${config.ide}`);
|
|
1161
1439
|
const manifest = await readInstalledManifest(projectRoot);
|
|
1162
1440
|
if (manifest) {
|
|
1163
1441
|
const pkg = manifest.installed.find(
|
|
1164
|
-
(p) => p.package === "@teamix-evo/
|
|
1442
|
+
(p) => p.package === "@teamix-evo/tokens" && p.variant === variant
|
|
1165
1443
|
);
|
|
1166
1444
|
if (pkg) {
|
|
1167
1445
|
logger.info(` Resources: ${pkg.resources.length} files`);
|
|
@@ -1176,20 +1454,17 @@ var listCommand = new Command3("list").description("\u5217\u51FA\u5DF2\u5B89\u88
|
|
|
1176
1454
|
}
|
|
1177
1455
|
});
|
|
1178
1456
|
|
|
1179
|
-
// src/commands/
|
|
1457
|
+
// src/commands/tokens/list-variants.ts
|
|
1180
1458
|
import { Command as Command4 } from "commander";
|
|
1181
|
-
var listVariantsCommand = new Command4("list-variants").description("\u5217\u51FA @teamix-evo/
|
|
1459
|
+
var listVariantsCommand = new Command4("list-variants").description("\u5217\u51FA @teamix-evo/tokens \u5305\u5185\u63D0\u4F9B\u7684\u6240\u6709\u53D8\u4F53").action(async () => {
|
|
1182
1460
|
try {
|
|
1183
|
-
const result = await
|
|
1184
|
-
logger.info(
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
if (result.defaultDescription) {
|
|
1188
|
-
logger.info(` ${result.defaultDescription}`);
|
|
1189
|
-
}
|
|
1461
|
+
const result = await listTokenVariants();
|
|
1462
|
+
logger.info(
|
|
1463
|
+
`Available variants in ${result.packageName} v${result.packageVersion}:`
|
|
1464
|
+
);
|
|
1190
1465
|
logger.info("");
|
|
1191
1466
|
if (result.variants.length === 0) {
|
|
1192
|
-
logger.info(" (no variants
|
|
1467
|
+
logger.info(" (no variants advertised in manifest.json)");
|
|
1193
1468
|
return;
|
|
1194
1469
|
}
|
|
1195
1470
|
for (const v of result.variants) {
|
|
@@ -1198,12 +1473,13 @@ var listVariantsCommand = new Command4("list-variants").description("\u5217\u51F
|
|
|
1198
1473
|
if (v.linked) {
|
|
1199
1474
|
const links = [];
|
|
1200
1475
|
if (v.linked["biz-ui"]) links.push(`biz-ui: ${v.linked["biz-ui"]}`);
|
|
1201
|
-
if (v.linked.templates)
|
|
1476
|
+
if (v.linked.templates)
|
|
1477
|
+
links.push(`templates: ${v.linked.templates}`);
|
|
1202
1478
|
if (links.length) logger.info(` linked: ${links.join(" / ")}`);
|
|
1203
1479
|
}
|
|
1204
1480
|
logger.info("");
|
|
1205
1481
|
}
|
|
1206
|
-
logger.info("Install a variant: teamix-evo
|
|
1482
|
+
logger.info("Install a variant: teamix-evo tokens init <name>");
|
|
1207
1483
|
} catch (err) {
|
|
1208
1484
|
logger.error(`Failed to list variants: ${err.message}`);
|
|
1209
1485
|
logger.debug(err.stack ?? "");
|
|
@@ -1211,37 +1487,42 @@ var listVariantsCommand = new Command4("list-variants").description("\u5217\u51F
|
|
|
1211
1487
|
}
|
|
1212
1488
|
});
|
|
1213
1489
|
|
|
1214
|
-
// src/commands/
|
|
1490
|
+
// src/commands/tokens/uninstall.ts
|
|
1215
1491
|
import { Command as Command5 } from "commander";
|
|
1216
|
-
import * as
|
|
1217
|
-
import * as
|
|
1492
|
+
import * as fs9 from "fs/promises";
|
|
1493
|
+
import * as path12 from "path";
|
|
1218
1494
|
import * as prompts from "@clack/prompts";
|
|
1219
|
-
var
|
|
1220
|
-
var uninstallCommand = new Command5("uninstall").description(
|
|
1495
|
+
var TOKENS_PACKAGE = "@teamix-evo/tokens";
|
|
1496
|
+
var uninstallCommand = new Command5("uninstall").description(
|
|
1497
|
+
"\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"
|
|
1498
|
+
).option("-y, --yes", "\u8DF3\u8FC7\u786E\u8BA4").option(
|
|
1221
1499
|
"--keep-files",
|
|
1222
|
-
"\u4EC5\u6E05\u7406 .teamix-evo \u4E2D\u7684\u8BB0\u8D26\u4FE1\u606F\uFF0C\u4E0D\u5220\u9664\
|
|
1500
|
+
"\u4EC5\u6E05\u7406 .teamix-evo \u4E2D\u7684\u8BB0\u8D26\u4FE1\u606F\uFF0C\u4E0D\u5220\u9664\u4EFB\u4F55\u843D\u5730\u8D44\u6E90\u6587\u4EF6"
|
|
1501
|
+
).option(
|
|
1502
|
+
"--purge",
|
|
1503
|
+
"\u540C\u65F6\u5220\u9664 frozen \u6587\u4EF6\uFF08\u9ED8\u8BA4 frozen / managed \u90FD\u4FDD\u7559 \u2014 ADR 0003\uFF09"
|
|
1223
1504
|
).action(async (opts) => {
|
|
1224
1505
|
try {
|
|
1225
1506
|
const ide = detectIde();
|
|
1226
1507
|
const projectRoot = ide.getProjectRoot();
|
|
1227
1508
|
const config = await readProjectConfig(projectRoot);
|
|
1228
|
-
if (!config?.packages?.
|
|
1229
|
-
logger.info("
|
|
1509
|
+
if (!config?.packages?.tokens) {
|
|
1510
|
+
logger.info("No tokens variant installed. Nothing to do.");
|
|
1230
1511
|
return;
|
|
1231
1512
|
}
|
|
1232
1513
|
const installedManifest = await readInstalledManifest(projectRoot);
|
|
1233
1514
|
const pkg = installedManifest?.installed.find(
|
|
1234
|
-
(p) => p.package ===
|
|
1515
|
+
(p) => p.package === TOKENS_PACKAGE
|
|
1235
1516
|
);
|
|
1236
1517
|
const resources = pkg?.resources ?? [];
|
|
1237
|
-
const removable = opts.keepFiles ? [] : resources.filter((r) => r.strategy !== "managed");
|
|
1518
|
+
const removable = opts.keepFiles ? [] : opts.purge ? resources.filter((r) => r.strategy !== "managed") : resources.filter((r) => r.strategy === "regenerable");
|
|
1238
1519
|
const kept = resources.length - removable.length;
|
|
1239
1520
|
logger.info(
|
|
1240
1521
|
`Will remove ${removable.length} file(s); keep ${kept} managed file(s).`
|
|
1241
1522
|
);
|
|
1242
1523
|
if (!opts.yes) {
|
|
1243
1524
|
const confirm4 = await prompts.confirm({
|
|
1244
|
-
message: "\u786E\u8BA4\u5378\u8F7D\
|
|
1525
|
+
message: "\u786E\u8BA4\u5378\u8F7D tokens \u53D8\u4F53\uFF1F",
|
|
1245
1526
|
initialValue: false
|
|
1246
1527
|
});
|
|
1247
1528
|
if (prompts.isCancel(confirm4) || !confirm4) {
|
|
@@ -1251,9 +1532,9 @@ var uninstallCommand = new Command5("uninstall").description("\u5378\u8F7D\u8BBE
|
|
|
1251
1532
|
}
|
|
1252
1533
|
let removed = 0;
|
|
1253
1534
|
for (const r of removable) {
|
|
1254
|
-
const target =
|
|
1535
|
+
const target = path12.isAbsolute(r.target) ? r.target : path12.join(projectRoot, r.target);
|
|
1255
1536
|
try {
|
|
1256
|
-
await
|
|
1537
|
+
await fs9.unlink(target);
|
|
1257
1538
|
removed++;
|
|
1258
1539
|
} catch (err) {
|
|
1259
1540
|
if (err.code !== "ENOENT") {
|
|
@@ -1265,18 +1546,31 @@ var uninstallCommand = new Command5("uninstall").description("\u5378\u8F7D\u8BBE
|
|
|
1265
1546
|
}
|
|
1266
1547
|
if (installedManifest) {
|
|
1267
1548
|
installedManifest.installed = installedManifest.installed.filter(
|
|
1268
|
-
(p) => p.package !==
|
|
1549
|
+
(p) => p.package !== TOKENS_PACKAGE
|
|
1269
1550
|
);
|
|
1270
1551
|
await writeInstalledManifest(projectRoot, installedManifest);
|
|
1271
1552
|
}
|
|
1272
|
-
delete config.packages.
|
|
1553
|
+
delete config.packages.tokens;
|
|
1273
1554
|
await writeProjectConfig(projectRoot, config);
|
|
1274
|
-
|
|
1555
|
+
const lockPath = path12.join(
|
|
1556
|
+
projectRoot,
|
|
1557
|
+
".teamix-evo",
|
|
1558
|
+
"tokens-lock.json"
|
|
1559
|
+
);
|
|
1560
|
+
try {
|
|
1561
|
+
await fs9.unlink(lockPath);
|
|
1562
|
+
} catch (err) {
|
|
1563
|
+
if (err.code !== "ENOENT") {
|
|
1564
|
+
logger.warn(
|
|
1565
|
+
`Failed to remove tokens-lock.json: ${err.message}`
|
|
1566
|
+
);
|
|
1567
|
+
}
|
|
1568
|
+
}
|
|
1569
|
+
logger.success(`Uninstalled ${TOKENS_PACKAGE}`);
|
|
1275
1570
|
logger.info(` Removed: ${removed} files`);
|
|
1276
1571
|
if (kept > 0) {
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
);
|
|
1572
|
+
const note = opts.purge ? "managed (you may delete manually)" : "frozen / managed (preserved \u2014 ADR 0003; --purge to force)";
|
|
1573
|
+
logger.info(` Kept: ${kept} files \u2014 ${note}`);
|
|
1280
1574
|
}
|
|
1281
1575
|
} catch (err) {
|
|
1282
1576
|
logger.error(`Failed to uninstall: ${err.message}`);
|
|
@@ -1285,15 +1579,13 @@ var uninstallCommand = new Command5("uninstall").description("\u5378\u8F7D\u8BBE
|
|
|
1285
1579
|
}
|
|
1286
1580
|
});
|
|
1287
1581
|
|
|
1288
|
-
// src/commands/
|
|
1289
|
-
var
|
|
1290
|
-
|
|
1291
|
-
);
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
designCommand.addCommand(listVariantsCommand);
|
|
1296
|
-
designCommand.addCommand(uninstallCommand);
|
|
1582
|
+
// src/commands/tokens/index.ts
|
|
1583
|
+
var tokensCommand = new Command6("tokens").description("\u7BA1\u7406 design tokens(\u53D8\u4F53\u7EA7 theme.css \u7B49)");
|
|
1584
|
+
tokensCommand.addCommand(initCommand);
|
|
1585
|
+
tokensCommand.addCommand(updateCommand);
|
|
1586
|
+
tokensCommand.addCommand(listCommand);
|
|
1587
|
+
tokensCommand.addCommand(listVariantsCommand);
|
|
1588
|
+
tokensCommand.addCommand(uninstallCommand);
|
|
1297
1589
|
|
|
1298
1590
|
// src/commands/skills/index.ts
|
|
1299
1591
|
import { Command as Command13 } from "commander";
|
|
@@ -1301,34 +1593,6 @@ import { Command as Command13 } from "commander";
|
|
|
1301
1593
|
// src/commands/skills/add.ts
|
|
1302
1594
|
import { Command as Command7 } from "commander";
|
|
1303
1595
|
import * as prompts2 from "@clack/prompts";
|
|
1304
|
-
|
|
1305
|
-
// src/utils/global-root.ts
|
|
1306
|
-
import { existsSync } from "fs";
|
|
1307
|
-
import * as fs8 from "fs/promises";
|
|
1308
|
-
import * as os3 from "os";
|
|
1309
|
-
import * as path11 from "path";
|
|
1310
|
-
var GLOBAL_META_DIR = ".teamix-evo-global";
|
|
1311
|
-
var TEAMIX_DIR3 = ".teamix-evo";
|
|
1312
|
-
var CONFIG_FILE2 = "config.json";
|
|
1313
|
-
function getGlobalMetaRoot() {
|
|
1314
|
-
return path11.join(os3.homedir(), GLOBAL_META_DIR);
|
|
1315
|
-
}
|
|
1316
|
-
function isTeamixEvoProject(dir) {
|
|
1317
|
-
return existsSync(path11.join(dir, TEAMIX_DIR3, CONFIG_FILE2));
|
|
1318
|
-
}
|
|
1319
|
-
async function ensureGlobalMetaRoot() {
|
|
1320
|
-
const root = getGlobalMetaRoot();
|
|
1321
|
-
await fs8.mkdir(root, { recursive: true });
|
|
1322
|
-
return root;
|
|
1323
|
-
}
|
|
1324
|
-
function resolveSkillsMaintenanceRoot(cwd) {
|
|
1325
|
-
if (isTeamixEvoProject(cwd)) return cwd;
|
|
1326
|
-
const globalRoot = getGlobalMetaRoot();
|
|
1327
|
-
if (isTeamixEvoProject(globalRoot)) return globalRoot;
|
|
1328
|
-
return cwd;
|
|
1329
|
-
}
|
|
1330
|
-
|
|
1331
|
-
// src/commands/skills/add.ts
|
|
1332
1596
|
var addCommand = new Command7("add").description(
|
|
1333
1597
|
"\u5411\u9879\u76EE\uFF08\u6216\u5168\u5C40 IDE \u914D\u7F6E\uFF09\u6DFB\u52A0 teamix-evo skills\uFF1B\u4E0D\u4F20 names \u5219\u6DFB\u52A0 manifest \u5185\u5168\u90E8 skill"
|
|
1334
1598
|
).argument(
|
|
@@ -1351,6 +1615,11 @@ var addCommand = new Command7("add").description(
|
|
|
1351
1615
|
if (scope === "global" && !isTeamixEvoProject(cwd)) {
|
|
1352
1616
|
projectRoot = await ensureGlobalMetaRoot();
|
|
1353
1617
|
logger.info(`Global skill install \u2014 meta root: ${projectRoot}`);
|
|
1618
|
+
} else if (scope !== "global" && !hasPackageJson(cwd)) {
|
|
1619
|
+
logger.error(
|
|
1620
|
+
"No package.json found in current directory. Please run this command in a valid project root."
|
|
1621
|
+
);
|
|
1622
|
+
process.exit(1);
|
|
1354
1623
|
}
|
|
1355
1624
|
logger.info(
|
|
1356
1625
|
isIncremental ? `Adding skills [${names.join(",")}]: ides=[${ides.join(
|
|
@@ -1483,11 +1752,17 @@ var listCommand2 = new Command8("list").alias("ls").description(
|
|
|
1483
1752
|
const pkg = installedManifest?.installed.find(
|
|
1484
1753
|
(p) => p.package === SKILLS_PACKAGE
|
|
1485
1754
|
);
|
|
1755
|
+
const skillsLock = await readSkillsLock(projectRoot);
|
|
1486
1756
|
const installedBySkill = /* @__PURE__ */ new Map();
|
|
1487
1757
|
for (const r of pkg?.resources ?? []) {
|
|
1488
1758
|
const skillId = r.id.split(":")[0];
|
|
1489
1759
|
installedBySkill.set(skillId, (installedBySkill.get(skillId) ?? 0) + 1);
|
|
1490
1760
|
}
|
|
1761
|
+
for (const skillId of Object.keys(skillsLock?.skills ?? {})) {
|
|
1762
|
+
if (!installedBySkill.has(skillId)) {
|
|
1763
|
+
installedBySkill.set(skillId, 1);
|
|
1764
|
+
}
|
|
1765
|
+
}
|
|
1491
1766
|
if (opts.installed) {
|
|
1492
1767
|
if (!config?.packages?.skills || !pkg) {
|
|
1493
1768
|
logger.info("No skills installed.");
|
|
@@ -1510,9 +1785,13 @@ var listCommand2 = new Command8("list").alias("ls").description(
|
|
|
1510
1785
|
const skills = [...manifest.skills].sort(
|
|
1511
1786
|
(a, b) => a.id.localeCompare(b.id)
|
|
1512
1787
|
);
|
|
1513
|
-
const isInstalled =
|
|
1514
|
-
if (isInstalled) {
|
|
1788
|
+
const isInstalled = installedBySkill.size > 0;
|
|
1789
|
+
if (isInstalled && config?.packages?.skills && pkg) {
|
|
1515
1790
|
printInstalledHeader(config.packages.skills, pkg.installedAt);
|
|
1791
|
+
} else if (isInstalled) {
|
|
1792
|
+
logger.info(
|
|
1793
|
+
`Installed (${installedBySkill.size} skill(s)) \u2014 config or manifest record missing; run "teamix-evo skills doctor" to repair.`
|
|
1794
|
+
);
|
|
1516
1795
|
} else {
|
|
1517
1796
|
logger.info("Skills package not yet added.");
|
|
1518
1797
|
logger.info(
|
|
@@ -1648,8 +1927,8 @@ var updateCommand2 = new Command9("update").description("\u66F4\u65B0\u5DF2\u5B8
|
|
|
1648
1927
|
// src/commands/skills/uninstall.ts
|
|
1649
1928
|
import { Command as Command10 } from "commander";
|
|
1650
1929
|
import * as prompts3 from "@clack/prompts";
|
|
1651
|
-
import * as
|
|
1652
|
-
import * as
|
|
1930
|
+
import * as path13 from "path";
|
|
1931
|
+
import * as fs10 from "fs/promises";
|
|
1653
1932
|
var SKILLS_PACKAGE3 = "@teamix-evo/skills";
|
|
1654
1933
|
var uninstallCommand2 = new Command10("uninstall").description(
|
|
1655
1934
|
"\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"
|
|
@@ -1717,14 +1996,26 @@ async function runFullUninstall(args) {
|
|
|
1717
1996
|
const removed = await removeSkillFiles(resources);
|
|
1718
1997
|
logger.debug(`Removed ${removed.length} files`);
|
|
1719
1998
|
const skillsRoot = getSkillsSourceDir(projectRoot);
|
|
1999
|
+
const sourceSkillNames = await listSkillSourceNames(skillsRoot);
|
|
1720
2000
|
try {
|
|
1721
|
-
await
|
|
2001
|
+
await fs10.rm(skillsRoot, { recursive: true, force: true });
|
|
1722
2002
|
logger.debug(`Removed source dir ${skillsRoot}`);
|
|
1723
2003
|
} catch (err) {
|
|
1724
2004
|
logger.warn(
|
|
1725
2005
|
`Failed to remove ${skillsRoot}: ${err.message}`
|
|
1726
2006
|
);
|
|
1727
2007
|
}
|
|
2008
|
+
const skillNames = collectSkillNames({
|
|
2009
|
+
fromSources: sourceSkillNames,
|
|
2010
|
+
fromConfig: config,
|
|
2011
|
+
fromResources: resources
|
|
2012
|
+
});
|
|
2013
|
+
const cleanedMirrorDirs = await removeMirrorDirs(
|
|
2014
|
+
projectRoot,
|
|
2015
|
+
config?.packages?.skills?.scope,
|
|
2016
|
+
config?.packages?.skills?.ides,
|
|
2017
|
+
skillNames
|
|
2018
|
+
);
|
|
1728
2019
|
if (installedManifest && pkg) {
|
|
1729
2020
|
installedManifest.installed = installedManifest.installed.filter(
|
|
1730
2021
|
(p) => p.package !== SKILLS_PACKAGE3
|
|
@@ -1735,7 +2026,12 @@ async function runFullUninstall(args) {
|
|
|
1735
2026
|
await writeProjectConfig(projectRoot, config);
|
|
1736
2027
|
logger.success(`Uninstalled ${SKILLS_PACKAGE3}`);
|
|
1737
2028
|
logger.info(` Removed: ${removed.length} files`);
|
|
1738
|
-
logger.info(` Source: ${
|
|
2029
|
+
logger.info(` Source: ${path13.relative(projectRoot, skillsRoot)} (cleaned)`);
|
|
2030
|
+
if (cleanedMirrorDirs.length > 0) {
|
|
2031
|
+
logger.info(
|
|
2032
|
+
` Mirrors: ${cleanedMirrorDirs.map((d) => path13.relative(projectRoot, d)).join(", ")} (cleaned)`
|
|
2033
|
+
);
|
|
2034
|
+
}
|
|
1739
2035
|
}
|
|
1740
2036
|
async function runPartialUninstall(args) {
|
|
1741
2037
|
const { projectRoot, installedManifest, pkg, resources, ids, opts } = args;
|
|
@@ -1771,12 +2067,19 @@ async function runPartialUninstall(args) {
|
|
|
1771
2067
|
for (const id of matched) {
|
|
1772
2068
|
const dir = getSkillsSourceDir(projectRoot, id);
|
|
1773
2069
|
try {
|
|
1774
|
-
await
|
|
2070
|
+
await fs10.rm(dir, { recursive: true, force: true });
|
|
1775
2071
|
logger.debug(`Removed source dir ${dir}`);
|
|
1776
2072
|
} catch (err) {
|
|
1777
2073
|
logger.warn(`Failed to remove ${dir}: ${err.message}`);
|
|
1778
2074
|
}
|
|
1779
2075
|
}
|
|
2076
|
+
const config = await readProjectConfig(projectRoot);
|
|
2077
|
+
const cleanedMirrorDirs = await removeMirrorDirs(
|
|
2078
|
+
projectRoot,
|
|
2079
|
+
config?.packages?.skills?.scope,
|
|
2080
|
+
config?.packages?.skills?.ides,
|
|
2081
|
+
matched
|
|
2082
|
+
);
|
|
1780
2083
|
const lock = await readSkillsLock(projectRoot);
|
|
1781
2084
|
if (lock) {
|
|
1782
2085
|
for (const id of matched) delete lock.skills[id];
|
|
@@ -1790,10 +2093,69 @@ async function runPartialUninstall(args) {
|
|
|
1790
2093
|
`Removed ${matched.length} skill(s): ${matched.join(", ")}`
|
|
1791
2094
|
);
|
|
1792
2095
|
logger.info(` Files: ${removed.length}`);
|
|
2096
|
+
if (cleanedMirrorDirs.length > 0) {
|
|
2097
|
+
logger.info(
|
|
2098
|
+
` Mirrors: ${cleanedMirrorDirs.map((d) => path13.relative(projectRoot, d)).join(", ")} (cleaned)`
|
|
2099
|
+
);
|
|
2100
|
+
}
|
|
1793
2101
|
if (missing.length > 0) {
|
|
1794
2102
|
logger.info(` Skipped: ${missing.join(", ")} (not installed)`);
|
|
1795
2103
|
}
|
|
1796
2104
|
}
|
|
2105
|
+
async function listSkillSourceNames(skillsRoot) {
|
|
2106
|
+
try {
|
|
2107
|
+
const entries = await fs10.readdir(skillsRoot, { withFileTypes: true });
|
|
2108
|
+
return entries.filter((e) => e.isDirectory()).map((e) => e.name);
|
|
2109
|
+
} catch {
|
|
2110
|
+
return [];
|
|
2111
|
+
}
|
|
2112
|
+
}
|
|
2113
|
+
function collectSkillNames(args) {
|
|
2114
|
+
const set = new Set(args.fromSources);
|
|
2115
|
+
for (const r of args.fromResources) {
|
|
2116
|
+
set.add(r.id.split(":")[0]);
|
|
2117
|
+
}
|
|
2118
|
+
return [...set];
|
|
2119
|
+
}
|
|
2120
|
+
async function removeMirrorDirs(projectRoot, scope, ides, skillNames) {
|
|
2121
|
+
if (skillNames.length === 0) return [];
|
|
2122
|
+
const targetIdes = ides && ides.length > 0 ? ides.filter((i) => i === "qoder" || i === "claude") : [...ALL_IDE_KINDS];
|
|
2123
|
+
const targetScope = scope === "global" ? "global" : "project";
|
|
2124
|
+
const removed = [];
|
|
2125
|
+
for (const ide of targetIdes) {
|
|
2126
|
+
const adapter = getAdapter(ide);
|
|
2127
|
+
for (const name of skillNames) {
|
|
2128
|
+
const dir = adapter.getSkillTargetDir(name, targetScope, projectRoot);
|
|
2129
|
+
let existed = true;
|
|
2130
|
+
try {
|
|
2131
|
+
await fs10.access(dir);
|
|
2132
|
+
} catch {
|
|
2133
|
+
existed = false;
|
|
2134
|
+
}
|
|
2135
|
+
if (!existed) continue;
|
|
2136
|
+
try {
|
|
2137
|
+
await fs10.rm(dir, { recursive: true, force: true });
|
|
2138
|
+
removed.push(dir);
|
|
2139
|
+
logger.debug(`Removed mirror dir ${dir}`);
|
|
2140
|
+
} catch (err) {
|
|
2141
|
+
logger.warn(`Failed to remove ${dir}: ${err.message}`);
|
|
2142
|
+
}
|
|
2143
|
+
}
|
|
2144
|
+
if (removed.length > 0) {
|
|
2145
|
+
const skillsParent = path13.dirname(
|
|
2146
|
+
adapter.getSkillTargetDir("placeholder", targetScope, projectRoot)
|
|
2147
|
+
);
|
|
2148
|
+
try {
|
|
2149
|
+
const remaining = await fs10.readdir(skillsParent);
|
|
2150
|
+
if (remaining.length === 0) {
|
|
2151
|
+
await fs10.rmdir(skillsParent);
|
|
2152
|
+
}
|
|
2153
|
+
} catch {
|
|
2154
|
+
}
|
|
2155
|
+
}
|
|
2156
|
+
}
|
|
2157
|
+
return removed;
|
|
2158
|
+
}
|
|
1797
2159
|
function skillIdOf(r) {
|
|
1798
2160
|
return r.id.split(":")[0];
|
|
1799
2161
|
}
|
|
@@ -1815,7 +2177,26 @@ function dedupe(values) {
|
|
|
1815
2177
|
import { Command as Command11 } from "commander";
|
|
1816
2178
|
|
|
1817
2179
|
// src/core/skills-sync.ts
|
|
1818
|
-
import * as
|
|
2180
|
+
import * as path14 from "path";
|
|
2181
|
+
import * as fs11 from "fs/promises";
|
|
2182
|
+
import { createRequire as createRequire4 } from "module";
|
|
2183
|
+
import { loadSkillsPackageManifest as loadSkillsPackageManifest2 } from "@teamix-evo/registry";
|
|
2184
|
+
var require5 = createRequire4(import.meta.url);
|
|
2185
|
+
async function readSkillMetaFromUpstream(skillId) {
|
|
2186
|
+
try {
|
|
2187
|
+
const pkgJson = require5.resolve("@teamix-evo/skills/package.json");
|
|
2188
|
+
const packageRoot = path14.dirname(pkgJson);
|
|
2189
|
+
const manifest = await loadSkillsPackageManifest2(packageRoot);
|
|
2190
|
+
const entry = manifest.skills.find((s) => s.id === skillId);
|
|
2191
|
+
if (!entry) return null;
|
|
2192
|
+
return {
|
|
2193
|
+
updateStrategy: entry.updateStrategy,
|
|
2194
|
+
managedRegions: entry.managedRegions
|
|
2195
|
+
};
|
|
2196
|
+
} catch {
|
|
2197
|
+
return null;
|
|
2198
|
+
}
|
|
2199
|
+
}
|
|
1819
2200
|
var SKILLS_PACKAGE_DEFAULT = "@teamix-evo/skills";
|
|
1820
2201
|
async function runSkillsSync(options) {
|
|
1821
2202
|
const { projectRoot, names } = options;
|
|
@@ -1849,13 +2230,15 @@ async function runSkillsSync(options) {
|
|
|
1849
2230
|
logger.warn(`Skill "${skillId}" has no IDE mirror targets; skipped.`);
|
|
1850
2231
|
continue;
|
|
1851
2232
|
}
|
|
2233
|
+
const upstreamMeta = await readSkillMetaFromUpstream(skillId);
|
|
1852
2234
|
const result = await syncSkillsToIdes({
|
|
1853
2235
|
projectRoot,
|
|
1854
2236
|
skills: [
|
|
1855
2237
|
{
|
|
1856
2238
|
id: skillId,
|
|
1857
2239
|
name: skillId,
|
|
1858
|
-
updateStrategy: "regenerable"
|
|
2240
|
+
updateStrategy: upstreamMeta?.updateStrategy ?? "regenerable",
|
|
2241
|
+
managedRegions: upstreamMeta?.managedRegions
|
|
1859
2242
|
}
|
|
1860
2243
|
],
|
|
1861
2244
|
ides,
|
|
@@ -1882,7 +2265,7 @@ async function runSkillsSync(options) {
|
|
|
1882
2265
|
}
|
|
1883
2266
|
async function dirExists(p) {
|
|
1884
2267
|
try {
|
|
1885
|
-
const stat4 = await
|
|
2268
|
+
const stat4 = await fs11.stat(p);
|
|
1886
2269
|
return stat4.isDirectory();
|
|
1887
2270
|
} catch {
|
|
1888
2271
|
return false;
|
|
@@ -1976,8 +2359,8 @@ function parseScope2(input) {
|
|
|
1976
2359
|
import { Command as Command12 } from "commander";
|
|
1977
2360
|
|
|
1978
2361
|
// src/core/skills-doctor.ts
|
|
1979
|
-
import * as
|
|
1980
|
-
import * as
|
|
2362
|
+
import * as path15 from "path";
|
|
2363
|
+
import * as fs12 from "fs/promises";
|
|
1981
2364
|
async function runSkillsDoctor(options) {
|
|
1982
2365
|
const { projectRoot } = options;
|
|
1983
2366
|
const lock = await readSkillsLock(projectRoot);
|
|
@@ -1999,8 +2382,8 @@ async function runSkillsDoctor(options) {
|
|
|
1999
2382
|
const sourceFiles = await walkDir(sourceDir);
|
|
2000
2383
|
const sourceContents = /* @__PURE__ */ new Map();
|
|
2001
2384
|
for (const f of sourceFiles) {
|
|
2002
|
-
const rel2 =
|
|
2003
|
-
sourceContents.set(rel2, await
|
|
2385
|
+
const rel2 = path15.relative(sourceDir, f);
|
|
2386
|
+
sourceContents.set(rel2, await fs12.readFile(f, "utf-8"));
|
|
2004
2387
|
}
|
|
2005
2388
|
for (const ide of entry.mirroredTo) {
|
|
2006
2389
|
const adapter = getAdapter(ide);
|
|
@@ -2021,7 +2404,7 @@ async function runSkillsDoctor(options) {
|
|
|
2021
2404
|
continue;
|
|
2022
2405
|
}
|
|
2023
2406
|
for (const [rel2, sourceContent] of sourceContents.entries()) {
|
|
2024
|
-
const mirrorFile =
|
|
2407
|
+
const mirrorFile = path15.join(mirrorDir, rel2);
|
|
2025
2408
|
if (!await fileExists(mirrorFile)) {
|
|
2026
2409
|
findings.push({
|
|
2027
2410
|
kind: "missing-mirror",
|
|
@@ -2033,7 +2416,7 @@ async function runSkillsDoctor(options) {
|
|
|
2033
2416
|
});
|
|
2034
2417
|
continue;
|
|
2035
2418
|
}
|
|
2036
|
-
const mirrorContent = await
|
|
2419
|
+
const mirrorContent = await fs12.readFile(mirrorFile, "utf-8");
|
|
2037
2420
|
if (computeHash(mirrorContent) !== computeHash(sourceContent)) {
|
|
2038
2421
|
findings.push({
|
|
2039
2422
|
kind: "mirror-drift",
|
|
@@ -2054,7 +2437,7 @@ async function runSkillsDoctor(options) {
|
|
|
2054
2437
|
}
|
|
2055
2438
|
async function dirExists2(p) {
|
|
2056
2439
|
try {
|
|
2057
|
-
const stat4 = await
|
|
2440
|
+
const stat4 = await fs12.stat(p);
|
|
2058
2441
|
return stat4.isDirectory();
|
|
2059
2442
|
} catch {
|
|
2060
2443
|
return false;
|
|
@@ -2162,6 +2545,7 @@ async function runUiInit(options) {
|
|
|
2162
2545
|
rsc
|
|
2163
2546
|
};
|
|
2164
2547
|
await writeProjectConfig(projectRoot, config);
|
|
2548
|
+
await ensureMcpJson(projectRoot);
|
|
2165
2549
|
return {
|
|
2166
2550
|
status: "installed",
|
|
2167
2551
|
aliases,
|
|
@@ -2182,6 +2566,12 @@ var initCommand2 = new Command14("init").description(
|
|
|
2182
2566
|
try {
|
|
2183
2567
|
const ide = detectIde();
|
|
2184
2568
|
const projectRoot = ide.getProjectRoot();
|
|
2569
|
+
if (!hasPackageJson(projectRoot)) {
|
|
2570
|
+
logger.error(
|
|
2571
|
+
"No package.json found in current directory. Please run this command in a valid project root."
|
|
2572
|
+
);
|
|
2573
|
+
process.exit(1);
|
|
2574
|
+
}
|
|
2185
2575
|
const cfg = await resolveConfig(opts);
|
|
2186
2576
|
const result = await runUiInit({
|
|
2187
2577
|
projectRoot,
|
|
@@ -2282,23 +2672,23 @@ async function resolveConfig(opts) {
|
|
|
2282
2672
|
import { Command as Command15 } from "commander";
|
|
2283
2673
|
|
|
2284
2674
|
// src/core/ui-client.ts
|
|
2285
|
-
import * as
|
|
2286
|
-
import * as
|
|
2287
|
-
import { createRequire as
|
|
2675
|
+
import * as path16 from "path";
|
|
2676
|
+
import * as fs13 from "fs/promises";
|
|
2677
|
+
import { createRequire as createRequire5 } from "module";
|
|
2288
2678
|
import { loadUiPackageManifest } from "@teamix-evo/registry";
|
|
2289
|
-
var
|
|
2679
|
+
var require6 = createRequire5(import.meta.url);
|
|
2290
2680
|
function resolvePackageRoot2(packageName) {
|
|
2291
|
-
const pkgJsonPath =
|
|
2292
|
-
return
|
|
2681
|
+
const pkgJsonPath = require6.resolve(`${packageName}/package.json`);
|
|
2682
|
+
return path16.dirname(pkgJsonPath);
|
|
2293
2683
|
}
|
|
2294
2684
|
async function loadUiData(packageName) {
|
|
2295
2685
|
const packageRoot = resolvePackageRoot2(packageName);
|
|
2296
2686
|
logger.debug(`Resolved ui package root: ${packageRoot}`);
|
|
2297
2687
|
const manifest = await loadUiPackageManifest(packageRoot);
|
|
2298
2688
|
let data = {};
|
|
2299
|
-
const dataPath =
|
|
2689
|
+
const dataPath = path16.join(packageRoot, "_data.json");
|
|
2300
2690
|
try {
|
|
2301
|
-
const raw = await
|
|
2691
|
+
const raw = await fs13.readFile(dataPath, "utf-8");
|
|
2302
2692
|
data = JSON.parse(raw);
|
|
2303
2693
|
} catch (err) {
|
|
2304
2694
|
if (err.code !== "ENOENT") {
|
|
@@ -2310,8 +2700,8 @@ async function loadUiData(packageName) {
|
|
|
2310
2700
|
}
|
|
2311
2701
|
|
|
2312
2702
|
// src/core/ui-installer.ts
|
|
2313
|
-
import * as
|
|
2314
|
-
import * as
|
|
2703
|
+
import * as path17 from "path";
|
|
2704
|
+
import * as fs14 from "fs/promises";
|
|
2315
2705
|
import { resolveUiEntryOrder } from "@teamix-evo/registry";
|
|
2316
2706
|
|
|
2317
2707
|
// src/utils/transform-imports.ts
|
|
@@ -2324,13 +2714,13 @@ var SOURCE_ROOT_TO_ALIAS_KEY = {
|
|
|
2324
2714
|
function rewriteImports(source, aliases) {
|
|
2325
2715
|
return source.replace(
|
|
2326
2716
|
/(['"])@\/([a-z][a-z0-9-]*)(\/[^'"]*)?\1/g,
|
|
2327
|
-
(full,
|
|
2717
|
+
(full, quote2, root, rest) => {
|
|
2328
2718
|
const aliasKey = SOURCE_ROOT_TO_ALIAS_KEY[root];
|
|
2329
2719
|
if (!aliasKey) return full;
|
|
2330
2720
|
const alias = aliases[aliasKey];
|
|
2331
2721
|
const normalized = aliasToImportPath(alias);
|
|
2332
2722
|
const flatRest = flattenRestPath(rest);
|
|
2333
|
-
return `${
|
|
2723
|
+
return `${quote2}${normalized}${flatRest}${quote2}`;
|
|
2334
2724
|
}
|
|
2335
2725
|
);
|
|
2336
2726
|
}
|
|
@@ -2351,12 +2741,12 @@ function aliasToImportPath(alias) {
|
|
|
2351
2741
|
}
|
|
2352
2742
|
|
|
2353
2743
|
// src/core/ui-installer.ts
|
|
2354
|
-
var DESIGN_COMPONENTS_DIR = ".teamix-evo/design/components";
|
|
2355
2744
|
async function installUiEntries(options) {
|
|
2356
2745
|
const {
|
|
2357
2746
|
projectRoot,
|
|
2358
2747
|
manifest,
|
|
2359
2748
|
packageRoot,
|
|
2749
|
+
entryPackageRoot,
|
|
2360
2750
|
aliases,
|
|
2361
2751
|
requested,
|
|
2362
2752
|
skipExisting = true
|
|
@@ -2365,7 +2755,6 @@ async function installUiEntries(options) {
|
|
|
2365
2755
|
const idToEntry = new Map(manifest.entries.map((e) => [e.id, e]));
|
|
2366
2756
|
const resources = [];
|
|
2367
2757
|
const npmDeps = {};
|
|
2368
|
-
const metaFiles = [];
|
|
2369
2758
|
let written = 0;
|
|
2370
2759
|
let skipped = 0;
|
|
2371
2760
|
for (const id of orderedIds) {
|
|
@@ -2384,8 +2773,9 @@ async function installUiEntries(options) {
|
|
|
2384
2773
|
skipped++;
|
|
2385
2774
|
continue;
|
|
2386
2775
|
}
|
|
2387
|
-
const
|
|
2388
|
-
const
|
|
2776
|
+
const rootForEntry = entryPackageRoot?.get(entry.id) ?? packageRoot;
|
|
2777
|
+
const sourceAbs = path17.resolve(rootForEntry, file.source);
|
|
2778
|
+
const raw = await fs14.readFile(sourceAbs, "utf-8");
|
|
2389
2779
|
const transformed = rewriteImports(raw, aliases);
|
|
2390
2780
|
await writeFileSafe(targetAbs, transformed);
|
|
2391
2781
|
written++;
|
|
@@ -2397,32 +2787,13 @@ async function installUiEntries(options) {
|
|
|
2397
2787
|
strategy: entry.updateStrategy ?? "frozen"
|
|
2398
2788
|
});
|
|
2399
2789
|
}
|
|
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
2790
|
}
|
|
2419
2791
|
return {
|
|
2420
2792
|
orderedIds,
|
|
2421
2793
|
resources,
|
|
2422
2794
|
npmDependencies: npmDeps,
|
|
2423
2795
|
written,
|
|
2424
|
-
skipped
|
|
2425
|
-
metaFiles
|
|
2796
|
+
skipped
|
|
2426
2797
|
};
|
|
2427
2798
|
}
|
|
2428
2799
|
function resolveTargetPath(projectRoot, aliases, entry, file) {
|
|
@@ -2432,16 +2803,16 @@ function resolveTargetPath(projectRoot, aliases, entry, file) {
|
|
|
2432
2803
|
`Entry "${entry.id}" requires alias "${file.targetAlias}" but it is not configured.`
|
|
2433
2804
|
);
|
|
2434
2805
|
}
|
|
2435
|
-
return
|
|
2806
|
+
return path17.join(projectRoot, aliasDir, file.targetName);
|
|
2436
2807
|
}
|
|
2437
2808
|
function rel(projectRoot, abs) {
|
|
2438
|
-
return
|
|
2809
|
+
return path17.relative(projectRoot, abs);
|
|
2439
2810
|
}
|
|
2440
2811
|
|
|
2441
2812
|
// src/core/ui-add.ts
|
|
2442
2813
|
var DEFAULT_UI_PACKAGE = "@teamix-evo/ui";
|
|
2443
2814
|
async function runUiAdd(options) {
|
|
2444
|
-
const { projectRoot, ids, overwrite } = options;
|
|
2815
|
+
const { projectRoot, ids, overwrite, includeDeprecated } = options;
|
|
2445
2816
|
const packageName = options.packageName ?? DEFAULT_UI_PACKAGE;
|
|
2446
2817
|
if (ids.length === 0) {
|
|
2447
2818
|
throw new Error("At least one entry id must be provided.");
|
|
@@ -2454,7 +2825,21 @@ async function runUiAdd(options) {
|
|
|
2454
2825
|
);
|
|
2455
2826
|
}
|
|
2456
2827
|
const { manifest, packageRoot } = await loadUiData(packageName);
|
|
2457
|
-
const
|
|
2828
|
+
const archived = manifest.deprecatedEntries ?? [];
|
|
2829
|
+
const archivedIds = new Set(archived.map((e) => e.id));
|
|
2830
|
+
const activeIds = new Set(manifest.entries.map((e) => e.id));
|
|
2831
|
+
const requestedDeprecated = ids.filter((id) => archivedIds.has(id));
|
|
2832
|
+
if (requestedDeprecated.length > 0 && !includeDeprecated) {
|
|
2833
|
+
const list = requestedDeprecated.map((s) => `"${s}"`).join(", ");
|
|
2834
|
+
throw new Error(
|
|
2835
|
+
`Refusing to install deprecated entr${requestedDeprecated.length === 1 ? "y" : "ies"} ${list}. These entries are archived and not part of the active distribution (ADR 0028). Pass \`--include-deprecated\` to override (e.g. for migration tooling).`
|
|
2836
|
+
);
|
|
2837
|
+
}
|
|
2838
|
+
const effectiveManifest = includeDeprecated ? { ...manifest, entries: [...manifest.entries, ...archived] } : manifest;
|
|
2839
|
+
const knownIds = /* @__PURE__ */ new Set([
|
|
2840
|
+
...activeIds,
|
|
2841
|
+
...includeDeprecated ? archivedIds : []
|
|
2842
|
+
]);
|
|
2458
2843
|
const unknown = ids.filter((id) => !knownIds.has(id));
|
|
2459
2844
|
if (unknown.length > 0) {
|
|
2460
2845
|
throw new Error(
|
|
@@ -2463,7 +2848,7 @@ async function runUiAdd(options) {
|
|
|
2463
2848
|
}
|
|
2464
2849
|
const result = await installUiEntries({
|
|
2465
2850
|
projectRoot,
|
|
2466
|
-
manifest,
|
|
2851
|
+
manifest: effectiveManifest,
|
|
2467
2852
|
packageRoot,
|
|
2468
2853
|
aliases: uiCfg.aliases,
|
|
2469
2854
|
requested: ids,
|
|
@@ -2497,7 +2882,6 @@ async function runUiAdd(options) {
|
|
|
2497
2882
|
orderedIds: result.orderedIds,
|
|
2498
2883
|
written: result.written,
|
|
2499
2884
|
skipped: result.skipped,
|
|
2500
|
-
metaFiles: result.metaFiles,
|
|
2501
2885
|
npmDependencies: result.npmDependencies,
|
|
2502
2886
|
resources: result.resources
|
|
2503
2887
|
};
|
|
@@ -2512,46 +2896,48 @@ function mergeResources(prior, next) {
|
|
|
2512
2896
|
// src/commands/ui/add.ts
|
|
2513
2897
|
var addCommand2 = new Command15("add").description(
|
|
2514
2898
|
"\u5B89\u88C5\u4E00\u4E2A\u6216\u591A\u4E2A ui entry\uFF08\u6309 id\uFF0C\u81EA\u52A8\u5C55\u5F00 registryDependencies\uFF09"
|
|
2515
|
-
).argument("<ids...>", 'entry id \u5217\u8868\uFF0C\u5982 "button" "dialog"').option("--overwrite", "\u5373\u4F7F\u76EE\u6807\u6587\u4EF6\u5DF2\u5B58\u5728\u4E5F\u8986\u76D6\uFF08\u7ED5\u8FC7 frozen \u8DF3\u8FC7\uFF09").
|
|
2516
|
-
|
|
2517
|
-
|
|
2518
|
-
|
|
2519
|
-
|
|
2520
|
-
|
|
2521
|
-
|
|
2522
|
-
|
|
2523
|
-
|
|
2524
|
-
|
|
2525
|
-
|
|
2526
|
-
|
|
2527
|
-
|
|
2528
|
-
|
|
2529
|
-
|
|
2530
|
-
|
|
2531
|
-
|
|
2532
|
-
logger.info("");
|
|
2533
|
-
logger.info("Install npm dependencies in your project:");
|
|
2534
|
-
const installCmd = npmDeps.map(([name, range]) => `${name}@${range}`).join(" ");
|
|
2535
|
-
logger.info(` pnpm add ${installCmd}`);
|
|
2536
|
-
logger.info(` # or: npm install ${installCmd}`);
|
|
2537
|
-
}
|
|
2538
|
-
if (result.metaFiles.length > 0) {
|
|
2539
|
-
logger.info("");
|
|
2540
|
-
logger.info(
|
|
2541
|
-
"Component meta dropped under .teamix-evo/design/components/ (AI-readable)."
|
|
2899
|
+
).argument("<ids...>", 'entry id \u5217\u8868\uFF0C\u5982 "button" "dialog"').option("--overwrite", "\u5373\u4F7F\u76EE\u6807\u6587\u4EF6\u5DF2\u5B58\u5728\u4E5F\u8986\u76D6\uFF08\u7ED5\u8FC7 frozen \u8DF3\u8FC7\uFF09").option(
|
|
2900
|
+
"--include-deprecated",
|
|
2901
|
+
"\u5141\u8BB8\u5B89\u88C5\u5DF2\u5F52\u6863\u7684 deprecated entry\uFF08\u4EC5\u8FC1\u79FB / \u5BA1\u8BA1\u573A\u666F\uFF0CADR 0028\uFF09"
|
|
2902
|
+
).action(
|
|
2903
|
+
async (ids, opts) => {
|
|
2904
|
+
try {
|
|
2905
|
+
const ide = detectIde();
|
|
2906
|
+
const projectRoot = ide.getProjectRoot();
|
|
2907
|
+
logger.info(`Installing entries: ${ids.join(", ")}`);
|
|
2908
|
+
const result = await runUiAdd({
|
|
2909
|
+
projectRoot,
|
|
2910
|
+
ids,
|
|
2911
|
+
overwrite: opts.overwrite,
|
|
2912
|
+
includeDeprecated: opts.includeDeprecated
|
|
2913
|
+
});
|
|
2914
|
+
logger.success(
|
|
2915
|
+
`UI add complete: ${result.written} written, ${result.skipped} skipped.`
|
|
2542
2916
|
);
|
|
2917
|
+
logger.info("");
|
|
2918
|
+
logger.info(`Resolved order: ${result.orderedIds.join(" \u2192 ")}`);
|
|
2919
|
+
const npmDeps = Object.entries(result.npmDependencies);
|
|
2920
|
+
if (npmDeps.length > 0) {
|
|
2921
|
+
logger.info("");
|
|
2922
|
+
logger.info("Install npm dependencies in your project:");
|
|
2923
|
+
const installCmd = npmDeps.map(([name, range]) => `${name}@${range}`).join(" ");
|
|
2924
|
+
logger.info(` pnpm add ${installCmd}`);
|
|
2925
|
+
logger.info(` # or: npm install ${installCmd}`);
|
|
2926
|
+
}
|
|
2927
|
+
} catch (err) {
|
|
2928
|
+
const message = err.message;
|
|
2929
|
+
if (message.startsWith("UI not initialized")) {
|
|
2930
|
+
logger.error(
|
|
2931
|
+
"UI not initialized. Run `npx teamix-evo ui init` first."
|
|
2932
|
+
);
|
|
2933
|
+
} else {
|
|
2934
|
+
logger.error(`Failed to add ui entries: ${message}`);
|
|
2935
|
+
}
|
|
2936
|
+
logger.debug(err.stack ?? "");
|
|
2937
|
+
process.exitCode = 1;
|
|
2543
2938
|
}
|
|
2544
|
-
} catch (err) {
|
|
2545
|
-
const message = err.message;
|
|
2546
|
-
if (message.startsWith("UI not initialized")) {
|
|
2547
|
-
logger.error("UI not initialized. Run `npx teamix-evo ui init` first.");
|
|
2548
|
-
} else {
|
|
2549
|
-
logger.error(`Failed to add ui entries: ${message}`);
|
|
2550
|
-
}
|
|
2551
|
-
logger.debug(err.stack ?? "");
|
|
2552
|
-
process.exitCode = 1;
|
|
2553
2939
|
}
|
|
2554
|
-
|
|
2940
|
+
);
|
|
2555
2941
|
|
|
2556
2942
|
// src/commands/ui/list.ts
|
|
2557
2943
|
import { Command as Command16 } from "commander";
|
|
@@ -2559,7 +2945,7 @@ import { Command as Command16 } from "commander";
|
|
|
2559
2945
|
// src/core/ui-list.ts
|
|
2560
2946
|
var DEFAULT_UI_PACKAGE2 = "@teamix-evo/ui";
|
|
2561
2947
|
async function runUiList(options) {
|
|
2562
|
-
const { projectRoot, installedOnly } = options;
|
|
2948
|
+
const { projectRoot, installedOnly, includeDeprecated } = options;
|
|
2563
2949
|
const packageName = options.packageName ?? DEFAULT_UI_PACKAGE2;
|
|
2564
2950
|
const { manifest } = await loadUiData(packageName);
|
|
2565
2951
|
const installedManifest = await readInstalledManifest(projectRoot);
|
|
@@ -2571,65 +2957,77 @@ async function runUiList(options) {
|
|
|
2571
2957
|
const colon = r.id.indexOf(":");
|
|
2572
2958
|
installedIds.add(colon >= 0 ? r.id.slice(0, colon) : r.id);
|
|
2573
2959
|
}
|
|
2574
|
-
const
|
|
2575
|
-
|
|
2576
|
-
|
|
2577
|
-
|
|
2578
|
-
|
|
2960
|
+
const archived = manifest.deprecatedEntries ?? [];
|
|
2961
|
+
const pool = includeDeprecated ? [
|
|
2962
|
+
...manifest.entries.map((e) => ({ entry: e, deprecated: false })),
|
|
2963
|
+
...archived.map((e) => ({ entry: e, deprecated: true }))
|
|
2964
|
+
] : manifest.entries.map((e) => ({ entry: e, deprecated: false }));
|
|
2965
|
+
const entries = pool.filter(({ entry }) => !installedOnly || installedIds.has(entry.id)).map(({ entry, deprecated }) => ({
|
|
2966
|
+
id: entry.id,
|
|
2967
|
+
type: entry.type,
|
|
2968
|
+
description: entry.description,
|
|
2969
|
+
installed: installedIds.has(entry.id),
|
|
2970
|
+
deprecated
|
|
2579
2971
|
}));
|
|
2580
2972
|
return {
|
|
2581
2973
|
packageName,
|
|
2582
|
-
total: manifest.entries.length,
|
|
2974
|
+
total: manifest.entries.length + (includeDeprecated ? archived.length : 0),
|
|
2583
2975
|
installedCount: installedIds.size,
|
|
2584
2976
|
entries
|
|
2585
2977
|
};
|
|
2586
2978
|
}
|
|
2587
2979
|
|
|
2588
2980
|
// src/commands/ui/list.ts
|
|
2589
|
-
var listCommand3 = new Command16("list").description("\u5217\u51FA @teamix-evo/ui \u7684\u6240\u6709 entry \u53CA\u5DF2\u5B89\u88C5\u72B6\u6001").option("--installed", "\u4EC5\u5C55\u793A\u5DF2\u5B89\u88C5\u7684 entry").
|
|
2590
|
-
|
|
2591
|
-
|
|
2592
|
-
|
|
2593
|
-
|
|
2594
|
-
|
|
2595
|
-
|
|
2596
|
-
|
|
2597
|
-
|
|
2981
|
+
var listCommand3 = new Command16("list").description("\u5217\u51FA @teamix-evo/ui \u7684\u6240\u6709 entry \u53CA\u5DF2\u5B89\u88C5\u72B6\u6001").option("--installed", "\u4EC5\u5C55\u793A\u5DF2\u5B89\u88C5\u7684 entry").option(
|
|
2982
|
+
"--include-deprecated",
|
|
2983
|
+
"\u540C\u65F6\u5217\u51FA\u5DF2\u5F52\u6863\u7684 deprecated entry\uFF08\u9ED8\u8BA4\u9690\u85CF\uFF0CADR 0028\uFF09"
|
|
2984
|
+
).action(
|
|
2985
|
+
async (opts) => {
|
|
2986
|
+
try {
|
|
2987
|
+
const ide = detectIde();
|
|
2988
|
+
const projectRoot = ide.getProjectRoot();
|
|
2989
|
+
const { entries, total, installedCount } = await runUiList({
|
|
2990
|
+
projectRoot,
|
|
2991
|
+
installedOnly: opts.installed,
|
|
2992
|
+
includeDeprecated: opts.includeDeprecated
|
|
2993
|
+
});
|
|
2994
|
+
if (entries.length === 0) {
|
|
2995
|
+
logger.info(
|
|
2996
|
+
opts.installed ? "No ui entries installed." : "No ui entries available."
|
|
2997
|
+
);
|
|
2998
|
+
return;
|
|
2999
|
+
}
|
|
3000
|
+
const idWidth = Math.max(...entries.map((e) => e.id.length), 4);
|
|
3001
|
+
const typeWidth = Math.max(...entries.map((e) => e.type.length), 4);
|
|
2598
3002
|
logger.info(
|
|
2599
|
-
|
|
3003
|
+
`${"ID".padEnd(idWidth)} ${"TYPE".padEnd(
|
|
3004
|
+
typeWidth
|
|
3005
|
+
)} STATUS DESCRIPTION`
|
|
2600
3006
|
);
|
|
2601
|
-
return;
|
|
2602
|
-
}
|
|
2603
|
-
const idWidth = Math.max(...entries.map((e) => e.id.length), 4);
|
|
2604
|
-
const typeWidth = Math.max(...entries.map((e) => e.type.length), 4);
|
|
2605
|
-
logger.info(
|
|
2606
|
-
`${"ID".padEnd(idWidth)} ${"TYPE".padEnd(
|
|
2607
|
-
typeWidth
|
|
2608
|
-
)} STATUS DESCRIPTION`
|
|
2609
|
-
);
|
|
2610
|
-
logger.info(
|
|
2611
|
-
`${"\u2500".repeat(idWidth)} ${"\u2500".repeat(
|
|
2612
|
-
typeWidth
|
|
2613
|
-
)} \u2500\u2500\u2500\u2500\u2500\u2500\u2500 \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500`
|
|
2614
|
-
);
|
|
2615
|
-
for (const e of entries) {
|
|
2616
|
-
const status = e.installed ? "INSTALLED" : "\u2013";
|
|
2617
3007
|
logger.info(
|
|
2618
|
-
`${
|
|
3008
|
+
`${"\u2500".repeat(idWidth)} ${"\u2500".repeat(
|
|
2619
3009
|
typeWidth
|
|
2620
|
-
)}
|
|
3010
|
+
)} \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500`
|
|
2621
3011
|
);
|
|
3012
|
+
for (const e of entries) {
|
|
3013
|
+
const status = e.deprecated ? e.installed ? "INST/DEPR" : "DEPRECATED" : e.installed ? "INSTALLED" : "\u2013";
|
|
3014
|
+
logger.info(
|
|
3015
|
+
`${e.id.padEnd(idWidth)} ${e.type.padEnd(
|
|
3016
|
+
typeWidth
|
|
3017
|
+
)} ${status.padEnd(10)} ${e.description}`
|
|
3018
|
+
);
|
|
3019
|
+
}
|
|
3020
|
+
logger.info("");
|
|
3021
|
+
logger.info(
|
|
3022
|
+
`Total: ${total} entr${total === 1 ? "y" : "ies"}, ${installedCount} installed.`
|
|
3023
|
+
);
|
|
3024
|
+
} catch (err) {
|
|
3025
|
+
logger.error(`Failed to list ui entries: ${err.message}`);
|
|
3026
|
+
logger.debug(err.stack ?? "");
|
|
3027
|
+
process.exitCode = 1;
|
|
2622
3028
|
}
|
|
2623
|
-
logger.info("");
|
|
2624
|
-
logger.info(
|
|
2625
|
-
`Total: ${total} entr${total === 1 ? "y" : "ies"}, ${installedCount} installed.`
|
|
2626
|
-
);
|
|
2627
|
-
} catch (err) {
|
|
2628
|
-
logger.error(`Failed to list ui entries: ${err.message}`);
|
|
2629
|
-
logger.debug(err.stack ?? "");
|
|
2630
|
-
process.exitCode = 1;
|
|
2631
3029
|
}
|
|
2632
|
-
|
|
3030
|
+
);
|
|
2633
3031
|
|
|
2634
3032
|
// src/commands/ui/index.ts
|
|
2635
3033
|
var uiCommand = new Command17("ui").description(
|
|
@@ -2640,22 +3038,23 @@ uiCommand.addCommand(addCommand2);
|
|
|
2640
3038
|
uiCommand.addCommand(listCommand3);
|
|
2641
3039
|
|
|
2642
3040
|
// src/commands/biz-ui/index.ts
|
|
2643
|
-
import { Command as
|
|
3041
|
+
import { Command as Command21 } from "commander";
|
|
2644
3042
|
|
|
2645
3043
|
// src/commands/biz-ui/add.ts
|
|
2646
3044
|
import { Command as Command18 } from "commander";
|
|
2647
3045
|
|
|
2648
3046
|
// src/core/variant-ui-add.ts
|
|
2649
|
-
import * as
|
|
2650
|
-
import { createRequire as
|
|
3047
|
+
import * as path18 from "path";
|
|
3048
|
+
import { createRequire as createRequire6 } from "module";
|
|
2651
3049
|
import {
|
|
3050
|
+
loadUiPackageManifest as loadUiPackageManifest2,
|
|
2652
3051
|
loadVariantUiPackageCatalog,
|
|
2653
3052
|
loadVariantUiPackageManifest
|
|
2654
3053
|
} from "@teamix-evo/registry";
|
|
2655
|
-
var
|
|
3054
|
+
var require7 = createRequire6(import.meta.url);
|
|
2656
3055
|
function resolvePackageRoot3(packageName) {
|
|
2657
|
-
const pkgJsonPath =
|
|
2658
|
-
return
|
|
3056
|
+
const pkgJsonPath = require7.resolve(`${packageName}/package.json`);
|
|
3057
|
+
return path18.dirname(pkgJsonPath);
|
|
2659
3058
|
}
|
|
2660
3059
|
async function runVariantUiAdd(packageName, options) {
|
|
2661
3060
|
const { projectRoot, variant, ids, overwrite } = options;
|
|
@@ -2678,27 +3077,42 @@ async function runVariantUiAdd(packageName, options) {
|
|
|
2678
3077
|
`Variant "${variant}" not found in ${fullPackageName}. Known variants: ${known}. Hint: \`teamix-evo ${packageName} list-variants\` shows all.`
|
|
2679
3078
|
);
|
|
2680
3079
|
}
|
|
2681
|
-
const variantDir =
|
|
3080
|
+
const variantDir = path18.join(packageRoot, "variants", variant);
|
|
2682
3081
|
const variantManifest = await loadVariantUiPackageManifest(variantDir);
|
|
2683
3082
|
const knownIds = new Set(variantManifest.entries.map((e) => e.id));
|
|
2684
3083
|
const unknown = ids.filter((id) => !knownIds.has(id));
|
|
2685
3084
|
if (unknown.length > 0) {
|
|
2686
3085
|
throw new Error(
|
|
2687
|
-
`Unknown entry id(s) in ${packageName}#${variant}: ${unknown.map((s) => `"${s}"`).join(", ")}. Run \`teamix-evo ${packageName} list --variant ${variant}\`
|
|
3086
|
+
`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
3087
|
);
|
|
2689
3088
|
}
|
|
3089
|
+
const uiPackageRoot = resolvePackageRoot3("@teamix-evo/ui");
|
|
3090
|
+
const uiManifest = await loadUiPackageManifest2(uiPackageRoot);
|
|
3091
|
+
const entryPackageRoot = /* @__PURE__ */ new Map();
|
|
3092
|
+
const mergedEntries = [];
|
|
3093
|
+
for (const e of variantManifest.entries) {
|
|
3094
|
+
entryPackageRoot.set(e.id, variantDir);
|
|
3095
|
+
mergedEntries.push(e);
|
|
3096
|
+
}
|
|
3097
|
+
for (const e of uiManifest.entries) {
|
|
3098
|
+
if (entryPackageRoot.has(e.id)) continue;
|
|
3099
|
+
entryPackageRoot.set(e.id, uiPackageRoot);
|
|
3100
|
+
mergedEntries.push(e);
|
|
3101
|
+
}
|
|
2690
3102
|
const adaptedManifest = {
|
|
2691
3103
|
schemaVersion: 1,
|
|
2692
3104
|
package: "ui",
|
|
2693
3105
|
version: variantManifest.version,
|
|
2694
3106
|
engines: variantManifest.engines,
|
|
2695
|
-
entries:
|
|
3107
|
+
entries: mergedEntries
|
|
2696
3108
|
};
|
|
2697
3109
|
const result = await installUiEntries({
|
|
2698
3110
|
projectRoot,
|
|
2699
3111
|
manifest: adaptedManifest,
|
|
2700
3112
|
packageRoot: variantDir,
|
|
2701
|
-
//
|
|
3113
|
+
// default for variant entries
|
|
3114
|
+
entryPackageRoot,
|
|
3115
|
+
// ui entries resolve from uiPackageRoot
|
|
2702
3116
|
aliases: uiCfg.aliases,
|
|
2703
3117
|
requested: ids,
|
|
2704
3118
|
skipExisting: !overwrite
|
|
@@ -2730,7 +3144,6 @@ async function runVariantUiAdd(packageName, options) {
|
|
|
2730
3144
|
orderedIds: result.orderedIds,
|
|
2731
3145
|
written: result.written,
|
|
2732
3146
|
skipped: result.skipped,
|
|
2733
|
-
metaFiles: result.metaFiles,
|
|
2734
3147
|
npmDependencies: result.npmDependencies,
|
|
2735
3148
|
resources: result.resources
|
|
2736
3149
|
};
|
|
@@ -2767,6 +3180,36 @@ async function listBizUiVariants(packageRoot) {
|
|
|
2767
3180
|
async function listTemplatesVariants(packageRoot) {
|
|
2768
3181
|
return listVariantUi("templates", packageRoot);
|
|
2769
3182
|
}
|
|
3183
|
+
async function listVariantUiEntries(packageName, variant, packageRoot) {
|
|
3184
|
+
const fullPackageName = `@teamix-evo/${packageName}`;
|
|
3185
|
+
const root = packageRoot ?? resolvePackageRoot3(fullPackageName);
|
|
3186
|
+
const catalog = await loadVariantUiPackageCatalog(root);
|
|
3187
|
+
if (!catalog.variants.some((v) => v.name === variant)) {
|
|
3188
|
+
const known = catalog.variants.map((v) => v.name).join(", ");
|
|
3189
|
+
throw new Error(
|
|
3190
|
+
`Variant "${variant}" not found in ${fullPackageName}. Known: ${known}.`
|
|
3191
|
+
);
|
|
3192
|
+
}
|
|
3193
|
+
const variantDir = path18.join(root, "variants", variant);
|
|
3194
|
+
const variantManifest = await loadVariantUiPackageManifest(variantDir);
|
|
3195
|
+
return {
|
|
3196
|
+
packageName: fullPackageName,
|
|
3197
|
+
variant,
|
|
3198
|
+
entries: variantManifest.entries.map((e) => ({
|
|
3199
|
+
id: e.id,
|
|
3200
|
+
name: e.name,
|
|
3201
|
+
type: e.type,
|
|
3202
|
+
description: e.description,
|
|
3203
|
+
registryDependencies: e.registryDependencies ?? []
|
|
3204
|
+
}))
|
|
3205
|
+
};
|
|
3206
|
+
}
|
|
3207
|
+
async function listBizUiEntries(variant, packageRoot) {
|
|
3208
|
+
return listVariantUiEntries("biz-ui", variant, packageRoot);
|
|
3209
|
+
}
|
|
3210
|
+
async function listTemplatesEntries(variant, packageRoot) {
|
|
3211
|
+
return listVariantUiEntries("templates", variant, packageRoot);
|
|
3212
|
+
}
|
|
2770
3213
|
|
|
2771
3214
|
// src/commands/biz-ui/add.ts
|
|
2772
3215
|
var addCommand3 = new Command18("add").description(
|
|
@@ -2781,6 +3224,12 @@ var addCommand3 = new Command18("add").description(
|
|
|
2781
3224
|
}
|
|
2782
3225
|
const ide = detectIde();
|
|
2783
3226
|
const projectRoot = ide.getProjectRoot();
|
|
3227
|
+
const projectVariant = await readTokensVariant(projectRoot);
|
|
3228
|
+
if (projectVariant && projectVariant !== opts.variant) {
|
|
3229
|
+
throw new Error(
|
|
3230
|
+
`Variant mismatch \u2014 project is locked to "${projectVariant}" but you requested "${opts.variant}". Fix: run \`teamix-evo tokens uninstall -y\` then \`teamix-evo tokens init ${opts.variant}\` to switch, or re-run with \`--variant ${projectVariant}\` to install for the current variant.`
|
|
3231
|
+
);
|
|
3232
|
+
}
|
|
2784
3233
|
logger.info(
|
|
2785
3234
|
`Installing biz-ui entries from variant "${opts.variant}": ${ids.join(", ")}`
|
|
2786
3235
|
);
|
|
@@ -2791,7 +3240,7 @@ var addCommand3 = new Command18("add").description(
|
|
|
2791
3240
|
overwrite: opts.overwrite
|
|
2792
3241
|
});
|
|
2793
3242
|
logger.success(
|
|
2794
|
-
`biz-ui add complete: ${result.written} written, ${result.skipped} skipped
|
|
3243
|
+
`biz-ui add complete: ${result.written} written, ${result.skipped} skipped.`
|
|
2795
3244
|
);
|
|
2796
3245
|
logger.info("");
|
|
2797
3246
|
logger.info(`Variant: ${result.variant}`);
|
|
@@ -2811,9 +3260,35 @@ var addCommand3 = new Command18("add").description(
|
|
|
2811
3260
|
}
|
|
2812
3261
|
);
|
|
2813
3262
|
|
|
2814
|
-
// src/commands/biz-ui/list
|
|
3263
|
+
// src/commands/biz-ui/list.ts
|
|
2815
3264
|
import { Command as Command19 } from "commander";
|
|
2816
|
-
var
|
|
3265
|
+
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) => {
|
|
3266
|
+
try {
|
|
3267
|
+
const result = await listBizUiEntries(opts.variant);
|
|
3268
|
+
logger.info(`${result.packageName}#${result.variant} entries:`);
|
|
3269
|
+
logger.info("");
|
|
3270
|
+
if (result.entries.length === 0) {
|
|
3271
|
+
logger.info(" (no entries \u2014 variant skeleton, awaiting components)");
|
|
3272
|
+
return;
|
|
3273
|
+
}
|
|
3274
|
+
for (const e of result.entries) {
|
|
3275
|
+
const deps = e.registryDependencies.length ? ` [deps: ${e.registryDependencies.join(", ")}]` : "";
|
|
3276
|
+
logger.info(` ${e.id} (${e.type})${deps}`);
|
|
3277
|
+
if (e.description) logger.info(` ${e.description}`);
|
|
3278
|
+
logger.info("");
|
|
3279
|
+
}
|
|
3280
|
+
logger.info(
|
|
3281
|
+
`Install: teamix-evo biz-ui add <id> --variant ${result.variant}`
|
|
3282
|
+
);
|
|
3283
|
+
} catch (err) {
|
|
3284
|
+
logger.error(`Failed: ${err.message}`);
|
|
3285
|
+
process.exitCode = 1;
|
|
3286
|
+
}
|
|
3287
|
+
});
|
|
3288
|
+
|
|
3289
|
+
// src/commands/biz-ui/list-variants.ts
|
|
3290
|
+
import { Command as Command20 } from "commander";
|
|
3291
|
+
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
3292
|
try {
|
|
2818
3293
|
const result = await listBizUiVariants();
|
|
2819
3294
|
logger.info(`Available biz-ui variants in ${result.packageName}:`);
|
|
@@ -2835,18 +3310,19 @@ var listVariantsCommand2 = new Command19("list-variants").description("\u5217\u5
|
|
|
2835
3310
|
});
|
|
2836
3311
|
|
|
2837
3312
|
// src/commands/biz-ui/index.ts
|
|
2838
|
-
var bizUiCommand = new
|
|
3313
|
+
var bizUiCommand = new Command21("biz-ui").description(
|
|
2839
3314
|
"\u7BA1\u7406\u4E1A\u52A1 UI \u7EC4\u4EF6(\u53D8\u4F53\u611F\u77E5 \u2014 \u4E0E design / templates \u540C\u53D8\u4F53\u540D\u7A7A\u95F4)"
|
|
2840
3315
|
);
|
|
2841
3316
|
bizUiCommand.addCommand(addCommand3);
|
|
3317
|
+
bizUiCommand.addCommand(listCommand4);
|
|
2842
3318
|
bizUiCommand.addCommand(listVariantsCommand2);
|
|
2843
3319
|
|
|
2844
3320
|
// src/commands/templates/index.ts
|
|
2845
|
-
import { Command as
|
|
3321
|
+
import { Command as Command25 } from "commander";
|
|
2846
3322
|
|
|
2847
3323
|
// src/commands/templates/add.ts
|
|
2848
|
-
import { Command as
|
|
2849
|
-
var addCommand4 = new
|
|
3324
|
+
import { Command as Command22 } from "commander";
|
|
3325
|
+
var addCommand4 = new Command22("add").description(
|
|
2850
3326
|
"\u5B89\u88C5\u4E00\u4E2A\u6216\u591A\u4E2A\u9875\u9762\u6A21\u677F(\u6309 id,\u81EA\u52A8\u5C55\u5F00 ui \u5305\u7684 registryDependencies)"
|
|
2851
3327
|
).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
3328
|
async (ids, opts) => {
|
|
@@ -2858,6 +3334,12 @@ var addCommand4 = new Command21("add").description(
|
|
|
2858
3334
|
}
|
|
2859
3335
|
const ide = detectIde();
|
|
2860
3336
|
const projectRoot = ide.getProjectRoot();
|
|
3337
|
+
const projectVariant = await readTokensVariant(projectRoot);
|
|
3338
|
+
if (projectVariant && projectVariant !== opts.variant) {
|
|
3339
|
+
throw new Error(
|
|
3340
|
+
`Variant mismatch \u2014 project is locked to "${projectVariant}" but you requested "${opts.variant}". Fix: run \`teamix-evo tokens uninstall -y\` then \`teamix-evo tokens init ${opts.variant}\` to switch, or re-run with \`--variant ${projectVariant}\` to install for the current variant.`
|
|
3341
|
+
);
|
|
3342
|
+
}
|
|
2861
3343
|
logger.info(
|
|
2862
3344
|
`Installing templates from variant "${opts.variant}": ${ids.join(", ")}`
|
|
2863
3345
|
);
|
|
@@ -2868,7 +3350,7 @@ var addCommand4 = new Command21("add").description(
|
|
|
2868
3350
|
overwrite: opts.overwrite
|
|
2869
3351
|
});
|
|
2870
3352
|
logger.success(
|
|
2871
|
-
`templates add complete: ${result.written} written, ${result.skipped} skipped
|
|
3353
|
+
`templates add complete: ${result.written} written, ${result.skipped} skipped.`
|
|
2872
3354
|
);
|
|
2873
3355
|
logger.info("");
|
|
2874
3356
|
logger.info(`Variant: ${result.variant}`);
|
|
@@ -2888,9 +3370,35 @@ var addCommand4 = new Command21("add").description(
|
|
|
2888
3370
|
}
|
|
2889
3371
|
);
|
|
2890
3372
|
|
|
3373
|
+
// src/commands/templates/list.ts
|
|
3374
|
+
import { Command as Command23 } from "commander";
|
|
3375
|
+
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) => {
|
|
3376
|
+
try {
|
|
3377
|
+
const result = await listTemplatesEntries(opts.variant);
|
|
3378
|
+
logger.info(`${result.packageName}#${result.variant} entries:`);
|
|
3379
|
+
logger.info("");
|
|
3380
|
+
if (result.entries.length === 0) {
|
|
3381
|
+
logger.info(" (no entries \u2014 variant skeleton, awaiting templates)");
|
|
3382
|
+
return;
|
|
3383
|
+
}
|
|
3384
|
+
for (const e of result.entries) {
|
|
3385
|
+
const deps = e.registryDependencies.length ? ` [deps: ${e.registryDependencies.join(", ")}]` : "";
|
|
3386
|
+
logger.info(` ${e.id} (${e.type})${deps}`);
|
|
3387
|
+
if (e.description) logger.info(` ${e.description}`);
|
|
3388
|
+
logger.info("");
|
|
3389
|
+
}
|
|
3390
|
+
logger.info(
|
|
3391
|
+
`Install: teamix-evo templates add <id> --variant ${result.variant}`
|
|
3392
|
+
);
|
|
3393
|
+
} catch (err) {
|
|
3394
|
+
logger.error(`Failed: ${err.message}`);
|
|
3395
|
+
process.exitCode = 1;
|
|
3396
|
+
}
|
|
3397
|
+
});
|
|
3398
|
+
|
|
2891
3399
|
// src/commands/templates/list-variants.ts
|
|
2892
|
-
import { Command as
|
|
2893
|
-
var listVariantsCommand3 = new
|
|
3400
|
+
import { Command as Command24 } from "commander";
|
|
3401
|
+
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
3402
|
try {
|
|
2895
3403
|
const result = await listTemplatesVariants();
|
|
2896
3404
|
logger.info(`Available templates variants in ${result.packageName}:`);
|
|
@@ -2912,21 +3420,427 @@ var listVariantsCommand3 = new Command22("list-variants").description("\u5217\u5
|
|
|
2912
3420
|
});
|
|
2913
3421
|
|
|
2914
3422
|
// src/commands/templates/index.ts
|
|
2915
|
-
var templatesCommand = new
|
|
3423
|
+
var templatesCommand = new Command25("templates").description(
|
|
2916
3424
|
"\u7BA1\u7406\u9875\u9762\u6A21\u677F(\u53D8\u4F53\u611F\u77E5 \u2014 \u4E0E design / biz-ui \u540C\u53D8\u4F53\u540D\u7A7A\u95F4)"
|
|
2917
3425
|
);
|
|
2918
3426
|
templatesCommand.addCommand(addCommand4);
|
|
3427
|
+
templatesCommand.addCommand(listCommand5);
|
|
2919
3428
|
templatesCommand.addCommand(listVariantsCommand3);
|
|
2920
3429
|
|
|
3430
|
+
// src/commands/logs/index.ts
|
|
3431
|
+
import { Command as Command28 } from "commander";
|
|
3432
|
+
|
|
3433
|
+
// src/commands/logs/analyze.ts
|
|
3434
|
+
import { Command as Command26 } from "commander";
|
|
3435
|
+
import { readFileSync, readdirSync, existsSync as existsSync2, statSync } from "fs";
|
|
3436
|
+
import { resolve as resolve3, join as join17 } from "path";
|
|
3437
|
+
var DATE_DIR_RE = /^\d{4}-\d{2}-\d{2}$/;
|
|
3438
|
+
var logsAnalyzeCommand = new Command26("analyze").description(
|
|
3439
|
+
"\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"
|
|
3440
|
+
).option("--dir <path>", "log \u76EE\u5F55 (\u9ED8\u8BA4 <project>/.log/ai)").option(
|
|
3441
|
+
"--days <n>",
|
|
3442
|
+
"\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)"
|
|
3443
|
+
).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) => {
|
|
3444
|
+
const baseDir = resolve3(opts.dir ?? join17(process.cwd(), ".log", "ai"));
|
|
3445
|
+
if (!existsSync2(baseDir)) {
|
|
3446
|
+
logger.warn(`No log directory at ${baseDir}.`);
|
|
3447
|
+
logger.info(
|
|
3448
|
+
"\u8FD0\u884C vibe-logger hook \u89E6\u53D1\u540E\u4F1A\u5728\u6B64\u76EE\u5F55\u751F\u6210 JSONL \u2014 \u89C1 .claude/scripts/vibe-logger.mjs"
|
|
3449
|
+
);
|
|
3450
|
+
return;
|
|
3451
|
+
}
|
|
3452
|
+
const dayLimit = parseIntOrUndef(opts.days);
|
|
3453
|
+
const top = parseIntOrUndef(opts.top) ?? 10;
|
|
3454
|
+
const dayDirs = readdirSync(baseDir, { withFileTypes: true }).filter((e) => e.isDirectory() && DATE_DIR_RE.test(e.name)).map((e) => e.name).sort().reverse();
|
|
3455
|
+
const selected = dayLimit !== void 0 ? dayDirs.slice(0, dayLimit) : dayDirs;
|
|
3456
|
+
const records = [];
|
|
3457
|
+
for (const day of selected) {
|
|
3458
|
+
const dayPath = join17(baseDir, day);
|
|
3459
|
+
let entries;
|
|
3460
|
+
try {
|
|
3461
|
+
entries = readdirSync(dayPath);
|
|
3462
|
+
} catch {
|
|
3463
|
+
continue;
|
|
3464
|
+
}
|
|
3465
|
+
for (const entry of entries) {
|
|
3466
|
+
if (!entry.endsWith(".jsonl")) continue;
|
|
3467
|
+
const fp = join17(dayPath, entry);
|
|
3468
|
+
try {
|
|
3469
|
+
if (!statSync(fp).isFile()) continue;
|
|
3470
|
+
} catch {
|
|
3471
|
+
continue;
|
|
3472
|
+
}
|
|
3473
|
+
const text2 = readFileSync(fp, "utf8");
|
|
3474
|
+
for (const line of text2.split("\n")) {
|
|
3475
|
+
if (!line.trim()) continue;
|
|
3476
|
+
try {
|
|
3477
|
+
records.push(JSON.parse(line));
|
|
3478
|
+
} catch {
|
|
3479
|
+
}
|
|
3480
|
+
}
|
|
3481
|
+
}
|
|
3482
|
+
}
|
|
3483
|
+
const report = buildReport(records, top);
|
|
3484
|
+
if (opts.json) {
|
|
3485
|
+
process.stdout.write(JSON.stringify(report, null, 2) + "\n");
|
|
3486
|
+
return;
|
|
3487
|
+
}
|
|
3488
|
+
printReport(baseDir, selected.length, report);
|
|
3489
|
+
});
|
|
3490
|
+
function buildReport(records, top) {
|
|
3491
|
+
const byAgent = {};
|
|
3492
|
+
const byEvent = {};
|
|
3493
|
+
const tools = /* @__PURE__ */ new Map();
|
|
3494
|
+
const tags = /* @__PURE__ */ new Map();
|
|
3495
|
+
const mcp = /* @__PURE__ */ new Map();
|
|
3496
|
+
const sessions = /* @__PURE__ */ new Set();
|
|
3497
|
+
const filesTouched = /* @__PURE__ */ new Set();
|
|
3498
|
+
const errors = [];
|
|
3499
|
+
let from = null;
|
|
3500
|
+
let to = null;
|
|
3501
|
+
for (const r of records) {
|
|
3502
|
+
if (!from || r.ts < from) from = r.ts;
|
|
3503
|
+
if (!to || r.ts > to) to = r.ts;
|
|
3504
|
+
byAgent[r.agent] = (byAgent[r.agent] ?? 0) + 1;
|
|
3505
|
+
byEvent[r.event] = (byEvent[r.event] ?? 0) + 1;
|
|
3506
|
+
sessions.add(`${r.agent}::${r.session}`);
|
|
3507
|
+
if (r.file) filesTouched.add(r.file);
|
|
3508
|
+
if (r.tool) {
|
|
3509
|
+
tools.set(r.tool, (tools.get(r.tool) ?? 0) + 1);
|
|
3510
|
+
if (r.tool.startsWith("mcp__")) {
|
|
3511
|
+
const name = r.tool.replace(/^mcp__[^_]+__/, "");
|
|
3512
|
+
const slot = mcp.get(name) ?? { count: 0, keys: /* @__PURE__ */ new Set() };
|
|
3513
|
+
slot.count += 1;
|
|
3514
|
+
for (const k of r.mcpArgs ?? []) slot.keys.add(k);
|
|
3515
|
+
mcp.set(name, slot);
|
|
3516
|
+
}
|
|
3517
|
+
}
|
|
3518
|
+
for (const tag of r.tags ?? []) {
|
|
3519
|
+
tags.set(tag, (tags.get(tag) ?? 0) + 1);
|
|
3520
|
+
}
|
|
3521
|
+
if (r.error) {
|
|
3522
|
+
errors.push({
|
|
3523
|
+
ts: r.ts,
|
|
3524
|
+
tool: r.tool,
|
|
3525
|
+
file: r.file,
|
|
3526
|
+
session: r.session
|
|
3527
|
+
});
|
|
3528
|
+
}
|
|
3529
|
+
}
|
|
3530
|
+
const topTools = sortAndSlice(tools, top).map(([tool, count]) => ({
|
|
3531
|
+
tool,
|
|
3532
|
+
count
|
|
3533
|
+
}));
|
|
3534
|
+
const topTags = sortAndSlice(tags, top).map(([tag, count]) => ({
|
|
3535
|
+
tag,
|
|
3536
|
+
count
|
|
3537
|
+
}));
|
|
3538
|
+
const topMcp = [...mcp.entries()].sort((a, b) => b[1].count - a[1].count).slice(0, top).map(([name, v]) => ({
|
|
3539
|
+
name,
|
|
3540
|
+
count: v.count,
|
|
3541
|
+
argKeys: [...v.keys].sort()
|
|
3542
|
+
}));
|
|
3543
|
+
const recentErrors = errors.slice(-10);
|
|
3544
|
+
return {
|
|
3545
|
+
range: { from, to },
|
|
3546
|
+
totals: {
|
|
3547
|
+
records: records.length,
|
|
3548
|
+
sessions: sessions.size,
|
|
3549
|
+
errors: errors.length,
|
|
3550
|
+
files: filesTouched.size
|
|
3551
|
+
},
|
|
3552
|
+
byAgent,
|
|
3553
|
+
byEvent,
|
|
3554
|
+
topTools,
|
|
3555
|
+
topTags,
|
|
3556
|
+
topMcp,
|
|
3557
|
+
recentErrors
|
|
3558
|
+
};
|
|
3559
|
+
}
|
|
3560
|
+
function sortAndSlice(m, top) {
|
|
3561
|
+
return [...m.entries()].sort((a, b) => b[1] - a[1]).slice(0, top);
|
|
3562
|
+
}
|
|
3563
|
+
function printReport(baseDir, dayCount, r) {
|
|
3564
|
+
logger.info(`vibe-logger \u5206\u6790\u62A5\u544A`);
|
|
3565
|
+
logger.info(` \u76EE\u5F55: ${baseDir}`);
|
|
3566
|
+
logger.info(` \u5929\u6570: ${dayCount}`);
|
|
3567
|
+
logger.info(` \u65F6\u95F4: ${r.range.from ?? "-"} \u2192 ${r.range.to ?? "-"}`);
|
|
3568
|
+
logger.info("");
|
|
3569
|
+
logger.info(
|
|
3570
|
+
`Totals records=${r.totals.records} sessions=${r.totals.sessions} errors=${r.totals.errors} files=${r.totals.files}`
|
|
3571
|
+
);
|
|
3572
|
+
logger.info(`By agent ${formatKv(r.byAgent)}`);
|
|
3573
|
+
logger.info(`By event ${formatKv(r.byEvent)}`);
|
|
3574
|
+
logger.info("");
|
|
3575
|
+
logger.info("Top tools:");
|
|
3576
|
+
for (const { tool, count } of r.topTools) {
|
|
3577
|
+
logger.info(` ${pad(count, 5)} ${tool}`);
|
|
3578
|
+
}
|
|
3579
|
+
if (r.topTags.length) {
|
|
3580
|
+
logger.info("");
|
|
3581
|
+
logger.info("Top package tags (which package the AI touched):");
|
|
3582
|
+
for (const { tag, count } of r.topTags) {
|
|
3583
|
+
logger.info(` ${pad(count, 5)} ${tag}`);
|
|
3584
|
+
}
|
|
3585
|
+
}
|
|
3586
|
+
if (r.topMcp.length) {
|
|
3587
|
+
logger.info("");
|
|
3588
|
+
logger.info("Top MCP tools:");
|
|
3589
|
+
for (const { name, count, argKeys } of r.topMcp) {
|
|
3590
|
+
const keys = argKeys.length ? ` args: ${argKeys.join(", ")}` : "";
|
|
3591
|
+
logger.info(` ${pad(count, 5)} ${name}${keys}`);
|
|
3592
|
+
}
|
|
3593
|
+
}
|
|
3594
|
+
if (r.recentErrors.length) {
|
|
3595
|
+
logger.info("");
|
|
3596
|
+
logger.info(`Recent errors (last ${r.recentErrors.length}):`);
|
|
3597
|
+
for (const e of r.recentErrors) {
|
|
3598
|
+
logger.info(
|
|
3599
|
+
` ${e.ts} session=${e.session} tool=${e.tool ?? "-"} file=${e.file ?? "-"}`
|
|
3600
|
+
);
|
|
3601
|
+
}
|
|
3602
|
+
}
|
|
3603
|
+
}
|
|
3604
|
+
function formatKv(o) {
|
|
3605
|
+
return Object.entries(o).sort((a, b) => b[1] - a[1]).map(([k, v]) => `${k}=${v}`).join(" ");
|
|
3606
|
+
}
|
|
3607
|
+
function pad(n, width) {
|
|
3608
|
+
const s = String(n);
|
|
3609
|
+
return s.length >= width ? s : " ".repeat(width - s.length) + s;
|
|
3610
|
+
}
|
|
3611
|
+
function parseIntOrUndef(v) {
|
|
3612
|
+
if (v === void 0) return void 0;
|
|
3613
|
+
const n = Number.parseInt(v, 10);
|
|
3614
|
+
return Number.isFinite(n) && n > 0 ? n : void 0;
|
|
3615
|
+
}
|
|
3616
|
+
|
|
3617
|
+
// src/commands/logs/trace.ts
|
|
3618
|
+
import { Command as Command27 } from "commander";
|
|
3619
|
+
import { readFileSync as readFileSync2, readdirSync as readdirSync2, existsSync as existsSync3, statSync as statSync2 } from "fs";
|
|
3620
|
+
import { resolve as resolve4, join as join18 } from "path";
|
|
3621
|
+
var DATE_DIR_RE2 = /^\d{4}-\d{2}-\d{2}$/;
|
|
3622
|
+
var logsTraceCommand = new Command27("trace").description(
|
|
3623
|
+
"\u6309\u4F1A\u8BDD\u8FD8\u539F AI \u8C03\u7528\u94FE\u8DEF:\u4ECE\u7528\u6237 prompt \u8D77\u59CB,\u4E32\u8054\u540E\u7EED PreToolUse/PostToolUse \u76F4\u5230\u4E0B\u4E00\u4E2A prompt \u6216 Stop"
|
|
3624
|
+
).option("--prompt <keyword>", "\u6309\u7528\u6237\u8F93\u5165\u5173\u952E\u5B57\u8FC7\u6EE4 (\u5B50\u4E32\u5339\u914D,\u4E0D\u533A\u5206\u5927\u5C0F\u5199)").option("--session <id>", "\u6307\u5B9A\u4F1A\u8BDD ID (\u524D\u7F00\u5339\u914D)").option("--days <n>", "\u53EA\u770B\u6700\u8FD1 N \u5929\u7684\u76EE\u5F55 (\u9ED8\u8BA4 7)", "7").option("--dir <path>", "log \u76EE\u5F55 (\u9ED8\u8BA4 <project>/.log/ai)").option("--json", "\u4EE5 JSON \u8F93\u51FA (CI/\u5DE5\u5177\u53CB\u597D)").action((opts) => {
|
|
3625
|
+
const baseDir = resolve4(opts.dir ?? join18(process.cwd(), ".log", "ai"));
|
|
3626
|
+
if (!existsSync3(baseDir)) {
|
|
3627
|
+
logger.warn(`No log directory at ${baseDir}.`);
|
|
3628
|
+
logger.info(
|
|
3629
|
+
"\u8FD0\u884C vibe-logger hook \u89E6\u53D1\u540E\u4F1A\u5728\u6B64\u76EE\u5F55\u751F\u6210 JSONL \u2014 \u89C1 .claude/scripts/vibe-logger.mjs"
|
|
3630
|
+
);
|
|
3631
|
+
return;
|
|
3632
|
+
}
|
|
3633
|
+
const dayLimit = parseIntOrUndef2(opts.days) ?? 7;
|
|
3634
|
+
const records = readRecords(baseDir, dayLimit);
|
|
3635
|
+
const report = buildTrace(records, {
|
|
3636
|
+
prompt: opts.prompt,
|
|
3637
|
+
session: opts.session
|
|
3638
|
+
});
|
|
3639
|
+
if (opts.json) {
|
|
3640
|
+
process.stdout.write(JSON.stringify(report, null, 2) + "\n");
|
|
3641
|
+
return;
|
|
3642
|
+
}
|
|
3643
|
+
printTrace(baseDir, report);
|
|
3644
|
+
});
|
|
3645
|
+
function readRecords(baseDir, dayLimit) {
|
|
3646
|
+
const dayDirs = readdirSync2(baseDir, { withFileTypes: true }).filter((e) => e.isDirectory() && DATE_DIR_RE2.test(e.name)).map((e) => e.name).sort().reverse();
|
|
3647
|
+
const selected = dayDirs.slice(0, dayLimit);
|
|
3648
|
+
const records = [];
|
|
3649
|
+
for (const day of selected) {
|
|
3650
|
+
const dayPath = join18(baseDir, day);
|
|
3651
|
+
let entries;
|
|
3652
|
+
try {
|
|
3653
|
+
entries = readdirSync2(dayPath);
|
|
3654
|
+
} catch {
|
|
3655
|
+
continue;
|
|
3656
|
+
}
|
|
3657
|
+
for (const entry of entries) {
|
|
3658
|
+
if (!entry.endsWith(".jsonl")) continue;
|
|
3659
|
+
const fp = join18(dayPath, entry);
|
|
3660
|
+
try {
|
|
3661
|
+
if (!statSync2(fp).isFile()) continue;
|
|
3662
|
+
} catch {
|
|
3663
|
+
continue;
|
|
3664
|
+
}
|
|
3665
|
+
const text2 = readFileSync2(fp, "utf8");
|
|
3666
|
+
for (const line of text2.split("\n")) {
|
|
3667
|
+
if (!line.trim()) continue;
|
|
3668
|
+
try {
|
|
3669
|
+
records.push(JSON.parse(line));
|
|
3670
|
+
} catch {
|
|
3671
|
+
}
|
|
3672
|
+
}
|
|
3673
|
+
}
|
|
3674
|
+
}
|
|
3675
|
+
return records;
|
|
3676
|
+
}
|
|
3677
|
+
function buildTrace(records, filter = {}) {
|
|
3678
|
+
const groups = /* @__PURE__ */ new Map();
|
|
3679
|
+
for (const r of records) {
|
|
3680
|
+
if (!r.session) continue;
|
|
3681
|
+
const arr = groups.get(r.session) ?? [];
|
|
3682
|
+
arr.push(r);
|
|
3683
|
+
groups.set(r.session, arr);
|
|
3684
|
+
}
|
|
3685
|
+
const promptNeedle = filter.prompt?.toLowerCase();
|
|
3686
|
+
const sessionPrefix = filter.session;
|
|
3687
|
+
const sessions = [];
|
|
3688
|
+
for (const [sessionId, items] of groups.entries()) {
|
|
3689
|
+
if (sessionPrefix && !sessionId.startsWith(sessionPrefix)) continue;
|
|
3690
|
+
items.sort((a, b) => a.ts < b.ts ? -1 : a.ts > b.ts ? 1 : 0);
|
|
3691
|
+
const chains = [];
|
|
3692
|
+
let current = null;
|
|
3693
|
+
let pending = /* @__PURE__ */ new Map();
|
|
3694
|
+
const closeCurrent = () => {
|
|
3695
|
+
if (current) chains.push(current);
|
|
3696
|
+
current = null;
|
|
3697
|
+
pending = /* @__PURE__ */ new Map();
|
|
3698
|
+
};
|
|
3699
|
+
for (const r of items) {
|
|
3700
|
+
if (r.event === "UserPromptSubmit") {
|
|
3701
|
+
if (current) closeCurrent();
|
|
3702
|
+
current = { prompt: r.prompt ?? "", promptTs: r.ts, steps: [] };
|
|
3703
|
+
pending = /* @__PURE__ */ new Map();
|
|
3704
|
+
continue;
|
|
3705
|
+
}
|
|
3706
|
+
if (r.event === "Stop") {
|
|
3707
|
+
if (current) closeCurrent();
|
|
3708
|
+
continue;
|
|
3709
|
+
}
|
|
3710
|
+
if (!current) continue;
|
|
3711
|
+
if (r.event === "PreToolUse") {
|
|
3712
|
+
const idx = current.steps.length;
|
|
3713
|
+
current.steps.push({
|
|
3714
|
+
ts: r.ts,
|
|
3715
|
+
event: "PreToolUse",
|
|
3716
|
+
tool: r.tool,
|
|
3717
|
+
file: r.file,
|
|
3718
|
+
tags: r.tags,
|
|
3719
|
+
duration_ms: r.duration_ms,
|
|
3720
|
+
error: r.error ?? false
|
|
3721
|
+
});
|
|
3722
|
+
if (r.tool) {
|
|
3723
|
+
const list = pending.get(r.tool) ?? [];
|
|
3724
|
+
list.push(idx);
|
|
3725
|
+
pending.set(r.tool, list);
|
|
3726
|
+
}
|
|
3727
|
+
} else if (r.event === "PostToolUse") {
|
|
3728
|
+
const list = r.tool ? pending.get(r.tool) : void 0;
|
|
3729
|
+
if (list && list.length > 0) {
|
|
3730
|
+
const idx = list.shift();
|
|
3731
|
+
if (list.length === 0 && r.tool) pending.delete(r.tool);
|
|
3732
|
+
const step = current.steps[idx];
|
|
3733
|
+
if (r.duration_ms !== void 0) step.duration_ms = r.duration_ms;
|
|
3734
|
+
if (r.error !== void 0) step.error = r.error;
|
|
3735
|
+
if (!step.file && r.file) step.file = r.file;
|
|
3736
|
+
if ((!step.tags || step.tags.length === 0) && r.tags)
|
|
3737
|
+
step.tags = r.tags;
|
|
3738
|
+
} else {
|
|
3739
|
+
current.steps.push({
|
|
3740
|
+
ts: r.ts,
|
|
3741
|
+
event: "PostToolUse",
|
|
3742
|
+
tool: r.tool,
|
|
3743
|
+
file: r.file,
|
|
3744
|
+
tags: r.tags,
|
|
3745
|
+
duration_ms: r.duration_ms,
|
|
3746
|
+
error: r.error ?? false
|
|
3747
|
+
});
|
|
3748
|
+
}
|
|
3749
|
+
}
|
|
3750
|
+
}
|
|
3751
|
+
if (current) closeCurrent();
|
|
3752
|
+
const filteredChains = promptNeedle ? chains.filter((c) => c.prompt.toLowerCase().includes(promptNeedle)) : chains;
|
|
3753
|
+
if (filteredChains.length === 0) continue;
|
|
3754
|
+
sessions.push({
|
|
3755
|
+
id: sessionId,
|
|
3756
|
+
agent: items[0]?.agent ?? "unknown",
|
|
3757
|
+
chains: filteredChains
|
|
3758
|
+
});
|
|
3759
|
+
}
|
|
3760
|
+
sessions.sort((a, b) => {
|
|
3761
|
+
const ta = a.chains[0]?.promptTs ?? "";
|
|
3762
|
+
const tb = b.chains[0]?.promptTs ?? "";
|
|
3763
|
+
return tb.localeCompare(ta);
|
|
3764
|
+
});
|
|
3765
|
+
return { sessions };
|
|
3766
|
+
}
|
|
3767
|
+
function printTrace(baseDir, r) {
|
|
3768
|
+
logger.info(`vibe-logger \u94FE\u8DEF\u8FFD\u8E2A`);
|
|
3769
|
+
logger.info(` \u76EE\u5F55: ${baseDir}`);
|
|
3770
|
+
logger.info(` \u4F1A\u8BDD: ${r.sessions.length}`);
|
|
3771
|
+
logger.info("");
|
|
3772
|
+
if (r.sessions.length === 0) {
|
|
3773
|
+
logger.info("\u672A\u627E\u5230\u5339\u914D\u7684\u4F1A\u8BDD/\u63D0\u793A\u3002");
|
|
3774
|
+
return;
|
|
3775
|
+
}
|
|
3776
|
+
for (const s of r.sessions) {
|
|
3777
|
+
logger.info(`\u2501\u2501\u2501 Session: ${s.id} (${s.agent}) \u2501\u2501\u2501`);
|
|
3778
|
+
logger.info("");
|
|
3779
|
+
for (const c of s.chains) {
|
|
3780
|
+
logger.info(
|
|
3781
|
+
`[${formatTime(c.promptTs)}] \u{1F4AC} Prompt: ${quote(truncate(c.prompt, 200))}`
|
|
3782
|
+
);
|
|
3783
|
+
for (const step of c.steps) {
|
|
3784
|
+
logger.info(` ${formatStep(step)}`);
|
|
3785
|
+
}
|
|
3786
|
+
logger.info("");
|
|
3787
|
+
}
|
|
3788
|
+
}
|
|
3789
|
+
}
|
|
3790
|
+
function formatStep(s) {
|
|
3791
|
+
const ts = `[${formatTime(s.ts)}]`;
|
|
3792
|
+
const isEdit = s.tool === "Edit" || s.tool === "Write" || s.tool === "MultiEdit" || s.tool === "create_file" || s.tool === "search_replace";
|
|
3793
|
+
const icon = isEdit ? "\u{1F4DD}" : "\u{1F527}";
|
|
3794
|
+
const head = isEdit && s.file ? `${s.tool ?? "?"} \u2192 ${s.file}` : s.tool ?? s.event ?? "?";
|
|
3795
|
+
const dur = s.duration_ms !== void 0 ? `${s.duration_ms}ms` : "";
|
|
3796
|
+
const tags = s.tags && s.tags.length ? `[${s.tags.join(",")}]` : "";
|
|
3797
|
+
const err = s.error ? "\u274C" : "";
|
|
3798
|
+
return [ts, icon, padRight(head, 40), padLeft(dur, 6), tags, err].filter((x) => x !== "").join(" ");
|
|
3799
|
+
}
|
|
3800
|
+
function formatTime(ts) {
|
|
3801
|
+
const d = new Date(ts);
|
|
3802
|
+
if (Number.isNaN(d.getTime())) return ts;
|
|
3803
|
+
const hh = String(d.getUTCHours()).padStart(2, "0");
|
|
3804
|
+
const mm = String(d.getUTCMinutes()).padStart(2, "0");
|
|
3805
|
+
const ss = String(d.getUTCSeconds()).padStart(2, "0");
|
|
3806
|
+
return `${hh}:${mm}:${ss}`;
|
|
3807
|
+
}
|
|
3808
|
+
function quote(s) {
|
|
3809
|
+
return `"${s.replace(/"/g, '\\"')}"`;
|
|
3810
|
+
}
|
|
3811
|
+
function truncate(s, n) {
|
|
3812
|
+
if (s.length <= n) return s;
|
|
3813
|
+
return s.slice(0, n) + "\u2026";
|
|
3814
|
+
}
|
|
3815
|
+
function padRight(s, n) {
|
|
3816
|
+
return s.length >= n ? s : s + " ".repeat(n - s.length);
|
|
3817
|
+
}
|
|
3818
|
+
function padLeft(s, n) {
|
|
3819
|
+
return s.length >= n ? s : " ".repeat(n - s.length) + s;
|
|
3820
|
+
}
|
|
3821
|
+
function parseIntOrUndef2(v) {
|
|
3822
|
+
if (v === void 0) return void 0;
|
|
3823
|
+
const n = Number.parseInt(v, 10);
|
|
3824
|
+
return Number.isFinite(n) && n > 0 ? n : void 0;
|
|
3825
|
+
}
|
|
3826
|
+
|
|
3827
|
+
// src/commands/logs/index.ts
|
|
3828
|
+
var logsCommand = new Command28("logs").description(
|
|
3829
|
+
"\u67E5\u8BE2 vibe-logger \u8F93\u51FA (.log/ai/**/*.jsonl) \u2014 AI \u8C03\u7528\u94FE\u5206\u6790"
|
|
3830
|
+
);
|
|
3831
|
+
logsCommand.addCommand(logsAnalyzeCommand);
|
|
3832
|
+
logsCommand.addCommand(logsTraceCommand);
|
|
3833
|
+
|
|
2921
3834
|
// src/index.ts
|
|
2922
|
-
var
|
|
2923
|
-
var { version } =
|
|
2924
|
-
var program = new
|
|
3835
|
+
var require8 = createRequire7(import.meta.url);
|
|
3836
|
+
var { version } = require8("../package.json");
|
|
3837
|
+
var program = new Command29();
|
|
2925
3838
|
program.name("teamix-evo").description("Where ideas evolve. \u2014 AI Coding \u5957\u4EF6").version(version);
|
|
2926
|
-
program.addCommand(
|
|
3839
|
+
program.addCommand(tokensCommand);
|
|
2927
3840
|
program.addCommand(skillsCommand);
|
|
2928
3841
|
program.addCommand(uiCommand);
|
|
2929
3842
|
program.addCommand(bizUiCommand);
|
|
2930
3843
|
program.addCommand(templatesCommand);
|
|
3844
|
+
program.addCommand(logsCommand);
|
|
2931
3845
|
program.parse();
|
|
2932
3846
|
//# sourceMappingURL=index.js.map
|