nexus-prime 7.9.5 → 7.9.7
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/async-gate.d.ts +2 -0
- package/dist/agents/adapters/mcp/async-gate.js +13 -4
- package/dist/agents/adapters/mcp/dispatch.js +7 -1
- package/dist/agents/adapters/mcp/types.d.ts +6 -0
- package/dist/agents/adapters/mcp/types.js +41 -3
- package/dist/agents/adapters/mcp.d.ts +1 -0
- package/dist/agents/adapters/mcp.js +49 -3
- package/dist/cli.js +7 -3
- package/dist/engines/orchestrator.js +8 -0
- package/dist/engines/runtime-assets.js +107 -32
- package/dist/engines/token-supremacy.d.ts +1 -1
- package/dist/engines/token-supremacy.js +11 -2
- package/dist/phantom/runtime/worktree.js +2 -2
- package/dist/phantom/runtime.d.ts +2 -0
- package/dist/phantom/runtime.js +14 -7
- package/package.json +1 -1
|
@@ -41,6 +41,8 @@ export interface AsyncGateOpts {
|
|
|
41
41
|
maxSyncMs?: number;
|
|
42
42
|
/** Human-readable hint for estimated duration */
|
|
43
43
|
etaMs?: number;
|
|
44
|
+
/** Return the async receipt before starting work. Use for cold paths that may block synchronously. */
|
|
45
|
+
alwaysQueue?: boolean;
|
|
44
46
|
}
|
|
45
47
|
type HandlerFn = () => Promise<{
|
|
46
48
|
content: Array<{
|
|
@@ -33,10 +33,7 @@ class AsyncGate {
|
|
|
33
33
|
etaMs: opts.etaMs,
|
|
34
34
|
};
|
|
35
35
|
this.enqueueJob(job);
|
|
36
|
-
|
|
37
|
-
let syncResolved = false;
|
|
38
|
-
const deadline = new Promise((resolve) => setTimeout(() => resolve(null), maxSyncMs));
|
|
39
|
-
const work = (async () => {
|
|
36
|
+
const startWork = () => (async () => {
|
|
40
37
|
job.status = 'running';
|
|
41
38
|
job.stage = 'executing';
|
|
42
39
|
job.startedAt = Date.now();
|
|
@@ -64,6 +61,18 @@ class AsyncGate {
|
|
|
64
61
|
};
|
|
65
62
|
}
|
|
66
63
|
})();
|
|
64
|
+
if (opts.alwaysQueue) {
|
|
65
|
+
setImmediate(() => {
|
|
66
|
+
startWork().catch(() => { });
|
|
67
|
+
});
|
|
68
|
+
return { queued: true, runId, etaMs: opts.etaMs };
|
|
69
|
+
}
|
|
70
|
+
// Race: handler vs deadline. Note: this only protects paths that yield
|
|
71
|
+
// quickly. Cold synchronous work should set alwaysQueue so the receipt is
|
|
72
|
+
// returned before the heavy section starts.
|
|
73
|
+
let syncResolved = false;
|
|
74
|
+
const deadline = new Promise((resolve) => setTimeout(() => resolve(null), maxSyncMs));
|
|
75
|
+
const work = startWork();
|
|
67
76
|
// Suppress unhandled rejection: deadline may win while work is still in flight.
|
|
68
77
|
work.catch(() => { });
|
|
69
78
|
const winner = await Promise.race([
|
|
@@ -124,7 +124,13 @@ export async function dispatchMcpToolCall(hctx, request, args, ctx) {
|
|
|
124
124
|
const gated = await withAsyncGate(async () => {
|
|
125
125
|
const r = await runHandlers();
|
|
126
126
|
return r ?? { content: [{ type: 'text', text: `Tool ${toolName} returned no result` }] };
|
|
127
|
-
}, {
|
|
127
|
+
}, {
|
|
128
|
+
tool: toolName,
|
|
129
|
+
args,
|
|
130
|
+
maxSyncMs: 2000,
|
|
131
|
+
etaMs: TOOL_ETA_MS[toolName],
|
|
132
|
+
alwaysQueue: toolName === 'nexus_orchestrate',
|
|
133
|
+
});
|
|
128
134
|
if ('queued' in gated && gated.queued) {
|
|
129
135
|
// Persist orchestration run record for durable stage tracking
|
|
130
136
|
if (toolName === 'nexus_orchestrate') {
|
|
@@ -35,6 +35,8 @@ export declare class SessionTelemetry {
|
|
|
35
35
|
private fileIntentPaths;
|
|
36
36
|
private tokenAutoApplied;
|
|
37
37
|
private stickyTokenOptimization;
|
|
38
|
+
private tokenOptimizationPending;
|
|
39
|
+
private orchestrationPending;
|
|
38
40
|
bootstrapped: boolean;
|
|
39
41
|
bootstrapCallCount: number;
|
|
40
42
|
recordCall(): void;
|
|
@@ -54,12 +56,16 @@ export declare class SessionTelemetry {
|
|
|
54
56
|
fileReadIntentCount: number;
|
|
55
57
|
callsSinceOrchestrate: number;
|
|
56
58
|
tokenAutoApplied: boolean;
|
|
59
|
+
tokenOptimizationPending: boolean;
|
|
60
|
+
orchestrationPending: boolean;
|
|
57
61
|
};
|
|
58
62
|
elapsedMs(): number;
|
|
59
63
|
advancePhase(nextPhase: LifecyclePhase): void;
|
|
60
64
|
observeSuccessfulToolCall(toolName: string, args: Record<string, unknown>): void;
|
|
65
|
+
observeQueuedToolCall(toolName: string, args: Record<string, unknown>): void;
|
|
61
66
|
needsOptimizeTokens(currentToolName?: string): boolean;
|
|
62
67
|
markTokenAutoApplied(): void;
|
|
68
|
+
needsOrchestration(currentToolName?: string): boolean;
|
|
63
69
|
needsStoreMemory(currentToolName?: string): boolean;
|
|
64
70
|
needsSessionDna(currentToolName?: string): boolean;
|
|
65
71
|
notifyStore(priority: number, tags: string[], memStats: {
|
|
@@ -24,6 +24,8 @@ export class SessionTelemetry {
|
|
|
24
24
|
fileIntentPaths = new Set();
|
|
25
25
|
tokenAutoApplied = false;
|
|
26
26
|
stickyTokenOptimization = false;
|
|
27
|
+
tokenOptimizationPending = false;
|
|
28
|
+
orchestrationPending = false;
|
|
27
29
|
bootstrapped = false;
|
|
28
30
|
bootstrapCallCount = 0;
|
|
29
31
|
recordCall() {
|
|
@@ -49,6 +51,8 @@ export class SessionTelemetry {
|
|
|
49
51
|
fileReadIntentCount: this.fileReadIntentCount,
|
|
50
52
|
callsSinceOrchestrate: this.callsSinceOrchestrate,
|
|
51
53
|
tokenAutoApplied: this.tokenAutoApplied,
|
|
54
|
+
tokenOptimizationPending: this.tokenOptimizationPending,
|
|
55
|
+
orchestrationPending: this.orchestrationPending,
|
|
52
56
|
};
|
|
53
57
|
}
|
|
54
58
|
elapsedMs() {
|
|
@@ -69,8 +73,10 @@ export class SessionTelemetry {
|
|
|
69
73
|
this.optimizeTokensCalled = false;
|
|
70
74
|
this.tokenAutoApplied = false;
|
|
71
75
|
}
|
|
76
|
+
this.tokenOptimizationPending = false;
|
|
72
77
|
}
|
|
73
78
|
if (nextPhase === 'orchestrated') {
|
|
79
|
+
this.orchestrationPending = false;
|
|
74
80
|
this.mindkitCheckCalled = false;
|
|
75
81
|
this.storeMemoryCalledPostOrchestrate = false;
|
|
76
82
|
this.sessionDnaCalled = false;
|
|
@@ -85,12 +91,17 @@ export class SessionTelemetry {
|
|
|
85
91
|
return;
|
|
86
92
|
}
|
|
87
93
|
if (toolName === 'nexus_orchestrate') {
|
|
94
|
+
this.stickyTokenOptimization = true;
|
|
88
95
|
this.advancePhase('orchestrated');
|
|
96
|
+
this.optimizeTokensCalled = true;
|
|
97
|
+
this.tokenAutoApplied = true;
|
|
98
|
+
this.tokenOptimizationPending = false;
|
|
89
99
|
this.noteFileIntent(args.files);
|
|
90
100
|
return;
|
|
91
101
|
}
|
|
92
102
|
if (toolName === 'nexus_optimize_tokens') {
|
|
93
103
|
this.optimizeTokensCalled = true;
|
|
104
|
+
this.tokenOptimizationPending = false;
|
|
94
105
|
if (this.lifecyclePhase === 'orchestrated')
|
|
95
106
|
this.advancePhase('working');
|
|
96
107
|
this.noteFileIntent(args.files);
|
|
@@ -126,6 +137,20 @@ export class SessionTelemetry {
|
|
|
126
137
|
this.advancePhase('working');
|
|
127
138
|
}
|
|
128
139
|
}
|
|
140
|
+
observeQueuedToolCall(toolName, args) {
|
|
141
|
+
if (toolName === 'nexus_orchestrate') {
|
|
142
|
+
this.orchestrationPending = true;
|
|
143
|
+
this.tokenOptimizationPending = true;
|
|
144
|
+
this.optimizeTokensCalled = true;
|
|
145
|
+
this.noteFileIntent(args.files);
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
if (toolName === 'nexus_optimize_tokens') {
|
|
149
|
+
this.tokenOptimizationPending = true;
|
|
150
|
+
this.optimizeTokensCalled = true;
|
|
151
|
+
this.noteFileIntent(args.files);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
129
154
|
needsOptimizeTokens(currentToolName) {
|
|
130
155
|
if (currentToolName === 'nexus_optimize_tokens')
|
|
131
156
|
return false;
|
|
@@ -133,12 +158,26 @@ export class SessionTelemetry {
|
|
|
133
158
|
return false;
|
|
134
159
|
if (this.tokenAutoApplied)
|
|
135
160
|
return false;
|
|
161
|
+
if (this.tokenOptimizationPending)
|
|
162
|
+
return false;
|
|
136
163
|
return this.fileReadIntentCount >= 1 && !this.optimizeTokensCalled;
|
|
137
164
|
}
|
|
138
165
|
markTokenAutoApplied() {
|
|
139
166
|
this.tokenAutoApplied = true;
|
|
140
167
|
this.optimizeTokensCalled = true;
|
|
141
168
|
this.stickyTokenOptimization = true;
|
|
169
|
+
this.tokenOptimizationPending = false;
|
|
170
|
+
}
|
|
171
|
+
needsOrchestration(currentToolName) {
|
|
172
|
+
if (currentToolName === 'nexus_orchestrate')
|
|
173
|
+
return false;
|
|
174
|
+
if (this.lifecyclePhase === 'pre-bootstrap')
|
|
175
|
+
return false;
|
|
176
|
+
if (this.lifecyclePhase === 'orchestrated' || this.lifecyclePhase === 'working' || this.lifecyclePhase === 'closing')
|
|
177
|
+
return false;
|
|
178
|
+
if (this.orchestrationPending)
|
|
179
|
+
return false;
|
|
180
|
+
return this.bootstrapped && this.lifecyclePhase === 'bootstrapped';
|
|
142
181
|
}
|
|
143
182
|
needsStoreMemory(currentToolName) {
|
|
144
183
|
if (currentToolName === 'nexus_store_memory')
|
|
@@ -184,9 +223,8 @@ export class SessionTelemetry {
|
|
|
184
223
|
}
|
|
185
224
|
break;
|
|
186
225
|
case 'store':
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
}
|
|
226
|
+
// Storing memory completes the lifecycle step; do not create a
|
|
227
|
+
// self-referential "store again" loop.
|
|
190
228
|
break;
|
|
191
229
|
case 'mindkit_fail':
|
|
192
230
|
nudges.push('Guardrail FAILED. Do NOT proceed. Re-scope the task or call nexus_ghost_pass for a safer approach.');
|
|
@@ -41,6 +41,7 @@ export declare class MCPAdapter implements Adapter {
|
|
|
41
41
|
private formatRemainingProtocolSteps;
|
|
42
42
|
private prependTextToResponse;
|
|
43
43
|
private decorateLifecycleResponse;
|
|
44
|
+
private buildPreOrchestrationBlock;
|
|
44
45
|
private extractGoalLikeText;
|
|
45
46
|
private isMemoryTool;
|
|
46
47
|
private injectMemoryContext;
|
|
@@ -124,6 +124,23 @@ const PRE_BOOTSTRAP_ALLOWED_TOOLS = new Set([
|
|
|
124
124
|
'nexus_list_specialists',
|
|
125
125
|
'nexus_list_crews',
|
|
126
126
|
]);
|
|
127
|
+
const PRE_ORCHESTRATE_ALLOWED_TOOLS = new Set([
|
|
128
|
+
...PRE_BOOTSTRAP_ALLOWED_TOOLS,
|
|
129
|
+
'nexus_orchestrate',
|
|
130
|
+
'nexus_plan_execution',
|
|
131
|
+
'nexus_recall_memory',
|
|
132
|
+
'nexus_temporal_query',
|
|
133
|
+
'nexus_store_memory',
|
|
134
|
+
'nexus_search',
|
|
135
|
+
'nexus_optimize_tokens',
|
|
136
|
+
'nexus_mindkit_check',
|
|
137
|
+
'nexus_ghost_pass',
|
|
138
|
+
'nexus_token_report',
|
|
139
|
+
'nexus_session_dna',
|
|
140
|
+
'nexus_run_status',
|
|
141
|
+
'nexus_selection_ledger',
|
|
142
|
+
'nexus_license_usage',
|
|
143
|
+
]);
|
|
127
144
|
export class MCPAdapter {
|
|
128
145
|
name;
|
|
129
146
|
type = 'mcp';
|
|
@@ -513,6 +530,24 @@ export class MCPAdapter {
|
|
|
513
530
|
],
|
|
514
531
|
};
|
|
515
532
|
}
|
|
533
|
+
buildPreOrchestrationBlock(toolName) {
|
|
534
|
+
if (!this.telemetry.needsOrchestration(toolName))
|
|
535
|
+
return null;
|
|
536
|
+
if (PRE_ORCHESTRATE_ALLOWED_TOOLS.has(toolName) || isReadOnlyMcpTool(toolName))
|
|
537
|
+
return null;
|
|
538
|
+
return {
|
|
539
|
+
content: [{
|
|
540
|
+
type: 'text',
|
|
541
|
+
text: JSON.stringify({
|
|
542
|
+
status: 'blocked',
|
|
543
|
+
code: 'orchestration-required',
|
|
544
|
+
reason: 'nexus_orchestrate has not been called for this session',
|
|
545
|
+
action: 'Call nexus_orchestrate(prompt="<your task>") before invoking mutation, worker, kernel, hook, automation, or low-level execution tools.',
|
|
546
|
+
hint: 'Nexus Prime must own planning, token budgeting, memory recall, hooks, and review gates before work starts.',
|
|
547
|
+
}, null, 2),
|
|
548
|
+
}],
|
|
549
|
+
};
|
|
550
|
+
}
|
|
516
551
|
extractGoalLikeText(args) {
|
|
517
552
|
const candidates = [args.goal, args.task, args.prompt, args.query, args.action, args.content]
|
|
518
553
|
.map((value) => String(value ?? '').trim())
|
|
@@ -790,6 +825,9 @@ export class MCPAdapter {
|
|
|
790
825
|
}],
|
|
791
826
|
};
|
|
792
827
|
}
|
|
828
|
+
const preOrchestrationBlock = this.buildPreOrchestrationBlock(toolName);
|
|
829
|
+
if (preOrchestrationBlock)
|
|
830
|
+
return preOrchestrationBlock;
|
|
793
831
|
const callId = `mcp_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;
|
|
794
832
|
const startTimeMs = Date.now();
|
|
795
833
|
nexusEventBus.emit('mcp.call.start', {
|
|
@@ -831,8 +869,13 @@ export class MCPAdapter {
|
|
|
831
869
|
? { result: resultPreview }
|
|
832
870
|
: { error: envelope.error.message }),
|
|
833
871
|
});
|
|
834
|
-
if (envelope.ok
|
|
835
|
-
|
|
872
|
+
if (envelope.ok) {
|
|
873
|
+
if (asyncReceipt?.queued) {
|
|
874
|
+
this.telemetry.observeQueuedToolCall(toolName, args);
|
|
875
|
+
}
|
|
876
|
+
else {
|
|
877
|
+
this.telemetry.observeSuccessfulToolCall(toolName, args);
|
|
878
|
+
}
|
|
836
879
|
}
|
|
837
880
|
// Surface meaningful tool calls on the SSE feed; persist only high-signal outcomes.
|
|
838
881
|
if (this.nexusRef) {
|
|
@@ -1028,8 +1071,10 @@ export class MCPAdapter {
|
|
|
1028
1071
|
return;
|
|
1029
1072
|
// Skip if an explicit optimize/orchestrate already ran this session.
|
|
1030
1073
|
const usage = this.nexusRef?.getRuntime?.()?.getUsageSnapshot?.();
|
|
1031
|
-
if (usage?.tokenOptimizationApplied)
|
|
1074
|
+
if (usage?.tokenOptimizationApplied) {
|
|
1075
|
+
this.telemetry.markTokenAutoApplied?.();
|
|
1032
1076
|
return;
|
|
1077
|
+
}
|
|
1033
1078
|
const fileRefs = this.extractFileRefsFromArgs(args);
|
|
1034
1079
|
if (fileRefs.length < 5)
|
|
1035
1080
|
return;
|
|
@@ -1043,6 +1088,7 @@ export class MCPAdapter {
|
|
|
1043
1088
|
const compressionRatio = grossInput > 0 ? totalEstimated / grossInput : 0;
|
|
1044
1089
|
const pct = grossInput > 0 ? Math.round((savings / grossInput) * 100) : 0;
|
|
1045
1090
|
// Mark applied so we don't repeat this for every subsequent tool call.
|
|
1091
|
+
this.telemetry.markTokenAutoApplied?.();
|
|
1046
1092
|
try {
|
|
1047
1093
|
this.nexusRef?.getRuntime?.()?.recordClientToolCall?.(toolName, {
|
|
1048
1094
|
tokenOptimizationApplied: true,
|
package/dist/cli.js
CHANGED
|
@@ -1329,12 +1329,14 @@ program
|
|
|
1329
1329
|
.alias('claude')
|
|
1330
1330
|
.description('Integrate with Claude Code')
|
|
1331
1331
|
.option('--dry-run', 'Preview changes')
|
|
1332
|
-
.option('--hooks', '
|
|
1332
|
+
.option('--hooks', 'Install Claude Code hooks into ~/.claude/settings.json for auto-bootstrap, auto-memory, and governance (default)')
|
|
1333
|
+
.option('--no-hooks', 'Skip Claude Code hooks')
|
|
1333
1334
|
.action((options) => {
|
|
1334
1335
|
const definition = getSetupDefinition('claude-code');
|
|
1336
|
+
const shouldInstallHooks = options.hooks !== false;
|
|
1335
1337
|
if (options.dryRun) {
|
|
1336
1338
|
printSetupPreview(definition);
|
|
1337
|
-
if (
|
|
1339
|
+
if (shouldInstallHooks) {
|
|
1338
1340
|
const settingsPath = join(homedir(), '.claude', 'settings.json');
|
|
1339
1341
|
writeClaudeCodeHooks(settingsPath, true);
|
|
1340
1342
|
}
|
|
@@ -1344,7 +1346,7 @@ program
|
|
|
1344
1346
|
console.log(`✅ Nexus Prime installed for Claude Code`);
|
|
1345
1347
|
console.log(` MCP: ${definition.configPath}`);
|
|
1346
1348
|
definition.instructionFiles.forEach((file) => console.log(` Instruction: ${file.path}`));
|
|
1347
|
-
if (
|
|
1349
|
+
if (shouldInstallHooks) {
|
|
1348
1350
|
const settingsPath = join(homedir(), '.claude', 'settings.json');
|
|
1349
1351
|
writeClaudeCodeHooks(settingsPath, false);
|
|
1350
1352
|
console.log(`✅ Claude Code hooks installed (auto-bootstrap, auto-memory, governance)`);
|
|
@@ -1428,9 +1430,11 @@ program
|
|
|
1428
1430
|
.map((clientId) => getSetupDefinition(clientId));
|
|
1429
1431
|
if (options.dryRun) {
|
|
1430
1432
|
definitions.forEach((definition) => printSetupPreview(definition));
|
|
1433
|
+
writeClaudeCodeHooks(join(homedir(), '.claude', 'settings.json'), true);
|
|
1431
1434
|
return;
|
|
1432
1435
|
}
|
|
1433
1436
|
definitions.forEach((definition) => installSetup(definition));
|
|
1437
|
+
writeClaudeCodeHooks(join(homedir(), '.claude', 'settings.json'), false);
|
|
1434
1438
|
console.log('✅ Nexus Prime installed for all supported clients');
|
|
1435
1439
|
definitions.forEach((definition) => {
|
|
1436
1440
|
console.log(` ${definition.label}`);
|
|
@@ -2618,6 +2618,8 @@ export class OrchestratorEngine {
|
|
|
2618
2618
|
isCatalogVoteSelected(entry) {
|
|
2619
2619
|
if (entry.eligible === false)
|
|
2620
2620
|
return false;
|
|
2621
|
+
if (!entry.item && entry.source !== 'explicit')
|
|
2622
|
+
return false;
|
|
2621
2623
|
if (entry.source === 'explicit' || entry.source === 'planner')
|
|
2622
2624
|
return true;
|
|
2623
2625
|
if (entry.source === 'runtime-resolver')
|
|
@@ -2657,6 +2659,12 @@ export class OrchestratorEngine {
|
|
|
2657
2659
|
if (entry.source === 'explicit') {
|
|
2658
2660
|
return { eligible: true };
|
|
2659
2661
|
}
|
|
2662
|
+
if (!entry.item) {
|
|
2663
|
+
return {
|
|
2664
|
+
eligible: false,
|
|
2665
|
+
blockedReason: 'Recommended artifact is not present in the runtime catalog.',
|
|
2666
|
+
};
|
|
2667
|
+
}
|
|
2660
2668
|
if (entry.source === 'scorer' && entry.confidence === 'low') {
|
|
2661
2669
|
return {
|
|
2662
2670
|
eligible: false,
|
|
@@ -568,30 +568,36 @@ export const BUILTIN_SKILL_PACKS = BASE_DOMAIN_SKILLS.flatMap((seed) => ([
|
|
|
568
568
|
promotionThresholds: { minSuccesses: 2, maxFailures: 1 },
|
|
569
569
|
},
|
|
570
570
|
]));
|
|
571
|
-
|
|
571
|
+
const SPECIALIZED_WORKFLOW_PACKS = [
|
|
572
572
|
{
|
|
573
|
-
key:
|
|
574
|
-
name:
|
|
575
|
-
domain:
|
|
576
|
-
description:
|
|
577
|
-
triggerConditions: [
|
|
578
|
-
expectedOutputs:
|
|
579
|
-
guardrails:
|
|
580
|
-
|
|
581
|
-
|
|
573
|
+
key: 'release-pipeline',
|
|
574
|
+
name: 'release-pipeline',
|
|
575
|
+
domain: 'pdlc',
|
|
576
|
+
description: 'Release workflow with packaging, audit, smoke, and publish-readiness checkpoints.',
|
|
577
|
+
triggerConditions: ['release requested', 'publish or deploy task detected', 'version or tag work selected'],
|
|
578
|
+
expectedOutputs: ['release checklist', 'verification evidence', 'publish decision'],
|
|
579
|
+
guardrails: [
|
|
580
|
+
'Do not treat a draft release as published.',
|
|
581
|
+
'Do not publish without explicit release-gate evidence.',
|
|
582
|
+
],
|
|
583
|
+
verifierHooks: [
|
|
584
|
+
'Attach package, audit, and smoke evidence before promotion.',
|
|
585
|
+
'Record publish-readiness outcome in the run ledger.',
|
|
586
|
+
],
|
|
587
|
+
roleAffinity: ['planner', 'verifier', 'devops'],
|
|
582
588
|
steps: [
|
|
583
589
|
{
|
|
584
|
-
title:
|
|
590
|
+
title: 'Frame release criteria and affected package surface',
|
|
585
591
|
checkpoint: 'before-read',
|
|
586
592
|
role: 'planner',
|
|
587
593
|
},
|
|
588
594
|
{
|
|
589
|
-
title:
|
|
590
|
-
checkpoint: 'before-
|
|
591
|
-
role: '
|
|
595
|
+
title: 'Collect package, audit, and smoke evidence',
|
|
596
|
+
checkpoint: 'before-verify',
|
|
597
|
+
role: 'verifier',
|
|
592
598
|
},
|
|
593
599
|
{
|
|
594
|
-
title:
|
|
600
|
+
title: 'Record publish readiness and remaining blockers',
|
|
595
601
|
checkpoint: 'before-verify',
|
|
596
602
|
role: 'verifier',
|
|
597
603
|
},
|
|
@@ -599,35 +605,104 @@ export const BUILTIN_WORKFLOW_PACKS = BASE_DOMAIN_SKILLS.flatMap((seed) => ([
|
|
|
599
605
|
promotionThresholds: { minSuccesses: 2, maxFailures: 1 },
|
|
600
606
|
},
|
|
601
607
|
{
|
|
602
|
-
key:
|
|
603
|
-
name:
|
|
604
|
-
domain:
|
|
605
|
-
description:
|
|
606
|
-
triggerConditions: [
|
|
607
|
-
expectedOutputs: ['
|
|
608
|
-
guardrails: [
|
|
609
|
-
|
|
610
|
-
|
|
608
|
+
key: 'research-and-implement',
|
|
609
|
+
name: 'research-and-implement',
|
|
610
|
+
domain: 'deep-tech',
|
|
611
|
+
description: 'Research-backed implementation workflow tying retrieved context to bounded code changes and verification.',
|
|
612
|
+
triggerConditions: ['rag context attached', 'research-backed implementation requested', 'unknown code path requires grounding'],
|
|
613
|
+
expectedOutputs: ['source-grounded plan', 'bounded implementation notes', 'verification evidence'],
|
|
614
|
+
guardrails: [
|
|
615
|
+
'Do not promote research claims without source-grounded evidence.',
|
|
616
|
+
'Keep implementation scope tied to retrieved context.',
|
|
617
|
+
],
|
|
618
|
+
verifierHooks: [
|
|
619
|
+
'Attach source-grounding notes before verification.',
|
|
620
|
+
'Record how research context changed the implementation decision.',
|
|
621
|
+
],
|
|
622
|
+
roleAffinity: ['planner', 'coder', 'verifier', 'research-shadow'],
|
|
611
623
|
steps: [
|
|
612
624
|
{
|
|
613
|
-
title:
|
|
625
|
+
title: 'Extract source-grounded implementation constraints',
|
|
614
626
|
checkpoint: 'before-read',
|
|
615
627
|
role: 'planner',
|
|
616
628
|
},
|
|
617
629
|
{
|
|
618
|
-
title:
|
|
619
|
-
checkpoint: 'before-
|
|
620
|
-
role: '
|
|
630
|
+
title: 'Apply the smallest implementation compatible with the research context',
|
|
631
|
+
checkpoint: 'before-mutate',
|
|
632
|
+
role: 'coder',
|
|
621
633
|
},
|
|
622
634
|
{
|
|
623
|
-
title:
|
|
624
|
-
checkpoint: '
|
|
625
|
-
role: '
|
|
635
|
+
title: 'Verify behavior and cite grounding evidence',
|
|
636
|
+
checkpoint: 'before-verify',
|
|
637
|
+
role: 'verifier',
|
|
626
638
|
},
|
|
627
639
|
],
|
|
628
640
|
promotionThresholds: { minSuccesses: 2, maxFailures: 1 },
|
|
629
641
|
},
|
|
630
|
-
]
|
|
642
|
+
];
|
|
643
|
+
export const BUILTIN_WORKFLOW_PACKS = [
|
|
644
|
+
...BASE_DOMAIN_SKILLS.flatMap((seed) => ([
|
|
645
|
+
{
|
|
646
|
+
key: `${seed.domain}-execution-loop`,
|
|
647
|
+
name: `${seed.domain}-execution-loop`,
|
|
648
|
+
domain: seed.domain,
|
|
649
|
+
description: `Bundled ${seed.domain} workflow with planning, execution, and verification checkpoints.`,
|
|
650
|
+
triggerConditions: [`goal mentions ${seed.domain}`, `${seed.domain} pack selected`],
|
|
651
|
+
expectedOutputs: seed.outputs,
|
|
652
|
+
guardrails: seed.guardrails,
|
|
653
|
+
verifierHooks: ['Collect verifier evidence before workflow promotion.', ...seed.verifierHooks],
|
|
654
|
+
roleAffinity: ['planner', 'coder', 'verifier', 'skill-maker'],
|
|
655
|
+
steps: [
|
|
656
|
+
{
|
|
657
|
+
title: `Plan ${seed.domain} outcome and artifacts`,
|
|
658
|
+
checkpoint: 'before-read',
|
|
659
|
+
role: 'planner',
|
|
660
|
+
},
|
|
661
|
+
{
|
|
662
|
+
title: `Execute ${seed.domain} changes with bounded scope`,
|
|
663
|
+
checkpoint: 'before-mutate',
|
|
664
|
+
role: 'coder',
|
|
665
|
+
},
|
|
666
|
+
{
|
|
667
|
+
title: `Review ${seed.domain} outputs and attach evidence`,
|
|
668
|
+
checkpoint: 'before-verify',
|
|
669
|
+
role: 'verifier',
|
|
670
|
+
},
|
|
671
|
+
],
|
|
672
|
+
promotionThresholds: { minSuccesses: 2, maxFailures: 1 },
|
|
673
|
+
},
|
|
674
|
+
{
|
|
675
|
+
key: `${seed.domain}-approval-loop`,
|
|
676
|
+
name: `${seed.domain}-approval-loop`,
|
|
677
|
+
domain: seed.domain,
|
|
678
|
+
description: `Bundled ${seed.domain} approval loop with review, verification, and promotion control.`,
|
|
679
|
+
triggerConditions: [`${seed.domain} approval requested`, `${seed.domain} promotion under review`],
|
|
680
|
+
expectedOutputs: ['approval note', 'review evidence', 'promotion decision'],
|
|
681
|
+
guardrails: ['Do not approve unverified work.', ...seed.guardrails],
|
|
682
|
+
verifierHooks: ['Require approval evidence before promotion.', ...seed.verifierHooks],
|
|
683
|
+
roleAffinity: ['planner', 'verifier', 'research-shadow'],
|
|
684
|
+
steps: [
|
|
685
|
+
{
|
|
686
|
+
title: `Frame ${seed.domain} approval criteria`,
|
|
687
|
+
checkpoint: 'before-read',
|
|
688
|
+
role: 'planner',
|
|
689
|
+
},
|
|
690
|
+
{
|
|
691
|
+
title: `Review ${seed.domain} evidence and risks`,
|
|
692
|
+
checkpoint: 'before-verify',
|
|
693
|
+
role: 'verifier',
|
|
694
|
+
},
|
|
695
|
+
{
|
|
696
|
+
title: `Publish ${seed.domain} approval outcome`,
|
|
697
|
+
checkpoint: 'retry',
|
|
698
|
+
role: 'research-shadow',
|
|
699
|
+
},
|
|
700
|
+
],
|
|
701
|
+
promotionThresholds: { minSuccesses: 2, maxFailures: 1 },
|
|
702
|
+
},
|
|
703
|
+
])),
|
|
704
|
+
...SPECIALIZED_WORKFLOW_PACKS,
|
|
705
|
+
];
|
|
631
706
|
export function slugify(value) {
|
|
632
707
|
return value
|
|
633
708
|
.toLowerCase()
|
|
@@ -204,6 +204,10 @@ export class TokenSupremacyEngine {
|
|
|
204
204
|
// Saves ~60-70% tokens on follow-up sessions
|
|
205
205
|
// ───────────────────────────────────────────────────────────────────────────
|
|
206
206
|
differential(prev, curr) {
|
|
207
|
+
const previousFileSHAs = prev.fileSHAs && typeof prev.fileSHAs === 'object'
|
|
208
|
+
? prev.fileSHAs
|
|
209
|
+
: {};
|
|
210
|
+
const hasComparableFingerprints = Object.keys(previousFileSHAs).length > 0;
|
|
207
211
|
const delta = {
|
|
208
212
|
added: [],
|
|
209
213
|
changed: [],
|
|
@@ -214,10 +218,15 @@ export class TokenSupremacyEngine {
|
|
|
214
218
|
: undefined,
|
|
215
219
|
};
|
|
216
220
|
for (const file of curr) {
|
|
217
|
-
const prevSHA =
|
|
221
|
+
const prevSHA = previousFileSHAs[file.path];
|
|
218
222
|
const currSHA = this.fingerprintFile(file);
|
|
219
223
|
if (!prevSHA) {
|
|
220
|
-
|
|
224
|
+
if (hasComparableFingerprints) {
|
|
225
|
+
delta.added.push(file);
|
|
226
|
+
}
|
|
227
|
+
else {
|
|
228
|
+
delta.changed.push(file);
|
|
229
|
+
}
|
|
221
230
|
}
|
|
222
231
|
else if (prevSHA !== currSHA) {
|
|
223
232
|
delta.changed.push(file);
|
|
@@ -33,14 +33,14 @@ export class ArtifactRecorder {
|
|
|
33
33
|
writeJson(relativePath, value) {
|
|
34
34
|
const target = path.join(this.runDir, relativePath);
|
|
35
35
|
fs.mkdirSync(path.dirname(target), { recursive: true });
|
|
36
|
-
|
|
36
|
+
fs.writeFileSync(target, JSON.stringify(value, null, 2), 'utf-8');
|
|
37
37
|
this.index[relativePath] = target;
|
|
38
38
|
return target;
|
|
39
39
|
}
|
|
40
40
|
writeText(relativePath, value) {
|
|
41
41
|
const target = path.join(this.runDir, relativePath);
|
|
42
42
|
fs.mkdirSync(path.dirname(target), { recursive: true });
|
|
43
|
-
|
|
43
|
+
fs.writeFileSync(target, value, 'utf-8');
|
|
44
44
|
this.index[relativePath] = target;
|
|
45
45
|
return target;
|
|
46
46
|
}
|
|
@@ -187,6 +187,8 @@ export interface WorkerVerification {
|
|
|
187
187
|
workerId: string;
|
|
188
188
|
verifierId: string;
|
|
189
189
|
passed: boolean;
|
|
190
|
+
status: 'passed' | 'failed' | 'skipped';
|
|
191
|
+
skippedReason?: string;
|
|
190
192
|
commands: CommandRecord[];
|
|
191
193
|
summary: string;
|
|
192
194
|
artifactsPath: string;
|
package/dist/phantom/runtime.js
CHANGED
|
@@ -619,6 +619,7 @@ export class SubAgentRuntime {
|
|
|
619
619
|
workerId: manifest.targetWorkerId ?? manifest.workerId,
|
|
620
620
|
verifierId: manifest.workerId,
|
|
621
621
|
passed: false,
|
|
622
|
+
status: 'failed',
|
|
622
623
|
commands: [],
|
|
623
624
|
summary: target?.budgetExceeded
|
|
624
625
|
? 'Skipped verification for over-budget worker.'
|
|
@@ -637,12 +638,14 @@ export class SubAgentRuntime {
|
|
|
637
638
|
}
|
|
638
639
|
const verification = verificationResults.find((entry) => entry.workerId === result.workerId);
|
|
639
640
|
if (verification) {
|
|
641
|
+
const verificationPassed = verification.status === 'passed' || (verification.passed && verification.status !== 'skipped');
|
|
640
642
|
result.verification = verification;
|
|
641
|
-
result.verified =
|
|
643
|
+
result.verified = verificationPassed;
|
|
642
644
|
result.testsPassing = verification.commands.filter((command) => command.exitCode === 0).length;
|
|
643
|
-
result.outcome =
|
|
645
|
+
result.outcome = verificationPassed ? 'success' : (result.diff.trim() ? 'partial' : 'failed');
|
|
644
646
|
}
|
|
645
647
|
}
|
|
648
|
+
recorder.writeJson('worker-results.json', run.workerResults);
|
|
646
649
|
const decision = await consensusPolicy.merge(mergeableCoderResults);
|
|
647
650
|
run.finalDecision = decision;
|
|
648
651
|
run.backendEvidence.consensus = consensusPolicy.shadowStats();
|
|
@@ -2132,13 +2135,15 @@ export class SubAgentRuntime {
|
|
|
2132
2135
|
const artifactsPath = recorder.workerDir(manifest.workerId);
|
|
2133
2136
|
// Skip worktree creation if there is nothing to verify. An empty diff
|
|
2134
2137
|
// is not a verification failure — it means the worker produced no
|
|
2135
|
-
// mutation (typical for inspect/plan intents).
|
|
2136
|
-
//
|
|
2138
|
+
// mutation (typical for inspect/plan intents). This is a skipped
|
|
2139
|
+
// verification, not evidence that implementation passed.
|
|
2137
2140
|
if (!target?.diff?.trim()) {
|
|
2138
2141
|
return {
|
|
2139
2142
|
workerId: manifest.targetWorkerId ?? 'unknown',
|
|
2140
2143
|
verifierId: manifest.workerId,
|
|
2141
|
-
passed:
|
|
2144
|
+
passed: false,
|
|
2145
|
+
status: 'skipped',
|
|
2146
|
+
skippedReason: 'no_candidate_diff',
|
|
2142
2147
|
commands: [],
|
|
2143
2148
|
summary: 'Verifier skipped — no candidate diff to verify (read-only or no-op run).',
|
|
2144
2149
|
artifactsPath,
|
|
@@ -2175,6 +2180,7 @@ export class SubAgentRuntime {
|
|
|
2175
2180
|
workerId: manifest.targetWorkerId ?? 'unknown',
|
|
2176
2181
|
verifierId: manifest.workerId,
|
|
2177
2182
|
passed,
|
|
2183
|
+
status: passed ? 'passed' : 'failed',
|
|
2178
2184
|
commands: records,
|
|
2179
2185
|
summary: passed
|
|
2180
2186
|
? `Verifier passed ${records.length} command(s).`
|
|
@@ -2190,6 +2196,7 @@ export class SubAgentRuntime {
|
|
|
2190
2196
|
workerId: manifest.targetWorkerId ?? 'unknown',
|
|
2191
2197
|
verifierId: manifest.workerId,
|
|
2192
2198
|
passed: false,
|
|
2199
|
+
status: 'failed',
|
|
2193
2200
|
commands: [],
|
|
2194
2201
|
summary,
|
|
2195
2202
|
artifactsPath,
|
|
@@ -2945,8 +2952,8 @@ export class SubAgentRuntime {
|
|
|
2945
2952
|
};
|
|
2946
2953
|
}
|
|
2947
2954
|
evaluateReviewGates(run) {
|
|
2948
|
-
const verificationPassed = run.verificationResults.filter((result) => result.passed).length;
|
|
2949
|
-
const verificationFailed = run.verificationResults.filter((result) => !result.passed).length;
|
|
2955
|
+
const verificationPassed = run.verificationResults.filter((result) => result.status === 'passed' || (result.passed && result.status !== 'skipped')).length;
|
|
2956
|
+
const verificationFailed = run.verificationResults.filter((result) => result.status === 'failed' || (!result.passed && result.status !== 'skipped')).length;
|
|
2950
2957
|
const hasPlannerEvidence = Boolean(run.plannerState?.ledger?.length || run.plannerResult?.summary || run.executionLedger?.steps?.some((step) => step.id === 'planner-selection' && step.status === 'completed'));
|
|
2951
2958
|
const hasImplementation = run.workerResults.some((result) => result.role === 'coder');
|
|
2952
2959
|
const hasVerifiedImplementation = run.workerResults.some((result) => result.role === 'coder' && result.verified);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nexus-prime",
|
|
3
|
-
"version": "7.9.
|
|
3
|
+
"version": "7.9.7",
|
|
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",
|