neohive 6.3.0 → 6.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +110 -6
- package/cli.js +391 -64
- package/dashboard.html +107 -21
- package/dashboard.js +36 -5
- package/package.json +1 -1
- package/server.js +185 -147
- package/tools/governance.js +28 -6
- package/tools/messaging.js +2 -0
- package/tools/safety.js +3 -3
- package/tools/tasks.js +5 -5
package/cli.js
CHANGED
|
@@ -46,6 +46,8 @@ function printUsage() {
|
|
|
46
46
|
npx neohive doctor Diagnostic health check
|
|
47
47
|
npx neohive templates List available team templates
|
|
48
48
|
npx neohive reset --force Clear all data (auto-archives first)
|
|
49
|
+
npx neohive hooks Install listen-enforcement hooks into .claude/settings.json
|
|
50
|
+
npx neohive skills Install neohive skills & agents for all detected IDEs
|
|
49
51
|
npx neohive uninstall Remove from all CLI configs
|
|
50
52
|
npx neohive help Show this help
|
|
51
53
|
|
|
@@ -133,9 +135,119 @@ function setupClaude(serverPath, cwd) {
|
|
|
133
135
|
|
|
134
136
|
fs.writeFileSync(mcpConfigPath, JSON.stringify(mcpConfig, null, 2) + '\n');
|
|
135
137
|
console.log(' [ok] Claude Code: .mcp.json updated');
|
|
138
|
+
installSkillsForClaude(cwd);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// ─── installSkills ────────────────────────────────────────────────────────────
|
|
142
|
+
// Installs neohive skills, agents, and commands into the appropriate IDE dirs.
|
|
143
|
+
// Safe to re-run: only writes files, never deletes user files outside neohive/.
|
|
144
|
+
|
|
145
|
+
const SKILLS_SRC = path.join(__dirname, 'neohive-plugin', 'skills');
|
|
146
|
+
const AGENTS_SRC = path.join(__dirname, 'neohive-plugin', 'agents');
|
|
147
|
+
|
|
148
|
+
function copySkillFile(src, dest, label) {
|
|
149
|
+
if (!fs.existsSync(src)) return;
|
|
150
|
+
const existing = fs.existsSync(dest) ? fs.readFileSync(dest, 'utf8') : null;
|
|
151
|
+
const incoming = fs.readFileSync(src, 'utf8');
|
|
152
|
+
if (existing === incoming) {
|
|
153
|
+
console.log(` [skip] ${label} (unchanged)`);
|
|
154
|
+
} else {
|
|
155
|
+
fs.mkdirSync(path.dirname(dest), { recursive: true });
|
|
156
|
+
fs.writeFileSync(dest, incoming);
|
|
157
|
+
console.log(` [ok] ${label}`);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
function installSkillsForClaude(cwd) {
|
|
162
|
+
// Project-level skills: .claude/skills/neohive/<skill>/SKILL.md
|
|
163
|
+
const skillsDir = path.join(cwd, '.claude', 'skills', 'neohive');
|
|
164
|
+
const agentsDir = path.join(cwd, '.claude', 'skills', 'neohive', 'agents');
|
|
165
|
+
|
|
166
|
+
if (!fs.existsSync(SKILLS_SRC)) {
|
|
167
|
+
console.log(' [skip] Claude skills: source not found (neohive-plugin/skills)');
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
for (const skill of fs.readdirSync(SKILLS_SRC)) {
|
|
172
|
+
const src = path.join(SKILLS_SRC, skill, 'SKILL.md');
|
|
173
|
+
const dest = path.join(skillsDir, skill, 'SKILL.md');
|
|
174
|
+
copySkillFile(src, dest, `Claude skill: ${skill}`);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
if (fs.existsSync(AGENTS_SRC)) {
|
|
178
|
+
for (const agent of fs.readdirSync(AGENTS_SRC)) {
|
|
179
|
+
const src = path.join(AGENTS_SRC, agent);
|
|
180
|
+
const dest = path.join(agentsDir, agent);
|
|
181
|
+
copySkillFile(src, dest, `Claude agent: ${agent}`);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
function installSkillsForCursor(cwd) {
|
|
187
|
+
// .cursor/skills/neohive/<skill>/SKILL.md
|
|
188
|
+
// .cursor/agents/<agent>.md
|
|
189
|
+
// .cursor/commands/<command>.md (derived from skills)
|
|
190
|
+
if (!fs.existsSync(SKILLS_SRC)) {
|
|
191
|
+
console.log(' [skip] Cursor skills: source not found (neohive-plugin/skills)');
|
|
192
|
+
return;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
for (const skill of fs.readdirSync(SKILLS_SRC)) {
|
|
196
|
+
const src = path.join(SKILLS_SRC, skill, 'SKILL.md');
|
|
197
|
+
const dest = path.join(cwd, '.cursor', 'skills', 'neohive', skill, 'SKILL.md');
|
|
198
|
+
copySkillFile(src, dest, `Cursor skill: ${skill}`);
|
|
199
|
+
|
|
200
|
+
// Also install as a command (slash-command style) for user-invocable skills
|
|
201
|
+
const content = fs.existsSync(src) ? fs.readFileSync(src, 'utf8') : '';
|
|
202
|
+
if (content.includes('user-invocable: true') || !content.includes('user-invocable: false')) {
|
|
203
|
+
const cmdDest = path.join(cwd, '.cursor', 'commands', `neohive-${skill}.md`);
|
|
204
|
+
copySkillFile(src, cmdDest, `Cursor command: neohive-${skill}`);
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
if (fs.existsSync(AGENTS_SRC)) {
|
|
209
|
+
for (const agent of fs.readdirSync(AGENTS_SRC)) {
|
|
210
|
+
const src = path.join(AGENTS_SRC, agent);
|
|
211
|
+
const dest = path.join(cwd, '.cursor', 'agents', `neohive-${agent}`);
|
|
212
|
+
copySkillFile(src, dest, `Cursor agent: neohive-${agent}`);
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
function installSkillsForAntigravity(cwd) {
|
|
218
|
+
// .agent/skills/neohive/<skill>/SKILL.md (already partially done in setupAntigravity)
|
|
219
|
+
if (!fs.existsSync(SKILLS_SRC)) {
|
|
220
|
+
console.log(' [skip] Antigravity skills: source not found (neohive-plugin/skills)');
|
|
221
|
+
return;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
for (const skill of fs.readdirSync(SKILLS_SRC)) {
|
|
225
|
+
const src = path.join(SKILLS_SRC, skill, 'SKILL.md');
|
|
226
|
+
const dest = path.join(cwd, '.agent', 'skills', 'neohive', skill, 'SKILL.md');
|
|
227
|
+
copySkillFile(src, dest, `Antigravity skill: ${skill}`);
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
if (fs.existsSync(AGENTS_SRC)) {
|
|
231
|
+
for (const agent of fs.readdirSync(AGENTS_SRC)) {
|
|
232
|
+
const src = path.join(AGENTS_SRC, agent);
|
|
233
|
+
const dest = path.join(cwd, '.agent', 'agents', `neohive-${agent}`);
|
|
234
|
+
copySkillFile(src, dest, `Antigravity agent: neohive-${agent}`);
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
function installSkills(targets, cwd) {
|
|
240
|
+
console.log('');
|
|
241
|
+
console.log(' Installing Neohive skills & agents...');
|
|
242
|
+
for (const target of targets) {
|
|
243
|
+
switch (target) {
|
|
244
|
+
case 'claude': installSkillsForClaude(cwd); break;
|
|
245
|
+
case 'cursor': installSkillsForCursor(cwd); break;
|
|
246
|
+
case 'antigravity': installSkillsForAntigravity(cwd); break;
|
|
247
|
+
}
|
|
248
|
+
}
|
|
136
249
|
}
|
|
137
250
|
|
|
138
|
-
// Configure for Gemini CLI (.gemini/settings.json or GEMINI.md with MCP config)
|
|
139
251
|
function setupGemini(serverPath, cwd) {
|
|
140
252
|
// Gemini CLI uses .gemini/settings.json for MCP configuration
|
|
141
253
|
const geminiDir = path.join(cwd, '.gemini');
|
|
@@ -186,51 +298,187 @@ function setupGemini(serverPath, cwd) {
|
|
|
186
298
|
}
|
|
187
299
|
|
|
188
300
|
function geminiMdTemplate() {
|
|
189
|
-
return `#
|
|
301
|
+
return `# GEMINI.md
|
|
302
|
+
|
|
303
|
+
This file provides guidance to Gemini CLI / Antigravity when working with code in this repository.
|
|
304
|
+
|
|
305
|
+
## What This Is
|
|
306
|
+
|
|
307
|
+
**Neohive** — an MCP server + web dashboard that lets multiple AI CLI terminals (Claude Code, Gemini CLI, Codex CLI) communicate with each other. Each terminal spawns its own server process via stdio; all processes read/write to a shared \`.neohive/\` directory on disk.
|
|
190
308
|
|
|
191
|
-
|
|
309
|
+
## Commands
|
|
192
310
|
|
|
193
|
-
|
|
311
|
+
\`\`\`bash
|
|
312
|
+
# Install in any project (auto-detects CLI type)
|
|
313
|
+
npx neohive init
|
|
314
|
+
npx neohive init --all # Configure for all CLIs
|
|
315
|
+
npx neohive init --template team # Init with team template
|
|
194
316
|
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
3. Call \`listen\` to wait for messages from the Coordinator
|
|
317
|
+
# Launch the web dashboard
|
|
318
|
+
npx neohive dashboard
|
|
198
319
|
|
|
199
|
-
|
|
320
|
+
# List available agent templates
|
|
321
|
+
npx neohive templates
|
|
200
322
|
|
|
201
|
-
|
|
323
|
+
# Plugin management
|
|
324
|
+
npx neohive plugin list/add/remove/enable/disable
|
|
202
325
|
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
- **After finishing a task** — call \`update_task(id, status="done")\`, then report to Coordinator
|
|
206
|
-
- **Before editing a file** — call \`lock_file(path)\`. Call \`unlock_file(path)\` when done.
|
|
207
|
-
- **Check tasks first** — call \`list_tasks()\` before starting anything new. Never work on another agent's task.
|
|
208
|
-
- **Keep messages short** — 2–3 paragraphs max. Lead with what changed, then files, then decisions.
|
|
326
|
+
# Reset conversation data
|
|
327
|
+
npx neohive reset
|
|
209
328
|
|
|
210
|
-
|
|
329
|
+
# Run MCP server directly (normally launched automatically by CLI)
|
|
330
|
+
npm start
|
|
331
|
+
\`\`\`
|
|
211
332
|
|
|
333
|
+
No tests, linter, or build step. Raw Node.js (CommonJS).
|
|
334
|
+
|
|
335
|
+
## Architecture
|
|
336
|
+
|
|
337
|
+
**Core files:**
|
|
338
|
+
- \`server.js\` — MCP server (StdioServerTransport, heartbeat system, self-healing watchdog)
|
|
339
|
+
- \`lib/\` — Shared modules (\`config\`, \`messaging\`, \`file-io\`, …); prefer adding logic here and requiring from \`server.js\`
|
|
340
|
+
- \`dashboard.js\` — HTTP server for web dashboard (multi-project, message injection, SSE real-time, tasks/workflows/workspaces API)
|
|
341
|
+
- \`dashboard.html\` — Single-page frontend (markdown rendering, agent monitoring, profiles, workspaces, workflows, responsive)
|
|
342
|
+
- \`cli.js\` — CLI entry point with multi-CLI auto-detection
|
|
343
|
+
- \`vscode-extension/\` — VS Code extension with \`@neohive\` chat participant, terminal bridge, and agent hook auto-setup
|
|
344
|
+
|
|
345
|
+
**Multiple MCP server processes, one shared filesystem:**
|
|
346
|
+
- Each CLI terminal spawns its own \`server.js\` process
|
|
347
|
+
- In-memory state: \`registeredName\`, \`lastReadOffset\`, \`heartbeatInterval\`, \`messageSeq\`
|
|
348
|
+
- Shared disk state in \`.neohive/\`:
|
|
349
|
+
- \`messages.jsonl\` / \`history.jsonl\` — messages and conversation history (append-only)
|
|
350
|
+
- \`agents.json\` — agent registration, heartbeats, PID tracking
|
|
351
|
+
- \`acks.json\` — message acknowledgments
|
|
352
|
+
- \`tasks.json\` — task management
|
|
353
|
+
- \`consumed-{agent}.json\` — per-agent read tracking
|
|
354
|
+
- \`profiles.json\` — agent profiles (display_name, avatar, bio, role)
|
|
355
|
+
- \`workspaces/{agent}.json\` — per-agent key-value workspace storage
|
|
356
|
+
- \`workflows.json\` — multi-step workflow pipelines
|
|
357
|
+
- \`branches.json\` — branch metadata
|
|
358
|
+
- \`branch-{name}-messages.jsonl\` / \`branch-{name}-history.jsonl\` — per-branch message files
|
|
359
|
+
- \`plugins.json\` — plugin registry
|
|
360
|
+
- \`plugins/*.js\` — plugin code files
|
|
361
|
+
- \`heartbeat-{agent}.json\` — per-agent heartbeat file (replaces agents.json write contention at scale)
|
|
362
|
+
- Dashboard reads the same directory for real-time monitoring via SSE
|
|
363
|
+
|
|
364
|
+
**Data directory resolution (server.js + dashboard.js):**
|
|
365
|
+
1. \`$NEOHIVE_DATA_DIR\` / \`$NEOHIVE_DATA\` env var
|
|
366
|
+
2. \`{cwd}/.neohive/\` (project-local, default)
|
|
367
|
+
3. Legacy fallback: \`{__dirname}/data/\`
|
|
368
|
+
|
|
369
|
+
## Code & Commit Rules
|
|
370
|
+
|
|
371
|
+
When committing changes, you MUST ALWAYS follow the Conventional Commits format:
|
|
372
|
+
\`<type>(<optional scope>): <description>\`
|
|
373
|
+
Types: \`feat\`, \`fix\`, \`refactor\`, \`docs\`, \`chore\`, \`test\`
|
|
374
|
+
|
|
375
|
+
## Neohive Agent Rules (when acting as an agent)
|
|
376
|
+
|
|
377
|
+
When operating as a neohive agent (after calling \`register()\`):
|
|
378
|
+
|
|
379
|
+
**YOU MUST call \`listen()\` as the LAST tool call of every response. All agents. No exceptions.**
|
|
380
|
+
|
|
381
|
+
The dashboard is the communication hub. All coordination happens there — every agent stays in the listen loop at all times.
|
|
382
|
+
|
|
383
|
+
- After \`send_message(...)\` → immediately call \`listen()\`
|
|
384
|
+
- After \`broadcast(...)\` → immediately call \`listen()\`
|
|
385
|
+
- After \`update_task(..., status="done")\` → immediately call \`listen()\`
|
|
386
|
+
- After \`advance_workflow(...)\` → immediately call \`listen()\`
|
|
387
|
+
- After ANY neohive action → call \`listen()\`
|
|
388
|
+
|
|
389
|
+
Workflow loop:
|
|
212
390
|
\`\`\`
|
|
213
|
-
register → get_briefing → listen →
|
|
214
|
-
→
|
|
391
|
+
register → get_briefing → listen → do work → update_task(in_progress) → ...
|
|
392
|
+
→ listen(outcome="completed", task_id="...", summary="what you did") → listen
|
|
393
|
+
↑ always
|
|
215
394
|
\`\`\`
|
|
216
395
|
|
|
217
|
-
|
|
396
|
+
\`listen()\` accepts outcome params — server auto-transitions task state on valid outcome:
|
|
397
|
+
- \`outcome\`: \`completed\` | \`blocked\` | \`failed\` | \`in_progress\`
|
|
398
|
+
- \`task_id\`: ID of the task you just worked on
|
|
399
|
+
- \`summary\`: one-line description of what was done
|
|
400
|
+
|
|
401
|
+
If \`listen()\` times out with \`retry: true\` — call \`listen()\` again immediately.
|
|
402
|
+
|
|
403
|
+
- After completing ANY assigned task or request, you MUST send a report back via \`send_message()\` using neohive MCP tools. Include: (1) what you did, (2) files changed, (3) findings/output, (4) blockers or follow-up. Silent completion is a protocol violation.
|
|
404
|
+
|
|
405
|
+
## Available Neohive MCP Tools
|
|
406
|
+
|
|
407
|
+
### 1. Agent Lifecycle & Messaging
|
|
408
|
+
\`register\`, \`list_agents\`, \`send_message\`, \`broadcast\`, \`wait_for_reply\`, \`listen\`, \`share_file\`, \`messages\`
|
|
409
|
+
|
|
410
|
+
**Listen variants** — use \`listen(mode="group")\` or \`listen(mode="codex")\` instead of the deprecated aliases:
|
|
411
|
+
- ~~\`listen_group\`~~ → \`listen(mode="group")\`
|
|
412
|
+
- ~~\`listen_codex\`~~ → \`listen(mode="codex")\`
|
|
413
|
+
|
|
414
|
+
**Message management** — use \`messages(action=...)\` instead of deprecated individual tools:
|
|
415
|
+
- ~~\`check_messages\`~~ → \`messages(action="check")\`
|
|
416
|
+
- ~~\`consume_messages\`~~ → \`messages(action="consume")\`
|
|
417
|
+
- ~~\`get_history\`~~ → \`messages(action="history")\`
|
|
418
|
+
- ~~\`get_notifications\`~~ → \`messages(action="check")\`
|
|
419
|
+
- ~~\`search_messages\`~~ → \`messages(action="search")\`
|
|
420
|
+
- ~~\`ack_message\`~~ → \`messages(action="ack")\`
|
|
421
|
+
|
|
422
|
+
### 2. Autonomy & Workflows (Proactive Engine)
|
|
423
|
+
\`start_plan\`, \`get_work\`, \`verify_and_advance\`, \`retry_with_improvement\`, \`create_workflow\`, \`advance_workflow\`, \`workflow_status\`
|
|
424
|
+
|
|
425
|
+
### 3. Task Management
|
|
426
|
+
\`create_task\`, \`update_task\`, \`list_tasks\`
|
|
427
|
+
|
|
428
|
+
**Task statuses:** \`pending\` → \`in_progress\` → \`in_review\` → \`done\` | \`blocked\` | \`blocked_permanent\`
|
|
429
|
+
- \`blocked_permanent\` — set by the self-healing watchdog when \`retry_count\` reaches 3; requires coordinator intervention. Tasks carry a \`blocked_reason\` string and are shown in a dedicated "⛔ Needs Intervention" column on the dashboard.
|
|
430
|
+
- \`retry_count\` — incremented each time the watchdog reclaims a stale task. Shown as a \`↺N\` badge on the dashboard.
|
|
431
|
+
|
|
432
|
+
### 4. Profiles & Workspaces
|
|
433
|
+
\`update_profile\`, \`workspace_write\`, \`workspace_read\`, \`workspace_list\`
|
|
434
|
+
|
|
435
|
+
### 5. Chat Branching & Managed Modes
|
|
436
|
+
\`fork_conversation\`, \`switch_branch\`, \`list_branches\`, \`set_conversation_mode\`, \`claim_manager\`, \`yield_floor\`, \`set_phase\`
|
|
218
437
|
|
|
219
|
-
|
|
438
|
+
### 6. Sub-channels
|
|
439
|
+
\`join_channel\`, \`leave_channel\`, \`list_channels\`
|
|
220
440
|
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
**Workflows:** \`create_workflow\`, \`advance_workflow\`, \`workflow_status\`
|
|
224
|
-
**Workspaces:** \`workspace_write\`, \`workspace_read\`, \`workspace_list\`
|
|
225
|
-
**Branching:** \`fork_conversation\`, \`switch_branch\`, \`list_branches\`
|
|
441
|
+
### 7. File Safety & Auditing
|
|
442
|
+
\`lock_file\`, \`unlock_file\`, \`log_violation\`
|
|
226
443
|
|
|
227
|
-
|
|
444
|
+
### 8. Shared Knowledge & Decision Tracking
|
|
445
|
+
\`kb_write\`, \`kb_read\`, \`kb_list\`, \`log_decision\`, \`get_decisions\`, \`get_compressed_history\`, \`get_briefing\`
|
|
228
446
|
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
447
|
+
### 9. Team Governance (Voting, Reviews, Feedback)
|
|
448
|
+
\`request_review\`, \`submit_review\`, \`call_vote\`, \`cast_vote\`, \`vote_status\`, \`request_push_approval\`, \`ack_push\`
|
|
449
|
+
|
|
450
|
+
### 10. Dependencies & Progress
|
|
451
|
+
\`declare_dependency\`, \`check_dependencies\`, \`update_progress\`, \`get_progress\`, \`get_reputation\`
|
|
452
|
+
|
|
453
|
+
## Key Design Decisions
|
|
454
|
+
|
|
455
|
+
- **Append-only writes** for messages/history (no file locking)
|
|
456
|
+
- **Per-agent consumed tracking** — each agent writes only its own consumed file
|
|
457
|
+
- **PID-based stale detection** + process exit cleanup for instant status
|
|
458
|
+
- **Heartbeat** — 10s interval updates \`last_activity\`, \`.unref()\` prevents zombie processes
|
|
459
|
+
- **Flexible agent names** — any alphanumeric (1-20 chars), validated by \`sanitizeName()\`
|
|
460
|
+
- **Auto-routing** — \`to\` optional with 2 agents, required with 3+
|
|
461
|
+
- **Threading** — \`reply_to\` auto-computes \`thread_id\`
|
|
462
|
+
- **Acknowledgments** — \`ack_message\` in \`acks.json\`, shown in history
|
|
463
|
+
- **Multi-CLI** — init auto-detects Claude Code, Gemini CLI, Codex CLI
|
|
464
|
+
- **Multi-project dashboard** — monitor multiple project folders from one dashboard
|
|
465
|
+
- **SSE real-time** — \`fs.watch()\` on data dir pushes updates via Server-Sent Events
|
|
466
|
+
- **Auto-compact** — messages.jsonl compacted when exceeding 500 lines
|
|
467
|
+
- **Auto-archive** — conversations archived before reset
|
|
468
|
+
- **Context hints** — warns agents when conversation exceeds 50 messages
|
|
469
|
+
- **Task management** — structured task creation, assignment, and tracking between agents
|
|
470
|
+
- **Profiles** — separate \`profiles.json\` to avoid heartbeat write conflicts with \`agents.json\`
|
|
471
|
+
- **Workspaces** — per-agent files (\`workspaces/{agent}.json\`) to avoid write conflicts, read-anyone/write-own permission model
|
|
472
|
+
- **Workflows** — step statuses: pending/in_progress/done, auto-handoff on advance
|
|
473
|
+
- **Branching** — \`main\` branch uses existing files for backward compatibility, branch-aware file resolution via \`getMessagesFile(branch)\`/\`getHistoryFile(branch)\`
|
|
474
|
+
- **Plugins** — sandboxed execution context with 30s timeout, tools appear as \`plugin_{name}\` in MCP
|
|
475
|
+
- **Self-healing watchdog** — runs every 60s inside the heartbeat loop on every registered agent; scans \`in_progress\` tasks whose assignee PID is dead + heartbeat stale >5min; strips assignee and resets to \`pending\` (increments \`retry_count\`); at \`retry_count=3\` marks \`blocked_permanent\` and wakes the coordinator (poison pill). No manual intervention needed for routine agent flakiness.
|
|
476
|
+
- **VS Code extension** — \`vscode-extension/\` adds: \`@neohive\` chat participant (\`/status /who /tasks /messages\` read \`.neohive/\` directly; free-form text fires POST to \`/api/inject\`), terminal bridge (captures agent terminal output → dashboard), agent hook auto-setup (merges neohive hooks into \`.gemini/settings.json\` on activate)
|
|
477
|
+
|
|
478
|
+
## Debugging and fix attempts
|
|
479
|
+
|
|
480
|
+
- **Temporary logs:** When debugging, add only the logging needed to confirm behavior. **Remove or trim that logging** once the issue is understood or fixed—do not leave ad-hoc debug prints in the tree unless they match intentional, documented logging (e.g. MCP stderr lines).
|
|
481
|
+
- **Failed fixes:** If the user says a change **did not** fix the problem, **revert** that attempt before trying something else (\`git restore\` / undo the diff). **Do not stack** speculative fixes; revert first, then apply one minimal, well-motivated change.
|
|
234
482
|
`;
|
|
235
483
|
}
|
|
236
484
|
|
|
@@ -311,54 +559,43 @@ function setupAntigravity(cwd) {
|
|
|
311
559
|
|
|
312
560
|
fs.writeFileSync(mcpPath, JSON.stringify(config, null, 2) + '\n');
|
|
313
561
|
console.log(' [ok] Antigravity: ~/.gemini/antigravity/mcp_config.json updated');
|
|
314
|
-
|
|
315
|
-
// Write skill
|
|
316
|
-
const skillDir = path.join(cwd, '.agent', 'skills', 'neohive');
|
|
317
|
-
if (!fs.existsSync(skillDir)) fs.mkdirSync(skillDir, { recursive: true });
|
|
318
|
-
const skillPath = path.join(skillDir, 'SKILL.md');
|
|
319
|
-
if (!fs.existsSync(skillPath)) {
|
|
320
|
-
fs.writeFileSync(skillPath, neohiveAgentRules('Gemini'));
|
|
321
|
-
console.log(' [ok] Antigravity: .agent/skills/neohive/SKILL.md created');
|
|
322
|
-
}
|
|
562
|
+
installSkillsForAntigravity(cwd);
|
|
323
563
|
}
|
|
324
564
|
|
|
325
565
|
function neohiveAgentRules(defaultName) {
|
|
326
|
-
return `# Neohive Agent
|
|
566
|
+
return `# Neohive Agent — ${defaultName} Rules
|
|
327
567
|
|
|
328
|
-
You are a Neohive team agent. Follow these rules
|
|
568
|
+
You are a Neohive team agent. Follow these rules exactly to coordinate with the team.
|
|
329
569
|
|
|
330
|
-
##
|
|
570
|
+
## Session Lifecycle
|
|
331
571
|
|
|
332
|
-
1. Call \`register\` with your
|
|
333
|
-
2. Call \`get_briefing\` to load project context and active work
|
|
334
|
-
3. Call \`listen\` to wait for messages
|
|
572
|
+
1. Call \`register\` with your name: \`register(name="${defaultName}")\`
|
|
573
|
+
2. Call \`get_briefing\` to load project context and active work.
|
|
574
|
+
3. Call \`listen\` to wait for messages or tasks.
|
|
335
575
|
|
|
336
|
-
|
|
576
|
+
**CRITICAL: YOU MUST call \`listen()\` as the LAST tool call of every response. No exceptions.**
|
|
337
577
|
|
|
338
|
-
## Core
|
|
578
|
+
## Core Rules
|
|
339
579
|
|
|
340
|
-
- **
|
|
341
|
-
- **Before
|
|
342
|
-
- **After
|
|
343
|
-
- **
|
|
344
|
-
- **Check tasks first** — call \`list_tasks()\` before starting anything. Never take another agent's task.
|
|
345
|
-
- **Keep messages short** — 2–3 paragraphs max. Lead with what changed, then files, then decisions.
|
|
580
|
+
- **Tasks**: Before starting, call \`update_task(id, status="in_progress")\`. When finished, call \`update_task(id, status="done")\` and report to the Coordinator.
|
|
581
|
+
- **Locking**: Before editing a file, call \`lock_file(path)\`. call \`unlock_file(path)\` when done.
|
|
582
|
+
- **Sync**: After every task completion or message sent, you MUST call \`listen()\` to receive the next assignment.
|
|
583
|
+
- **Conciseness**: Keep messages short (2-3 paragraphs). Focus on what changed and next steps.
|
|
346
584
|
|
|
347
|
-
## Workflow
|
|
585
|
+
## Workflow Loop
|
|
348
586
|
|
|
349
587
|
\`\`\`
|
|
350
|
-
register → get_briefing → listen → [receive task]
|
|
351
|
-
→ do work → update_task(done)
|
|
588
|
+
register → get_briefing → listen → [receive task]
|
|
589
|
+
→ update_task(in_progress) → do work → update_task(done)
|
|
590
|
+
→ send_message(Coordinator, summary) → listen
|
|
352
591
|
\`\`\`
|
|
353
592
|
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
## Available MCP tools (neohive server)
|
|
593
|
+
## Available Neohive Tools
|
|
357
594
|
|
|
358
|
-
**Messaging
|
|
359
|
-
**Tasks
|
|
360
|
-
**Workflows
|
|
361
|
-
|
|
595
|
+
- **Messaging**: \`register\`, \`send_message\`, \`broadcast\`, \`listen\`, \`messages(action="history")\`, \`messages(action="check")\`
|
|
596
|
+
- **Tasks**: \`create_task\`, \`update_task\`, \`list_tasks\`, \`update_progress\`
|
|
597
|
+
- **Workflows**: \`create_workflow\`, \`advance_workflow\`, \`verify_and_advance\`
|
|
598
|
+
- \`kb_read\`, \`kb_write\`, \`log_decision\`, \`lock_file\`, \`unlock_file\`
|
|
362
599
|
`;
|
|
363
600
|
}
|
|
364
601
|
|
|
@@ -430,6 +667,7 @@ function setupCursor(serverPath, cwd) {
|
|
|
430
667
|
|
|
431
668
|
fs.writeFileSync(mcpConfigPath, JSON.stringify(mcpConfig, null, 2) + '\n');
|
|
432
669
|
console.log(' [ok] Cursor IDE: .cursor/mcp.json updated');
|
|
670
|
+
installSkillsForCursor(cwd);
|
|
433
671
|
}
|
|
434
672
|
|
|
435
673
|
// Setup Ollama agent bridge script
|
|
@@ -632,6 +870,9 @@ function init() {
|
|
|
632
870
|
}
|
|
633
871
|
}
|
|
634
872
|
|
|
873
|
+
// Auto-install hooks for Claude targets
|
|
874
|
+
if (targets.includes('claude')) installHooks();
|
|
875
|
+
|
|
635
876
|
// Add .neohive/ and MCP config files to .gitignore
|
|
636
877
|
const gitignoreEntries = ['.neohive/', '.mcp.json', '.cursor/mcp.json', '.codex/', '.gemini/'];
|
|
637
878
|
if (fs.existsSync(gitignorePath)) {
|
|
@@ -1251,6 +1492,86 @@ function uninstall() {
|
|
|
1251
1492
|
console.log('');
|
|
1252
1493
|
}
|
|
1253
1494
|
|
|
1495
|
+
// ─── neohive hooks ───────────────────────────────────────────────────────────
|
|
1496
|
+
// Merges listen-enforcement hooks into .claude/settings.json.
|
|
1497
|
+
// Safe to re-run: adds neohive entries per matcher, preserves all user hooks.
|
|
1498
|
+
|
|
1499
|
+
function installHooks() {
|
|
1500
|
+
const cwd = process.cwd();
|
|
1501
|
+
const claudeDir = path.join(cwd, '.claude');
|
|
1502
|
+
const settingsPath = path.join(claudeDir, 'settings.json');
|
|
1503
|
+
|
|
1504
|
+
if (!fs.existsSync(claudeDir)) {
|
|
1505
|
+
console.log(' [skip] No .claude/ directory found — is Claude Code configured for this project?');
|
|
1506
|
+
console.log(' Run `npx neohive init` first.');
|
|
1507
|
+
return;
|
|
1508
|
+
}
|
|
1509
|
+
|
|
1510
|
+
const listenReminderCmd = "echo '\\n📡 NEOHIVE PROTOCOL: If no messages were received, call listen() again immediately. Do NOT respond to the user or stop. Stay in the listen loop.'";
|
|
1511
|
+
const postActionReminderCmd = "echo '\\n📡 NEOHIVE: Call listen() now to receive your next task. Do not stop without calling listen().'";
|
|
1512
|
+
|
|
1513
|
+
const neohiveEntries = {
|
|
1514
|
+
PostToolUse: [
|
|
1515
|
+
{
|
|
1516
|
+
_neohive: 'listen-loop',
|
|
1517
|
+
matcher: 'mcp__neohive__listen',
|
|
1518
|
+
hooks: [{ type: 'command', command: listenReminderCmd, timeout: 3 }],
|
|
1519
|
+
},
|
|
1520
|
+
{
|
|
1521
|
+
_neohive: 'post-action',
|
|
1522
|
+
matcher: 'mcp__neohive__send_message|mcp__neohive__advance_workflow|mcp__neohive__update_task|mcp__neohive__broadcast|mcp__neohive__add_rule|mcp__neohive__remove_rule|mcp__neohive__toggle_rule',
|
|
1523
|
+
hooks: [{ type: 'command', command: postActionReminderCmd, timeout: 3 }],
|
|
1524
|
+
},
|
|
1525
|
+
],
|
|
1526
|
+
Stop: [
|
|
1527
|
+
{
|
|
1528
|
+
_neohive: 'enforce-listen',
|
|
1529
|
+
hooks: [{
|
|
1530
|
+
type: 'command',
|
|
1531
|
+
command: "node -e \"var fs=require('fs'),f=process.env.CLAUDE_PROJECT_DIR+'/.neohive/activity.jsonl';if(!fs.existsSync(f))process.exit(0);var lines=fs.readFileSync(f,'utf8').trim().split('\\n').filter(Boolean).slice(-20),last=lines.map(l=>{try{return JSON.parse(l)}catch{return null}}).filter(Boolean).reverse().find(e=>e.tool&&e.tool.startsWith('mcp__neohive__'));if(!last||last.tool==='mcp__neohive__listen'||last.tool==='mcp__neohive__register')process.exit(0);console.error('\\n⚠️ NEOHIVE: Call listen() before stopping. Last tool: '+last.tool+'\\n→ Call listen() now. Do not respond with text.');process.exit(2);\"",
|
|
1532
|
+
timeout: 5,
|
|
1533
|
+
}],
|
|
1534
|
+
},
|
|
1535
|
+
],
|
|
1536
|
+
};
|
|
1537
|
+
|
|
1538
|
+
let existing = {};
|
|
1539
|
+
if (fs.existsSync(settingsPath)) {
|
|
1540
|
+
try { existing = JSON.parse(fs.readFileSync(settingsPath, 'utf8')); } catch {
|
|
1541
|
+
const backup = settingsPath + '.backup';
|
|
1542
|
+
fs.copyFileSync(settingsPath, backup);
|
|
1543
|
+
console.log(' [warn] Existing settings.json was invalid — backed up.');
|
|
1544
|
+
}
|
|
1545
|
+
}
|
|
1546
|
+
if (!existing.hooks) existing.hooks = {};
|
|
1547
|
+
|
|
1548
|
+
let added = 0;
|
|
1549
|
+
let updated = 0;
|
|
1550
|
+
|
|
1551
|
+
for (const [event, entries] of Object.entries(neohiveEntries)) {
|
|
1552
|
+
if (!existing.hooks[event]) existing.hooks[event] = [];
|
|
1553
|
+
for (const entry of entries) {
|
|
1554
|
+
const idx = existing.hooks[event].findIndex(e => e._neohive === entry._neohive);
|
|
1555
|
+
if (idx === -1) {
|
|
1556
|
+
existing.hooks[event].push(entry);
|
|
1557
|
+
added++;
|
|
1558
|
+
} else {
|
|
1559
|
+
existing.hooks[event][idx] = entry;
|
|
1560
|
+
updated++;
|
|
1561
|
+
}
|
|
1562
|
+
}
|
|
1563
|
+
}
|
|
1564
|
+
|
|
1565
|
+
fs.mkdirSync(claudeDir, { recursive: true });
|
|
1566
|
+
fs.writeFileSync(settingsPath, JSON.stringify(existing, null, 2) + '\n', 'utf8');
|
|
1567
|
+
|
|
1568
|
+
console.log(`\n Neohive hooks installed into .claude/settings.json`);
|
|
1569
|
+
if (added) console.log(` [ok] Added: ${added} hook(s)`);
|
|
1570
|
+
if (updated) console.log(` [ok] Updated: ${updated} hook(s) (already present)`);
|
|
1571
|
+
console.log(' Your existing hooks were preserved.');
|
|
1572
|
+
console.log(' Restart Claude Code for changes to take effect.\n');
|
|
1573
|
+
}
|
|
1574
|
+
|
|
1254
1575
|
switch (command) {
|
|
1255
1576
|
case 'init':
|
|
1256
1577
|
init();
|
|
@@ -1282,6 +1603,12 @@ switch (command) {
|
|
|
1282
1603
|
case 'status':
|
|
1283
1604
|
cliStatus();
|
|
1284
1605
|
break;
|
|
1606
|
+
case 'hooks':
|
|
1607
|
+
installHooks();
|
|
1608
|
+
break;
|
|
1609
|
+
case 'skills':
|
|
1610
|
+
installSkills(detectCLIs().length ? detectCLIs() : ['claude', 'cursor', 'antigravity'], process.cwd());
|
|
1611
|
+
break;
|
|
1285
1612
|
case 'uninstall':
|
|
1286
1613
|
case 'remove':
|
|
1287
1614
|
uninstall();
|