claude-think 0.1.3 → 0.1.5

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.
@@ -22,7 +22,10 @@
22
22
  "Bash(npm publish:*)",
23
23
  "Bash(bun install:*)",
24
24
  "Bash(bun:*)",
25
- "Bash(git commit -m \"$\\(cat <<''EOF''\nv0.1.3: Fix --version to read from package.json\n\nCo-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>\nEOF\n\\)\")"
25
+ "Bash(git commit -m \"$\\(cat <<''EOF''\nv0.1.3: Fix --version to read from package.json\n\nCo-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>\nEOF\n\\)\")",
26
+ "Bash(git commit -m \"$\\(cat <<''EOF''\nv0.1.4: Improved setup wizard UX with @clack/prompts\n\n- Arrow key navigation and space to toggle checkboxes\n- Multi-select for frontend, CSS, database, infrastructure\n- Cleaner visual design with spinners and hints\n- Better cancel handling\n\nCo-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>\nEOF\n\\)\")",
27
+ "Bash(npm view:*)",
28
+ "Bash(git commit:*)"
26
29
  ]
27
30
  }
28
31
  }
package/CHANGELOG.md CHANGED
@@ -5,6 +5,23 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [0.1.5] - 2025-02-05
9
+
10
+ ### Added
11
+ - Enhanced profile section with role and experience level
12
+ - Claude personality selection (pair programmer, mentor, assistant, etc.)
13
+ - SDLC preferences: planning, testing, code review, git workflow
14
+ - Documentation, debugging, and refactoring preferences
15
+ - Generated profile now includes full development workflow guidance
16
+
17
+ ## [0.1.4] - 2025-02-05
18
+
19
+ ### Changed
20
+ - Setup wizard now uses @clack/prompts for better UX
21
+ - Arrow key navigation and space to toggle checkboxes
22
+ - Multi-select for frontend, CSS, database, infrastructure (can pick multiple)
23
+ - Cleaner visual design with spinners and hints
24
+
8
25
  ## [0.1.3] - 2025-02-05
9
26
 
10
27
  ### Fixed
