nexus-prime 7.9.0 → 7.9.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/dist/agents/adapters/mcp/async-gate.d.ts +5 -0
- package/dist/agents/adapters/mcp/async-gate.js +12 -2
- package/dist/agents/adapters/mcp/dispatch.js +35 -1
- package/dist/agents/adapters/mcp/handlers/runtime.js +33 -1
- package/dist/agents/adapters/mcp/runHandler.d.ts +2 -1
- package/dist/agents/adapters/mcp/runHandler.js +13 -4
- package/dist/agents/adapters/mcp.d.ts +2 -0
- package/dist/agents/adapters/mcp.js +59 -14
- package/dist/dashboard/app/main.js +26 -4
- package/dist/dashboard/server.d.ts +2 -0
- package/dist/dashboard/server.js +36 -5
- package/dist/index.d.ts +7 -0
- package/dist/index.js +5 -0
- package/package.json +1 -1
|
@@ -15,6 +15,7 @@ export type AsyncJobStatus = 'pending' | 'running' | 'completed' | 'failed';
|
|
|
15
15
|
export interface AsyncJob {
|
|
16
16
|
runId: string;
|
|
17
17
|
tool: string;
|
|
18
|
+
args?: Record<string, unknown>;
|
|
18
19
|
status: AsyncJobStatus;
|
|
19
20
|
stage: string;
|
|
20
21
|
progress: number;
|
|
@@ -29,10 +30,13 @@ export interface AsyncJob {
|
|
|
29
30
|
};
|
|
30
31
|
error?: string;
|
|
31
32
|
etaMs?: number;
|
|
33
|
+
lifecycleReportedAt?: number;
|
|
32
34
|
}
|
|
33
35
|
export interface AsyncGateOpts {
|
|
34
36
|
/** Tool name — for job metadata */
|
|
35
37
|
tool: string;
|
|
38
|
+
/** Original tool args, used when a poll observes final lifecycle state. */
|
|
39
|
+
args?: Record<string, unknown>;
|
|
36
40
|
/** If handler resolves within this window, return inline. Default: 2000ms */
|
|
37
41
|
maxSyncMs?: number;
|
|
38
42
|
/** Human-readable hint for estimated duration */
|
|
@@ -67,6 +71,7 @@ declare class AsyncGate {
|
|
|
67
71
|
}>;
|
|
68
72
|
};
|
|
69
73
|
updateStage(runId: string, stage: string, progress: number): void;
|
|
74
|
+
markLifecycleReported(runId: string): void;
|
|
70
75
|
/** Return jobs that have been running longer than their stale threshold. */
|
|
71
76
|
getStaleJobs(now: number, defaultStaleMs: number, etaMultiplier: number): AsyncJob[];
|
|
72
77
|
/** Mark a running job as failed (watchdog reap). */
|
|
@@ -25,6 +25,7 @@ class AsyncGate {
|
|
|
25
25
|
const job = {
|
|
26
26
|
runId,
|
|
27
27
|
tool: opts.tool,
|
|
28
|
+
args: opts.args,
|
|
28
29
|
status: 'pending',
|
|
29
30
|
stage: 'queued',
|
|
30
31
|
progress: 0,
|
|
@@ -55,8 +56,12 @@ class AsyncGate {
|
|
|
55
56
|
job.error = err instanceof Error ? err.message : String(err);
|
|
56
57
|
job.completedAt = Date.now();
|
|
57
58
|
nexusEventBus.emit('async_gate.failed', { runId, tool: opts.tool, error: job.error });
|
|
58
|
-
|
|
59
|
-
|
|
59
|
+
return {
|
|
60
|
+
content: [{
|
|
61
|
+
type: 'text',
|
|
62
|
+
text: `❌ Run ${runId} failed\nTool: ${opts.tool}\nError: ${job.error ?? 'unknown'}`,
|
|
63
|
+
}],
|
|
64
|
+
};
|
|
60
65
|
}
|
|
61
66
|
})();
|
|
62
67
|
// Suppress unhandled rejection: deadline may win while work is still in flight.
|
|
@@ -118,6 +123,11 @@ class AsyncGate {
|
|
|
118
123
|
job.progress = Math.min(99, progress);
|
|
119
124
|
}
|
|
120
125
|
}
|
|
126
|
+
markLifecycleReported(runId) {
|
|
127
|
+
const job = this.jobs.get(runId);
|
|
128
|
+
if (job)
|
|
129
|
+
job.lifecycleReportedAt = Date.now();
|
|
130
|
+
}
|
|
121
131
|
/** Return jobs that have been running longer than their stale threshold. */
|
|
122
132
|
getStaleJobs(now, defaultStaleMs, etaMultiplier) {
|
|
123
133
|
const stale = [];
|
|
@@ -26,6 +26,23 @@ const SLOW_TOOLS = new Set([
|
|
|
26
26
|
'nexus_ghost_pass',
|
|
27
27
|
'nexus_spawn_workers',
|
|
28
28
|
'nexus_optimize_tokens',
|
|
29
|
+
'nexus_search',
|
|
30
|
+
'nexus_assemble_context',
|
|
31
|
+
'nexus_graph_query',
|
|
32
|
+
'nexus_session_search',
|
|
33
|
+
'nexus_memory_export',
|
|
34
|
+
'nexus_memory_backup',
|
|
35
|
+
'nexus_memory_import',
|
|
36
|
+
'nexus_memory_hygiene',
|
|
37
|
+
'nexus_memory_audit',
|
|
38
|
+
'nexus_pattern_search',
|
|
39
|
+
'nexus_knowledge_provenance',
|
|
40
|
+
'nexus_rag_ingest_collection',
|
|
41
|
+
'nexus_workflow_run',
|
|
42
|
+
'nexus_automation_run',
|
|
43
|
+
'nexus_doctor',
|
|
44
|
+
'nexus_autofix',
|
|
45
|
+
'nexus_hypertune_max',
|
|
29
46
|
]);
|
|
30
47
|
/** Estimated wall-clock duration for each slow tool (ms). */
|
|
31
48
|
const TOOL_ETA_MS = {
|
|
@@ -34,6 +51,23 @@ const TOOL_ETA_MS = {
|
|
|
34
51
|
nexus_ghost_pass: 45_000,
|
|
35
52
|
nexus_spawn_workers: 30_000,
|
|
36
53
|
nexus_optimize_tokens: 10_000,
|
|
54
|
+
nexus_search: 20_000,
|
|
55
|
+
nexus_assemble_context: 20_000,
|
|
56
|
+
nexus_graph_query: 30_000,
|
|
57
|
+
nexus_session_search: 20_000,
|
|
58
|
+
nexus_memory_export: 20_000,
|
|
59
|
+
nexus_memory_backup: 30_000,
|
|
60
|
+
nexus_memory_import: 30_000,
|
|
61
|
+
nexus_memory_hygiene: 30_000,
|
|
62
|
+
nexus_memory_audit: 30_000,
|
|
63
|
+
nexus_pattern_search: 20_000,
|
|
64
|
+
nexus_knowledge_provenance: 20_000,
|
|
65
|
+
nexus_rag_ingest_collection: 45_000,
|
|
66
|
+
nexus_workflow_run: 45_000,
|
|
67
|
+
nexus_automation_run: 45_000,
|
|
68
|
+
nexus_doctor: 20_000,
|
|
69
|
+
nexus_autofix: 45_000,
|
|
70
|
+
nexus_hypertune_max: 45_000,
|
|
37
71
|
};
|
|
38
72
|
/**
|
|
39
73
|
* Route a tool call to the appropriate handler group.
|
|
@@ -90,7 +124,7 @@ export async function dispatchMcpToolCall(hctx, request, args, ctx) {
|
|
|
90
124
|
const gated = await withAsyncGate(async () => {
|
|
91
125
|
const r = await runHandlers();
|
|
92
126
|
return r ?? { content: [{ type: 'text', text: `Tool ${toolName} returned no result` }] };
|
|
93
|
-
}, { tool: toolName, maxSyncMs: 2000, etaMs: TOOL_ETA_MS[toolName] });
|
|
127
|
+
}, { tool: toolName, args, maxSyncMs: 2000, etaMs: TOOL_ETA_MS[toolName] });
|
|
94
128
|
if ('queued' in gated && gated.queued) {
|
|
95
129
|
// Persist orchestration run record for durable stage tracking
|
|
96
130
|
if (toolName === 'nexus_orchestrate') {
|
|
@@ -4,10 +4,11 @@
|
|
|
4
4
|
* federation_status, run_status.
|
|
5
5
|
* Extracted from mcp.ts (Phase 3 split).
|
|
6
6
|
*/
|
|
7
|
-
import { formatBullets, formatJsonDetails, } from '../helpers.js';
|
|
7
|
+
import { formatBullets, formatJsonDetails, buildAutoMemorySummary, } from '../helpers.js';
|
|
8
8
|
import { nexusEventBus } from '../../../../engines/event-bus.js';
|
|
9
9
|
import { getSharedLicenseManager, snapshotPCU, formatPCUStatus } from '../../../../licensing/index.js';
|
|
10
10
|
import { TokenAnalyticsEngine } from '../../../../engines/token-analytics.js';
|
|
11
|
+
import * as path from 'path';
|
|
11
12
|
import { requireRuntime } from '../util/require-runtime.js';
|
|
12
13
|
import { getAsyncGate } from '../async-gate.js';
|
|
13
14
|
import { getRun as getOrchRun } from '../../../../engines/orchestrator/store.js';
|
|
@@ -231,6 +232,37 @@ export async function handleRuntimeGroup(toolName, hctx, request, args, ctx) {
|
|
|
231
232
|
// Check async gate first (fast in-memory jobs from withAsyncGate)
|
|
232
233
|
const asyncJob = getAsyncGate().getJob(runId);
|
|
233
234
|
if (asyncJob) {
|
|
235
|
+
if (!asyncJob.lifecycleReportedAt
|
|
236
|
+
&& (asyncJob.status === 'completed' || asyncJob.status === 'failed')) {
|
|
237
|
+
if (asyncJob.status === 'completed') {
|
|
238
|
+
hctx.telemetry.observeSuccessfulToolCall(asyncJob.tool, asyncJob.args ?? {});
|
|
239
|
+
}
|
|
240
|
+
const shouldPersistSuccess = [
|
|
241
|
+
'nexus_orchestrate',
|
|
242
|
+
'nexus_plan_execution',
|
|
243
|
+
'nexus_session_dna',
|
|
244
|
+
'nexus_ghost_pass',
|
|
245
|
+
'nexus_mindkit_check',
|
|
246
|
+
].includes(asyncJob.tool);
|
|
247
|
+
try {
|
|
248
|
+
if (asyncJob.tool !== 'nexus_store_memory' && (asyncJob.status === 'failed' || shouldPersistSuccess)) {
|
|
249
|
+
const workspace = hctx.getWorkspace(asyncJob.args ?? {});
|
|
250
|
+
const repoName = workspace.repoName || path.basename(workspace.repoRoot || '');
|
|
251
|
+
const summary = asyncJob.status === 'completed'
|
|
252
|
+
? `MCP ${asyncJob.tool} completed asynchronously. ${buildAutoMemorySummary(asyncJob.tool, asyncJob.args ?? {})}`
|
|
253
|
+
: `MCP ${asyncJob.tool} failed asynchronously: ${asyncJob.error ?? 'unknown failure'}. ${buildAutoMemorySummary(asyncJob.tool, asyncJob.args ?? {})}`;
|
|
254
|
+
hctx.nexusRef.storeMemory(summary.slice(0, 1200), asyncJob.status === 'completed' ? 0.55 : 0.72, [
|
|
255
|
+
'#mcp-result',
|
|
256
|
+
'#auto',
|
|
257
|
+
`#tool:${asyncJob.tool}`,
|
|
258
|
+
...(repoName ? [`repo:${repoName}`, `#repo:${repoName}`] : []),
|
|
259
|
+
...(asyncJob.status === 'completed' ? ['#workspace'] : ['#failure-mode', '#runtime-result', '#inbox']),
|
|
260
|
+
]);
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
catch { /* best-effort lifecycle memory */ }
|
|
264
|
+
getAsyncGate().markLifecycleReported(runId);
|
|
265
|
+
}
|
|
234
266
|
if (fmt === 'nxl')
|
|
235
267
|
return nxlResult(asyncJob);
|
|
236
268
|
return getAsyncGate().formatStatus(runId);
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* 3. Transient retries — SQLite-busy / cold runtime → one retry with backoff.
|
|
8
8
|
*
|
|
9
9
|
* Per-client timeouts (AI Lead refinement):
|
|
10
|
-
* Codex 90 s · Claude Code 60 s · Cursor 30 s · default
|
|
10
|
+
* Codex 90 s · Claude Code 60 s · Cursor 30 s · MCP clients 60 s · default 60 s
|
|
11
11
|
*
|
|
12
12
|
* Types and `envelopeToMcpResponse` are canonical in ./envelope.ts;
|
|
13
13
|
* re-exported from here for backward compatibility.
|
|
@@ -16,6 +16,7 @@ import type { RunHandlerOptions } from './envelope.js';
|
|
|
16
16
|
import type { HandlerEnvelope } from './envelope.js';
|
|
17
17
|
export type { HandlerErrorCode, HandlerEnvelope, RunHandlerOptions } from './envelope.js';
|
|
18
18
|
export { envelopeToMcpResponse } from './envelope.js';
|
|
19
|
+
export declare function resolveHandlerTimeoutForTest(opts?: RunHandlerOptions): number;
|
|
19
20
|
/**
|
|
20
21
|
* Run a handler function with timeout, retry, and structured envelope.
|
|
21
22
|
*
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* 3. Transient retries — SQLite-busy / cold runtime → one retry with backoff.
|
|
8
8
|
*
|
|
9
9
|
* Per-client timeouts (AI Lead refinement):
|
|
10
|
-
* Codex 90 s · Claude Code 60 s · Cursor 30 s · default
|
|
10
|
+
* Codex 90 s · Claude Code 60 s · Cursor 30 s · MCP clients 60 s · default 60 s
|
|
11
11
|
*
|
|
12
12
|
* Types and `envelopeToMcpResponse` are canonical in ./envelope.ts;
|
|
13
13
|
* re-exported from here for backward compatibility.
|
|
@@ -20,16 +20,25 @@ const CLIENT_TIMEOUTS = {
|
|
|
20
20
|
'codex': 90_000,
|
|
21
21
|
'claude-code': 60_000,
|
|
22
22
|
'cursor': 30_000,
|
|
23
|
+
'openclaw': 90_000,
|
|
24
|
+
'opencode': 90_000,
|
|
25
|
+
'windsurf': 90_000,
|
|
26
|
+
'antigravity': 90_000,
|
|
27
|
+
'mcp': 60_000,
|
|
23
28
|
};
|
|
24
|
-
const DEFAULT_TIMEOUT =
|
|
29
|
+
const DEFAULT_TIMEOUT = 60_000;
|
|
25
30
|
function resolveTimeout(opts) {
|
|
26
31
|
if (opts.timeoutMs !== undefined)
|
|
27
32
|
return opts.timeoutMs;
|
|
28
|
-
|
|
29
|
-
|
|
33
|
+
const callerName = String(opts.callerName ?? '').trim().toLowerCase();
|
|
34
|
+
if (callerName && callerName in CLIENT_TIMEOUTS) {
|
|
35
|
+
return CLIENT_TIMEOUTS[callerName];
|
|
30
36
|
}
|
|
31
37
|
return DEFAULT_TIMEOUT;
|
|
32
38
|
}
|
|
39
|
+
export function resolveHandlerTimeoutForTest(opts = {}) {
|
|
40
|
+
return resolveTimeout(opts);
|
|
41
|
+
}
|
|
33
42
|
// ─── Error classification ─────────────────────────────────────────────────────
|
|
34
43
|
function classifyError(err) {
|
|
35
44
|
const msg = err instanceof Error ? err.message : String(err);
|
|
@@ -818,6 +818,7 @@ export class MCPAdapter {
|
|
|
818
818
|
const result = envelopeToMcpResponse(envelope);
|
|
819
819
|
const durationMs = Date.now() - startTimeMs;
|
|
820
820
|
const resultPreview = envelope.ok ? buildResultPreview(result) : null;
|
|
821
|
+
const asyncReceipt = envelope.ok ? this.parseAsyncReceipt(result) : null;
|
|
821
822
|
nexusEventBus.emit('mcp.call.complete', {
|
|
822
823
|
callId,
|
|
823
824
|
serverName: 'nexus-prime',
|
|
@@ -830,27 +831,71 @@ export class MCPAdapter {
|
|
|
830
831
|
? { result: resultPreview }
|
|
831
832
|
: { error: envelope.error.message }),
|
|
832
833
|
});
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
//
|
|
837
|
-
|
|
838
|
-
if (this.nexusRef && !isReadOnlyMcpTool(toolName)) {
|
|
834
|
+
if (envelope.ok && !asyncReceipt?.queued) {
|
|
835
|
+
this.telemetry.observeSuccessfulToolCall(toolName, args);
|
|
836
|
+
}
|
|
837
|
+
// Surface meaningful tool calls on the SSE feed; persist only high-signal outcomes.
|
|
838
|
+
if (this.nexusRef) {
|
|
839
839
|
const repoRoot = this.nexusRef.getWorkspaceContext?.()?.repoRoot ?? '';
|
|
840
840
|
const repoName = repoRoot ? path.basename(repoRoot) : '';
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
841
|
+
if (!isReadOnlyMcpTool(toolName)) {
|
|
842
|
+
try {
|
|
843
|
+
nexusEventBus.emit('memory.snapshot', {
|
|
844
|
+
kind: 'tool-invocation',
|
|
845
|
+
toolName,
|
|
846
|
+
repo: repoName,
|
|
847
|
+
summary: buildAutoMemorySummary(toolName, args),
|
|
848
|
+
});
|
|
849
|
+
}
|
|
850
|
+
catch { /* best-effort */ }
|
|
848
851
|
}
|
|
849
|
-
|
|
852
|
+
this.maybeStoreToolOutcomeMemory(toolName, args, envelope, durationMs, repoName, asyncReceipt);
|
|
850
853
|
}
|
|
851
854
|
const decorated = this.decorateLifecycleResponse(toolName, result);
|
|
852
855
|
return this.injectMemoryContext(toolName, args, decorated);
|
|
853
856
|
}
|
|
857
|
+
parseAsyncReceipt(result) {
|
|
858
|
+
const text = result.content?.[0]?.text;
|
|
859
|
+
if (!text)
|
|
860
|
+
return null;
|
|
861
|
+
try {
|
|
862
|
+
const parsed = JSON.parse(String(text).split('\n\n')[0] ?? '{}');
|
|
863
|
+
return parsed && typeof parsed === 'object' && parsed.queued === true ? parsed : null;
|
|
864
|
+
}
|
|
865
|
+
catch {
|
|
866
|
+
return null;
|
|
867
|
+
}
|
|
868
|
+
}
|
|
869
|
+
maybeStoreToolOutcomeMemory(toolName, args, envelope, durationMs, repoName, asyncReceipt) {
|
|
870
|
+
if (!this.nexusRef || toolName === 'nexus_store_memory')
|
|
871
|
+
return;
|
|
872
|
+
if (asyncReceipt?.queued)
|
|
873
|
+
return;
|
|
874
|
+
const shouldPersistSuccess = [
|
|
875
|
+
'nexus_orchestrate',
|
|
876
|
+
'nexus_plan_execution',
|
|
877
|
+
'nexus_session_dna',
|
|
878
|
+
'nexus_ghost_pass',
|
|
879
|
+
'nexus_mindkit_check',
|
|
880
|
+
].includes(toolName);
|
|
881
|
+
if (envelope.ok && !shouldPersistSuccess)
|
|
882
|
+
return;
|
|
883
|
+
const error = envelope.error;
|
|
884
|
+
const summary = envelope.ok
|
|
885
|
+
? `MCP ${toolName} completed in ${durationMs}ms. ${buildAutoMemorySummary(toolName, args)}`
|
|
886
|
+
: `MCP ${toolName} failed after ${durationMs}ms: ${error?.code ?? 'error'} ${error?.message ?? 'unknown failure'}. ${buildAutoMemorySummary(toolName, args)}`;
|
|
887
|
+
const tags = [
|
|
888
|
+
'#mcp-result',
|
|
889
|
+
'#auto',
|
|
890
|
+
`#tool:${toolName}`,
|
|
891
|
+
...(repoName ? [`repo:${repoName}`, `#repo:${repoName}`] : []),
|
|
892
|
+
...(envelope.ok ? ['#workspace'] : ['#failure-mode', '#runtime-result', '#inbox']),
|
|
893
|
+
];
|
|
894
|
+
try {
|
|
895
|
+
this.nexusRef.storeMemory(summary.slice(0, 1200), envelope.ok ? 0.55 : 0.72, tags);
|
|
896
|
+
}
|
|
897
|
+
catch { /* best-effort */ }
|
|
898
|
+
}
|
|
854
899
|
buildHandlerCtx(args = {}) {
|
|
855
900
|
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
|
856
901
|
const self = this;
|
|
@@ -27,6 +27,24 @@ import { mount as mountRuntimeBadges } from './widgets/runtime-badge.js';
|
|
|
27
27
|
|
|
28
28
|
const $ = id => document.getElementById(id);
|
|
29
29
|
const esc = s => s==null?'':String(s).replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>').replace(/"/g,'"');
|
|
30
|
+
let memoryReloadTimer = null;
|
|
31
|
+
|
|
32
|
+
function _memoryApiUrl() {
|
|
33
|
+
return S.workspace?.repoName ? '/api/memory?repo='+encodeURIComponent(S.workspace.repoName) : '/api/memory';
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function _refreshMemorySoon() {
|
|
37
|
+
bustCache(_memoryApiUrl());
|
|
38
|
+
bustCache('/api/memory');
|
|
39
|
+
bustCache('/api/memory/health');
|
|
40
|
+
bustCache('/api/dashboard/surface/memory');
|
|
41
|
+
if (S.tab !== 'memory') return;
|
|
42
|
+
clearTimeout(memoryReloadTimer);
|
|
43
|
+
memoryReloadTimer = setTimeout(() => {
|
|
44
|
+
memoryReloadTimer = null;
|
|
45
|
+
Memory.load();
|
|
46
|
+
}, 150);
|
|
47
|
+
}
|
|
30
48
|
|
|
31
49
|
/* ─────────────────── Router ─────────────────── */
|
|
32
50
|
navRegister('board', Board.load);
|
|
@@ -53,15 +71,19 @@ setOnEvent(evt => {
|
|
|
53
71
|
Board.render();
|
|
54
72
|
_renderTicker();
|
|
55
73
|
}
|
|
56
|
-
// Refresh tool health tile on
|
|
57
|
-
if (
|
|
58
|
-
|
|
74
|
+
// Refresh tool health tile on tool lifecycle events.
|
|
75
|
+
if (['tool.invocation', 'mcp.handler.complete', 'mcp.handler.failed'].includes(String(evt.type||''))) {
|
|
76
|
+
bustCache('/api/runtime/tool-health');
|
|
77
|
+
bustCache('/api/dashboard/surface/operate');
|
|
78
|
+
if (tab === 'board') {
|
|
79
|
+
Board.loadToolHealth();
|
|
80
|
+
}
|
|
59
81
|
}
|
|
60
82
|
if (tab === 'workforce' && ['synapse','operative','mission'].includes(evt.category)) {
|
|
61
83
|
Workforce.render();
|
|
62
84
|
}
|
|
63
85
|
if (tab === 'memory' && evt.category === 'memory') {
|
|
64
|
-
|
|
86
|
+
_refreshMemorySoon();
|
|
65
87
|
}
|
|
66
88
|
if (tab === 'governance' && evt.category === 'darwin') {
|
|
67
89
|
Governance.load();
|
|
@@ -64,6 +64,8 @@ export declare class DashboardServer {
|
|
|
64
64
|
private readJsonIfExists;
|
|
65
65
|
private fileExists;
|
|
66
66
|
private collectUsageSnapshot;
|
|
67
|
+
private normalizeDashboardRepoToken;
|
|
68
|
+
private dashboardMemoryMatchesRepoName;
|
|
67
69
|
private listDashboardMemories;
|
|
68
70
|
private listCrossProjectMemories;
|
|
69
71
|
private listCrossProjectProjects;
|
package/dist/dashboard/server.js
CHANGED
|
@@ -762,6 +762,35 @@ export class DashboardServer {
|
|
|
762
762
|
latestRun: null,
|
|
763
763
|
};
|
|
764
764
|
}
|
|
765
|
+
normalizeDashboardRepoToken(value) {
|
|
766
|
+
return String(value ?? '').trim().replace(/^#/, '').toLowerCase();
|
|
767
|
+
}
|
|
768
|
+
dashboardMemoryMatchesRepoName(memory, repoName) {
|
|
769
|
+
const expected = this.normalizeDashboardRepoToken(repoName);
|
|
770
|
+
if (!expected)
|
|
771
|
+
return true;
|
|
772
|
+
const tags = Array.isArray(memory.tags) ? memory.tags : [];
|
|
773
|
+
const provenance = memory.provenance ?? {};
|
|
774
|
+
const candidates = [
|
|
775
|
+
...tags,
|
|
776
|
+
...(Array.isArray(provenance.tags) ? provenance.tags : []),
|
|
777
|
+
...(Array.isArray(provenance.containerTags) ? provenance.containerTags : []),
|
|
778
|
+
provenance.repoName,
|
|
779
|
+
provenance.repoId,
|
|
780
|
+
provenance.workspaceId,
|
|
781
|
+
provenance.projectId,
|
|
782
|
+
];
|
|
783
|
+
return candidates.some((candidate) => {
|
|
784
|
+
const token = this.normalizeDashboardRepoToken(candidate);
|
|
785
|
+
if (!token)
|
|
786
|
+
return false;
|
|
787
|
+
if (token === expected)
|
|
788
|
+
return true;
|
|
789
|
+
if (token === `repo:${expected}`)
|
|
790
|
+
return true;
|
|
791
|
+
return token.startsWith('repo:') && token.slice(5) === expected;
|
|
792
|
+
});
|
|
793
|
+
}
|
|
765
794
|
listDashboardMemories(options = {}) {
|
|
766
795
|
const limit = Math.max(1, Number(options.limit || 40));
|
|
767
796
|
const raw = this.getMemory()?.listSnapshots(Math.min(limit * 3, 200), {
|
|
@@ -769,21 +798,20 @@ export class DashboardServer {
|
|
|
769
798
|
tag: options.tag,
|
|
770
799
|
linkedType: options.linkedType,
|
|
771
800
|
recencyMs: options.recencyMs,
|
|
801
|
+
state: options.includeHidden || options.lane === 'inbox' ? undefined : 'active',
|
|
772
802
|
lane: options.lane,
|
|
773
803
|
repoId: options.repoId,
|
|
774
804
|
workspaceId: options.workspaceId,
|
|
775
805
|
projectId: options.projectId,
|
|
776
806
|
includeHidden: options.includeHidden,
|
|
777
807
|
}) ?? [];
|
|
778
|
-
|
|
808
|
+
const visible = raw
|
|
779
809
|
.filter((memory) => {
|
|
780
810
|
const tags = Array.isArray(memory.tags) ? memory.tags : [];
|
|
781
811
|
if (!options.includeHidden && tags.includes('#system-hidden'))
|
|
782
812
|
return false;
|
|
783
813
|
if (!options.includeHidden && tags.includes('#auto') && Number(memory.priority ?? 0) < 0.4)
|
|
784
814
|
return false;
|
|
785
|
-
if (options.repoName && !tags.some((t) => t === `repo:${options.repoName}`))
|
|
786
|
-
return false;
|
|
787
815
|
if (tags.includes('#quarantine') && options.lane !== 'inbox')
|
|
788
816
|
return false;
|
|
789
817
|
if (!options.showPhantom && (tags.includes('#phantom-learning') || tags.includes('#swarm')))
|
|
@@ -793,8 +821,11 @@ export class DashboardServer {
|
|
|
793
821
|
if (!options.includeHidden && (tags.includes('#hidden') || tags.includes('#repo-profile') || tags.includes('#system-hidden')))
|
|
794
822
|
return false;
|
|
795
823
|
return true;
|
|
796
|
-
})
|
|
797
|
-
|
|
824
|
+
});
|
|
825
|
+
const scoped = options.repoName
|
|
826
|
+
? visible.filter((memory) => this.dashboardMemoryMatchesRepoName(memory, options.repoName))
|
|
827
|
+
: visible;
|
|
828
|
+
return (options.repoName && scoped.length === 0 ? visible : scoped).slice(0, limit);
|
|
798
829
|
}
|
|
799
830
|
listCrossProjectMemories(options) {
|
|
800
831
|
const memory = this.getMemory();
|
package/dist/index.d.ts
CHANGED
|
@@ -281,3 +281,10 @@ export declare class NexusPrime {
|
|
|
281
281
|
private getDefaultCapabilities;
|
|
282
282
|
}
|
|
283
283
|
export declare const createNexusPrime: (config?: Partial<NexusConfig>) => NexusPrime;
|
|
284
|
+
export { GhostPass, PhantomOrchestrator, PhantomWorker } from './phantom/index.js';
|
|
285
|
+
export type { GhostReport, WorkerTask, WorkerResult, MergeDecision } from './phantom/index.js';
|
|
286
|
+
export { MemoryEngine, createMemoryEngine } from './engines/memory.js';
|
|
287
|
+
export { SessionDNAManager } from './engines/session-dna.js';
|
|
288
|
+
export type { SessionDNA } from './engines/session-dna.js';
|
|
289
|
+
export { GithubBridge, getSharedGithubBridge } from './engines/github-bridge.js';
|
|
290
|
+
export type { GithubPromotionInput, GithubPromotionResult } from './engines/github-bridge.js';
|
package/dist/index.js
CHANGED
|
@@ -1193,3 +1193,8 @@ function detectCurrentClient() {
|
|
|
1193
1193
|
}
|
|
1194
1194
|
return null;
|
|
1195
1195
|
}
|
|
1196
|
+
// Public API surface for sibling packages (e.g., @nexus-prime/finishit)
|
|
1197
|
+
export { GhostPass, PhantomOrchestrator, PhantomWorker } from './phantom/index.js';
|
|
1198
|
+
export { MemoryEngine, createMemoryEngine } from './engines/memory.js';
|
|
1199
|
+
export { SessionDNAManager } from './engines/session-dna.js';
|
|
1200
|
+
export { GithubBridge, getSharedGithubBridge } from './engines/github-bridge.js';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nexus-prime",
|
|
3
|
-
"version": "7.9.
|
|
3
|
+
"version": "7.9.1",
|
|
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",
|