claude-think 0.5.2 → 0.5.3
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/CHANGELOG.md +11 -0
- package/README.md +1 -1
- package/package.json +1 -1
- package/src/cli/commands/setup.ts +13 -173
- package/src/core/profile-generator.ts +290 -0
- package/src/tui/App.tsx +0 -12
- package/src/tui/components/ProfileSwitcher.tsx +96 -5
- package/src/tui/components/StatusBar.tsx +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,17 @@ 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.5.3] - 2026-02-09
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
- **Inline profile creation in TUI** — create new profiles with role-based defaults without leaving the TUI
|
|
12
|
+
- Select a role (Senior Dev, Mid-level, Junior, Founder, Student, Hobbyist) and profile files are auto-generated
|
|
13
|
+
- No longer exits to `think setup` CLI wizard when creating empty profiles
|
|
14
|
+
- **`P profiles` visible in status bar** — profile switching shortcut is now discoverable
|
|
15
|
+
|
|
16
|
+
### Changed
|
|
17
|
+
- Extracted profile generation logic into shared `profile-generator.ts` module (used by both CLI setup and TUI)
|
|
18
|
+
|
|
8
19
|
## [0.5.2] - 2026-02-08
|
|
9
20
|
|
|
10
21
|
### Fixed
|
package/README.md
CHANGED
|
@@ -79,7 +79,7 @@ Switch between different configurations for work, personal projects, or clients:
|
|
|
79
79
|
think switch work # Switch profile (auto-syncs)
|
|
80
80
|
```
|
|
81
81
|
|
|
82
|
-
Press `P` in the TUI to manage profiles interactively (create, delete, switch).
|
|
82
|
+
Press `P` in the TUI to manage profiles interactively (create, delete, switch). New profiles can be created with role-based defaults without leaving the TUI.
|
|
83
83
|
|
|
84
84
|
## TUI
|
|
85
85
|
|
package/package.json
CHANGED
|
@@ -7,179 +7,19 @@ import { ensureProfilesStructure } from "../../core/profiles.ts";
|
|
|
7
7
|
import { generatePlugin } from "../../core/generator.ts";
|
|
8
8
|
import { detectProject } from "../../core/project-detect.ts";
|
|
9
9
|
import type { ProjectInfo } from "../../core/project-detect.ts";
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
],
|
|
24
|
-
detailed: [
|
|
25
|
-
"Provide thorough explanations",
|
|
26
|
-
"Include context and reasoning",
|
|
27
|
-
"Explain trade-offs and alternatives",
|
|
28
|
-
],
|
|
29
|
-
};
|
|
30
|
-
|
|
31
|
-
const roleDescriptions: Record<string, string> = {
|
|
32
|
-
"senior-dev": "Senior developer - experienced and autonomous, prefers concise guidance",
|
|
33
|
-
"mid-dev": "Mid-level developer - competent but appreciates context on complex topics",
|
|
34
|
-
"junior-dev": "Junior developer - learning, benefits from more explanation and examples",
|
|
35
|
-
founder: "Founder/Tech Lead - focused on shipping, pragmatic decisions over perfect code",
|
|
36
|
-
student: "Student - learning fundamentals, explain concepts when relevant",
|
|
37
|
-
hobbyist: "Hobbyist - exploring for fun, balance learning with getting things done",
|
|
38
|
-
};
|
|
39
|
-
|
|
40
|
-
const personalityDescriptions: Record<string, string[]> = {
|
|
41
|
-
"pair-programmer": [
|
|
42
|
-
"Act as a pair programmer - think out loud, collaborate on solutions",
|
|
43
|
-
"Discuss trade-offs and alternatives when relevant",
|
|
44
|
-
"Catch potential issues early, suggest improvements as we go",
|
|
45
|
-
],
|
|
46
|
-
"senior-dev": [
|
|
47
|
-
"Act as a senior developer - give direction, review approaches",
|
|
48
|
-
"Point out potential issues and better patterns",
|
|
49
|
-
"Be opinionated when it matters, flexible when it doesn't",
|
|
50
|
-
],
|
|
51
|
-
assistant: [
|
|
52
|
-
"Act as an efficient assistant - execute tasks with minimal chatter",
|
|
53
|
-
"Ask clarifying questions only when truly needed",
|
|
54
|
-
"Focus on delivering what was asked",
|
|
55
|
-
],
|
|
56
|
-
mentor: [
|
|
57
|
-
"Act as a mentor - teach concepts, explain the 'why'",
|
|
58
|
-
"Use opportunities to share knowledge",
|
|
59
|
-
"Suggest learning resources when helpful",
|
|
60
|
-
],
|
|
61
|
-
"rubber-duck": [
|
|
62
|
-
"Act as a rubber duck - help me think through problems",
|
|
63
|
-
"Ask probing questions rather than giving immediate answers",
|
|
64
|
-
"Help me discover solutions myself",
|
|
65
|
-
],
|
|
66
|
-
};
|
|
67
|
-
|
|
68
|
-
const planningDescriptions: Record<string, string> = {
|
|
69
|
-
"plan-first": "Discuss architecture and approach before writing code",
|
|
70
|
-
iterate: "Start with a rough plan, refine as we go",
|
|
71
|
-
"dive-in": "Start coding quickly, figure out structure as needed",
|
|
72
|
-
};
|
|
73
|
-
|
|
74
|
-
const testingDescriptions: Record<string, string> = {
|
|
75
|
-
tdd: "Write tests first (TDD), then implement",
|
|
76
|
-
"test-after": "Write tests after implementation",
|
|
77
|
-
"critical-paths": "Test critical paths and edge cases",
|
|
78
|
-
minimal: "Minimal testing - add tests when necessary",
|
|
79
|
-
};
|
|
80
|
-
|
|
81
|
-
const reviewDescriptions: Record<string, string> = {
|
|
82
|
-
"review-before-commit": "Review changes before committing - catch issues early",
|
|
83
|
-
"review-on-request": "Review code when explicitly asked",
|
|
84
|
-
"self-review": "I review my own code, no automatic reviews needed",
|
|
85
|
-
};
|
|
86
|
-
|
|
87
|
-
const gitDescriptions: Record<string, string> = {
|
|
88
|
-
"small-commits": "Small, atomic commits - easy to review and revert",
|
|
89
|
-
"feature-branches": "Feature branches with squash merges",
|
|
90
|
-
"trunk-based": "Trunk-based development with feature flags",
|
|
91
|
-
flexible: "Flexible git workflow based on project needs",
|
|
92
|
-
};
|
|
93
|
-
|
|
94
|
-
const docDescriptions: Record<string, string> = {
|
|
95
|
-
inline: "Document with inline comments as code is written",
|
|
96
|
-
"readme-driven": "README-driven development - docs first",
|
|
97
|
-
minimal: "Minimal documentation - code should be self-documenting",
|
|
98
|
-
"on-request": "Add documentation when requested",
|
|
99
|
-
};
|
|
100
|
-
|
|
101
|
-
const debugDescriptions: Record<string, string> = {
|
|
102
|
-
systematic: "Debug systematically - isolate, reproduce, trace",
|
|
103
|
-
hypothesis: "Hypothesis-driven debugging - test likely causes first",
|
|
104
|
-
printf: "Printf debugging - add logs and observe",
|
|
105
|
-
"whatever-works": "Whatever works to fix the issue quickly",
|
|
106
|
-
};
|
|
107
|
-
|
|
108
|
-
const refactorDescriptions: Record<string, string> = {
|
|
109
|
-
proactive: "Proactively suggest refactoring opportunities",
|
|
110
|
-
"on-request": "Refactor only when asked",
|
|
111
|
-
"boy-scout": "Boy scout rule - leave code better than you found it",
|
|
112
|
-
"if-broken": "Don't refactor working code unless necessary",
|
|
113
|
-
};
|
|
114
|
-
|
|
115
|
-
// ── Role-based workflow defaults ──────────────────────────────────
|
|
116
|
-
|
|
117
|
-
interface WorkflowDefaults {
|
|
118
|
-
planning: string;
|
|
119
|
-
testing: string;
|
|
120
|
-
review: string;
|
|
121
|
-
git: string;
|
|
122
|
-
docs: string;
|
|
123
|
-
debug: string;
|
|
124
|
-
refactor: string;
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
const roleWorkflowDefaults: Record<string, WorkflowDefaults> = {
|
|
128
|
-
"senior-dev": {
|
|
129
|
-
planning: "plan-first",
|
|
130
|
-
testing: "tdd",
|
|
131
|
-
review: "review-before-commit",
|
|
132
|
-
git: "small-commits",
|
|
133
|
-
docs: "minimal",
|
|
134
|
-
debug: "systematic",
|
|
135
|
-
refactor: "boy-scout",
|
|
136
|
-
},
|
|
137
|
-
"mid-dev": {
|
|
138
|
-
planning: "iterate",
|
|
139
|
-
testing: "test-after",
|
|
140
|
-
review: "review-before-commit",
|
|
141
|
-
git: "feature-branches",
|
|
142
|
-
docs: "inline",
|
|
143
|
-
debug: "hypothesis",
|
|
144
|
-
refactor: "on-request",
|
|
145
|
-
},
|
|
146
|
-
"junior-dev": {
|
|
147
|
-
planning: "plan-first",
|
|
148
|
-
testing: "test-after",
|
|
149
|
-
review: "review-before-commit",
|
|
150
|
-
git: "feature-branches",
|
|
151
|
-
docs: "inline",
|
|
152
|
-
debug: "systematic",
|
|
153
|
-
refactor: "proactive",
|
|
154
|
-
},
|
|
155
|
-
founder: {
|
|
156
|
-
planning: "dive-in",
|
|
157
|
-
testing: "critical-paths",
|
|
158
|
-
review: "self-review",
|
|
159
|
-
git: "trunk-based",
|
|
160
|
-
docs: "minimal",
|
|
161
|
-
debug: "whatever-works",
|
|
162
|
-
refactor: "if-broken",
|
|
163
|
-
},
|
|
164
|
-
student: {
|
|
165
|
-
planning: "plan-first",
|
|
166
|
-
testing: "test-after",
|
|
167
|
-
review: "review-on-request",
|
|
168
|
-
git: "feature-branches",
|
|
169
|
-
docs: "inline",
|
|
170
|
-
debug: "systematic",
|
|
171
|
-
refactor: "proactive",
|
|
172
|
-
},
|
|
173
|
-
hobbyist: {
|
|
174
|
-
planning: "iterate",
|
|
175
|
-
testing: "minimal",
|
|
176
|
-
review: "self-review",
|
|
177
|
-
git: "flexible",
|
|
178
|
-
docs: "on-request",
|
|
179
|
-
debug: "printf",
|
|
180
|
-
refactor: "if-broken",
|
|
181
|
-
},
|
|
182
|
-
};
|
|
10
|
+
import {
|
|
11
|
+
styleDescriptions,
|
|
12
|
+
roleDescriptions,
|
|
13
|
+
personalityDescriptions,
|
|
14
|
+
planningDescriptions,
|
|
15
|
+
testingDescriptions,
|
|
16
|
+
reviewDescriptions,
|
|
17
|
+
gitDescriptions,
|
|
18
|
+
docDescriptions,
|
|
19
|
+
debugDescriptions,
|
|
20
|
+
refactorDescriptions,
|
|
21
|
+
roleWorkflowDefaults,
|
|
22
|
+
} from "../../core/profile-generator.ts";
|
|
183
23
|
|
|
184
24
|
// ── Helpers ───────────────────────────────────────────────────────
|
|
185
25
|
|
|
@@ -0,0 +1,290 @@
|
|
|
1
|
+
import { writeFile } from "fs/promises";
|
|
2
|
+
import { join } from "path";
|
|
3
|
+
import { CONFIG } from "./config.ts";
|
|
4
|
+
|
|
5
|
+
// ── Description maps ──────────────────────────────────────────────
|
|
6
|
+
|
|
7
|
+
export const styleDescriptions: Record<string, string[]> = {
|
|
8
|
+
direct: [
|
|
9
|
+
"Be direct and minimal - no fluff, just answers and code",
|
|
10
|
+
"Skip lengthy reasoning unless asked",
|
|
11
|
+
"Don't explain obvious things",
|
|
12
|
+
],
|
|
13
|
+
conversational: [
|
|
14
|
+
"Be friendly but efficient",
|
|
15
|
+
"Brief explanations when helpful",
|
|
16
|
+
"Keep a conversational tone",
|
|
17
|
+
],
|
|
18
|
+
detailed: [
|
|
19
|
+
"Provide thorough explanations",
|
|
20
|
+
"Include context and reasoning",
|
|
21
|
+
"Explain trade-offs and alternatives",
|
|
22
|
+
],
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
export const roleDescriptions: Record<string, string> = {
|
|
26
|
+
"senior-dev": "Senior developer - experienced and autonomous, prefers concise guidance",
|
|
27
|
+
"mid-dev": "Mid-level developer - competent but appreciates context on complex topics",
|
|
28
|
+
"junior-dev": "Junior developer - learning, benefits from more explanation and examples",
|
|
29
|
+
founder: "Founder/Tech Lead - focused on shipping, pragmatic decisions over perfect code",
|
|
30
|
+
student: "Student - learning fundamentals, explain concepts when relevant",
|
|
31
|
+
hobbyist: "Hobbyist - exploring for fun, balance learning with getting things done",
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
export const personalityDescriptions: Record<string, string[]> = {
|
|
35
|
+
"pair-programmer": [
|
|
36
|
+
"Act as a pair programmer - think out loud, collaborate on solutions",
|
|
37
|
+
"Discuss trade-offs and alternatives when relevant",
|
|
38
|
+
"Catch potential issues early, suggest improvements as we go",
|
|
39
|
+
],
|
|
40
|
+
"senior-dev": [
|
|
41
|
+
"Act as a senior developer - give direction, review approaches",
|
|
42
|
+
"Point out potential issues and better patterns",
|
|
43
|
+
"Be opinionated when it matters, flexible when it doesn't",
|
|
44
|
+
],
|
|
45
|
+
assistant: [
|
|
46
|
+
"Act as an efficient assistant - execute tasks with minimal chatter",
|
|
47
|
+
"Ask clarifying questions only when truly needed",
|
|
48
|
+
"Focus on delivering what was asked",
|
|
49
|
+
],
|
|
50
|
+
mentor: [
|
|
51
|
+
"Act as a mentor - teach concepts, explain the 'why'",
|
|
52
|
+
"Use opportunities to share knowledge",
|
|
53
|
+
"Suggest learning resources when helpful",
|
|
54
|
+
],
|
|
55
|
+
"rubber-duck": [
|
|
56
|
+
"Act as a rubber duck - help me think through problems",
|
|
57
|
+
"Ask probing questions rather than giving immediate answers",
|
|
58
|
+
"Help me discover solutions myself",
|
|
59
|
+
],
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
export const planningDescriptions: Record<string, string> = {
|
|
63
|
+
"plan-first": "Discuss architecture and approach before writing code",
|
|
64
|
+
iterate: "Start with a rough plan, refine as we go",
|
|
65
|
+
"dive-in": "Start coding quickly, figure out structure as needed",
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
export const testingDescriptions: Record<string, string> = {
|
|
69
|
+
tdd: "Write tests first (TDD), then implement",
|
|
70
|
+
"test-after": "Write tests after implementation",
|
|
71
|
+
"critical-paths": "Test critical paths and edge cases",
|
|
72
|
+
minimal: "Minimal testing - add tests when necessary",
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
export const reviewDescriptions: Record<string, string> = {
|
|
76
|
+
"review-before-commit": "Review changes before committing - catch issues early",
|
|
77
|
+
"review-on-request": "Review code when explicitly asked",
|
|
78
|
+
"self-review": "I review my own code, no automatic reviews needed",
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
export const gitDescriptions: Record<string, string> = {
|
|
82
|
+
"small-commits": "Small, atomic commits - easy to review and revert",
|
|
83
|
+
"feature-branches": "Feature branches with squash merges",
|
|
84
|
+
"trunk-based": "Trunk-based development with feature flags",
|
|
85
|
+
flexible: "Flexible git workflow based on project needs",
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
export const docDescriptions: Record<string, string> = {
|
|
89
|
+
inline: "Document with inline comments as code is written",
|
|
90
|
+
"readme-driven": "README-driven development - docs first",
|
|
91
|
+
minimal: "Minimal documentation - code should be self-documenting",
|
|
92
|
+
"on-request": "Add documentation when requested",
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
export const debugDescriptions: Record<string, string> = {
|
|
96
|
+
systematic: "Debug systematically - isolate, reproduce, trace",
|
|
97
|
+
hypothesis: "Hypothesis-driven debugging - test likely causes first",
|
|
98
|
+
printf: "Printf debugging - add logs and observe",
|
|
99
|
+
"whatever-works": "Whatever works to fix the issue quickly",
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
export const refactorDescriptions: Record<string, string> = {
|
|
103
|
+
proactive: "Proactively suggest refactoring opportunities",
|
|
104
|
+
"on-request": "Refactor only when asked",
|
|
105
|
+
"boy-scout": "Boy scout rule - leave code better than you found it",
|
|
106
|
+
"if-broken": "Don't refactor working code unless necessary",
|
|
107
|
+
};
|
|
108
|
+
|
|
109
|
+
// ── Role-based workflow defaults ──────────────────────────────────
|
|
110
|
+
|
|
111
|
+
export interface WorkflowDefaults {
|
|
112
|
+
planning: string;
|
|
113
|
+
testing: string;
|
|
114
|
+
review: string;
|
|
115
|
+
git: string;
|
|
116
|
+
docs: string;
|
|
117
|
+
debug: string;
|
|
118
|
+
refactor: string;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
export const roleWorkflowDefaults: Record<string, WorkflowDefaults> = {
|
|
122
|
+
"senior-dev": {
|
|
123
|
+
planning: "plan-first",
|
|
124
|
+
testing: "tdd",
|
|
125
|
+
review: "review-before-commit",
|
|
126
|
+
git: "small-commits",
|
|
127
|
+
docs: "minimal",
|
|
128
|
+
debug: "systematic",
|
|
129
|
+
refactor: "boy-scout",
|
|
130
|
+
},
|
|
131
|
+
"mid-dev": {
|
|
132
|
+
planning: "iterate",
|
|
133
|
+
testing: "test-after",
|
|
134
|
+
review: "review-before-commit",
|
|
135
|
+
git: "feature-branches",
|
|
136
|
+
docs: "inline",
|
|
137
|
+
debug: "hypothesis",
|
|
138
|
+
refactor: "on-request",
|
|
139
|
+
},
|
|
140
|
+
"junior-dev": {
|
|
141
|
+
planning: "plan-first",
|
|
142
|
+
testing: "test-after",
|
|
143
|
+
review: "review-before-commit",
|
|
144
|
+
git: "feature-branches",
|
|
145
|
+
docs: "inline",
|
|
146
|
+
debug: "systematic",
|
|
147
|
+
refactor: "proactive",
|
|
148
|
+
},
|
|
149
|
+
founder: {
|
|
150
|
+
planning: "dive-in",
|
|
151
|
+
testing: "critical-paths",
|
|
152
|
+
review: "self-review",
|
|
153
|
+
git: "trunk-based",
|
|
154
|
+
docs: "minimal",
|
|
155
|
+
debug: "whatever-works",
|
|
156
|
+
refactor: "if-broken",
|
|
157
|
+
},
|
|
158
|
+
student: {
|
|
159
|
+
planning: "plan-first",
|
|
160
|
+
testing: "test-after",
|
|
161
|
+
review: "review-on-request",
|
|
162
|
+
git: "feature-branches",
|
|
163
|
+
docs: "inline",
|
|
164
|
+
debug: "systematic",
|
|
165
|
+
refactor: "proactive",
|
|
166
|
+
},
|
|
167
|
+
hobbyist: {
|
|
168
|
+
planning: "iterate",
|
|
169
|
+
testing: "minimal",
|
|
170
|
+
review: "self-review",
|
|
171
|
+
git: "flexible",
|
|
172
|
+
docs: "on-request",
|
|
173
|
+
debug: "printf",
|
|
174
|
+
refactor: "if-broken",
|
|
175
|
+
},
|
|
176
|
+
};
|
|
177
|
+
|
|
178
|
+
// ── Role-based personality/style defaults ─────────────────────────
|
|
179
|
+
|
|
180
|
+
const rolePersonalityDefaults: Record<string, string> = {
|
|
181
|
+
"senior-dev": "assistant",
|
|
182
|
+
"mid-dev": "pair-programmer",
|
|
183
|
+
"junior-dev": "mentor",
|
|
184
|
+
founder: "assistant",
|
|
185
|
+
student: "mentor",
|
|
186
|
+
hobbyist: "pair-programmer",
|
|
187
|
+
};
|
|
188
|
+
|
|
189
|
+
const roleStyleDefaults: Record<string, string> = {
|
|
190
|
+
"senior-dev": "direct",
|
|
191
|
+
"mid-dev": "conversational",
|
|
192
|
+
"junior-dev": "detailed",
|
|
193
|
+
founder: "direct",
|
|
194
|
+
student: "detailed",
|
|
195
|
+
hobbyist: "conversational",
|
|
196
|
+
};
|
|
197
|
+
|
|
198
|
+
// ── Profile generation ────────────────────────────────────────────
|
|
199
|
+
|
|
200
|
+
export interface ProfileGenerationOptions {
|
|
201
|
+
name?: string;
|
|
202
|
+
role: string;
|
|
203
|
+
style?: string;
|
|
204
|
+
personality?: string;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* Generate profile files with role-based defaults.
|
|
209
|
+
* Creates profile.md and preferences/anti-patterns.md in the given profile directory.
|
|
210
|
+
*/
|
|
211
|
+
export async function generateProfileFiles(
|
|
212
|
+
profileDir: string,
|
|
213
|
+
options: ProfileGenerationOptions,
|
|
214
|
+
): Promise<void> {
|
|
215
|
+
const { role } = options;
|
|
216
|
+
const name = options.name ?? "";
|
|
217
|
+
const style = options.style ?? roleStyleDefaults[role] ?? "direct";
|
|
218
|
+
const personality = options.personality ?? rolePersonalityDefaults[role] ?? "assistant";
|
|
219
|
+
const defaults = roleWorkflowDefaults[role] ?? roleWorkflowDefaults["senior-dev"]!;
|
|
220
|
+
|
|
221
|
+
// ── Write profile.md ────────────────────────────────────────────
|
|
222
|
+
const profileContent = `---
|
|
223
|
+
name: ${name}
|
|
224
|
+
role: ${role}
|
|
225
|
+
style: ${style}
|
|
226
|
+
personality: ${personality}
|
|
227
|
+
---
|
|
228
|
+
|
|
229
|
+
# Who I Am
|
|
230
|
+
|
|
231
|
+
${roleDescriptions[role] ?? role}
|
|
232
|
+
|
|
233
|
+
# How Claude Should Behave
|
|
234
|
+
|
|
235
|
+
${(personalityDescriptions[personality] ?? []).map((line) => `- ${line}`).join("\n")}
|
|
236
|
+
|
|
237
|
+
# Communication Style
|
|
238
|
+
|
|
239
|
+
${(styleDescriptions[style] ?? []).map((line) => `- ${line}`).join("\n")}
|
|
240
|
+
- No emojis unless explicitly requested
|
|
241
|
+
- Show code when it's clearer than explanation
|
|
242
|
+
|
|
243
|
+
# Development Workflow
|
|
244
|
+
|
|
245
|
+
## Planning
|
|
246
|
+
- ${planningDescriptions[defaults.planning] ?? defaults.planning}
|
|
247
|
+
|
|
248
|
+
## Testing
|
|
249
|
+
- ${testingDescriptions[defaults.testing] ?? defaults.testing}
|
|
250
|
+
|
|
251
|
+
## Code Review
|
|
252
|
+
- ${reviewDescriptions[defaults.review] ?? defaults.review}
|
|
253
|
+
|
|
254
|
+
## Git Workflow
|
|
255
|
+
- ${gitDescriptions[defaults.git] ?? defaults.git}
|
|
256
|
+
|
|
257
|
+
## Documentation
|
|
258
|
+
- ${docDescriptions[defaults.docs] ?? defaults.docs}
|
|
259
|
+
|
|
260
|
+
## Debugging
|
|
261
|
+
- ${debugDescriptions[defaults.debug] ?? defaults.debug}
|
|
262
|
+
|
|
263
|
+
## Refactoring
|
|
264
|
+
- ${refactorDescriptions[defaults.refactor] ?? defaults.refactor}
|
|
265
|
+
`;
|
|
266
|
+
|
|
267
|
+
await writeFile(join(profileDir, CONFIG.files.profile), profileContent);
|
|
268
|
+
|
|
269
|
+
// ── Write anti-patterns.md (moderate defaults) ──────────────────
|
|
270
|
+
const antiContent = `# Anti-Patterns to Avoid
|
|
271
|
+
|
|
272
|
+
## Code Style
|
|
273
|
+
- Don't add comments for obvious code
|
|
274
|
+
- Don't add type annotations that can be inferred
|
|
275
|
+
- Don't create abstractions for one-time use
|
|
276
|
+
|
|
277
|
+
## Architecture
|
|
278
|
+
- Don't over-engineer solutions
|
|
279
|
+
- Don't add features that weren't requested
|
|
280
|
+
- Don't create unnecessary indirection
|
|
281
|
+
- Don't add "future-proofing" complexity
|
|
282
|
+
|
|
283
|
+
## Communication
|
|
284
|
+
- Don't explain obvious things
|
|
285
|
+
- Don't repeat back what was just said
|
|
286
|
+
- Don't pad responses with unnecessary context
|
|
287
|
+
`;
|
|
288
|
+
|
|
289
|
+
await writeFile(join(profileDir, CONFIG.files.antiPatterns), antiContent);
|
|
290
|
+
}
|
package/src/tui/App.tsx
CHANGED
|
@@ -16,7 +16,6 @@ import { ProfileSwitcher } from "./components/ProfileSwitcher.tsx";
|
|
|
16
16
|
import { FullScreen, useTerminalSize } from "./components/FullScreen.tsx";
|
|
17
17
|
import { existsSync, readdirSync } from "fs";
|
|
18
18
|
import { readFile } from "fs/promises";
|
|
19
|
-
import { spawn } from "child_process";
|
|
20
19
|
import { CONFIG, getActiveProfile, estimateTokens, formatTokens } from "../core/config.ts";
|
|
21
20
|
import { switchProfile } from "../core/profiles.ts";
|
|
22
21
|
import { generatePlugin } from "../core/generator.ts";
|
|
@@ -151,16 +150,6 @@ export function App() {
|
|
|
151
150
|
setModal("none");
|
|
152
151
|
}
|
|
153
152
|
|
|
154
|
-
function handleSetup() {
|
|
155
|
-
isExitingRef.current = true;
|
|
156
|
-
exit();
|
|
157
|
-
setTimeout(() => {
|
|
158
|
-
spawn("think", ["setup"], {
|
|
159
|
-
stdio: "inherit",
|
|
160
|
-
});
|
|
161
|
-
}, 100);
|
|
162
|
-
}
|
|
163
|
-
|
|
164
153
|
// Don't render while exiting
|
|
165
154
|
if (isExitingRef.current) {
|
|
166
155
|
return null;
|
|
@@ -224,7 +213,6 @@ export function App() {
|
|
|
224
213
|
<ProfileSwitcher
|
|
225
214
|
onClose={() => setModal("none")}
|
|
226
215
|
onSwitch={handleProfileSwitch}
|
|
227
|
-
onSetup={handleSetup}
|
|
228
216
|
/>
|
|
229
217
|
</Box>
|
|
230
218
|
</FullScreen>
|
|
@@ -3,22 +3,34 @@ import { Box, Text, useInput } from "ink";
|
|
|
3
3
|
import TextInput from "ink-text-input";
|
|
4
4
|
import type { ProfileInfo } from "../../core/profiles.ts";
|
|
5
5
|
import { listProfiles, createProfile, deleteProfile } from "../../core/profiles.ts";
|
|
6
|
+
import { profilePath } from "../../core/config.ts";
|
|
7
|
+
import { roleDescriptions, generateProfileFiles } from "../../core/profile-generator.ts";
|
|
6
8
|
|
|
7
9
|
interface ProfileSwitcherProps {
|
|
8
10
|
onClose: () => void;
|
|
9
11
|
onSwitch: (name: string) => void;
|
|
10
|
-
onSetup?: () => void;
|
|
11
12
|
}
|
|
12
13
|
|
|
13
|
-
type Mode = "list" | "create" | "confirmCopy" | "confirmDelete";
|
|
14
|
+
type Mode = "list" | "create" | "confirmCopy" | "confirmDelete" | "selectRole";
|
|
14
15
|
|
|
15
|
-
|
|
16
|
+
const roles = [
|
|
17
|
+
{ value: "senior-dev", label: "Senior Developer", hint: "experienced, autonomous" },
|
|
18
|
+
{ value: "mid-dev", label: "Mid-level Developer", hint: "some guidance helpful" },
|
|
19
|
+
{ value: "junior-dev", label: "Junior Developer", hint: "more explanation needed" },
|
|
20
|
+
{ value: "founder", label: "Founder / Tech Lead", hint: "shipping matters" },
|
|
21
|
+
{ value: "student", label: "Student", hint: "learning fundamentals" },
|
|
22
|
+
{ value: "hobbyist", label: "Hobbyist", hint: "exploring for fun" },
|
|
23
|
+
];
|
|
24
|
+
|
|
25
|
+
export function ProfileSwitcher({ onClose, onSwitch }: ProfileSwitcherProps) {
|
|
16
26
|
const [profiles, setProfiles] = useState<ProfileInfo[]>([]);
|
|
17
27
|
const [selected, setSelected] = useState(0);
|
|
18
28
|
const [loading, setLoading] = useState(true);
|
|
19
29
|
const [mode, setMode] = useState<Mode>("list");
|
|
20
30
|
const [newName, setNewName] = useState("");
|
|
21
31
|
const [error, setError] = useState<string | null>(null);
|
|
32
|
+
const [roleIndex, setRoleIndex] = useState(0);
|
|
33
|
+
const [generating, setGenerating] = useState(false);
|
|
22
34
|
|
|
23
35
|
function loadProfiles() {
|
|
24
36
|
const loaded = listProfiles();
|
|
@@ -47,8 +59,11 @@ export function ProfileSwitcher({ onClose, onSwitch, onSetup }: ProfileSwitcherP
|
|
|
47
59
|
try {
|
|
48
60
|
createProfile(name, copyFrom);
|
|
49
61
|
|
|
50
|
-
if (!copyFrom
|
|
51
|
-
|
|
62
|
+
if (!copyFrom) {
|
|
63
|
+
// No source to copy from — go to role selection
|
|
64
|
+
setMode("selectRole");
|
|
65
|
+
setRoleIndex(0);
|
|
66
|
+
setError(null);
|
|
52
67
|
return;
|
|
53
68
|
}
|
|
54
69
|
|
|
@@ -62,6 +77,25 @@ export function ProfileSwitcher({ onClose, onSwitch, onSetup }: ProfileSwitcherP
|
|
|
62
77
|
}
|
|
63
78
|
}
|
|
64
79
|
|
|
80
|
+
async function handleRoleSelect() {
|
|
81
|
+
const name = newName.trim();
|
|
82
|
+
const role = roles[roleIndex]!;
|
|
83
|
+
setGenerating(true);
|
|
84
|
+
try {
|
|
85
|
+
const dir = profilePath(name);
|
|
86
|
+
await generateProfileFiles(dir, { role: role.value });
|
|
87
|
+
setNewName("");
|
|
88
|
+
setMode("list");
|
|
89
|
+
setError(null);
|
|
90
|
+
setGenerating(false);
|
|
91
|
+
loadProfiles();
|
|
92
|
+
onSwitch(name);
|
|
93
|
+
} catch {
|
|
94
|
+
setError("Failed to generate profile");
|
|
95
|
+
setGenerating(false);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
65
99
|
function handleDelete() {
|
|
66
100
|
const profile = profiles[selected];
|
|
67
101
|
if (!profile) return;
|
|
@@ -111,6 +145,26 @@ export function ProfileSwitcher({ onClose, onSwitch, onSetup }: ProfileSwitcherP
|
|
|
111
145
|
return;
|
|
112
146
|
}
|
|
113
147
|
|
|
148
|
+
// Select role mode
|
|
149
|
+
if (mode === "selectRole") {
|
|
150
|
+
if (generating) return;
|
|
151
|
+
if (key.escape) {
|
|
152
|
+
setMode("list");
|
|
153
|
+
setNewName("");
|
|
154
|
+
setError(null);
|
|
155
|
+
}
|
|
156
|
+
if (key.upArrow || input === "k") {
|
|
157
|
+
setRoleIndex((i) => (i - 1 + roles.length) % roles.length);
|
|
158
|
+
}
|
|
159
|
+
if (key.downArrow || input === "j") {
|
|
160
|
+
setRoleIndex((i) => (i + 1) % roles.length);
|
|
161
|
+
}
|
|
162
|
+
if (key.return) {
|
|
163
|
+
handleRoleSelect();
|
|
164
|
+
}
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
|
|
114
168
|
// Confirm delete mode
|
|
115
169
|
if (mode === "confirmDelete") {
|
|
116
170
|
if (input === "y" || input === "Y") {
|
|
@@ -217,6 +271,43 @@ export function ProfileSwitcher({ onClose, onSwitch, onSetup }: ProfileSwitcherP
|
|
|
217
271
|
);
|
|
218
272
|
}
|
|
219
273
|
|
|
274
|
+
// Select role mode
|
|
275
|
+
if (mode === "selectRole") {
|
|
276
|
+
return (
|
|
277
|
+
<Box flexDirection="column" padding={1}>
|
|
278
|
+
<Text bold color="cyan">Select Role for "{newName}"</Text>
|
|
279
|
+
|
|
280
|
+
<Box flexDirection="column" marginTop={1}>
|
|
281
|
+
{roles.map((role, i) => (
|
|
282
|
+
<Box key={role.value}>
|
|
283
|
+
<Text color={i === roleIndex ? "cyan" : undefined} dimColor={i !== roleIndex}>
|
|
284
|
+
{i === roleIndex ? " \u25b8 " : " "}
|
|
285
|
+
</Text>
|
|
286
|
+
<Text bold={i === roleIndex} color={i === roleIndex ? "white" : undefined} dimColor={i !== roleIndex}>
|
|
287
|
+
{role.label}
|
|
288
|
+
</Text>
|
|
289
|
+
<Text dimColor> {role.hint}</Text>
|
|
290
|
+
</Box>
|
|
291
|
+
))}
|
|
292
|
+
</Box>
|
|
293
|
+
|
|
294
|
+
{generating && (
|
|
295
|
+
<Box marginTop={1}>
|
|
296
|
+
<Text color="yellow"> Generating profile...</Text>
|
|
297
|
+
</Box>
|
|
298
|
+
)}
|
|
299
|
+
{error && (
|
|
300
|
+
<Box marginTop={1}>
|
|
301
|
+
<Text color="red"> {error}</Text>
|
|
302
|
+
</Box>
|
|
303
|
+
)}
|
|
304
|
+
<Box marginTop={1}>
|
|
305
|
+
<Text dimColor> {"\u2191\u2193"}: select | Enter: create | Esc: cancel</Text>
|
|
306
|
+
</Box>
|
|
307
|
+
</Box>
|
|
308
|
+
);
|
|
309
|
+
}
|
|
310
|
+
|
|
220
311
|
// Confirm delete mode
|
|
221
312
|
if (mode === "confirmDelete") {
|
|
222
313
|
const profile = profiles[selected];
|
|
@@ -49,7 +49,7 @@ export function StatusBar({ message, section }: StatusBarProps) {
|
|
|
49
49
|
return (
|
|
50
50
|
<Box>
|
|
51
51
|
<Text dimColor>
|
|
52
|
-
{"↑↓ nav · "}{sectionHints}{" · / search · ? help · q quit"}
|
|
52
|
+
{"↑↓ nav · "}{sectionHints}{" · P profiles · / search · ? help · q quit"}
|
|
53
53
|
</Text>
|
|
54
54
|
</Box>
|
|
55
55
|
);
|
|
@@ -58,7 +58,7 @@ export function StatusBar({ message, section }: StatusBarProps) {
|
|
|
58
58
|
return (
|
|
59
59
|
<Box>
|
|
60
60
|
<Text dimColor>
|
|
61
|
-
{"↑↓ navigate · "}{sectionHints}{" · s sync · p preview · / search · ? help · q quit"}
|
|
61
|
+
{"↑↓ navigate · "}{sectionHints}{" · s sync · p preview · P profiles · / search · ? help · q quit"}
|
|
62
62
|
</Text>
|
|
63
63
|
</Box>
|
|
64
64
|
);
|