package/bun.lock CHANGED
@@ -5,6 +5,7 @@
5
5
  "": {
6
6
  "name": "think",
7
7
  "dependencies": {
8
+ "@clack/prompts": "^1.0.0",
8
9
  "chalk": "^5.6.2",
9
10
  "commander": "^14.0.3",
10
11
  "gray-matter": "^4.0.3",
@@ -25,6 +26,10 @@
25
26
  "packages": {
26
27
  "@alcalzone/ansi-tokenize": ["@alcalzone/ansi-tokenize@0.2.4", "", { "dependencies": { "ansi-styles": "^6.2.1", "is-fullwidth-code-point": "^5.0.0" } }, "sha512-HTgrrTgZ9Jgeo6Z3oqbQ7lifOVvRR14vaDuBGPPUxk9Thm+vObaO4QfYYYWw4Zo5CWQDBEfsinFA6Gre+AqwNQ=="],
27
28
 
29
+ "@clack/core": ["@clack/core@1.0.0", "", { "dependencies": { "picocolors": "^1.0.0", "sisteransi": "^1.0.5" } }, "sha512-Orf9Ltr5NeiEuVJS8Rk2XTw3IxNC2Bic3ash7GgYeA8LJ/zmSNpSQ/m5UAhe03lA6KFgklzZ5KTHs4OAMA/SAQ=="],
30
+
31
+ "@clack/prompts": ["@clack/prompts@1.0.0", "", { "dependencies": { "@clack/core": "1.0.0", "picocolors": "^1.0.0", "sisteransi": "^1.0.5" } }, "sha512-rWPXg9UaCFqErJVQ+MecOaWsozjaxol4yjnmYcGNipAWzdaWa2x+VJmKfGq7L0APwBohQOYdHC+9RO4qRXej+A=="],
32
+
28
33
  "@types/bun": ["@types/bun@1.3.8", "", { "dependencies": { "bun-types": "1.3.8" } }, "sha512-3LvWJ2q5GerAXYxO2mffLTqOzEu5qnhEAlh48Vnu8WQfnmSwbgagjGZV6BoHKJztENYEDn6QmVd949W4uESRJA=="],
29
34
 
30
35
  "@types/node": ["@types/node@25.2.1", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-CPrnr8voK8vC6eEtyRzvMpgp3VyVRhgclonE7qYi6P9sXwYb59ucfrnmFBTaP0yUi8Gk4yZg/LlTJULGxvTNsg=="],
@@ -97,6 +102,8 @@
97
102
 
98
103
  "patch-console": ["patch-console@2.0.0", "", {}, "sha512-0YNdUceMdaQwoKce1gatDScmMo5pu/tfABfnzEqeG0gtTmd7mh/WcwgUjtAeOU7N8nFFlbQBnFK2gXW5fGvmMA=="],
99
104
 
105
+ "picocolors": ["picocolors@1.1.1", "", {}, "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="],
106
+
100
107
  "react": ["react@19.2.4", "", {}, "sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ=="],
101
108
 
102
109
  "react-reconciler": ["react-reconciler@0.33.0", "", { "dependencies": { "scheduler": "^0.27.0" }, "peerDependencies": { "react": "^19.2.0" } }, "sha512-KetWRytFv1epdpJc3J4G75I4WrplZE5jOL7Yq0p34+OVOKF4Se7WrdIdVC45XsSSmUTlht2FM/fM1FZb1mfQeA=="],
@@ -109,6 +116,8 @@
109
116
 
110
117
  "signal-exit": ["signal-exit@3.0.7", "", {}, "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ=="],
111
118
 
119
+ "sisteransi": ["sisteransi@1.0.5", "", {}, "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg=="],
120
+
112
121
  "slice-ansi": ["slice-ansi@7.1.2", "", { "dependencies": { "ansi-styles": "^6.2.1", "is-fullwidth-code-point": "^5.0.0" } }, "sha512-iOBWFgUX7caIZiuutICxVgX1SdxwAVFFKwt1EvMYYec/NWO5meOJ6K5uQxhrYBdQJne4KxiqZc+KptFOWFSI9w=="],
113
122
 
114
123
  "sprintf-js": ["sprintf-js@1.0.3", "", {}, "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g=="],
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claude-think",
3
- "version": "0.1.3",
3
+ "version": "0.1.5",
4
4
  "description": "Personal context manager for Claude - manage your preferences, patterns, and memory",
5
5
  "author": "Amit Feldman",
6
6
  "license": "MIT",
@@ -27,6 +27,7 @@
27
27
  "typescript": "^5"
28
28
  },
29
29
  "dependencies": {
30
+ "@clack/prompts": "^1.0.0",
30
31
  "chalk": "^5.6.2",
31
32
  "commander": "^14.0.3",
32
33
  "gray-matter": "^4.0.3",
@@ -1,29 +1,11 @@
1
- import { writeFile, readFile } from "fs/promises";
1
+ import { writeFile } from "fs/promises";
2
2
  import { existsSync } from "fs";
3
- import * as readline from "readline";
3
+ import * as p from "@clack/prompts";
4
4
  import chalk from "chalk";
5
5
  import { CONFIG, thinkPath } from "../../core/config";
6
6
  import { printBanner } from "../../core/banner";
7
7
  import { syncCommand } from "./sync";
8
8
 
9
- interface SetupAnswers {
10
- name: string;
11
- style: "direct" | "conversational" | "detailed";
12
- packageManager: "bun" | "pnpm" | "npm" | "yarn";
13
- languages: string[];
14
- backend: string;
15
- frontend: string;
16
- css: string;
17
- database: string;
18
- infrastructure: string;
19
- monorepo: string;
20
- testing: string[];
21
- linting: string[];
22
- validation: string[];
23
- editor: string;
24
- avoidAll: boolean;
25
- }
26
-
27
9
  /**
28
10
  * Interactive profile setup wizard
29
11
  */
@@ -34,428 +16,644 @@ export async function setupCommand(): Promise<void> {
34
16
  }
35
17
 
36
18
  printBanner();
37
- console.log(chalk.bold("Profile Setup\n"));
38
- console.log(chalk.dim("Let's configure your preferences.\n"));
39
19
 
40
- const rl = readline.createInterface({
41
- input: process.stdin,
42
- output: process.stdout,
43
- });
20
+ p.intro(chalk.bgCyan(chalk.black(" think setup ")));
44
21
 
45
- const question = (prompt: string): Promise<string> => {
46
- return new Promise((resolve) => {
47
- rl.question(prompt, resolve);
22
+ const name = await p.text({
23
+ message: "What's your name?",
24
+ placeholder: "Your name",
25
+ });
26
+ if (p.isCancel(name)) return handleCancel();
27
+
28
+ const style = await p.select({
29
+ message: "What communication style do you prefer?",
30
+ options: [
31
+ { value: "direct", label: "Direct & minimal", hint: "no fluff, just answers" },
32
+ { value: "conversational", label: "Conversational", hint: "friendly but efficient" },
33
+ { value: "detailed", label: "Detailed", hint: "thorough explanations" },
34
+ ],
35
+ });
36
+ if (p.isCancel(style)) return handleCancel();
37
+
38
+ // === PROFILE & PERSONALITY ===
39
+ p.note("Let's understand who you are and how you work");
40
+
41
+ const role = await p.select({
42
+ message: "What's your role?",
43
+ options: [
44
+ { value: "senior-dev", label: "Senior Developer", hint: "experienced, autonomous" },
45
+ { value: "mid-dev", label: "Mid-level Developer", hint: "growing, some guidance helpful" },
46
+ { value: "junior-dev", label: "Junior Developer", hint: "learning, more explanation needed" },
47
+ { value: "founder", label: "Founder / Tech Lead", hint: "building fast, shipping matters" },
48
+ { value: "student", label: "Student", hint: "learning fundamentals" },
49
+ { value: "hobbyist", label: "Hobbyist", hint: "exploring for fun" },
50
+ ],
51
+ });
52
+ if (p.isCancel(role)) return handleCancel();
53
+
54
+ const claudePersonality = await p.select({
55
+ message: "How should Claude behave?",
56
+ options: [
57
+ { value: "pair-programmer", label: "Pair Programmer", hint: "collaborative, thinks out loud" },
58
+ { value: "senior-dev", label: "Senior Dev", hint: "gives direction, reviews your approach" },
59
+ { value: "assistant", label: "Efficient Assistant", hint: "executes tasks, minimal chatter" },
60
+ { value: "mentor", label: "Mentor", hint: "teaches concepts, explains why" },
61
+ { value: "rubber-duck", label: "Rubber Duck", hint: "helps you think, asks questions" },
62
+ ],
63
+ });
64
+ if (p.isCancel(claudePersonality)) return handleCancel();
65
+
66
+ // === SDLC PREFERENCES ===
67
+ p.note("How do you like to work through the development lifecycle?");
68
+
69
+ const planningApproach = await p.select({
70
+ message: "Planning approach?",
71
+ options: [
72
+ { value: "plan-first", label: "Plan first", hint: "discuss architecture before coding" },
73
+ { value: "iterate", label: "Iterate", hint: "rough plan, refine as we go" },
74
+ { value: "dive-in", label: "Dive in", hint: "start coding, figure it out" },
75
+ ],
76
+ });
77
+ if (p.isCancel(planningApproach)) return handleCancel();
78
+
79
+ const testingApproach = await p.select({
80
+ message: "Testing approach?",
81
+ options: [
82
+ { value: "tdd", label: "TDD", hint: "write tests first" },
83
+ { value: "test-after", label: "Test after", hint: "write tests after implementation" },
84
+ { value: "critical-paths", label: "Critical paths only", hint: "test important stuff" },
85
+ { value: "minimal", label: "Minimal", hint: "tests when necessary" },
86
+ ],
87
+ });
88
+ if (p.isCancel(testingApproach)) return handleCancel();
89
+
90
+ const codeReview = await p.select({
91
+ message: "Code review preference?",
92
+ options: [
93
+ { value: "review-before-commit", label: "Review before commit", hint: "Claude reviews changes" },
94
+ { value: "review-on-request", label: "On request", hint: "review when asked" },
95
+ { value: "self-review", label: "Self review", hint: "I review my own code" },
96
+ ],
97
+ });
98
+ if (p.isCancel(codeReview)) return handleCancel();
99
+
100
+ const gitWorkflow = await p.select({
101
+ message: "Git workflow?",
102
+ options: [
103
+ { value: "small-commits", label: "Small commits", hint: "atomic, frequent commits" },
104
+ { value: "feature-branches", label: "Feature branches", hint: "branch per feature, squash merge" },
105
+ { value: "trunk-based", label: "Trunk-based", hint: "commit to main, feature flags" },
106
+ { value: "flexible", label: "Flexible", hint: "depends on the project" },
107
+ ],
108
+ });
109
+ if (p.isCancel(gitWorkflow)) return handleCancel();
110
+
111
+ const documentationApproach = await p.select({
112
+ message: "Documentation approach?",
113
+ options: [
114
+ { value: "inline", label: "Inline comments", hint: "document as you code" },
115
+ { value: "readme-driven", label: "README driven", hint: "docs first, then code" },
116
+ { value: "minimal", label: "Minimal", hint: "self-documenting code" },
117
+ { value: "on-request", label: "On request", hint: "document when asked" },
118
+ ],
119
+ });
120
+ if (p.isCancel(documentationApproach)) return handleCancel();
121
+
122
+ const debuggingStyle = await p.select({
123
+ message: "Debugging style?",
124
+ options: [
125
+ { value: "systematic", label: "Systematic", hint: "isolate, reproduce, trace" },
126
+ { value: "hypothesis", label: "Hypothesis-driven", hint: "guess likely causes first" },
127
+ { value: "printf", label: "Printf debugging", hint: "add logs, observe behavior" },
128
+ { value: "whatever-works", label: "Whatever works", hint: "just fix it" },
129
+ ],
130
+ });
131
+ if (p.isCancel(debuggingStyle)) return handleCancel();
132
+
133
+ const refactoringPreference = await p.select({
134
+ message: "Refactoring preference?",
135
+ options: [
136
+ { value: "proactive", label: "Proactive", hint: "Claude suggests improvements" },
137
+ { value: "on-request", label: "On request", hint: "only when asked" },
138
+ { value: "boy-scout", label: "Boy scout rule", hint: "leave code better than found" },
139
+ { value: "if-broken", label: "If it ain't broke...", hint: "don't fix what works" },
140
+ ],
141
+ });
142
+ if (p.isCancel(refactoringPreference)) return handleCancel();
143
+
144
+ // === TECH STACK ===
145
+ p.note("Now let's configure your tech stack");
146
+
147
+ const packageManager = await p.select({
148
+ message: "Preferred package manager?",
149
+ options: [
150
+ { value: "bun", label: "Bun" },
151
+ { value: "pnpm", label: "pnpm" },
152
+ { value: "npm", label: "npm" },
153
+ { value: "yarn", label: "yarn" },
154
+ ],
155
+ });
156
+ if (p.isCancel(packageManager)) return handleCancel();
157
+
158
+ let bunFeatures: string[] = [];
159
+ if (packageManager === "bun") {
160
+ const features = await p.multiselect({
161
+ message: "Bun features you use?",
162
+ options: [
163
+ { value: "catalog", label: "Dependency catalog" },
164
+ { value: "workspaces", label: "Bun workspaces" },
165
+ { value: "macros", label: "Bun macros" },
166
+ { value: "shell", label: "Bun shell ($``)" },
167
+ { value: "sqlite", label: "bun:sqlite" },
168
+ { value: "test", label: "bun test" },
169
+ ],
170
+ required: false,
48
171
  });
172
+ if (p.isCancel(features)) return handleCancel();
173
+ bunFeatures = features as string[];
174
+ }
175
+
176
+ const languages = await p.multiselect({
177
+ message: "Primary programming languages?",
178
+ options: [
179
+ { value: "TypeScript", label: "TypeScript" },
180
+ { value: "JavaScript", label: "JavaScript" },
181
+ { value: "Python", label: "Python" },
182
+ { value: "Ruby", label: "Ruby" },
183
+ { value: "Rust", label: "Rust" },
184
+ { value: "Go", label: "Go" },
185
+ { value: "Java", label: "Java" },
186
+ { value: "C#", label: "C#" },
187
+ { value: "PHP", label: "PHP" },
188
+ { value: "Elixir", label: "Elixir" },
189
+ ],
190
+ required: true,
191
+ });
192
+ if (p.isCancel(languages)) return handleCancel();
193
+
194
+ const backend = await p.select({
195
+ message: "Backend framework?",
196
+ options: [
197
+ { value: "none", label: "None / Custom" },
198
+ { value: "Rails", label: "Ruby on Rails" },
199
+ { value: "Django", label: "Django" },
200
+ { value: "FastAPI", label: "FastAPI" },
201
+ { value: "Express", label: "Express.js" },
202
+ { value: "Hono", label: "Hono" },
203
+ { value: "Phoenix", label: "Phoenix (Elixir)" },
204
+ { value: "Spring", label: "Spring Boot" },
205
+ { value: "ASP.NET", label: "ASP.NET Core" },
206
+ { value: "Laravel", label: "Laravel" },
207
+ ],
208
+ });
209
+ if (p.isCancel(backend)) return handleCancel();
210
+
211
+ const frontend = await p.multiselect({
212
+ message: "Frontend frameworks?",
213
+ options: [
214
+ { value: "React", label: "React" },
215
+ { value: "Vue", label: "Vue.js" },
216
+ { value: "Svelte", label: "Svelte" },
217
+ { value: "Angular", label: "Angular" },
218
+ { value: "Solid", label: "SolidJS" },
219
+ { value: "HTMX", label: "HTMX" },
220
+ ],
221
+ required: false,
222
+ });
223
+ if (p.isCancel(frontend)) return handleCancel();
224
+
225
+ const css = await p.multiselect({
226
+ message: "CSS / UI frameworks?",
227
+ options: [
228
+ { value: "Tailwind", label: "Tailwind CSS" },
229
+ { value: "Vuetify", label: "Vuetify" },
230
+ { value: "Bootstrap", label: "Bootstrap" },
231
+ { value: "Material UI", label: "Material UI" },
232
+ { value: "shadcn/ui", label: "shadcn/ui" },
233
+ { value: "CSS Modules", label: "CSS Modules" },
234
+ { value: "styled-components", label: "styled-components" },
235
+ ],
236
+ required: false,
237
+ });
238
+ if (p.isCancel(css)) return handleCancel();
239
+
240
+ const database = await p.multiselect({
241
+ message: "Databases?",
242
+ options: [
243
+ { value: "PostgreSQL", label: "PostgreSQL" },
244
+ { value: "MySQL", label: "MySQL" },
245
+ { value: "MongoDB", label: "MongoDB" },
246
+ { value: "SQLite", label: "SQLite" },
247
+ { value: "Redis", label: "Redis" },
248
+ { value: "Supabase", label: "Supabase" },
249
+ { value: "Firebase", label: "Firebase" },
250
+ ],
251
+ required: false,
252
+ });
253
+ if (p.isCancel(database)) return handleCancel();
254
+
255
+ const orm = await p.multiselect({
256
+ message: "ORM / database tools?",
257
+ options: [
258
+ { value: "Prisma", label: "Prisma" },
259
+ { value: "Drizzle", label: "Drizzle" },
260
+ { value: "TypeORM", label: "TypeORM" },
261
+ { value: "Kysely", label: "Kysely" },
262
+ { value: "Sequelize", label: "Sequelize" },
263
+ { value: "Mongoose", label: "Mongoose" },
264
+ { value: "ActiveRecord", label: "ActiveRecord (Rails)" },
265
+ { value: "SQLAlchemy", label: "SQLAlchemy" },
266
+ { value: "Django ORM", label: "Django ORM" },
267
+ ],
268
+ required: false,
269
+ });
270
+ if (p.isCancel(orm)) return handleCancel();
271
+
272
+ const auth = await p.multiselect({
273
+ message: "Authentication?",
274
+ options: [
275
+ { value: "better-auth", label: "better-auth" },
276
+ { value: "Auth.js", label: "Auth.js (NextAuth)" },
277
+ { value: "Lucia", label: "Lucia" },
278
+ { value: "Clerk", label: "Clerk" },
279
+ { value: "Supabase Auth", label: "Supabase Auth" },
280
+ { value: "Firebase Auth", label: "Firebase Auth" },
281
+ { value: "Passport.js", label: "Passport.js" },
282
+ { value: "Devise", label: "Devise (Rails)" },
283
+ ],
284
+ required: false,
285
+ });
286
+ if (p.isCancel(auth)) return handleCancel();
287
+
288
+ const infrastructure = await p.multiselect({
289
+ message: "Infrastructure / deployment?",
290
+ options: [
291
+ { value: "Docker Compose", label: "Docker + Compose" },
292
+ { value: "Docker", label: "Docker only" },
293
+ { value: "Kubernetes", label: "Kubernetes" },
294
+ { value: "Fly.io", label: "Fly.io" },
295
+ { value: "Vercel", label: "Vercel" },
296
+ { value: "Railway", label: "Railway" },
297
+ { value: "Render", label: "Render" },
298
+ ],
299
+ required: false,
300
+ });
301
+ if (p.isCancel(infrastructure)) return handleCancel();
302
+
303
+ const monorepo = await p.select({
304
+ message: "Monorepo tooling?",
305
+ options: [
306
+ { value: "none", label: "None / Single repo" },
307
+ { value: "Turborepo", label: "Turborepo" },
308
+ { value: "Bun workspaces", label: "Bun workspaces" },
309
+ { value: "Nx", label: "Nx" },
310
+ { value: "pnpm workspaces", label: "pnpm workspaces" },
311
+ { value: "Lerna", label: "Lerna" },
312
+ ],
313
+ });
314
+ if (p.isCancel(monorepo)) return handleCancel();
315
+
316
+ const testing = await p.multiselect({
317
+ message: "Testing frameworks?",
318
+ options: [
319
+ { value: "bun test", label: "bun test" },
320
+ { value: "Vitest", label: "Vitest" },
321
+ { value: "Jest", label: "Jest" },
322
+ { value: "RSpec", label: "RSpec" },
323
+ { value: "pytest", label: "pytest" },
324
+ { value: "Playwright", label: "Playwright (E2E)" },
325
+ { value: "Cypress", label: "Cypress (E2E)" },
326
+ ],
327
+ required: false,
328
+ });
329
+ if (p.isCancel(testing)) return handleCancel();
330
+
331
+ const linting = await p.multiselect({
332
+ message: "Linting & formatting?",
333
+ options: [
334
+ { value: "Biome", label: "Biome" },
335
+ { value: "ESLint", label: "ESLint" },
336
+ { value: "Prettier", label: "Prettier" },
337
+ { value: "oxlint", label: "oxlint" },
338
+ { value: "Rubocop", label: "Rubocop" },
339
+ { value: "Ruff", label: "Ruff (Python)" },
340
+ { value: "rustfmt", label: "rustfmt" },
341
+ { value: "gofmt", label: "gofmt" },
342
+ ],
343
+ required: false,
344
+ });
345
+ if (p.isCancel(linting)) return handleCancel();
346
+
347
+ const validation = await p.multiselect({
348
+ message: "Validation & schema libraries?",
349
+ options: [
350
+ { value: "Zod", label: "Zod" },
351
+ { value: "Yup", label: "Yup" },
352
+ { value: "Valibot", label: "Valibot" },
353
+ { value: "ArkType", label: "ArkType" },
354
+ { value: "io-ts", label: "io-ts" },
355
+ { value: "TypeBox", label: "TypeBox" },
356
+ { value: "Pydantic", label: "Pydantic" },
357
+ { value: "Joi", label: "Joi" },
358
+ ],
359
+ required: false,
360
+ });
361
+ if (p.isCancel(validation)) return handleCancel();
362
+
363
+ const editor = await p.select({
364
+ message: "Primary editor?",
365
+ options: [
366
+ { value: "Zed", label: "Zed" },
367
+ { value: "VS Code", label: "VS Code" },
368
+ { value: "Cursor", label: "Cursor" },
369
+ { value: "Neovim", label: "Neovim" },
370
+ { value: "WebStorm", label: "WebStorm" },
371
+ ],
372
+ });
373
+ if (p.isCancel(editor)) return handleCancel();
374
+
375
+ const avoidAnswer = await p.select({
376
+ message: "What should Claude avoid?",
377
+ options: [
378
+ { value: "all", label: "All", hint: "over-engineering, verbose explanations, extra features" },
379
+ { value: "some", label: "Just over-engineering" },
380
+ { value: "none", label: "No specific restrictions" },
381
+ ],
382
+ });
383
+ if (p.isCancel(avoidAnswer)) return handleCancel();
384
+
385
+ const s = p.spinner();
386
+ s.start("Generating profile");
387
+
388
+ // Generate profile
389
+ const styleDescriptions: Record<string, string[]> = {
390
+ direct: [
391
+ "Be direct and minimal - no fluff, just answers and code",
392
+ "Skip lengthy reasoning unless asked",
393
+ "Don't explain obvious things",
394
+ ],
395
+ conversational: [
396
+ "Be friendly but efficient",
397
+ "Brief explanations when helpful",
398
+ "Keep a conversational tone",
399
+ ],
400
+ detailed: [
401
+ "Provide thorough explanations",
402
+ "Include context and reasoning",
403
+ "Explain trade-offs and alternatives",
404
+ ],
49
405
  };
50
406
 
51
- const select = async (
52
- prompt: string,
53
- options: { key: string; label: string }[]
54
- ): Promise<string> => {
55
- console.log(chalk.cyan(prompt));
56
- options.forEach((opt, i) => {
57
- console.log(` ${chalk.green(i + 1)}) ${opt.label}`);
58
- });
59
- const answer = await question(chalk.dim("Enter number: "));
60
- const idx = parseInt(answer) - 1;
61
- if (idx >= 0 && idx < options.length) {
62
- return options[idx].key;
63
- }
64
- return options[0].key;
407
+ const roleDescriptions: Record<string, string> = {
408
+ "senior-dev": "Senior developer - experienced and autonomous, prefers concise guidance",
409
+ "mid-dev": "Mid-level developer - competent but appreciates context on complex topics",
410
+ "junior-dev": "Junior developer - learning, benefits from more explanation and examples",
411
+ "founder": "Founder/Tech Lead - focused on shipping, pragmatic decisions over perfect code",
412
+ "student": "Student - learning fundamentals, explain concepts when relevant",
413
+ "hobbyist": "Hobbyist - exploring for fun, balance learning with getting things done",
65
414
  };
66
415
 
67
- const multiSelect = async (
68
- prompt: string,
69
- options: { key: string; label: string }[]
70
- ): Promise<string[]> => {
71
- console.log(chalk.cyan(prompt));
72
- options.forEach((opt, i) => {
73
- console.log(` ${chalk.green(i + 1)}) ${opt.label}`);
74
- });
75
- const answer = await question(chalk.dim("Enter numbers (comma-separated): "));
76
- const indices = answer.split(",").map((s) => parseInt(s.trim()) - 1);
77
- return indices
78
- .filter((i) => i >= 0 && i < options.length)
79
- .map((i) => options[i].key);
416
+ const personalityDescriptions: Record<string, string[]> = {
417
+ "pair-programmer": [
418
+ "Act as a pair programmer - think out loud, collaborate on solutions",
419
+ "Discuss trade-offs and alternatives when relevant",
420
+ "Catch potential issues early, suggest improvements as we go",
421
+ ],
422
+ "senior-dev": [
423
+ "Act as a senior developer - give direction, review approaches",
424
+ "Point out potential issues and better patterns",
425
+ "Be opinionated when it matters, flexible when it doesn't",
426
+ ],
427
+ "assistant": [
428
+ "Act as an efficient assistant - execute tasks with minimal chatter",
429
+ "Ask clarifying questions only when truly needed",
430
+ "Focus on delivering what was asked",
431
+ ],
432
+ "mentor": [
433
+ "Act as a mentor - teach concepts, explain the 'why'",
434
+ "Use opportunities to share knowledge",
435
+ "Suggest learning resources when helpful",
436
+ ],
437
+ "rubber-duck": [
438
+ "Act as a rubber duck - help me think through problems",
439
+ "Ask probing questions rather than giving immediate answers",
440
+ "Help me discover solutions myself",
441
+ ],
80
442
  };
81
443
 
82
- try {
83
- // Name
84
- const name = await question(chalk.cyan("What's your name? "));
85
- console.log();
86
-
87
- // Communication style
88
- const style = await select("What communication style do you prefer?", [
89
- { key: "direct", label: "Direct & minimal - no fluff, just answers" },
90
- { key: "conversational", label: "Conversational - friendly but efficient" },
91
- { key: "detailed", label: "Detailed - thorough explanations" },
92
- ]);
93
- console.log();
94
-
95
- // Package manager
96
- const packageManager = await select("Preferred package manager?", [
97
- { key: "bun", label: "bun" },
98
- { key: "pnpm", label: "pnpm" },
99
- { key: "npm", label: "npm" },
100
- { key: "yarn", label: "yarn" },
101
- ]);
102
- console.log();
103
-
104
- // Bun-specific features
105
- let bunFeatures: string[] = [];
106
- if (packageManager === "bun") {
107
- bunFeatures = await multiSelect("Bun features you use?", [
108
- { key: "catalog", label: "Dependency catalog" },
109
- { key: "workspaces", label: "Bun workspaces" },
110
- { key: "macros", label: "Bun macros" },
111
- { key: "shell", label: "Bun shell ($``)" },
112
- { key: "sqlite", label: "bun:sqlite" },
113
- { key: "test", label: "bun test" },
114
- ]);
115
- console.log();
116
- }
444
+ const planningDescriptions: Record<string, string> = {
445
+ "plan-first": "Discuss architecture and approach before writing code",
446
+ "iterate": "Start with a rough plan, refine as we go",
447
+ "dive-in": "Start coding quickly, figure out structure as needed",
448
+ };
117
449
 
118
- // Languages
119
- const languages = await multiSelect("Primary programming languages?", [
120
- { key: "TypeScript", label: "TypeScript" },
121
- { key: "JavaScript", label: "JavaScript" },
122
- { key: "Python", label: "Python" },
123
- { key: "Ruby", label: "Ruby" },
124
- { key: "Rust", label: "Rust" },
125
- { key: "Go", label: "Go" },
126
- { key: "Java", label: "Java" },
127
- { key: "C#", label: "C#" },
128
- { key: "PHP", label: "PHP" },
129
- { key: "Elixir", label: "Elixir" },
130
- ]);
131
- console.log();
132
-
133
- // Backend framework
134
- const backend = await select("Backend framework?", [
135
- { key: "none", label: "None / Custom" },
136
- { key: "Rails", label: "Ruby on Rails" },
137
- { key: "Django", label: "Django" },
138
- { key: "FastAPI", label: "FastAPI" },
139
- { key: "Express", label: "Express.js" },
140
- { key: "Hono", label: "Hono" },
141
- { key: "Phoenix", label: "Phoenix (Elixir)" },
142
- { key: "Spring", label: "Spring Boot" },
143
- { key: "ASP.NET", label: "ASP.NET Core" },
144
- { key: "Laravel", label: "Laravel" },
145
- ]);
146
- console.log();
147
-
148
- // Frontend framework
149
- const frontend = await select("Frontend framework?", [
150
- { key: "none", label: "None / Backend only" },
151
- { key: "React", label: "React" },
152
- { key: "Vue", label: "Vue.js" },
153
- { key: "Svelte", label: "Svelte" },
154
- { key: "Angular", label: "Angular" },
155
- { key: "Solid", label: "SolidJS" },
156
- { key: "HTMX", label: "HTMX" },
157
- ]);
158
- console.log();
159
-
160
- // CSS/UI framework
161
- const css = await select("CSS / UI framework?", [
162
- { key: "none", label: "Plain CSS / None" },
163
- { key: "Tailwind", label: "Tailwind CSS" },
164
- { key: "Vuetify", label: "Vuetify" },
165
- { key: "Bootstrap", label: "Bootstrap" },
166
- { key: "Material UI", label: "Material UI" },
167
- { key: "shadcn/ui", label: "shadcn/ui" },
168
- { key: "CSS Modules", label: "CSS Modules" },
169
- { key: "styled-components", label: "styled-components" },
170
- ]);
171
- console.log();
172
-
173
- // Database
174
- const database = await select("Primary database?", [
175
- { key: "none", label: "None" },
176
- { key: "PostgreSQL", label: "PostgreSQL" },
177
- { key: "MySQL", label: "MySQL" },
178
- { key: "MongoDB", label: "MongoDB" },
179
- { key: "SQLite", label: "SQLite" },
180
- { key: "Redis", label: "Redis" },
181
- { key: "Supabase", label: "Supabase" },
182
- { key: "Firebase", label: "Firebase" },
183
- ]);
184
- console.log();
185
-
186
- // ORM / Database tools
187
- const orm = await multiSelect("ORM / database tools?", [
188
- { key: "Prisma", label: "Prisma" },
189
- { key: "Drizzle", label: "Drizzle" },
190
- { key: "TypeORM", label: "TypeORM" },
191
- { key: "Kysely", label: "Kysely" },
192
- { key: "Sequelize", label: "Sequelize" },
193
- { key: "Mongoose", label: "Mongoose" },
194
- { key: "ActiveRecord", label: "ActiveRecord (Rails)" },
195
- { key: "SQLAlchemy", label: "SQLAlchemy" },
196
- { key: "Django ORM", label: "Django ORM" },
197
- ]);
198
- console.log();
199
-
200
- // Auth
201
- const auth = await multiSelect("Authentication?", [
202
- { key: "better-auth", label: "better-auth" },
203
- { key: "Auth.js", label: "Auth.js (NextAuth)" },
204
- { key: "Lucia", label: "Lucia" },
205
- { key: "Clerk", label: "Clerk" },
206
- { key: "Supabase Auth", label: "Supabase Auth" },
207
- { key: "Firebase Auth", label: "Firebase Auth" },
208
- { key: "Passport.js", label: "Passport.js" },
209
- { key: "Devise", label: "Devise (Rails)" },
210
- ]);
211
- console.log();
212
-
213
- // Infrastructure
214
- const infrastructure = await select("Infrastructure / containerization?", [
215
- { key: "none", label: "None" },
216
- { key: "Docker Compose", label: "Docker + Compose" },
217
- { key: "Docker", label: "Docker only" },
218
- { key: "Kubernetes", label: "Kubernetes" },
219
- { key: "Fly.io", label: "Fly.io" },
220
- { key: "Vercel", label: "Vercel" },
221
- { key: "Railway", label: "Railway" },
222
- ]);
223
- console.log();
224
-
225
- // Monorepo
226
- const monorepo = await select("Monorepo tooling?", [
227
- { key: "none", label: "None / Single repo" },
228
- { key: "Turborepo", label: "Turborepo" },
229
- { key: "Bun workspaces", label: "Bun workspaces" },
230
- { key: "Nx", label: "Nx" },
231
- { key: "pnpm workspaces", label: "pnpm workspaces" },
232
- { key: "Lerna", label: "Lerna" },
233
- ]);
234
- console.log();
235
-
236
- // Testing
237
- const testing = await multiSelect("Testing frameworks?", [
238
- { key: "bun test", label: "bun test" },
239
- { key: "Vitest", label: "Vitest" },
240
- { key: "Jest", label: "Jest" },
241
- { key: "RSpec", label: "RSpec" },
242
- { key: "pytest", label: "pytest" },
243
- { key: "Playwright", label: "Playwright (E2E)" },
244
- { key: "Cypress", label: "Cypress (E2E)" },
245
- ]);
246
- console.log();
247
-
248
- // Linting/Formatting
249
- const linting = await multiSelect("Linting & formatting?", [
250
- { key: "Biome", label: "Biome" },
251
- { key: "ESLint", label: "ESLint" },
252
- { key: "Prettier", label: "Prettier" },
253
- { key: "oxlint", label: "oxlint" },
254
- { key: "Rubocop", label: "Rubocop" },
255
- { key: "Ruff", label: "Ruff (Python)" },
256
- { key: "rustfmt", label: "rustfmt" },
257
- { key: "gofmt", label: "gofmt" },
258
- ]);
259
- console.log();
260
-
261
- // Validation/Schema
262
- const validation = await multiSelect("Validation & schema libraries?", [
263
- { key: "Zod", label: "Zod" },
264
- { key: "Yup", label: "Yup" },
265
- { key: "Valibot", label: "Valibot" },
266
- { key: "ArkType", label: "ArkType" },
267
- { key: "io-ts", label: "io-ts" },
268
- { key: "TypeBox", label: "TypeBox" },
269
- { key: "Pydantic", label: "Pydantic" },
270
- { key: "Joi", label: "Joi" },
271
- ]);
272
- console.log();
273
-
274
- // Editor
275
- const editor = await select("Primary editor?", [
276
- { key: "Zed", label: "Zed" },
277
- { key: "VS Code", label: "VS Code" },
278
- { key: "Cursor", label: "Cursor" },
279
- { key: "Neovim", label: "Neovim" },
280
- ]);
281
- console.log();
282
-
283
- // Avoid patterns
284
- const avoidAnswer = await select("What should Claude avoid?", [
285
- { key: "all", label: "All: over-engineering, verbose explanations, extra features" },
286
- { key: "some", label: "Just over-engineering" },
287
- { key: "none", label: "No specific restrictions" },
288
- ]);
289
- console.log();
290
-
291
- rl.close();
292
-
293
- // Generate profile
294
- const styleDescriptions: Record<string, string[]> = {
295
- direct: [
296
- "Be direct and minimal - no fluff, just answers and code",
297
- "Skip lengthy reasoning unless asked",
298
- "Don't explain obvious things",
299
- ],
300
- conversational: [
301
- "Be friendly but efficient",
302
- "Brief explanations when helpful",
303
- "Keep a conversational tone",
304
- ],
305
- detailed: [
306
- "Provide thorough explanations",
307
- "Include context and reasoning",
308
- "Explain trade-offs and alternatives",
309
- ],
310
- };
450
+ const testingDescriptions: Record<string, string> = {
451
+ "tdd": "Write tests first (TDD), then implement",
452
+ "test-after": "Write tests after implementation",
453
+ "critical-paths": "Test critical paths and edge cases",
454
+ "minimal": "Minimal testing - add tests when necessary",
455
+ };
311
456
 
312
- const profileContent = `---
457
+ const reviewDescriptions: Record<string, string> = {
458
+ "review-before-commit": "Review changes before committing - catch issues early",
459
+ "review-on-request": "Review code when explicitly asked",
460
+ "self-review": "I review my own code, no automatic reviews needed",
461
+ };
462
+
463
+ const gitDescriptions: Record<string, string> = {
464
+ "small-commits": "Small, atomic commits - easy to review and revert",
465
+ "feature-branches": "Feature branches with squash merges",
466
+ "trunk-based": "Trunk-based development with feature flags",
467
+ "flexible": "Flexible git workflow based on project needs",
468
+ };
469
+
470
+ const docDescriptions: Record<string, string> = {
471
+ "inline": "Document with inline comments as code is written",
472
+ "readme-driven": "README-driven development - docs first",
473
+ "minimal": "Minimal documentation - code should be self-documenting",
474
+ "on-request": "Add documentation when requested",
475
+ };
476
+
477
+ const debugDescriptions: Record<string, string> = {
478
+ "systematic": "Debug systematically - isolate, reproduce, trace",
479
+ "hypothesis": "Hypothesis-driven debugging - test likely causes first",
480
+ "printf": "Printf debugging - add logs and observe",
481
+ "whatever-works": "Whatever works to fix the issue quickly",
482
+ };
483
+
484
+ const refactorDescriptions: Record<string, string> = {
485
+ "proactive": "Proactively suggest refactoring opportunities",
486
+ "on-request": "Refactor only when asked",
487
+ "boy-scout": "Boy scout rule - leave code better than you found it",
488
+ "if-broken": "Don't refactor working code unless necessary",
489
+ };
490
+
491
+ const profileContent = `---
313
492
  name: ${name}
493
+ role: ${role}
314
494
  style: ${style}
495
+ personality: ${claudePersonality}
315
496
  ---
316
497
 
317
- # Communication Preferences
498
+ # Who I Am
318
499
 
319
- ${styleDescriptions[style].map((s) => `- ${s}`).join("\n")}
500
+ ${roleDescriptions[role as string]}
501
+
502
+ # How Claude Should Behave
503
+
504
+ ${personalityDescriptions[claudePersonality as string].map((s) => `- ${s}`).join("\n")}
505
+
506
+ # Communication Style
507
+
508
+ ${styleDescriptions[style as string].map((s) => `- ${s}`).join("\n")}
320
509
  - No emojis unless explicitly requested
321
510
  - Show code when it's clearer than explanation
322
511
 
323
- # Work Style
512
+ # Development Workflow
513
+
514
+ ## Planning
515
+ - ${planningDescriptions[planningApproach as string]}
516
+
517
+ ## Testing
518
+ - ${testingDescriptions[testingApproach as string]}
519
+
520
+ ## Code Review
521
+ - ${reviewDescriptions[codeReview as string]}
522
+
523
+ ## Git Workflow
524
+ - ${gitDescriptions[gitWorkflow as string]}
525
+
526
+ ## Documentation
527
+ - ${docDescriptions[documentationApproach as string]}
528
+
529
+ ## Debugging
530
+ - ${debugDescriptions[debuggingStyle as string]}
324
531
 
325
- - Prefer practical solutions over theoretical
326
- - Match existing code patterns in the project
532
+ ## Refactoring
533
+ - ${refactorDescriptions[refactoringPreference as string]}
327
534
  `;
328
535
 
329
- await writeFile(thinkPath(CONFIG.files.profile), profileContent);
330
-
331
- // Generate tools preferences
332
- const toolsSections: string[] = ["# Tool Preferences"];
333
-
334
- // Runtime & Package Manager
335
- const pmAlternatives = ["npm", "pnpm", "yarn", "Node.js"].filter(
336
- (p) => p.toLowerCase() !== packageManager.toLowerCase()
337
- );
338
- const pmSection = [`- Use ${packageManager === "bun" ? "Bun" : packageManager}${pmAlternatives.length ? ` (not ${pmAlternatives.join(", ")})` : ""}`];
339
-
340
- if (bunFeatures.length > 0) {
341
- if (bunFeatures.includes("catalog")) pmSection.push("- Use Bun dependency catalog for shared deps");
342
- if (bunFeatures.includes("workspaces")) pmSection.push("- Use Bun workspaces for monorepos");
343
- if (bunFeatures.includes("macros")) pmSection.push("- Use Bun macros for compile-time code");
344
- if (bunFeatures.includes("shell")) pmSection.push("- Use Bun shell ($``) for shell commands");
345
- if (bunFeatures.includes("sqlite")) pmSection.push("- Use bun:sqlite for embedded database");
346
- if (bunFeatures.includes("test")) pmSection.push("- Use `bun test` for testing");
347
- } else {
348
- pmSection.push(`- Use \`${packageManager} test\` for testing`);
349
- }
536
+ await writeFile(thinkPath(CONFIG.files.profile), profileContent);
537
+
538
+ // Generate tools preferences
539
+ const toolsSections: string[] = ["# Tool Preferences"];
540
+
541
+ // Runtime & Package Manager
542
+ const pmAlternatives = ["npm", "pnpm", "yarn", "Node.js"].filter(
543
+ (pm) => pm.toLowerCase() !== (packageManager as string).toLowerCase()
544
+ );
545
+ const pmSection = [`- Use ${packageManager === "bun" ? "Bun" : packageManager}${pmAlternatives.length ? ` (not ${pmAlternatives.join(", ")})` : ""}`];
546
+
547
+ if (bunFeatures.length > 0) {
548
+ if (bunFeatures.includes("catalog")) pmSection.push("- Use Bun dependency catalog for shared deps");
549
+ if (bunFeatures.includes("workspaces")) pmSection.push("- Use Bun workspaces for monorepos");
550
+ if (bunFeatures.includes("macros")) pmSection.push("- Use Bun macros for compile-time code");
551
+ if (bunFeatures.includes("shell")) pmSection.push("- Use Bun shell ($``) for shell commands");
552
+ if (bunFeatures.includes("sqlite")) pmSection.push("- Use bun:sqlite for embedded database");
553
+ if (bunFeatures.includes("test")) pmSection.push("- Use `bun test` for testing");
554
+ } else {
555
+ pmSection.push(`- Use \`${packageManager} test\` for testing`);
556
+ }
350
557
 
351
- toolsSections.push(`
558
+ toolsSections.push(`
352
559
  ## Runtime & Package Manager
353
560
  ${pmSection.join("\n")}`);
354
561
 
355
- // Languages
356
- toolsSections.push(`
562
+ // Languages
563
+ toolsSections.push(`
357
564
  ## Languages
358
- ${languages.map((l) => `- ${l}`).join("\n")}`);
565
+ ${(languages as string[]).map((l) => `- ${l}`).join("\n")}`);
359
566
 
360
- // Backend
361
- if (backend !== "none") {
362
- toolsSections.push(`
567
+ // Backend
568
+ if (backend !== "none") {
569
+ toolsSections.push(`
363
570
  ## Backend
364
571
  - ${backend}`);
365
- }
572
+ }
366
573
 
367
- // Frontend
368
- if (frontend !== "none") {
369
- const frontendAlternatives = ["Next.js", "Vue", "Svelte", "Angular"].filter(
370
- (f) => f.toLowerCase() !== frontend.toLowerCase()
371
- );
372
- toolsSections.push(`
574
+ // Frontend
575
+ if ((frontend as string[]).length > 0) {
576
+ toolsSections.push(`
373
577
  ## Frontend
374
- - ${frontend}${frontendAlternatives.length ? ` (not ${frontendAlternatives.slice(0, 2).join(", ")})` : ""}
578
+ ${(frontend as string[]).map((f) => `- ${f}`).join("\n")}
375
579
  - Prefer functional components with hooks`);
580
+ }
376
581
 
377
- // CSS
378
- if (css !== "none") {
379
- toolsSections.push(`- ${css} for styling`);
380
- }
381
- }
582
+ // CSS
583
+ if ((css as string[]).length > 0) {
584
+ toolsSections.push(`
585
+ ## CSS / UI
586
+ ${(css as string[]).map((c) => `- ${c}`).join("\n")}`);
587
+ }
382
588
 
383
- // Database
384
- if (database !== "none") {
385
- const dbAlternatives = ["SQLite", "MySQL", "MongoDB", "PostgreSQL"].filter(
386
- (d) => d.toLowerCase() !== database.toLowerCase()
387
- );
388
- toolsSections.push(`
589
+ // Database
590
+ if ((database as string[]).length > 0) {
591
+ toolsSections.push(`
389
592
  ## Database
390
- - ${database}${dbAlternatives.length ? ` (not ${dbAlternatives.slice(0, 3).join(", ")})` : ""}`);
391
- }
593
+ ${(database as string[]).map((d) => `- ${d}`).join("\n")}`);
594
+ }
392
595
 
393
- // ORM
394
- if (orm.length > 0) {
395
- toolsSections.push(`
596
+ // ORM
597
+ if ((orm as string[]).length > 0) {
598
+ toolsSections.push(`
396
599
  ## ORM / Database Tools
397
- ${orm.map((o) => `- ${o}`).join("\n")}`);
398
- }
600
+ ${(orm as string[]).map((o) => `- ${o}`).join("\n")}`);
601
+ }
399
602
 
400
- // Auth
401
- if (auth.length > 0) {
402
- toolsSections.push(`
603
+ // Auth
604
+ if ((auth as string[]).length > 0) {
605
+ toolsSections.push(`
403
606
  ## Authentication
404
- ${auth.map((a) => `- ${a}`).join("\n")}`);
405
- }
607
+ ${(auth as string[]).map((a) => `- ${a}`).join("\n")}`);
608
+ }
406
609
 
407
- // Infrastructure
408
- if (infrastructure !== "none") {
409
- const infraAlternatives = infrastructure.includes("Kubernetes")
410
- ? []
411
- : ["Kubernetes"];
412
- toolsSections.push(`
610
+ // Infrastructure
611
+ if ((infrastructure as string[]).length > 0) {
612
+ toolsSections.push(`
413
613
  ## Infrastructure
414
- - ${infrastructure} for containerization${infraAlternatives.length ? ` (not ${infraAlternatives.join(", ")})` : ""}
415
- - Prefer simple Docker Compose for local dev`);
416
- }
614
+ ${(infrastructure as string[]).map((i) => `- ${i}`).join("\n")}`);
615
+ }
417
616
 
418
- // Monorepo
419
- if (monorepo !== "none") {
420
- toolsSections.push(`
617
+ // Monorepo
618
+ if (monorepo !== "none") {
619
+ toolsSections.push(`
421
620
  ## Monorepo
422
621
  - ${monorepo}`);
423
- }
622
+ }
424
623
 
425
- // Testing
426
- if (testing.length > 0) {
427
- toolsSections.push(`
624
+ // Testing
625
+ if ((testing as string[]).length > 0) {
626
+ toolsSections.push(`
428
627
  ## Testing
429
- ${testing.map((t) => `- ${t}`).join("\n")}`);
430
- }
628
+ ${(testing as string[]).map((t) => `- ${t}`).join("\n")}`);
629
+ }
431
630
 
432
- // Linting & Formatting
433
- if (linting.length > 0) {
434
- toolsSections.push(`
631
+ // Linting & Formatting
632
+ if ((linting as string[]).length > 0) {
633
+ toolsSections.push(`
435
634
  ## Linting & Formatting
436
- ${linting.map((l) => `- ${l}`).join("\n")}
635
+ ${(linting as string[]).map((l) => `- ${l}`).join("\n")}
437
636
  - Use project's existing config when present`);
438
- }
637
+ }
439
638
 
440
- // Validation
441
- if (validation.length > 0) {
442
- toolsSections.push(`
639
+ // Validation
640
+ if ((validation as string[]).length > 0) {
641
+ toolsSections.push(`
443
642
  ## Validation & Schema
444
- ${validation.map((v) => `- ${v}`).join("\n")}`);
445
- }
643
+ ${(validation as string[]).map((v) => `- ${v}`).join("\n")}`);
644
+ }
446
645
 
447
- // Editor
448
- toolsSections.push(`
646
+ // Editor
647
+ toolsSections.push(`
449
648
  ## Editor
450
649
  - Primary: ${editor}`);
451
650
 
452
- const toolsContent = toolsSections.join("\n");
651
+ const toolsContent = toolsSections.join("\n");
652
+ await writeFile(thinkPath(CONFIG.files.tools), toolsContent);
453
653
 
454
- await writeFile(thinkPath(CONFIG.files.tools), toolsContent);
455
-
456
- // Generate anti-patterns if selected
457
- if (avoidAnswer === "all") {
458
- const antiSections: string[] = [`# Anti-Patterns to Avoid
654
+ // Generate anti-patterns if selected
655
+ if (avoidAnswer === "all") {
656
+ const antiSections: string[] = [`# Anti-Patterns to Avoid
459
657
 
460
658
  ## Code Style
461
659
  - Don't add comments for obvious code
@@ -468,53 +666,51 @@ ${validation.map((v) => `- ${v}`).join("\n")}`);
468
666
  - Don't create unnecessary indirection
469
667
  - Don't add "future-proofing" complexity`];
470
668
 
471
- // Tech choices to avoid
472
- const techAvoid: string[] = [];
473
- if (packageManager === "bun") {
474
- techAvoid.push("- Don't suggest npm/yarn/pnpm - use Bun");
475
- }
476
- if (frontend === "React") {
477
- techAvoid.push("- Don't suggest Next.js - use plain React");
478
- }
479
- if (infrastructure === "Docker" || infrastructure === "Docker Compose") {
669
+ // Tech choices to avoid
670
+ const techAvoid: string[] = [];
671
+ if (packageManager === "bun") {
672
+ techAvoid.push("- Don't suggest npm/yarn/pnpm - use Bun");
673
+ }
674
+ if ((frontend as string[]).includes("React") && !(frontend as string[]).includes("Next.js")) {
675
+ techAvoid.push("- Don't suggest Next.js - use plain React");
676
+ }
677
+ if ((infrastructure as string[]).includes("Docker") || (infrastructure as string[]).includes("Docker Compose")) {
678
+ if (!(infrastructure as string[]).includes("Kubernetes")) {
480
679
  techAvoid.push("- Don't suggest Kubernetes - use Docker");
481
680
  }
482
- if (database === "PostgreSQL") {
483
- techAvoid.push("- Don't suggest SQLite/MySQL/MongoDB - use PostgreSQL");
484
- }
681
+ }
485
682
 
486
- if (techAvoid.length > 0) {
487
- antiSections.push(`
683
+ if (techAvoid.length > 0) {
684
+ antiSections.push(`
488
685
  ## Tech Choices
489
686
  ${techAvoid.join("\n")}`);
490
- }
687
+ }
491
688
 
492
- antiSections.push(`
689
+ antiSections.push(`
493
690
  ## Communication
494
691
  - Don't explain obvious things
495
692
  - Don't repeat back what was just said
496
693
  - Don't pad responses with unnecessary context
497
694
  `);
498
695
 
499
- await writeFile(thinkPath(CONFIG.files.antiPatterns), antiSections.join("\n"));
500
- }
696
+ await writeFile(thinkPath(CONFIG.files.antiPatterns), antiSections.join("\n"));
697
+ }
501
698
 
502
- console.log(chalk.green("Profile created!\n"));
699
+ s.stop("Profile created");
503
700
 
504
- // Sync
505
- await syncCommand();
701
+ // Sync
702
+ await syncCommand();
506
703
 
507
- console.log();
508
- console.log(chalk.bold("Your profile is ready."));
509
- console.log(chalk.dim("Start a new Claude session to use your context."));
510
- console.log();
511
- console.log("To customize further:");
512
- console.log(` ${chalk.cyan("think edit profile")} Edit your profile`);
513
- console.log(` ${chalk.cyan("think edit patterns")} Add coding patterns`);
514
- console.log(` ${chalk.cyan("think learn \"...\"")} Add learnings over time`);
704
+ p.outro(chalk.green("Your profile is ready!"));
515
705
 
516
- } catch (error) {
517
- rl.close();
518
- throw error;
519
- }
706
+ console.log();
707
+ console.log("To customize further:");
708
+ console.log(` ${chalk.cyan("think edit profile")} Edit your profile`);
709
+ console.log(` ${chalk.cyan("think edit patterns")} Add coding patterns`);
710
+ console.log(` ${chalk.cyan("think learn \"...\"")} Add learnings over time`);
711
+ }
712
+
713
+ function handleCancel(): void {
714
+ p.cancel("Setup cancelled");
715
+ process.exit(0);
520
716
  }