@codecademy/gamut 68.6.1-alpha.f6b2ce.0 → 68.6.2-alpha.1fc7ca.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/dist/Modals/elements.d.ts +186 -1
- package/dist/Modals/elements.js +3 -3
- package/dist/{InternalFloatingCard/InternalFloatingCard.d.ts → PatternBackdrop/PatternBackdrop.d.ts} +8 -24
- package/dist/PatternBackdrop/PatternBackdrop.js +42 -0
- package/dist/Toast/Toast.js +4 -4
- 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 -696
- package/agent-tools/DESIGN.LXStudio.md +0 -512
- package/agent-tools/DESIGN.Percipio.md +0 -513
- package/agent-tools/DESIGN.md +0 -1
- package/agent-tools/agents/.gitkeep +0 -0
- package/agent-tools/commands/gamut-review.md +0 -259
- package/agent-tools/guidelines/components/animations.md +0 -74
- package/agent-tools/guidelines/components/buttons.md +0 -95
- package/agent-tools/guidelines/components/card.md +0 -19
- package/agent-tools/guidelines/components/coachmark.md +0 -21
- package/agent-tools/guidelines/components/data-table.md +0 -79
- package/agent-tools/guidelines/components/forms.md +0 -106
- package/agent-tools/guidelines/components/loading-states.md +0 -17
- package/agent-tools/guidelines/components/menu.md +0 -58
- package/agent-tools/guidelines/components/overview.md +0 -124
- package/agent-tools/guidelines/components/radial-progress.md +0 -13
- package/agent-tools/guidelines/components/select.md +0 -23
- package/agent-tools/guidelines/components/tooltips.md +0 -22
- package/agent-tools/guidelines/components/video.md +0 -29
- package/agent-tools/guidelines/foundations/color.md +0 -168
- package/agent-tools/guidelines/foundations/modes.md +0 -69
- package/agent-tools/guidelines/foundations/spacing.md +0 -107
- package/agent-tools/guidelines/foundations/typography.md +0 -82
- package/agent-tools/guidelines/overview-icons.md +0 -19
- package/agent-tools/guidelines/overview-illustrations.md +0 -7
- package/agent-tools/guidelines/overview-patterns.md +0 -7
- package/agent-tools/guidelines/overview.md +0 -84
- package/agent-tools/guidelines/setup.md +0 -83
- package/agent-tools/rules/accessibility.mdc +0 -78
- package/agent-tools/skills/gamut-accessibility/SKILL.md +0 -224
- package/agent-tools/skills/gamut-color-mode/SKILL.md +0 -149
- package/agent-tools/skills/gamut-components/SKILL.md +0 -46
- package/agent-tools/skills/gamut-forms/SKILL.md +0 -101
- package/agent-tools/skills/gamut-style-utilities/SKILL.md +0 -111
- package/agent-tools/skills/gamut-system-props/SKILL.md +0 -225
- package/agent-tools/skills/gamut-testing/SKILL.md +0 -225
- package/agent-tools/skills/gamut-theming/SKILL.md +0 -63
- package/agent-tools/skills/gamut-typography/SKILL.md +0 -79
- package/bin/commands/plugin/install.mjs +0 -213
- 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
- package/dist/InternalFloatingCard/InternalFloatingCard.js +0 -98
|
@@ -1,213 +0,0 @@
|
|
|
1
|
-
import { cp, mkdir, readdir, rm, symlink } from 'node:fs/promises';
|
|
2
|
-
import { resolve } from 'node:path';
|
|
3
|
-
|
|
4
|
-
import { claudePluginSpec, marketplaceName } from '../../lib/claude.mjs';
|
|
5
|
-
import { cursorDestPath } from '../../lib/cursor.mjs';
|
|
6
|
-
import {
|
|
7
|
-
installDesignMd,
|
|
8
|
-
listCanonicalThemes,
|
|
9
|
-
resolveTheme,
|
|
10
|
-
} from '../../lib/design.mjs';
|
|
11
|
-
import { log, warn } from '../../lib/io.mjs';
|
|
12
|
-
import { getFlag, resolvePluginDir } from '../../lib/resolve-plugin-dir.mjs';
|
|
13
|
-
import { runCommand } from '../../lib/run-command.mjs';
|
|
14
|
-
|
|
15
|
-
export const TARGETS = ['cursor', 'claude'];
|
|
16
|
-
export const SCOPES = ['all', 'skills', 'rules', 'commands', 'agents'];
|
|
17
|
-
|
|
18
|
-
export function help() {
|
|
19
|
-
log(`
|
|
20
|
-
Usage:
|
|
21
|
-
gamut plugin install [target] [options]
|
|
22
|
-
|
|
23
|
-
Install the Gamut plugin into an AI tool.
|
|
24
|
-
|
|
25
|
-
Arguments:
|
|
26
|
-
target Tool to install into (default: cursor)
|
|
27
|
-
cursor | claude
|
|
28
|
-
|
|
29
|
-
Options:
|
|
30
|
-
--scope <scope> Content to install (default: all)
|
|
31
|
-
all | skills | rules | commands | agents
|
|
32
|
-
--theme <theme> Copy DESIGN.*.md to ./DESIGN.md in the current directory
|
|
33
|
-
core | admin | platform | percipio | lxstudio
|
|
34
|
-
(admin/platform use Codecademy DESIGN; aliases: codecademy, cc, lx-studio)
|
|
35
|
-
--force Overwrite existing DESIGN.md when using --theme
|
|
36
|
-
--plugin-dir <path> Override the bundled agent-tools directory
|
|
37
|
-
-h, --help Show this help message
|
|
38
|
-
|
|
39
|
-
Examples:
|
|
40
|
-
gamut plugin install
|
|
41
|
-
gamut plugin install claude
|
|
42
|
-
gamut plugin install cursor --theme core
|
|
43
|
-
gamut plugin install cursor --theme percipio --force
|
|
44
|
-
gamut plugin install cursor --scope skills
|
|
45
|
-
gamut plugin install cursor --plugin-dir ./my-agent-tools
|
|
46
|
-
`);
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
// ---------------------------------------------------------------------------
|
|
50
|
-
|
|
51
|
-
/** Directories in the plugin source that should not be installed to Cursor. */
|
|
52
|
-
const CURSOR_IGNORE = new Set([
|
|
53
|
-
'.claude-plugin', // Claude Code manifest — not a Cursor concept
|
|
54
|
-
]);
|
|
55
|
-
|
|
56
|
-
/** @param {string} sourceRoot @param {string} scope */
|
|
57
|
-
async function installCursor(sourceRoot, scope) {
|
|
58
|
-
const dest = await cursorDestPath(sourceRoot);
|
|
59
|
-
|
|
60
|
-
if ((process.env.CURSOR_INSTALL_METHOD ?? 'copy') !== 'copy') {
|
|
61
|
-
// Symlink the whole plugin dir (dev convenience)
|
|
62
|
-
await rm(dest, { recursive: true, force: true });
|
|
63
|
-
await symlink(resolve(sourceRoot), dest, 'dir');
|
|
64
|
-
log(`Cursor: symlinked to ${dest}`);
|
|
65
|
-
return;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
// Selective copy: always include the cursor manifest, then scoped content dirs
|
|
69
|
-
await rm(dest, { recursive: true, force: true });
|
|
70
|
-
await mkdir(dest, { recursive: true });
|
|
71
|
-
|
|
72
|
-
await cp(`${sourceRoot}/.cursor-plugin`, `${dest}/.cursor-plugin`, {
|
|
73
|
-
recursive: true,
|
|
74
|
-
});
|
|
75
|
-
|
|
76
|
-
let dirs;
|
|
77
|
-
if (scope === 'all') {
|
|
78
|
-
const entries = await readdir(sourceRoot, { withFileTypes: true });
|
|
79
|
-
dirs = entries
|
|
80
|
-
.filter(
|
|
81
|
-
(e) =>
|
|
82
|
-
e.isDirectory() &&
|
|
83
|
-
!e.name.startsWith('.') &&
|
|
84
|
-
!CURSOR_IGNORE.has(e.name)
|
|
85
|
-
)
|
|
86
|
-
.map((e) => e.name);
|
|
87
|
-
} else {
|
|
88
|
-
dirs = [scope];
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
await Promise.all(
|
|
92
|
-
dirs.map((dir) =>
|
|
93
|
-
cp(`${sourceRoot}/${dir}`, `${dest}/${dir}`, { recursive: true }).catch(
|
|
94
|
-
() => {
|
|
95
|
-
// directory may be empty/missing — not an error
|
|
96
|
-
}
|
|
97
|
-
)
|
|
98
|
-
)
|
|
99
|
-
);
|
|
100
|
-
|
|
101
|
-
const scopeLabel = scope === 'all' ? 'all content' : scope;
|
|
102
|
-
log(`Cursor: installed (${scopeLabel}) → ${dest}`);
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
// Claude Code only loads from recognized plugin directories: skills/, commands/, agents/.
|
|
106
|
-
// rules/ is Cursor-specific (.mdc format). guidelines/ is installed to Cursor and is
|
|
107
|
-
// also source for the Figma Make kit; Claude marketplace registers the full sourceRoot.
|
|
108
|
-
|
|
109
|
-
/** @param {string} sourceRoot */
|
|
110
|
-
async function installClaude(sourceRoot) {
|
|
111
|
-
const spec = await claudePluginSpec(sourceRoot);
|
|
112
|
-
const mpName = marketplaceName(spec);
|
|
113
|
-
const root = resolve(sourceRoot);
|
|
114
|
-
|
|
115
|
-
let code = await runCommand('claude', [
|
|
116
|
-
'plugin',
|
|
117
|
-
'marketplace',
|
|
118
|
-
'add',
|
|
119
|
-
root,
|
|
120
|
-
'--scope',
|
|
121
|
-
'user',
|
|
122
|
-
]);
|
|
123
|
-
if (code !== 0) {
|
|
124
|
-
warn(
|
|
125
|
-
`warning: "claude plugin marketplace add" exited ${code} — ` +
|
|
126
|
-
`if it's already registered this is safe to ignore.`
|
|
127
|
-
);
|
|
128
|
-
code = await runCommand('claude', [
|
|
129
|
-
'plugin',
|
|
130
|
-
'marketplace',
|
|
131
|
-
'update',
|
|
132
|
-
mpName,
|
|
133
|
-
]);
|
|
134
|
-
if (code !== 0) {
|
|
135
|
-
throw new Error(
|
|
136
|
-
`claude plugin marketplace add/update failed (exit ${code}).\n` +
|
|
137
|
-
`Try manually: claude plugin marketplace add ${root}`
|
|
138
|
-
);
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
code = await runCommand('claude', [
|
|
143
|
-
'plugin',
|
|
144
|
-
'install',
|
|
145
|
-
spec,
|
|
146
|
-
'--scope',
|
|
147
|
-
'user',
|
|
148
|
-
]);
|
|
149
|
-
if (code !== 0) {
|
|
150
|
-
throw new Error(
|
|
151
|
-
`claude plugin install failed (exit ${code}).\n` +
|
|
152
|
-
`Try manually: claude plugin install ${spec} --scope user`
|
|
153
|
-
);
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
log(`Claude Code: installed ${spec} (user scope)`);
|
|
157
|
-
log(
|
|
158
|
-
` Tip: run /reload-plugins in Claude Code if skills don't appear immediately.`
|
|
159
|
-
);
|
|
160
|
-
log(` One-off without install: claude --plugin-dir ${root}`);
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
// ---------------------------------------------------------------------------
|
|
164
|
-
|
|
165
|
-
/**
|
|
166
|
-
* gamut plugin install [cursor|claude] [--scope all|skills|rules|commands|agents]
|
|
167
|
-
* [--plugin-dir <path>]
|
|
168
|
-
*
|
|
169
|
-
* @param {string[]} args
|
|
170
|
-
*/
|
|
171
|
-
export default async function install(args) {
|
|
172
|
-
const target = args.find((a) => !a.startsWith('-')) ?? 'cursor';
|
|
173
|
-
const scope = getFlag(args, '--scope', 'all') ?? 'all';
|
|
174
|
-
|
|
175
|
-
if (!TARGETS.includes(target)) {
|
|
176
|
-
throw new Error(
|
|
177
|
-
`Unknown target: "${target}". Choose from: ${TARGETS.join(', ')}`
|
|
178
|
-
);
|
|
179
|
-
}
|
|
180
|
-
if (!SCOPES.includes(scope)) {
|
|
181
|
-
throw new Error(
|
|
182
|
-
`Unknown scope: "${scope}". Choose from: ${SCOPES.join(', ')}`
|
|
183
|
-
);
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
const pluginDir = await resolvePluginDir(args);
|
|
187
|
-
const theme = getFlag(args, '--theme');
|
|
188
|
-
const force = args.includes('--force');
|
|
189
|
-
|
|
190
|
-
if (theme) {
|
|
191
|
-
resolveTheme(theme);
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
if (target === 'cursor') {
|
|
195
|
-
await installCursor(pluginDir, scope);
|
|
196
|
-
} else if (target === 'claude') {
|
|
197
|
-
await installClaude(pluginDir);
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
if (theme) {
|
|
201
|
-
const { dest, label } = await installDesignMd(
|
|
202
|
-
pluginDir,
|
|
203
|
-
process.cwd(),
|
|
204
|
-
theme,
|
|
205
|
-
{
|
|
206
|
-
force,
|
|
207
|
-
}
|
|
208
|
-
);
|
|
209
|
-
log(`DESIGN.md: installed (${label}) → ${dest}`);
|
|
210
|
-
}
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
export { listCanonicalThemes };
|
|
@@ -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 | commands | 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|commands|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|commands|agents]
|
|
10
|
-
* gamut plugin remove [cursor|claude]
|
|
11
|
-
* gamut plugin update [cursor|claude] [--scope all|skills|rules|commands|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 | commands | 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
|
-
}
|