nexus-prime 7.9.22 → 7.9.23
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/dist/agents/adapters/ide-compat.d.ts +3 -3
- package/dist/agents/adapters/ide-compat.js +51 -1
- package/dist/agents/adapters/mcp/definitions.js +4 -1
- package/dist/agents/adapters/mcp/dispatch.js +66 -4
- package/dist/agents/adapters/mcp/handlers/orchestration.js +91 -0
- package/dist/agents/adapters/mcp/runHandler.js +3 -0
- package/dist/agents/adapters/mcp/util/detect-caller.js +21 -0
- package/dist/agents/adapters/mcp.js +1 -1
- package/dist/agents/adapters.d.ts +10 -1
- package/dist/agents/adapters.js +21 -0
- package/dist/agents/core/types.d.ts +1 -1
- package/dist/cli/hook.d.ts +4 -6
- package/dist/cli/hook.js +6 -8
- package/dist/cli/install-wizard.js +5 -1
- package/dist/cli.js +181 -15
- package/dist/core/types.d.ts +1 -1
- package/dist/dashboard/app/styles/board.css +85 -1
- package/dist/dashboard/app/views/board.js +56 -0
- package/dist/dashboard/app/views/memory.js +71 -10
- package/dist/dashboard/routes/events.js +3 -0
- package/dist/dashboard/selectors/operate-selector.js +5 -0
- package/dist/dashboard/selectors/runs-selector.js +5 -0
- package/dist/dashboard/server.js +6 -0
- package/dist/dashboard/types.d.ts +4 -0
- package/dist/engines/client-bootstrap.d.ts +5 -1
- package/dist/engines/client-bootstrap.js +105 -10
- package/dist/engines/client-registry.js +51 -0
- package/dist/engines/event-bus.d.ts +16 -2
- package/dist/engines/feature-registry.js +1 -0
- package/dist/engines/instruction-gateway.d.ts +9 -0
- package/dist/engines/instruction-gateway.js +113 -4
- package/dist/engines/memory/types.d.ts +28 -0
- package/dist/engines/memory-bridge.d.ts +1 -1
- package/dist/engines/memory-bridge.js +1 -1
- package/dist/engines/memory.d.ts +5 -0
- package/dist/engines/memory.js +144 -12
- package/dist/engines/orchestrator/decision-spine.d.ts +26 -0
- package/dist/engines/orchestrator/decision-spine.js +145 -6
- package/dist/engines/orchestrator/funnel.js +8 -1
- package/dist/engines/orchestrator/scoring.d.ts +1 -1
- package/dist/engines/orchestrator/scoring.js +24 -2
- package/dist/engines/orchestrator.d.ts +3 -0
- package/dist/engines/orchestrator.js +73 -13
- package/dist/engines/peer-connectors.d.ts +1 -1
- package/dist/engines/peer-connectors.js +9 -2
- package/dist/engines/runtime-registry.d.ts +9 -0
- package/dist/index.js +9 -0
- package/dist/install/state-locator.d.ts +1 -1
- package/dist/install/state-locator.js +3 -0
- package/dist/synapse/bootstrap.js +3 -0
- package/dist/synapse/mandate/pipeline.js +52 -5
- package/dist/synapse/sorties/runner.js +32 -0
- package/dist/synapse/types.d.ts +27 -0
- package/package.json +1 -1
|
@@ -2,10 +2,10 @@
|
|
|
2
2
|
* Nexus Prime — IDE Compatibility Utilities
|
|
3
3
|
* Provides MCP config templates and detection logic for all supported IDEs.
|
|
4
4
|
*
|
|
5
|
-
* Supported: VS Code (Claude Code ext), JetBrains, Cursor, Windsurf, Zed, Continue.dev, Aider, Cline, Codex
|
|
5
|
+
* Supported: VS Code (Claude Code ext), JetBrains, Cursor, Windsurf, Zed, Continue.dev, Aider, Cline, Codex, and peer agent clients.
|
|
6
6
|
*/
|
|
7
|
-
export type IDEId = 'claude-code' | 'cursor' | 'windsurf' | 'continue' | 'cline' | 'zed' | 'codex';
|
|
8
|
-
export type CallerIDEId = 'claude-code' | 'cursor' | 'windsurf' | 'continue' | 'zed' | 'codex';
|
|
7
|
+
export type IDEId = 'claude-code' | 'cursor' | 'windsurf' | 'continue' | 'cline' | 'openclaw' | 'hermes' | 'nanoclaw' | 'picoclaw' | 'zed' | 'codex';
|
|
8
|
+
export type CallerIDEId = 'claude-code' | 'cursor' | 'windsurf' | 'continue' | 'openclaw' | 'hermes' | 'nanoclaw' | 'picoclaw' | 'zed' | 'codex';
|
|
9
9
|
export interface McpConfigOutput {
|
|
10
10
|
/** Absolute path where the config should be written */
|
|
11
11
|
configPath: string | null;
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Nexus Prime — IDE Compatibility Utilities
|
|
3
3
|
* Provides MCP config templates and detection logic for all supported IDEs.
|
|
4
4
|
*
|
|
5
|
-
* Supported: VS Code (Claude Code ext), JetBrains, Cursor, Windsurf, Zed, Continue.dev, Aider, Cline, Codex
|
|
5
|
+
* Supported: VS Code (Claude Code ext), JetBrains, Cursor, Windsurf, Zed, Continue.dev, Aider, Cline, Codex, and peer agent clients.
|
|
6
6
|
*/
|
|
7
7
|
import { existsSync } from 'fs';
|
|
8
8
|
import { homedir } from 'os';
|
|
@@ -29,6 +29,18 @@ function detectCallerIDEFromEnv() {
|
|
|
29
29
|
if (hasAnyEnvPrefix('WINDSURF_')) {
|
|
30
30
|
return 'windsurf';
|
|
31
31
|
}
|
|
32
|
+
if (hasAnyEnvPrefix('OPENCLAW_') || hasAnyEnvPrefix('ANTIGRAVITY_')) {
|
|
33
|
+
return 'openclaw';
|
|
34
|
+
}
|
|
35
|
+
if (hasAnyEnvPrefix('HERMES_')) {
|
|
36
|
+
return 'hermes';
|
|
37
|
+
}
|
|
38
|
+
if (hasAnyEnvPrefix('NANOCLAW_')) {
|
|
39
|
+
return 'nanoclaw';
|
|
40
|
+
}
|
|
41
|
+
if (hasAnyEnvPrefix('PICOCLAW_')) {
|
|
42
|
+
return 'picoclaw';
|
|
43
|
+
}
|
|
32
44
|
if (hasAnyEnvPrefix('CONTINUE_')) {
|
|
33
45
|
return 'continue';
|
|
34
46
|
}
|
|
@@ -46,6 +58,14 @@ function detectCallerIDEFromFilesystem(startDir) {
|
|
|
46
58
|
return 'continue';
|
|
47
59
|
if (existsSync(join(current, '.windsurf')))
|
|
48
60
|
return 'windsurf';
|
|
61
|
+
if (existsSync(join(current, '.openclaw')))
|
|
62
|
+
return 'openclaw';
|
|
63
|
+
if (existsSync(join(current, '.hermes')))
|
|
64
|
+
return 'hermes';
|
|
65
|
+
if (existsSync(join(current, '.nanoclaw')))
|
|
66
|
+
return 'nanoclaw';
|
|
67
|
+
if (existsSync(join(current, '.picoclaw')))
|
|
68
|
+
return 'picoclaw';
|
|
49
69
|
if (existsSync(join(current, '.zed')))
|
|
50
70
|
return 'zed';
|
|
51
71
|
const parent = dirname(current);
|
|
@@ -84,6 +104,22 @@ export function detectInstalledIDEs(workspaceRoot) {
|
|
|
84
104
|
existsSync(join(home, '.windsurf'))) {
|
|
85
105
|
detected.push('windsurf');
|
|
86
106
|
}
|
|
107
|
+
if (existsSync(join(workspaceRoot, '.openclaw')) ||
|
|
108
|
+
existsSync(join(home, '.openclaw'))) {
|
|
109
|
+
detected.push('openclaw');
|
|
110
|
+
}
|
|
111
|
+
if (existsSync(join(workspaceRoot, '.hermes')) ||
|
|
112
|
+
existsSync(join(home, '.hermes'))) {
|
|
113
|
+
detected.push('hermes');
|
|
114
|
+
}
|
|
115
|
+
if (existsSync(join(workspaceRoot, '.nanoclaw')) ||
|
|
116
|
+
existsSync(join(home, '.nanoclaw'))) {
|
|
117
|
+
detected.push('nanoclaw');
|
|
118
|
+
}
|
|
119
|
+
if (existsSync(join(workspaceRoot, '.picoclaw')) ||
|
|
120
|
+
existsSync(join(home, '.picoclaw'))) {
|
|
121
|
+
detected.push('picoclaw');
|
|
122
|
+
}
|
|
87
123
|
// Continue.dev: .continue/ directory
|
|
88
124
|
if (existsSync(join(workspaceRoot, '.continue')) ||
|
|
89
125
|
existsSync(join(home, '.continue'))) {
|
|
@@ -140,6 +176,20 @@ export function getMcpConfigForIDE(ide, workspaceRoot) {
|
|
|
140
176
|
}, null, 2);
|
|
141
177
|
return { configPath, content, merge: true };
|
|
142
178
|
}
|
|
179
|
+
case 'openclaw':
|
|
180
|
+
case 'hermes':
|
|
181
|
+
case 'nanoclaw':
|
|
182
|
+
case 'picoclaw': {
|
|
183
|
+
const configPath = ide === 'openclaw'
|
|
184
|
+
? join(home, '.openclaw', 'openclaw.json')
|
|
185
|
+
: join(home, `.${ide}`, 'mcp.json');
|
|
186
|
+
const content = JSON.stringify({
|
|
187
|
+
mcpServers: {
|
|
188
|
+
'nexus-prime': entry,
|
|
189
|
+
},
|
|
190
|
+
}, null, 2);
|
|
191
|
+
return { configPath, content, merge: true };
|
|
192
|
+
}
|
|
143
193
|
case 'continue': {
|
|
144
194
|
// Continue.dev uses ~/.continue/config.json
|
|
145
195
|
const configPath = join(home, '.continue', 'config.json');
|
|
@@ -279,7 +279,10 @@ export function buildMcpToolDefinitions() {
|
|
|
279
279
|
crews: { type: 'array', items: { type: 'string' }, description: 'Optional hard crew selectors' },
|
|
280
280
|
specialists: { type: 'array', items: { type: 'string' }, description: 'Optional hard specialist selectors' },
|
|
281
281
|
optimizationProfile: { type: 'string', enum: ['standard', 'max'], description: 'Planner optimization profile override' },
|
|
282
|
-
executionPreset: { type: 'string', enum: ['fast', 'balanced', 'deep', 'release'], description: 'Optional execution preset that maps orchestration depth, verification strictness, and backend routing' }
|
|
282
|
+
executionPreset: { type: 'string', enum: ['fast', 'balanced', 'deep', 'release'], description: 'Optional execution preset that maps orchestration depth, verification strictness, and backend routing' },
|
|
283
|
+
background: { type: 'boolean', description: 'When true, return a queued receipt immediately and let the run continue in the async gate.' },
|
|
284
|
+
async: { type: 'boolean', description: 'Alias for background; useful for clients that prefer explicit async orchestration.' },
|
|
285
|
+
waitMs: { type: 'number', description: 'Optional bounded wait before returning a queued receipt. Clamped to 45 seconds; normal orchestrate calls default to 15 seconds.' }
|
|
283
286
|
},
|
|
284
287
|
required: ['prompt'],
|
|
285
288
|
},
|
|
@@ -16,9 +16,18 @@ import { handleMiscGroup } from './handlers/misc.js';
|
|
|
16
16
|
import { handleWorkforceGroup } from './handlers/workforce.js';
|
|
17
17
|
import { nexusEventBus } from '../../../engines/event-bus.js';
|
|
18
18
|
import { recordToolInvocation } from './tool-health.js';
|
|
19
|
-
import { withAsyncGate } from './async-gate.js';
|
|
19
|
+
import { getAsyncGate, withAsyncGate } from './async-gate.js';
|
|
20
20
|
import { getCircuitManager, checkBackpressure } from './circuit.js';
|
|
21
|
-
import { createRun } from '../../../engines/orchestrator/store.js';
|
|
21
|
+
import { completeRun, createRun, failRun, updateStage } from '../../../engines/orchestrator/store.js';
|
|
22
|
+
function summarizeAsyncMcpResult(toolName, result) {
|
|
23
|
+
const text = result?.content
|
|
24
|
+
?.map((part) => part?.type === 'text' ? String(part.text ?? '') : '')
|
|
25
|
+
.filter(Boolean)
|
|
26
|
+
.join('\n')
|
|
27
|
+
.trim();
|
|
28
|
+
const firstLine = text?.split('\n').find((line) => line.trim())?.trim();
|
|
29
|
+
return (firstLine ? `${toolName}: ${firstLine}` : `${toolName} completed asynchronously`).slice(0, 1024);
|
|
30
|
+
}
|
|
22
31
|
/** Tools that may exceed the MCP client timeout (~60s). Wrap in async gate. */
|
|
23
32
|
const SLOW_TOOLS = new Set([
|
|
24
33
|
'nexus_orchestrate',
|
|
@@ -69,6 +78,37 @@ const TOOL_ETA_MS = {
|
|
|
69
78
|
nexus_autofix: 45_000,
|
|
70
79
|
nexus_hypertune_max: 45_000,
|
|
71
80
|
};
|
|
81
|
+
const DEFAULT_MAX_SYNC_MS = 2000;
|
|
82
|
+
const ORCHESTRATE_DEFAULT_MAX_SYNC_MS = 15_000;
|
|
83
|
+
const MAX_CLIENT_SYNC_WAIT_MS = 45_000;
|
|
84
|
+
function isTruthyFlag(value) {
|
|
85
|
+
if (value === true)
|
|
86
|
+
return true;
|
|
87
|
+
if (typeof value === 'number')
|
|
88
|
+
return value > 0;
|
|
89
|
+
if (typeof value === 'string')
|
|
90
|
+
return ['1', 'true', 'yes', 'on'].includes(value.trim().toLowerCase());
|
|
91
|
+
return false;
|
|
92
|
+
}
|
|
93
|
+
function coerceBoundedWaitMs(value) {
|
|
94
|
+
const numeric = Number(value);
|
|
95
|
+
if (!Number.isFinite(numeric) || numeric < 0)
|
|
96
|
+
return undefined;
|
|
97
|
+
return Math.min(MAX_CLIENT_SYNC_WAIT_MS, Math.floor(numeric));
|
|
98
|
+
}
|
|
99
|
+
function shouldReturnQueuedReceipt(toolName, args) {
|
|
100
|
+
if (!SLOW_TOOLS.has(toolName))
|
|
101
|
+
return false;
|
|
102
|
+
return isTruthyFlag(args.background)
|
|
103
|
+
|| isTruthyFlag(args.async)
|
|
104
|
+
|| isTruthyFlag(args.queue)
|
|
105
|
+
|| isTruthyFlag(args.detach);
|
|
106
|
+
}
|
|
107
|
+
function resolveMaxSyncMs(toolName, args) {
|
|
108
|
+
return coerceBoundedWaitMs(args.waitMs)
|
|
109
|
+
?? coerceBoundedWaitMs(args.maxSyncMs)
|
|
110
|
+
?? (toolName === 'nexus_orchestrate' ? ORCHESTRATE_DEFAULT_MAX_SYNC_MS : DEFAULT_MAX_SYNC_MS);
|
|
111
|
+
}
|
|
72
112
|
/**
|
|
73
113
|
* Route a tool call to the appropriate handler group.
|
|
74
114
|
*
|
|
@@ -127,9 +167,9 @@ export async function dispatchMcpToolCall(hctx, request, args, ctx) {
|
|
|
127
167
|
}, {
|
|
128
168
|
tool: toolName,
|
|
129
169
|
args,
|
|
130
|
-
maxSyncMs:
|
|
170
|
+
maxSyncMs: resolveMaxSyncMs(toolName, args),
|
|
131
171
|
etaMs: TOOL_ETA_MS[toolName],
|
|
132
|
-
alwaysQueue: toolName
|
|
172
|
+
alwaysQueue: shouldReturnQueuedReceipt(toolName, args),
|
|
133
173
|
});
|
|
134
174
|
if ('queued' in gated && gated.queued) {
|
|
135
175
|
// Persist orchestration run record for durable stage tracking
|
|
@@ -138,6 +178,7 @@ export async function dispatchMcpToolCall(hctx, request, args, ctx) {
|
|
|
138
178
|
const client = hctx.getToolProfile();
|
|
139
179
|
try {
|
|
140
180
|
createRun(gated.runId, goal, client);
|
|
181
|
+
updateStage(gated.runId, 'executing', 20);
|
|
141
182
|
}
|
|
142
183
|
catch { /* non-fatal */ }
|
|
143
184
|
}
|
|
@@ -147,8 +188,24 @@ export async function dispatchMcpToolCall(hctx, request, args, ctx) {
|
|
|
147
188
|
const runId = gated.runId;
|
|
148
189
|
let unsubOk = null;
|
|
149
190
|
let unsubFail = null;
|
|
191
|
+
let finalized = false;
|
|
150
192
|
const finalize = (success) => {
|
|
193
|
+
if (finalized)
|
|
194
|
+
return;
|
|
195
|
+
finalized = true;
|
|
151
196
|
const durationMs = Date.now() - startedAt;
|
|
197
|
+
if (toolName === 'nexus_orchestrate') {
|
|
198
|
+
try {
|
|
199
|
+
const job = getAsyncGate().getJob(runId);
|
|
200
|
+
if (success) {
|
|
201
|
+
completeRun(runId, summarizeAsyncMcpResult(toolName, job?.result));
|
|
202
|
+
}
|
|
203
|
+
else {
|
|
204
|
+
failRun(runId, job?.error ?? `${toolName} failed asynchronously`);
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
catch { /* durable run updates are best-effort */ }
|
|
208
|
+
}
|
|
152
209
|
try {
|
|
153
210
|
circuit.recordComplete(toolName, durationMs, success);
|
|
154
211
|
}
|
|
@@ -166,6 +223,11 @@ export async function dispatchMcpToolCall(hctx, request, args, ctx) {
|
|
|
166
223
|
if (ev.runId === runId)
|
|
167
224
|
finalize(false);
|
|
168
225
|
});
|
|
226
|
+
const existingJob = getAsyncGate().getJob(runId);
|
|
227
|
+
if (existingJob?.status === 'completed')
|
|
228
|
+
finalize(true);
|
|
229
|
+
if (existingJob?.status === 'failed')
|
|
230
|
+
finalize(false);
|
|
169
231
|
// Return async receipt as MCP text so agent can poll
|
|
170
232
|
rawResult = {
|
|
171
233
|
content: [{
|
|
@@ -55,6 +55,82 @@ export function extractSkillSelectorsFromPrompt(prompt) {
|
|
|
55
55
|
export function inferSpawnWorkersIntent(actions) {
|
|
56
56
|
return actions.length > 0 ? 'mutate' : 'plan';
|
|
57
57
|
}
|
|
58
|
+
function namedValue(value) {
|
|
59
|
+
if (typeof value === 'string')
|
|
60
|
+
return value.trim();
|
|
61
|
+
if (!value || typeof value !== 'object')
|
|
62
|
+
return '';
|
|
63
|
+
const record = value;
|
|
64
|
+
return String(record.name ?? record.id ?? record.specialistId ?? record.skillId ?? record.workflowId ?? record.crewId ?? record.workerId ?? '').trim();
|
|
65
|
+
}
|
|
66
|
+
function asStringList(values, limit = 8) {
|
|
67
|
+
const array = Array.isArray(values) ? values : values ? [values] : [];
|
|
68
|
+
return [...new Set(array.map(namedValue).filter(Boolean))].slice(0, limit);
|
|
69
|
+
}
|
|
70
|
+
function formatSelectionList(values, fallback = 'none') {
|
|
71
|
+
return values.length > 0 ? values.join(', ') : fallback;
|
|
72
|
+
}
|
|
73
|
+
function formatModelRoute(route) {
|
|
74
|
+
if (!route)
|
|
75
|
+
return 'default runtime route';
|
|
76
|
+
const worker = String(route.workerTier ?? 'T1');
|
|
77
|
+
const reviewer = route.reviewerTier ? ` + reviewer ${route.reviewerTier}` : '';
|
|
78
|
+
const reason = route.reason ? ` - ${route.reason}` : '';
|
|
79
|
+
return `${worker}${reviewer}${reason}`;
|
|
80
|
+
}
|
|
81
|
+
function formatBudgetRoute(plan) {
|
|
82
|
+
const budgets = plan?.budgets ?? {};
|
|
83
|
+
const policy = plan?.executionPolicy?.agentFlow ?? {};
|
|
84
|
+
const total = Number(budgets.totalTokens ?? 0);
|
|
85
|
+
const codeBlocks = Number(budgets.codeBlocks ?? budgets.codeBlockPolicy?.reservedTokens ?? 0);
|
|
86
|
+
const cap = Number(policy.maxTaskCostUsd ?? 0);
|
|
87
|
+
const parts = [
|
|
88
|
+
total > 0 ? `${total.toLocaleString()} tokens` : 'budget pending',
|
|
89
|
+
codeBlocks > 0 ? `${codeBlocks.toLocaleString()} code-block tokens` : null,
|
|
90
|
+
cap > 0 ? `$${cap.toFixed(2)} task cap` : null,
|
|
91
|
+
].filter(Boolean);
|
|
92
|
+
return parts.join(' · ');
|
|
93
|
+
}
|
|
94
|
+
function buildSelectionSummary(execution, runtimeUsage) {
|
|
95
|
+
const selectionPlan = execution.selectionPlan ?? {};
|
|
96
|
+
const selected = selectionPlan.selected ?? {};
|
|
97
|
+
const planner = execution.plannerState ?? {};
|
|
98
|
+
const taskGraph = runtimeUsage.taskGraph ?? execution.taskGraph ?? {};
|
|
99
|
+
const workerPlan = runtimeUsage.workerPlan ?? execution.workerPlan ?? {};
|
|
100
|
+
const audit = runtimeUsage.artifactSelectionAudit ?? execution.artifactSelectionAudit ?? {};
|
|
101
|
+
const crew = asStringList(selected.crews, 2)[0]
|
|
102
|
+
?? namedValue(planner.selectedCrew)
|
|
103
|
+
?? 'baseline path';
|
|
104
|
+
const specialists = asStringList(selected.specialists, 8).length > 0
|
|
105
|
+
? asStringList(selected.specialists, 8)
|
|
106
|
+
: asStringList(planner.selectedSpecialists, 8);
|
|
107
|
+
const skills = asStringList(selected.skills, 8).length > 0
|
|
108
|
+
? asStringList(selected.skills, 8)
|
|
109
|
+
: asStringList(execution.activeSkills, 8).concat(asStringList(planner.selectedSkills, 8)).slice(0, 8);
|
|
110
|
+
const workflows = asStringList(selected.workflows, 8).length > 0
|
|
111
|
+
? asStringList(selected.workflows, 8)
|
|
112
|
+
: asStringList(execution.activeWorkflows, 8).concat(asStringList(planner.selectedWorkflows, 8)).slice(0, 8);
|
|
113
|
+
const workers = asStringList(selected.workers, 8).length > 0
|
|
114
|
+
? asStringList(selected.workers, 8)
|
|
115
|
+
: asStringList(execution.workerManifests, 8);
|
|
116
|
+
return {
|
|
117
|
+
crew,
|
|
118
|
+
specialists,
|
|
119
|
+
skills: [...new Set(skills)],
|
|
120
|
+
workflows: [...new Set(workflows)],
|
|
121
|
+
hooks: asStringList(selected.hooks, 8),
|
|
122
|
+
automations: asStringList(selected.automations, 8),
|
|
123
|
+
workers,
|
|
124
|
+
modelRoute: selectionPlan.modelRoute ?? execution.requestBrief?.modelPolicy,
|
|
125
|
+
budgetRoute: formatBudgetRoute(selectionPlan),
|
|
126
|
+
agentFlow: selectionPlan.executionPolicy?.agentFlow,
|
|
127
|
+
phaseCount: Array.isArray(taskGraph.phases) ? taskGraph.phases.length : 0,
|
|
128
|
+
workerLaneCount: Number(workerPlan.totalWorkers ?? workers.length ?? execution.workerResults?.length ?? 0),
|
|
129
|
+
mode: String(workerPlan.mode ?? execution.mode ?? 'autonomous'),
|
|
130
|
+
auditSelected: Array.isArray(audit.selected) ? audit.selected.length : 0,
|
|
131
|
+
auditRejected: Array.isArray(audit.rejected) ? audit.rejected.length : 0,
|
|
132
|
+
};
|
|
133
|
+
}
|
|
58
134
|
export async function handleOrchestrationGroup(toolName, hctx, request, args, ctx) {
|
|
59
135
|
const runtimeError = requireRuntime(hctx);
|
|
60
136
|
if (runtimeError)
|
|
@@ -457,6 +533,7 @@ export async function handleOrchestrationGroup(toolName, hctx, request, args, ct
|
|
|
457
533
|
result.modifiedFiles.forEach((file) => hctx.sessionDNA.recordFileModified(file));
|
|
458
534
|
});
|
|
459
535
|
const runtimeUsage = hctx.getRuntime().getUsageSnapshot();
|
|
536
|
+
const selectionSummary = buildSelectionSummary(execution, runtimeUsage);
|
|
460
537
|
hctx.sessionDNA.recordDecision('Orchestrated autonomous run completed', execution.result || summarizeExecution(execution), execution.state === 'merged' ? 0.95
|
|
461
538
|
: execution.state === 'inspected' ? 0.85
|
|
462
539
|
: execution.state === 'rolled_back' ? 0.55
|
|
@@ -491,6 +568,8 @@ export async function handleOrchestrationGroup(toolName, hctx, request, args, ct
|
|
|
491
568
|
worktreeHealth: runtimeUsage.worktreeHealth,
|
|
492
569
|
ragUsageSummary: runtimeUsage.ragUsageSummary ?? execution.ragUsageSummary,
|
|
493
570
|
memoryScopeUsage: runtimeUsage.memoryScopeUsage ?? execution.memoryScopeUsage,
|
|
571
|
+
selection: selectionSummary,
|
|
572
|
+
modelRoute: selectionSummary.modelRoute,
|
|
494
573
|
verifiedWorkers,
|
|
495
574
|
continuationChildren: execution.continuationChildren.length,
|
|
496
575
|
executionPreset: preset ? { id: preset.id, name: preset.name, summary: preset.summary } : undefined,
|
|
@@ -525,6 +604,10 @@ export async function handleOrchestrationGroup(toolName, hctx, request, args, ct
|
|
|
525
604
|
ragUsageSummary: runtimeUsage.ragUsageSummary ?? execution.ragUsageSummary,
|
|
526
605
|
memoryScopeUsage: runtimeUsage.memoryScopeUsage ?? execution.memoryScopeUsage,
|
|
527
606
|
memoryReconciliationSummary: runtimeUsage.memoryReconciliationSummary ?? execution.memoryReconciliationSummary,
|
|
607
|
+
requestBrief: execution.requestBrief,
|
|
608
|
+
selectionPlan: execution.selectionPlan,
|
|
609
|
+
selection: selectionSummary,
|
|
610
|
+
modelRoute: selectionSummary.modelRoute,
|
|
528
611
|
tokens: execution.tokenTelemetry,
|
|
529
612
|
verifiedWorkers,
|
|
530
613
|
continuationChildren: execution.continuationChildren,
|
|
@@ -545,6 +628,14 @@ export async function handleOrchestrationGroup(toolName, hctx, request, args, ct
|
|
|
545
628
|
`Run ID: ${execution.runId}`,
|
|
546
629
|
`Summary: ${summarizeExecution(execution)}`,
|
|
547
630
|
`Crew: ${execution.plannerState?.selectedCrew?.name || 'baseline path'}`,
|
|
631
|
+
`Decomposition: ${selectionSummary.phaseCount} phase(s), ${selectionSummary.workerLaneCount} worker lane(s), ${selectionSummary.mode}`,
|
|
632
|
+
`Hired/selected: crew ${selectionSummary.crew}; specialists ${formatSelectionList(selectionSummary.specialists)}; workflows ${formatSelectionList(selectionSummary.workflows)}; skills ${formatSelectionList(selectionSummary.skills)}`,
|
|
633
|
+
`Model route: ${formatModelRoute(selectionSummary.modelRoute)}`,
|
|
634
|
+
`Budget route: ${selectionSummary.budgetRoute || 'budget pending'}`,
|
|
635
|
+
selectionSummary.agentFlow?.stages?.length
|
|
636
|
+
? `AgentFlow gates: ${selectionSummary.agentFlow.stages.map((stage) => `${stage.stage}:${stage.ownerRole}`).join(' -> ')}`
|
|
637
|
+
: null,
|
|
638
|
+
`Selection audit: ${selectionSummary.auditSelected} selected, ${selectionSummary.auditRejected} rejected`,
|
|
548
639
|
`Verification: ${verifiedWorkers}/${execution.workerResults.length} worker(s) verified`,
|
|
549
640
|
`Tokens: saved ${Number(execution.tokenTelemetry?.savedTokens || 0).toLocaleString()} · compression ${Number(execution.tokenTelemetry?.compressionPct || 0)}%`,
|
|
550
641
|
autoTokenApplyNote || null,
|
|
@@ -17,6 +17,9 @@ const ENV_MAP = [
|
|
|
17
17
|
[['CURSOR_HOME', 'CURSOR_SESSION'], 'cursor'],
|
|
18
18
|
[['OPENCODE_HOME'], 'opencode'],
|
|
19
19
|
[['WINDSURF_HOME', 'WINDSURF_SESSION'], 'windsurf'],
|
|
20
|
+
[['HERMES_HOME', 'HERMES_SESSION'], 'hermes'],
|
|
21
|
+
[['NANOCLAW_HOME', 'NANOCLAW_SESSION'], 'nanoclaw'],
|
|
22
|
+
[['PICOCLAW_HOME', 'PICOCLAW_SESSION'], 'picoclaw'],
|
|
20
23
|
];
|
|
21
24
|
// Module-level store for the caller name obtained from the MCP initialize
|
|
22
25
|
// handshake. Takes precedence over env-var and ps fallback once set.
|
|
@@ -52,6 +55,18 @@ export function setMcpClientName(rawName) {
|
|
|
52
55
|
_mcpHandshakeName = 'windsurf';
|
|
53
56
|
return;
|
|
54
57
|
}
|
|
58
|
+
if (lower.includes('hermes')) {
|
|
59
|
+
_mcpHandshakeName = 'hermes';
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
if (lower.includes('nanoclaw') || lower.includes('nano-claw')) {
|
|
63
|
+
_mcpHandshakeName = 'nanoclaw';
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
if (lower.includes('picoclaw') || lower.includes('pico-claw')) {
|
|
67
|
+
_mcpHandshakeName = 'picoclaw';
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
55
70
|
if (lower.includes('anticlaw') || lower.includes('openclaw')) {
|
|
56
71
|
_mcpHandshakeName = 'openclaw';
|
|
57
72
|
return;
|
|
@@ -95,6 +110,12 @@ export async function detectCallerAsync() {
|
|
|
95
110
|
return 'opencode';
|
|
96
111
|
if (ps.includes('windsurf'))
|
|
97
112
|
return 'windsurf';
|
|
113
|
+
if (ps.includes('hermes'))
|
|
114
|
+
return 'hermes';
|
|
115
|
+
if (ps.includes('nanoclaw') || ps.includes('nano-claw'))
|
|
116
|
+
return 'nanoclaw';
|
|
117
|
+
if (ps.includes('picoclaw') || ps.includes('pico-claw'))
|
|
118
|
+
return 'picoclaw';
|
|
98
119
|
if (ps.includes('antigravity') || ps.includes('openclaw'))
|
|
99
120
|
return 'openclaw';
|
|
100
121
|
}
|
|
@@ -719,7 +719,7 @@ export class MCPAdapter {
|
|
|
719
719
|
try {
|
|
720
720
|
this.getRuntime().recordClientInstructionStatus({
|
|
721
721
|
clientId: this.name,
|
|
722
|
-
clientFamily: this.name === 'openclaw' ? 'antigravity' : this.name,
|
|
722
|
+
clientFamily: this.name === 'openclaw' || this.name === 'antigravity' ? 'antigravity' : this.name,
|
|
723
723
|
toolProfile: profile,
|
|
724
724
|
status: profile === 'autonomous' ? 'guided' : 'manual',
|
|
725
725
|
summary: this.describeClientInstructionStatus(profile),
|
|
@@ -24,6 +24,15 @@ declare abstract class RenderedInstructionAdapter implements Adapter {
|
|
|
24
24
|
export declare class OpenClawAdapter extends RenderedInstructionAdapter {
|
|
25
25
|
constructor();
|
|
26
26
|
}
|
|
27
|
+
export declare class HermesAdapter extends RenderedInstructionAdapter {
|
|
28
|
+
constructor();
|
|
29
|
+
}
|
|
30
|
+
export declare class NanoClawAdapter extends RenderedInstructionAdapter {
|
|
31
|
+
constructor();
|
|
32
|
+
}
|
|
33
|
+
export declare class PicoClawAdapter extends RenderedInstructionAdapter {
|
|
34
|
+
constructor();
|
|
35
|
+
}
|
|
27
36
|
export declare class ClaudeCodeAdapter extends RenderedInstructionAdapter {
|
|
28
37
|
constructor();
|
|
29
38
|
}
|
|
@@ -60,5 +69,5 @@ export declare class CustomAdapter extends RenderedInstructionAdapter {
|
|
|
60
69
|
setSendHandler(handler: (message: NetworkMessage) => Promise<void>): void;
|
|
61
70
|
setReceiveHandler(handler: (message: NetworkMessage) => void): void;
|
|
62
71
|
}
|
|
63
|
-
export type AdapterType = 'openclaw' | 'claude-code' | 'ruflo' | 'langchain' | 'autogen' | 'custom' | 'mcp' | 'codex' | 'opencode' | 'cursor' | 'windsurf' | 'aider' | 'continue' | 'cline';
|
|
72
|
+
export type AdapterType = 'openclaw' | 'hermes' | 'nanoclaw' | 'picoclaw' | 'claude-code' | 'ruflo' | 'langchain' | 'autogen' | 'custom' | 'mcp' | 'codex' | 'opencode' | 'cursor' | 'windsurf' | 'aider' | 'continue' | 'cline';
|
|
64
73
|
export declare function createAdapter(type: AdapterType, customName?: string): Adapter;
|
package/dist/agents/adapters.js
CHANGED
|
@@ -78,6 +78,21 @@ export class OpenClawAdapter extends RenderedInstructionAdapter {
|
|
|
78
78
|
super('openclaw', 'openclaw');
|
|
79
79
|
}
|
|
80
80
|
}
|
|
81
|
+
export class HermesAdapter extends RenderedInstructionAdapter {
|
|
82
|
+
constructor() {
|
|
83
|
+
super('hermes', 'hermes');
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
export class NanoClawAdapter extends RenderedInstructionAdapter {
|
|
87
|
+
constructor() {
|
|
88
|
+
super('nanoclaw', 'nanoclaw');
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
export class PicoClawAdapter extends RenderedInstructionAdapter {
|
|
92
|
+
constructor() {
|
|
93
|
+
super('picoclaw', 'picoclaw');
|
|
94
|
+
}
|
|
95
|
+
}
|
|
81
96
|
export class ClaudeCodeAdapter extends RenderedInstructionAdapter {
|
|
82
97
|
constructor() {
|
|
83
98
|
super('claude-code', 'claude-code');
|
|
@@ -158,6 +173,12 @@ export function createAdapter(type, customName) {
|
|
|
158
173
|
switch (type) {
|
|
159
174
|
case 'openclaw':
|
|
160
175
|
return new OpenClawAdapter();
|
|
176
|
+
case 'hermes':
|
|
177
|
+
return new HermesAdapter();
|
|
178
|
+
case 'nanoclaw':
|
|
179
|
+
return new NanoClawAdapter();
|
|
180
|
+
case 'picoclaw':
|
|
181
|
+
return new PicoClawAdapter();
|
|
161
182
|
case 'claude-code':
|
|
162
183
|
return new ClaudeCodeAdapter();
|
|
163
184
|
case 'ruflo':
|
|
@@ -146,7 +146,7 @@ export interface EvolutionConfig {
|
|
|
146
146
|
}
|
|
147
147
|
export interface Adapter {
|
|
148
148
|
name: string;
|
|
149
|
-
type: 'openclaw' | 'claude-code' | 'ruflo' | 'langchain' | 'autogen' | 'custom' | 'mcp' | 'codex' | 'opencode' | 'cursor' | 'windsurf' | 'aider' | 'continue' | 'cline';
|
|
149
|
+
type: 'openclaw' | 'hermes' | 'nanoclaw' | 'picoclaw' | 'claude-code' | 'ruflo' | 'langchain' | 'autogen' | 'custom' | 'mcp' | 'codex' | 'opencode' | 'cursor' | 'windsurf' | 'aider' | 'continue' | 'cline';
|
|
150
150
|
connected: boolean;
|
|
151
151
|
agents: string[];
|
|
152
152
|
connect(): Promise<void>;
|
package/dist/cli/hook.d.ts
CHANGED
|
@@ -17,13 +17,11 @@
|
|
|
17
17
|
/** UserPromptSubmit — call nexus_session_bootstrap so the model never has to. */
|
|
18
18
|
export declare function runHookBootstrap(): Promise<void>;
|
|
19
19
|
/**
|
|
20
|
-
* PostToolUse (Edit|Write|MultiEdit|Bash) —
|
|
20
|
+
* PostToolUse (Edit|Write|MultiEdit|Bash) — compact audit memory.
|
|
21
21
|
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
* nexus_store_memory by the agent itself. To opt back in, set
|
|
26
|
-
* NEXUS_HOOK_AUTO_MEMORY=1.
|
|
22
|
+
* The hook stores only compact, hidden lifecycle breadcrumbs. Real findings
|
|
23
|
+
* should still be stored via nexus_store_memory by the agent itself. Set
|
|
24
|
+
* NEXUS_HOOK_AUTO_MEMORY=0 to disable this hook in a local session.
|
|
27
25
|
*/
|
|
28
26
|
export declare function runHookMemory(): Promise<void>;
|
|
29
27
|
/**
|
package/dist/cli/hook.js
CHANGED
|
@@ -150,16 +150,14 @@ export async function runHookBootstrap() {
|
|
|
150
150
|
}, 10_000);
|
|
151
151
|
}
|
|
152
152
|
/**
|
|
153
|
-
* PostToolUse (Edit|Write|MultiEdit|Bash) —
|
|
153
|
+
* PostToolUse (Edit|Write|MultiEdit|Bash) — compact audit memory.
|
|
154
154
|
*
|
|
155
|
-
*
|
|
156
|
-
*
|
|
157
|
-
*
|
|
158
|
-
* nexus_store_memory by the agent itself. To opt back in, set
|
|
159
|
-
* NEXUS_HOOK_AUTO_MEMORY=1.
|
|
155
|
+
* The hook stores only compact, hidden lifecycle breadcrumbs. Real findings
|
|
156
|
+
* should still be stored via nexus_store_memory by the agent itself. Set
|
|
157
|
+
* NEXUS_HOOK_AUTO_MEMORY=0 to disable this hook in a local session.
|
|
160
158
|
*/
|
|
161
159
|
export async function runHookMemory() {
|
|
162
|
-
if (process.env.NEXUS_HOOK_AUTO_MEMORY
|
|
160
|
+
if (process.env.NEXUS_HOOK_AUTO_MEMORY === '0')
|
|
163
161
|
return;
|
|
164
162
|
const data = await readStdinJson();
|
|
165
163
|
const cwd = String(data.cwd ?? process.cwd());
|
|
@@ -182,7 +180,7 @@ export async function runHookMemory() {
|
|
|
182
180
|
await callDaemonTool(lock, 'nexus_store_memory', {
|
|
183
181
|
content: `${toolName}: ${inputSummary}`,
|
|
184
182
|
priority: 0.2,
|
|
185
|
-
tags: ['#auto', `tool:${toolName}`, `repo:${repoName}`],
|
|
183
|
+
tags: ['#auto', '#memory-hook', '#system-hidden', `tool:${toolName}`, `repo:${repoName}`],
|
|
186
184
|
}, 5_000);
|
|
187
185
|
}
|
|
188
186
|
/**
|
|
@@ -37,6 +37,10 @@ const SETUP_CLIENT_BY_IDE = {
|
|
|
37
37
|
windsurf: 'windsurf',
|
|
38
38
|
continue: 'continue',
|
|
39
39
|
cline: 'cline',
|
|
40
|
+
openclaw: 'openclaw',
|
|
41
|
+
hermes: 'hermes',
|
|
42
|
+
nanoclaw: 'nanoclaw',
|
|
43
|
+
picoclaw: 'picoclaw',
|
|
40
44
|
codex: 'codex',
|
|
41
45
|
};
|
|
42
46
|
function resolveSetupWorkspaceRoot(explicitWorkspaceRoot) {
|
|
@@ -365,7 +369,7 @@ function mergeIntoExistingConfig(configPath, newContent, ide) {
|
|
|
365
369
|
try {
|
|
366
370
|
const existing = JSON.parse(readFileSync(configPath, 'utf8'));
|
|
367
371
|
const incoming = JSON.parse(newContent);
|
|
368
|
-
if (ide === 'cursor' || ide === 'windsurf' || ide === 'continue') {
|
|
372
|
+
if (ide === 'cursor' || ide === 'windsurf' || ide === 'continue' || ide === 'openclaw' || ide === 'hermes' || ide === 'nanoclaw' || ide === 'picoclaw') {
|
|
369
373
|
// These use { mcpServers: { "nexus-prime": {...} } }
|
|
370
374
|
existing.mcpServers = {
|
|
371
375
|
...(existing.mcpServers ?? {}),
|