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.
Files changed (61) hide show
  1. package/README.md +15 -15
  2. package/VERSION +1 -0
  3. package/agents/custom/.gitkeep +0 -0
  4. package/agents/gsp-ascii-artist.md +63 -0
  5. package/agents/gsp-auditor.md +2 -2
  6. package/agents/gsp-builder.md +60 -24
  7. package/agents/gsp-codebase-scanner.md +2 -2
  8. package/agents/gsp-critic.md +2 -2
  9. package/agents/gsp-designer.md +18 -2
  10. package/agents/gsp-project-researcher.md +2 -2
  11. package/agents/gsp-researcher.md +2 -2
  12. package/agents/gsp-reviewer.md +39 -21
  13. package/agents/gsp-scoper.md +2 -2
  14. package/agents/gsp-system-architect.md +2 -2
  15. package/bin/install.js +181 -63
  16. package/commands/gsp/add-reference.md +96 -0
  17. package/commands/gsp/art.md +54 -0
  18. package/commands/gsp/brand-audit.md +2 -2
  19. package/commands/gsp/brand-identity.md +31 -24
  20. package/commands/gsp/brand-patterns.md +31 -19
  21. package/commands/gsp/brand-research.md +19 -5
  22. package/commands/gsp/brand-strategy.md +22 -12
  23. package/commands/gsp/brand-verbal.md +24 -14
  24. package/commands/gsp/doctor.md +8 -8
  25. package/commands/gsp/help.md +105 -98
  26. package/commands/gsp/launch.md +1 -1
  27. package/commands/gsp/pretty.md +61 -0
  28. package/commands/gsp/progress.md +157 -45
  29. package/commands/gsp/{brief.md → project-brief.md} +22 -7
  30. package/commands/gsp/project-build.md +141 -0
  31. package/commands/gsp/{critique.md → project-critique.md} +47 -8
  32. package/commands/gsp/{design.md → project-design.md} +40 -8
  33. package/commands/gsp/{research.md → project-research.md} +26 -7
  34. package/commands/gsp/{review.md → project-review.md} +55 -14
  35. package/commands/gsp/{new.md → start.md} +112 -27
  36. package/package.json +4 -3
  37. package/prompts/09-design-to-code-translator.md +12 -6
  38. package/prompts/11-deliverable-reviewer.md +21 -12
  39. package/references/phase-transitions.md +96 -0
  40. package/references/questioning.md +10 -4
  41. package/references/terminal-art.md +196 -0
  42. package/templates/branding/config.json +1 -1
  43. package/templates/codebase-inventory.md +1 -1
  44. package/templates/exports-index.md +14 -6
  45. package/templates/phases/build.md +36 -20
  46. package/templates/phases/design.md +8 -0
  47. package/templates/phases/review.md +12 -12
  48. package/templates/projects/config.json +2 -7
  49. package/templates/projects/roadmap.md +6 -6
  50. package/templates/projects/state.md +8 -0
  51. package/commands/gsp/brand-discover.md +0 -17
  52. package/commands/gsp/brand-system.md +0 -17
  53. package/commands/gsp/brand.md +0 -20
  54. package/commands/gsp/build.md +0 -92
  55. package/commands/gsp/discover.md +0 -17
  56. package/commands/gsp/identity.md +0 -18
  57. package/commands/gsp/new-project.md +0 -17
  58. package/commands/gsp/plan.md +0 -18
  59. package/commands/gsp/strategy.md +0 -18
  60. package/commands/gsp/system.md +0 -17
  61. 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
- // Colors
9
- const cyan = '\x1b[36m';
10
- const green = '\x1b[32m';
11
- const yellow = '\x1b[33m';
12
- const magenta = '\x1b[35m';
13
- const bold = '\x1b[1m';
14
- const dim = '\x1b[2m';
15
- const reset = '\x1b[0m';
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
- // Banner
83
- const banner = '\n' +
84
- cyan + ' ██████╗ ███████╗██████╗\n' +
85
- ' ██╔════╝ ██╔════╝██╔══██╗\n' +
86
- ' ██║ ███╗███████╗██████╔╝\n' +
87
- ' ██║ ██║╚════██║██╔═══╝\n' +
88
- ' ╚██████╔╝███████║██║\n' +
89
- ' ╚═════╝ ╚══════╝╚═╝' + reset + '\n' +
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
- ' ' + bold + 'Get Shit Pretty' + reset + ' ' + dim + 'v' + pkg.version + reset + '\n' +
92
- ' ' + dim + tagline + reset + '\n';
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
- console.log(` ${green}+${reset} Symlinked ${agentCount} agents`);
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(` ${green}+${reset} Symlinked commands/gsp`);
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(` ${green}+${reset} Symlinked get-shit-pretty/${dir}`);
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(` ${green}+${reset} Wrote VERSION (${pkg.version})`);
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(` ${green}+${reset} Installed GSP statusline`);
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(` ${green}+${reset} Installed statusline dispatcher`);
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(` Installing for ${cyan}${runtimeLabel}${reset} to ${cyan}${locationLabel}${reset}\n`);
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(` ${green}+${reset} Installed ${count} commands to command/`);
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(` ${green}+${reset} Installed ${count} skills to skills/`);
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(` ${green}+${reset} Installed commands/gsp`);
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
- console.log(` ${green}+${reset} Installed ${count} agents`);
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(` ${green}+${reset} Installed get-shit-pretty/${dir}`);
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(` ${green}+${reset} Wrote VERSION (${pkg.version})`);
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(` ${green}+${reset} Installed GSP statusline`);
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(` ${green}+${reset} Installed statusline dispatcher`);
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(` ${green}+${reset} Removed GSP commands from command/`);
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(` ${green}+${reset} Removed GSP skills from skills/`);
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(` ${green}+${reset} Removed commands/gsp/`);
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(` ${green}+${reset} Removed get-shit-pretty/`);
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(` ${green}+${reset} Removed ${agentCount} GSP agents`);
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(` ${green}+${reset} Removed ${hook}`);
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(` ${green}+${reset} Removed GSP statusline from settings`);
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 ${green}Done!${reset} GSP has been uninstalled from ${runtimeLabel}.\n Your other files and settings have been preserved.\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(` ${green}+${reset} Configured statusline`);
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-new' : isCodex ? '$gsp-new' : '/gsp:new';
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
- ${dim}┌──────────────────────────────────────────────────────┐${reset}
1111
- ${dim}│${reset} ${dim}│${reset}
1112
- ${dim}│${reset} ${bold}The idea${reset} ${dim}│${reset}
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 assess coherence, market fit, equity, evolution map
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:new` first.
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