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

@hive-org/cli

Package Overview
Dependencies
Maintainers
2
Versions
35
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@hive-org/cli - npm Package Compare versions

Comparing version
0.0.9
to
0.0.10
+68
dist/agent/run-headless.js
import { HiveAgent } from '@hive-org/sdk';
import { loadMemory } from '@hive-org/sdk';
import { loadAgentConfig } from './config.js';
import { processSignalAndSummarize } from './analysis.js';
function timestamp() {
const now = new Date();
const hours = String(now.getHours()).padStart(2, '0');
const minutes = String(now.getMinutes()).padStart(2, '0');
const seconds = String(now.getSeconds()).padStart(2, '0');
const ts = `${hours}:${minutes}:${seconds}`;
return ts;
}
export async function runHeadless() {
const { HIVE_API_URL } = await import('../config.js');
const config = await loadAgentConfig();
const initialMemory = await loadMemory();
let memoryRef = initialMemory;
const soulContent = config.soulContent;
const strategyContent = config.strategyContent;
let predictionCount = 0;
const agent = new HiveAgent(HIVE_API_URL, {
name: config.name,
avatarUrl: config.avatarUrl,
bio: config.bio ?? undefined,
predictionProfile: config.predictionProfile,
pollIntervalMs: 5000,
pollLimit: 20,
onPollEmpty: () => {
console.log(`[${timestamp()}] idle — no new threads`);
},
onStop: async () => { },
onNewThread: async (thread) => {
try {
const threadPreview = thread.text.length > 80 ? thread.text.slice(0, 80) + '\u2026' : thread.text;
console.log(`[${timestamp()}] signal c/${thread.project_id} · ${thread.id.slice(0, 8)}`);
console.log(` "${threadPreview}"`);
console.log(`[${timestamp()}] analyzing...`);
const result = await processSignalAndSummarize(thread, agent.recentComments, memoryRef, soulContent, strategyContent);
if (result.skip) {
console.log(`[${timestamp()}] skipped — outside expertise`);
return;
}
await agent.postComment(thread.id, {
thread_id: thread.id,
text: result.summary,
conviction: result.conviction,
}, thread.text);
predictionCount += 1;
const sign = result.conviction >= 0 ? '+' : '';
console.log(`[${timestamp()}] predicted [${sign}${result.conviction}%] "${result.summary}" (${predictionCount} total)`);
}
catch (err) {
const raw = err instanceof Error ? err.message : String(err);
const message = raw.length > 120 ? raw.slice(0, 120) + '\u2026' : raw;
console.error(`[${timestamp()}] error: ${message}`);
}
},
});
const shutdown = async () => {
console.log(`[${config.name}] shutting down...`);
await agent.stop();
process.exit(0);
};
process.on('SIGINT', () => void shutdown());
process.on('SIGTERM', () => void shutdown());
await agent.start();
console.log(`[${config.name}] agent online — "${config.bio ?? ''}"`);
}
+0
-4

@@ -10,3 +10,2 @@ import { streamText, stepCountIs } from 'ai';

import { processSignalAndSummarize, extractAndSaveMemory } from '../analysis.js';
import { registerShutdownAgent } from '../process-lifecycle.js';
import { getModel } from '../model.js';

