ux-toolkit 0.4.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/marketplace.json +11 -0
- package/.claude-plugin/plugin.json +23 -0
- package/dist/cli.js +739 -116
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +353 -101
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +117 -6
- package/dist/index.d.ts +117 -6
- package/dist/index.js +342 -102
- package/dist/index.js.map +1 -1
- package/package.json +5 -2
package/dist/cli.js
CHANGED
|
@@ -1,28 +1,106 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
3
|
+
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
4
|
+
}) : x)(function(x) {
|
|
5
|
+
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
6
|
+
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
7
|
+
});
|
|
2
8
|
|
|
3
9
|
// src/cli.ts
|
|
4
10
|
import { parseArgs } from "util";
|
|
11
|
+
import { createInterface } from "readline";
|
|
5
12
|
|
|
6
13
|
// src/installer.ts
|
|
7
|
-
import { existsSync, mkdirSync, cpSync, readdirSync } from "fs";
|
|
14
|
+
import { existsSync as existsSync2, mkdirSync, cpSync, readdirSync, rmSync, statSync } from "fs";
|
|
8
15
|
import { join as join2, dirname as dirname2 } from "path";
|
|
9
16
|
|
|
10
17
|
// src/paths.ts
|
|
11
|
-
import { homedir } from "os";
|
|
12
|
-
import { join, dirname } from "path";
|
|
18
|
+
import { homedir, platform } from "os";
|
|
19
|
+
import { join, dirname, resolve } from "path";
|
|
13
20
|
import { fileURLToPath } from "url";
|
|
14
|
-
|
|
21
|
+
import { existsSync } from "fs";
|
|
22
|
+
function getCurrentDirname() {
|
|
23
|
+
try {
|
|
24
|
+
if (import.meta?.url) {
|
|
25
|
+
return dirname(fileURLToPath(import.meta.url));
|
|
26
|
+
}
|
|
27
|
+
} catch {
|
|
28
|
+
}
|
|
29
|
+
try {
|
|
30
|
+
const packageJsonPath = __require.resolve("ux-toolkit/package.json");
|
|
31
|
+
return join(dirname(packageJsonPath), "dist");
|
|
32
|
+
} catch {
|
|
33
|
+
}
|
|
34
|
+
const cwd = process.cwd();
|
|
35
|
+
try {
|
|
36
|
+
const fs = __require("fs");
|
|
37
|
+
const pkgPath = resolve(cwd, "package.json");
|
|
38
|
+
if (fs.existsSync(pkgPath)) {
|
|
39
|
+
const pkg = __require(pkgPath);
|
|
40
|
+
if (pkg.name === "ux-toolkit") {
|
|
41
|
+
return resolve(cwd, "dist");
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
} catch {
|
|
45
|
+
}
|
|
46
|
+
return resolve(cwd, "dist");
|
|
47
|
+
}
|
|
48
|
+
var currentDirname = getCurrentDirname();
|
|
15
49
|
function getPackageRoot() {
|
|
16
|
-
return join(
|
|
50
|
+
return join(currentDirname, "..");
|
|
17
51
|
}
|
|
18
52
|
function getGlobalConfigDir() {
|
|
19
|
-
|
|
53
|
+
if (process.env.UX_TOOLKIT_CONFIG_DIR) {
|
|
54
|
+
return resolve(process.env.UX_TOOLKIT_CONFIG_DIR);
|
|
55
|
+
}
|
|
56
|
+
if (process.env.OPENCODE_CONFIG_DIR) {
|
|
57
|
+
return resolve(process.env.OPENCODE_CONFIG_DIR);
|
|
58
|
+
}
|
|
59
|
+
const home = homedir();
|
|
60
|
+
const currentPlatform = platform();
|
|
61
|
+
if (currentPlatform === "linux" && process.env.XDG_CONFIG_HOME) {
|
|
62
|
+
return join(process.env.XDG_CONFIG_HOME, "opencode");
|
|
63
|
+
}
|
|
64
|
+
return join(home, ".config", "opencode");
|
|
65
|
+
}
|
|
66
|
+
function isOpenCodeInstalled() {
|
|
67
|
+
return existsSync(getGlobalConfigDir());
|
|
68
|
+
}
|
|
69
|
+
function getClaudeConfigDir() {
|
|
70
|
+
if (process.env.CLAUDE_CONFIG_DIR) {
|
|
71
|
+
return resolve(process.env.CLAUDE_CONFIG_DIR);
|
|
72
|
+
}
|
|
73
|
+
return join(homedir(), ".claude");
|
|
74
|
+
}
|
|
75
|
+
function isClaudeInstalled() {
|
|
76
|
+
return existsSync(getClaudeConfigDir());
|
|
20
77
|
}
|
|
21
|
-
function
|
|
22
|
-
|
|
78
|
+
function getPlatformInfo() {
|
|
79
|
+
const opencodeDir = getGlobalConfigDir();
|
|
80
|
+
const claudeDir = getClaudeConfigDir();
|
|
81
|
+
return {
|
|
82
|
+
platform: platform(),
|
|
83
|
+
opencode: {
|
|
84
|
+
configDir: opencodeDir,
|
|
85
|
+
exists: existsSync(opencodeDir)
|
|
86
|
+
},
|
|
87
|
+
claude: {
|
|
88
|
+
configDir: claudeDir,
|
|
89
|
+
exists: existsSync(claudeDir)
|
|
90
|
+
}
|
|
91
|
+
};
|
|
23
92
|
}
|
|
24
|
-
function
|
|
25
|
-
const
|
|
93
|
+
function getProjectConfigDir(projectRoot = process.cwd(), target = "opencode") {
|
|
94
|
+
const dirName = target === "claude" ? ".claude" : ".opencode";
|
|
95
|
+
return join(projectRoot, dirName);
|
|
96
|
+
}
|
|
97
|
+
function getDestinationPaths(global, projectRoot, target = "opencode") {
|
|
98
|
+
let baseDir;
|
|
99
|
+
if (global) {
|
|
100
|
+
baseDir = target === "claude" ? getClaudeConfigDir() : getGlobalConfigDir();
|
|
101
|
+
} else {
|
|
102
|
+
baseDir = getProjectConfigDir(projectRoot, target);
|
|
103
|
+
}
|
|
26
104
|
return {
|
|
27
105
|
skills: join(baseDir, "skills"),
|
|
28
106
|
agents: join(baseDir, "agents"),
|
|
@@ -30,97 +108,6 @@ function getDestinationPaths(global, projectRoot) {
|
|
|
30
108
|
};
|
|
31
109
|
}
|
|
32
110
|
|
|
33
|
-
// src/installer.ts
|
|
34
|
-
async function install(options = {}) {
|
|
35
|
-
const {
|
|
36
|
-
global: isGlobal = false,
|
|
37
|
-
projectRoot = process.cwd(),
|
|
38
|
-
categories = ["skills", "agents", "commands"],
|
|
39
|
-
force = false,
|
|
40
|
-
verbose = false
|
|
41
|
-
} = options;
|
|
42
|
-
const result = {
|
|
43
|
-
installed: [],
|
|
44
|
-
skipped: [],
|
|
45
|
-
errors: []
|
|
46
|
-
};
|
|
47
|
-
const packageRoot = getPackageRoot();
|
|
48
|
-
const destinations = getDestinationPaths(isGlobal, projectRoot);
|
|
49
|
-
const log = (msg) => {
|
|
50
|
-
if (verbose) console.log(msg);
|
|
51
|
-
};
|
|
52
|
-
if (categories.includes("skills")) {
|
|
53
|
-
const skillsDir = join2(packageRoot, "skills");
|
|
54
|
-
if (existsSync(skillsDir)) {
|
|
55
|
-
const skills = readdirSync(skillsDir, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name);
|
|
56
|
-
for (const skill of skills) {
|
|
57
|
-
const src = join2(skillsDir, skill);
|
|
58
|
-
const dest = join2(destinations.skills, skill);
|
|
59
|
-
try {
|
|
60
|
-
if (existsSync(dest) && !force) {
|
|
61
|
-
result.skipped.push(`skill:${skill}`);
|
|
62
|
-
log(`Skipped skill/${skill} (already exists)`);
|
|
63
|
-
continue;
|
|
64
|
-
}
|
|
65
|
-
mkdirSync(dirname2(dest), { recursive: true });
|
|
66
|
-
cpSync(src, dest, { recursive: true });
|
|
67
|
-
result.installed.push(`skill:${skill}`);
|
|
68
|
-
log(`Installed skill/${skill}`);
|
|
69
|
-
} catch (err) {
|
|
70
|
-
result.errors.push(`skill:${skill}: ${err}`);
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
if (categories.includes("agents")) {
|
|
76
|
-
const agentsDir = join2(packageRoot, "agents");
|
|
77
|
-
if (existsSync(agentsDir)) {
|
|
78
|
-
const agents = readdirSync(agentsDir).filter((f) => f.endsWith(".md")).map((f) => f.replace(".md", ""));
|
|
79
|
-
for (const agent of agents) {
|
|
80
|
-
const src = join2(agentsDir, `${agent}.md`);
|
|
81
|
-
const dest = join2(destinations.agents, `${agent}.md`);
|
|
82
|
-
try {
|
|
83
|
-
if (existsSync(dest) && !force) {
|
|
84
|
-
result.skipped.push(`agent:${agent}`);
|
|
85
|
-
log(`Skipped agents/${agent}.md (already exists)`);
|
|
86
|
-
continue;
|
|
87
|
-
}
|
|
88
|
-
mkdirSync(dirname2(dest), { recursive: true });
|
|
89
|
-
cpSync(src, dest);
|
|
90
|
-
result.installed.push(`agent:${agent}`);
|
|
91
|
-
log(`Installed agents/${agent}.md`);
|
|
92
|
-
} catch (err) {
|
|
93
|
-
result.errors.push(`agent:${agent}: ${err}`);
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
if (categories.includes("commands")) {
|
|
99
|
-
const commandsDir = join2(packageRoot, "commands");
|
|
100
|
-
if (existsSync(commandsDir)) {
|
|
101
|
-
const commands = readdirSync(commandsDir).filter((f) => f.endsWith(".md")).map((f) => f.replace(".md", ""));
|
|
102
|
-
for (const command of commands) {
|
|
103
|
-
const src = join2(commandsDir, `${command}.md`);
|
|
104
|
-
const dest = join2(destinations.commands, `${command}.md`);
|
|
105
|
-
try {
|
|
106
|
-
if (existsSync(dest) && !force) {
|
|
107
|
-
result.skipped.push(`command:${command}`);
|
|
108
|
-
log(`Skipped commands/${command}.md (already exists)`);
|
|
109
|
-
continue;
|
|
110
|
-
}
|
|
111
|
-
mkdirSync(dirname2(dest), { recursive: true });
|
|
112
|
-
cpSync(src, dest);
|
|
113
|
-
result.installed.push(`command:${command}`);
|
|
114
|
-
log(`Installed commands/${command}.md`);
|
|
115
|
-
} catch (err) {
|
|
116
|
-
result.errors.push(`command:${command}: ${err}`);
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
return result;
|
|
122
|
-
}
|
|
123
|
-
|
|
124
111
|
// src/manifest.ts
|
|
125
112
|
var SKILLS = [
|
|
126
113
|
// Core UX Skills
|
|
@@ -372,7 +359,269 @@ var COMMANDS = [
|
|
|
372
359
|
}
|
|
373
360
|
];
|
|
374
361
|
|
|
362
|
+
// src/installer.ts
|
|
363
|
+
async function install(options = {}) {
|
|
364
|
+
const {
|
|
365
|
+
global: isGlobal = false,
|
|
366
|
+
projectRoot = process.cwd(),
|
|
367
|
+
target = "opencode",
|
|
368
|
+
categories = ["skills", "agents", "commands"],
|
|
369
|
+
skills: specificSkills,
|
|
370
|
+
agents: specificAgents,
|
|
371
|
+
commands: specificCommands,
|
|
372
|
+
force = false,
|
|
373
|
+
verbose = false
|
|
374
|
+
} = options;
|
|
375
|
+
const hasSpecificComponents = specificSkills?.length || specificAgents?.length || specificCommands?.length;
|
|
376
|
+
const effectiveCategories = hasSpecificComponents ? categories.filter((cat) => {
|
|
377
|
+
if (cat === "skills" && specificSkills?.length) return true;
|
|
378
|
+
if (cat === "agents" && specificAgents?.length) return true;
|
|
379
|
+
if (cat === "commands" && specificCommands?.length) return true;
|
|
380
|
+
return false;
|
|
381
|
+
}) : categories;
|
|
382
|
+
const result = {
|
|
383
|
+
installed: [],
|
|
384
|
+
skipped: [],
|
|
385
|
+
errors: []
|
|
386
|
+
};
|
|
387
|
+
const packageRoot = getPackageRoot();
|
|
388
|
+
const destinations = getDestinationPaths(isGlobal, projectRoot, target);
|
|
389
|
+
const log = (msg) => {
|
|
390
|
+
if (verbose) console.log(msg);
|
|
391
|
+
};
|
|
392
|
+
if (effectiveCategories.includes("skills")) {
|
|
393
|
+
const skillsDir = join2(packageRoot, "skills");
|
|
394
|
+
if (existsSync2(skillsDir)) {
|
|
395
|
+
let skills = readdirSync(skillsDir, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name);
|
|
396
|
+
if (specificSkills?.length) {
|
|
397
|
+
const requested = new Set(specificSkills.map((s) => s.toLowerCase()));
|
|
398
|
+
skills = skills.filter((s) => requested.has(s.toLowerCase()));
|
|
399
|
+
}
|
|
400
|
+
for (const skill of skills) {
|
|
401
|
+
const src = join2(skillsDir, skill);
|
|
402
|
+
const dest = join2(destinations.skills, skill);
|
|
403
|
+
try {
|
|
404
|
+
if (existsSync2(dest) && !force) {
|
|
405
|
+
result.skipped.push(`skill:${skill}`);
|
|
406
|
+
log(`Skipped skill/${skill} (already exists)`);
|
|
407
|
+
continue;
|
|
408
|
+
}
|
|
409
|
+
mkdirSync(dirname2(dest), { recursive: true });
|
|
410
|
+
cpSync(src, dest, { recursive: true });
|
|
411
|
+
result.installed.push(`skill:${skill}`);
|
|
412
|
+
log(`Installed skill/${skill}`);
|
|
413
|
+
} catch (err) {
|
|
414
|
+
result.errors.push(`skill:${skill}: ${err}`);
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
if (effectiveCategories.includes("agents")) {
|
|
420
|
+
const agentsDir = join2(packageRoot, "agents");
|
|
421
|
+
if (existsSync2(agentsDir)) {
|
|
422
|
+
let agents = readdirSync(agentsDir).filter((f) => f.endsWith(".md")).map((f) => f.replace(".md", ""));
|
|
423
|
+
if (specificAgents?.length) {
|
|
424
|
+
const requested = new Set(specificAgents.map((a) => a.toLowerCase()));
|
|
425
|
+
agents = agents.filter((a) => requested.has(a.toLowerCase()));
|
|
426
|
+
}
|
|
427
|
+
for (const agent of agents) {
|
|
428
|
+
const src = join2(agentsDir, `${agent}.md`);
|
|
429
|
+
const dest = join2(destinations.agents, `${agent}.md`);
|
|
430
|
+
try {
|
|
431
|
+
if (existsSync2(dest) && !force) {
|
|
432
|
+
result.skipped.push(`agent:${agent}`);
|
|
433
|
+
log(`Skipped agents/${agent}.md (already exists)`);
|
|
434
|
+
continue;
|
|
435
|
+
}
|
|
436
|
+
mkdirSync(dirname2(dest), { recursive: true });
|
|
437
|
+
cpSync(src, dest);
|
|
438
|
+
result.installed.push(`agent:${agent}`);
|
|
439
|
+
log(`Installed agents/${agent}.md`);
|
|
440
|
+
} catch (err) {
|
|
441
|
+
result.errors.push(`agent:${agent}: ${err}`);
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
if (effectiveCategories.includes("commands")) {
|
|
447
|
+
const commandsDir = join2(packageRoot, "commands");
|
|
448
|
+
if (existsSync2(commandsDir)) {
|
|
449
|
+
let commands = readdirSync(commandsDir).filter((f) => f.endsWith(".md")).map((f) => f.replace(".md", ""));
|
|
450
|
+
if (specificCommands?.length) {
|
|
451
|
+
const requested = new Set(specificCommands.map((c) => c.toLowerCase()));
|
|
452
|
+
commands = commands.filter((c) => requested.has(c.toLowerCase()));
|
|
453
|
+
}
|
|
454
|
+
for (const command of commands) {
|
|
455
|
+
const src = join2(commandsDir, `${command}.md`);
|
|
456
|
+
const dest = join2(destinations.commands, `${command}.md`);
|
|
457
|
+
try {
|
|
458
|
+
if (existsSync2(dest) && !force) {
|
|
459
|
+
result.skipped.push(`command:${command}`);
|
|
460
|
+
log(`Skipped commands/${command}.md (already exists)`);
|
|
461
|
+
continue;
|
|
462
|
+
}
|
|
463
|
+
mkdirSync(dirname2(dest), { recursive: true });
|
|
464
|
+
cpSync(src, dest);
|
|
465
|
+
result.installed.push(`command:${command}`);
|
|
466
|
+
log(`Installed commands/${command}.md`);
|
|
467
|
+
} catch (err) {
|
|
468
|
+
result.errors.push(`command:${command}: ${err}`);
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
return result;
|
|
474
|
+
}
|
|
475
|
+
function checkComponentStatus(componentPath, name) {
|
|
476
|
+
const installed = existsSync2(componentPath);
|
|
477
|
+
if (!installed) {
|
|
478
|
+
return { name, installed: false };
|
|
479
|
+
}
|
|
480
|
+
try {
|
|
481
|
+
const stats = statSync(componentPath);
|
|
482
|
+
return {
|
|
483
|
+
name,
|
|
484
|
+
installed: true,
|
|
485
|
+
path: componentPath,
|
|
486
|
+
modifiedAt: stats.mtime
|
|
487
|
+
};
|
|
488
|
+
} catch {
|
|
489
|
+
return { name, installed: true, path: componentPath };
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
function getTargetStatus(target, isGlobal, projectRoot) {
|
|
493
|
+
const available = target === "opencode" ? isOpenCodeInstalled() : isClaudeInstalled();
|
|
494
|
+
const destinations = getDestinationPaths(isGlobal, projectRoot, target);
|
|
495
|
+
const skillStatuses = SKILLS.map(
|
|
496
|
+
(s) => checkComponentStatus(join2(destinations.skills, s.name), s.name)
|
|
497
|
+
);
|
|
498
|
+
const agentStatuses = AGENTS.map(
|
|
499
|
+
(a) => checkComponentStatus(join2(destinations.agents, `${a.name}.md`), a.name)
|
|
500
|
+
);
|
|
501
|
+
const commandStatuses = COMMANDS.map(
|
|
502
|
+
(c) => checkComponentStatus(join2(destinations.commands, `${c.name}.md`), c.name)
|
|
503
|
+
);
|
|
504
|
+
return {
|
|
505
|
+
target,
|
|
506
|
+
available,
|
|
507
|
+
configDir: target === "opencode" ? isGlobal ? destinations.skills.replace(/[/\\]skills$/, "") : destinations.skills.replace(/[/\\]skills$/, "") : isGlobal ? destinations.skills.replace(/[/\\]skills$/, "") : destinations.skills.replace(/[/\\]skills$/, ""),
|
|
508
|
+
skills: {
|
|
509
|
+
installed: skillStatuses.filter((s) => s.installed).length,
|
|
510
|
+
total: SKILLS.length,
|
|
511
|
+
components: skillStatuses
|
|
512
|
+
},
|
|
513
|
+
agents: {
|
|
514
|
+
installed: agentStatuses.filter((a) => a.installed).length,
|
|
515
|
+
total: AGENTS.length,
|
|
516
|
+
components: agentStatuses
|
|
517
|
+
},
|
|
518
|
+
commands: {
|
|
519
|
+
installed: commandStatuses.filter((c) => c.installed).length,
|
|
520
|
+
total: COMMANDS.length,
|
|
521
|
+
components: commandStatuses
|
|
522
|
+
}
|
|
523
|
+
};
|
|
524
|
+
}
|
|
525
|
+
async function getStatus(options = {}) {
|
|
526
|
+
const { global: isGlobal = true, projectRoot = process.cwd() } = options;
|
|
527
|
+
return {
|
|
528
|
+
opencode: getTargetStatus("opencode", isGlobal, projectRoot),
|
|
529
|
+
claude: getTargetStatus("claude", isGlobal, projectRoot)
|
|
530
|
+
};
|
|
531
|
+
}
|
|
532
|
+
async function uninstall(options = {}) {
|
|
533
|
+
const {
|
|
534
|
+
global: isGlobal = false,
|
|
535
|
+
projectRoot = process.cwd(),
|
|
536
|
+
target = "opencode",
|
|
537
|
+
categories = ["skills", "agents", "commands"],
|
|
538
|
+
verbose = false
|
|
539
|
+
} = options;
|
|
540
|
+
const result = {
|
|
541
|
+
removed: [],
|
|
542
|
+
notFound: [],
|
|
543
|
+
errors: []
|
|
544
|
+
};
|
|
545
|
+
const destinations = getDestinationPaths(isGlobal, projectRoot, target);
|
|
546
|
+
const log = (msg) => {
|
|
547
|
+
if (verbose) console.log(msg);
|
|
548
|
+
};
|
|
549
|
+
const ourSkills = SKILLS.map((s) => s.name);
|
|
550
|
+
const ourAgents = AGENTS.map((a) => a.name);
|
|
551
|
+
const ourCommands = COMMANDS.map((c) => c.name);
|
|
552
|
+
if (categories.includes("skills")) {
|
|
553
|
+
for (const skill of ourSkills) {
|
|
554
|
+
const dest = join2(destinations.skills, skill);
|
|
555
|
+
try {
|
|
556
|
+
if (!existsSync2(dest)) {
|
|
557
|
+
result.notFound.push(`skill:${skill}`);
|
|
558
|
+
log(`Not found: skill/${skill}`);
|
|
559
|
+
continue;
|
|
560
|
+
}
|
|
561
|
+
rmSync(dest, { recursive: true, force: true });
|
|
562
|
+
result.removed.push(`skill:${skill}`);
|
|
563
|
+
log(`Removed skill/${skill}`);
|
|
564
|
+
} catch (err) {
|
|
565
|
+
result.errors.push(`skill:${skill}: ${err}`);
|
|
566
|
+
}
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
if (categories.includes("agents")) {
|
|
570
|
+
for (const agent of ourAgents) {
|
|
571
|
+
const dest = join2(destinations.agents, `${agent}.md`);
|
|
572
|
+
try {
|
|
573
|
+
if (!existsSync2(dest)) {
|
|
574
|
+
result.notFound.push(`agent:${agent}`);
|
|
575
|
+
log(`Not found: agents/${agent}.md`);
|
|
576
|
+
continue;
|
|
577
|
+
}
|
|
578
|
+
rmSync(dest, { force: true });
|
|
579
|
+
result.removed.push(`agent:${agent}`);
|
|
580
|
+
log(`Removed agents/${agent}.md`);
|
|
581
|
+
} catch (err) {
|
|
582
|
+
result.errors.push(`agent:${agent}: ${err}`);
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
}
|
|
586
|
+
if (categories.includes("commands")) {
|
|
587
|
+
for (const command of ourCommands) {
|
|
588
|
+
const dest = join2(destinations.commands, `${command}.md`);
|
|
589
|
+
try {
|
|
590
|
+
if (!existsSync2(dest)) {
|
|
591
|
+
result.notFound.push(`command:${command}`);
|
|
592
|
+
log(`Not found: commands/${command}.md`);
|
|
593
|
+
continue;
|
|
594
|
+
}
|
|
595
|
+
rmSync(dest, { force: true });
|
|
596
|
+
result.removed.push(`command:${command}`);
|
|
597
|
+
log(`Removed commands/${command}.md`);
|
|
598
|
+
} catch (err) {
|
|
599
|
+
result.errors.push(`command:${command}: ${err}`);
|
|
600
|
+
}
|
|
601
|
+
}
|
|
602
|
+
}
|
|
603
|
+
return result;
|
|
604
|
+
}
|
|
605
|
+
|
|
375
606
|
// src/cli.ts
|
|
607
|
+
async function prompt(question) {
|
|
608
|
+
const rl = createInterface({
|
|
609
|
+
input: process.stdin,
|
|
610
|
+
output: process.stdout
|
|
611
|
+
});
|
|
612
|
+
return new Promise((resolve2) => {
|
|
613
|
+
rl.question(question, (answer) => {
|
|
614
|
+
rl.close();
|
|
615
|
+
resolve2(answer.trim().toLowerCase());
|
|
616
|
+
});
|
|
617
|
+
});
|
|
618
|
+
}
|
|
619
|
+
async function promptYesNo(question, defaultYes = true) {
|
|
620
|
+
const suffix = defaultYes ? "[Y/n]" : "[y/N]";
|
|
621
|
+
const answer = await prompt(`${question} ${suffix} `);
|
|
622
|
+
if (answer === "") return defaultYes;
|
|
623
|
+
return answer === "y" || answer === "yes";
|
|
624
|
+
}
|
|
376
625
|
var HELP = `
|
|
377
626
|
ux-toolkit - AI-powered UI/UX review toolkit
|
|
378
627
|
|
|
@@ -381,20 +630,67 @@ USAGE:
|
|
|
381
630
|
|
|
382
631
|
COMMANDS:
|
|
383
632
|
install Install skills, agents, and commands
|
|
633
|
+
uninstall Remove installed skills, agents, and commands
|
|
634
|
+
upgrade Reinstall all components (alias for install --force)
|
|
635
|
+
status Show what's installed vs available
|
|
636
|
+
doctor Diagnose installation issues
|
|
384
637
|
list List available components
|
|
638
|
+
info Show platform and config information
|
|
639
|
+
|
|
640
|
+
TARGET (choose one):
|
|
641
|
+
--opencode Target OpenCode (default) - ~/.config/opencode
|
|
642
|
+
--claude Target Claude Code - ~/.claude
|
|
643
|
+
|
|
644
|
+
SCOPE:
|
|
645
|
+
--global, -g Install to global config (default)
|
|
646
|
+
--project, -p Install to project config (.opencode/ or .claude/)
|
|
385
647
|
|
|
386
648
|
OPTIONS:
|
|
387
|
-
--
|
|
388
|
-
--project, -p Install to project config (.opencode/)
|
|
649
|
+
--all, -a Install to all detected platforms (no prompt)
|
|
389
650
|
--force, -f Overwrite existing files
|
|
390
651
|
--verbose, -v Verbose output
|
|
652
|
+
--only Install specific categories (skills,agents,commands)
|
|
653
|
+
--skill Install specific skill(s) by name (can repeat)
|
|
654
|
+
--agent Install specific agent(s) by name (can repeat)
|
|
655
|
+
--command Install specific command(s) by name (can repeat)
|
|
391
656
|
--help, -h Show this help
|
|
392
657
|
|
|
658
|
+
ENVIRONMENT:
|
|
659
|
+
UX_TOOLKIT_CONFIG_DIR Override config directory
|
|
660
|
+
OPENCODE_CONFIG_DIR OpenCode config directory override
|
|
661
|
+
CLAUDE_CONFIG_DIR Claude Code config directory override
|
|
662
|
+
XDG_CONFIG_HOME Linux XDG config home (respected)
|
|
663
|
+
|
|
393
664
|
EXAMPLES:
|
|
665
|
+
# OpenCode (default)
|
|
394
666
|
npx ux-toolkit install --global
|
|
395
|
-
npx ux-toolkit install --
|
|
667
|
+
npx ux-toolkit install --opencode --global
|
|
668
|
+
|
|
669
|
+
# Claude Code
|
|
670
|
+
npx ux-toolkit install --claude --global
|
|
671
|
+
npx ux-toolkit uninstall --claude --global
|
|
672
|
+
|
|
673
|
+
# Both platforms
|
|
674
|
+
npx ux-toolkit install --opencode --global && npx ux-toolkit install --claude --global
|
|
675
|
+
|
|
676
|
+
# Project-level
|
|
677
|
+
npx ux-toolkit install --project
|
|
678
|
+
npx ux-toolkit install --claude --project
|
|
679
|
+
|
|
680
|
+
# Selective
|
|
681
|
+
npx ux-toolkit install --global --only=skills,agents
|
|
682
|
+
|
|
683
|
+
# Other commands
|
|
684
|
+
npx ux-toolkit info
|
|
396
685
|
npx ux-toolkit list
|
|
397
686
|
`;
|
|
687
|
+
function parseCategories(only) {
|
|
688
|
+
if (!only) return void 0;
|
|
689
|
+
const valid = ["skills", "agents", "commands"];
|
|
690
|
+
const parsed = only.split(",").map((s) => s.trim().toLowerCase());
|
|
691
|
+
const filtered = parsed.filter((c) => valid.includes(c));
|
|
692
|
+
return filtered.length > 0 ? filtered : void 0;
|
|
693
|
+
}
|
|
398
694
|
async function main() {
|
|
399
695
|
const { values, positionals } = parseArgs({
|
|
400
696
|
allowPositionals: true,
|
|
@@ -403,7 +699,14 @@ async function main() {
|
|
|
403
699
|
project: { type: "boolean", short: "p", default: false },
|
|
404
700
|
force: { type: "boolean", short: "f", default: false },
|
|
405
701
|
verbose: { type: "boolean", short: "v", default: false },
|
|
406
|
-
help: { type: "boolean", short: "h", default: false }
|
|
702
|
+
help: { type: "boolean", short: "h", default: false },
|
|
703
|
+
only: { type: "string" },
|
|
704
|
+
opencode: { type: "boolean", default: false },
|
|
705
|
+
claude: { type: "boolean", default: false },
|
|
706
|
+
all: { type: "boolean", short: "a", default: false },
|
|
707
|
+
skill: { type: "string", multiple: true },
|
|
708
|
+
agent: { type: "string", multiple: true },
|
|
709
|
+
command: { type: "string", multiple: true }
|
|
407
710
|
}
|
|
408
711
|
});
|
|
409
712
|
if (values.help || positionals.length === 0) {
|
|
@@ -411,25 +714,103 @@ async function main() {
|
|
|
411
714
|
process.exit(0);
|
|
412
715
|
}
|
|
413
716
|
const command = positionals[0];
|
|
717
|
+
const isGlobal = values.global || !values.project;
|
|
718
|
+
const categories = parseCategories(values.only);
|
|
719
|
+
async function runInstall(target, showHeader = true) {
|
|
720
|
+
const targetName = target === "claude" ? "Claude Code" : "OpenCode";
|
|
721
|
+
if (showHeader) {
|
|
722
|
+
console.log(`
|
|
723
|
+
Installing UX Toolkit to ${targetName} ${isGlobal ? "globally" : "in project"}...
|
|
724
|
+
`);
|
|
725
|
+
}
|
|
726
|
+
const result = await install({
|
|
727
|
+
global: isGlobal,
|
|
728
|
+
target,
|
|
729
|
+
force: values.force,
|
|
730
|
+
verbose: values.verbose,
|
|
731
|
+
categories,
|
|
732
|
+
skills: values.skill,
|
|
733
|
+
agents: values.agent,
|
|
734
|
+
commands: values.command
|
|
735
|
+
});
|
|
736
|
+
if (result.installed.length > 0) {
|
|
737
|
+
console.log(`Installed ${result.installed.length} components:`);
|
|
738
|
+
result.installed.forEach((item) => console.log(` + ${item}`));
|
|
739
|
+
}
|
|
740
|
+
if (result.skipped.length > 0) {
|
|
741
|
+
console.log(`
|
|
742
|
+
Skipped ${result.skipped.length} (already exist, use --force to overwrite):`);
|
|
743
|
+
result.skipped.forEach((item) => console.log(` - ${item}`));
|
|
744
|
+
}
|
|
745
|
+
if (result.errors.length > 0) {
|
|
746
|
+
console.error(`
|
|
747
|
+
Errors:`);
|
|
748
|
+
result.errors.forEach((err) => console.error(` ! ${err}`));
|
|
749
|
+
return false;
|
|
750
|
+
}
|
|
751
|
+
return true;
|
|
752
|
+
}
|
|
414
753
|
switch (command) {
|
|
415
754
|
case "install": {
|
|
416
|
-
const
|
|
755
|
+
const opencodeInstalled = isOpenCodeInstalled();
|
|
756
|
+
const claudeInstalled = isClaudeInstalled();
|
|
757
|
+
const explicitTarget = values.opencode || values.claude;
|
|
758
|
+
let targets = [];
|
|
759
|
+
if (values.all) {
|
|
760
|
+
if (opencodeInstalled) targets.push("opencode");
|
|
761
|
+
if (claudeInstalled) targets.push("claude");
|
|
762
|
+
if (targets.length === 0) {
|
|
763
|
+
console.warn("\n\u26A0\uFE0F No platforms detected. Installing to OpenCode by default.\n");
|
|
764
|
+
targets = ["opencode"];
|
|
765
|
+
}
|
|
766
|
+
} else if (explicitTarget) {
|
|
767
|
+
targets = [values.claude ? "claude" : "opencode"];
|
|
768
|
+
} else if (isGlobal && opencodeInstalled && claudeInstalled) {
|
|
769
|
+
console.log("\n\u{1F50D} Detected both OpenCode and Claude Code installations.\n");
|
|
770
|
+
const installBoth = await promptYesNo("Install to both platforms?", true);
|
|
771
|
+
if (installBoth) {
|
|
772
|
+
targets = ["opencode", "claude"];
|
|
773
|
+
} else {
|
|
774
|
+
const choice = await prompt("Which platform? (opencode/claude) [opencode]: ");
|
|
775
|
+
targets = [choice === "claude" ? "claude" : "opencode"];
|
|
776
|
+
}
|
|
777
|
+
} else if (isGlobal && claudeInstalled && !opencodeInstalled) {
|
|
778
|
+
console.log("\n\u{1F50D} Detected Claude Code (OpenCode not found).\n");
|
|
779
|
+
targets = ["claude"];
|
|
780
|
+
} else {
|
|
781
|
+
targets = ["opencode"];
|
|
782
|
+
}
|
|
783
|
+
let hasErrors = false;
|
|
784
|
+
for (let i = 0; i < targets.length; i++) {
|
|
785
|
+
const target = targets[i];
|
|
786
|
+
if (i > 0) console.log("");
|
|
787
|
+
const success = await runInstall(target);
|
|
788
|
+
if (!success) hasErrors = true;
|
|
789
|
+
}
|
|
790
|
+
console.log("\nDone!");
|
|
791
|
+
if (hasErrors) process.exit(1);
|
|
792
|
+
break;
|
|
793
|
+
}
|
|
794
|
+
case "uninstall": {
|
|
795
|
+
const target = values.claude ? "claude" : "opencode";
|
|
796
|
+
const targetName = target === "claude" ? "Claude Code" : "OpenCode";
|
|
417
797
|
console.log(`
|
|
418
|
-
|
|
798
|
+
Uninstalling UX Toolkit from ${targetName} ${isGlobal ? "globally" : "in project"}...
|
|
419
799
|
`);
|
|
420
|
-
const result = await
|
|
800
|
+
const result = await uninstall({
|
|
421
801
|
global: isGlobal,
|
|
422
|
-
|
|
423
|
-
verbose: values.verbose
|
|
802
|
+
target,
|
|
803
|
+
verbose: values.verbose,
|
|
804
|
+
categories
|
|
424
805
|
});
|
|
425
|
-
if (result.
|
|
426
|
-
console.log(`
|
|
427
|
-
result.
|
|
806
|
+
if (result.removed.length > 0) {
|
|
807
|
+
console.log(`Removed ${result.removed.length} components:`);
|
|
808
|
+
result.removed.forEach((item) => console.log(` - ${item}`));
|
|
428
809
|
}
|
|
429
|
-
if (result.
|
|
810
|
+
if (result.notFound.length > 0 && values.verbose) {
|
|
430
811
|
console.log(`
|
|
431
|
-
|
|
432
|
-
result.
|
|
812
|
+
Not found (${result.notFound.length}):`);
|
|
813
|
+
result.notFound.forEach((item) => console.log(` ? ${item}`));
|
|
433
814
|
}
|
|
434
815
|
if (result.errors.length > 0) {
|
|
435
816
|
console.error(`
|
|
@@ -440,6 +821,248 @@ Errors:`);
|
|
|
440
821
|
console.log("\nDone!");
|
|
441
822
|
break;
|
|
442
823
|
}
|
|
824
|
+
case "upgrade": {
|
|
825
|
+
const target = values.claude ? "claude" : "opencode";
|
|
826
|
+
const targetName = target === "claude" ? "Claude Code" : "OpenCode";
|
|
827
|
+
console.log(`
|
|
828
|
+
Upgrading UX Toolkit in ${targetName} ${isGlobal ? "globally" : "in project"}...
|
|
829
|
+
`);
|
|
830
|
+
const result = await install({
|
|
831
|
+
global: isGlobal,
|
|
832
|
+
target,
|
|
833
|
+
force: true,
|
|
834
|
+
// Always force for upgrade
|
|
835
|
+
verbose: values.verbose,
|
|
836
|
+
categories
|
|
837
|
+
});
|
|
838
|
+
if (result.installed.length > 0) {
|
|
839
|
+
console.log(`Upgraded ${result.installed.length} components:`);
|
|
840
|
+
result.installed.forEach((item) => console.log(` \u2191 ${item}`));
|
|
841
|
+
}
|
|
842
|
+
if (result.errors.length > 0) {
|
|
843
|
+
console.error(`
|
|
844
|
+
Errors:`);
|
|
845
|
+
result.errors.forEach((err) => console.error(` ! ${err}`));
|
|
846
|
+
process.exit(1);
|
|
847
|
+
}
|
|
848
|
+
console.log("\nDone!");
|
|
849
|
+
break;
|
|
850
|
+
}
|
|
851
|
+
case "status": {
|
|
852
|
+
const status = await getStatus({ global: isGlobal });
|
|
853
|
+
console.log("\nUX Toolkit - Installation Status\n");
|
|
854
|
+
const formatStatus = (installed, total) => {
|
|
855
|
+
if (installed === 0) return `\u2717 0/${total}`;
|
|
856
|
+
if (installed === total) return `\u2713 ${installed}/${total}`;
|
|
857
|
+
return `\u25D0 ${installed}/${total}`;
|
|
858
|
+
};
|
|
859
|
+
const getMissing = (components) => {
|
|
860
|
+
return components.filter((c) => !c.installed).map((c) => c.name);
|
|
861
|
+
};
|
|
862
|
+
console.log(" OpenCode:");
|
|
863
|
+
if (!status.opencode.available) {
|
|
864
|
+
console.log(" Not installed (no config directory found)");
|
|
865
|
+
} else {
|
|
866
|
+
console.log(` Skills: ${formatStatus(status.opencode.skills.installed, status.opencode.skills.total)}`);
|
|
867
|
+
console.log(` Agents: ${formatStatus(status.opencode.agents.installed, status.opencode.agents.total)}`);
|
|
868
|
+
console.log(` Commands: ${formatStatus(status.opencode.commands.installed, status.opencode.commands.total)}`);
|
|
869
|
+
if (values.verbose) {
|
|
870
|
+
const missingSkills = getMissing(status.opencode.skills.components);
|
|
871
|
+
const missingAgents = getMissing(status.opencode.agents.components);
|
|
872
|
+
const missingCommands = getMissing(status.opencode.commands.components);
|
|
873
|
+
if (missingSkills.length > 0) {
|
|
874
|
+
console.log(` Missing skills: ${missingSkills.join(", ")}`);
|
|
875
|
+
}
|
|
876
|
+
if (missingAgents.length > 0) {
|
|
877
|
+
console.log(` Missing agents: ${missingAgents.join(", ")}`);
|
|
878
|
+
}
|
|
879
|
+
if (missingCommands.length > 0) {
|
|
880
|
+
console.log(` Missing commands: ${missingCommands.join(", ")}`);
|
|
881
|
+
}
|
|
882
|
+
}
|
|
883
|
+
}
|
|
884
|
+
console.log("\n Claude Code:");
|
|
885
|
+
if (!status.claude.available) {
|
|
886
|
+
console.log(" Not installed (no config directory found)");
|
|
887
|
+
} else {
|
|
888
|
+
console.log(` Skills: ${formatStatus(status.claude.skills.installed, status.claude.skills.total)}`);
|
|
889
|
+
console.log(` Agents: ${formatStatus(status.claude.agents.installed, status.claude.agents.total)}`);
|
|
890
|
+
console.log(` Commands: ${formatStatus(status.claude.commands.installed, status.claude.commands.total)}`);
|
|
891
|
+
if (values.verbose) {
|
|
892
|
+
const missingSkills = getMissing(status.claude.skills.components);
|
|
893
|
+
const missingAgents = getMissing(status.claude.agents.components);
|
|
894
|
+
const missingCommands = getMissing(status.claude.commands.components);
|
|
895
|
+
if (missingSkills.length > 0) {
|
|
896
|
+
console.log(` Missing skills: ${missingSkills.join(", ")}`);
|
|
897
|
+
}
|
|
898
|
+
if (missingAgents.length > 0) {
|
|
899
|
+
console.log(` Missing agents: ${missingAgents.join(", ")}`);
|
|
900
|
+
}
|
|
901
|
+
if (missingCommands.length > 0) {
|
|
902
|
+
console.log(` Missing commands: ${missingCommands.join(", ")}`);
|
|
903
|
+
}
|
|
904
|
+
}
|
|
905
|
+
}
|
|
906
|
+
const totalOpencode = status.opencode.skills.installed + status.opencode.agents.installed + status.opencode.commands.installed;
|
|
907
|
+
const totalClaude = status.claude.skills.installed + status.claude.agents.installed + status.claude.commands.installed;
|
|
908
|
+
const totalAvailable = SKILLS.length + AGENTS.length + COMMANDS.length;
|
|
909
|
+
console.log("\n Summary:");
|
|
910
|
+
if (status.opencode.available && totalOpencode === totalAvailable) {
|
|
911
|
+
console.log(" OpenCode: \u2713 Fully installed");
|
|
912
|
+
} else if (status.opencode.available && totalOpencode > 0) {
|
|
913
|
+
console.log(` OpenCode: \u25D0 Partially installed (${totalOpencode}/${totalAvailable})`);
|
|
914
|
+
} else if (status.opencode.available) {
|
|
915
|
+
console.log(" OpenCode: \u2717 Not installed");
|
|
916
|
+
}
|
|
917
|
+
if (status.claude.available && totalClaude === totalAvailable) {
|
|
918
|
+
console.log(" Claude Code: \u2713 Fully installed");
|
|
919
|
+
} else if (status.claude.available && totalClaude > 0) {
|
|
920
|
+
console.log(` Claude Code: \u25D0 Partially installed (${totalClaude}/${totalAvailable})`);
|
|
921
|
+
} else if (status.claude.available) {
|
|
922
|
+
console.log(" Claude Code: \u2717 Not installed");
|
|
923
|
+
}
|
|
924
|
+
break;
|
|
925
|
+
}
|
|
926
|
+
case "doctor": {
|
|
927
|
+
console.log("\nUX Toolkit - Diagnostics\n");
|
|
928
|
+
const issues = [];
|
|
929
|
+
const warnings = [];
|
|
930
|
+
const ok = [];
|
|
931
|
+
const nodeVersion = process.version;
|
|
932
|
+
const majorVersion = parseInt(nodeVersion.slice(1).split(".")[0], 10);
|
|
933
|
+
if (majorVersion < 18) {
|
|
934
|
+
issues.push(`Node.js ${nodeVersion} is below minimum (v18+)`);
|
|
935
|
+
} else {
|
|
936
|
+
ok.push(`Node.js ${nodeVersion}`);
|
|
937
|
+
}
|
|
938
|
+
const platformInfo = getPlatformInfo();
|
|
939
|
+
if (platformInfo.opencode.exists) {
|
|
940
|
+
ok.push(`OpenCode detected at ${platformInfo.opencode.configDir}`);
|
|
941
|
+
const { existsSync: existsSync3 } = await import("fs");
|
|
942
|
+
const { join: join3 } = await import("path");
|
|
943
|
+
const skillsDir = join3(platformInfo.opencode.configDir, "skills");
|
|
944
|
+
const agentsDir = join3(platformInfo.opencode.configDir, "agents");
|
|
945
|
+
const commandsDir = join3(platformInfo.opencode.configDir, "commands");
|
|
946
|
+
if (!existsSync3(skillsDir)) {
|
|
947
|
+
warnings.push("OpenCode skills directory missing");
|
|
948
|
+
}
|
|
949
|
+
if (!existsSync3(agentsDir)) {
|
|
950
|
+
warnings.push("OpenCode agents directory missing");
|
|
951
|
+
}
|
|
952
|
+
if (!existsSync3(commandsDir)) {
|
|
953
|
+
warnings.push("OpenCode commands directory missing");
|
|
954
|
+
}
|
|
955
|
+
} else {
|
|
956
|
+
warnings.push("OpenCode not detected (config directory not found)");
|
|
957
|
+
}
|
|
958
|
+
if (platformInfo.claude.exists) {
|
|
959
|
+
ok.push(`Claude Code detected at ${platformInfo.claude.configDir}`);
|
|
960
|
+
const { existsSync: existsSync3 } = await import("fs");
|
|
961
|
+
const { join: join3 } = await import("path");
|
|
962
|
+
const skillsDir = join3(platformInfo.claude.configDir, "skills");
|
|
963
|
+
const agentsDir = join3(platformInfo.claude.configDir, "agents");
|
|
964
|
+
const commandsDir = join3(platformInfo.claude.configDir, "commands");
|
|
965
|
+
if (!existsSync3(skillsDir)) {
|
|
966
|
+
warnings.push("Claude Code skills directory missing");
|
|
967
|
+
}
|
|
968
|
+
if (!existsSync3(agentsDir)) {
|
|
969
|
+
warnings.push("Claude Code agents directory missing");
|
|
970
|
+
}
|
|
971
|
+
if (!existsSync3(commandsDir)) {
|
|
972
|
+
warnings.push("Claude Code commands directory missing");
|
|
973
|
+
}
|
|
974
|
+
} else {
|
|
975
|
+
warnings.push("Claude Code not detected (config directory not found)");
|
|
976
|
+
}
|
|
977
|
+
const status = await getStatus({ global: true });
|
|
978
|
+
const opencodeTotal = status.opencode.skills.installed + status.opencode.agents.installed + status.opencode.commands.installed;
|
|
979
|
+
const claudeTotal = status.claude.skills.installed + status.claude.agents.installed + status.claude.commands.installed;
|
|
980
|
+
const totalAvailable = SKILLS.length + AGENTS.length + COMMANDS.length;
|
|
981
|
+
if (status.opencode.available) {
|
|
982
|
+
if (opencodeTotal === totalAvailable) {
|
|
983
|
+
ok.push("OpenCode: All components installed");
|
|
984
|
+
} else if (opencodeTotal > 0) {
|
|
985
|
+
warnings.push(`OpenCode: Partial installation (${opencodeTotal}/${totalAvailable})`);
|
|
986
|
+
} else {
|
|
987
|
+
warnings.push("OpenCode: No components installed");
|
|
988
|
+
}
|
|
989
|
+
}
|
|
990
|
+
if (status.claude.available) {
|
|
991
|
+
if (claudeTotal === totalAvailable) {
|
|
992
|
+
ok.push("Claude Code: All components installed");
|
|
993
|
+
} else if (claudeTotal > 0) {
|
|
994
|
+
warnings.push(`Claude Code: Partial installation (${claudeTotal}/${totalAvailable})`);
|
|
995
|
+
} else {
|
|
996
|
+
warnings.push("Claude Code: No components installed");
|
|
997
|
+
}
|
|
998
|
+
}
|
|
999
|
+
if (ok.length > 0) {
|
|
1000
|
+
console.log(" \u2713 OK:");
|
|
1001
|
+
ok.forEach((item) => console.log(` \u2022 ${item}`));
|
|
1002
|
+
}
|
|
1003
|
+
if (warnings.length > 0) {
|
|
1004
|
+
console.log("\n \u26A0 Warnings:");
|
|
1005
|
+
warnings.forEach((item) => console.log(` \u2022 ${item}`));
|
|
1006
|
+
}
|
|
1007
|
+
if (issues.length > 0) {
|
|
1008
|
+
console.log("\n \u2717 Issues:");
|
|
1009
|
+
issues.forEach((item) => console.log(` \u2022 ${item}`));
|
|
1010
|
+
}
|
|
1011
|
+
console.log("\n Summary:");
|
|
1012
|
+
if (issues.length === 0 && warnings.length === 0) {
|
|
1013
|
+
console.log(" Everything looks good!");
|
|
1014
|
+
} else if (issues.length === 0) {
|
|
1015
|
+
console.log(` ${warnings.length} warning(s), no critical issues`);
|
|
1016
|
+
} else {
|
|
1017
|
+
console.log(` ${issues.length} issue(s), ${warnings.length} warning(s)`);
|
|
1018
|
+
}
|
|
1019
|
+
if (warnings.length > 0 || issues.length > 0) {
|
|
1020
|
+
console.log("\n Suggestions:");
|
|
1021
|
+
if (!platformInfo.opencode.exists && !platformInfo.claude.exists) {
|
|
1022
|
+
console.log(" \u2022 Install OpenCode or Claude Code first");
|
|
1023
|
+
}
|
|
1024
|
+
if (opencodeTotal < totalAvailable && status.opencode.available) {
|
|
1025
|
+
console.log(" \u2022 Run: npx ux-toolkit install --opencode --global");
|
|
1026
|
+
}
|
|
1027
|
+
if (claudeTotal < totalAvailable && status.claude.available) {
|
|
1028
|
+
console.log(" \u2022 Run: npx ux-toolkit install --claude --global");
|
|
1029
|
+
}
|
|
1030
|
+
}
|
|
1031
|
+
break;
|
|
1032
|
+
}
|
|
1033
|
+
case "info": {
|
|
1034
|
+
const platformInfo = getPlatformInfo();
|
|
1035
|
+
console.log("\nUX Toolkit - Platform Information\n");
|
|
1036
|
+
console.log(` Platform: ${platformInfo.platform}`);
|
|
1037
|
+
console.log(` Node Version: ${process.version}`);
|
|
1038
|
+
console.log("\n OpenCode:");
|
|
1039
|
+
console.log(` Config Dir: ${platformInfo.opencode.configDir}`);
|
|
1040
|
+
console.log(` Installed: ${platformInfo.opencode.exists ? "Yes" : "No"}`);
|
|
1041
|
+
console.log("\n Claude Code:");
|
|
1042
|
+
console.log(` Config Dir: ${platformInfo.claude.configDir}`);
|
|
1043
|
+
console.log(` Installed: ${platformInfo.claude.exists ? "Yes" : "No"}`);
|
|
1044
|
+
if (process.env.UX_TOOLKIT_CONFIG_DIR || process.env.OPENCODE_CONFIG_DIR || process.env.CLAUDE_CONFIG_DIR || process.env.XDG_CONFIG_HOME) {
|
|
1045
|
+
console.log("\n Environment Overrides:");
|
|
1046
|
+
if (process.env.UX_TOOLKIT_CONFIG_DIR) {
|
|
1047
|
+
console.log(` UX_TOOLKIT_CONFIG_DIR: ${process.env.UX_TOOLKIT_CONFIG_DIR}`);
|
|
1048
|
+
}
|
|
1049
|
+
if (process.env.OPENCODE_CONFIG_DIR) {
|
|
1050
|
+
console.log(` OPENCODE_CONFIG_DIR: ${process.env.OPENCODE_CONFIG_DIR}`);
|
|
1051
|
+
}
|
|
1052
|
+
if (process.env.CLAUDE_CONFIG_DIR) {
|
|
1053
|
+
console.log(` CLAUDE_CONFIG_DIR: ${process.env.CLAUDE_CONFIG_DIR}`);
|
|
1054
|
+
}
|
|
1055
|
+
if (process.env.XDG_CONFIG_HOME) {
|
|
1056
|
+
console.log(` XDG_CONFIG_HOME: ${process.env.XDG_CONFIG_HOME}`);
|
|
1057
|
+
}
|
|
1058
|
+
}
|
|
1059
|
+
console.log(`
|
|
1060
|
+
Components:`);
|
|
1061
|
+
console.log(` Skills: ${SKILLS.length}`);
|
|
1062
|
+
console.log(` Agents: ${AGENTS.length}`);
|
|
1063
|
+
console.log(` Commands: ${COMMANDS.length}`);
|
|
1064
|
+
break;
|
|
1065
|
+
}
|
|
443
1066
|
case "list": {
|
|
444
1067
|
console.log("\nSkills:");
|
|
445
1068
|
SKILLS.forEach((s) => console.log(` ${s.name.padEnd(25)} ${s.description}`));
|