nexus-prime 7.9.24 → 7.9.26
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/mcp/definitions.js +3 -2
- package/dist/agents/adapters/mcp/dispatch.js +23 -14
- package/dist/dashboard/app/styles/board.css +34 -0
- package/dist/dashboard/app/views/board.js +39 -9
- package/dist/engines/event-bus.d.ts +16 -0
- package/dist/engines/orchestrator.d.ts +2 -0
- package/dist/engines/orchestrator.js +56 -5
- package/dist/install/claude-code-hooks.js +4 -0
- package/dist/phantom/runtime.d.ts +6 -0
- package/dist/phantom/runtime.js +16 -0
- package/package.json +1 -1
|
@@ -280,9 +280,10 @@ export function buildMcpToolDefinitions() {
|
|
|
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
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: '
|
|
283
|
+
background: { type: 'boolean', description: 'Compatibility flag; nexus_orchestrate already returns a queued hiring preflight by default and continues in the async gate.' },
|
|
284
284
|
async: { type: 'boolean', description: 'Alias for background; useful for clients that prefer explicit async orchestration.' },
|
|
285
|
-
waitMs: { type: 'number', description: '
|
|
285
|
+
waitMs: { type: 'number', description: 'Advanced/debug bounded wait for inline execution. Clamped to 45 seconds; normal orchestrate calls return a queued preflight immediately.' },
|
|
286
|
+
inline: { type: 'boolean', description: 'Advanced/debug only: wait for inline orchestrate output instead of the default fast queued preflight.' }
|
|
286
287
|
},
|
|
287
288
|
required: ['prompt'],
|
|
288
289
|
},
|
|
@@ -100,6 +100,9 @@ function coerceBoundedWaitMs(value) {
|
|
|
100
100
|
function shouldReturnQueuedReceipt(toolName, args) {
|
|
101
101
|
if (!SLOW_TOOLS.has(toolName))
|
|
102
102
|
return false;
|
|
103
|
+
if (toolName === 'nexus_orchestrate') {
|
|
104
|
+
return !isTruthyFlag(args.inline) && !isTruthyFlag(args.sync) && !isTruthyFlag(args.blocking);
|
|
105
|
+
}
|
|
103
106
|
return isTruthyFlag(args.background)
|
|
104
107
|
|| isTruthyFlag(args.async)
|
|
105
108
|
|| isTruthyFlag(args.queue)
|
|
@@ -157,29 +160,35 @@ function inferQueuedOrchestratePreview(args, runId) {
|
|
|
157
160
|
...asStringList(args.skillNames),
|
|
158
161
|
...extractLinkedSelectors(prompt, '$'),
|
|
159
162
|
], 20);
|
|
163
|
+
const isRuntimeControlPlane = /orchestrat|synapse|architect|runtime|mcp|dispatch|route|routing|queue|queued|scheduler|model routing|worker|hiring|workflow selection|token|budget|memory|lifecycle/.test(lower);
|
|
164
|
+
const wantsResearch = /research|paper|literature|deep-research|source-grounded|cited/.test(lower);
|
|
165
|
+
const wantsMemory = /memory|recall|learning|decay|graph|mcp/.test(lower);
|
|
166
|
+
const wantsPerf = /fast|faster|millisecond|latency|performance|budget|token|optim/i.test(lower);
|
|
160
167
|
const workflows = uniqueList([
|
|
161
168
|
...asStringList(args.workflows),
|
|
162
169
|
...asStringList(args.workflowSelectors),
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
170
|
+
isRuntimeControlPlane ? 'orchestration-execution-loop' : undefined,
|
|
171
|
+
isRuntimeControlPlane ? 'backend-execution-loop' : undefined,
|
|
172
|
+
isRuntimeControlPlane ? 'testing-execution-loop' : undefined,
|
|
173
|
+
isRuntimeControlPlane && !wantsResearch ? 'typescript-execution-loop' : undefined,
|
|
174
|
+
wantsResearch ? 'research-and-implement' : undefined,
|
|
175
|
+
lower.match(/dashboard|board|ui|ux/) && !isRuntimeControlPlane ? 'frontend-execution-loop' : undefined,
|
|
168
176
|
], 8);
|
|
169
177
|
const specialists = uniqueList([
|
|
170
178
|
...asStringList(args.specialists),
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
179
|
+
isRuntimeControlPlane ? 'Agents Orchestrator' : undefined,
|
|
180
|
+
isRuntimeControlPlane ? 'Backend Architect' : undefined,
|
|
181
|
+
isRuntimeControlPlane ? 'Workflow Optimizer' : undefined,
|
|
182
|
+
wantsPerf ? 'Performance Benchmarker' : undefined,
|
|
183
|
+
wantsMemory && !wantsPerf ? 'Backend Architect' : undefined,
|
|
184
|
+
lower.match(/dashboard|board|ui|ux/) && !isRuntimeControlPlane ? 'Frontend Developer' : undefined,
|
|
176
185
|
lower.match(/test|verify|qa|release|publish/) ? 'Verification Engineer' : undefined,
|
|
177
186
|
], 8);
|
|
178
187
|
const crew = String(args.crew ?? args.selectedCrew ?? (lower.match(/orchestrat|synapse|runtime|mcp|dispatch|queue|queued/)
|
|
179
|
-
? '
|
|
180
|
-
: lower.match(/
|
|
181
|
-
? '
|
|
182
|
-
: '
|
|
188
|
+
? 'Implementation Crew'
|
|
189
|
+
: lower.match(/research|paper|literature/)
|
|
190
|
+
? 'Research Crew'
|
|
191
|
+
: 'Implementation Crew'));
|
|
183
192
|
const risk = lower.match(/fix|broken|bug|doesn.?t|failed|queued|runtime|synapse|orchestrat/) ? 'high' : 'medium';
|
|
184
193
|
const task = {
|
|
185
194
|
goal: prompt,
|
|
@@ -479,6 +479,38 @@
|
|
|
479
479
|
color: var(--text-main); margin-bottom: 4px;
|
|
480
480
|
}
|
|
481
481
|
.frh-sub { font-size: var(--text-sm); color: var(--text-dim); }
|
|
482
|
+
.frh-steps {
|
|
483
|
+
display: grid;
|
|
484
|
+
grid-template-columns: repeat(3, minmax(0, 1fr));
|
|
485
|
+
gap: 8px;
|
|
486
|
+
margin-bottom: 14px;
|
|
487
|
+
}
|
|
488
|
+
.frh-step {
|
|
489
|
+
display: grid;
|
|
490
|
+
grid-template-columns: auto 1fr;
|
|
491
|
+
grid-template-rows: auto auto;
|
|
492
|
+
gap: 1px 8px;
|
|
493
|
+
align-items: center;
|
|
494
|
+
padding: 9px 10px;
|
|
495
|
+
border: 1px solid color-mix(in oklch, var(--accent) 24%, var(--border));
|
|
496
|
+
border-radius: var(--radius);
|
|
497
|
+
background: color-mix(in oklch, var(--accent) 4%, var(--bg-panel));
|
|
498
|
+
min-width: 0;
|
|
499
|
+
}
|
|
500
|
+
.frh-step span {
|
|
501
|
+
grid-row: 1 / span 2;
|
|
502
|
+
display: inline-grid;
|
|
503
|
+
place-items: center;
|
|
504
|
+
width: 22px;
|
|
505
|
+
height: 22px;
|
|
506
|
+
border-radius: 50%;
|
|
507
|
+
background: color-mix(in oklch, var(--accent) 18%, transparent);
|
|
508
|
+
color: var(--accent);
|
|
509
|
+
font-family: var(--font-mono);
|
|
510
|
+
font-size: 0.72rem;
|
|
511
|
+
}
|
|
512
|
+
.frh-step strong { font-size: 0.78rem; color: var(--text-main); min-width: 0; }
|
|
513
|
+
.frh-step small { font-size: 0.72rem; color: var(--text-dim); min-width: 0; }
|
|
482
514
|
.frh-command {
|
|
483
515
|
display: grid;
|
|
484
516
|
grid-template-columns: minmax(220px, 1fr) auto auto;
|
|
@@ -492,6 +524,7 @@
|
|
|
492
524
|
transition: border-color 0.15s;
|
|
493
525
|
}
|
|
494
526
|
.frh-pick:hover { border-color: var(--accent); }
|
|
527
|
+
.frh-pick-loading { border-style: dashed; }
|
|
495
528
|
.frh-pick-name { font-size: var(--text-sm); font-weight: var(--weight-semibold); color: var(--text-main); }
|
|
496
529
|
.frh-pick-desc { font-size: 0.78rem; color: var(--text-dim); flex: 1; }
|
|
497
530
|
.frh-pick-cost { font-family: var(--font-mono); font-size: 0.75rem; color: var(--accent); margin-top: 2px; }
|
|
@@ -507,6 +540,7 @@
|
|
|
507
540
|
}
|
|
508
541
|
@media (max-width: 768px) {
|
|
509
542
|
#kanban-board { grid-template-columns: repeat(2, 1fr); }
|
|
543
|
+
.frh-steps,
|
|
510
544
|
.frh-command,
|
|
511
545
|
.frh-picks { grid-template-columns: 1fr; }
|
|
512
546
|
}
|
|
@@ -376,7 +376,6 @@ function renderFirstRunHero() {
|
|
|
376
376
|
if (hasOps || (alreadySeen && hasRuns)) return;
|
|
377
377
|
|
|
378
378
|
const specs = (S.curatedSpecialists || []).slice(0, 3);
|
|
379
|
-
if (!specs.length) return; // Still loading — will re-render when prefetch resolves
|
|
380
379
|
const readiness = getHireReadiness();
|
|
381
380
|
const noticesHtml = readiness.notes.length
|
|
382
381
|
? `<div class="frh-notices" style="display:flex;flex-direction:column;gap:8px;margin-bottom:12px">
|
|
@@ -389,23 +388,33 @@ function renderFirstRunHero() {
|
|
|
389
388
|
card.className = 'first-run-hero card';
|
|
390
389
|
card.innerHTML = `
|
|
391
390
|
<div class="frh-header">
|
|
392
|
-
<div class="frh-title">${hasRuns ? '
|
|
393
|
-
<div class="frh-sub">${hasRuns ? 'Hire a specialist
|
|
391
|
+
<div class="frh-title">${hasRuns ? 'Choose the next worker' : 'Start the first real run'}</div>
|
|
392
|
+
<div class="frh-sub">${hasRuns ? 'Hire a specialist or queue a goal. Nexus will show the route, budget, workers, and verification here.' : 'Queue one goal from the dashboard. Nexus will route it, show who gets hired, and write the run trail into Board and Context Log.'}</div>
|
|
394
393
|
</div>
|
|
395
394
|
${noticesHtml}
|
|
395
|
+
<div class="frh-steps" aria-label="Onboarding steps">
|
|
396
|
+
<div class="frh-step"><span>1</span><strong>Describe goal</strong><small>Run or hire from here.</small></div>
|
|
397
|
+
<div class="frh-step"><span>2</span><strong>Watch route</strong><small>Board shows workers and budget.</small></div>
|
|
398
|
+
<div class="frh-step"><span>3</span><strong>Verify proof</strong><small>Context Log keeps artifacts.</small></div>
|
|
399
|
+
</div>
|
|
396
400
|
<div class="frh-command">
|
|
397
401
|
<input id="frh-goal-input" class="form-input" type="text" placeholder="Inspect this repo and suggest the next fix" autocomplete="off">
|
|
398
|
-
<button class="btn btn-primary btn-sm" id="frh-run-btn">Run goal</button>
|
|
402
|
+
<button class="btn btn-primary btn-sm" id="frh-run-btn">Run first goal</button>
|
|
399
403
|
<button class="btn btn-sm" id="frh-context-btn">Open context</button>
|
|
400
404
|
</div>
|
|
401
405
|
<div class="frh-picks">
|
|
402
|
-
${specs.map(s => `
|
|
406
|
+
${specs.length ? specs.map(s => `
|
|
403
407
|
<div class="frh-pick" data-specid="${esc(s.specialistId)}" data-specname="${esc(s.name)}">
|
|
404
408
|
<div class="frh-pick-name">${esc(s.name)}</div>
|
|
405
409
|
<div class="frh-pick-desc">${esc((s.description||'').slice(0, 72))}${(s.description||'').length > 72 ? '…' : ''}</div>
|
|
406
410
|
<div class="frh-pick-cost">~$${esc(String(s.pricing?.typical ?? '?'))}/sortie</div>
|
|
407
411
|
<button class="btn btn-primary btn-sm frh-hire-btn" data-specid="${esc(s.specialistId)}" data-specname="${esc(s.name)}" ${readiness.unavailable ? 'disabled title="Synapse is not ready"' : ''}>Hire</button>
|
|
408
|
-
</div>`).join('')
|
|
412
|
+
</div>`).join('') : `
|
|
413
|
+
<div class="frh-pick frh-pick-loading">
|
|
414
|
+
<div class="frh-pick-name">Specialists loading</div>
|
|
415
|
+
<div class="frh-pick-desc">You can run a goal immediately. Hiring picks will appear when the catalog responds.</div>
|
|
416
|
+
<div class="frh-pick-cost">route first, hire second</div>
|
|
417
|
+
</div>`}
|
|
409
418
|
</div>
|
|
410
419
|
<div id="frh-status" style="display:none;margin-top:12px;font-size:var(--text-sm)"></div>
|
|
411
420
|
<button class="btn btn-ghost btn-sm frh-dismiss" style="margin-top:var(--space-3)">Dismiss</button>`;
|
|
@@ -424,6 +433,7 @@ function renderFirstRunHero() {
|
|
|
424
433
|
const result = await post('/api/orchestrate', { goal, source: 'dashboard-onboarding' });
|
|
425
434
|
if (result.ok) {
|
|
426
435
|
setFirstRunStatus('Run queued. Board and Context Log will update as Nexus writes artifacts.');
|
|
436
|
+
try { localStorage.setItem(FIRST_RUN_KEY, '1'); } catch { /* ignore */ }
|
|
427
437
|
bustCache('/api/runs?limit=12');
|
|
428
438
|
bustCache('/api/events');
|
|
429
439
|
setTimeout(load, 900);
|
|
@@ -431,7 +441,7 @@ function renderFirstRunHero() {
|
|
|
431
441
|
setFirstRunStatus(result.error || 'Run failed to queue.', 'bad');
|
|
432
442
|
if (button) {
|
|
433
443
|
button.disabled = false;
|
|
434
|
-
button.textContent = 'Run goal';
|
|
444
|
+
button.textContent = 'Run first goal';
|
|
435
445
|
}
|
|
436
446
|
}
|
|
437
447
|
});
|
|
@@ -508,6 +518,21 @@ function buildKanbanCols() {
|
|
|
508
518
|
if (sg) cols[sg].push({id:w.id||w.workerId||w.goal,goal:w.goal||w.task||w.approach||'(worker)',status:st,tokens:w.tokensUsed||w.budget,time:w.startedAt||w.createdAt,role:w.role});
|
|
509
519
|
}
|
|
510
520
|
}
|
|
521
|
+
const ghost = S.lastDecomposition?.autoGhostPass || S.lastCompletion?.autoGhostPass || op?.orchestration?.autoGhostPass || op?.autoGhostPass;
|
|
522
|
+
if (ghost && (ghost.applied || ghost.policy?.reason)) {
|
|
523
|
+
const risks = Array.isArray(ghost.riskAreas) ? ghost.riskAreas.length : 0;
|
|
524
|
+
const reason = ghost.policy?.reason ? ` · ${ghost.policy.reason}` : '';
|
|
525
|
+
cols.ghostpass.push({
|
|
526
|
+
id: 'auto-ghostpass',
|
|
527
|
+
goal: ghost.applied
|
|
528
|
+
? `Auto Ghost Pass: ${risks} risk area${risks === 1 ? '' : 's'}, ${ghost.workerApproaches || 0} approach${ghost.workerApproaches === 1 ? '' : 'es'}`
|
|
529
|
+
: `Auto Ghost Pass skipped${reason}`,
|
|
530
|
+
status: ghost.applied ? 'reviewing' : 'skipped',
|
|
531
|
+
tokens: ghost.estimatedTokens,
|
|
532
|
+
time: S.lastDecomposition?.ts || S.lastCompletion?.ts,
|
|
533
|
+
role: 'ghost-pass',
|
|
534
|
+
});
|
|
535
|
+
}
|
|
511
536
|
for (const r of (S.runs||[]).slice(0,8)) {
|
|
512
537
|
const runId = r.runId || r.id;
|
|
513
538
|
if (!runId) continue;
|
|
@@ -874,11 +899,16 @@ function renderOrchestrationPipeline() {
|
|
|
874
899
|
const more = arr.length > 6 ? ` <span style="color:var(--muted)">+${arr.length - 6}</span>` : '';
|
|
875
900
|
return `<div style="margin:4px 0"><span style="color:var(--muted);font-size:11px;text-transform:uppercase;letter-spacing:0.5px">${esc(label)}</span> <span style="font-family:var(--font-mono);font-size:12px">${head}${more}</span></div>`;
|
|
876
901
|
};
|
|
902
|
+
const ghostChip = (ghost) => ghost
|
|
903
|
+
? chip('ghost-pass', ghost.applied
|
|
904
|
+
? `${ghost.riskAreas?.length ?? 0} risks · ${ghost.workerApproaches ?? 0} approaches`
|
|
905
|
+
: `skipped${ghost.policy?.reason ? ` · ${ghost.policy.reason}` : ''}`)
|
|
906
|
+
: '';
|
|
877
907
|
const decBlock = dec ? `
|
|
878
908
|
<div style="border-left:3px solid var(--accent);padding:8px 12px;margin-bottom:8px">
|
|
879
909
|
<div style="font-size:13px;font-weight:600;margin-bottom:4px">Decomposition · run ${esc((dec.runId || '').slice(-8))}</div>
|
|
880
910
|
<div style="font-size:12px;color:var(--muted);margin-bottom:6px">${esc(dec.goal || '')}</div>
|
|
881
|
-
<div>${chip('intent', dec.intent || 'auto')}${chip('crew', dec.crew || 'baseline')}${chip('workers', dec.workers ?? 0)}${chip('phases', dec.phases ?? 0)}</div>
|
|
911
|
+
<div>${chip('intent', dec.intent || 'auto')}${chip('crew', dec.crew || 'baseline')}${chip('workers', dec.workers ?? 0)}${chip('phases', dec.phases ?? 0)}${ghostChip(dec.autoGhostPass)}</div>
|
|
882
912
|
${chipList('specialists', dec.specialists)}
|
|
883
913
|
${chipList('skills', dec.skills)}
|
|
884
914
|
${chipList('files', dec.files)}
|
|
@@ -888,7 +918,7 @@ function renderOrchestrationPipeline() {
|
|
|
888
918
|
<div style="border-left:3px solid ${stateColor(cmpState)};padding:8px 12px">
|
|
889
919
|
<div style="font-size:13px;font-weight:600;margin-bottom:4px">Completion · run ${esc((cmp.runId || '').slice(-8))} · <span style="color:${stateColor(cmpState)}">${esc(cmpState || '')}</span></div>
|
|
890
920
|
<div style="font-size:12px;color:var(--muted);margin-bottom:6px">${esc(cmp.result || '')}</div>
|
|
891
|
-
<div>${chip('verified', `${cmp.verifiedWorkers ?? 0}/${cmp.totalWorkers ?? 0}`)}${chip('saved', `${fmtNum(cmp.savedTokens ?? 0)} t`)}${chip('compression', `${cmp.compressionPct ?? 0}%`)}${chip('duration', `${Math.round((cmp.durationMs ?? 0) / 100) / 10}s`)}</div>
|
|
921
|
+
<div>${chip('verified', `${cmp.verifiedWorkers ?? 0}/${cmp.totalWorkers ?? 0}`)}${chip('saved', `${fmtNum(cmp.savedTokens ?? 0)} t`)}${chip('compression', `${cmp.compressionPct ?? 0}%`)}${chip('duration', `${Math.round((cmp.durationMs ?? 0) / 100) / 10}s`)}${ghostChip(cmp.autoGhostPass)}</div>
|
|
892
922
|
</div>` : '';
|
|
893
923
|
const spineBlock = spine ? _buildDecisionSpineMiniHtml(spine) : '';
|
|
894
924
|
const headerNote = same ? '' : (dec && cmp ? '<div style="font-size:11px;color:var(--muted);margin-bottom:6px">Showing latest decomposition + most recent completion (different runs)</div>' : '');
|
|
@@ -93,6 +93,16 @@ export interface NexusEventPayloads {
|
|
|
93
93
|
files: string[];
|
|
94
94
|
workers: number;
|
|
95
95
|
phases: number;
|
|
96
|
+
autoGhostPass?: {
|
|
97
|
+
applied: boolean;
|
|
98
|
+
riskAreas: string[];
|
|
99
|
+
workerApproaches: number;
|
|
100
|
+
estimatedTokens: number;
|
|
101
|
+
policy?: {
|
|
102
|
+
enabled?: boolean;
|
|
103
|
+
reason?: string;
|
|
104
|
+
};
|
|
105
|
+
};
|
|
96
106
|
};
|
|
97
107
|
'orchestration.completed': {
|
|
98
108
|
runId: string;
|
|
@@ -104,6 +114,12 @@ export interface NexusEventPayloads {
|
|
|
104
114
|
compressionPct: number;
|
|
105
115
|
durationMs: number;
|
|
106
116
|
result: string;
|
|
117
|
+
autoGhostPass?: {
|
|
118
|
+
applied: boolean;
|
|
119
|
+
riskAreas: string[];
|
|
120
|
+
workerApproaches: number;
|
|
121
|
+
estimatedTokens: number;
|
|
122
|
+
};
|
|
107
123
|
};
|
|
108
124
|
'session.summaryBootstrap': {
|
|
109
125
|
originalTokens: number;
|
|
@@ -183,6 +183,8 @@ export declare class OrchestratorEngine {
|
|
|
183
183
|
private searchIndexedRepoCandidates;
|
|
184
184
|
private toFileRef;
|
|
185
185
|
private resolveSelections;
|
|
186
|
+
private inferRuntimeCatalogHints;
|
|
187
|
+
private filterExistingCatalogSelectors;
|
|
186
188
|
private getSkillCatalogItems;
|
|
187
189
|
private getWorkflowCatalogItems;
|
|
188
190
|
private getHookCatalogItems;
|
|
@@ -1036,7 +1036,7 @@ export class OrchestratorEngine {
|
|
|
1036
1036
|
// Non-fatal: bootstrap receipt is a safety net, not a hard dependency
|
|
1037
1037
|
}
|
|
1038
1038
|
const [army, prepared] = await this.runParallelPhases(this.induce(task), this._prepareExecution(task, options));
|
|
1039
|
-
const { intent, phases, primaryClient, bootstrapManifest, latestDNA, memoryMatches, memoryStats, candidateFiles, knowledgeFabric, plannedFiles, planner, selections, catalogHealth, tokenBudget, workerCount, mode, taskGraph, workerPlan, autoGhostPass, crSignals, } = prepared;
|
|
1039
|
+
const { intent, phases, primaryClient, bootstrapManifest, latestDNA, memoryMatches, memoryStats, candidateFiles, knowledgeFabric, plannedFiles, planner, selections, catalogHealth, tokenBudget, workerCount, mode, taskGraph, workerPlan, autoGhostPass, autoGhostPassDecision, crSignals, } = prepared;
|
|
1040
1040
|
this.runtime.recordClientToolCall('nexus_orchestrate', {
|
|
1041
1041
|
orchestrateCalled: true,
|
|
1042
1042
|
plannerCalled: true,
|
|
@@ -1314,6 +1314,8 @@ export class OrchestratorEngine {
|
|
|
1314
1314
|
instructionPacket,
|
|
1315
1315
|
executionLedger: ledger,
|
|
1316
1316
|
knowledgeFabric,
|
|
1317
|
+
autoGhostPass,
|
|
1318
|
+
autoGhostPassDecision,
|
|
1317
1319
|
});
|
|
1318
1320
|
this.executionDedupeStore.set(fingerprint, {
|
|
1319
1321
|
id: ledger.runId,
|
|
@@ -2382,10 +2384,16 @@ export class OrchestratorEngine {
|
|
|
2382
2384
|
limit: 5,
|
|
2383
2385
|
selector: 'name',
|
|
2384
2386
|
});
|
|
2385
|
-
const
|
|
2387
|
+
const runtimeCatalogHints = this.inferRuntimeCatalogHints(task, intent, {
|
|
2388
|
+
workflows: allWorkflowItems,
|
|
2389
|
+
specialists: allSpecialistItems,
|
|
2390
|
+
crews: allCrewItems,
|
|
2391
|
+
});
|
|
2392
|
+
const workflowSelection = this.resolveCatalogVotes('workflow', task, intent, options.workflowSelectors?.length || runtimeCatalogHints.workflows.length ? allWorkflowItems : workflowItems, {
|
|
2386
2393
|
explicit: options.workflowSelectors,
|
|
2387
2394
|
planner: planner.selectedWorkflows,
|
|
2388
2395
|
knowledge: knowledgeFabric.recommendations.workflows,
|
|
2396
|
+
runtime: runtimeCatalogHints.workflows,
|
|
2389
2397
|
scorerLimit: 4,
|
|
2390
2398
|
limit: 4,
|
|
2391
2399
|
selector: 'name',
|
|
@@ -2423,18 +2431,20 @@ export class OrchestratorEngine {
|
|
|
2423
2431
|
limit: intent.taskType === 'release' || this.sessionState.repeatedFailures > 0 ? 3 : 2,
|
|
2424
2432
|
selector: 'name',
|
|
2425
2433
|
});
|
|
2426
|
-
const specialistSelection = this.resolveCatalogVotes('specialist', task, intent, options.specialistSelectors?.length ? allSpecialistItems : specialistItems, {
|
|
2434
|
+
const specialistSelection = this.resolveCatalogVotes('specialist', task, intent, options.specialistSelectors?.length || runtimeCatalogHints.specialists.length ? allSpecialistItems : specialistItems, {
|
|
2427
2435
|
explicit: options.specialistSelectors,
|
|
2428
2436
|
planner: planner.selectedSpecialists.map((specialist) => specialist.specialistId),
|
|
2429
2437
|
knowledge: knowledgeFabric.recommendations.specialists,
|
|
2438
|
+
runtime: runtimeCatalogHints.specialists,
|
|
2430
2439
|
scorerLimit: 4,
|
|
2431
2440
|
limit: 4,
|
|
2432
2441
|
selector: 'id',
|
|
2433
2442
|
});
|
|
2434
|
-
const crewSelection = this.resolveCatalogVotes('crew', task, intent, options.crewSelectors?.length ? allCrewItems : crewItems, {
|
|
2443
|
+
const crewSelection = this.resolveCatalogVotes('crew', task, intent, options.crewSelectors?.length || runtimeCatalogHints.crews.length ? allCrewItems : crewItems, {
|
|
2435
2444
|
explicit: options.crewSelectors,
|
|
2436
2445
|
planner: planner.selectedCrew ? [planner.selectedCrew.crewId] : [],
|
|
2437
2446
|
knowledge: knowledgeFabric.recommendations.crews,
|
|
2447
|
+
runtime: runtimeCatalogHints.crews,
|
|
2438
2448
|
scorerLimit: 2,
|
|
2439
2449
|
limit: 1,
|
|
2440
2450
|
selector: 'id',
|
|
@@ -2504,6 +2514,47 @@ export class OrchestratorEngine {
|
|
|
2504
2514
|
},
|
|
2505
2515
|
};
|
|
2506
2516
|
}
|
|
2517
|
+
inferRuntimeCatalogHints(task, intent, catalog) {
|
|
2518
|
+
const lower = task.toLowerCase();
|
|
2519
|
+
const isControlPlane = /\b(orchestrat(?:e|or|ion)|synapse|architects?|mcp|dispatch|routing|route|queued?|queue|scheduler|runtime|control plane|agentflow|worker|hiring|specialist|crew|workflow selection|model routing|token budget|memory hook|memory graph|lifecycle)\b/.test(lower);
|
|
2520
|
+
if (!isControlPlane) {
|
|
2521
|
+
return { workflows: [], specialists: [], crews: [] };
|
|
2522
|
+
}
|
|
2523
|
+
const wantsResearch = /\b(research|papers?|literature|source-grounded|cited|deep-research)\b/.test(lower);
|
|
2524
|
+
const wantsMemory = /\b(memory|recall|learning|decay|graph|mcp)\b/.test(lower);
|
|
2525
|
+
const wantsPerf = /\b(fast|faster|milliseconds?|latency|performance|budget|token|optim(?:i|is|iz))\b/.test(lower);
|
|
2526
|
+
const readOnlyResearch = intent.taskType === 'research'
|
|
2527
|
+
&& !/\b(fix|patch|implement|refactor|change|add|wire|ship|deploy|release|mutate|improve)\b/.test(lower);
|
|
2528
|
+
const workflowSelectors = [
|
|
2529
|
+
'orchestration-execution-loop',
|
|
2530
|
+
'backend-execution-loop',
|
|
2531
|
+
'testing-execution-loop',
|
|
2532
|
+
wantsResearch ? 'research-and-implement' : 'typescript-execution-loop',
|
|
2533
|
+
];
|
|
2534
|
+
const specialistSelectors = [
|
|
2535
|
+
'specialist_specialized-agents-orchestrator',
|
|
2536
|
+
'specialist_engineering-engineering-backend-architect',
|
|
2537
|
+
'specialist_testing-testing-workflow-optimizer',
|
|
2538
|
+
wantsPerf
|
|
2539
|
+
? 'specialist_testing-testing-performance-benchmarker'
|
|
2540
|
+
: wantsMemory
|
|
2541
|
+
? 'specialist_integrations-mcp-memory-backend-architect-with-memory'
|
|
2542
|
+
: undefined,
|
|
2543
|
+
];
|
|
2544
|
+
const crewSelectors = [
|
|
2545
|
+
readOnlyResearch ? 'crew_research' : 'crew_implementation',
|
|
2546
|
+
];
|
|
2547
|
+
return {
|
|
2548
|
+
workflows: this.filterExistingCatalogSelectors(catalog.workflows, workflowSelectors, 'name'),
|
|
2549
|
+
specialists: this.filterExistingCatalogSelectors(catalog.specialists, specialistSelectors, 'id'),
|
|
2550
|
+
crews: this.filterExistingCatalogSelectors(catalog.crews, crewSelectors, 'id'),
|
|
2551
|
+
};
|
|
2552
|
+
}
|
|
2553
|
+
filterExistingCatalogSelectors(items, selectors, selector) {
|
|
2554
|
+
const existing = new Set(items.map((item) => selector === 'id' ? item.id : item.name));
|
|
2555
|
+
return dedupeStrings(selectors.filter((value) => Boolean(value)))
|
|
2556
|
+
.filter((value) => existing.has(value));
|
|
2557
|
+
}
|
|
2507
2558
|
getSkillCatalogItems() {
|
|
2508
2559
|
const skills = this.runtime.listSkillsForSelection();
|
|
2509
2560
|
const signature = skills
|
|
@@ -2657,7 +2708,7 @@ export class OrchestratorEngine {
|
|
|
2657
2708
|
applyVote(value, 'knowledge-fabric', 0.76, 'medium', 'Knowledge Fabric recommended this artifact from cross-source evidence.');
|
|
2658
2709
|
});
|
|
2659
2710
|
(input.runtime ?? []).forEach((value) => {
|
|
2660
|
-
applyVote(value, 'runtime-resolver', 0
|
|
2711
|
+
applyVote(value, 'runtime-resolver', 2.0, 'high', 'Runtime resolver matched this artifact against the registered catalog for the active goal.');
|
|
2661
2712
|
});
|
|
2662
2713
|
this.pickCatalogEntries(task, intent, items, input.scorerLimit).forEach((entry) => {
|
|
2663
2714
|
applyVote(input.selector === 'id' ? entry.item.id : entry.item.name, 'scorer', Math.min(0.7, entry.score / 10), entry.score >= 9 ? 'medium' : 'low', `Keyword scorer matched the task with score ${entry.score}.`);
|
|
@@ -24,6 +24,10 @@ export function getNexusHookSpec() {
|
|
|
24
24
|
matcher: 'Edit|Write|MultiEdit',
|
|
25
25
|
hooks: [{ type: 'command', command: 'nexus-prime hook mindkit', timeout: 10 }],
|
|
26
26
|
},
|
|
27
|
+
{
|
|
28
|
+
matcher: 'MultiEdit',
|
|
29
|
+
hooks: [{ type: 'command', command: 'nexus-prime hook ghost-pass', timeout: 15 }],
|
|
30
|
+
},
|
|
27
31
|
],
|
|
28
32
|
PostToolUse: [
|
|
29
33
|
{
|
|
@@ -101,6 +101,12 @@ export interface ExecutionTask {
|
|
|
101
101
|
instructionPacket?: InstructionPacket;
|
|
102
102
|
executionLedger?: ExecutionLedger;
|
|
103
103
|
knowledgeFabric?: KnowledgeFabricBundle;
|
|
104
|
+
autoGhostPass?: GhostReport;
|
|
105
|
+
autoGhostPassDecision?: {
|
|
106
|
+
enabled: boolean;
|
|
107
|
+
reason: string;
|
|
108
|
+
contextHash?: string;
|
|
109
|
+
};
|
|
104
110
|
}
|
|
105
111
|
export interface WorkerSkillOverlay {
|
|
106
112
|
base: string[];
|
package/dist/phantom/runtime.js
CHANGED
|
@@ -225,6 +225,16 @@ export class SubAgentRuntime {
|
|
|
225
225
|
files: (task.files ?? []).slice(0, 24),
|
|
226
226
|
workers: planner.plannerState.selectedSpecialists.length || 1,
|
|
227
227
|
phases: planner.plannerState.ledger.length,
|
|
228
|
+
autoGhostPass: {
|
|
229
|
+
applied: Boolean(task.autoGhostPass),
|
|
230
|
+
riskAreas: task.autoGhostPass?.riskAreas ?? [],
|
|
231
|
+
workerApproaches: task.autoGhostPass?.workerAssignments?.length ?? 0,
|
|
232
|
+
estimatedTokens: task.autoGhostPass?.totalEstimatedTokens ?? 0,
|
|
233
|
+
policy: task.autoGhostPassDecision ? {
|
|
234
|
+
enabled: task.autoGhostPassDecision.enabled,
|
|
235
|
+
reason: task.autoGhostPassDecision.reason,
|
|
236
|
+
} : undefined,
|
|
237
|
+
},
|
|
228
238
|
});
|
|
229
239
|
}
|
|
230
240
|
catch { /* best-effort */ }
|
|
@@ -765,6 +775,12 @@ export class SubAgentRuntime {
|
|
|
765
775
|
compressionPct: Number(tt?.compressionPct ?? 0),
|
|
766
776
|
durationMs: Date.now() - runStartedAt,
|
|
767
777
|
result: String(applied.summary ?? '').slice(0, 280),
|
|
778
|
+
autoGhostPass: {
|
|
779
|
+
applied: Boolean(task.autoGhostPass),
|
|
780
|
+
riskAreas: task.autoGhostPass?.riskAreas ?? [],
|
|
781
|
+
workerApproaches: task.autoGhostPass?.workerAssignments?.length ?? 0,
|
|
782
|
+
estimatedTokens: task.autoGhostPass?.totalEstimatedTokens ?? 0,
|
|
783
|
+
},
|
|
768
784
|
});
|
|
769
785
|
}
|
|
770
786
|
catch { /* best-effort */ }
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nexus-prime",
|
|
3
|
-
"version": "7.9.
|
|
3
|
+
"version": "7.9.26",
|
|
4
4
|
"description": "Local-first MCP control plane for coding agents with bootstrap-orchestrate execution, memory fabric, token budgeting, and worktree-backed swarms",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|