get-shit-pretty 0.4.0 → 0.4.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/README.md +15 -15
- package/VERSION +1 -0
- package/agents/custom/.gitkeep +0 -0
- package/agents/gsp-ascii-artist.md +63 -0
- package/agents/gsp-auditor.md +2 -2
- package/agents/gsp-builder.md +60 -24
- package/agents/gsp-codebase-scanner.md +2 -2
- package/agents/gsp-critic.md +2 -2
- package/agents/gsp-designer.md +18 -2
- package/agents/gsp-project-researcher.md +2 -2
- package/agents/gsp-researcher.md +2 -2
- package/agents/gsp-reviewer.md +39 -21
- package/agents/gsp-scoper.md +2 -2
- package/agents/gsp-system-architect.md +2 -2
- package/bin/install.js +181 -63
- package/commands/gsp/add-reference.md +96 -0
- package/commands/gsp/art.md +54 -0
- package/commands/gsp/brand-audit.md +2 -2
- package/commands/gsp/brand-identity.md +31 -24
- package/commands/gsp/brand-patterns.md +31 -19
- package/commands/gsp/brand-research.md +19 -5
- package/commands/gsp/brand-strategy.md +22 -12
- package/commands/gsp/brand-verbal.md +24 -14
- package/commands/gsp/doctor.md +8 -8
- package/commands/gsp/help.md +105 -98
- package/commands/gsp/launch.md +1 -1
- package/commands/gsp/pretty.md +61 -0
- package/commands/gsp/progress.md +157 -45
- package/commands/gsp/{brief.md → project-brief.md} +22 -7
- package/commands/gsp/project-build.md +141 -0
- package/commands/gsp/{critique.md → project-critique.md} +47 -8
- package/commands/gsp/{design.md → project-design.md} +40 -8
- package/commands/gsp/{research.md → project-research.md} +26 -7
- package/commands/gsp/{review.md → project-review.md} +55 -14
- package/commands/gsp/{new.md → start.md} +112 -27
- package/package.json +4 -3
- package/prompts/09-design-to-code-translator.md +12 -6
- package/prompts/11-deliverable-reviewer.md +21 -12
- package/references/phase-transitions.md +96 -0
- package/references/questioning.md +10 -4
- package/references/terminal-art.md +196 -0
- package/templates/branding/config.json +1 -1
- package/templates/codebase-inventory.md +1 -1
- package/templates/exports-index.md +14 -6
- package/templates/phases/build.md +36 -20
- package/templates/phases/design.md +8 -0
- package/templates/phases/review.md +12 -12
- package/templates/projects/config.json +2 -7
- package/templates/projects/roadmap.md +6 -6
- package/templates/projects/state.md +8 -0
- package/commands/gsp/brand-discover.md +0 -17
- package/commands/gsp/brand-system.md +0 -17
- package/commands/gsp/brand.md +0 -20
- package/commands/gsp/build.md +0 -92
- package/commands/gsp/discover.md +0 -17
- package/commands/gsp/identity.md +0 -18
- package/commands/gsp/new-project.md +0 -17
- package/commands/gsp/plan.md +0 -18
- package/commands/gsp/strategy.md +0 -18
- package/commands/gsp/system.md +0 -17
- package/commands/gsp/verbal.md +0 -18
package/bin/install.js
CHANGED
|
@@ -5,14 +5,82 @@ const path = require('path');
|
|
|
5
5
|
const os = require('os');
|
|
6
6
|
const readline = require('readline');
|
|
7
7
|
|
|
8
|
-
//
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
const
|
|
15
|
-
|
|
8
|
+
// ── Color tier detection ──
|
|
9
|
+
|
|
10
|
+
function getColorTier() {
|
|
11
|
+
if (process.env.NO_COLOR !== undefined) return 'none';
|
|
12
|
+
if (!process.stdout.isTTY) return 'none';
|
|
13
|
+
if (process.env.FORCE_COLOR !== undefined) {
|
|
14
|
+
const level = parseInt(process.env.FORCE_COLOR, 10);
|
|
15
|
+
if (level >= 3) return 'truecolor';
|
|
16
|
+
if (level >= 2) return '256';
|
|
17
|
+
if (level >= 1) return '16';
|
|
18
|
+
return 'none';
|
|
19
|
+
}
|
|
20
|
+
if (process.env.COLORTERM === 'truecolor' || process.env.COLORTERM === '24bit') return 'truecolor';
|
|
21
|
+
if (process.env.TERM === 'xterm-256color' || process.stdout.hasColors?.(256)) return '256';
|
|
22
|
+
return '16';
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const TRUECOLOR = {
|
|
26
|
+
accent: '\x1b[38;2;255;107;53m',
|
|
27
|
+
primary: '\x1b[38;2;224;224;224m',
|
|
28
|
+
secondary: '\x1b[38;2;160;160;160m',
|
|
29
|
+
tertiary: '\x1b[38;2;102;102;102m',
|
|
30
|
+
success: '\x1b[38;2;34;197;94m',
|
|
31
|
+
warning: '\x1b[38;2;251;191;36m',
|
|
32
|
+
error: '\x1b[38;2;239;68;68m',
|
|
33
|
+
info: '\x1b[38;2;96;165;250m',
|
|
34
|
+
bold: '\x1b[1m',
|
|
35
|
+
dim: '\x1b[2m',
|
|
36
|
+
reset: '\x1b[0m',
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
const COLOR256 = {
|
|
40
|
+
accent: '\x1b[38;5;202m',
|
|
41
|
+
primary: '\x1b[38;5;253m',
|
|
42
|
+
secondary: '\x1b[38;5;247m',
|
|
43
|
+
tertiary: '\x1b[38;5;241m',
|
|
44
|
+
success: '\x1b[38;5;35m',
|
|
45
|
+
warning: '\x1b[38;5;220m',
|
|
46
|
+
error: '\x1b[38;5;196m',
|
|
47
|
+
info: '\x1b[38;5;69m',
|
|
48
|
+
bold: '\x1b[1m',
|
|
49
|
+
dim: '\x1b[2m',
|
|
50
|
+
reset: '\x1b[0m',
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
const COLOR16 = {
|
|
54
|
+
accent: '\x1b[33m',
|
|
55
|
+
primary: '\x1b[37m',
|
|
56
|
+
secondary: '\x1b[37m',
|
|
57
|
+
tertiary: '\x1b[90m',
|
|
58
|
+
success: '\x1b[32m',
|
|
59
|
+
warning: '\x1b[33m',
|
|
60
|
+
error: '\x1b[31m',
|
|
61
|
+
info: '\x1b[36m',
|
|
62
|
+
bold: '\x1b[1m',
|
|
63
|
+
dim: '\x1b[2m',
|
|
64
|
+
reset: '\x1b[0m',
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
const NOCOLOR = {
|
|
68
|
+
accent: '', primary: '', secondary: '', tertiary: '',
|
|
69
|
+
success: '', warning: '', error: '', info: '',
|
|
70
|
+
bold: '', dim: '', reset: '',
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
const tier = getColorTier();
|
|
74
|
+
const c = tier === 'truecolor' ? TRUECOLOR : tier === '256' ? COLOR256 : tier === '16' ? COLOR16 : NOCOLOR;
|
|
75
|
+
|
|
76
|
+
// Legacy aliases (used in interactive prompts and error messages)
|
|
77
|
+
const cyan = c.accent;
|
|
78
|
+
const green = c.success;
|
|
79
|
+
const yellow = c.warning;
|
|
80
|
+
const magenta = c.accent;
|
|
81
|
+
const bold = c.bold;
|
|
82
|
+
const dim = c.dim;
|
|
83
|
+
const reset = c.reset;
|
|
16
84
|
|
|
17
85
|
// Get version from package.json
|
|
18
86
|
const pkg = require('../package.json');
|
|
@@ -79,17 +147,41 @@ const taglines = [
|
|
|
79
147
|
];
|
|
80
148
|
const tagline = taglines[Math.floor(Math.random() * taglines.length)];
|
|
81
149
|
|
|
82
|
-
//
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
'
|
|
86
|
-
'
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
150
|
+
// ── Sparkle field + density ramp banner ──
|
|
151
|
+
|
|
152
|
+
function sparkleLine(width) {
|
|
153
|
+
const chars = ['✧', '.', '·'];
|
|
154
|
+
const line = Array(width).fill(' ');
|
|
155
|
+
const count = 4 + Math.floor(Math.random() * 5);
|
|
156
|
+
for (let i = 0; i < count; i++) {
|
|
157
|
+
const pos = Math.floor(Math.random() * width);
|
|
158
|
+
line[pos] = chars[Math.floor(Math.random() * chars.length)];
|
|
159
|
+
}
|
|
160
|
+
return line.join('');
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
function center(text, width) {
|
|
164
|
+
const stripped = text.replace(/\x1b\[[0-9;]*m/g, '');
|
|
165
|
+
const pad = Math.max(0, Math.floor((width - stripped.length) / 2));
|
|
166
|
+
return ' '.repeat(pad) + text;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
const columns = process.stdout.columns || 80;
|
|
170
|
+
const rampText = `${c.accent}░▒▓█${c.reset} ${c.bold} GET SHIT PRETTY ${c.reset} ${c.accent}█▓▒░${c.reset}`;
|
|
171
|
+
const sparkleWidth = Math.min(34, columns - 4);
|
|
172
|
+
const showSparkles = columns >= 40;
|
|
173
|
+
|
|
174
|
+
const banner = '\n\n' +
|
|
175
|
+
(showSparkles ? `${c.dim} ${sparkleLine(sparkleWidth)}${c.reset}\n` : '') +
|
|
176
|
+
(showSparkles ? `${c.dim} ${sparkleLine(sparkleWidth)}${c.reset}\n` : '') +
|
|
177
|
+
'\n' +
|
|
178
|
+
center(rampText, columns) + '\n' +
|
|
90
179
|
'\n' +
|
|
91
|
-
|
|
92
|
-
|
|
180
|
+
(showSparkles ? `${c.dim} ${sparkleLine(sparkleWidth)}${c.reset}\n` : '') +
|
|
181
|
+
(showSparkles ? `${c.dim} ${sparkleLine(sparkleWidth)}${c.reset}\n` : '') +
|
|
182
|
+
'\n' +
|
|
183
|
+
` ${c.bold}${c.accent}/gsp:${c.reset} ${c.tertiary}◇◇${c.reset} ${c.dim}v${pkg.version}${c.reset}\n` +
|
|
184
|
+
` ${c.dim}${tagline}${c.reset}\n`;
|
|
93
185
|
|
|
94
186
|
console.log(banner);
|
|
95
187
|
|
|
@@ -686,8 +778,24 @@ function installLocalSymlinks(targetDir, src) {
|
|
|
686
778
|
agentCount++;
|
|
687
779
|
}
|
|
688
780
|
}
|
|
781
|
+
|
|
782
|
+
// ── Custom agents (agents/custom/) ──
|
|
783
|
+
const customAgentsSrc = path.join(cwd, 'agents', 'custom');
|
|
784
|
+
let customAgentCount = 0;
|
|
785
|
+
if (fs.existsSync(customAgentsSrc)) {
|
|
786
|
+
for (const file of fs.readdirSync(customAgentsSrc)) {
|
|
787
|
+
if (file.endsWith('.md') && file !== '.gitkeep') {
|
|
788
|
+
forceSymlink(path.join('..', '..', 'agents', 'custom', file), path.join(agentsDest, file));
|
|
789
|
+
customAgentCount++;
|
|
790
|
+
}
|
|
791
|
+
}
|
|
792
|
+
}
|
|
793
|
+
|
|
689
794
|
if (agentCount > 0) {
|
|
690
|
-
|
|
795
|
+
const msg = customAgentCount > 0
|
|
796
|
+
? `Symlinked ${agentCount} agents + ${customAgentCount} custom`
|
|
797
|
+
: `Symlinked ${agentCount} agents`;
|
|
798
|
+
console.log(` ${c.success}✓${c.reset} ${msg}`);
|
|
691
799
|
} else { failures.push('agents'); }
|
|
692
800
|
|
|
693
801
|
// ── Command symlink (whole gsp/ directory) ──
|
|
@@ -696,7 +804,7 @@ function installLocalSymlinks(targetDir, src) {
|
|
|
696
804
|
const gspCommandsDest = path.join(commandsDir, 'gsp');
|
|
697
805
|
try { fs.rmSync(gspCommandsDest, { recursive: true }); } catch {}
|
|
698
806
|
forceSymlink(path.join('..', '..', 'commands', 'gsp'), gspCommandsDest);
|
|
699
|
-
console.log(` ${
|
|
807
|
+
console.log(` ${c.success}✓${c.reset} Symlinked commands/gsp`);
|
|
700
808
|
|
|
701
809
|
// ── Bundle symlinks (prompts, templates, references → get-shit-pretty/) ──
|
|
702
810
|
const bundleDest = path.join(targetDir, 'get-shit-pretty');
|
|
@@ -708,13 +816,13 @@ function installLocalSymlinks(targetDir, src) {
|
|
|
708
816
|
for (const dir of ['prompts', 'templates', 'references']) {
|
|
709
817
|
if (fs.existsSync(path.join(cwd, dir))) {
|
|
710
818
|
forceSymlink(path.join('..', '..', dir), path.join(bundleDest, dir));
|
|
711
|
-
console.log(` ${
|
|
819
|
+
console.log(` ${c.success}✓${c.reset} Symlinked get-shit-pretty/${dir}`);
|
|
712
820
|
}
|
|
713
821
|
}
|
|
714
822
|
|
|
715
823
|
// VERSION is a real file (not in source repo as a standalone file)
|
|
716
824
|
fs.writeFileSync(path.join(bundleDest, 'VERSION'), pkg.version);
|
|
717
|
-
console.log(` ${
|
|
825
|
+
console.log(` ${c.success}✓${c.reset} Wrote VERSION (${pkg.version})`);
|
|
718
826
|
|
|
719
827
|
// ── Statusline ──
|
|
720
828
|
const hooksDest = path.join(targetDir, 'hooks');
|
|
@@ -724,12 +832,12 @@ function installLocalSymlinks(targetDir, src) {
|
|
|
724
832
|
let content = fs.readFileSync(statuslineSrc, 'utf8');
|
|
725
833
|
content = content.replace(/'\.claude'/g, getConfigDirFromHome('claude', false));
|
|
726
834
|
fs.writeFileSync(path.join(hooksDest, 'gsp-statusline.js'), content);
|
|
727
|
-
console.log(` ${
|
|
835
|
+
console.log(` ${c.success}✓${c.reset} Installed GSP statusline`);
|
|
728
836
|
}
|
|
729
837
|
const dispatcherSrc = path.join(src, 'scripts', 'statusline-dispatcher.js');
|
|
730
838
|
if (fs.existsSync(dispatcherSrc)) {
|
|
731
839
|
fs.copyFileSync(dispatcherSrc, path.join(hooksDest, 'statusline-dispatcher.js'));
|
|
732
|
-
console.log(` ${
|
|
840
|
+
console.log(` ${c.success}✓${c.reset} Installed statusline dispatcher`);
|
|
733
841
|
}
|
|
734
842
|
|
|
735
843
|
if (failures.length > 0) {
|
|
@@ -781,11 +889,11 @@ function install(isGlobal, runtime = 'claude') {
|
|
|
781
889
|
: `./${dirName}/`;
|
|
782
890
|
|
|
783
891
|
const runtimeLabel = getRuntimeLabel(runtime);
|
|
784
|
-
console.log(
|
|
892
|
+
console.log(`\n ${c.secondary}installing for${c.reset} ${c.primary}${runtimeLabel}${c.reset} ${c.secondary}to${c.reset} ${c.primary}${locationLabel}${c.reset}\n`);
|
|
785
893
|
|
|
786
894
|
// Local Claude install in GSP source repo → use symlinks
|
|
787
895
|
if (!isGlobal && runtime === 'claude' && installLocalSymlinks(targetDir, src)) {
|
|
788
|
-
console.log(` ${dim}(symlinked — edits to agents/ and commands/ are reflected immediately)${reset}`);
|
|
896
|
+
console.log(` ${c.dim}(symlinked — edits to agents/ and commands/ are reflected immediately)${c.reset}`);
|
|
789
897
|
const settingsPath = path.join(targetDir, 'settings.json');
|
|
790
898
|
const settings = readSettings(settingsPath);
|
|
791
899
|
const statuslineCommand = `node ${dirName}/hooks/statusline-dispatcher.js`;
|
|
@@ -801,7 +909,7 @@ function install(isGlobal, runtime = 'claude') {
|
|
|
801
909
|
copyFlattenedCommands(path.join(src, 'commands', 'gsp'), commandDir, 'gsp', pathPrefix, runtime);
|
|
802
910
|
if (verifyInstalled(commandDir, 'command/gsp-*')) {
|
|
803
911
|
const count = fs.readdirSync(commandDir).filter(f => f.startsWith('gsp-')).length;
|
|
804
|
-
console.log(` ${
|
|
912
|
+
console.log(` ${c.success}✓${c.reset} Installed ${count} commands to command/`);
|
|
805
913
|
} else { failures.push('commands'); }
|
|
806
914
|
} else if (isCodex) {
|
|
807
915
|
const skillsDir = path.join(targetDir, 'skills');
|
|
@@ -809,7 +917,7 @@ function install(isGlobal, runtime = 'claude') {
|
|
|
809
917
|
copyCodexSkills(path.join(src, 'commands', 'gsp'), skillsDir, 'gsp', pathPrefix);
|
|
810
918
|
if (verifyInstalled(skillsDir, 'skills/gsp-*')) {
|
|
811
919
|
const count = fs.readdirSync(skillsDir).filter(f => f.startsWith('gsp-')).length;
|
|
812
|
-
console.log(` ${
|
|
920
|
+
console.log(` ${c.success}✓${c.reset} Installed ${count} skills to skills/`);
|
|
813
921
|
} else { failures.push('skills'); }
|
|
814
922
|
} else {
|
|
815
923
|
const commandsDir = path.join(targetDir, 'commands');
|
|
@@ -817,7 +925,7 @@ function install(isGlobal, runtime = 'claude') {
|
|
|
817
925
|
const gspDest = path.join(commandsDir, 'gsp');
|
|
818
926
|
copyWithPathReplacement(path.join(src, 'commands', 'gsp'), gspDest, pathPrefix, runtime, true);
|
|
819
927
|
if (verifyInstalled(gspDest, 'commands/gsp')) {
|
|
820
|
-
console.log(` ${
|
|
928
|
+
console.log(` ${c.success}✓${c.reset} Installed commands/gsp`);
|
|
821
929
|
} else { failures.push('commands'); }
|
|
822
930
|
}
|
|
823
931
|
|
|
@@ -852,9 +960,35 @@ function install(isGlobal, runtime = 'claude') {
|
|
|
852
960
|
fs.writeFileSync(path.join(agentsDest, entry.name), content);
|
|
853
961
|
}
|
|
854
962
|
}
|
|
963
|
+
|
|
964
|
+
// ── Custom agents (agents/custom/) ──
|
|
965
|
+
const customAgentsSrc = path.join(agentsSrc, 'custom');
|
|
966
|
+
let customAgentCount = 0;
|
|
967
|
+
if (fs.existsSync(customAgentsSrc)) {
|
|
968
|
+
for (const entry of fs.readdirSync(customAgentsSrc, { withFileTypes: true })) {
|
|
969
|
+
if (entry.isFile() && entry.name.endsWith('.md')) {
|
|
970
|
+
let content = fs.readFileSync(path.join(customAgentsSrc, entry.name), 'utf8');
|
|
971
|
+
content = content.replace(/~\/\.claude\//g, pathPrefix);
|
|
972
|
+
|
|
973
|
+
if (isOpencode) {
|
|
974
|
+
content = convertClaudeToOpencodeFrontmatter(content);
|
|
975
|
+
} else if (isGemini) {
|
|
976
|
+
content = convertClaudeToGeminiAgent(content);
|
|
977
|
+
} else if (isCodex) {
|
|
978
|
+
content = convertClaudeToCodexAgent(content);
|
|
979
|
+
}
|
|
980
|
+
fs.writeFileSync(path.join(agentsDest, entry.name), content);
|
|
981
|
+
customAgentCount++;
|
|
982
|
+
}
|
|
983
|
+
}
|
|
984
|
+
}
|
|
985
|
+
|
|
855
986
|
if (verifyInstalled(agentsDest, 'agents')) {
|
|
856
987
|
const count = fs.readdirSync(agentsDest).filter(f => f.startsWith('gsp-')).length;
|
|
857
|
-
|
|
988
|
+
const msg = customAgentCount > 0
|
|
989
|
+
? `Installed ${count} agents + ${customAgentCount} custom`
|
|
990
|
+
: `Installed ${count} agents`;
|
|
991
|
+
console.log(` ${c.success}✓${c.reset} ${msg}`);
|
|
858
992
|
} else { failures.push('agents'); }
|
|
859
993
|
}
|
|
860
994
|
|
|
@@ -872,14 +1006,14 @@ function install(isGlobal, runtime = 'claude') {
|
|
|
872
1006
|
if (fs.existsSync(dirSrc)) {
|
|
873
1007
|
copyWithPathReplacement(dirSrc, path.join(bundleDest, dir), pathPrefix, runtime);
|
|
874
1008
|
if (verifyInstalled(path.join(bundleDest, dir), `get-shit-pretty/${dir}`)) {
|
|
875
|
-
console.log(` ${
|
|
1009
|
+
console.log(` ${c.success}✓${c.reset} Installed get-shit-pretty/${dir}`);
|
|
876
1010
|
} else { failures.push(dir); }
|
|
877
1011
|
}
|
|
878
1012
|
}
|
|
879
1013
|
|
|
880
1014
|
// Write VERSION file
|
|
881
1015
|
fs.writeFileSync(path.join(bundleDest, 'VERSION'), pkg.version);
|
|
882
|
-
console.log(` ${
|
|
1016
|
+
console.log(` ${c.success}✓${c.reset} Wrote VERSION (${pkg.version})`);
|
|
883
1017
|
|
|
884
1018
|
// ── Statusline (Claude Code only) ──
|
|
885
1019
|
if (runtime === 'claude') {
|
|
@@ -892,14 +1026,14 @@ function install(isGlobal, runtime = 'claude') {
|
|
|
892
1026
|
let content = fs.readFileSync(statuslineSrc, 'utf8');
|
|
893
1027
|
content = content.replace(/'\.claude'/g, getConfigDirFromHome(runtime, isGlobal));
|
|
894
1028
|
fs.writeFileSync(path.join(hooksDest, 'gsp-statusline.js'), content);
|
|
895
|
-
console.log(` ${
|
|
1029
|
+
console.log(` ${c.success}✓${c.reset} Installed GSP statusline`);
|
|
896
1030
|
}
|
|
897
1031
|
|
|
898
1032
|
// Copy dispatcher (routes to GSP or GSD based on project type)
|
|
899
1033
|
const dispatcherSrc = path.join(src, 'scripts', 'statusline-dispatcher.js');
|
|
900
1034
|
if (fs.existsSync(dispatcherSrc)) {
|
|
901
1035
|
fs.copyFileSync(dispatcherSrc, path.join(hooksDest, 'statusline-dispatcher.js'));
|
|
902
|
-
console.log(` ${
|
|
1036
|
+
console.log(` ${c.success}✓${c.reset} Installed statusline dispatcher`);
|
|
903
1037
|
}
|
|
904
1038
|
}
|
|
905
1039
|
|
|
@@ -957,7 +1091,7 @@ function uninstall(isGlobal, runtime = 'claude') {
|
|
|
957
1091
|
removedCount++;
|
|
958
1092
|
}
|
|
959
1093
|
}
|
|
960
|
-
if (removedCount > 0) console.log(` ${
|
|
1094
|
+
if (removedCount > 0) console.log(` ${c.success}✓${c.reset} Removed GSP commands from command/`);
|
|
961
1095
|
}
|
|
962
1096
|
} else if (isCodex) {
|
|
963
1097
|
const skillsDir = path.join(targetDir, 'skills');
|
|
@@ -968,14 +1102,14 @@ function uninstall(isGlobal, runtime = 'claude') {
|
|
|
968
1102
|
removedCount++;
|
|
969
1103
|
}
|
|
970
1104
|
}
|
|
971
|
-
if (removedCount > 0) console.log(` ${
|
|
1105
|
+
if (removedCount > 0) console.log(` ${c.success}✓${c.reset} Removed GSP skills from skills/`);
|
|
972
1106
|
}
|
|
973
1107
|
} else {
|
|
974
1108
|
const gspCommandsDir = path.join(targetDir, 'commands', 'gsp');
|
|
975
1109
|
if (fs.existsSync(gspCommandsDir)) {
|
|
976
1110
|
fs.rmSync(gspCommandsDir, { recursive: true });
|
|
977
1111
|
removedCount++;
|
|
978
|
-
console.log(` ${
|
|
1112
|
+
console.log(` ${c.success}✓${c.reset} Removed commands/gsp/`);
|
|
979
1113
|
}
|
|
980
1114
|
}
|
|
981
1115
|
|
|
@@ -984,7 +1118,7 @@ function uninstall(isGlobal, runtime = 'claude') {
|
|
|
984
1118
|
if (fs.existsSync(gspDir)) {
|
|
985
1119
|
fs.rmSync(gspDir, { recursive: true });
|
|
986
1120
|
removedCount++;
|
|
987
|
-
console.log(` ${
|
|
1121
|
+
console.log(` ${c.success}✓${c.reset} Removed get-shit-pretty/`);
|
|
988
1122
|
}
|
|
989
1123
|
|
|
990
1124
|
// Remove GSP agents
|
|
@@ -999,7 +1133,7 @@ function uninstall(isGlobal, runtime = 'claude') {
|
|
|
999
1133
|
}
|
|
1000
1134
|
if (agentCount > 0) {
|
|
1001
1135
|
removedCount++;
|
|
1002
|
-
console.log(` ${
|
|
1136
|
+
console.log(` ${c.success}✓${c.reset} Removed ${agentCount} GSP agents`);
|
|
1003
1137
|
}
|
|
1004
1138
|
}
|
|
1005
1139
|
|
|
@@ -1009,7 +1143,7 @@ function uninstall(isGlobal, runtime = 'claude') {
|
|
|
1009
1143
|
if (fs.existsSync(hookPath)) {
|
|
1010
1144
|
fs.unlinkSync(hookPath);
|
|
1011
1145
|
removedCount++;
|
|
1012
|
-
console.log(` ${
|
|
1146
|
+
console.log(` ${c.success}✓${c.reset} Removed ${hook}`);
|
|
1013
1147
|
}
|
|
1014
1148
|
}
|
|
1015
1149
|
|
|
@@ -1023,7 +1157,7 @@ function uninstall(isGlobal, runtime = 'claude') {
|
|
|
1023
1157
|
(settings.statusLine.command.includes('gsp-statusline') || settings.statusLine.command.includes('statusline-dispatcher'))) {
|
|
1024
1158
|
delete settings.statusLine;
|
|
1025
1159
|
modified = true;
|
|
1026
|
-
console.log(` ${
|
|
1160
|
+
console.log(` ${c.success}✓${c.reset} Removed GSP statusline from settings`);
|
|
1027
1161
|
}
|
|
1028
1162
|
|
|
1029
1163
|
if (modified) {
|
|
@@ -1036,7 +1170,7 @@ function uninstall(isGlobal, runtime = 'claude') {
|
|
|
1036
1170
|
console.log(` ${yellow}!${reset} No GSP files found to remove.`);
|
|
1037
1171
|
}
|
|
1038
1172
|
|
|
1039
|
-
console.log(`\n ${
|
|
1173
|
+
console.log(`\n ${c.success}done.${c.reset} ${c.secondary}GSP has been uninstalled from ${runtimeLabel}.${c.reset}\n ${c.secondary}Your other files and settings have been preserved.${c.reset}\n`);
|
|
1040
1174
|
}
|
|
1041
1175
|
|
|
1042
1176
|
// ──────────────────────────────────────────────────────
|
|
@@ -1089,7 +1223,7 @@ function finishInstall(settingsPath, settings, statuslineCommand, shouldInstallS
|
|
|
1089
1223
|
type: 'command',
|
|
1090
1224
|
command: statuslineCommand
|
|
1091
1225
|
};
|
|
1092
|
-
console.log(` ${
|
|
1226
|
+
console.log(` ${c.success}✓${c.reset} Configured statusline`);
|
|
1093
1227
|
}
|
|
1094
1228
|
|
|
1095
1229
|
// Write settings for Claude/Gemini (they use settings.json)
|
|
@@ -1099,31 +1233,15 @@ function finishInstall(settingsPath, settings, statuslineCommand, shouldInstallS
|
|
|
1099
1233
|
|
|
1100
1234
|
const runtimeLabel = getRuntimeLabel(runtime);
|
|
1101
1235
|
const helpCmd = isOpencode ? '/gsp-help' : isCodex ? '$gsp-help' : '/gsp:help';
|
|
1102
|
-
const newCmd = isOpencode ? '/gsp-
|
|
1103
|
-
const brandCmd = isOpencode ? '/gsp-brand' : isCodex ? '$gsp-brand' : '/gsp:brand';
|
|
1104
|
-
console.log(`\n ${green}Done!${reset} GSP installed for ${cyan}${runtimeLabel}${reset}.`);
|
|
1236
|
+
const newCmd = isOpencode ? '/gsp-start' : isCodex ? '$gsp-start' : '/gsp:start';
|
|
1105
1237
|
|
|
1106
1238
|
// Show onboarding once (not per-runtime)
|
|
1107
1239
|
if (!onboardingShown && !hasQuiet) {
|
|
1108
1240
|
onboardingShown = true;
|
|
1109
1241
|
console.log(`
|
|
1110
|
-
${
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
${dim}│${reset} ${dim}│${reset}
|
|
1114
|
-
${dim}│${reset} GSP is a design system your agent can follow. ${dim}│${reset}
|
|
1115
|
-
${dim}│${reset} Research before pixels. Brand before screens. ${dim}│${reset}
|
|
1116
|
-
${dim}│${reset} Two pipelines, both opinionated: ${dim}│${reset}
|
|
1117
|
-
${dim}│${reset} ${dim}│${reset}
|
|
1118
|
-
${dim}│${reset} ${magenta}◇${reset} ${bold}Brand${reset} discover → strategy → identity ${dim}│${reset}
|
|
1119
|
-
${dim}│${reset} ${cyan}◇${reset} ${bold}Project${reset} brief → design → build → review ${dim}│${reset}
|
|
1120
|
-
${dim}│${reset} ${dim}│${reset}
|
|
1121
|
-
${dim}│${reset} ${yellow}Start here:${reset} ${dim}│${reset}
|
|
1122
|
-
${dim}│${reset} ${cyan}${newCmd}${reset} new project ${dim}│${reset}
|
|
1123
|
-
${dim}│${reset} ${cyan}${brandCmd}${reset} brand identity ${dim}│${reset}
|
|
1124
|
-
${dim}│${reset} ${cyan}${helpCmd}${reset} all commands ${dim}│${reset}
|
|
1125
|
-
${dim}│${reset} ${dim}│${reset}
|
|
1126
|
-
${dim}└──────────────────────────────────────────────────────┘${reset}
|
|
1242
|
+
${c.bold}Get started:${c.reset}
|
|
1243
|
+
${c.accent}${newCmd}${c.reset} ${c.secondary}start here — brand, project, or both${c.reset}
|
|
1244
|
+
${c.accent}${helpCmd}${c.reset} ${c.secondary}all commands${c.reset}
|
|
1127
1245
|
`);
|
|
1128
1246
|
}
|
|
1129
1247
|
}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: gsp:add-reference
|
|
3
|
+
description: Add reference material to a project
|
|
4
|
+
allowed-tools:
|
|
5
|
+
- Read
|
|
6
|
+
- Write
|
|
7
|
+
- Bash
|
|
8
|
+
- Glob
|
|
9
|
+
- AskUserQuestion
|
|
10
|
+
---
|
|
11
|
+
<context>
|
|
12
|
+
Adds reference material (screenshots, wireframes, brand guidelines, competitor examples, design specs, URLs) to a project's `references/` directory for use by all downstream agents.
|
|
13
|
+
|
|
14
|
+
References are loaded by design, build, and research commands and passed to their agents as additional context.
|
|
15
|
+
</context>
|
|
16
|
+
|
|
17
|
+
<objective>
|
|
18
|
+
Add reference material to a project for downstream agents to consume.
|
|
19
|
+
|
|
20
|
+
**Input:** User-provided files, URLs, or descriptions
|
|
21
|
+
**Output:** `{project}/references/` with organized reference files + `references/INDEX.md`
|
|
22
|
+
</objective>
|
|
23
|
+
|
|
24
|
+
<process>
|
|
25
|
+
## Step 0: Resolve project
|
|
26
|
+
|
|
27
|
+
Scan `.design/projects/` for project directories. If only one project exists, use it. If multiple, ask the user which project to work on.
|
|
28
|
+
|
|
29
|
+
Set `PROJECT_PATH` = `.design/projects/{project}`
|
|
30
|
+
|
|
31
|
+
## Step 1: Ensure references directory
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
mkdir -p {PROJECT_PATH}/references
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## Step 2: Determine reference type
|
|
38
|
+
|
|
39
|
+
If the user provided a file path, URL, or description in the command invocation, use that. Otherwise, ask:
|
|
40
|
+
|
|
41
|
+
Use `AskUserQuestion` with options:
|
|
42
|
+
- **Screenshot or image** — "Add a screenshot, mockup, or wireframe"
|
|
43
|
+
- **URL** — "Save a webpage or design reference from a URL"
|
|
44
|
+
- **Competitor example** — "Document a competitor's approach"
|
|
45
|
+
- **Brand guidelines** — "Add existing brand guidelines or style guide"
|
|
46
|
+
- **Design spec** — "Add a design specification or requirements doc"
|
|
47
|
+
- **Other** — "Add any other reference material"
|
|
48
|
+
|
|
49
|
+
## Step 3: Process reference
|
|
50
|
+
|
|
51
|
+
**For file paths (images, PDFs, documents):**
|
|
52
|
+
1. Verify the file exists
|
|
53
|
+
2. Copy to `{PROJECT_PATH}/references/` with a descriptive name
|
|
54
|
+
3. If it's an image, read it to generate a text description
|
|
55
|
+
4. Write a companion `.md` file with metadata (source, date added, description, relevant screens/phases)
|
|
56
|
+
|
|
57
|
+
**For URLs:**
|
|
58
|
+
1. Fetch the URL content
|
|
59
|
+
2. Write a summary to `{PROJECT_PATH}/references/url-{kebab-name}.md` with:
|
|
60
|
+
- Source URL
|
|
61
|
+
- Date captured
|
|
62
|
+
- Key takeaways
|
|
63
|
+
- Relevant screens/phases
|
|
64
|
+
- Screenshots or key quotes
|
|
65
|
+
|
|
66
|
+
**For descriptions/notes:**
|
|
67
|
+
1. Write to `{PROJECT_PATH}/references/note-{kebab-name}.md` with:
|
|
68
|
+
- Description
|
|
69
|
+
- Date added
|
|
70
|
+
- Relevant screens/phases
|
|
71
|
+
|
|
72
|
+
## Step 4: Update index
|
|
73
|
+
|
|
74
|
+
Write or update `{PROJECT_PATH}/references/INDEX.md`:
|
|
75
|
+
|
|
76
|
+
```markdown
|
|
77
|
+
# Project References
|
|
78
|
+
> Project: {name} | Last updated: {DATE}
|
|
79
|
+
|
|
80
|
+
## References
|
|
81
|
+
|
|
82
|
+
| # | Reference | Type | File | Added | Relevant To |
|
|
83
|
+
|---|-----------|------|------|-------|-------------|
|
|
84
|
+
| 1 | {description} | {screenshot/url/note/guideline} | [{filename}](./{filename}) | {DATE} | {screens/phases} |
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
## Step 5: Confirm
|
|
88
|
+
|
|
89
|
+
Display what was added and which phases will use it:
|
|
90
|
+
- Research agents scan references for competitive context
|
|
91
|
+
- Design agents use references as visual/functional inspiration
|
|
92
|
+
- Build agents reference implementation examples
|
|
93
|
+
- Review agents check against reference expectations
|
|
94
|
+
|
|
95
|
+
"Reference added. It will be available to all downstream phases."
|
|
96
|
+
</process>
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: gsp:art
|
|
3
|
+
description: "Craft ASCII art interactively — you direct, the artist creates"
|
|
4
|
+
allowed-tools:
|
|
5
|
+
- Read
|
|
6
|
+
- Bash
|
|
7
|
+
- AskUserQuestion
|
|
8
|
+
- Agent
|
|
9
|
+
---
|
|
10
|
+
<context>
|
|
11
|
+
Interactive terminal art studio. You describe what you want, the ASCII artist creates it, and you iterate until it's perfect.
|
|
12
|
+
|
|
13
|
+
Not part of the main design pipeline. Just for fun.
|
|
14
|
+
</context>
|
|
15
|
+
|
|
16
|
+
<objective>
|
|
17
|
+
Create terminal art with the user in the loop — gather intent, create, iterate.
|
|
18
|
+
|
|
19
|
+
**Input:** User's vision (subject, mood, size, usage)
|
|
20
|
+
**Output:** Rendered art in the terminal + reusable code snippet
|
|
21
|
+
**Agent:** `gsp-ascii-artist`
|
|
22
|
+
</objective>
|
|
23
|
+
|
|
24
|
+
<process>
|
|
25
|
+
## Step 1: Gather intent
|
|
26
|
+
|
|
27
|
+
Ask the user what they want to render (subject — text, image, or concept).
|
|
28
|
+
|
|
29
|
+
Then use `AskUserQuestion` for mood:
|
|
30
|
+
- **Bold** — "High contrast, strong lines, maximum impact"
|
|
31
|
+
- **Minimal** — "Clean, sparse, breathing room"
|
|
32
|
+
- **Playful** — "Fun, quirky, unexpected"
|
|
33
|
+
- **Retro** — "8-bit nostalgia, old-school terminal vibes"
|
|
34
|
+
|
|
35
|
+
Then use `AskUserQuestion` for size:
|
|
36
|
+
- **Small** — "1-5 lines — compact accent"
|
|
37
|
+
- **Medium** — "5-15 lines — solid presence"
|
|
38
|
+
- **Large** — "15-25 lines — full showpiece"
|
|
39
|
+
|
|
40
|
+
Optionally ask about usage (one-off fun, splash screen, CLI output, embedded in code) if it's not obvious from context.
|
|
41
|
+
|
|
42
|
+
## Step 2: Create the art
|
|
43
|
+
|
|
44
|
+
Spawn the `gsp-ascii-artist` agent with the user's request. Ask for 2-3 options so the user can pick.
|
|
45
|
+
|
|
46
|
+
The agent will:
|
|
47
|
+
1. Draft the art
|
|
48
|
+
2. Test each option via `node -e` in the terminal
|
|
49
|
+
3. Return all rendered results and reusable code
|
|
50
|
+
|
|
51
|
+
## Step 3: Show and iterate
|
|
52
|
+
|
|
53
|
+
Present the options to the user. Let them pick a favorite, request tweaks, or ask for a completely new direction. Re-spawn the agent as needed until the user is happy.
|
|
54
|
+
</process>
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: gsp:brand-audit
|
|
3
|
-
description: Audit existing brand
|
|
3
|
+
description: Audit an existing brand before evolving it
|
|
4
4
|
allowed-tools:
|
|
5
5
|
- Read
|
|
6
6
|
- Write
|
|
@@ -39,7 +39,7 @@ Set `BRAND_PATH` = `.design/branding/{brand}`
|
|
|
39
39
|
Read `{BRAND_PATH}/BRIEF.md` to understand the brand's aspirational direction.
|
|
40
40
|
Read `{BRAND_PATH}/config.json` to confirm `brand_mode` is `evolve` and get `evolution_scope`.
|
|
41
41
|
|
|
42
|
-
If BRAND_PATH doesn't exist, tell the user to run `/gsp:
|
|
42
|
+
If BRAND_PATH doesn't exist, tell the user to run `/gsp:start` first.
|
|
43
43
|
|
|
44
44
|
## Step 2: Gather existing brand assets (interactive)
|
|
45
45
|
|