@codecademy/gamut 68.5.2-alpha.f0a056.0 → 68.6.1-alpha.e6c390.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/agent-tools/.claude-plugin/marketplace.json +16 -0
- package/agent-tools/.claude-plugin/plugin.json +7 -0
- package/agent-tools/.cursor-plugin/plugin.json +7 -0
- package/agent-tools/DESIGN.Codecademy.md +648 -0
- package/agent-tools/DESIGN.LXStudio.md +460 -0
- package/agent-tools/DESIGN.Percipio.md +463 -0
- package/agent-tools/DESIGN.md +1 -0
- package/agent-tools/agents/.gitkeep +0 -0
- package/agent-tools/commands/gamut-review.md +170 -0
- package/agent-tools/guidelines/components/buttons.md +44 -0
- package/agent-tools/guidelines/components/overview.md +44 -0
- package/agent-tools/guidelines/foundations/color.md +86 -0
- package/agent-tools/guidelines/foundations/modes.md +47 -0
- package/agent-tools/guidelines/foundations/spacing.md +66 -0
- package/agent-tools/guidelines/foundations/typography.md +50 -0
- package/agent-tools/guidelines/overview.md +38 -0
- package/agent-tools/guidelines/setup.md +42 -0
- package/agent-tools/rules/accessibility.mdc +69 -0
- package/agent-tools/skills/gamut-accessibility/SKILL.md +239 -0
- package/agent-tools/skills/gamut-color-mode/SKILL.md +99 -0
- package/agent-tools/skills/gamut-system-props/SKILL.md +181 -0
- package/agent-tools/skills/gamut-testing/SKILL.md +181 -0
- package/agent-tools/skills/gamut-theming/SKILL.md +115 -0
- package/agent-tools/skills/gamut-typography/SKILL.md +123 -0
- package/bin/commands/plugin/install.mjs +173 -0
- package/bin/commands/plugin/list.mjs +105 -0
- package/bin/commands/plugin/remove.mjs +116 -0
- package/bin/commands/plugin/update.mjs +49 -0
- package/bin/gamut.mjs +92 -0
- package/bin/lib/claude.mjs +52 -0
- package/bin/lib/cursor.mjs +40 -0
- package/bin/lib/figma.mjs +49 -0
- package/bin/lib/resolve-plugin-dir.mjs +38 -0
- package/bin/lib/run-command.mjs +22 -0
- package/package.json +11 -8
|
@@ -0,0 +1,116 @@
|
|
|
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 { resolveFigmaOutput } from '../../lib/figma.mjs';
|
|
6
|
+
import { getFlag, 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
|
+
console.log(`
|
|
12
|
+
Usage:
|
|
13
|
+
gamut plugin remove [target] [options]
|
|
14
|
+
|
|
15
|
+
Remove the installed Gamut plugin from an AI or design tool.
|
|
16
|
+
|
|
17
|
+
Arguments:
|
|
18
|
+
target Tool to remove from (default: cursor)
|
|
19
|
+
cursor | claude | figma
|
|
20
|
+
|
|
21
|
+
Options:
|
|
22
|
+
--output <path> [figma] Path to the DESIGN.md that was installed.
|
|
23
|
+
If omitted, walks up from cwd to find figma.config.json.
|
|
24
|
+
--plugin-dir <path> Override the bundled agent-tools directory
|
|
25
|
+
-h, --help Show this help message
|
|
26
|
+
|
|
27
|
+
Examples:
|
|
28
|
+
gamut plugin remove
|
|
29
|
+
gamut plugin remove claude
|
|
30
|
+
gamut plugin remove figma
|
|
31
|
+
gamut plugin remove figma --output ./docs/DESIGN.md
|
|
32
|
+
`);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// ---------------------------------------------------------------------------
|
|
36
|
+
|
|
37
|
+
/** @param {string} sourceRoot */
|
|
38
|
+
async function removeCursor(sourceRoot) {
|
|
39
|
+
const dest = await cursorDestPath(sourceRoot);
|
|
40
|
+
const st = await stat(dest).catch(() => null);
|
|
41
|
+
|
|
42
|
+
if (!st) {
|
|
43
|
+
console.log(`Cursor: nothing to remove — ${dest} does not exist.`);
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
await rm(dest, { recursive: true, force: true });
|
|
48
|
+
console.log(`Cursor: removed ${dest}`);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/** @param {string} sourceRoot */
|
|
52
|
+
async function removeClaude(sourceRoot) {
|
|
53
|
+
const spec = await claudePluginSpec(sourceRoot);
|
|
54
|
+
const mpName = marketplaceName(spec);
|
|
55
|
+
const pluginName = spec.split('@')[0];
|
|
56
|
+
|
|
57
|
+
let code = await runCommand('claude', ['plugin', 'remove', pluginName, '--scope', 'user']);
|
|
58
|
+
if (code !== 0) {
|
|
59
|
+
console.warn(
|
|
60
|
+
`warning: "claude plugin remove" exited ${code} — the plugin may not have been installed.`,
|
|
61
|
+
);
|
|
62
|
+
} else {
|
|
63
|
+
console.log(`Claude Code: removed plugin "${pluginName}"`);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
code = await runCommand('claude', ['plugin', 'marketplace', 'remove', mpName]);
|
|
67
|
+
if (code !== 0) {
|
|
68
|
+
console.warn(
|
|
69
|
+
`warning: "claude plugin marketplace remove" exited ${code} — ` +
|
|
70
|
+
`the marketplace entry may not exist or the command syntax may differ. ` +
|
|
71
|
+
`Run "claude plugin marketplace list" to check.`,
|
|
72
|
+
);
|
|
73
|
+
} else {
|
|
74
|
+
console.log(`Claude Code: removed marketplace "${mpName}"`);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/** @param {string | undefined} outputArg */
|
|
79
|
+
async function removeFigma(outputArg) {
|
|
80
|
+
const { path: dest } = await resolveFigmaOutput(outputArg);
|
|
81
|
+
const st = await stat(dest).catch(() => null);
|
|
82
|
+
|
|
83
|
+
if (!st) {
|
|
84
|
+
console.log(`Figma: nothing to remove — ${dest} does not exist.`);
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
await rm(dest, { force: true });
|
|
89
|
+
console.log(`Figma: removed ${dest}`);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// ---------------------------------------------------------------------------
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* gamut plugin remove [cursor|claude|figma] [--plugin-dir <path>]
|
|
96
|
+
*
|
|
97
|
+
* @param {string[]} args
|
|
98
|
+
*/
|
|
99
|
+
export default async function remove(args) {
|
|
100
|
+
const target = args.find((a) => !a.startsWith('-')) ?? 'cursor';
|
|
101
|
+
|
|
102
|
+
if (!TARGETS.includes(target)) {
|
|
103
|
+
throw new Error(`Unknown target: "${target}". Choose from: ${TARGETS.join(', ')}`);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
const pluginDir = await resolvePluginDir(args);
|
|
107
|
+
|
|
108
|
+
if (target === 'cursor') {
|
|
109
|
+
await removeCursor(pluginDir);
|
|
110
|
+
} else if (target === 'claude') {
|
|
111
|
+
await removeClaude(pluginDir);
|
|
112
|
+
} else if (target === 'figma') {
|
|
113
|
+
const output = getFlag(args, '--output', undefined);
|
|
114
|
+
await removeFigma(output);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { getFlag } from '../../lib/resolve-plugin-dir.mjs';
|
|
2
|
+
import install, { TARGETS } from './install.mjs';
|
|
3
|
+
|
|
4
|
+
export function help() {
|
|
5
|
+
console.log(`
|
|
6
|
+
Usage:
|
|
7
|
+
gamut plugin update [target] [options]
|
|
8
|
+
|
|
9
|
+
Update the Gamut plugin in an AI or design tool.
|
|
10
|
+
Equivalent to re-running install — replaces the existing installation in place.
|
|
11
|
+
|
|
12
|
+
Arguments:
|
|
13
|
+
target Tool to update (default: cursor)
|
|
14
|
+
cursor | claude | figma
|
|
15
|
+
|
|
16
|
+
Options:
|
|
17
|
+
--scope <scope> Content to update (default: all)
|
|
18
|
+
all | skills | rules | commands | agents
|
|
19
|
+
--plugin-dir <path> Override the bundled agent-tools directory
|
|
20
|
+
-h, --help Show this help message
|
|
21
|
+
|
|
22
|
+
Examples:
|
|
23
|
+
gamut plugin update
|
|
24
|
+
gamut plugin update claude
|
|
25
|
+
gamut plugin update cursor --scope skills
|
|
26
|
+
`);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* gamut plugin update [cursor|claude|figma] [--scope all|skills|rules|commands|agents]
|
|
31
|
+
* [--plugin-dir <path>]
|
|
32
|
+
*
|
|
33
|
+
* Re-runs install with the same arguments. For Cursor this does an in-place
|
|
34
|
+
* copy replacing any existing installation. For Claude Code it updates the
|
|
35
|
+
* marketplace entry and re-installs.
|
|
36
|
+
*
|
|
37
|
+
* @param {string[]} args
|
|
38
|
+
*/
|
|
39
|
+
export default async function update(args) {
|
|
40
|
+
const target = args.find((a) => !a.startsWith('-')) ?? 'cursor';
|
|
41
|
+
const scope = getFlag(args, '--scope', 'all') ?? 'all';
|
|
42
|
+
|
|
43
|
+
if (!TARGETS.includes(target)) {
|
|
44
|
+
throw new Error(`Unknown target: "${target}". Choose from: ${TARGETS.join(', ')}`);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
console.log(`Updating Gamut plugin for ${target}${scope !== 'all' ? ` (scope: ${scope})` : ''}…`);
|
|
48
|
+
await install(args);
|
|
49
|
+
}
|
package/bin/gamut.mjs
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Gamut CLI
|
|
5
|
+
*
|
|
6
|
+
* Usage:
|
|
7
|
+
* gamut plugin install [cursor|claude|figma] [--scope all|skills|rules|commands|agents]
|
|
8
|
+
* gamut plugin remove [cursor|claude|figma]
|
|
9
|
+
* gamut plugin update [cursor|claude|figma] [--scope all|skills|rules|commands|agents]
|
|
10
|
+
* gamut plugin list
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
const args = process.argv.slice(2);
|
|
14
|
+
const [noun, verb, ...rest] = args;
|
|
15
|
+
|
|
16
|
+
if (!noun || noun === '--help' || noun === '-h') {
|
|
17
|
+
printHelp();
|
|
18
|
+
process.exit(noun ? 0 : 1);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
if (noun !== 'plugin') {
|
|
22
|
+
console.error(`Unknown command: "${noun}"`);
|
|
23
|
+
printHelp();
|
|
24
|
+
process.exit(1);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
if (!verb || verb === '--help' || verb === '-h') {
|
|
28
|
+
printPluginHelp();
|
|
29
|
+
process.exit(verb ? 0 : 1);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
let cmd;
|
|
33
|
+
try {
|
|
34
|
+
cmd = await import(`./commands/plugin/${verb}.mjs`);
|
|
35
|
+
} catch {
|
|
36
|
+
console.error(`Unknown plugin subcommand: "${verb}"`);
|
|
37
|
+
printPluginHelp();
|
|
38
|
+
process.exit(1);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if (rest.includes('--help') || rest.includes('-h')) {
|
|
42
|
+
cmd.help();
|
|
43
|
+
process.exit(0);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
try {
|
|
47
|
+
await cmd.default(rest);
|
|
48
|
+
} catch (/** @type {any} */ err) {
|
|
49
|
+
console.error(`Error: ${err.message}`);
|
|
50
|
+
process.exit(1);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// ---------------------------------------------------------------------------
|
|
54
|
+
// Help
|
|
55
|
+
// ---------------------------------------------------------------------------
|
|
56
|
+
|
|
57
|
+
function printHelp() {
|
|
58
|
+
console.log(`
|
|
59
|
+
gamut — Gamut design system CLI
|
|
60
|
+
|
|
61
|
+
Usage:
|
|
62
|
+
gamut <command> [subcommand] [options]
|
|
63
|
+
|
|
64
|
+
Commands:
|
|
65
|
+
plugin Manage the Gamut plugin in your AI/design tools
|
|
66
|
+
|
|
67
|
+
Run "gamut plugin --help" for plugin subcommands.
|
|
68
|
+
`);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function printPluginHelp() {
|
|
72
|
+
console.log(`
|
|
73
|
+
gamut plugin — Manage the Gamut plugin
|
|
74
|
+
|
|
75
|
+
Subcommands:
|
|
76
|
+
install [target] [--scope <scope>] Install the plugin into a tool
|
|
77
|
+
remove [target] Remove an installed plugin
|
|
78
|
+
update [target] [--scope <scope>] Update an already-installed plugin
|
|
79
|
+
list Show installation status for all targets
|
|
80
|
+
|
|
81
|
+
Targets: cursor (default) | claude | figma
|
|
82
|
+
Scopes: all (default) | skills | rules | commands | agents
|
|
83
|
+
|
|
84
|
+
Examples:
|
|
85
|
+
gamut plugin install
|
|
86
|
+
gamut plugin install claude
|
|
87
|
+
gamut plugin install cursor --scope skills
|
|
88
|
+
gamut plugin remove claude
|
|
89
|
+
gamut plugin update
|
|
90
|
+
gamut plugin list
|
|
91
|
+
`);
|
|
92
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
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
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
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
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { stat } from 'node:fs/promises';
|
|
2
|
+
import { dirname, join, resolve } from 'node:path';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Walk up from `startDir` looking for a `figma.config.json` file.
|
|
6
|
+
* Returns the directory containing it, or null if not found before the filesystem root.
|
|
7
|
+
*
|
|
8
|
+
* @param {string} startDir
|
|
9
|
+
* @returns {Promise<string | null>}
|
|
10
|
+
*/
|
|
11
|
+
export async function findFigmaConfigDir(startDir) {
|
|
12
|
+
let dir = startDir;
|
|
13
|
+
while (true) {
|
|
14
|
+
const st = await stat(join(dir, 'figma.config.json')).catch(() => null);
|
|
15
|
+
if (st?.isFile()) return dir;
|
|
16
|
+
const parent = dirname(dir);
|
|
17
|
+
if (parent === dir) return null;
|
|
18
|
+
dir = parent;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Resolves the destination directory for the guidelines/ folder.
|
|
24
|
+
*
|
|
25
|
+
* Priority:
|
|
26
|
+
* 1. --output <path> if provided (treated as the parent directory)
|
|
27
|
+
* 2. Directory containing the nearest figma.config.json (walking up from cwd)
|
|
28
|
+
*
|
|
29
|
+
* Throws with actionable guidance if neither resolves.
|
|
30
|
+
*
|
|
31
|
+
* @param {string | undefined} outputArg
|
|
32
|
+
* @returns {Promise<{ path: string; discovered: boolean }>}
|
|
33
|
+
*/
|
|
34
|
+
export async function resolveFigmaOutput(outputArg) {
|
|
35
|
+
if (outputArg) {
|
|
36
|
+
return { path: resolve(outputArg), discovered: false };
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const dir = await findFigmaConfigDir(process.cwd());
|
|
40
|
+
if (dir) {
|
|
41
|
+
return { path: join(dir, 'guidelines'), discovered: true };
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
throw new Error(
|
|
45
|
+
`Could not find figma.config.json in ${process.cwd()} or any parent directory.\n` +
|
|
46
|
+
`Provide the destination explicitly with --output:\n` +
|
|
47
|
+
` gamut plugin install figma --output /path/to/your/project/guidelines`,
|
|
48
|
+
);
|
|
49
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
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
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
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
|
+
}
|
package/package.json
CHANGED
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@codecademy/gamut",
|
|
3
3
|
"description": "Styleguide & Component library for Codecademy",
|
|
4
|
-
"version": "68.
|
|
4
|
+
"version": "68.6.1-alpha.e6c390.0",
|
|
5
5
|
"author": "Codecademy Engineering <dev@codecademy.com>",
|
|
6
|
+
"bin": "./bin/gamut.mjs",
|
|
6
7
|
"dependencies": {
|
|
7
|
-
"@codecademy/gamut-icons": "9.57.
|
|
8
|
-
"@codecademy/gamut-illustrations": "0.58.
|
|
9
|
-
"@codecademy/gamut-patterns": "0.10.
|
|
10
|
-
"@codecademy/gamut-styles": "
|
|
11
|
-
"@codecademy/variance": "0.26.2-alpha.
|
|
8
|
+
"@codecademy/gamut-icons": "9.57.6-alpha.e6c390.0",
|
|
9
|
+
"@codecademy/gamut-illustrations": "0.58.12-alpha.e6c390.0",
|
|
10
|
+
"@codecademy/gamut-patterns": "0.10.31-alpha.e6c390.0",
|
|
11
|
+
"@codecademy/gamut-styles": "18.0.1-alpha.e6c390.0",
|
|
12
|
+
"@codecademy/variance": "0.26.2-alpha.e6c390.0",
|
|
12
13
|
"@formatjs/intl-locale": "5.3.1",
|
|
13
14
|
"@react-aria/interactions": "3.25.0",
|
|
14
15
|
"@types/marked": "^4.0.8",
|
|
@@ -30,7 +31,9 @@
|
|
|
30
31
|
"sanitize-markdown": "^2.6.7"
|
|
31
32
|
},
|
|
32
33
|
"files": [
|
|
33
|
-
"dist"
|
|
34
|
+
"dist",
|
|
35
|
+
"bin",
|
|
36
|
+
"agent-tools"
|
|
34
37
|
],
|
|
35
38
|
"license": "MIT",
|
|
36
39
|
"main": "./dist/index.js",
|
|
@@ -52,7 +55,7 @@
|
|
|
52
55
|
"build": "nx build @codecademy/gamut",
|
|
53
56
|
"build:watch": "yarn build && onchange ./src -- yarn build",
|
|
54
57
|
"compile": "babel ./src --out-dir ./dist --extensions \".ts,.tsx\"",
|
|
55
|
-
"verify": "tsc --noEmit"
|
|
58
|
+
"verify": "tsc --noEmit && tsc --project tsconfig.bin.json"
|
|
56
59
|
},
|
|
57
60
|
"sideEffects": [
|
|
58
61
|
"**/*.css",
|