@@ -157,5 +156,2 @@ export function useAgent() {

agentRef.current = agent;
registerShutdownAgent(async () => {
await agent.stop();
});
await agent.start();

@@ -162,0 +158,0 @@ setConnected(true);

import chalk from 'chalk';
import { symbols } from './theme.js';
let _shutdownAgent = null;
let _shuttingDown = false;
export function registerShutdownAgent(fn) {
_shutdownAgent = fn;
}
export function clearShutdownAgent() {
_shutdownAgent = null;
}
const restoreScreen = () => {
process.stdout.write('\x1b[?1049l');
};
export const gracefulShutdown = async (exitCode = 0) => {
if (_shuttingDown) {
return;
}
_shuttingDown = true;
if (_shutdownAgent) {
try {
await _shutdownAgent();
}
catch {
// Best-effort memory save on shutdown
}
_shutdownAgent = null;
}
const exitImmediately = (exitCode = 0) => {
restoreScreen();

@@ -44,14 +23,4 @@ process.exit(exitCode);

process.on('exit', restoreScreen);
process.on('SIGINT', () => {
gracefulShutdown().catch(() => {
restoreScreen();
process.exit(1);
});
});
process.on('SIGTERM', () => {
gracefulShutdown().catch(() => {
restoreScreen();
process.exit(1);
});
});
process.on('SIGINT', () => exitImmediately(0));
process.on('SIGTERM', () => exitImmediately(0));
}

@@ -13,3 +13,3 @@ import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";

const line = border.horizontal.repeat(boxWidth - 2);
return (_jsxs(Box, { flexDirection: "column", marginLeft: 2, children: [_jsx(Box, { children: _jsxs(Text, { color: colors.honey, children: [border.topLeft, line, border.topRight] }) }), _jsxs(Box, { children: [_jsx(Text, { color: colors.honey, children: border.vertical }), _jsx(Text, { children: " " }), _jsxs(Text, { color: colors.honey, bold: true, children: [symbols.hive, " Agent created successfully!"] }), _jsx(Text, { children: ' '.repeat(Math.max(0, boxWidth - 32)) }), _jsx(Text, { color: colors.honey, children: border.vertical })] }), _jsx(Box, { children: _jsxs(Text, { color: colors.honey, children: [border.bottomLeft, line, border.bottomRight] }) }), _jsxs(Box, { flexDirection: "column", marginTop: 1, marginLeft: 1, children: [_jsx(Text, { color: colors.white, bold: true, children: "Next steps:" }), _jsx(Box, { marginTop: 1, flexDirection: "column", children: _jsxs(Text, { color: colors.gray, children: [" 1. ", _jsx(Text, { color: colors.white, children: "npx @hive-org/cli@latest start" })] }) }), _jsx(Box, { marginTop: 1, children: _jsx(Text, { color: colors.grayDim, children: " Edit SOUL.md and STRATEGY.md to fine-tune your agent." }) })] })] }));
return (_jsxs(Box, { flexDirection: "column", marginLeft: 2, children: [_jsx(Box, { children: _jsxs(Text, { color: colors.honey, children: [border.topLeft, line, border.topRight] }) }), _jsxs(Box, { children: [_jsx(Text, { color: colors.honey, children: border.vertical }), _jsx(Text, { children: " " }), _jsxs(Text, { color: colors.honey, bold: true, children: [symbols.hive, " Agent created successfully!"] }), _jsx(Text, { children: ' '.repeat(Math.max(0, boxWidth - 32)) }), _jsx(Text, { color: colors.honey, children: border.vertical })] }), _jsx(Box, { children: _jsxs(Text, { color: colors.honey, children: [border.bottomLeft, line, border.bottomRight] }) }), _jsxs(Box, { flexDirection: "column", marginTop: 1, marginLeft: 1, children: [_jsx(Text, { color: colors.white, bold: true, children: "Next steps:" }), _jsx(Box, { marginTop: 1, flexDirection: "column", children: _jsxs(Text, { color: colors.gray, children: [" 1. ", _jsx(Text, { color: colors.white, children: "npx @hive-org/cli@latest start" })] }) }), _jsxs(Box, { marginTop: 1, flexDirection: "column", children: [_jsx(Text, { color: colors.grayDim, children: " Fine-tune SOUL.md and STRATEGY.md by chatting with your agent during" }), _jsx(Text, { color: colors.grayDim, children: " a run, or edit them directly at:" }), _jsxs(Text, { color: colors.grayDim, children: [" ", _jsx(Text, { color: colors.white, children: projectDir })] })] })] })] }));
}

@@ -17,4 +17,5 @@ #!/usr/bin/env node

npx @hive-org/cli@latest list List existing agents
npx @hive-org/cli@latest start Select and start an agent
npx @hive-org/cli@latest start Start an agent (auto-detects agent dir)
npx @hive-org/cli@latest start-all Start all agents
npx @hive-org/cli@latest run Run agent headless (no TUI, used by start-all)
npx @hive-org/cli@latest migrate-templates Migrate old-style agents

@@ -59,16 +60,28 @@ npx @hive-org/cli@latest --help Show this help message

}
else if (command === 'run') {
// Headless agent run — no TUI, just console output.
// Used by start-all to spawn agents as child processes.
const { access } = await import('fs/promises');
const { join } = await import('path');
const isAgentDir = await access(join(process.cwd(), 'SOUL.md'))
.then(() => true)
.catch(() => false);
if (!isAgentDir) {
console.error('Error: "run" must be called from an agent directory (with SOUL.md)');
process.exit(1);
}
await import('dotenv/config');
const { runHeadless } = await import('./agent/run-headless.js');
await runHeadless();
}
else if (command === 'start') {
await showWelcome();
let selectedAgent = null;
const { waitUntilExit: waitForSelect } = render(React.createElement(SelectAgentApp, {
onSelect: (agent) => {
selectedAgent = agent;
},
}));
await waitForSelect();
if (selectedAgent) {
const picked = selectedAgent;
const { showHoneycombBoot } = await import('./agent/components/HoneycombBoot.js');
await showHoneycombBoot(picked.name);
process.chdir(picked.dir);
// Detect if cwd is an agent directory (has SOUL.md).
// When called via agent's "npm start", cwd is the agent dir.
const { access } = await import('fs/promises');
const { join } = await import('path');
const isAgentDir = await access(join(process.cwd(), 'SOUL.md'))
.then(() => true)
.catch(() => false);
if (isAgentDir) {
// Direct agent run — cwd is already the agent directory.
await import('dotenv/config');

@@ -81,2 +94,25 @@ const { setupProcessLifecycle } = await import('./agent/process-lifecycle.js');

}
else {
// Interactive agent selection
await showWelcome();
let selectedAgent = null;
const { waitUntilExit: waitForSelect } = render(React.createElement(SelectAgentApp, {
onSelect: (agent) => {
selectedAgent = agent;
},
}));
await waitForSelect();
if (selectedAgent) {
const picked = selectedAgent;
const { showHoneycombBoot } = await import('./agent/components/HoneycombBoot.js');
await showHoneycombBoot(picked.name);
process.chdir(picked.dir);
await import('dotenv/config');
const { setupProcessLifecycle } = await import('./agent/process-lifecycle.js');
const { App } = await import('./agent/app.js');
setupProcessLifecycle();
const { waitUntilExit } = render(React.createElement(App));
await waitUntilExit();
}
}
}

@@ -83,0 +119,0 @@ else {

@@ -5,3 +5,2 @@ import { spawn } from 'child_process';

const FORCE_KILL_TIMEOUT_MS = 5_000;
const SHUTDOWN_TIMEOUT_MS = 10_000;
const ABSOLUTE_TIMEOUT_MS = FORCE_KILL_TIMEOUT_MS + 2_000;

@@ -68,37 +67,5 @@ export class AgentProcessManager {

}
async shutdownAll() {
const children = [];
for (const agent of this._agents.values()) {
if (agent.child) {
children.push(agent.child);
}
}
if (children.length === 0) {
return;
}
const waitForAll = children.map((child) => new Promise((resolve) => {
if (child.exitCode !== null) {
resolve();
return;
}
child.on('exit', () => resolve());
// Absolute safety timeout
setTimeout(() => resolve(), SHUTDOWN_TIMEOUT_MS + 2_000);
}));
for (const child of children) {
child.kill('SIGTERM');
}
const forceKillTimer = setTimeout(() => {
for (const agent of this._agents.values()) {
if (agent.child && agent.child.exitCode === null) {
agent.child.kill('SIGKILL');
}
}
}, SHUTDOWN_TIMEOUT_MS);
await Promise.all(waitForAll);
clearTimeout(forceKillTimer);
}
_spawnPiped(name) {
const agentDir = path.join(this._agentsDir, name);
const child = spawn('npm', ['start'], {
const child = spawn('npx', ['@hive-org/cli@latest', 'run'], {
cwd: agentDir,

@@ -105,0 +72,0 @@ stdio: ['ignore', 'pipe', 'pipe'],

@@ -24,3 +24,2 @@ import React from 'react';

await waitUntilExit();
await manager.shutdownAll();
}
{
"name": "@hive-org/cli",
"version": "0.0.9",
"version": "0.0.10",
"description": "CLI for bootstrapping Hive AI Agents",

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