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