init
This commit is contained in:
8
.opencode/skills/sequential-thinking/.env.example
Normal file
8
.opencode/skills/sequential-thinking/.env.example
Normal file
@@ -0,0 +1,8 @@
|
||||
# Sequential Thinking Configuration
|
||||
|
||||
# Disable thought logging output (useful for automated processing)
|
||||
# Set to "true" to disable console logging
|
||||
DISABLE_THOUGHT_LOGGING=false
|
||||
|
||||
# History file location (optional, defaults to scripts/.thought-history.json)
|
||||
# THOUGHT_HISTORY_FILE=/path/to/custom/history.json
|
||||
15
.opencode/skills/sequential-thinking/.gitignore
vendored
Normal file
15
.opencode/skills/sequential-thinking/.gitignore
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
# Dependencies
|
||||
node_modules/
|
||||
package-lock.json
|
||||
|
||||
# Environment
|
||||
.env
|
||||
|
||||
# Thought history (generated during use)
|
||||
scripts/.thought-history.json
|
||||
|
||||
# Test coverage
|
||||
coverage/
|
||||
|
||||
# Logs
|
||||
*.log
|
||||
183
.opencode/skills/sequential-thinking/README.md
Normal file
183
.opencode/skills/sequential-thinking/README.md
Normal file
@@ -0,0 +1,183 @@
|
||||
# Sequential Thinking Agent Skill
|
||||
|
||||
Structured, reflective problem-solving methodology converted from the sequential-thinking MCP server into a native Agent Skill.
|
||||
|
||||
## Overview
|
||||
|
||||
This skill teaches Claude to apply systematic sequential thinking methodology for complex problem-solving, without relying on external MCP tools. It enables:
|
||||
- Breaking down complex problems into manageable thought sequences
|
||||
- Dynamic adjustment of thought count as understanding evolves
|
||||
- Revision of previous thoughts when new insights emerge
|
||||
- Branching into alternative reasoning paths
|
||||
- Hypothesis generation and verification
|
||||
|
||||
## Skill Structure
|
||||
|
||||
```
|
||||
sequential-thinking/
|
||||
├── SKILL.md (105 lines)
|
||||
│ Core methodology, when to apply, scripts usage
|
||||
│
|
||||
├── package.json
|
||||
│ Test dependencies (jest)
|
||||
│
|
||||
├── .env.example
|
||||
│ Configuration options
|
||||
│
|
||||
├── scripts/
|
||||
│ ├── process-thought.js (executable)
|
||||
│ │ Validate and track thoughts deterministically
|
||||
│ │
|
||||
│ └── format-thought.js (executable)
|
||||
│ Format thoughts for display (box/simple/markdown)
|
||||
│
|
||||
├── tests/
|
||||
│ ├── process-thought.test.js
|
||||
│ │ Validation, tracking, history tests
|
||||
│ │
|
||||
│ └── format-thought.test.js
|
||||
│ Formatting tests (all formats)
|
||||
│
|
||||
└── references/
|
||||
├── core-patterns.md (95 lines)
|
||||
│ Essential revision & branching patterns
|
||||
│
|
||||
├── examples-api.md (88 lines)
|
||||
│ API design example walkthrough
|
||||
│
|
||||
├── examples-debug.md (90 lines)
|
||||
│ Performance debugging example
|
||||
│
|
||||
├── examples-architecture.md (94 lines)
|
||||
│ Architecture decision example
|
||||
│
|
||||
├── advanced-techniques.md (76 lines)
|
||||
│ Spiral refinement, hypothesis testing, convergence
|
||||
│
|
||||
└── advanced-strategies.md (79 lines)
|
||||
Uncertainty management, revision cascades, meta-thinking
|
||||
```
|
||||
|
||||
**Documentation**: 627 lines across 7 files (all under 100 lines)
|
||||
**Scripts**: 2 executable Node.js scripts with tests
|
||||
|
||||
## Key Features
|
||||
|
||||
### Progressive Disclosure Design
|
||||
Each file focuses on specific aspects, loaded only when needed:
|
||||
- **SKILL.md**: Quick reference with core methodology
|
||||
- **core-patterns.md**: Common patterns for everyday use
|
||||
- **examples-*.md**: Real-world walkthroughs for learning
|
||||
- **advanced-*.md**: Sophisticated techniques for complex scenarios
|
||||
|
||||
### Token Efficiency
|
||||
- Concise explanations sacrifice grammar for brevity
|
||||
- Examples demonstrate patterns without verbose explanation
|
||||
- Cross-references between files avoid duplication
|
||||
|
||||
### Methodology Conversion
|
||||
Extracted from MCP server's approach and converted to instructions:
|
||||
- MCP tool provided **interface** for sequential thinking
|
||||
- Agent skill provides **methodology** to think sequentially
|
||||
- No dependency on external tools—pure instructional approach
|
||||
|
||||
## Usage Modes
|
||||
|
||||
**Explicit Mode**: Use visible thought markers
|
||||
```
|
||||
Thought 1/5: [Analysis]
|
||||
Thought 2/5: [Further analysis]
|
||||
```
|
||||
|
||||
**Implicit Mode**: Apply methodology internally without cluttering output
|
||||
|
||||
## When Claude Should Use This Skill
|
||||
|
||||
Automatically activated for:
|
||||
- Complex problem decomposition
|
||||
- Adaptive planning with potential revisions
|
||||
- Debugging and root cause analysis
|
||||
- Architecture and design decisions
|
||||
- Problems with unclear or emerging scope
|
||||
- Multi-step solutions requiring context
|
||||
|
||||
## Scripts Usage
|
||||
|
||||
### Process Thought (Validation & Tracking)
|
||||
|
||||
```bash
|
||||
# Process a thought
|
||||
node scripts/process-thought.js --thought "Initial analysis" --number 1 --total 5 --next true
|
||||
|
||||
# Process with revision
|
||||
node scripts/process-thought.js --thought "Corrected analysis" --number 2 --total 5 --next true --revision 1
|
||||
|
||||
# Process with branching
|
||||
node scripts/process-thought.js --thought "Branch A" --number 2 --total 5 --next true --branch 1 --branchId "branch-a"
|
||||
|
||||
# View history
|
||||
node scripts/process-thought.js --history
|
||||
|
||||
# Reset history
|
||||
node scripts/process-thought.js --reset
|
||||
```
|
||||
|
||||
### Format Thought (Display)
|
||||
|
||||
```bash
|
||||
# Box format (default)
|
||||
node scripts/format-thought.js --thought "Analysis" --number 1 --total 5
|
||||
|
||||
# Simple text format
|
||||
node scripts/format-thought.js --thought "Analysis" --number 1 --total 5 --format simple
|
||||
|
||||
# Markdown format
|
||||
node scripts/format-thought.js --thought "Analysis" --number 1 --total 5 --format markdown
|
||||
|
||||
# With revision
|
||||
node scripts/format-thought.js --thought "Revised" --number 2 --total 5 --revision 1
|
||||
|
||||
# With branch
|
||||
node scripts/format-thought.js --thought "Branch" --number 2 --total 5 --branch 1 --branchId "a"
|
||||
```
|
||||
|
||||
### Running Tests
|
||||
|
||||
```bash
|
||||
# Install dependencies (first time only)
|
||||
npm install
|
||||
|
||||
# Run all tests
|
||||
npm test
|
||||
|
||||
# Run tests in watch mode
|
||||
npm run test:watch
|
||||
|
||||
# Run with coverage
|
||||
npm run test:coverage
|
||||
```
|
||||
|
||||
## When to Use Scripts
|
||||
|
||||
**Use scripts when**:
|
||||
- Need deterministic validation of thought structure
|
||||
- Want persistent thought history tracking
|
||||
- Require formatted output for documentation
|
||||
- Building tools that integrate with sequential thinking
|
||||
|
||||
**Don't use scripts when**:
|
||||
- Applying methodology directly in responses
|
||||
- Want lightweight, inline thinking
|
||||
- No need for validation or tracking
|
||||
|
||||
Scripts are **optional tooling** - the methodology can be applied without them.
|
||||
|
||||
## Source
|
||||
|
||||
Converted from: https://github.com/modelcontextprotocol/servers/tree/main/src/sequentialthinking
|
||||
|
||||
Original MCP server by Anthropic (MIT License).
|
||||
Skill conversion:
|
||||
- Extracts methodology as instructions
|
||||
- Adds executable scripts for deterministic validation
|
||||
- Makes tool-independent while preserving functionality
|
||||
97
.opencode/skills/sequential-thinking/SKILL.md
Normal file
97
.opencode/skills/sequential-thinking/SKILL.md
Normal file
@@ -0,0 +1,97 @@
|
||||
---
|
||||
name: ck:sequential-thinking
|
||||
description: Apply step-by-step analysis for complex problems with revision capability. Use for multi-step reasoning, hypothesis verification, adaptive planning, problem decomposition, course correction.
|
||||
license: MIT
|
||||
argument-hint: "[problem to analyze step-by-step]"
|
||||
metadata:
|
||||
author: claudekit
|
||||
version: "1.0.0"
|
||||
---
|
||||
|
||||
# Sequential Thinking
|
||||
|
||||
Structured problem-solving via manageable, reflective thought sequences with dynamic adjustment.
|
||||
|
||||
## When to Apply
|
||||
|
||||
- Complex problem decomposition
|
||||
- Adaptive planning with revision capability
|
||||
- Analysis needing course correction
|
||||
- Problems with unclear/emerging scope
|
||||
- Multi-step solutions requiring context maintenance
|
||||
- Hypothesis-driven investigation/debugging
|
||||
|
||||
## Core Process
|
||||
|
||||
### 1. Start with Loose Estimate
|
||||
```
|
||||
Thought 1/5: [Initial analysis]
|
||||
```
|
||||
Adjust dynamically as understanding evolves.
|
||||
|
||||
### 2. Structure Each Thought
|
||||
- Build on previous context explicitly
|
||||
- Address one aspect per thought
|
||||
- State assumptions, uncertainties, realizations
|
||||
- Signal what next thought should address
|
||||
|
||||
### 3. Apply Dynamic Adjustment
|
||||
- **Expand**: More complexity discovered → increase total
|
||||
- **Contract**: Simpler than expected → decrease total
|
||||
- **Revise**: New insight invalidates previous → mark revision
|
||||
- **Branch**: Multiple approaches → explore alternatives
|
||||
|
||||
### 4. Use Revision When Needed
|
||||
```
|
||||
Thought 5/8 [REVISION of Thought 2]: [Corrected understanding]
|
||||
- Original: [What was stated]
|
||||
- Why revised: [New insight]
|
||||
- Impact: [What changes]
|
||||
```
|
||||
|
||||
### 5. Branch for Alternatives
|
||||
```
|
||||
Thought 4/7 [BRANCH A from Thought 2]: [Approach A]
|
||||
Thought 4/7 [BRANCH B from Thought 2]: [Approach B]
|
||||
```
|
||||
Compare explicitly, converge with decision rationale.
|
||||
|
||||
### 6. Generate & Verify Hypotheses
|
||||
```
|
||||
Thought 6/9 [HYPOTHESIS]: [Proposed solution]
|
||||
Thought 7/9 [VERIFICATION]: [Test results]
|
||||
```
|
||||
Iterate until hypothesis verified.
|
||||
|
||||
### 7. Complete Only When Ready
|
||||
Mark final: `Thought N/N [FINAL]`
|
||||
|
||||
Complete when:
|
||||
- Solution verified
|
||||
- All critical aspects addressed
|
||||
- Confidence achieved
|
||||
- No outstanding uncertainties
|
||||
|
||||
## Application Modes
|
||||
|
||||
**Explicit**: Use visible thought markers when complexity warrants visible reasoning or user requests breakdown.
|
||||
|
||||
**Implicit**: Apply methodology internally for routine problem-solving where thinking aids accuracy without cluttering response.
|
||||
|
||||
## Scripts (Optional)
|
||||
|
||||
Optional scripts for deterministic validation/tracking:
|
||||
- `scripts/process-thought.js` - Validate & track thoughts with history
|
||||
- `scripts/format-thought.js` - Format for display (box/markdown/simple)
|
||||
|
||||
See README.md for usage examples. Use when validation/persistence needed; otherwise apply methodology directly.
|
||||
|
||||
## References
|
||||
|
||||
Load when deeper understanding needed:
|
||||
- `references/core-patterns.md` - Revision & branching patterns
|
||||
- `references/examples-api.md` - API design example
|
||||
- `references/examples-debug.md` - Debugging example
|
||||
- `references/examples-architecture.md` - Architecture decision example
|
||||
- `references/advanced-techniques.md` - Spiral refinement, hypothesis testing, convergence
|
||||
- `references/advanced-strategies.md` - Uncertainty, revision cascades, meta-thinking
|
||||
31
.opencode/skills/sequential-thinking/package.json
Normal file
31
.opencode/skills/sequential-thinking/package.json
Normal file
@@ -0,0 +1,31 @@
|
||||
{
|
||||
"name": "sequential-thinking-skill",
|
||||
"version": "1.0.0",
|
||||
"description": "Sequential thinking methodology with thought processing scripts",
|
||||
"main": "scripts/process-thought.js",
|
||||
"scripts": {
|
||||
"test": "jest",
|
||||
"test:watch": "jest --watch",
|
||||
"test:coverage": "jest --coverage"
|
||||
},
|
||||
"keywords": [
|
||||
"sequential-thinking",
|
||||
"problem-solving",
|
||||
"agent-skill"
|
||||
],
|
||||
"author": "Converted from Anthropic MCP Server",
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"jest": "^29.7.0"
|
||||
},
|
||||
"jest": {
|
||||
"testEnvironment": "node",
|
||||
"testMatch": [
|
||||
"**/tests/**/*.test.js"
|
||||
],
|
||||
"coveragePathIgnorePatterns": [
|
||||
"/node_modules/",
|
||||
"/tests/"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
# Advanced Sequential Thinking Strategies
|
||||
|
||||
Additional sophisticated patterns for complex scenarios.
|
||||
|
||||
## Uncertainty Management
|
||||
|
||||
Handle incomplete information systematically.
|
||||
|
||||
```
|
||||
Thought 2/7: Need to decide X
|
||||
Thought 3/7: Insufficient data—two scenarios possible
|
||||
Thought 4/7 [SCENARIO A if P true]: Analysis for A
|
||||
Thought 4/7 [SCENARIO B if P false]: Analysis for B
|
||||
Thought 5/7: Decision that works for both scenarios
|
||||
Thought 6/7: Or determine critical info needed
|
||||
Thought 7/7 [FINAL]: Robust solution or clear info requirement
|
||||
```
|
||||
|
||||
**Use for**: Decisions under uncertainty, incomplete requirements.
|
||||
|
||||
**Strategies**:
|
||||
- Find solution robust to uncertainty
|
||||
- Identify minimal info needed to resolve
|
||||
- Make safe assumptions with clear documentation
|
||||
|
||||
## Revision Cascade Management
|
||||
|
||||
Handle revisions that invalidate multiple subsequent thoughts.
|
||||
|
||||
```
|
||||
Thought 1/8: Foundation assumption
|
||||
Thought 2/8: Build on Thought 1
|
||||
Thought 3/8: Further build
|
||||
Thought 4/8: Discover Thought 1 invalid
|
||||
Thought 5/8 [REVISION of Thought 1]: Corrected foundation
|
||||
Thought 6/8 [REASSESSMENT]: Which of 2-3 still valid?
|
||||
- Thought 2: Partially valid, needs adjustment
|
||||
- Thought 3: Completely invalid
|
||||
Thought 7/8: Rebuild from corrected Thought 5
|
||||
Thought 8/8 [FINAL]: Solution on correct foundation
|
||||
```
|
||||
|
||||
**Key**: After major revision, explicitly assess downstream impact.
|
||||
|
||||
## Meta-Thinking Calibration
|
||||
|
||||
Monitor and adjust thinking process itself.
|
||||
|
||||
```
|
||||
Thought 5/9: [Regular thought]
|
||||
Thought 6/9 [META]: Past 3 thoughts circling without progress
|
||||
Analysis: Missing key information
|
||||
Adjustment: Need to research X before continuing
|
||||
Thought 7/9: Research findings on X
|
||||
Thought 8/9: Now can proceed with informed decision
|
||||
Thought 9/9: [Resume productive path]
|
||||
```
|
||||
|
||||
**Use when**: Stuck, circling, or unproductive pattern noticed.
|
||||
**Action**: Pause, identify issue, adjust strategy.
|
||||
|
||||
## Parallel Constraint Satisfaction
|
||||
|
||||
Handle multiple independent constraints simultaneously.
|
||||
|
||||
```
|
||||
Thought 2/10: Solution must satisfy A, B, C
|
||||
Thought 3/10 [CONSTRAINT A]: Solutions satisfying A: {X, Y, Z}
|
||||
Thought 4/10 [CONSTRAINT B]: Solutions satisfying B: {Y, Z, W}
|
||||
Thought 5/10 [CONSTRAINT C]: Solutions satisfying C: {X, Z}
|
||||
Thought 6/10 [INTERSECTION]: Z satisfies all
|
||||
Thought 7/10: Verify Z feasible
|
||||
Thought 8/10 [BRANCH if infeasible]: Relax which constraint?
|
||||
Thought 9/10: Decision on constraint relaxation if needed
|
||||
Thought 10/10 [FINAL]: Optimal solution given constraints
|
||||
```
|
||||
|
||||
**Use for**: Optimization problems, multi-criteria decisions.
|
||||
**Pattern**: Analyze independently → Find intersection → Verify feasibility.
|
||||
@@ -0,0 +1,76 @@
|
||||
# Advanced Sequential Thinking Techniques
|
||||
|
||||
Complex problem-solving patterns.
|
||||
|
||||
## Spiral Refinement
|
||||
|
||||
Return to concepts with progressively deeper understanding.
|
||||
|
||||
```
|
||||
Thought 1/7: Initial design (surface)
|
||||
Thought 2/7: Discover constraint A
|
||||
Thought 3/7: Refine for A
|
||||
Thought 4/7: Discover constraint B
|
||||
Thought 5/7: Refine for both A and B
|
||||
Thought 6/7: Integration reveals edge case
|
||||
Thought 7/7: Final design addressing all constraints
|
||||
```
|
||||
|
||||
**Use for**: Complex systems where constraints emerge iteratively.
|
||||
**Key**: Each return is refinement, not restart.
|
||||
|
||||
## Hypothesis-Driven Investigation
|
||||
|
||||
Systematic hypothesis generation and testing.
|
||||
|
||||
```
|
||||
Thought 1/6: Observe symptoms
|
||||
Thought 2/6 [HYPOTHESIS]: Explanation X
|
||||
Thought 3/6 [VERIFICATION]: Test X—partial match
|
||||
Thought 4/6 [REFINED HYPOTHESIS]: Adjusted Y
|
||||
Thought 5/6 [VERIFICATION]: Test Y—confirmed
|
||||
Thought 6/6 [FINAL]: Solution based on verified Y
|
||||
```
|
||||
|
||||
**Use for**: Debugging, root cause analysis, diagnostics.
|
||||
**Pattern**: Generate → Test → Refine → Re-test loop.
|
||||
|
||||
## Multi-Branch Convergence
|
||||
|
||||
Explore alternatives, then synthesize best approach.
|
||||
|
||||
```
|
||||
Thought 2/8: Multiple viable approaches
|
||||
Thought 3/8 [BRANCH A]: Approach A benefits
|
||||
Thought 4/8 [BRANCH A]: Approach A drawbacks
|
||||
Thought 5/8 [BRANCH B]: Approach B benefits
|
||||
Thought 6/8 [BRANCH B]: Approach B drawbacks
|
||||
Thought 7/8 [CONVERGENCE]: Hybrid combining A's X with B's Y
|
||||
Thought 8/8 [FINAL]: Hybrid superior to either alone
|
||||
```
|
||||
|
||||
**Use for**: Complex decisions where neither option clearly best.
|
||||
**Key**: Convergence often yields better solution than either branch.
|
||||
|
||||
## Progressive Context Deepening
|
||||
|
||||
Build understanding in layers from abstract to concrete.
|
||||
|
||||
```
|
||||
Thought 1/9: High-level problem
|
||||
Thought 2/9: Identify major components
|
||||
Thought 3/9: Zoom into component A (detailed)
|
||||
Thought 4/9: Zoom into component B (detailed)
|
||||
Thought 5/9: Identify A-B interactions
|
||||
Thought 6/9: Discover emergent constraint
|
||||
Thought 7/9 [REVISION of 3-4]: Adjust for interaction
|
||||
Thought 8/9: Verify complete system
|
||||
Thought 9/9 [FINAL]: Integrated solution
|
||||
```
|
||||
|
||||
**Use for**: System design, architecture, integration problems.
|
||||
**Pattern**: Abstract → Components → Details → Interactions → Integration.
|
||||
|
||||
## Reference
|
||||
|
||||
See `advanced-strategies.md` for: Uncertainty Management, Revision Cascade Management, Meta-Thinking Calibration, Parallel Constraint Satisfaction.
|
||||
@@ -0,0 +1,95 @@
|
||||
# Core Sequential Thinking Patterns
|
||||
|
||||
Essential revision and branching patterns.
|
||||
|
||||
## Revision Patterns
|
||||
|
||||
### Assumption Challenge
|
||||
Early assumption proves invalid with new data.
|
||||
```
|
||||
Thought 1/5: Assume X is bottleneck
|
||||
Thought 4/5 [REVISION of Thought 1]: X adequate; Y is actual bottleneck
|
||||
```
|
||||
|
||||
### Scope Expansion
|
||||
Problem larger than initially understood.
|
||||
```
|
||||
Thought 1/4: Fix bug
|
||||
Thought 4/5 [REVISION of scope]: Architectural redesign needed, not patch
|
||||
```
|
||||
|
||||
### Approach Shift
|
||||
Initial strategy inadequate for requirements.
|
||||
```
|
||||
Thought 2/6: Optimize query
|
||||
Thought 5/6 [REVISION of Thought 2]: Optimization + cache layer required
|
||||
```
|
||||
|
||||
### Understanding Deepening
|
||||
Later insight fundamentally changes interpretation.
|
||||
```
|
||||
Thought 1/5: Feature broken
|
||||
Thought 4/5 [REVISION of Thought 1]: Not bug—UX confusion issue
|
||||
```
|
||||
|
||||
## Branching Patterns
|
||||
|
||||
### Trade-off Evaluation
|
||||
Compare approaches with different trade-offs.
|
||||
```
|
||||
Thought 3/7: Choose between X and Y
|
||||
Thought 4/7 [BRANCH A]: X—simpler, less scalable
|
||||
Thought 4/7 [BRANCH B]: Y—complex, scales better
|
||||
Thought 5/7: Choose Y for long-term needs
|
||||
```
|
||||
|
||||
### Risk Mitigation
|
||||
Prepare backup for high-risk primary approach.
|
||||
```
|
||||
Thought 2/6: Primary: API integration
|
||||
Thought 3/6 [BRANCH A]: API details
|
||||
Thought 3/6 [BRANCH B]: Fallback: webhook
|
||||
Thought 4/6: Implement A with B contingency
|
||||
```
|
||||
|
||||
### Parallel Exploration
|
||||
Investigate independent concerns separately.
|
||||
```
|
||||
Thought 3/8: Two unknowns—DB schema & API design
|
||||
Thought 4/8 [BRANCH DB]: DB options
|
||||
Thought 4/8 [BRANCH API]: API patterns
|
||||
Thought 5/8: Integrate findings
|
||||
```
|
||||
|
||||
### Hypothesis Testing
|
||||
Test multiple explanations systematically.
|
||||
```
|
||||
Thought 2/6: Could be A, B, or C
|
||||
Thought 3/6 [BRANCH A]: Test A—not cause
|
||||
Thought 3/6 [BRANCH B]: Test B—confirmed
|
||||
Thought 4/6: Root cause via Branch B
|
||||
```
|
||||
|
||||
## Adjustment Guidelines
|
||||
|
||||
**Expand when**: Complexity discovered, multiple aspects identified, verification needed, alternatives require exploration.
|
||||
|
||||
**Contract when**: Key insight solves earlier, problem simpler, steps merge naturally.
|
||||
|
||||
**Example**:
|
||||
```
|
||||
Thought 1/5: Initial
|
||||
Thought 3/7: Complexity (5→7)
|
||||
Thought 5/8: Another aspect (7→8)
|
||||
Thought 8/8 [FINAL]: Complete
|
||||
```
|
||||
|
||||
## Anti-Patterns
|
||||
|
||||
**Premature Completion**: Rushing without verification → Add verification thoughts.
|
||||
|
||||
**Revision Cascade**: Repeated revisions without understanding why → Identify root cause.
|
||||
|
||||
**Branching Explosion**: Too many branches → Limit to 2-3, converge before more.
|
||||
|
||||
**Context Loss**: Ignoring earlier insights → Reference previous thoughts explicitly.
|
||||
@@ -0,0 +1,88 @@
|
||||
# Example: API Design with Sequential Thinking
|
||||
|
||||
**Problem**: Design authentication API for multi-tenant SaaS.
|
||||
|
||||
## Without Sequential Thinking
|
||||
"Use JWT with OAuth2. Add tenant ID to claims. Implement refresh tokens."
|
||||
(Misses edge cases, scaling, security)
|
||||
|
||||
## With Sequential Thinking
|
||||
|
||||
```
|
||||
Thought 1/5: Requirements
|
||||
|
||||
Multi-tenant SaaS authentication needs:
|
||||
- Tenant isolation (prevent cross-tenant access)
|
||||
- Scalability (thousands of tenants)
|
||||
- Security (industry standards)
|
||||
|
||||
Uncertainty: Session vs token? Stateful vs stateless?
|
||||
Next: Evaluate approaches
|
||||
|
||||
Thought 2/6: Approach evaluation (adjusted)
|
||||
|
||||
Comparing session vs JWT:
|
||||
- Session: Server state, easy revocation, harder scaling
|
||||
- JWT: Stateless, scales well, complex revocation
|
||||
|
||||
Multi-tenancy complicates sessions (which DB?).
|
||||
JWT better for distributed systems.
|
||||
Next: JWT structure
|
||||
|
||||
Thought 3/6: JWT payload design
|
||||
|
||||
JWT includes: User ID, Tenant ID, Permissions, Expiration
|
||||
|
||||
Uncertainty: Where verify tenant? Gateway vs service?
|
||||
Next: Token refresh
|
||||
|
||||
Thought 4/6 [REVISION of Thought 3]: Security fix
|
||||
|
||||
Original: Tenant ID in JWT claims.
|
||||
Issue: Claims visible (base64), could read tenant IDs.
|
||||
|
||||
Corrected:
|
||||
- Keep tenant ID (needed for routing)
|
||||
- Add gateway verification
|
||||
- Log access attempts
|
||||
|
||||
Impact: Need gateway security layer
|
||||
|
||||
Thought 5/7: Refresh strategy (adjusted)
|
||||
|
||||
Access: 15 min
|
||||
Refresh: 7 days, rotate on use
|
||||
|
||||
Storage:
|
||||
- Access: Client memory
|
||||
- Refresh: HttpOnly cookie + DB revocation
|
||||
|
||||
Enables revocation + stateless benefits.
|
||||
|
||||
Thought 6/7: Gateway flow
|
||||
|
||||
1. Verify JWT signature
|
||||
2. Extract tenant ID
|
||||
3. Verify user belongs to tenant (cache + DB)
|
||||
4. Forward with verified context
|
||||
|
||||
Addresses Thought 4 security concern.
|
||||
|
||||
Thought 7/7 [FINAL]: Complete solution
|
||||
|
||||
- JWT with refresh rotation
|
||||
- Tenant ID + gateway verification
|
||||
- 15-min access, 7-day refresh
|
||||
- HttpOnly cookies + revocation DB
|
||||
- Gateway enforces isolation
|
||||
|
||||
Confidence: High
|
||||
Assumptions: Distributed, centralized gateway
|
||||
Trade-offs: Slight latency vs security
|
||||
```
|
||||
|
||||
## Key Outcomes
|
||||
|
||||
1. **Revision caught security issue**: Tenant ID visibility
|
||||
2. **Dynamic adjustment**: 5→7 thoughts as complexity emerged
|
||||
3. **Comprehensive**: Authentication, authorization, multi-tenancy, revocation
|
||||
@@ -0,0 +1,94 @@
|
||||
# Example: Architecture Decision with Sequential Thinking
|
||||
|
||||
**Problem**: Choose state management for growing React app.
|
||||
|
||||
## Sequential Thinking Approach
|
||||
|
||||
```
|
||||
Thought 1/4: Initial assessment
|
||||
|
||||
React app growing complex. useState scattered across components.
|
||||
Need centralized state management.
|
||||
Options: Redux, MobX, Zustand, Context API, Jotai.
|
||||
|
||||
Next: Define requirements
|
||||
|
||||
Thought 2/5: Requirements (adjusted up)
|
||||
|
||||
App needs:
|
||||
- Real-time updates (WebSocket)
|
||||
- Offline support
|
||||
- Complex nested state
|
||||
- Multiple devs (maintainability)
|
||||
- TypeScript (type safety)
|
||||
|
||||
These eliminate simpler solutions.
|
||||
Next: Evaluate remaining options
|
||||
|
||||
Thought 3/5 [REVISION of Thought 1]: Scope refinement
|
||||
|
||||
Original assumption: Need global state management.
|
||||
Realization: Not all state needs centralization.
|
||||
|
||||
Better breakdown:
|
||||
- Server state (API data): React Query
|
||||
- UI state (modals, forms): Local useState
|
||||
- Auth state: Context API
|
||||
- App-wide settings: Simple global store
|
||||
|
||||
This reduces problem scope significantly.
|
||||
Changes evaluation criteria.
|
||||
Next: Re-evaluate with refined scope
|
||||
|
||||
Thought 4/6: Re-evaluation (adjusted)
|
||||
|
||||
Only need lightweight store for app-wide settings.
|
||||
Zustand fits:
|
||||
- Minimal boilerplate
|
||||
- Excellent TypeScript support
|
||||
- No provider wrapper
|
||||
- ~1KB size
|
||||
|
||||
React Query handles server state (caching, refetch, offline).
|
||||
Most state stays local.
|
||||
|
||||
Next: Verify this handles all requirements
|
||||
|
||||
Thought 5/6 [HYPOTHESIS]: Hybrid approach
|
||||
|
||||
Hypothesis: Zustand + React Query + local state solves needs.
|
||||
|
||||
- Zustand: Theme, user prefs, global UI flags
|
||||
- React Query: All server data, caching, sync
|
||||
- useState: Component-local UI
|
||||
|
||||
Benefits: Simple, performant, maintainable.
|
||||
Uncertainty: Real-time updates?
|
||||
|
||||
Thought 6/6 [FINAL]: Verified solution
|
||||
|
||||
React Query supports WebSocket via custom hooks.
|
||||
Zustand handles global UI simply.
|
||||
Local state for component-specific needs.
|
||||
|
||||
Architecture decision:
|
||||
- Zustand for global UI state
|
||||
- React Query for all server interactions
|
||||
- Local useState for component state
|
||||
|
||||
Confidence: High
|
||||
Assumptions: Team comfortable with React Query patterns
|
||||
Benefits: Simpler than Redux, more powerful than Context
|
||||
Trade-offs: Learning curve for React Query (but worthwhile)
|
||||
```
|
||||
|
||||
## Key Insights
|
||||
|
||||
1. **Scope revision crucial**: Original "need global state" reframed to specific state categories
|
||||
2. **Separation of concerns**: Different state types need different solutions
|
||||
3. **Hypothesis verification**: Confirmed WebSocket support before finalizing
|
||||
4. **Simpler is better**: Avoided over-engineering with heavy Redux solution
|
||||
|
||||
## Impact of Revision
|
||||
|
||||
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 @@
|
||||
# Example: Performance Debugging with Sequential Thinking
|
||||
|
||||
**Problem**: API endpoint slow (2-3s instead of <200ms).
|
||||
|
||||
## Sequential Thinking Approach
|
||||
|
||||
```
|
||||
Thought 1/5: Initial investigation
|
||||
|
||||
Endpoint: GET /api/users/{id}/dashboard
|
||||
Expected: <200ms
|
||||
Actual: 2-3s
|
||||
|
||||
Need to identify bottleneck.
|
||||
Next: Analyze endpoint logic
|
||||
|
||||
Thought 2/5: Endpoint analysis
|
||||
|
||||
Dashboard fetches:
|
||||
- User profile
|
||||
- Recent activities (last 50)
|
||||
- Notifications (unread)
|
||||
- Analytics summary
|
||||
|
||||
Each is separate DB query. Could be N+1 problem.
|
||||
Next: Profile actual execution
|
||||
|
||||
Thought 3/6: Profiling results (adjusted up—more complex)
|
||||
|
||||
Profiling:
|
||||
- User profile: 20ms
|
||||
- Activities: 1800ms (!!)
|
||||
- Notifications: 100ms
|
||||
- Analytics: 80ms
|
||||
|
||||
Activities query is bottleneck (90% of time).
|
||||
Need to examine that query.
|
||||
Next: Investigate activities query
|
||||
|
||||
Thought 4/6 [BRANCH A]: Hypothesis - N+1 query
|
||||
|
||||
Activities table has user_id FK to users.
|
||||
Query might fetch activities, then user for each (N+1).
|
||||
Verification: Check if uses joins or loops.
|
||||
|
||||
Thought 4/6 [BRANCH B]: Hypothesis - Missing index
|
||||
|
||||
Activities table might lack index on user_id + created_at.
|
||||
Without index, full table scan for user's activities.
|
||||
Verification: Check table indexes.
|
||||
|
||||
Thought 5/6 [VERIFICATION]: Testing hypotheses
|
||||
|
||||
Query examination: Uses proper joins (not N+1).
|
||||
Index check: user_id indexed, NOT created_at.
|
||||
Query filters by user_id AND sorts by created_at.
|
||||
|
||||
Branch B confirmed: Missing composite index causes slow sort.
|
||||
Branch A eliminated: No N+1 issue.
|
||||
|
||||
Root cause identified.
|
||||
Next: Implement solution
|
||||
|
||||
Thought 6/6 [FINAL]: Solution and verification
|
||||
|
||||
Create composite index:
|
||||
```sql
|
||||
CREATE INDEX idx_activities_user_created
|
||||
ON activities(user_id, created_at DESC);
|
||||
```
|
||||
|
||||
Tested: Response time now 120ms (target met).
|
||||
|
||||
Confidence: High (verified with profiling)
|
||||
Result: 95% performance improvement
|
||||
```
|
||||
|
||||
## Key Techniques Demonstrated
|
||||
|
||||
1. **Branching for hypothesis testing**: Explored N+1 vs index hypotheses in parallel
|
||||
2. **Verification before solution**: Tested both hypotheses systematically
|
||||
3. **Data-driven decisions**: Used profiling data to guide investigation
|
||||
4. **Dynamic adjustment**: Expanded thought count when complexity emerged
|
||||
5. **Elimination method**: Ruled out N+1, confirmed index issue
|
||||
|
||||
## Comparison
|
||||
|
||||
**Without sequential thinking**: Might jump to N+1 conclusion (common issue), waste time optimizing wrong thing.
|
||||
|
||||
**With sequential thinking**: Systematically tested hypotheses, identified actual root cause, implemented correct fix.
|
||||
159
.opencode/skills/sequential-thinking/scripts/format-thought.js
Executable file
159
.opencode/skills/sequential-thinking/scripts/format-thought.js
Executable file
@@ -0,0 +1,159 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
/**
|
||||
* Sequential Thinking Thought Formatter
|
||||
*
|
||||
* Formats thoughts for display with visual indicators for type (regular/revision/branch).
|
||||
* Provides consistent, readable output for thought sequences.
|
||||
*
|
||||
* Usage:
|
||||
* node format-thought.js --thought "Analysis" --number 1 --total 5
|
||||
* node format-thought.js --thought "Revision" --number 2 --total 5 --revision 1
|
||||
* node format-thought.js --thought "Branch A" --number 3 --total 5 --branch 2 --branchId "a"
|
||||
*/
|
||||
|
||||
class ThoughtFormatter {
|
||||
static format(thoughtData) {
|
||||
const { thoughtNumber, totalThoughts, thought, isRevision, revisesThought, branchFromThought, branchId } = thoughtData;
|
||||
|
||||
let prefix = '';
|
||||
let context = '';
|
||||
let emoji = '';
|
||||
|
||||
if (isRevision && revisesThought) {
|
||||
emoji = '🔄';
|
||||
prefix = 'REVISION';
|
||||
context = ` (revising thought ${revisesThought})`;
|
||||
} else if (branchFromThought) {
|
||||
emoji = '🌿';
|
||||
prefix = 'BRANCH';
|
||||
context = branchId ? ` (from thought ${branchFromThought}, ID: ${branchId})` : ` (from thought ${branchFromThought})`;
|
||||
} else {
|
||||
emoji = '💭';
|
||||
prefix = 'Thought';
|
||||
context = '';
|
||||
}
|
||||
|
||||
const header = `${emoji} ${prefix} ${thoughtNumber}/${totalThoughts}${context}`;
|
||||
const maxLength = Math.max(header.length, thought.length);
|
||||
const border = '─'.repeat(maxLength + 4);
|
||||
|
||||
// Wrap long thoughts
|
||||
const wrappedThought = this.wrapText(thought, maxLength);
|
||||
const thoughtLines = wrappedThought.map(line => `│ ${line.padEnd(maxLength + 2)} │`).join('\n');
|
||||
|
||||
return `
|
||||
┌${border}┐
|
||||
│ ${header.padEnd(maxLength + 2)} │
|
||||
├${border}┤
|
||||
${thoughtLines}
|
||||
└${border}┘`;
|
||||
}
|
||||
|
||||
static wrapText(text, maxWidth) {
|
||||
if (text.length <= maxWidth) {
|
||||
return [text];
|
||||
}
|
||||
|
||||
const words = text.split(' ');
|
||||
const lines = [];
|
||||
let currentLine = '';
|
||||
|
||||
for (const word of words) {
|
||||
if ((currentLine + ' ' + word).trim().length <= maxWidth) {
|
||||
currentLine = currentLine ? currentLine + ' ' + word : word;
|
||||
} else {
|
||||
if (currentLine) lines.push(currentLine);
|
||||
currentLine = word;
|
||||
}
|
||||
}
|
||||
|
||||
if (currentLine) lines.push(currentLine);
|
||||
return lines;
|
||||
}
|
||||
|
||||
static formatSimple(thoughtData) {
|
||||
const { thoughtNumber, totalThoughts, thought, isRevision, revisesThought, branchFromThought, branchId } = thoughtData;
|
||||
|
||||
let marker = '';
|
||||
if (isRevision && revisesThought) {
|
||||
marker = ` [REVISION of Thought ${revisesThought}]`;
|
||||
} else if (branchFromThought) {
|
||||
marker = branchId ? ` [BRANCH ${branchId.toUpperCase()} from Thought ${branchFromThought}]` : ` [BRANCH from Thought ${branchFromThought}]`;
|
||||
}
|
||||
|
||||
return `Thought ${thoughtNumber}/${totalThoughts}${marker}: ${thought}`;
|
||||
}
|
||||
|
||||
static formatMarkdown(thoughtData) {
|
||||
const { thoughtNumber, totalThoughts, thought, isRevision, revisesThought, branchFromThought, branchId } = thoughtData;
|
||||
|
||||
let marker = '';
|
||||
if (isRevision && revisesThought) {
|
||||
marker = ` **[REVISION of Thought ${revisesThought}]**`;
|
||||
} else if (branchFromThought) {
|
||||
marker = branchId ? ` **[BRANCH ${branchId.toUpperCase()} from Thought ${branchFromThought}]**` : ` **[BRANCH from Thought ${branchFromThought}]**`;
|
||||
}
|
||||
|
||||
return `**Thought ${thoughtNumber}/${totalThoughts}**${marker}\n\n${thought}\n`;
|
||||
}
|
||||
}
|
||||
|
||||
// CLI Interface
|
||||
if (require.main === module) {
|
||||
const args = process.argv.slice(2);
|
||||
|
||||
const parseArgs = (args) => {
|
||||
const parsed = {};
|
||||
for (let i = 0; i < args.length; i++) {
|
||||
const arg = args[i];
|
||||
if (arg.startsWith('--')) {
|
||||
const key = arg.slice(2);
|
||||
const value = args[i + 1];
|
||||
|
||||
if (value && !value.startsWith('--')) {
|
||||
// Parse boolean
|
||||
if (value === 'true') parsed[key] = true;
|
||||
else if (value === 'false') parsed[key] = false;
|
||||
// Parse number
|
||||
else if (!isNaN(value)) parsed[key] = parseFloat(value);
|
||||
// String
|
||||
else parsed[key] = value;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
return parsed;
|
||||
};
|
||||
|
||||
const input = parseArgs(args);
|
||||
|
||||
const thoughtData = {
|
||||
thought: input.thought || 'No thought provided',
|
||||
thoughtNumber: input.number || 1,
|
||||
totalThoughts: input.total || 1,
|
||||
isRevision: input.revision !== undefined,
|
||||
revisesThought: input.revision,
|
||||
branchFromThought: input.branch,
|
||||
branchId: input.branchId
|
||||
};
|
||||
|
||||
const format = input.format || 'box';
|
||||
|
||||
let output;
|
||||
switch (format) {
|
||||
case 'simple':
|
||||
output = ThoughtFormatter.formatSimple(thoughtData);
|
||||
break;
|
||||
case 'markdown':
|
||||
output = ThoughtFormatter.formatMarkdown(thoughtData);
|
||||
break;
|
||||
case 'box':
|
||||
default:
|
||||
output = ThoughtFormatter.format(thoughtData);
|
||||
}
|
||||
|
||||
console.log(output);
|
||||
}
|
||||
|
||||
module.exports = { ThoughtFormatter };
|
||||
236
.opencode/skills/sequential-thinking/scripts/process-thought.js
Executable file
236
.opencode/skills/sequential-thinking/scripts/process-thought.js
Executable file
@@ -0,0 +1,236 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
/**
|
||||
* Sequential Thinking Thought Processor
|
||||
*
|
||||
* Validates and tracks sequential thoughts with revision and branching support.
|
||||
* Provides deterministic validation and context management.
|
||||
*
|
||||
* Usage:
|
||||
* node process-thought.js --thought "Analysis text" --number 1 --total 5 --next true
|
||||
* node process-thought.js --thought "Revision" --number 2 --total 5 --next true --revision 1
|
||||
* node process-thought.js --reset # Reset thought history
|
||||
*/
|
||||
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
// Configuration
|
||||
const HISTORY_FILE = path.join(__dirname, '.thought-history.json');
|
||||
const DISABLE_LOGGING = process.env.DISABLE_THOUGHT_LOGGING?.toLowerCase() === 'true';
|
||||
|
||||
class ThoughtProcessor {
|
||||
constructor() {
|
||||
this.loadHistory();
|
||||
}
|
||||
|
||||
loadHistory() {
|
||||
try {
|
||||
if (fs.existsSync(HISTORY_FILE)) {
|
||||
const data = JSON.parse(fs.readFileSync(HISTORY_FILE, 'utf8'));
|
||||
this.thoughtHistory = data.thoughtHistory || [];
|
||||
this.branches = data.branches || {};
|
||||
} else {
|
||||
this.thoughtHistory = [];
|
||||
this.branches = {};
|
||||
}
|
||||
} catch (error) {
|
||||
this.thoughtHistory = [];
|
||||
this.branches = {};
|
||||
}
|
||||
}
|
||||
|
||||
saveHistory() {
|
||||
fs.writeFileSync(
|
||||
HISTORY_FILE,
|
||||
JSON.stringify({
|
||||
thoughtHistory: this.thoughtHistory,
|
||||
branches: this.branches
|
||||
}, null, 2)
|
||||
);
|
||||
}
|
||||
|
||||
resetHistory() {
|
||||
this.thoughtHistory = [];
|
||||
this.branches = {};
|
||||
if (fs.existsSync(HISTORY_FILE)) {
|
||||
fs.unlinkSync(HISTORY_FILE);
|
||||
}
|
||||
}
|
||||
|
||||
validateThought(input) {
|
||||
const errors = [];
|
||||
|
||||
if (!input.thought || typeof input.thought !== 'string' || input.thought.trim() === '') {
|
||||
errors.push('Invalid thought: must be a non-empty string');
|
||||
}
|
||||
|
||||
if (!input.thoughtNumber || typeof input.thoughtNumber !== 'number' || input.thoughtNumber < 1) {
|
||||
errors.push('Invalid thoughtNumber: must be a positive number');
|
||||
}
|
||||
|
||||
if (!input.totalThoughts || typeof input.totalThoughts !== 'number' || input.totalThoughts < 1) {
|
||||
errors.push('Invalid totalThoughts: must be a positive number');
|
||||
}
|
||||
|
||||
if (typeof input.nextThoughtNeeded !== 'boolean') {
|
||||
errors.push('Invalid nextThoughtNeeded: must be a boolean');
|
||||
}
|
||||
|
||||
// Optional field validations
|
||||
if (input.isRevision !== undefined && typeof input.isRevision !== 'boolean') {
|
||||
errors.push('Invalid isRevision: must be a boolean');
|
||||
}
|
||||
|
||||
if (input.revisesThought !== undefined && (typeof input.revisesThought !== 'number' || input.revisesThought < 1)) {
|
||||
errors.push('Invalid revisesThought: must be a positive number');
|
||||
}
|
||||
|
||||
if (input.branchFromThought !== undefined && (typeof input.branchFromThought !== 'number' || input.branchFromThought < 1)) {
|
||||
errors.push('Invalid branchFromThought: must be a positive number');
|
||||
}
|
||||
|
||||
if (input.branchId !== undefined && typeof input.branchId !== 'string') {
|
||||
errors.push('Invalid branchId: must be a string');
|
||||
}
|
||||
|
||||
if (input.needsMoreThoughts !== undefined && typeof input.needsMoreThoughts !== 'boolean') {
|
||||
errors.push('Invalid needsMoreThoughts: must be a boolean');
|
||||
}
|
||||
|
||||
return errors;
|
||||
}
|
||||
|
||||
processThought(input) {
|
||||
const errors = this.validateThought(input);
|
||||
|
||||
if (errors.length > 0) {
|
||||
return {
|
||||
success: false,
|
||||
errors,
|
||||
status: 'failed'
|
||||
};
|
||||
}
|
||||
|
||||
// Auto-adjust totalThoughts if thoughtNumber exceeds it
|
||||
if (input.thoughtNumber > input.totalThoughts) {
|
||||
input.totalThoughts = input.thoughtNumber;
|
||||
}
|
||||
|
||||
// Create thought data
|
||||
const thoughtData = {
|
||||
thought: input.thought,
|
||||
thoughtNumber: input.thoughtNumber,
|
||||
totalThoughts: input.totalThoughts,
|
||||
nextThoughtNeeded: input.nextThoughtNeeded,
|
||||
isRevision: input.isRevision,
|
||||
revisesThought: input.revisesThought,
|
||||
branchFromThought: input.branchFromThought,
|
||||
branchId: input.branchId,
|
||||
needsMoreThoughts: input.needsMoreThoughts,
|
||||
timestamp: new Date().toISOString()
|
||||
};
|
||||
|
||||
// Add to history
|
||||
this.thoughtHistory.push(thoughtData);
|
||||
|
||||
// Track branches
|
||||
if (thoughtData.branchFromThought && thoughtData.branchId) {
|
||||
if (!this.branches[thoughtData.branchId]) {
|
||||
this.branches[thoughtData.branchId] = [];
|
||||
}
|
||||
this.branches[thoughtData.branchId].push(thoughtData);
|
||||
}
|
||||
|
||||
// Save history
|
||||
this.saveHistory();
|
||||
|
||||
return {
|
||||
success: true,
|
||||
thoughtNumber: thoughtData.thoughtNumber,
|
||||
totalThoughts: thoughtData.totalThoughts,
|
||||
nextThoughtNeeded: thoughtData.nextThoughtNeeded,
|
||||
branches: Object.keys(this.branches),
|
||||
thoughtHistoryLength: this.thoughtHistory.length,
|
||||
timestamp: thoughtData.timestamp
|
||||
};
|
||||
}
|
||||
|
||||
getHistory() {
|
||||
return {
|
||||
thoughts: this.thoughtHistory,
|
||||
branches: this.branches,
|
||||
totalThoughts: this.thoughtHistory.length
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// CLI Interface
|
||||
if (require.main === module) {
|
||||
const args = process.argv.slice(2);
|
||||
const processor = new ThoughtProcessor();
|
||||
|
||||
// Parse arguments
|
||||
const parseArgs = (args) => {
|
||||
const parsed = {};
|
||||
for (let i = 0; i < args.length; i++) {
|
||||
const arg = args[i];
|
||||
if (arg.startsWith('--')) {
|
||||
const key = arg.slice(2);
|
||||
const value = args[i + 1];
|
||||
|
||||
if (key === 'reset') {
|
||||
return { reset: true };
|
||||
}
|
||||
|
||||
if (key === 'history') {
|
||||
return { history: true };
|
||||
}
|
||||
|
||||
if (value && !value.startsWith('--')) {
|
||||
// Parse boolean
|
||||
if (value === 'true') parsed[key] = true;
|
||||
else if (value === 'false') parsed[key] = false;
|
||||
// Parse number
|
||||
else if (!isNaN(value)) parsed[key] = parseFloat(value);
|
||||
// String
|
||||
else parsed[key] = value;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
return parsed;
|
||||
};
|
||||
|
||||
const input = parseArgs(args);
|
||||
|
||||
if (input.reset) {
|
||||
processor.resetHistory();
|
||||
console.log(JSON.stringify({ success: true, message: 'History reset' }, null, 2));
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
if (input.history) {
|
||||
console.log(JSON.stringify(processor.getHistory(), null, 2));
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
// Map CLI args to expected field names
|
||||
const thoughtInput = {
|
||||
thought: input.thought,
|
||||
thoughtNumber: input.number,
|
||||
totalThoughts: input.total,
|
||||
nextThoughtNeeded: input.next,
|
||||
isRevision: input.revision !== undefined ? true : input.isRevision,
|
||||
revisesThought: input.revision,
|
||||
branchFromThought: input.branch,
|
||||
branchId: input.branchId,
|
||||
needsMoreThoughts: input.needsMore
|
||||
};
|
||||
|
||||
const result = processor.processThought(thoughtInput);
|
||||
console.log(JSON.stringify(result, null, 2));
|
||||
process.exit(result.success ? 0 : 1);
|
||||
}
|
||||
|
||||
module.exports = { ThoughtProcessor };
|
||||
@@ -0,0 +1,133 @@
|
||||
/**
|
||||
* Tests for Sequential Thinking Thought Formatter
|
||||
*
|
||||
* Run with: npm test
|
||||
*/
|
||||
|
||||
const { ThoughtFormatter } = require('../scripts/format-thought');
|
||||
|
||||
describe('ThoughtFormatter', () => {
|
||||
describe('Simple Format', () => {
|
||||
test('formats regular thought', () => {
|
||||
const result = ThoughtFormatter.formatSimple({
|
||||
thought: 'Test thought',
|
||||
thoughtNumber: 1,
|
||||
totalThoughts: 5
|
||||
});
|
||||
|
||||
expect(result).toBe('Thought 1/5: Test thought');
|
||||
});
|
||||
|
||||
test('formats revision thought', () => {
|
||||
const result = ThoughtFormatter.formatSimple({
|
||||
thought: 'Revised thought',
|
||||
thoughtNumber: 2,
|
||||
totalThoughts: 5,
|
||||
isRevision: true,
|
||||
revisesThought: 1
|
||||
});
|
||||
|
||||
expect(result).toContain('[REVISION of Thought 1]');
|
||||
expect(result).toContain('Revised thought');
|
||||
});
|
||||
|
||||
test('formats branch thought', () => {
|
||||
const result = ThoughtFormatter.formatSimple({
|
||||
thought: 'Branch thought',
|
||||
thoughtNumber: 3,
|
||||
totalThoughts: 5,
|
||||
branchFromThought: 2,
|
||||
branchId: 'a'
|
||||
});
|
||||
|
||||
expect(result).toContain('[BRANCH A from Thought 2]');
|
||||
expect(result).toContain('Branch thought');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Markdown Format', () => {
|
||||
test('formats regular thought', () => {
|
||||
const result = ThoughtFormatter.formatMarkdown({
|
||||
thought: 'Test thought',
|
||||
thoughtNumber: 1,
|
||||
totalThoughts: 5
|
||||
});
|
||||
|
||||
expect(result).toContain('**Thought 1/5**');
|
||||
expect(result).toContain('Test thought');
|
||||
});
|
||||
|
||||
test('formats revision thought', () => {
|
||||
const result = ThoughtFormatter.formatMarkdown({
|
||||
thought: 'Revised thought',
|
||||
thoughtNumber: 2,
|
||||
totalThoughts: 5,
|
||||
isRevision: true,
|
||||
revisesThought: 1
|
||||
});
|
||||
|
||||
expect(result).toContain('**[REVISION of Thought 1]**');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Box Format', () => {
|
||||
test('formats with border', () => {
|
||||
const result = ThoughtFormatter.format({
|
||||
thought: 'Test thought',
|
||||
thoughtNumber: 1,
|
||||
totalThoughts: 5
|
||||
});
|
||||
|
||||
expect(result).toContain('┌');
|
||||
expect(result).toContain('└');
|
||||
expect(result).toContain('💭');
|
||||
expect(result).toContain('Test thought');
|
||||
});
|
||||
|
||||
test('formats revision with emoji', () => {
|
||||
const result = ThoughtFormatter.format({
|
||||
thought: 'Revised',
|
||||
thoughtNumber: 2,
|
||||
totalThoughts: 5,
|
||||
isRevision: true,
|
||||
revisesThought: 1
|
||||
});
|
||||
|
||||
expect(result).toContain('🔄');
|
||||
expect(result).toContain('REVISION');
|
||||
});
|
||||
|
||||
test('formats branch with emoji', () => {
|
||||
const result = ThoughtFormatter.format({
|
||||
thought: 'Branch',
|
||||
thoughtNumber: 3,
|
||||
totalThoughts: 5,
|
||||
branchFromThought: 2,
|
||||
branchId: 'a'
|
||||
});
|
||||
|
||||
expect(result).toContain('🌿');
|
||||
expect(result).toContain('BRANCH');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Text Wrapping', () => {
|
||||
test('wraps long text', () => {
|
||||
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';
|
||||
const wrapped = ThoughtFormatter.wrapText(longText, 50);
|
||||
|
||||
expect(wrapped.length).toBeGreaterThan(1);
|
||||
wrapped.forEach(line => {
|
||||
expect(line.length).toBeLessThanOrEqual(50);
|
||||
});
|
||||
});
|
||||
|
||||
test('does not wrap short text', () => {
|
||||
const shortText = 'Short thought';
|
||||
const wrapped = ThoughtFormatter.wrapText(shortText, 50);
|
||||
|
||||
expect(wrapped.length).toBe(1);
|
||||
expect(wrapped[0]).toBe(shortText);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,215 @@
|
||||
/**
|
||||
* Tests for Sequential Thinking Thought Processor
|
||||
*
|
||||
* Run with: npm test
|
||||
*/
|
||||
|
||||
const { ThoughtProcessor } = require('../scripts/process-thought');
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
// Mock history file for testing
|
||||
const TEST_HISTORY_FILE = path.join(__dirname, '../scripts/.thought-history.json');
|
||||
|
||||
describe('ThoughtProcessor', () => {
|
||||
let processor;
|
||||
|
||||
beforeEach(() => {
|
||||
// Clean up any existing history file
|
||||
if (fs.existsSync(TEST_HISTORY_FILE)) {
|
||||
fs.unlinkSync(TEST_HISTORY_FILE);
|
||||
}
|
||||
processor = new ThoughtProcessor();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
// Clean up after tests
|
||||
if (fs.existsSync(TEST_HISTORY_FILE)) {
|
||||
fs.unlinkSync(TEST_HISTORY_FILE);
|
||||
}
|
||||
});
|
||||
|
||||
describe('Validation', () => {
|
||||
test('rejects missing thought', () => {
|
||||
const result = processor.processThought({
|
||||
thoughtNumber: 1,
|
||||
totalThoughts: 5,
|
||||
nextThoughtNeeded: true
|
||||
});
|
||||
|
||||
expect(result.success).toBe(false);
|
||||
expect(result.errors).toContain('Invalid thought: must be a non-empty string');
|
||||
});
|
||||
|
||||
test('rejects empty thought string', () => {
|
||||
const result = processor.processThought({
|
||||
thought: ' ',
|
||||
thoughtNumber: 1,
|
||||
totalThoughts: 5,
|
||||
nextThoughtNeeded: true
|
||||
});
|
||||
|
||||
expect(result.success).toBe(false);
|
||||
expect(result.errors).toContain('Invalid thought: must be a non-empty string');
|
||||
});
|
||||
|
||||
test('rejects invalid thoughtNumber', () => {
|
||||
const result = processor.processThought({
|
||||
thought: 'Test',
|
||||
thoughtNumber: 0,
|
||||
totalThoughts: 5,
|
||||
nextThoughtNeeded: true
|
||||
});
|
||||
|
||||
expect(result.success).toBe(false);
|
||||
expect(result.errors).toContain('Invalid thoughtNumber: must be a positive number');
|
||||
});
|
||||
|
||||
test('rejects missing nextThoughtNeeded', () => {
|
||||
const result = processor.processThought({
|
||||
thought: 'Test',
|
||||
thoughtNumber: 1,
|
||||
totalThoughts: 5
|
||||
});
|
||||
|
||||
expect(result.success).toBe(false);
|
||||
expect(result.errors).toContain('Invalid nextThoughtNeeded: must be a boolean');
|
||||
});
|
||||
|
||||
test('accepts valid thought', () => {
|
||||
const result = processor.processThought({
|
||||
thought: 'Valid thought',
|
||||
thoughtNumber: 1,
|
||||
totalThoughts: 5,
|
||||
nextThoughtNeeded: true
|
||||
});
|
||||
|
||||
expect(result.success).toBe(true);
|
||||
expect(result.thoughtNumber).toBe(1);
|
||||
expect(result.totalThoughts).toBe(5);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Thought Processing', () => {
|
||||
test('tracks thought history', () => {
|
||||
processor.processThought({
|
||||
thought: 'First thought',
|
||||
thoughtNumber: 1,
|
||||
totalThoughts: 3,
|
||||
nextThoughtNeeded: true
|
||||
});
|
||||
|
||||
processor.processThought({
|
||||
thought: 'Second thought',
|
||||
thoughtNumber: 2,
|
||||
totalThoughts: 3,
|
||||
nextThoughtNeeded: true
|
||||
});
|
||||
|
||||
const result = processor.processThought({
|
||||
thought: 'Third thought',
|
||||
thoughtNumber: 3,
|
||||
totalThoughts: 3,
|
||||
nextThoughtNeeded: false
|
||||
});
|
||||
|
||||
expect(result.thoughtHistoryLength).toBe(3);
|
||||
});
|
||||
|
||||
test('auto-adjusts totalThoughts when exceeded', () => {
|
||||
const result = processor.processThought({
|
||||
thought: 'Thought 5',
|
||||
thoughtNumber: 5,
|
||||
totalThoughts: 3,
|
||||
nextThoughtNeeded: true
|
||||
});
|
||||
|
||||
expect(result.totalThoughts).toBe(5);
|
||||
});
|
||||
|
||||
test('tracks revisions', () => {
|
||||
processor.processThought({
|
||||
thought: 'Original thought',
|
||||
thoughtNumber: 1,
|
||||
totalThoughts: 5,
|
||||
nextThoughtNeeded: true
|
||||
});
|
||||
|
||||
const result = processor.processThought({
|
||||
thought: 'Revised thought',
|
||||
thoughtNumber: 2,
|
||||
totalThoughts: 5,
|
||||
nextThoughtNeeded: true,
|
||||
isRevision: true,
|
||||
revisesThought: 1
|
||||
});
|
||||
|
||||
expect(result.success).toBe(true);
|
||||
expect(result.thoughtHistoryLength).toBe(2);
|
||||
});
|
||||
|
||||
test('tracks branches', () => {
|
||||
processor.processThought({
|
||||
thought: 'Main thought',
|
||||
thoughtNumber: 1,
|
||||
totalThoughts: 5,
|
||||
nextThoughtNeeded: true
|
||||
});
|
||||
|
||||
processor.processThought({
|
||||
thought: 'Branch A',
|
||||
thoughtNumber: 2,
|
||||
totalThoughts: 5,
|
||||
nextThoughtNeeded: true,
|
||||
branchFromThought: 1,
|
||||
branchId: 'branch-a'
|
||||
});
|
||||
|
||||
const result = processor.processThought({
|
||||
thought: 'Branch B',
|
||||
thoughtNumber: 2,
|
||||
totalThoughts: 5,
|
||||
nextThoughtNeeded: false,
|
||||
branchFromThought: 1,
|
||||
branchId: 'branch-b'
|
||||
});
|
||||
|
||||
expect(result.branches).toContain('branch-a');
|
||||
expect(result.branches).toContain('branch-b');
|
||||
expect(result.branches.length).toBe(2);
|
||||
});
|
||||
});
|
||||
|
||||
describe('History Management', () => {
|
||||
test('resets history', () => {
|
||||
processor.processThought({
|
||||
thought: 'First thought',
|
||||
thoughtNumber: 1,
|
||||
totalThoughts: 5,
|
||||
nextThoughtNeeded: true
|
||||
});
|
||||
|
||||
processor.resetHistory();
|
||||
|
||||
const history = processor.getHistory();
|
||||
expect(history.totalThoughts).toBe(0);
|
||||
expect(history.thoughts.length).toBe(0);
|
||||
});
|
||||
|
||||
test('persists and loads history', () => {
|
||||
processor.processThought({
|
||||
thought: 'Persisted thought',
|
||||
thoughtNumber: 1,
|
||||
totalThoughts: 5,
|
||||
nextThoughtNeeded: true
|
||||
});
|
||||
|
||||
// Create new processor instance (should load from file)
|
||||
const newProcessor = new ThoughtProcessor();
|
||||
const history = newProcessor.getHistory();
|
||||
|
||||
expect(history.totalThoughts).toBe(1);
|
||||
expect(history.thoughts[0].thought).toBe('Persisted thought');
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user