Files
2026-04-12 01:06:31 +07:00

160 lines
4.7 KiB
JavaScript
Executable File

#!/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 };