🚀. Socket Launch Week Day 2:Introducing Manifest Alerts.Learn more
Sign In

clawfix

Package Overview
Dependencies
Maintainers
1
Versions
7
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

clawfix - npm Package Compare versions

Comparing version
0.6.1
to
0.7.0
+127
-47
bin/clawfix.js

@@ -20,3 +20,3 @@ #!/usr/bin/env node

const API_URL = process.env.CLAWFIX_API || 'https://clawfix.dev';
const VERSION = '0.6.0';
const VERSION = '0.7.0';

@@ -29,2 +29,3 @@ // --- Flags ---

const SHOW_HELP = args.includes('--help') || args.includes('-h');
const SHOW_VERSION = args.includes('--version') || args.includes('-v') || args.includes('-V');
const ONE_SHOT = args.includes('--scan') || args.includes('--no-interactive') || DRY_RUN;

@@ -635,2 +636,9 @@

// --- Concurrency guard ---
let busy = false;
// --- Paste detection: batch rapid lines into one message ---
let pasteBuffer = [];
let pasteTimer = null;
const PASTE_DELAY_MS = 80; // lines arriving within 80ms = paste
// --- Clear screen and show header ---

@@ -688,10 +696,5 @@ process.stdout.write('\x1b[2J\x1b[H');

rl.prompt();
rl.on('line', async (line) => {
const input = line.trim();
// --- Process a single input (command or chat) ---
async function handleInput(input) {
if (!input) {
// Empty enter → show issues summary
renderIssues(issues, serverIssues);
rl.prompt();

@@ -728,6 +731,7 @@ return;

try {
const payload = { ...diagnostic, _localIssues: issues.map(i => ({ severity: i.severity, text: i.text })) };
const resp = await fetch(`${API_URL}/api/diagnose`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(diagnostic),
body: JSON.stringify(payload),
});

@@ -859,5 +863,48 @@ if (resp.ok) {

console.log('');
await streamChat(input, diagnosticId, conversationId, rl);
busy = true;
try {
await streamChat(input, diagnosticId, conversationId, rl);
} finally {
busy = false;
}
console.log('');
rl.prompt();
}
// --- Flush paste buffer as a single combined message ---
function flushPasteBuffer() {
pasteTimer = null;
if (pasteBuffer.length === 0) return;
// Combine all buffered lines into one message
const combined = pasteBuffer.join('\n').trim();
pasteBuffer = [];
if (!combined) {
rl.prompt();
return;
}
// If the combined paste looks like a single command, handle as command
const firstLine = combined.split('\n')[0].trim();
if (combined.split('\n').length === 1 || /^(exit|quit|q|help|\?|scan|rescan|issues?|status|fix\s+\d+|apply\s+\d+)$/i.test(firstLine)) {
handleInput(firstLine);
} else {
// Multi-line paste → send as one chat message
handleInput(combined);
}
}
rl.prompt();
rl.on('line', (line) => {
const input = line.trim();
// If busy streaming, silently drop input
if (busy) return;
// Paste detection: buffer rapid lines and flush after a delay
pasteBuffer.push(input);
if (pasteTimer) clearTimeout(pasteTimer);
pasteTimer = setTimeout(flushPasteBuffer, PASTE_DELAY_MS);
});

@@ -1008,53 +1055,80 @@

// SSE streaming
// SSE streaming — collect full response, then render
// Buffer approach: collect content chunks, flush periodically for progressive display
process.stdout.write('\r\x1b[K');
process.stdout.write(' ');
const reader = resp.body.getReader();
const decoder = new TextDecoder();
let buffer = '';
let sseBuffer = '';
let contentBuffer = ''; // accumulate content between flushes
let col = 2; // Current column (2 for indent)
let started = false; // whether we've written any content yet
let hadError = false;
while (true) {
const { done, value } = await reader.read();
if (done) break;
// Flush accumulated content to screen
function flushContent() {
if (!contentBuffer) return;
if (!started) {
process.stdout.write(' ');
started = true;
}
for (const ch of contentBuffer) {
if (ch === '\n') {
process.stdout.write('\n ');
col = 2;
} else {
process.stdout.write(ch);
col++;
if (col > 76 && ch === ' ') {
process.stdout.write('\n ');
col = 2;
}
}
}
contentBuffer = '';
}
buffer += decoder.decode(value, { stream: true });
const lines = buffer.split('\n');
buffer = lines.pop() || '';
// Set up periodic flush (every 50ms) for smooth progressive rendering
const flushInterval = setInterval(flushContent, 50);
for (const line of lines) {
const trimmed = line.trim();
if (!trimmed || !trimmed.startsWith('data: ')) continue;
try {
while (true) {
const { done, value } = await reader.read();
if (done) break;
const data = trimmed.slice(6);
if (data === '[DONE]') break;
sseBuffer += decoder.decode(value, { stream: true });
const lines = sseBuffer.split('\n');
sseBuffer = lines.pop() || '';
try {
const parsed = JSON.parse(data);
if (parsed.error) {
process.stdout.write(c.red(parsed.error));
break;
}
if (parsed.content) {
// Word-wrap at ~76 cols
for (const ch of parsed.content) {
if (ch === '\n') {
process.stdout.write('\n ');
col = 2;
} else {
process.stdout.write(ch);
col++;
if (col > 76 && ch === ' ') {
process.stdout.write('\n ');
col = 2;
}
}
for (const line of lines) {
const trimmed = line.trim();
if (!trimmed || !trimmed.startsWith('data: ')) continue;
const data = trimmed.slice(6);
if (data === '[DONE]') break;
try {
const parsed = JSON.parse(data);
if (parsed.error) {
flushContent();
process.stdout.write(c.red(parsed.error));
hadError = true;
break;
}
}
} catch {}
if (parsed.content) {
contentBuffer += parsed.content;
}
} catch {}
}
if (hadError) break;
}
} finally {
clearInterval(flushInterval);
}
process.stdout.write('\n');
// Final flush of any remaining content
flushContent();
if (started || hadError) {
process.stdout.write('\n');
}
} catch (err) {

@@ -1100,2 +1174,7 @@ process.stdout.write('\r\x1b[K');

async function main() {
if (SHOW_VERSION) {
console.log(`clawfix v${VERSION}`);
return;
}
if (SHOW_HELP) {

@@ -1116,2 +1195,3 @@ console.log(`

--yes, -y Skip confirmation prompt and send automatically
--version, -v Show version
--help, -h Show this help message

@@ -1118,0 +1198,0 @@

{
"name": "clawfix",
"version": "0.6.1",
"version": "0.7.0",
"description": "AI-powered diagnostic and repair for OpenClaw installations",

@@ -5,0 +5,0 @@ "bin": {