@codecademy/gamut 68.6.2-alpha.f8b396.0 → 68.6.3-alpha.57e1cd.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.
Files changed (39) hide show
  1. package/dist/DatePicker/DatePicker.js +5 -2
  2. package/dist/DatePicker/DatePickerCalendar/Calendar/CalendarBody.js +4 -3
  3. package/dist/DatePicker/DatePickerInput/Segment/index.js +1 -1
  4. package/dist/DatePicker/DatePickerInput/index.d.ts +4 -0
  5. package/dist/DatePicker/DatePickerInput/index.js +10 -13
  6. package/dist/DatePicker/types.d.ts +6 -0
  7. package/package.json +8 -11
  8. package/agent-tools/.claude-plugin/marketplace.json +0 -16
  9. package/agent-tools/.claude-plugin/plugin.json +0 -7
  10. package/agent-tools/.cursor-plugin/plugin.json +0 -7
  11. package/agent-tools/DESIGN.Codecademy.md +0 -643
  12. package/agent-tools/DESIGN.LXStudio.md +0 -437
  13. package/agent-tools/DESIGN.Percipio.md +0 -433
  14. package/agent-tools/DESIGN.md +0 -1
  15. package/agent-tools/agents/.gitkeep +0 -0
  16. package/agent-tools/rules/accessibility.mdc +0 -78
  17. package/agent-tools/skills/gamut-accessibility/SKILL.md +0 -214
  18. package/agent-tools/skills/gamut-buttons/SKILL.md +0 -96
  19. package/agent-tools/skills/gamut-color-mode/SKILL.md +0 -257
  20. package/agent-tools/skills/gamut-forms/SKILL.md +0 -84
  21. package/agent-tools/skills/gamut-layout/SKILL.md +0 -109
  22. package/agent-tools/skills/gamut-list/SKILL.md +0 -273
  23. package/agent-tools/skills/gamut-review/SKILL.md +0 -254
  24. package/agent-tools/skills/gamut-style-utilities/SKILL.md +0 -107
  25. package/agent-tools/skills/gamut-system-props/SKILL.md +0 -203
  26. package/agent-tools/skills/gamut-testing/SKILL.md +0 -221
  27. package/agent-tools/skills/gamut-theming/SKILL.md +0 -115
  28. package/agent-tools/skills/gamut-typography/SKILL.md +0 -98
  29. package/bin/commands/plugin/install.mjs +0 -212
  30. package/bin/commands/plugin/list.mjs +0 -73
  31. package/bin/commands/plugin/remove.mjs +0 -108
  32. package/bin/commands/plugin/update.mjs +0 -59
  33. package/bin/gamut.mjs +0 -96
  34. package/bin/lib/claude.mjs +0 -52
  35. package/bin/lib/cursor.mjs +0 -40
  36. package/bin/lib/design.mjs +0 -71
  37. package/bin/lib/io.mjs +0 -14
  38. package/bin/lib/resolve-plugin-dir.mjs +0 -38
  39. 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
- }
@@ -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
- }
@@ -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
- }
@@ -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
- }
@@ -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
- }