cursor-kit-cli 1.2.0-beta → 1.2.0-beta.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/bin/cursor-reinstall-instance.sh +102 -0
- package/dist/cli.cjs +366 -69
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +367 -70
- package/dist/cli.js.map +1 -1
- package/dist/index.cjs +39 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +9 -1
- package/dist/index.d.ts +9 -1
- package/dist/index.js +33 -2
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/templates/commands/docs.md +5 -3
- package/templates/commands/explain.md +5 -3
- package/templates/commands/fix.md +5 -3
- package/templates/commands/implement.md +5 -3
- package/templates/commands/refactor.md +5 -3
- package/templates/commands/review.md +5 -3
- package/templates/commands/test.md +5 -3
- package/templates/manifest.json +11 -8
- package/templates/rules/git.mdc +0 -2
- package/templates/rules/toc.mdc +17 -9
- package/templates/skills/aesthetic/SKILL.md +121 -0
- package/templates/skills/aesthetic/assets/design-guideline-template.md +163 -0
- package/templates/skills/aesthetic/assets/design-story-template.md +135 -0
- package/templates/skills/aesthetic/references/design-principles.md +62 -0
- package/templates/skills/aesthetic/references/design-resources.md +75 -0
- package/templates/skills/aesthetic/references/micro-interactions.md +53 -0
- package/templates/skills/aesthetic/references/storytelling-design.md +50 -0
- package/templates/skills/backend-development/SKILL.mdc +95 -0
- package/templates/skills/backend-development/references/backend-api-design.md +495 -0
- package/templates/skills/backend-development/references/backend-architecture.md +454 -0
- package/templates/skills/backend-development/references/backend-authentication.md +338 -0
- package/templates/skills/backend-development/references/backend-code-quality.md +659 -0
- package/templates/skills/backend-development/references/backend-debugging.md +904 -0
- package/templates/skills/backend-development/references/backend-devops.md +494 -0
- package/templates/skills/backend-development/references/backend-mindset.md +387 -0
- package/templates/skills/backend-development/references/backend-performance.md +397 -0
- package/templates/skills/backend-development/references/backend-security.md +290 -0
- package/templates/skills/backend-development/references/backend-technologies.md +256 -0
- package/templates/skills/backend-development/references/backend-testing.md +429 -0
- package/templates/skills/frontend-design/SKILL.mdc +41 -0
- package/templates/skills/frontend-design/references/animejs.md +396 -0
- package/templates/skills/frontend-development/SKILL.mdc +399 -0
- package/templates/skills/frontend-development/resources/common-patterns.md +331 -0
- package/templates/skills/frontend-development/resources/complete-examples.md +872 -0
- package/templates/skills/frontend-development/resources/component-patterns.md +502 -0
- package/templates/skills/frontend-development/resources/data-fetching.md +767 -0
- package/templates/skills/frontend-development/resources/file-organization.md +502 -0
- package/templates/skills/frontend-development/resources/loading-and-error-states.md +501 -0
- package/templates/skills/frontend-development/resources/performance.md +406 -0
- package/templates/skills/frontend-development/resources/routing-guide.md +364 -0
- package/templates/skills/frontend-development/resources/styling-guide.md +428 -0
- package/templates/skills/frontend-development/resources/typescript-standards.md +418 -0
- package/templates/skills/problem-solving/SKILL.mdc +96 -0
- package/templates/skills/problem-solving/references/attribution.md +69 -0
- package/templates/skills/problem-solving/references/collision-zone-thinking.md +79 -0
- package/templates/skills/problem-solving/references/inversion-exercise.md +91 -0
- package/templates/skills/problem-solving/references/meta-pattern-recognition.md +87 -0
- package/templates/skills/problem-solving/references/scale-game.md +95 -0
- package/templates/skills/problem-solving/references/simplification-cascades.md +80 -0
- package/templates/skills/problem-solving/references/when-stuck.md +72 -0
- package/templates/skills/research/SKILL.mdc +168 -0
- package/templates/skills/sequential-thinking/.env.example +8 -0
- package/templates/skills/sequential-thinking/README.md +183 -0
- package/templates/skills/sequential-thinking/SKILL.mdc +94 -0
- package/templates/skills/sequential-thinking/package.json +31 -0
- package/templates/skills/sequential-thinking/references/advanced-strategies.md +79 -0
- package/templates/skills/sequential-thinking/references/advanced-techniques.md +76 -0
- package/templates/skills/sequential-thinking/references/core-patterns.md +95 -0
- package/templates/skills/sequential-thinking/references/examples-api.md +88 -0
- package/templates/skills/sequential-thinking/references/examples-architecture.md +94 -0
- package/templates/skills/sequential-thinking/references/examples-debug.md +90 -0
- package/templates/skills/sequential-thinking/scripts/format-thought.js +159 -0
- package/templates/skills/sequential-thinking/scripts/process-thought.js +236 -0
- package/templates/skills/sequential-thinking/tests/format-thought.test.js +133 -0
- package/templates/skills/sequential-thinking/tests/process-thought.test.js +215 -0
- package/templates/skills/ui-styling/LICENSE.txt +202 -0
- package/templates/skills/ui-styling/SKILL.mdc +321 -0
- package/templates/skills/ui-styling/references/canvas-design-system.md +320 -0
- package/templates/skills/ui-styling/references/shadcn-accessibility.md +471 -0
- package/templates/skills/ui-styling/references/shadcn-components.md +424 -0
- package/templates/skills/ui-styling/references/shadcn-theming.md +373 -0
- package/templates/skills/ui-styling/references/tailwind-customization.md +483 -0
- package/templates/skills/ui-styling/references/tailwind-responsive.md +382 -0
- package/templates/skills/ui-styling/references/tailwind-utilities.md +455 -0
- package/templates/rules/frontend-design.mdc +0 -48
- package/templates/rules/performance.mdc +0 -54
- package/templates/rules/react.mdc +0 -58
- package/templates/rules/security.mdc +0 -50
- package/templates/rules/testing.mdc +0 -54
- package/templates/rules/typescript.mdc +0 -36
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
# Example: Architecture Decision with Sequential Thinking
|
|
2
|
+
|
|
3
|
+
**Problem**: Choose state management for growing React app.
|
|
4
|
+
|
|
5
|
+
## Sequential Thinking Approach
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
Thought 1/4: Initial assessment
|
|
9
|
+
|
|
10
|
+
React app growing complex. useState scattered across components.
|
|
11
|
+
Need centralized state management.
|
|
12
|
+
Options: Redux, MobX, Zustand, Context API, Jotai.
|
|
13
|
+
|
|
14
|
+
Next: Define requirements
|
|
15
|
+
|
|
16
|
+
Thought 2/5: Requirements (adjusted up)
|
|
17
|
+
|
|
18
|
+
App needs:
|
|
19
|
+
- Real-time updates (WebSocket)
|
|
20
|
+
- Offline support
|
|
21
|
+
- Complex nested state
|
|
22
|
+
- Multiple devs (maintainability)
|
|
23
|
+
- TypeScript (type safety)
|
|
24
|
+
|
|
25
|
+
These eliminate simpler solutions.
|
|
26
|
+
Next: Evaluate remaining options
|
|
27
|
+
|
|
28
|
+
Thought 3/5 [REVISION of Thought 1]: Scope refinement
|
|
29
|
+
|
|
30
|
+
Original assumption: Need global state management.
|
|
31
|
+
Realization: Not all state needs centralization.
|
|
32
|
+
|
|
33
|
+
Better breakdown:
|
|
34
|
+
- Server state (API data): React Query
|
|
35
|
+
- UI state (modals, forms): Local useState
|
|
36
|
+
- Auth state: Context API
|
|
37
|
+
- App-wide settings: Simple global store
|
|
38
|
+
|
|
39
|
+
This reduces problem scope significantly.
|
|
40
|
+
Changes evaluation criteria.
|
|
41
|
+
Next: Re-evaluate with refined scope
|
|
42
|
+
|
|
43
|
+
Thought 4/6: Re-evaluation (adjusted)
|
|
44
|
+
|
|
45
|
+
Only need lightweight store for app-wide settings.
|
|
46
|
+
Zustand fits:
|
|
47
|
+
- Minimal boilerplate
|
|
48
|
+
- Excellent TypeScript support
|
|
49
|
+
- No provider wrapper
|
|
50
|
+
- ~1KB size
|
|
51
|
+
|
|
52
|
+
React Query handles server state (caching, refetch, offline).
|
|
53
|
+
Most state stays local.
|
|
54
|
+
|
|
55
|
+
Next: Verify this handles all requirements
|
|
56
|
+
|
|
57
|
+
Thought 5/6 [HYPOTHESIS]: Hybrid approach
|
|
58
|
+
|
|
59
|
+
Hypothesis: Zustand + React Query + local state solves needs.
|
|
60
|
+
|
|
61
|
+
- Zustand: Theme, user prefs, global UI flags
|
|
62
|
+
- React Query: All server data, caching, sync
|
|
63
|
+
- useState: Component-local UI
|
|
64
|
+
|
|
65
|
+
Benefits: Simple, performant, maintainable.
|
|
66
|
+
Uncertainty: Real-time updates?
|
|
67
|
+
|
|
68
|
+
Thought 6/6 [FINAL]: Verified solution
|
|
69
|
+
|
|
70
|
+
React Query supports WebSocket via custom hooks.
|
|
71
|
+
Zustand handles global UI simply.
|
|
72
|
+
Local state for component-specific needs.
|
|
73
|
+
|
|
74
|
+
Architecture decision:
|
|
75
|
+
- Zustand for global UI state
|
|
76
|
+
- React Query for all server interactions
|
|
77
|
+
- Local useState for component state
|
|
78
|
+
|
|
79
|
+
Confidence: High
|
|
80
|
+
Assumptions: Team comfortable with React Query patterns
|
|
81
|
+
Benefits: Simpler than Redux, more powerful than Context
|
|
82
|
+
Trade-offs: Learning curve for React Query (but worthwhile)
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
## Key Insights
|
|
86
|
+
|
|
87
|
+
1. **Scope revision crucial**: Original "need global state" reframed to specific state categories
|
|
88
|
+
2. **Separation of concerns**: Different state types need different solutions
|
|
89
|
+
3. **Hypothesis verification**: Confirmed WebSocket support before finalizing
|
|
90
|
+
4. **Simpler is better**: Avoided over-engineering with heavy Redux solution
|
|
91
|
+
|
|
92
|
+
## Impact of Revision
|
|
93
|
+
|
|
94
|
+
Without Thought 3 revision, might have chosen Redux for all state—significant over-engineering. Revision led to more appropriate, simpler solution.
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
# Example: Performance Debugging with Sequential Thinking
|
|
2
|
+
|
|
3
|
+
**Problem**: API endpoint slow (2-3s instead of <200ms).
|
|
4
|
+
|
|
5
|
+
## Sequential Thinking Approach
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
Thought 1/5: Initial investigation
|
|
9
|
+
|
|
10
|
+
Endpoint: GET /api/users/{id}/dashboard
|
|
11
|
+
Expected: <200ms
|
|
12
|
+
Actual: 2-3s
|
|
13
|
+
|
|
14
|
+
Need to identify bottleneck.
|
|
15
|
+
Next: Analyze endpoint logic
|
|
16
|
+
|
|
17
|
+
Thought 2/5: Endpoint analysis
|
|
18
|
+
|
|
19
|
+
Dashboard fetches:
|
|
20
|
+
- User profile
|
|
21
|
+
- Recent activities (last 50)
|
|
22
|
+
- Notifications (unread)
|
|
23
|
+
- Analytics summary
|
|
24
|
+
|
|
25
|
+
Each is separate DB query. Could be N+1 problem.
|
|
26
|
+
Next: Profile actual execution
|
|
27
|
+
|
|
28
|
+
Thought 3/6: Profiling results (adjusted up—more complex)
|
|
29
|
+
|
|
30
|
+
Profiling:
|
|
31
|
+
- User profile: 20ms
|
|
32
|
+
- Activities: 1800ms (!!)
|
|
33
|
+
- Notifications: 100ms
|
|
34
|
+
- Analytics: 80ms
|
|
35
|
+
|
|
36
|
+
Activities query is bottleneck (90% of time).
|
|
37
|
+
Need to examine that query.
|
|
38
|
+
Next: Investigate activities query
|
|
39
|
+
|
|
40
|
+
Thought 4/6 [BRANCH A]: Hypothesis - N+1 query
|
|
41
|
+
|
|
42
|
+
Activities table has user_id FK to users.
|
|
43
|
+
Query might fetch activities, then user for each (N+1).
|
|
44
|
+
Verification: Check if uses joins or loops.
|
|
45
|
+
|
|
46
|
+
Thought 4/6 [BRANCH B]: Hypothesis - Missing index
|
|
47
|
+
|
|
48
|
+
Activities table might lack index on user_id + created_at.
|
|
49
|
+
Without index, full table scan for user's activities.
|
|
50
|
+
Verification: Check table indexes.
|
|
51
|
+
|
|
52
|
+
Thought 5/6 [VERIFICATION]: Testing hypotheses
|
|
53
|
+
|
|
54
|
+
Query examination: Uses proper joins (not N+1).
|
|
55
|
+
Index check: user_id indexed, NOT created_at.
|
|
56
|
+
Query filters by user_id AND sorts by created_at.
|
|
57
|
+
|
|
58
|
+
Branch B confirmed: Missing composite index causes slow sort.
|
|
59
|
+
Branch A eliminated: No N+1 issue.
|
|
60
|
+
|
|
61
|
+
Root cause identified.
|
|
62
|
+
Next: Implement solution
|
|
63
|
+
|
|
64
|
+
Thought 6/6 [FINAL]: Solution and verification
|
|
65
|
+
|
|
66
|
+
Create composite index:
|
|
67
|
+
```sql
|
|
68
|
+
CREATE INDEX idx_activities_user_created
|
|
69
|
+
ON activities(user_id, created_at DESC);
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Tested: Response time now 120ms (target met).
|
|
73
|
+
|
|
74
|
+
Confidence: High (verified with profiling)
|
|
75
|
+
Result: 95% performance improvement
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
## Key Techniques Demonstrated
|
|
79
|
+
|
|
80
|
+
1. **Branching for hypothesis testing**: Explored N+1 vs index hypotheses in parallel
|
|
81
|
+
2. **Verification before solution**: Tested both hypotheses systematically
|
|
82
|
+
3. **Data-driven decisions**: Used profiling data to guide investigation
|
|
83
|
+
4. **Dynamic adjustment**: Expanded thought count when complexity emerged
|
|
84
|
+
5. **Elimination method**: Ruled out N+1, confirmed index issue
|
|
85
|
+
|
|
86
|
+
## Comparison
|
|
87
|
+
|
|
88
|
+
**Without sequential thinking**: Might jump to N+1 conclusion (common issue), waste time optimizing wrong thing.
|
|
89
|
+
|
|
90
|
+
**With sequential thinking**: Systematically tested hypotheses, identified actual root cause, implemented correct fix.
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Sequential Thinking Thought Formatter
|
|
5
|
+
*
|
|
6
|
+
* Formats thoughts for display with visual indicators for type (regular/revision/branch).
|
|
7
|
+
* Provides consistent, readable output for thought sequences.
|
|
8
|
+
*
|
|
9
|
+
* Usage:
|
|
10
|
+
* node format-thought.js --thought "Analysis" --number 1 --total 5
|
|
11
|
+
* node format-thought.js --thought "Revision" --number 2 --total 5 --revision 1
|
|
12
|
+
* node format-thought.js --thought "Branch A" --number 3 --total 5 --branch 2 --branchId "a"
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
class ThoughtFormatter {
|
|
16
|
+
static format(thoughtData) {
|
|
17
|
+
const { thoughtNumber, totalThoughts, thought, isRevision, revisesThought, branchFromThought, branchId } = thoughtData;
|
|
18
|
+
|
|
19
|
+
let prefix = '';
|
|
20
|
+
let context = '';
|
|
21
|
+
let emoji = '';
|
|
22
|
+
|
|
23
|
+
if (isRevision && revisesThought) {
|
|
24
|
+
emoji = '🔄';
|
|
25
|
+
prefix = 'REVISION';
|
|
26
|
+
context = ` (revising thought ${revisesThought})`;
|
|
27
|
+
} else if (branchFromThought) {
|
|
28
|
+
emoji = '🌿';
|
|
29
|
+
prefix = 'BRANCH';
|
|
30
|
+
context = branchId ? ` (from thought ${branchFromThought}, ID: ${branchId})` : ` (from thought ${branchFromThought})`;
|
|
31
|
+
} else {
|
|
32
|
+
emoji = '💭';
|
|
33
|
+
prefix = 'Thought';
|
|
34
|
+
context = '';
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const header = `${emoji} ${prefix} ${thoughtNumber}/${totalThoughts}${context}`;
|
|
38
|
+
const maxLength = Math.max(header.length, thought.length);
|
|
39
|
+
const border = '─'.repeat(maxLength + 4);
|
|
40
|
+
|
|
41
|
+
// Wrap long thoughts
|
|
42
|
+
const wrappedThought = this.wrapText(thought, maxLength);
|
|
43
|
+
const thoughtLines = wrappedThought.map(line => `│ ${line.padEnd(maxLength + 2)} │`).join('\n');
|
|
44
|
+
|
|
45
|
+
return `
|
|
46
|
+
┌${border}┐
|
|
47
|
+
│ ${header.padEnd(maxLength + 2)} │
|
|
48
|
+
├${border}┤
|
|
49
|
+
${thoughtLines}
|
|
50
|
+
└${border}┘`;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
static wrapText(text, maxWidth) {
|
|
54
|
+
if (text.length <= maxWidth) {
|
|
55
|
+
return [text];
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const words = text.split(' ');
|
|
59
|
+
const lines = [];
|
|
60
|
+
let currentLine = '';
|
|
61
|
+
|
|
62
|
+
for (const word of words) {
|
|
63
|
+
if ((currentLine + ' ' + word).trim().length <= maxWidth) {
|
|
64
|
+
currentLine = currentLine ? currentLine + ' ' + word : word;
|
|
65
|
+
} else {
|
|
66
|
+
if (currentLine) lines.push(currentLine);
|
|
67
|
+
currentLine = word;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
if (currentLine) lines.push(currentLine);
|
|
72
|
+
return lines;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
static formatSimple(thoughtData) {
|
|
76
|
+
const { thoughtNumber, totalThoughts, thought, isRevision, revisesThought, branchFromThought, branchId } = thoughtData;
|
|
77
|
+
|
|
78
|
+
let marker = '';
|
|
79
|
+
if (isRevision && revisesThought) {
|
|
80
|
+
marker = ` [REVISION of Thought ${revisesThought}]`;
|
|
81
|
+
} else if (branchFromThought) {
|
|
82
|
+
marker = branchId ? ` [BRANCH ${branchId.toUpperCase()} from Thought ${branchFromThought}]` : ` [BRANCH from Thought ${branchFromThought}]`;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
return `Thought ${thoughtNumber}/${totalThoughts}${marker}: ${thought}`;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
static formatMarkdown(thoughtData) {
|
|
89
|
+
const { thoughtNumber, totalThoughts, thought, isRevision, revisesThought, branchFromThought, branchId } = thoughtData;
|
|
90
|
+
|
|
91
|
+
let marker = '';
|
|
92
|
+
if (isRevision && revisesThought) {
|
|
93
|
+
marker = ` **[REVISION of Thought ${revisesThought}]**`;
|
|
94
|
+
} else if (branchFromThought) {
|
|
95
|
+
marker = branchId ? ` **[BRANCH ${branchId.toUpperCase()} from Thought ${branchFromThought}]**` : ` **[BRANCH from Thought ${branchFromThought}]**`;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
return `**Thought ${thoughtNumber}/${totalThoughts}**${marker}\n\n${thought}\n`;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// CLI Interface
|
|
103
|
+
if (require.main === module) {
|
|
104
|
+
const args = process.argv.slice(2);
|
|
105
|
+
|
|
106
|
+
const parseArgs = (args) => {
|
|
107
|
+
const parsed = {};
|
|
108
|
+
for (let i = 0; i < args.length; i++) {
|
|
109
|
+
const arg = args[i];
|
|
110
|
+
if (arg.startsWith('--')) {
|
|
111
|
+
const key = arg.slice(2);
|
|
112
|
+
const value = args[i + 1];
|
|
113
|
+
|
|
114
|
+
if (value && !value.startsWith('--')) {
|
|
115
|
+
// Parse boolean
|
|
116
|
+
if (value === 'true') parsed[key] = true;
|
|
117
|
+
else if (value === 'false') parsed[key] = false;
|
|
118
|
+
// Parse number
|
|
119
|
+
else if (!isNaN(value)) parsed[key] = parseFloat(value);
|
|
120
|
+
// String
|
|
121
|
+
else parsed[key] = value;
|
|
122
|
+
i++;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
return parsed;
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
const input = parseArgs(args);
|
|
130
|
+
|
|
131
|
+
const thoughtData = {
|
|
132
|
+
thought: input.thought || 'No thought provided',
|
|
133
|
+
thoughtNumber: input.number || 1,
|
|
134
|
+
totalThoughts: input.total || 1,
|
|
135
|
+
isRevision: input.revision !== undefined,
|
|
136
|
+
revisesThought: input.revision,
|
|
137
|
+
branchFromThought: input.branch,
|
|
138
|
+
branchId: input.branchId
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
const format = input.format || 'box';
|
|
142
|
+
|
|
143
|
+
let output;
|
|
144
|
+
switch (format) {
|
|
145
|
+
case 'simple':
|
|
146
|
+
output = ThoughtFormatter.formatSimple(thoughtData);
|
|
147
|
+
break;
|
|
148
|
+
case 'markdown':
|
|
149
|
+
output = ThoughtFormatter.formatMarkdown(thoughtData);
|
|
150
|
+
break;
|
|
151
|
+
case 'box':
|
|
152
|
+
default:
|
|
153
|
+
output = ThoughtFormatter.format(thoughtData);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
console.log(output);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
module.exports = { ThoughtFormatter };
|
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Sequential Thinking Thought Processor
|
|
5
|
+
*
|
|
6
|
+
* Validates and tracks sequential thoughts with revision and branching support.
|
|
7
|
+
* Provides deterministic validation and context management.
|
|
8
|
+
*
|
|
9
|
+
* Usage:
|
|
10
|
+
* node process-thought.js --thought "Analysis text" --number 1 --total 5 --next true
|
|
11
|
+
* node process-thought.js --thought "Revision" --number 2 --total 5 --next true --revision 1
|
|
12
|
+
* node process-thought.js --reset # Reset thought history
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
const fs = require('fs');
|
|
16
|
+
const path = require('path');
|
|
17
|
+
|
|
18
|
+
// Configuration
|
|
19
|
+
const HISTORY_FILE = path.join(__dirname, '.thought-history.json');
|
|
20
|
+
const DISABLE_LOGGING = process.env.DISABLE_THOUGHT_LOGGING?.toLowerCase() === 'true';
|
|
21
|
+
|
|
22
|
+
class ThoughtProcessor {
|
|
23
|
+
constructor() {
|
|
24
|
+
this.loadHistory();
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
loadHistory() {
|
|
28
|
+
try {
|
|
29
|
+
if (fs.existsSync(HISTORY_FILE)) {
|
|
30
|
+
const data = JSON.parse(fs.readFileSync(HISTORY_FILE, 'utf8'));
|
|
31
|
+
this.thoughtHistory = data.thoughtHistory || [];
|
|
32
|
+
this.branches = data.branches || {};
|
|
33
|
+
} else {
|
|
34
|
+
this.thoughtHistory = [];
|
|
35
|
+
this.branches = {};
|
|
36
|
+
}
|
|
37
|
+
} catch (error) {
|
|
38
|
+
this.thoughtHistory = [];
|
|
39
|
+
this.branches = {};
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
saveHistory() {
|
|
44
|
+
fs.writeFileSync(
|
|
45
|
+
HISTORY_FILE,
|
|
46
|
+
JSON.stringify({
|
|
47
|
+
thoughtHistory: this.thoughtHistory,
|
|
48
|
+
branches: this.branches
|
|
49
|
+
}, null, 2)
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
resetHistory() {
|
|
54
|
+
this.thoughtHistory = [];
|
|
55
|
+
this.branches = {};
|
|
56
|
+
if (fs.existsSync(HISTORY_FILE)) {
|
|
57
|
+
fs.unlinkSync(HISTORY_FILE);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
validateThought(input) {
|
|
62
|
+
const errors = [];
|
|
63
|
+
|
|
64
|
+
if (!input.thought || typeof input.thought !== 'string' || input.thought.trim() === '') {
|
|
65
|
+
errors.push('Invalid thought: must be a non-empty string');
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
if (!input.thoughtNumber || typeof input.thoughtNumber !== 'number' || input.thoughtNumber < 1) {
|
|
69
|
+
errors.push('Invalid thoughtNumber: must be a positive number');
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
if (!input.totalThoughts || typeof input.totalThoughts !== 'number' || input.totalThoughts < 1) {
|
|
73
|
+
errors.push('Invalid totalThoughts: must be a positive number');
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
if (typeof input.nextThoughtNeeded !== 'boolean') {
|
|
77
|
+
errors.push('Invalid nextThoughtNeeded: must be a boolean');
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Optional field validations
|
|
81
|
+
if (input.isRevision !== undefined && typeof input.isRevision !== 'boolean') {
|
|
82
|
+
errors.push('Invalid isRevision: must be a boolean');
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
if (input.revisesThought !== undefined && (typeof input.revisesThought !== 'number' || input.revisesThought < 1)) {
|
|
86
|
+
errors.push('Invalid revisesThought: must be a positive number');
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
if (input.branchFromThought !== undefined && (typeof input.branchFromThought !== 'number' || input.branchFromThought < 1)) {
|
|
90
|
+
errors.push('Invalid branchFromThought: must be a positive number');
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
if (input.branchId !== undefined && typeof input.branchId !== 'string') {
|
|
94
|
+
errors.push('Invalid branchId: must be a string');
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
if (input.needsMoreThoughts !== undefined && typeof input.needsMoreThoughts !== 'boolean') {
|
|
98
|
+
errors.push('Invalid needsMoreThoughts: must be a boolean');
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
return errors;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
processThought(input) {
|
|
105
|
+
const errors = this.validateThought(input);
|
|
106
|
+
|
|
107
|
+
if (errors.length > 0) {
|
|
108
|
+
return {
|
|
109
|
+
success: false,
|
|
110
|
+
errors,
|
|
111
|
+
status: 'failed'
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// Auto-adjust totalThoughts if thoughtNumber exceeds it
|
|
116
|
+
if (input.thoughtNumber > input.totalThoughts) {
|
|
117
|
+
input.totalThoughts = input.thoughtNumber;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// Create thought data
|
|
121
|
+
const thoughtData = {
|
|
122
|
+
thought: input.thought,
|
|
123
|
+
thoughtNumber: input.thoughtNumber,
|
|
124
|
+
totalThoughts: input.totalThoughts,
|
|
125
|
+
nextThoughtNeeded: input.nextThoughtNeeded,
|
|
126
|
+
isRevision: input.isRevision,
|
|
127
|
+
revisesThought: input.revisesThought,
|
|
128
|
+
branchFromThought: input.branchFromThought,
|
|
129
|
+
branchId: input.branchId,
|
|
130
|
+
needsMoreThoughts: input.needsMoreThoughts,
|
|
131
|
+
timestamp: new Date().toISOString()
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
// Add to history
|
|
135
|
+
this.thoughtHistory.push(thoughtData);
|
|
136
|
+
|
|
137
|
+
// Track branches
|
|
138
|
+
if (thoughtData.branchFromThought && thoughtData.branchId) {
|
|
139
|
+
if (!this.branches[thoughtData.branchId]) {
|
|
140
|
+
this.branches[thoughtData.branchId] = [];
|
|
141
|
+
}
|
|
142
|
+
this.branches[thoughtData.branchId].push(thoughtData);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// Save history
|
|
146
|
+
this.saveHistory();
|
|
147
|
+
|
|
148
|
+
return {
|
|
149
|
+
success: true,
|
|
150
|
+
thoughtNumber: thoughtData.thoughtNumber,
|
|
151
|
+
totalThoughts: thoughtData.totalThoughts,
|
|
152
|
+
nextThoughtNeeded: thoughtData.nextThoughtNeeded,
|
|
153
|
+
branches: Object.keys(this.branches),
|
|
154
|
+
thoughtHistoryLength: this.thoughtHistory.length,
|
|
155
|
+
timestamp: thoughtData.timestamp
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
getHistory() {
|
|
160
|
+
return {
|
|
161
|
+
thoughts: this.thoughtHistory,
|
|
162
|
+
branches: this.branches,
|
|
163
|
+
totalThoughts: this.thoughtHistory.length
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// CLI Interface
|
|
169
|
+
if (require.main === module) {
|
|
170
|
+
const args = process.argv.slice(2);
|
|
171
|
+
const processor = new ThoughtProcessor();
|
|
172
|
+
|
|
173
|
+
// Parse arguments
|
|
174
|
+
const parseArgs = (args) => {
|
|
175
|
+
const parsed = {};
|
|
176
|
+
for (let i = 0; i < args.length; i++) {
|
|
177
|
+
const arg = args[i];
|
|
178
|
+
if (arg.startsWith('--')) {
|
|
179
|
+
const key = arg.slice(2);
|
|
180
|
+
const value = args[i + 1];
|
|
181
|
+
|
|
182
|
+
if (key === 'reset') {
|
|
183
|
+
return { reset: true };
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
if (key === 'history') {
|
|
187
|
+
return { history: true };
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
if (value && !value.startsWith('--')) {
|
|
191
|
+
// Parse boolean
|
|
192
|
+
if (value === 'true') parsed[key] = true;
|
|
193
|
+
else if (value === 'false') parsed[key] = false;
|
|
194
|
+
// Parse number
|
|
195
|
+
else if (!isNaN(value)) parsed[key] = parseFloat(value);
|
|
196
|
+
// String
|
|
197
|
+
else parsed[key] = value;
|
|
198
|
+
i++;
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
return parsed;
|
|
203
|
+
};
|
|
204
|
+
|
|
205
|
+
const input = parseArgs(args);
|
|
206
|
+
|
|
207
|
+
if (input.reset) {
|
|
208
|
+
processor.resetHistory();
|
|
209
|
+
console.log(JSON.stringify({ success: true, message: 'History reset' }, null, 2));
|
|
210
|
+
process.exit(0);
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
if (input.history) {
|
|
214
|
+
console.log(JSON.stringify(processor.getHistory(), null, 2));
|
|
215
|
+
process.exit(0);
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
// Map CLI args to expected field names
|
|
219
|
+
const thoughtInput = {
|
|
220
|
+
thought: input.thought,
|
|
221
|
+
thoughtNumber: input.number,
|
|
222
|
+
totalThoughts: input.total,
|
|
223
|
+
nextThoughtNeeded: input.next,
|
|
224
|
+
isRevision: input.revision !== undefined ? true : input.isRevision,
|
|
225
|
+
revisesThought: input.revision,
|
|
226
|
+
branchFromThought: input.branch,
|
|
227
|
+
branchId: input.branchId,
|
|
228
|
+
needsMoreThoughts: input.needsMore
|
|
229
|
+
};
|
|
230
|
+
|
|
231
|
+
const result = processor.processThought(thoughtInput);
|
|
232
|
+
console.log(JSON.stringify(result, null, 2));
|
|
233
|
+
process.exit(result.success ? 0 : 1);
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
module.exports = { ThoughtProcessor };
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for Sequential Thinking Thought Formatter
|
|
3
|
+
*
|
|
4
|
+
* Run with: npm test
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const { ThoughtFormatter } = require('../scripts/format-thought');
|
|
8
|
+
|
|
9
|
+
describe('ThoughtFormatter', () => {
|
|
10
|
+
describe('Simple Format', () => {
|
|
11
|
+
test('formats regular thought', () => {
|
|
12
|
+
const result = ThoughtFormatter.formatSimple({
|
|
13
|
+
thought: 'Test thought',
|
|
14
|
+
thoughtNumber: 1,
|
|
15
|
+
totalThoughts: 5
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
expect(result).toBe('Thought 1/5: Test thought');
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
test('formats revision thought', () => {
|
|
22
|
+
const result = ThoughtFormatter.formatSimple({
|
|
23
|
+
thought: 'Revised thought',
|
|
24
|
+
thoughtNumber: 2,
|
|
25
|
+
totalThoughts: 5,
|
|
26
|
+
isRevision: true,
|
|
27
|
+
revisesThought: 1
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
expect(result).toContain('[REVISION of Thought 1]');
|
|
31
|
+
expect(result).toContain('Revised thought');
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
test('formats branch thought', () => {
|
|
35
|
+
const result = ThoughtFormatter.formatSimple({
|
|
36
|
+
thought: 'Branch thought',
|
|
37
|
+
thoughtNumber: 3,
|
|
38
|
+
totalThoughts: 5,
|
|
39
|
+
branchFromThought: 2,
|
|
40
|
+
branchId: 'a'
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
expect(result).toContain('[BRANCH A from Thought 2]');
|
|
44
|
+
expect(result).toContain('Branch thought');
|
|
45
|
+
});
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
describe('Markdown Format', () => {
|
|
49
|
+
test('formats regular thought', () => {
|
|
50
|
+
const result = ThoughtFormatter.formatMarkdown({
|
|
51
|
+
thought: 'Test thought',
|
|
52
|
+
thoughtNumber: 1,
|
|
53
|
+
totalThoughts: 5
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
expect(result).toContain('**Thought 1/5**');
|
|
57
|
+
expect(result).toContain('Test thought');
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
test('formats revision thought', () => {
|
|
61
|
+
const result = ThoughtFormatter.formatMarkdown({
|
|
62
|
+
thought: 'Revised thought',
|
|
63
|
+
thoughtNumber: 2,
|
|
64
|
+
totalThoughts: 5,
|
|
65
|
+
isRevision: true,
|
|
66
|
+
revisesThought: 1
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
expect(result).toContain('**[REVISION of Thought 1]**');
|
|
70
|
+
});
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
describe('Box Format', () => {
|
|
74
|
+
test('formats with border', () => {
|
|
75
|
+
const result = ThoughtFormatter.format({
|
|
76
|
+
thought: 'Test thought',
|
|
77
|
+
thoughtNumber: 1,
|
|
78
|
+
totalThoughts: 5
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
expect(result).toContain('┌');
|
|
82
|
+
expect(result).toContain('└');
|
|
83
|
+
expect(result).toContain('💭');
|
|
84
|
+
expect(result).toContain('Test thought');
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
test('formats revision with emoji', () => {
|
|
88
|
+
const result = ThoughtFormatter.format({
|
|
89
|
+
thought: 'Revised',
|
|
90
|
+
thoughtNumber: 2,
|
|
91
|
+
totalThoughts: 5,
|
|
92
|
+
isRevision: true,
|
|
93
|
+
revisesThought: 1
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
expect(result).toContain('🔄');
|
|
97
|
+
expect(result).toContain('REVISION');
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
test('formats branch with emoji', () => {
|
|
101
|
+
const result = ThoughtFormatter.format({
|
|
102
|
+
thought: 'Branch',
|
|
103
|
+
thoughtNumber: 3,
|
|
104
|
+
totalThoughts: 5,
|
|
105
|
+
branchFromThought: 2,
|
|
106
|
+
branchId: 'a'
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
expect(result).toContain('🌿');
|
|
110
|
+
expect(result).toContain('BRANCH');
|
|
111
|
+
});
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
describe('Text Wrapping', () => {
|
|
115
|
+
test('wraps long text', () => {
|
|
116
|
+
const longText = 'This is a very long thought that should be wrapped across multiple lines when it exceeds the maximum width specified for the formatter';
|
|
117
|
+
const wrapped = ThoughtFormatter.wrapText(longText, 50);
|
|
118
|
+
|
|
119
|
+
expect(wrapped.length).toBeGreaterThan(1);
|
|
120
|
+
wrapped.forEach(line => {
|
|
121
|
+
expect(line.length).toBeLessThanOrEqual(50);
|
|
122
|
+
});
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
test('does not wrap short text', () => {
|
|
126
|
+
const shortText = 'Short thought';
|
|
127
|
+
const wrapped = ThoughtFormatter.wrapText(shortText, 50);
|
|
128
|
+
|
|
129
|
+
expect(wrapped.length).toBe(1);
|
|
130
|
+
expect(wrapped[0]).toBe(shortText);
|
|
131
|
+
});
|
|
132
|
+
});
|
|
133
|
+
});
|