@codecademy/gamut 68.6.2-alpha.f8b396.0 → 68.6.2
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/dist/DatePicker/DatePickerCalendar/Calendar/CalendarBody.js +3 -3
- package/dist/DatePicker/DatePickerInput/Segment/index.js +1 -1
- package/dist/DatePicker/DatePickerInput/index.js +1 -1
- package/package.json +8 -11
- package/agent-tools/.claude-plugin/marketplace.json +0 -16
- package/agent-tools/.claude-plugin/plugin.json +0 -7
- package/agent-tools/.cursor-plugin/plugin.json +0 -7
- package/agent-tools/DESIGN.Codecademy.md +0 -643
- package/agent-tools/DESIGN.LXStudio.md +0 -437
- package/agent-tools/DESIGN.Percipio.md +0 -433
- package/agent-tools/DESIGN.md +0 -1
- package/agent-tools/agents/.gitkeep +0 -0
- package/agent-tools/rules/accessibility.mdc +0 -78
- package/agent-tools/skills/gamut-accessibility/SKILL.md +0 -214
- package/agent-tools/skills/gamut-buttons/SKILL.md +0 -96
- package/agent-tools/skills/gamut-color-mode/SKILL.md +0 -257
- package/agent-tools/skills/gamut-forms/SKILL.md +0 -84
- package/agent-tools/skills/gamut-layout/SKILL.md +0 -109
- package/agent-tools/skills/gamut-list/SKILL.md +0 -273
- package/agent-tools/skills/gamut-review/SKILL.md +0 -254
- package/agent-tools/skills/gamut-style-utilities/SKILL.md +0 -107
- package/agent-tools/skills/gamut-system-props/SKILL.md +0 -203
- package/agent-tools/skills/gamut-testing/SKILL.md +0 -221
- package/agent-tools/skills/gamut-theming/SKILL.md +0 -115
- package/agent-tools/skills/gamut-typography/SKILL.md +0 -98
- package/bin/commands/plugin/install.mjs +0 -212
- package/bin/commands/plugin/list.mjs +0 -73
- package/bin/commands/plugin/remove.mjs +0 -108
- package/bin/commands/plugin/update.mjs +0 -59
- package/bin/gamut.mjs +0 -96
- package/bin/lib/claude.mjs +0 -52
- package/bin/lib/cursor.mjs +0 -40
- package/bin/lib/design.mjs +0 -71
- package/bin/lib/io.mjs +0 -14
- package/bin/lib/resolve-plugin-dir.mjs +0 -38
- package/bin/lib/run-command.mjs +0 -22
|
@@ -1,73 +0,0 @@
|
|
|
1
|
-
import { stat } from 'node:fs/promises';
|
|
2
|
-
|
|
3
|
-
import { cursorDestPath } from '../../lib/cursor.mjs';
|
|
4
|
-
import { log } from '../../lib/io.mjs';
|
|
5
|
-
import { resolvePluginDir } from '../../lib/resolve-plugin-dir.mjs';
|
|
6
|
-
|
|
7
|
-
export function help() {
|
|
8
|
-
log(`
|
|
9
|
-
Usage:
|
|
10
|
-
gamut plugin list [options]
|
|
11
|
-
|
|
12
|
-
Show installation status for all supported targets.
|
|
13
|
-
|
|
14
|
-
Options:
|
|
15
|
-
--plugin-dir <path> Override the bundled agent-tools directory
|
|
16
|
-
-h, --help Show this help message
|
|
17
|
-
|
|
18
|
-
Examples:
|
|
19
|
-
gamut plugin list
|
|
20
|
-
`);
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
// ---------------------------------------------------------------------------
|
|
24
|
-
|
|
25
|
-
/** @param {string} sourceRoot */
|
|
26
|
-
async function cursorStatus(sourceRoot) {
|
|
27
|
-
const dest = await cursorDestPath(sourceRoot);
|
|
28
|
-
const installed = !!(await stat(dest).catch(() => null));
|
|
29
|
-
return {
|
|
30
|
-
target: 'cursor',
|
|
31
|
-
status: installed ? '✓ installed' : '✗ not installed',
|
|
32
|
-
notes: installed ? dest : 'run: gamut plugin install cursor',
|
|
33
|
-
};
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
async function claudeStatus() {
|
|
37
|
-
// Claude Code doesn't expose a stable filesystem path we can check.
|
|
38
|
-
return {
|
|
39
|
-
target: 'claude',
|
|
40
|
-
status: '? unknown',
|
|
41
|
-
notes: 'run: claude plugin list',
|
|
42
|
-
};
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
// ---------------------------------------------------------------------------
|
|
46
|
-
|
|
47
|
-
/**
|
|
48
|
-
* gamut plugin list
|
|
49
|
-
*
|
|
50
|
-
* Shows installation status for each supported target.
|
|
51
|
-
*
|
|
52
|
-
* @param {string[]} args
|
|
53
|
-
*/
|
|
54
|
-
export default async function list(args) {
|
|
55
|
-
const pluginDir = await resolvePluginDir(args);
|
|
56
|
-
|
|
57
|
-
const rows = await Promise.all([cursorStatus(pluginDir), claudeStatus()]);
|
|
58
|
-
|
|
59
|
-
const col0 = Math.max(...rows.map((r) => r.target.length));
|
|
60
|
-
const col1 = Math.max(...rows.map((r) => r.status.length));
|
|
61
|
-
|
|
62
|
-
const header = `${'Target'.padEnd(col0)} ${'Status'.padEnd(
|
|
63
|
-
col1
|
|
64
|
-
)} Path / Notes`;
|
|
65
|
-
const rule = '─'.repeat(header.length);
|
|
66
|
-
|
|
67
|
-
log(`\n${header}`);
|
|
68
|
-
log(rule);
|
|
69
|
-
for (const row of rows) {
|
|
70
|
-
log(`${row.target.padEnd(col0)} ${row.status.padEnd(col1)} ${row.notes}`);
|
|
71
|
-
}
|
|
72
|
-
log('');
|
|
73
|
-
}
|
|
@@ -1,108 +0,0 @@
|
|
|
1
|
-
import { rm, stat } from 'node:fs/promises';
|
|
2
|
-
|
|
3
|
-
import { claudePluginSpec, marketplaceName } from '../../lib/claude.mjs';
|
|
4
|
-
import { cursorDestPath } from '../../lib/cursor.mjs';
|
|
5
|
-
import { log, warn } from '../../lib/io.mjs';
|
|
6
|
-
import { resolvePluginDir } from '../../lib/resolve-plugin-dir.mjs';
|
|
7
|
-
import { runCommand } from '../../lib/run-command.mjs';
|
|
8
|
-
import { TARGETS } from './install.mjs';
|
|
9
|
-
|
|
10
|
-
export function help() {
|
|
11
|
-
log(`
|
|
12
|
-
Usage:
|
|
13
|
-
gamut plugin remove [target] [options]
|
|
14
|
-
|
|
15
|
-
Remove the installed Gamut plugin from an AI tool.
|
|
16
|
-
|
|
17
|
-
Arguments:
|
|
18
|
-
target Tool to remove from (default: cursor)
|
|
19
|
-
cursor | claude
|
|
20
|
-
|
|
21
|
-
Options:
|
|
22
|
-
--plugin-dir <path> Override the bundled agent-tools directory
|
|
23
|
-
-h, --help Show this help message
|
|
24
|
-
|
|
25
|
-
Examples:
|
|
26
|
-
gamut plugin remove
|
|
27
|
-
gamut plugin remove claude
|
|
28
|
-
`);
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
// ---------------------------------------------------------------------------
|
|
32
|
-
|
|
33
|
-
/** @param {string} sourceRoot */
|
|
34
|
-
async function removeCursor(sourceRoot) {
|
|
35
|
-
const dest = await cursorDestPath(sourceRoot);
|
|
36
|
-
const st = await stat(dest).catch(() => null);
|
|
37
|
-
|
|
38
|
-
if (!st) {
|
|
39
|
-
log(`Cursor: nothing to remove — ${dest} does not exist.`);
|
|
40
|
-
return;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
await rm(dest, { recursive: true, force: true });
|
|
44
|
-
log(`Cursor: removed ${dest}`);
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
/** @param {string} sourceRoot */
|
|
48
|
-
async function removeClaude(sourceRoot) {
|
|
49
|
-
const spec = await claudePluginSpec(sourceRoot);
|
|
50
|
-
const mpName = marketplaceName(spec);
|
|
51
|
-
const pluginName = spec.split('@')[0];
|
|
52
|
-
|
|
53
|
-
let code = await runCommand('claude', [
|
|
54
|
-
'plugin',
|
|
55
|
-
'remove',
|
|
56
|
-
pluginName,
|
|
57
|
-
'--scope',
|
|
58
|
-
'user',
|
|
59
|
-
]);
|
|
60
|
-
if (code !== 0) {
|
|
61
|
-
warn(
|
|
62
|
-
`warning: "claude plugin remove" exited ${code} — the plugin may not have been installed.`
|
|
63
|
-
);
|
|
64
|
-
} else {
|
|
65
|
-
log(`Claude Code: removed plugin "${pluginName}"`);
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
code = await runCommand('claude', [
|
|
69
|
-
'plugin',
|
|
70
|
-
'marketplace',
|
|
71
|
-
'remove',
|
|
72
|
-
mpName,
|
|
73
|
-
]);
|
|
74
|
-
if (code !== 0) {
|
|
75
|
-
warn(
|
|
76
|
-
`warning: "claude plugin marketplace remove" exited ${code} — ` +
|
|
77
|
-
`the marketplace entry may not exist or the command syntax may differ. ` +
|
|
78
|
-
`Run "claude plugin marketplace list" to check.`
|
|
79
|
-
);
|
|
80
|
-
} else {
|
|
81
|
-
log(`Claude Code: removed marketplace "${mpName}"`);
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
// ---------------------------------------------------------------------------
|
|
86
|
-
|
|
87
|
-
/**
|
|
88
|
-
* gamut plugin remove [cursor|claude] [--plugin-dir <path>]
|
|
89
|
-
*
|
|
90
|
-
* @param {string[]} args
|
|
91
|
-
*/
|
|
92
|
-
export default async function remove(args) {
|
|
93
|
-
const target = args.find((a) => !a.startsWith('-')) ?? 'cursor';
|
|
94
|
-
|
|
95
|
-
if (!TARGETS.includes(target)) {
|
|
96
|
-
throw new Error(
|
|
97
|
-
`Unknown target: "${target}". Choose from: ${TARGETS.join(', ')}`
|
|
98
|
-
);
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
const pluginDir = await resolvePluginDir(args);
|
|
102
|
-
|
|
103
|
-
if (target === 'cursor') {
|
|
104
|
-
await removeCursor(pluginDir);
|
|
105
|
-
} else if (target === 'claude') {
|
|
106
|
-
await removeClaude(pluginDir);
|
|
107
|
-
}
|
|
108
|
-
}
|
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
import { log } from '../../lib/io.mjs';
|
|
2
|
-
import { getFlag } from '../../lib/resolve-plugin-dir.mjs';
|
|
3
|
-
import install, { TARGETS } from './install.mjs';
|
|
4
|
-
|
|
5
|
-
export function help() {
|
|
6
|
-
log(`
|
|
7
|
-
Usage:
|
|
8
|
-
gamut plugin update [target] [options]
|
|
9
|
-
|
|
10
|
-
Update the Gamut plugin in an AI or design tool.
|
|
11
|
-
Equivalent to re-running install — replaces the existing installation in place.
|
|
12
|
-
|
|
13
|
-
Arguments:
|
|
14
|
-
target Tool to update (default: cursor)
|
|
15
|
-
cursor | claude
|
|
16
|
-
|
|
17
|
-
Options:
|
|
18
|
-
--scope <scope> Content to update (default: all)
|
|
19
|
-
all | skills | rules | agents
|
|
20
|
-
--theme <theme> Refresh ./DESIGN.md (same themes as install)
|
|
21
|
-
--force Overwrite existing DESIGN.md when using --theme
|
|
22
|
-
--plugin-dir <path> Override the bundled agent-tools directory
|
|
23
|
-
-h, --help Show this help message
|
|
24
|
-
|
|
25
|
-
Examples:
|
|
26
|
-
gamut plugin update
|
|
27
|
-
gamut plugin update claude
|
|
28
|
-
gamut plugin update cursor --theme core --force
|
|
29
|
-
gamut plugin update cursor --scope skills
|
|
30
|
-
`);
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
/**
|
|
34
|
-
* gamut plugin update [cursor|claude] [--scope all|skills|rules|agents]
|
|
35
|
-
* [--plugin-dir <path>]
|
|
36
|
-
*
|
|
37
|
-
* Re-runs install with the same arguments. For Cursor this does an in-place
|
|
38
|
-
* copy replacing any existing installation. For Claude Code it updates the
|
|
39
|
-
* marketplace entry and re-installs.
|
|
40
|
-
*
|
|
41
|
-
* @param {string[]} args
|
|
42
|
-
*/
|
|
43
|
-
export default async function update(args) {
|
|
44
|
-
const target = args.find((a) => !a.startsWith('-')) ?? 'cursor';
|
|
45
|
-
const scope = getFlag(args, '--scope', 'all') ?? 'all';
|
|
46
|
-
|
|
47
|
-
if (!TARGETS.includes(target)) {
|
|
48
|
-
throw new Error(
|
|
49
|
-
`Unknown target: "${target}". Choose from: ${TARGETS.join(', ')}`
|
|
50
|
-
);
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
log(
|
|
54
|
-
`Updating Gamut plugin for ${target}${
|
|
55
|
-
scope !== 'all' ? ` (scope: ${scope})` : ''
|
|
56
|
-
}…`
|
|
57
|
-
);
|
|
58
|
-
await install(args);
|
|
59
|
-
}
|
package/bin/gamut.mjs
DELETED
|
@@ -1,96 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
import { error, log } from './lib/io.mjs';
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Gamut CLI
|
|
7
|
-
*
|
|
8
|
-
* Usage:
|
|
9
|
-
* gamut plugin install [cursor|claude] [--scope all|skills|rules|agents]
|
|
10
|
-
* gamut plugin remove [cursor|claude]
|
|
11
|
-
* gamut plugin update [cursor|claude] [--scope all|skills|rules|agents]
|
|
12
|
-
* gamut plugin list
|
|
13
|
-
*/
|
|
14
|
-
|
|
15
|
-
const args = process.argv.slice(2);
|
|
16
|
-
const [noun, verb, ...rest] = args;
|
|
17
|
-
|
|
18
|
-
if (!noun || noun === '--help' || noun === '-h') {
|
|
19
|
-
printHelp();
|
|
20
|
-
process.exit(noun ? 0 : 1);
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
if (noun !== 'plugin') {
|
|
24
|
-
error(`Unknown command: "${noun}"`);
|
|
25
|
-
printHelp();
|
|
26
|
-
process.exit(1);
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
if (!verb || verb === '--help' || verb === '-h') {
|
|
30
|
-
printPluginHelp();
|
|
31
|
-
process.exit(verb ? 0 : 1);
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
let cmd;
|
|
35
|
-
try {
|
|
36
|
-
cmd = await import(`./commands/plugin/${verb}.mjs`);
|
|
37
|
-
} catch {
|
|
38
|
-
error(`Unknown plugin subcommand: "${verb}"`);
|
|
39
|
-
printPluginHelp();
|
|
40
|
-
process.exit(1);
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
if (rest.includes('--help') || rest.includes('-h')) {
|
|
44
|
-
cmd.help();
|
|
45
|
-
process.exit(0);
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
try {
|
|
49
|
-
await cmd.default(rest);
|
|
50
|
-
} catch (/** @type {any} */ err) {
|
|
51
|
-
error(`Error: ${err.message}`);
|
|
52
|
-
process.exit(1);
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
// ---------------------------------------------------------------------------
|
|
56
|
-
// Help
|
|
57
|
-
// ---------------------------------------------------------------------------
|
|
58
|
-
|
|
59
|
-
function printHelp() {
|
|
60
|
-
log(`
|
|
61
|
-
gamut — Gamut design system CLI
|
|
62
|
-
|
|
63
|
-
Usage:
|
|
64
|
-
gamut <command> [subcommand] [options]
|
|
65
|
-
|
|
66
|
-
Commands:
|
|
67
|
-
plugin Manage the Gamut plugin in your AI/design tools
|
|
68
|
-
|
|
69
|
-
Run "gamut plugin --help" for plugin subcommands.
|
|
70
|
-
`);
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
function printPluginHelp() {
|
|
74
|
-
log(`
|
|
75
|
-
gamut plugin — Manage the Gamut plugin
|
|
76
|
-
|
|
77
|
-
Subcommands:
|
|
78
|
-
install [target] [--scope <scope>] [--theme <theme>] Install the plugin (+ optional DESIGN.md)
|
|
79
|
-
remove [target] Remove an installed plugin
|
|
80
|
-
update [target] [--scope <scope>] [--theme <theme>] Update an installed plugin
|
|
81
|
-
list Show installation status for all targets
|
|
82
|
-
|
|
83
|
-
Targets: cursor (default) | claude
|
|
84
|
-
Scopes: all (default) | skills | rules | agents
|
|
85
|
-
Themes: core | admin | platform | percipio | lxstudio (--theme copies DESIGN.md to repo root)
|
|
86
|
-
|
|
87
|
-
Examples:
|
|
88
|
-
gamut plugin install
|
|
89
|
-
gamut plugin install claude
|
|
90
|
-
gamut plugin install cursor --theme percipio
|
|
91
|
-
gamut plugin install cursor --scope skills
|
|
92
|
-
gamut plugin remove claude
|
|
93
|
-
gamut plugin update
|
|
94
|
-
gamut plugin list
|
|
95
|
-
`);
|
|
96
|
-
}
|
package/bin/lib/claude.mjs
DELETED
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
import { readFile } from 'node:fs/promises';
|
|
2
|
-
import { join } from 'node:path';
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* Reads .claude-plugin/marketplace.json and returns a "name@marketplace" plugin spec.
|
|
6
|
-
*
|
|
7
|
-
* @param {string} sourceRoot
|
|
8
|
-
* @returns {Promise<string>}
|
|
9
|
-
*/
|
|
10
|
-
export async function claudePluginSpec(sourceRoot) {
|
|
11
|
-
const mp = join(sourceRoot, '.claude-plugin', 'marketplace.json');
|
|
12
|
-
let text;
|
|
13
|
-
try {
|
|
14
|
-
text = await readFile(mp, 'utf8');
|
|
15
|
-
} catch {
|
|
16
|
-
throw new Error(
|
|
17
|
-
`Missing ${mp}.\n` +
|
|
18
|
-
`A .claude-plugin/marketplace.json is required for Claude Code installation.`,
|
|
19
|
-
);
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
const json =
|
|
23
|
-
/** @type {{ name?: string; plugins?: Array<{ name?: string; source?: string }> }} */ (
|
|
24
|
-
JSON.parse(text)
|
|
25
|
-
);
|
|
26
|
-
const { name: marketplaceName, plugins } = json;
|
|
27
|
-
|
|
28
|
-
if (!marketplaceName || !Array.isArray(plugins) || plugins.length === 0) {
|
|
29
|
-
throw new Error(`Invalid marketplace.json — needs "name" and "plugins[]": ${mp}`);
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
const entry =
|
|
33
|
-
plugins.find((p) => p.source === './' || p.source === '.' || p.source == null) ?? plugins[0];
|
|
34
|
-
|
|
35
|
-
if (!entry?.name) {
|
|
36
|
-
throw new Error(`No plugin name found in marketplace.json plugins[]: ${mp}`);
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
return `${entry.name}@${marketplaceName}`;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
/**
|
|
43
|
-
* Returns just the marketplace name portion of a plugin spec ("name@marketplace").
|
|
44
|
-
*
|
|
45
|
-
* @param {string} spec
|
|
46
|
-
* @returns {string}
|
|
47
|
-
*/
|
|
48
|
-
export function marketplaceName(spec) {
|
|
49
|
-
const name = spec.split('@')[1];
|
|
50
|
-
if (!name) throw new Error(`Could not parse marketplace name from plugin spec: ${spec}`);
|
|
51
|
-
return name;
|
|
52
|
-
}
|
package/bin/lib/cursor.mjs
DELETED
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
import { readFile } from 'node:fs/promises';
|
|
2
|
-
import { homedir } from 'node:os';
|
|
3
|
-
import { join } from 'node:path';
|
|
4
|
-
|
|
5
|
-
/** @returns {string} */
|
|
6
|
-
export function cursorPluginsRoot() {
|
|
7
|
-
return process.env.CURSOR_PLUGINS_LOCAL ?? join(homedir(), '.cursor', 'plugins', 'local');
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* Reads the .cursor-plugin/plugin.json manifest and derives a folder name.
|
|
12
|
-
* Falls back to "gamut-agent-tools" if no manifest is found.
|
|
13
|
-
*
|
|
14
|
-
* @param {string} sourceRoot
|
|
15
|
-
* @returns {Promise<string>}
|
|
16
|
-
*/
|
|
17
|
-
export async function cursorFolderName(sourceRoot) {
|
|
18
|
-
const manifest = join(sourceRoot, '.cursor-plugin', 'plugin.json');
|
|
19
|
-
try {
|
|
20
|
-
const text = await readFile(manifest, 'utf8');
|
|
21
|
-
const json = /** @type {{ name?: string }} */ (JSON.parse(text));
|
|
22
|
-
if (json.name && typeof json.name === 'string') {
|
|
23
|
-
return json.name.replace(/^@/, '').replace(/\//g, '-');
|
|
24
|
-
}
|
|
25
|
-
} catch {
|
|
26
|
-
// no manifest — use default
|
|
27
|
-
}
|
|
28
|
-
return 'gamut-agent-tools';
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
/**
|
|
32
|
-
* Returns the absolute path where the plugin is/should be installed for Cursor.
|
|
33
|
-
*
|
|
34
|
-
* @param {string} sourceRoot
|
|
35
|
-
* @returns {Promise<string>}
|
|
36
|
-
*/
|
|
37
|
-
export async function cursorDestPath(sourceRoot) {
|
|
38
|
-
const folderName = await cursorFolderName(sourceRoot);
|
|
39
|
-
return join(cursorPluginsRoot(), folderName);
|
|
40
|
-
}
|
package/bin/lib/design.mjs
DELETED
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
import { copyFile, stat } from 'node:fs/promises';
|
|
2
|
-
import { join } from 'node:path';
|
|
3
|
-
|
|
4
|
-
/** @type {Record<string, { sourceFile: string, label: string }>} */
|
|
5
|
-
const THEME_ALIASES = {
|
|
6
|
-
core: { sourceFile: 'DESIGN.Codecademy.md', label: 'Codecademy (Core)' },
|
|
7
|
-
codecademy: {
|
|
8
|
-
sourceFile: 'DESIGN.Codecademy.md',
|
|
9
|
-
label: 'Codecademy (Core)',
|
|
10
|
-
},
|
|
11
|
-
cc: { sourceFile: 'DESIGN.Codecademy.md', label: 'Codecademy (Core)' },
|
|
12
|
-
admin: { sourceFile: 'DESIGN.Codecademy.md', label: 'Codecademy (Admin)' },
|
|
13
|
-
platform: {
|
|
14
|
-
sourceFile: 'DESIGN.Codecademy.md',
|
|
15
|
-
label: 'Codecademy (Platform)',
|
|
16
|
-
},
|
|
17
|
-
percipio: { sourceFile: 'DESIGN.Percipio.md', label: 'Percipio' },
|
|
18
|
-
lxstudio: { sourceFile: 'DESIGN.LXStudio.md', label: 'LX Studio' },
|
|
19
|
-
'lx-studio': { sourceFile: 'DESIGN.LXStudio.md', label: 'LX Studio' },
|
|
20
|
-
};
|
|
21
|
-
|
|
22
|
-
const CANONICAL_THEMES = ['core', 'admin', 'platform', 'percipio', 'lxstudio'];
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
* @param {string} name
|
|
26
|
-
* @returns {{ sourceFile: string, label: string, alias: string }}
|
|
27
|
-
*/
|
|
28
|
-
export function resolveTheme(name) {
|
|
29
|
-
const alias = name.trim().toLowerCase();
|
|
30
|
-
const entry = THEME_ALIASES[alias];
|
|
31
|
-
if (!entry) {
|
|
32
|
-
throw new Error(
|
|
33
|
-
`Unknown theme: "${name}". Choose from: ${CANONICAL_THEMES.join(', ')} ` +
|
|
34
|
-
`(aliases: codecademy, cc, lx-studio, …).`
|
|
35
|
-
);
|
|
36
|
-
}
|
|
37
|
-
return { ...entry, alias };
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
/** @returns {string[]} */
|
|
41
|
-
export function listCanonicalThemes() {
|
|
42
|
-
return [...CANONICAL_THEMES];
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
/**
|
|
46
|
-
* @param {string} sourceRoot agent-tools directory
|
|
47
|
-
* @param {string} cwd destination directory (app repo root)
|
|
48
|
-
* @param {string} theme
|
|
49
|
-
* @param {{ force?: boolean }} [options]
|
|
50
|
-
* @returns {Promise<{ dest: string, label: string }>}
|
|
51
|
-
*/
|
|
52
|
-
export async function installDesignMd(sourceRoot, cwd, theme, options = {}) {
|
|
53
|
-
const { sourceFile, label } = resolveTheme(theme);
|
|
54
|
-
const src = join(sourceRoot, sourceFile);
|
|
55
|
-
const dest = join(cwd, 'DESIGN.md');
|
|
56
|
-
|
|
57
|
-
const srcStat = await stat(src).catch(() => null);
|
|
58
|
-
if (!srcStat?.isFile()) {
|
|
59
|
-
throw new Error(`DESIGN source not found: ${src}`);
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
const destStat = await stat(dest).catch(() => null);
|
|
63
|
-
if (destStat?.isFile() && !options.force) {
|
|
64
|
-
throw new Error(
|
|
65
|
-
`DESIGN.md already exists at ${dest}. Use --force to overwrite, or remove it first.`
|
|
66
|
-
);
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
await copyFile(src, dest);
|
|
70
|
-
return { dest, label };
|
|
71
|
-
}
|
package/bin/lib/io.mjs
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
/** @param {string} message */
|
|
2
|
-
export function log(message) {
|
|
3
|
-
process.stdout.write(message.endsWith('\n') ? message : `${message}\n`);
|
|
4
|
-
}
|
|
5
|
-
|
|
6
|
-
/** @param {string} message */
|
|
7
|
-
export function warn(message) {
|
|
8
|
-
process.stderr.write(message.endsWith('\n') ? message : `${message}\n`);
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
/** @param {string} message */
|
|
12
|
-
export function error(message) {
|
|
13
|
-
process.stderr.write(message.endsWith('\n') ? message : `${message}\n`);
|
|
14
|
-
}
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
import { stat } from 'node:fs/promises';
|
|
2
|
-
import { dirname, resolve } from 'node:path';
|
|
3
|
-
import { fileURLToPath } from 'node:url';
|
|
4
|
-
|
|
5
|
-
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* Returns the absolute path to the bundled agent-tools directory, or the
|
|
9
|
-
* value of --plugin-dir if provided.
|
|
10
|
-
*
|
|
11
|
-
* @param {string[]} args
|
|
12
|
-
* @returns {Promise<string>}
|
|
13
|
-
*/
|
|
14
|
-
export async function resolvePluginDir(args) {
|
|
15
|
-
const override = getFlag(args, '--plugin-dir');
|
|
16
|
-
if (override) {
|
|
17
|
-
const abs = resolve(override);
|
|
18
|
-
const st = await stat(abs).catch(() => null);
|
|
19
|
-
if (!st?.isDirectory()) {
|
|
20
|
-
throw new Error(`--plugin-dir path not found: ${abs}`);
|
|
21
|
-
}
|
|
22
|
-
return abs;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
// agent-tools/ is bundled at <package-root>/agent-tools/ relative to bin/lib/
|
|
26
|
-
return resolve(__dirname, '..', '..', 'agent-tools');
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
/**
|
|
30
|
-
* @param {string[]} argv
|
|
31
|
-
* @param {string} flag
|
|
32
|
-
* @param {string} [fallback]
|
|
33
|
-
* @returns {string | undefined}
|
|
34
|
-
*/
|
|
35
|
-
export function getFlag(argv, flag, fallback) {
|
|
36
|
-
const idx = argv.indexOf(flag);
|
|
37
|
-
return idx !== -1 ? argv[idx + 1] : fallback;
|
|
38
|
-
}
|
package/bin/lib/run-command.mjs
DELETED
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import { spawn } from 'node:child_process';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Spawns an external command and returns its exit code.
|
|
5
|
-
*
|
|
6
|
-
* @param {string} command
|
|
7
|
-
* @param {string[]} args
|
|
8
|
-
* @returns {Promise<number>}
|
|
9
|
-
*/
|
|
10
|
-
export function runCommand(command, args) {
|
|
11
|
-
return new Promise((resolve, reject) => {
|
|
12
|
-
const child = spawn(command, args, { stdio: 'inherit', shell: false });
|
|
13
|
-
child.on('error', (/** @type {NodeJS.ErrnoException} */ err) => {
|
|
14
|
-
if (err.code === 'ENOENT') {
|
|
15
|
-
reject(new Error(`"${command}" not found on PATH. Is it installed?`));
|
|
16
|
-
} else {
|
|
17
|
-
reject(err);
|
|
18
|
-
}
|
|
19
|
-
});
|
|
20
|
-
child.on('close', (code) => resolve(code ?? 1));
|
|
21
|
-
});
|
|
22
|
-
}
|