Big News: Socket raises $60M Series C at a $1B valuation to secure software supply chains for AI-driven development.Announcement
Sign In

cloudctx

Package Overview
Dependencies
Maintainers
1
Versions
13
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

cloudctx - npm Package Compare versions

Comparing version
0.1.4
to
0.1.5
+23
-3
bin/cloudctx.js

@@ -494,8 +494,15 @@ #!/usr/bin/env node

if (bool) {
installStatusline();
const result = installStatusline();
console.log(` ✓ statusline = true — wired into ~/.claude/settings.json`);
if (result.wrapped) {
console.log(` Existing statusLine detected — wrapping it (you'll see both).`);
}
console.log(` Open a new Claude Code session to see it.`);
} else {
uninstallStatusline();
console.log(` ✓ statusline = false — removed from ~/.claude/settings.json`);
const result = uninstallStatusline();
if (result.restored) {
console.log(` ✓ statusline = false — your original statusLine restored.`);
} else {
console.log(` ✓ statusline = false — removed from ~/.claude/settings.json`);
}
}

@@ -521,3 +528,16 @@ } else {

function registerRawModeExitGuard() {
process.once('exit', () => {
try { if (process.stdin.isTTY) process.stdin.setRawMode(false); } catch {}
});
for (const sig of ['SIGINT', 'SIGTERM', 'SIGHUP']) {
process.once(sig, () => {
try { if (process.stdin.isTTY) process.stdin.setRawMode(false); } catch {}
process.exit(130);
});
}
}
async function pickColorInteractive() {
registerRawModeExitGuard();
const colors = Object.keys(STATUSLINE_COLORS);

@@ -524,0 +544,0 @@ const currentColor = getConfigValue('statusline_color') || 'cyan';

+1
-1

@@ -42,3 +42,3 @@ import { existsSync, readFileSync, writeFileSync, mkdirSync, readdirSync } from 'fs';

try {
input = readFileSync('/dev/stdin', 'utf-8');
input = readFileSync(0, 'utf-8');
} catch {

@@ -45,0 +45,0 @@ console.log(`Reminder: ${REMINDER}`);

@@ -5,2 +5,3 @@ import { readFileSync, writeFileSync, existsSync, mkdirSync, unlinkSync } from 'fs';

import { execSync } from 'child_process';
import { getConfigValue, setConfig, unsetConfig } from './config.js';

@@ -97,2 +98,7 @@ const CLAUDE_DIR = join(homedir(), '.claude');

function isCloudctxStatusLine(entry) {
const cmd = entry?.command || '';
return cmd.includes('cloudctx') && /\bstatusline\b/.test(cmd);
}
export function installStatusline() {

@@ -104,2 +110,12 @@ const binPath = getCloudctxBinPath();

}
// If there's an existing non-cloudctx statusLine, preserve it so our
// subcommand can wrap it (toolbelt mode).
const existing = settings.statusLine;
let wrapped = false;
if (existing && !isCloudctxStatusLine(existing)) {
setConfig('wrapped_statusline', existing);
wrapped = true;
}
settings.statusLine = {

@@ -110,14 +126,25 @@ type: 'command',

writeFileSync(SETTINGS_FILE, JSON.stringify(settings, null, 2) + '\n');
return true;
return { installed: true, wrapped };
}
export function uninstallStatusline() {
if (!existsSync(SETTINGS_FILE)) return false;
if (!existsSync(SETTINGS_FILE)) return { removed: false, restored: false };
let settings;
try { settings = JSON.parse(readFileSync(SETTINGS_FILE, 'utf-8')); } catch { return false; }
const cmd = settings.statusLine?.command || '';
if (!cmd.includes('cloudctx') || !cmd.includes('statusline')) return false;
delete settings.statusLine;
try { settings = JSON.parse(readFileSync(SETTINGS_FILE, 'utf-8')); } catch { return { removed: false, restored: false }; }
const currentIsOurs = isCloudctxStatusLine(settings.statusLine);
if (!currentIsOurs) return { removed: false, restored: false };
// Restore whatever we wrapped, if anything.
const wrapped = getConfigValue('wrapped_statusline');
let restored = false;
if (wrapped && wrapped.command) {
settings.statusLine = wrapped;
unsetConfig('wrapped_statusline');
restored = true;
} else {
delete settings.statusLine;
}
writeFileSync(SETTINGS_FILE, JSON.stringify(settings, null, 2) + '\n');
return true;
return { removed: true, restored };
}

@@ -124,0 +151,0 @@

@@ -202,2 +202,12 @@ import { getReadonlyDb, getDb, dbExists, migrate } from './db.js';

process.once('exit', () => {
try { if (process.stdin.isTTY) process.stdin.setRawMode(false); } catch {}
});
for (const sig of ['SIGINT', 'SIGTERM', 'SIGHUP']) {
process.once(sig, () => {
try { if (process.stdin.isTTY) process.stdin.setRawMode(false); } catch {}
process.exit(130);
});
}
process.stdin.setRawMode(true);

@@ -204,0 +214,0 @@ process.stdin.resume();

import { readFileSync } from 'fs';
import { execSync } from 'child_process';
import { getReadonlyDb, dbExists } from './db.js';

@@ -6,14 +7,10 @@ import { getConfigValue, STATUSLINE_COLORS } from './config.js';

export function runStatusline() {
let input = '';
let sessionId = '';
let ourPrefix = '';
try {
if (!dbExists()) {
process.exit(0);
}
try { input = readFileSync(0, 'utf-8'); } catch {}
let input = '';
try {
input = readFileSync('/dev/stdin', 'utf-8');
} catch {}
let sessionId = '';
try {
const parsed = JSON.parse(input);

@@ -23,20 +20,40 @@ sessionId = parsed.session_id || parsed.sessionId || '';

if (!sessionId) process.exit(0);
if (sessionId && dbExists()) {
try {
const db = getReadonlyDb();
const row = db.prepare(
'SELECT name FROM saved_threads WHERE session_id = ? ORDER BY saved_at DESC LIMIT 1'
).get(sessionId);
db.close();
if (row && row.name) {
const colorName = getConfigValue('statusline_color') || 'cyan';
const code = STATUSLINE_COLORS[colorName] ?? '';
const open = code ? `\x1b[1;${code}m` : `\x1b[1m`;
ourPrefix = `${open}📌 ${row.name}\x1b[0m`;
}
} catch {}
}
const db = getReadonlyDb();
const row = db.prepare(
'SELECT name FROM saved_threads WHERE session_id = ? ORDER BY saved_at DESC LIMIT 1'
).get(sessionId);
db.close();
const wrapped = getConfigValue('wrapped_statusline');
let wrappedOutput = '';
if (wrapped && wrapped.command) {
try {
wrappedOutput = execSync(wrapped.command, {
input,
timeout: 800,
encoding: 'utf-8',
stdio: ['pipe', 'pipe', 'ignore'],
shell: true,
}).replace(/\r?\n+$/g, '');
} catch {
// wrapped command failed or timed out — fall back to just our prefix
}
}
if (row && row.name) {
const colorName = getConfigValue('statusline_color') || 'cyan';
const code = STATUSLINE_COLORS[colorName] ?? '';
const prefix = code ? `\x1b[1;${code}m` : `\x1b[1m`;
process.stdout.write(`${prefix}📌 ${row.name}\x1b[0m`);
}
const parts = [ourPrefix, wrappedOutput].filter(s => s && s.length);
if (parts.length) process.stdout.write(parts.join(' · '));
} catch {
// silent — statusline should never crash CC
// never crash Claude Code's status line
}
process.exit(0);
}
{
"name": "cloudctx",
"version": "0.1.4",
"version": "0.1.5",
"description": "Persistent memory for Claude Code. One command, full recall.",

@@ -5,0 +5,0 @@ "type": "module",