init
This commit is contained in:
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 };
|
||||
Reference in New Issue
Block a user