nexus-prime 7.9.19 → 7.9.20
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 +2 -3
- package/dist/agents/adapters/mcp/handlers/governance.js +1 -1
- package/dist/cli/doctor-storage.js +1 -2
- package/dist/cli.js +12 -11
- package/dist/daemon/client.d.ts +1 -0
- package/dist/daemon/server.js +1 -0
- package/dist/dashboard/server.js +22 -1
- package/dist/engines/ngram-index.d.ts +4 -1
- package/dist/engines/ngram-index.js +16 -14
- package/dist/index.d.ts +1 -0
- package/dist/index.js +4 -1
- package/package.json +1 -1
|
@@ -976,11 +976,10 @@ export function buildMcpToolDefinitions() {
|
|
|
976
976
|
required: ['taskId', 'goal', 'findings'],
|
|
977
977
|
},
|
|
978
978
|
},
|
|
979
|
-
// When NEXUS_DISABLE_WORKFORCE=1 (
|
|
979
|
+
// When NEXUS_DISABLE_WORKFORCE=1 (explicit break-glass mode),
|
|
980
980
|
// strip the 24 nexus_synapse_* / nexus_architects_* tools from the
|
|
981
981
|
// catalog so the model doesn't see surface area for engines that
|
|
982
|
-
// aren't initialized at runtime.
|
|
983
|
-
// re-enable both engines + their tools.
|
|
982
|
+
// aren't initialized at runtime.
|
|
984
983
|
...(process.env.NEXUS_DISABLE_WORKFORCE === '1' ? [] : synapseToolDefinitions),
|
|
985
984
|
...(process.env.NEXUS_DISABLE_WORKFORCE === '1' ? [] : architectsToolDefinitions),
|
|
986
985
|
// ── Workforce (unified worker+job layer) ──────────────────────────
|
|
@@ -173,7 +173,7 @@ export async function handleGovernanceGroup(toolName, hctx, request, args, ctx)
|
|
|
173
173
|
const manifest = ensureBootstrap({
|
|
174
174
|
packageRoot: PROJECT_ROOT,
|
|
175
175
|
workspaceRoot: hctx.nexusRef.getWorkspaceContext().workspaceRoot,
|
|
176
|
-
phase: '
|
|
176
|
+
phase: 'install',
|
|
177
177
|
silent: true,
|
|
178
178
|
});
|
|
179
179
|
const memoryMaintenance = hctx.nexusRef.maintainMemory();
|
|
@@ -12,10 +12,9 @@ import { resolveRunsBudget, resolveWorktreeBudget } from './cleanup.js';
|
|
|
12
12
|
import { dirBytes, formatBytes } from '../install/fs-purge.js';
|
|
13
13
|
import { enumerateNgramArchives, enumerateStatePaths, getNexusStateDir, getRuntimeTmpRoots, getWorktreeRoots, } from '../install/state-locator.js';
|
|
14
14
|
import { INSTALL_ARCH_GENERATION, loadManifest, } from '../install/manifest.js';
|
|
15
|
-
import { getNgramFootprintBytes } from '../engines/ngram-index.js';
|
|
15
|
+
import { getNgramFootprintBytes, NGRAM_DEFAULT_FOOTPRINT_BYTES } from '../engines/ngram-index.js';
|
|
16
16
|
import { getSharedLicenseManager } from '../licensing/license-manager.js';
|
|
17
17
|
const NGRAM_DEFAULT_WAL_LIMIT_BYTES = 64 * 1024 * 1024;
|
|
18
|
-
const NGRAM_DEFAULT_FOOTPRINT_BYTES = 512 * 1024 * 1024;
|
|
19
18
|
function readEnvBytesPositive(name, fallback) {
|
|
20
19
|
const raw = process.env[name];
|
|
21
20
|
if (!raw)
|
package/dist/cli.js
CHANGED
|
@@ -30,7 +30,7 @@ import { cliSetup, configureIDE, computeFileHash, readSetupMarker, writeSetupMar
|
|
|
30
30
|
import { isNewUser, promptLicenseKey, printReturningUserBanner } from './cli/interactive-setup.js';
|
|
31
31
|
import { runHookBootstrap, runHookMemory, runHookMindkit, runHookGhostPass, runHookSessionDna } from './cli/hook.js';
|
|
32
32
|
import { resolveWorkspaceContext } from './engines/workspace-resolver.js';
|
|
33
|
-
import { ensureDaemonReady, getDaemonStatus, stopDaemon } from './daemon/client.js';
|
|
33
|
+
import { ensureDaemonReady, getDaemonStatus, pingDaemonHealth, stopDaemon } from './daemon/client.js';
|
|
34
34
|
import { NexusDaemonServer } from './daemon/server.js';
|
|
35
35
|
import { DaemonSupervisor } from './daemon/supervisor.js';
|
|
36
36
|
import { startDaemonBackedMcpProxy } from './daemon/proxy.js';
|
|
@@ -720,8 +720,10 @@ program
|
|
|
720
720
|
try {
|
|
721
721
|
const record = await ensureDaemonManaged({ force: options.force });
|
|
722
722
|
const dashboardPort = process.env.NEXUS_DASHBOARD_PORT ?? '3377';
|
|
723
|
+
const health = await pingDaemonHealth(record).catch(() => null);
|
|
724
|
+
const dashboardUrl = health?.dashboardUrl ?? `http://localhost:${dashboardPort}`;
|
|
723
725
|
console.log(`Nexus Prime daemon running (pid ${record.pid}, ${formatDaemonAddress(record)})`);
|
|
724
|
-
console.log(`Dashboard:
|
|
726
|
+
console.log(`Dashboard: ${dashboardUrl}`);
|
|
725
727
|
}
|
|
726
728
|
catch (err) {
|
|
727
729
|
console.error(`Failed to start daemon: ${err.message}`);
|
|
@@ -820,15 +822,14 @@ program
|
|
|
820
822
|
if (process.env.NEXUS_DAEMON_FAST_START === undefined) {
|
|
821
823
|
process.env.NEXUS_DAEMON_FAST_START = '1';
|
|
822
824
|
}
|
|
823
|
-
//
|
|
824
|
-
//
|
|
825
|
-
//
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
process.env.NEXUS_DISABLE_WORKFORCE = '1';
|
|
825
|
+
// Keep daemon startup fast, but do not disable workforce. Synapse and
|
|
826
|
+
// Architects can lazily warm on first hire/tool call unless the operator
|
|
827
|
+
// explicitly sets the NEXUS_DISABLE_WORKFORCE escape hatch.
|
|
828
|
+
if (process.env.NEXUS_SYNAPSE_LAZY === undefined) {
|
|
829
|
+
process.env.NEXUS_SYNAPSE_LAZY = '1';
|
|
830
|
+
}
|
|
831
|
+
if (process.env.NEXUS_ARCHITECTS_LAZY === undefined) {
|
|
832
|
+
process.env.NEXUS_ARCHITECTS_LAZY = '1';
|
|
832
833
|
}
|
|
833
834
|
const workspaceContext = resolveWorkspaceContext({ workspaceRoot: getWorkspaceRoot() });
|
|
834
835
|
const daemon = new NexusDaemonServer(workspaceContext);
|
package/dist/daemon/client.d.ts
CHANGED
package/dist/daemon/server.js
CHANGED
|
@@ -390,6 +390,7 @@ export class NexusDaemonServer {
|
|
|
390
390
|
stateKey: this.workspace.stateKey,
|
|
391
391
|
workspaceRoot: this.workspace.workspaceRoot,
|
|
392
392
|
repoRoot: this.workspace.repoRoot,
|
|
393
|
+
dashboardUrl: this.nexus?.getDashboardAddress?.() ?? null,
|
|
393
394
|
startedAt: this.lockRecord?.startedAt ?? Date.now(),
|
|
394
395
|
});
|
|
395
396
|
return;
|
package/dist/dashboard/server.js
CHANGED
|
@@ -1126,9 +1126,26 @@ export class DashboardServer {
|
|
|
1126
1126
|
const capabilities = this.buildAdvertisedCapabilities();
|
|
1127
1127
|
const compatibility = this.buildCompatibilityStatus(capabilities);
|
|
1128
1128
|
const runtimeEnvelope = this.buildProbeRuntimeEnvelope();
|
|
1129
|
+
const workspace = this.resolveCanonicalWorkspaceContext();
|
|
1129
1130
|
return {
|
|
1130
1131
|
dashboardApiVersion: DASHBOARD_API_VERSION,
|
|
1131
|
-
projectName:
|
|
1132
|
+
projectName: workspace.repoName,
|
|
1133
|
+
repoIdentity: {
|
|
1134
|
+
repoName: workspace.repoName,
|
|
1135
|
+
repoRoot: workspace.repoRoot,
|
|
1136
|
+
workspaceRoot: workspace.workspaceRoot,
|
|
1137
|
+
workspaceSource: workspace.workspaceSource,
|
|
1138
|
+
workspaceStateKey: workspace.stateKey,
|
|
1139
|
+
remoteUrl: workspace.remoteUrl ?? null,
|
|
1140
|
+
currentRepoId: null,
|
|
1141
|
+
},
|
|
1142
|
+
scanContext: {
|
|
1143
|
+
repoRoot: workspace.repoRoot,
|
|
1144
|
+
workspaceRoot: workspace.workspaceRoot,
|
|
1145
|
+
workspaceSource: workspace.workspaceSource,
|
|
1146
|
+
workspaceStateKey: workspace.stateKey,
|
|
1147
|
+
notes: ['Probe snapshot uses the lightweight compatibility contract.'],
|
|
1148
|
+
},
|
|
1132
1149
|
capabilities,
|
|
1133
1150
|
compatibility,
|
|
1134
1151
|
dashboardUrl: this.getAddress(),
|
|
@@ -1513,6 +1530,10 @@ export class DashboardServer {
|
|
|
1513
1530
|
if (payload.compatibility?.status !== 'compatible') {
|
|
1514
1531
|
return false;
|
|
1515
1532
|
}
|
|
1533
|
+
const stateRoot = payload.runtimeEnvelope?.workspace?.stateRoot;
|
|
1534
|
+
if (!stateRoot || path.resolve(stateRoot) !== path.resolve(resolveNexusStateDir())) {
|
|
1535
|
+
return false;
|
|
1536
|
+
}
|
|
1516
1537
|
const required = payload.compatibility?.requiredCapabilities?.length
|
|
1517
1538
|
? payload.compatibility.requiredCapabilities
|
|
1518
1539
|
: [...DASHBOARD_COMPATIBILITY_CAPABILITIES];
|
|
@@ -11,6 +11,9 @@
|
|
|
11
11
|
*
|
|
12
12
|
* Persistence: SQLite (same pattern as memory.db / graph.db)
|
|
13
13
|
*/
|
|
14
|
+
export declare const NGRAM_WARMUP_MAX_DB_BYTES: number;
|
|
15
|
+
export declare const NGRAM_DEFAULT_ROTATE_BYTES: number;
|
|
16
|
+
export declare const NGRAM_DEFAULT_FOOTPRINT_BYTES: number;
|
|
14
17
|
export declare function getNgramWalPath(dbPath: string): string;
|
|
15
18
|
export declare function getNgramShmPath(dbPath: string): string;
|
|
16
19
|
export declare function getNgramFootprintBytes(dbPath: string): number;
|
|
@@ -147,7 +150,7 @@ export declare class NgramIndex {
|
|
|
147
150
|
optimizeStorage(force?: boolean): void;
|
|
148
151
|
/**
|
|
149
152
|
* Operator-focused maintenance for the on-disk ngram DB.
|
|
150
|
-
* - Bounds runaway DB growth via rotation
|
|
153
|
+
* - Bounds runaway DB growth via rotation, counting the
|
|
151
154
|
* full SQLite footprint (db + wal + shm) so a runaway WAL triggers it.
|
|
152
155
|
* - Vacuums only when safe (<= vacuumMaxBytes) and either forced or dirty.
|
|
153
156
|
*/
|
|
@@ -45,7 +45,9 @@ function safeStatSize(filePath) {
|
|
|
45
45
|
// wal/shm misses the bug that turned ngram-index.db-wal into 84GB on disk.
|
|
46
46
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
47
47
|
const NGRAM_DEFAULT_WAL_LIMIT_BYTES = 64 * 1024 * 1024; // 64 MB
|
|
48
|
-
const
|
|
48
|
+
export const NGRAM_WARMUP_MAX_DB_BYTES = 200 * 1024 * 1024; // 200 MB
|
|
49
|
+
export const NGRAM_DEFAULT_ROTATE_BYTES = NGRAM_WARMUP_MAX_DB_BYTES;
|
|
50
|
+
export const NGRAM_DEFAULT_FOOTPRINT_BYTES = NGRAM_WARMUP_MAX_DB_BYTES;
|
|
49
51
|
const NGRAM_DEFAULT_CHECKPOINT_INTERVAL_MS = 30_000;
|
|
50
52
|
const NGRAM_DEFAULT_CHECKPOINT_DOC_COUNT = 200;
|
|
51
53
|
export function getNgramWalPath(dbPath) {
|
|
@@ -199,13 +201,13 @@ export class NgramIndex {
|
|
|
199
201
|
this.warmHashSet();
|
|
200
202
|
try {
|
|
201
203
|
const sizeBytes = safeStatSize(this.dbPath);
|
|
202
|
-
// Only VACUUM on medium-size DBs. Large DBs
|
|
204
|
+
// Only VACUUM on medium-size DBs. Large DBs take too long
|
|
203
205
|
// synchronously — VACUUM rewrites the entire file. Skip here; let
|
|
204
206
|
// periodic maintenance handle it.
|
|
205
|
-
if (sizeBytes > 32 * 1024 * 1024 && sizeBytes <=
|
|
207
|
+
if (sizeBytes > 32 * 1024 * 1024 && sizeBytes <= NGRAM_WARMUP_MAX_DB_BYTES) {
|
|
206
208
|
this.optimizeStorage(true);
|
|
207
209
|
}
|
|
208
|
-
else if (sizeBytes >
|
|
210
|
+
else if (sizeBytes > NGRAM_WARMUP_MAX_DB_BYTES) {
|
|
209
211
|
logNgramNoticeOnce(`ngram:vacuum-skip:${this.dbPath}`, `[NgramIndex] skipping VACUUM on large DB (${Math.round(sizeBytes / 1024 / 1024)}MB) db=${this.dbPath}`);
|
|
210
212
|
}
|
|
211
213
|
}
|
|
@@ -217,17 +219,17 @@ export class NgramIndex {
|
|
|
217
219
|
// Count the full SQLite footprint (db + wal + shm). The 84GB regression
|
|
218
220
|
// happened because a 32MB db file had a 84GB -wal sibling that this
|
|
219
221
|
// routine never inspected.
|
|
220
|
-
const rotateBytes = readEnvBytes('NEXUS_NGRAM_ROTATE_BYTES',
|
|
222
|
+
const rotateBytes = readEnvBytes('NEXUS_NGRAM_ROTATE_BYTES', NGRAM_DEFAULT_ROTATE_BYTES);
|
|
221
223
|
const dbBytes = safeStatSize(this.dbPath);
|
|
222
224
|
const footprint = getNgramFootprintBytes(this.dbPath);
|
|
223
225
|
if (footprint <= 0 || footprint < rotateBytes)
|
|
224
226
|
return;
|
|
225
|
-
//
|
|
226
|
-
//
|
|
227
|
-
//
|
|
227
|
+
// The n-gram DB is a rebuildable cache, so oversized rotation drops it by
|
|
228
|
+
// default. Operators can opt into one retained archive for forensics with
|
|
229
|
+
// NEXUS_NGRAM_ARCHIVE_OVERSIZE=1.
|
|
228
230
|
const dir = path.dirname(this.dbPath);
|
|
229
231
|
const base = path.basename(this.dbPath);
|
|
230
|
-
const archiveEnabled = process.env.NEXUS_NGRAM_ARCHIVE_OVERSIZE
|
|
232
|
+
const archiveEnabled = process.env.NEXUS_NGRAM_ARCHIVE_OVERSIZE === '1';
|
|
231
233
|
const existing = fs.existsSync(dir)
|
|
232
234
|
? fs.readdirSync(dir).filter((entry) => entry.startsWith(`${base}.oversize.`)).sort().reverse()
|
|
233
235
|
: [];
|
|
@@ -324,8 +326,8 @@ export class NgramIndex {
|
|
|
324
326
|
// Size guard: SELECT DISTINCT on very large DBs blocks startup under swap pressure.
|
|
325
327
|
try {
|
|
326
328
|
const sizeBytes = fs.statSync(this.dbPath).size;
|
|
327
|
-
if (sizeBytes >
|
|
328
|
-
logNgramNoticeOnce(`ngram:warmup-skip:${this.dbPath}`, `[NgramIndex] warmup skipped — DB too large (${Math.round(sizeBytes / 1024 / 1024)}MB >
|
|
329
|
+
if (sizeBytes > NGRAM_WARMUP_MAX_DB_BYTES) {
|
|
330
|
+
logNgramNoticeOnce(`ngram:warmup-skip:${this.dbPath}`, `[NgramIndex] warmup skipped — DB too large (${Math.round(sizeBytes / 1024 / 1024)}MB > ${Math.round(NGRAM_WARMUP_MAX_DB_BYTES / 1024 / 1024)}MB) db=${this.dbPath}`);
|
|
329
331
|
return;
|
|
330
332
|
}
|
|
331
333
|
}
|
|
@@ -667,17 +669,17 @@ export class NgramIndex {
|
|
|
667
669
|
}
|
|
668
670
|
/**
|
|
669
671
|
* Operator-focused maintenance for the on-disk ngram DB.
|
|
670
|
-
* - Bounds runaway DB growth via rotation
|
|
672
|
+
* - Bounds runaway DB growth via rotation, counting the
|
|
671
673
|
* full SQLite footprint (db + wal + shm) so a runaway WAL triggers it.
|
|
672
674
|
* - Vacuums only when safe (<= vacuumMaxBytes) and either forced or dirty.
|
|
673
675
|
*/
|
|
674
676
|
maintainBounded(options = {}) {
|
|
675
677
|
const dbBytes = safeStatSize(this.dbPath);
|
|
676
678
|
const footprint = this.getSqliteFootprintBytes();
|
|
677
|
-
const rotateBytes = readEnvBytes('NEXUS_NGRAM_ROTATE_BYTES',
|
|
679
|
+
const rotateBytes = readEnvBytes('NEXUS_NGRAM_ROTATE_BYTES', NGRAM_DEFAULT_ROTATE_BYTES);
|
|
678
680
|
const vacuumMaxBytes = readEnvBytes('NEXUS_NGRAM_VACUUM_MAX_BYTES', 256 * 1024 * 1024);
|
|
679
681
|
if (footprint >= rotateBytes && footprint > 0) {
|
|
680
|
-
const archiveEnabled = process.env.NEXUS_NGRAM_ARCHIVE_OVERSIZE
|
|
682
|
+
const archiveEnabled = process.env.NEXUS_NGRAM_ARCHIVE_OVERSIZE === '1';
|
|
681
683
|
const rotatedPath = `${this.dbPath}.oversize.${Date.now()}`;
|
|
682
684
|
const removeSibling = (suffix) => {
|
|
683
685
|
try {
|
package/dist/index.d.ts
CHANGED
|
@@ -213,6 +213,7 @@ export declare class NexusPrime {
|
|
|
213
213
|
awaitReady(): Promise<void>;
|
|
214
214
|
getClientRegistry(): ClientRegistry;
|
|
215
215
|
getRuntimeHotAt(): number | null;
|
|
216
|
+
getDashboardAddress(): string | null;
|
|
216
217
|
getSynapse(): SynapseRuntime | null;
|
|
217
218
|
getArchitects(): ArchitectsRuntime | null;
|
|
218
219
|
/**
|
package/dist/index.js
CHANGED
|
@@ -847,6 +847,9 @@ export class NexusPrime {
|
|
|
847
847
|
getRuntimeHotAt() {
|
|
848
848
|
return this.runtimeHotAt;
|
|
849
849
|
}
|
|
850
|
+
getDashboardAddress() {
|
|
851
|
+
return this.dashboardServer.getAddress();
|
|
852
|
+
}
|
|
850
853
|
getSynapse() {
|
|
851
854
|
return this.synapse;
|
|
852
855
|
}
|
|
@@ -1070,7 +1073,7 @@ export class NexusPrime {
|
|
|
1070
1073
|
const bootstrapManifest = ensureBootstrap({
|
|
1071
1074
|
packageRoot: PACKAGE_ROOT,
|
|
1072
1075
|
workspaceRoot: this.getWorkspaceContext().workspaceRoot,
|
|
1073
|
-
phase: '
|
|
1076
|
+
phase: 'install',
|
|
1074
1077
|
silent: true,
|
|
1075
1078
|
});
|
|
1076
1079
|
this.runtime.recordBootstrapManifestStatus?.(bootstrapManifest);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nexus-prime",
|
|
3
|
-
"version": "7.9.
|
|
3
|
+
"version": "7.9.20",
|
|
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",
|