nexus-prime 7.9.16 → 7.9.17
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/handlers/runtime.js +4 -2
- package/dist/agents/adapters/mcp/types.js +2 -0
- package/dist/cli/install-wizard.js +12 -4
- package/dist/cli.js +19 -7
- package/dist/engines/client-bootstrap.d.ts +1 -0
- package/dist/engines/client-bootstrap.js +16 -5
- package/dist/engines/mcp-entrypoint.d.ts +1 -1
- package/dist/engines/mcp-entrypoint.js +42 -4
- package/dist/licensing/enforcement.js +1 -4
- package/dist/licensing/license-manager.js +4 -17
- package/dist/licensing/types.d.ts +1 -1
- package/dist/licensing/upgrade-prompts.js +13 -4
- package/package.json +1 -1
|
@@ -44,8 +44,10 @@ export async function handleRuntimeGroup(toolName, hctx, request, args, ctx) {
|
|
|
44
44
|
? `- **Trial remaining**: ${licStatus.trialDaysRemaining} day${licStatus.trialDaysRemaining === 1 ? '' : 's'}`
|
|
45
45
|
: '',
|
|
46
46
|
licStatus.activationRequired
|
|
47
|
-
? `- **Agent motion**:
|
|
48
|
-
:
|
|
47
|
+
? `- **Agent motion**: License activation is required for paid-tier work; keep license/status tools available.`
|
|
48
|
+
: licStatus.trialPhase === 'activation'
|
|
49
|
+
? `- **Agent motion**: Trial remains active; ask the user to request or activate a license soon, then keep working.`
|
|
50
|
+
: `- **Agent motion**: No license is mandatory during the first 3 days; ask the user to request a license soon.`,
|
|
49
51
|
].filter((line) => Boolean(line)) : [];
|
|
50
52
|
const lines = [
|
|
51
53
|
`## License Status`,
|
|
@@ -154,6 +154,8 @@ export class SessionTelemetry {
|
|
|
154
154
|
needsOptimizeTokens(currentToolName) {
|
|
155
155
|
if (currentToolName === 'nexus_optimize_tokens')
|
|
156
156
|
return false;
|
|
157
|
+
if (currentToolName === 'nexus_mindkit_check')
|
|
158
|
+
return false;
|
|
157
159
|
if (this.lifecyclePhase === 'pre-bootstrap')
|
|
158
160
|
return false;
|
|
159
161
|
if (this.tokenAutoApplied)
|
|
@@ -39,6 +39,13 @@ const SETUP_CLIENT_BY_IDE = {
|
|
|
39
39
|
cline: 'cline',
|
|
40
40
|
codex: 'codex',
|
|
41
41
|
};
|
|
42
|
+
function resolveSetupWorkspaceRoot(explicitWorkspaceRoot) {
|
|
43
|
+
return resolveWorkspaceContext({
|
|
44
|
+
workspaceRoot: explicitWorkspaceRoot,
|
|
45
|
+
cwd: process.cwd(),
|
|
46
|
+
env: process.env,
|
|
47
|
+
}).workspaceRoot;
|
|
48
|
+
}
|
|
42
49
|
function isSetupMarker(value) {
|
|
43
50
|
if (!value || typeof value !== 'object') {
|
|
44
51
|
return false;
|
|
@@ -89,7 +96,7 @@ export function writeSetupMarker(marker, markerPath = SETUP_MARKER_PATH) {
|
|
|
89
96
|
return nextMarker;
|
|
90
97
|
}
|
|
91
98
|
export async function configureIDE(ide, opts = {}) {
|
|
92
|
-
const workspaceRoot =
|
|
99
|
+
const workspaceRoot = resolveSetupWorkspaceRoot(opts.workspaceRoot);
|
|
93
100
|
const mappedClient = SETUP_CLIENT_BY_IDE[ide];
|
|
94
101
|
if (mappedClient) {
|
|
95
102
|
const definition = getSetupDefinition(mappedClient, {
|
|
@@ -285,7 +292,7 @@ export function runArchitectureUpgrade(opts = {}) {
|
|
|
285
292
|
}
|
|
286
293
|
/** Run the install wizard: detect IDEs and write MCP configs. */
|
|
287
294
|
export async function runInstallWizard(opts = {}) {
|
|
288
|
-
const workspaceRoot =
|
|
295
|
+
const workspaceRoot = resolveSetupWorkspaceRoot(opts.workspaceRoot);
|
|
289
296
|
const verbose = opts.verbose ?? true;
|
|
290
297
|
const dryRun = opts.dryRun ?? false;
|
|
291
298
|
const setupMarker = readSetupMarker();
|
|
@@ -414,6 +421,7 @@ export async function cliSetup(opts = []) {
|
|
|
414
421
|
const port = process.env.NEXUS_DASHBOARD_PORT ?? '3377';
|
|
415
422
|
const dashUrl = `http://localhost:${port}`;
|
|
416
423
|
const isNew = options.isNewUser ?? false;
|
|
424
|
+
const workspaceRoot = resolveSetupWorkspaceRoot();
|
|
417
425
|
const ANSI = { cyan: '\x1b[36m', green: '\x1b[32m', yellow: '\x1b[33m', dim: '\x1b[2m', reset: '\x1b[0m' };
|
|
418
426
|
const isTTY = process.stdout.isTTY === true && !process.env.NO_COLOR;
|
|
419
427
|
const c = (s, k) => isTTY ? `${ANSI[k]}${s}${ANSI.reset}` : s;
|
|
@@ -438,7 +446,7 @@ export async function cliSetup(opts = []) {
|
|
|
438
446
|
}
|
|
439
447
|
catch { /* non-fatal */ }
|
|
440
448
|
};
|
|
441
|
-
const result = await runInstallWizard({ dryRun, verbose: false });
|
|
449
|
+
const result = await runInstallWizard({ workspaceRoot, dryRun, verbose: false });
|
|
442
450
|
const allIDEs = [...result.configured, ...result.skipped, ...result.errors.map(e => e.ide)];
|
|
443
451
|
if (allIDEs.length > 0) {
|
|
444
452
|
for (const ide of allIDEs) {
|
|
@@ -499,7 +507,7 @@ export async function cliSetup(opts = []) {
|
|
|
499
507
|
let daemonReady = false;
|
|
500
508
|
if (!dryRun) {
|
|
501
509
|
try {
|
|
502
|
-
const workspace = resolveWorkspaceContext({ workspaceRoot: process.cwd() });
|
|
510
|
+
const workspace = resolveWorkspaceContext({ workspaceRoot, cwd: process.cwd(), env: process.env });
|
|
503
511
|
await withSpinner('Connecting to daemon', ensureDaemonReady(workspace, { timeoutMs: DEFAULT_DAEMON_READY_TIMEOUT_MS, entrypoint: process.argv[1] }));
|
|
504
512
|
daemonReady = true;
|
|
505
513
|
log(` ${c('✓', 'green')} Dashboard: ${c(dashUrl, 'cyan')}`);
|
package/dist/cli.js
CHANGED
|
@@ -454,11 +454,13 @@ function resolveClaudeDesktopConfigPath() {
|
|
|
454
454
|
return join(homedir(), '.claude', 'claude_desktop_config.json');
|
|
455
455
|
}
|
|
456
456
|
function getSetupDefinition(clientId) {
|
|
457
|
+
const workspaceRoot = getWorkspaceRoot();
|
|
457
458
|
const instructionFiles = buildInstructionFiles(clientId);
|
|
458
459
|
if (clientId === 'codex') {
|
|
459
460
|
return {
|
|
460
461
|
id: clientId,
|
|
461
462
|
label: 'Codex',
|
|
463
|
+
workspaceRoot,
|
|
462
464
|
configPath: resolveCodexConfigPath(),
|
|
463
465
|
instructionFiles,
|
|
464
466
|
};
|
|
@@ -467,6 +469,7 @@ function getSetupDefinition(clientId) {
|
|
|
467
469
|
return {
|
|
468
470
|
id: clientId,
|
|
469
471
|
label: 'Cursor',
|
|
472
|
+
workspaceRoot,
|
|
470
473
|
configPath: join(homedir(), '.cursor', 'mcp.json'),
|
|
471
474
|
instructionFiles,
|
|
472
475
|
};
|
|
@@ -475,7 +478,8 @@ function getSetupDefinition(clientId) {
|
|
|
475
478
|
return {
|
|
476
479
|
id: clientId,
|
|
477
480
|
label: 'Claude Code',
|
|
478
|
-
|
|
481
|
+
workspaceRoot,
|
|
482
|
+
configPath: join(workspaceRoot, '.mcp.json'),
|
|
479
483
|
instructionFiles,
|
|
480
484
|
};
|
|
481
485
|
}
|
|
@@ -483,6 +487,7 @@ function getSetupDefinition(clientId) {
|
|
|
483
487
|
return {
|
|
484
488
|
id: clientId,
|
|
485
489
|
label: 'Claude Desktop',
|
|
490
|
+
workspaceRoot,
|
|
486
491
|
configPath: resolveClaudeDesktopConfigPath(),
|
|
487
492
|
instructionFiles,
|
|
488
493
|
};
|
|
@@ -491,6 +496,7 @@ function getSetupDefinition(clientId) {
|
|
|
491
496
|
return {
|
|
492
497
|
id: clientId,
|
|
493
498
|
label: 'Opencode',
|
|
499
|
+
workspaceRoot,
|
|
494
500
|
configPath: join(homedir(), '.config', 'opencode', 'opencode.json'),
|
|
495
501
|
instructionFiles,
|
|
496
502
|
};
|
|
@@ -499,6 +505,7 @@ function getSetupDefinition(clientId) {
|
|
|
499
505
|
return {
|
|
500
506
|
id: clientId,
|
|
501
507
|
label: 'Windsurf',
|
|
508
|
+
workspaceRoot,
|
|
502
509
|
configPath: join(homedir(), '.windsurf', 'mcp.json'),
|
|
503
510
|
instructionFiles,
|
|
504
511
|
};
|
|
@@ -507,6 +514,7 @@ function getSetupDefinition(clientId) {
|
|
|
507
514
|
return {
|
|
508
515
|
id: clientId,
|
|
509
516
|
label: 'Antigravity / OpenClaw',
|
|
517
|
+
workspaceRoot,
|
|
510
518
|
configPath: join(homedir(), '.antigravity', 'mcp.json'),
|
|
511
519
|
instructionFiles,
|
|
512
520
|
};
|
|
@@ -515,6 +523,7 @@ function getSetupDefinition(clientId) {
|
|
|
515
523
|
return {
|
|
516
524
|
id: clientId,
|
|
517
525
|
label: 'Aider',
|
|
526
|
+
workspaceRoot,
|
|
518
527
|
configPath: join(homedir(), '.aider', 'mcp.json'),
|
|
519
528
|
instructionFiles,
|
|
520
529
|
};
|
|
@@ -523,6 +532,7 @@ function getSetupDefinition(clientId) {
|
|
|
523
532
|
return {
|
|
524
533
|
id: clientId,
|
|
525
534
|
label: 'Continue.dev',
|
|
535
|
+
workspaceRoot,
|
|
526
536
|
configPath: join(homedir(), '.continue', 'config.json'),
|
|
527
537
|
instructionFiles,
|
|
528
538
|
};
|
|
@@ -531,6 +541,7 @@ function getSetupDefinition(clientId) {
|
|
|
531
541
|
return {
|
|
532
542
|
id: clientId,
|
|
533
543
|
label: 'OpenClaw',
|
|
544
|
+
workspaceRoot,
|
|
534
545
|
configPath: join(homedir(), '.openclaw', 'openclaw.json'),
|
|
535
546
|
instructionFiles,
|
|
536
547
|
};
|
|
@@ -538,6 +549,7 @@ function getSetupDefinition(clientId) {
|
|
|
538
549
|
return {
|
|
539
550
|
id: clientId,
|
|
540
551
|
label: 'Cline',
|
|
552
|
+
workspaceRoot,
|
|
541
553
|
configPath: join(homedir(), '.vscode', 'cline-mcp.json'),
|
|
542
554
|
instructionFiles,
|
|
543
555
|
};
|
|
@@ -548,10 +560,10 @@ function installSetup(definition) {
|
|
|
548
560
|
writeCodexMcpConfig(definition.configPath);
|
|
549
561
|
}
|
|
550
562
|
else if (definition.id === 'opencode') {
|
|
551
|
-
writeOpencodeConfig(definition.configPath,
|
|
563
|
+
writeOpencodeConfig(definition.configPath, definition.workspaceRoot);
|
|
552
564
|
}
|
|
553
565
|
else {
|
|
554
|
-
writeStandardMcpConfig(definition.configPath,
|
|
566
|
+
writeStandardMcpConfig(definition.configPath, definition.workspaceRoot);
|
|
555
567
|
}
|
|
556
568
|
}
|
|
557
569
|
for (const file of definition.instructionFiles) {
|
|
@@ -585,12 +597,12 @@ function printSetupPreview(definition) {
|
|
|
585
597
|
console.log(JSON.stringify(definition.id === 'opencode'
|
|
586
598
|
? {
|
|
587
599
|
mcp: {
|
|
588
|
-
servers: [{ id: 'nexus-prime', ...buildStandardMcpServerConfig(
|
|
600
|
+
servers: [{ id: 'nexus-prime', ...buildStandardMcpServerConfig(definition.workspaceRoot) }]
|
|
589
601
|
}
|
|
590
602
|
}
|
|
591
603
|
: {
|
|
592
604
|
mcpServers: {
|
|
593
|
-
'nexus-prime': buildStandardMcpServerConfig(
|
|
605
|
+
'nexus-prime': buildStandardMcpServerConfig(definition.workspaceRoot)
|
|
594
606
|
}
|
|
595
607
|
}, null, 2));
|
|
596
608
|
}
|
|
@@ -612,10 +624,10 @@ function hasExpectedConfig(definition) {
|
|
|
612
624
|
return false;
|
|
613
625
|
if (definition.id === 'opencode') {
|
|
614
626
|
const server = parsed?.mcp?.['nexus-prime'];
|
|
615
|
-
return Boolean(server && isStableNexusMcpServerConfig(server, 'environment'));
|
|
627
|
+
return Boolean(server && isStableNexusMcpServerConfig(server, 'environment', definition.workspaceRoot));
|
|
616
628
|
}
|
|
617
629
|
const server = parsed?.mcpServers?.['nexus-prime'];
|
|
618
|
-
return Boolean(server && isStableNexusMcpServerConfig(server));
|
|
630
|
+
return Boolean(server && isStableNexusMcpServerConfig(server, 'env', definition.workspaceRoot));
|
|
619
631
|
}
|
|
620
632
|
catch {
|
|
621
633
|
return false;
|
|
@@ -309,8 +309,8 @@ function codexTomlHasAutonomousProfile(doc) {
|
|
|
309
309
|
return false;
|
|
310
310
|
if (codexTomlExposesInternalGraphPeer(doc))
|
|
311
311
|
return false;
|
|
312
|
-
const commandOk = !/(?:^|\n)\s*command\s*=\s*"npx"\s*(?:\n|$)/.test(mcpSection);
|
|
313
|
-
const argsOk = /(?:^|\n)\s*args\s*=\s*\[[^\]]*"mcp"[^\]]*\]\s*(?:\n|$)/s.test(mcpSection);
|
|
312
|
+
const commandOk = !/(?:^|\n)\s*command\s*=\s*"(?:npx|nexus-prime)"\s*(?:\n|$)/.test(mcpSection);
|
|
313
|
+
const argsOk = /(?:^|\n)\s*args\s*=\s*\[[^\]]*["'][^"']*cli\.js["'][^\]]*"mcp"[^\]]*\]\s*(?:\n|$)/s.test(mcpSection);
|
|
314
314
|
const envOk = Boolean(envSection && /(?:^|\n)\s*NEXUS_MCP_TOOL_PROFILE\s*=\s*"autonomous"\s*(?:\n|$)/.test(envSection));
|
|
315
315
|
const noStartupRewrite = Boolean(envSection && /(?:^|\n)\s*NEXUS_MCP_AUTO_CONFIG\s*=\s*"0"\s*(?:\n|$)/.test(envSection));
|
|
316
316
|
const fullDnaOnDisconnect = Boolean(envSection && /(?:^|\n)\s*NEXUS_MCP_FULL_DNA_ON_DISCONNECT\s*=\s*"1"\s*(?:\n|$)/.test(envSection));
|
|
@@ -548,6 +548,7 @@ export function getSetupDefinition(clientId, options) {
|
|
|
548
548
|
return {
|
|
549
549
|
id: clientId,
|
|
550
550
|
label: 'Codex',
|
|
551
|
+
workspaceRoot,
|
|
551
552
|
configPath: resolveCodexConfigPath(),
|
|
552
553
|
instructionFiles,
|
|
553
554
|
};
|
|
@@ -557,6 +558,7 @@ export function getSetupDefinition(clientId, options) {
|
|
|
557
558
|
return {
|
|
558
559
|
id: clientId,
|
|
559
560
|
label: 'Cursor',
|
|
561
|
+
workspaceRoot,
|
|
560
562
|
configPath: join(workspacePath, '.cursor', 'mcp.json'),
|
|
561
563
|
instructionFiles,
|
|
562
564
|
};
|
|
@@ -565,6 +567,7 @@ export function getSetupDefinition(clientId, options) {
|
|
|
565
567
|
return {
|
|
566
568
|
id: clientId,
|
|
567
569
|
label: 'Claude Code',
|
|
570
|
+
workspaceRoot,
|
|
568
571
|
configPath: join(workspaceRoot, '.mcp.json'),
|
|
569
572
|
instructionFiles,
|
|
570
573
|
};
|
|
@@ -578,6 +581,7 @@ export function getSetupDefinition(clientId, options) {
|
|
|
578
581
|
return {
|
|
579
582
|
id: clientId,
|
|
580
583
|
label: 'Claude Desktop',
|
|
584
|
+
workspaceRoot,
|
|
581
585
|
configPath: claudeDesktopPath,
|
|
582
586
|
instructionFiles,
|
|
583
587
|
};
|
|
@@ -586,6 +590,7 @@ export function getSetupDefinition(clientId, options) {
|
|
|
586
590
|
return {
|
|
587
591
|
id: clientId,
|
|
588
592
|
label: 'Opencode',
|
|
593
|
+
workspaceRoot,
|
|
589
594
|
configPath: join(homedir(), '.config', 'opencode', 'opencode.json'),
|
|
590
595
|
instructionFiles,
|
|
591
596
|
};
|
|
@@ -594,6 +599,7 @@ export function getSetupDefinition(clientId, options) {
|
|
|
594
599
|
return {
|
|
595
600
|
id: clientId,
|
|
596
601
|
label: 'Windsurf',
|
|
602
|
+
workspaceRoot,
|
|
597
603
|
configPath: join(homedir(), '.windsurf', 'mcp.json'),
|
|
598
604
|
instructionFiles,
|
|
599
605
|
};
|
|
@@ -602,6 +608,7 @@ export function getSetupDefinition(clientId, options) {
|
|
|
602
608
|
return {
|
|
603
609
|
id: clientId,
|
|
604
610
|
label: 'Aider',
|
|
611
|
+
workspaceRoot,
|
|
605
612
|
configPath: join(homedir(), '.aider', 'mcp.json'),
|
|
606
613
|
instructionFiles,
|
|
607
614
|
};
|
|
@@ -610,6 +617,7 @@ export function getSetupDefinition(clientId, options) {
|
|
|
610
617
|
return {
|
|
611
618
|
id: clientId,
|
|
612
619
|
label: 'Continue.dev',
|
|
620
|
+
workspaceRoot,
|
|
613
621
|
configPath: join(homedir(), '.continue', 'config.json'),
|
|
614
622
|
instructionFiles,
|
|
615
623
|
};
|
|
@@ -618,6 +626,7 @@ export function getSetupDefinition(clientId, options) {
|
|
|
618
626
|
return {
|
|
619
627
|
id: clientId,
|
|
620
628
|
label: 'Cline',
|
|
629
|
+
workspaceRoot,
|
|
621
630
|
configPath: join(homedir(), '.vscode', 'cline-mcp.json'),
|
|
622
631
|
instructionFiles,
|
|
623
632
|
};
|
|
@@ -626,6 +635,7 @@ export function getSetupDefinition(clientId, options) {
|
|
|
626
635
|
return {
|
|
627
636
|
id: clientId,
|
|
628
637
|
label: 'OpenClaw',
|
|
638
|
+
workspaceRoot,
|
|
629
639
|
configPath: join(homedir(), '.openclaw', 'openclaw.json'),
|
|
630
640
|
instructionFiles,
|
|
631
641
|
};
|
|
@@ -633,6 +643,7 @@ export function getSetupDefinition(clientId, options) {
|
|
|
633
643
|
return {
|
|
634
644
|
id: clientId,
|
|
635
645
|
label: 'Antigravity',
|
|
646
|
+
workspaceRoot,
|
|
636
647
|
configPath: join(homedir(), '.antigravity', 'mcp.json'),
|
|
637
648
|
instructionFiles,
|
|
638
649
|
};
|
|
@@ -697,11 +708,11 @@ export function hasExpectedConfig(definition) {
|
|
|
697
708
|
if (definition.id === 'opencode') {
|
|
698
709
|
const server = parsed?.mcp?.['nexus-prime'];
|
|
699
710
|
return Boolean(server
|
|
700
|
-
&& isStableNexusMcpServerConfig(server, 'environment'));
|
|
711
|
+
&& isStableNexusMcpServerConfig(server, 'environment', definition.workspaceRoot));
|
|
701
712
|
}
|
|
702
713
|
const server = parsed?.mcpServers?.['nexus-prime'];
|
|
703
714
|
return Boolean(server
|
|
704
|
-
&& isStableNexusMcpServerConfig(server));
|
|
715
|
+
&& isStableNexusMcpServerConfig(server, 'env', definition.workspaceRoot));
|
|
705
716
|
}
|
|
706
717
|
catch {
|
|
707
718
|
return false;
|
|
@@ -986,7 +997,7 @@ export function ensureBootstrap(options) {
|
|
|
986
997
|
const stat = statSync(configPath);
|
|
987
998
|
const mtimeMs = stat.mtimeMs;
|
|
988
999
|
const now = Date.now();
|
|
989
|
-
if (now - mtimeMs < 60000) {
|
|
1000
|
+
if (now - mtimeMs < 60000 && hasExpectedConfig(definition)) {
|
|
990
1001
|
continue;
|
|
991
1002
|
}
|
|
992
1003
|
}
|
|
@@ -9,4 +9,4 @@ export declare function buildNexusMcpCommand(): {
|
|
|
9
9
|
};
|
|
10
10
|
export declare function buildNexusMcpEnv(workspaceRoot?: string): Record<string, string>;
|
|
11
11
|
export declare function buildNexusMcpServerConfig(workspaceRoot?: string): NexusMcpServerConfig;
|
|
12
|
-
export declare function isStableNexusMcpServerConfig(server: any, envKey?: 'env' | 'environment'): boolean;
|
|
12
|
+
export declare function isStableNexusMcpServerConfig(server: any, envKey?: 'env' | 'environment', expectedWorkspaceRoot?: string): boolean;
|
|
@@ -1,4 +1,22 @@
|
|
|
1
|
+
import { existsSync } from 'fs';
|
|
2
|
+
import { dirname, isAbsolute, resolve } from 'path';
|
|
3
|
+
import { fileURLToPath } from 'url';
|
|
4
|
+
function resolveCliEntrypoint() {
|
|
5
|
+
const currentDir = dirname(fileURLToPath(import.meta.url));
|
|
6
|
+
const candidates = [
|
|
7
|
+
resolve(currentDir, '..', 'cli.js'),
|
|
8
|
+
resolve(currentDir, '..', '..', 'dist', 'cli.js'),
|
|
9
|
+
];
|
|
10
|
+
return candidates.find((candidate) => existsSync(candidate)) ?? null;
|
|
11
|
+
}
|
|
1
12
|
export function buildNexusMcpCommand() {
|
|
13
|
+
const cliPath = resolveCliEntrypoint();
|
|
14
|
+
if (cliPath) {
|
|
15
|
+
return {
|
|
16
|
+
command: process.execPath,
|
|
17
|
+
args: [cliPath, 'mcp'],
|
|
18
|
+
};
|
|
19
|
+
}
|
|
2
20
|
return {
|
|
3
21
|
command: 'nexus-prime',
|
|
4
22
|
args: ['mcp'],
|
|
@@ -26,16 +44,36 @@ export function buildNexusMcpServerConfig(workspaceRoot) {
|
|
|
26
44
|
env: buildNexusMcpEnv(workspaceRoot),
|
|
27
45
|
};
|
|
28
46
|
}
|
|
29
|
-
|
|
47
|
+
function sameResolvedPath(a, b) {
|
|
48
|
+
if (typeof a !== 'string' || !a.trim())
|
|
49
|
+
return false;
|
|
50
|
+
try {
|
|
51
|
+
return resolve(a) === resolve(b);
|
|
52
|
+
}
|
|
53
|
+
catch {
|
|
54
|
+
return false;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
export function isStableNexusMcpServerConfig(server, envKey = 'env', expectedWorkspaceRoot) {
|
|
30
58
|
const env = server?.[envKey];
|
|
59
|
+
const command = typeof server?.command === 'string' ? server.command : '';
|
|
31
60
|
const args = Array.isArray(server?.args) ? server.args.map((arg) => String(arg)) : [];
|
|
61
|
+
const cliArg = args.find((arg) => /(?:^|[/\\])cli\.js$/.test(arg));
|
|
62
|
+
const workspaceOk = expectedWorkspaceRoot
|
|
63
|
+
? sameResolvedPath(env?.NEXUS_WORKSPACE_ROOT, expectedWorkspaceRoot)
|
|
64
|
+
: true;
|
|
32
65
|
return Boolean(server
|
|
33
|
-
&&
|
|
34
|
-
&&
|
|
66
|
+
&& command
|
|
67
|
+
&& command !== 'npx'
|
|
68
|
+
&& command !== 'nexus-prime'
|
|
69
|
+
&& isAbsolute(command)
|
|
70
|
+
&& cliArg
|
|
71
|
+
&& isAbsolute(cliArg)
|
|
35
72
|
&& args.includes('mcp')
|
|
36
73
|
&& !args.includes('-y')
|
|
37
74
|
&& env?.NEXUS_MCP_TOOL_PROFILE === 'autonomous'
|
|
38
75
|
&& env?.NEXUS_MCP_AUTO_CONFIG === '0'
|
|
39
76
|
&& env?.NEXUS_DAEMON_AUTOSPAWN === '0'
|
|
40
|
-
&& env?.NEXUS_MCP_FULL_DNA_ON_DISCONNECT === '1'
|
|
77
|
+
&& env?.NEXUS_MCP_FULL_DNA_ON_DISCONNECT === '1'
|
|
78
|
+
&& workspaceOk);
|
|
41
79
|
}
|
|
@@ -55,10 +55,7 @@ export const LicenseEnforcementMiddleware = {
|
|
|
55
55
|
if (status.degradedReason === 'activation-required') {
|
|
56
56
|
const msg = trialActiveMessage(status);
|
|
57
57
|
if (mode !== 'audit') {
|
|
58
|
-
ctx.meta.
|
|
59
|
-
content: [{ type: 'text', text: msg }],
|
|
60
|
-
};
|
|
61
|
-
ctx.meta.shortCircuitedBy = 'license-enforcement';
|
|
58
|
+
ctx.meta.licenseUpgradeHint = msg;
|
|
62
59
|
}
|
|
63
60
|
return;
|
|
64
61
|
}
|
|
@@ -113,9 +113,9 @@ function buildActivationMotion(phase, daysRemaining) {
|
|
|
113
113
|
if (phase === 'activation') {
|
|
114
114
|
return {
|
|
115
115
|
phase: 'activation',
|
|
116
|
-
required:
|
|
117
|
-
title: '
|
|
118
|
-
message: `The 3-day no-license grace period is over
|
|
116
|
+
required: false,
|
|
117
|
+
title: 'Activate license',
|
|
118
|
+
message: `The 3-day no-license grace period is over, but the 30-day trial remains active for ${daysRemaining} day${daysRemaining === 1 ? '' : 's'}. Keep running Nexus Prime and ask the user to request or activate a license soon. Request one in the Nexus account page or email ${LICENSE_TEAM_EMAIL}; the team will share licenses within 24 hours.`,
|
|
119
119
|
action: 'Request license',
|
|
120
120
|
url: ACCOUNT_URL,
|
|
121
121
|
command: 'nexus-prime license activate <token>',
|
|
@@ -125,7 +125,7 @@ function buildActivationMotion(phase, daysRemaining) {
|
|
|
125
125
|
phase: 'grace',
|
|
126
126
|
required: false,
|
|
127
127
|
title: '3-day no-license grace',
|
|
128
|
-
message: `Nexus Prime is in the first 3-day no-license grace period.
|
|
128
|
+
message: `Nexus Prime is in the first 3-day no-license grace period. No license is mandatory during these first 3 days; ask the user to request a license soon so approvals can be shared within 24 hours by the Nexus Prime team.`,
|
|
129
129
|
action: 'Request license',
|
|
130
130
|
url: ACCOUNT_URL,
|
|
131
131
|
command: 'nexus-prime license activate <token>',
|
|
@@ -168,19 +168,6 @@ function buildTrialStatus(marker, now = Date.now()) {
|
|
|
168
168
|
const daysRemaining = daysUntil(marker.expiresAt, now);
|
|
169
169
|
const trialPhase = now >= graceEndsAt ? 'activation' : 'grace';
|
|
170
170
|
const trialDaysElapsed = Math.max(0, Math.floor((now - marker.issuedAt) / DAY_MS));
|
|
171
|
-
if (trialPhase === 'activation') {
|
|
172
|
-
return {
|
|
173
|
-
...buildFreeStatus('activation-required'),
|
|
174
|
-
trial: true,
|
|
175
|
-
trialPhase,
|
|
176
|
-
trialIssuedAt: marker.issuedAt,
|
|
177
|
-
trialGraceEndsAt: graceEndsAt,
|
|
178
|
-
trialDaysElapsed,
|
|
179
|
-
trialDaysRemaining: daysRemaining,
|
|
180
|
-
activationRequired: true,
|
|
181
|
-
activationMotion: buildActivationMotion(trialPhase, daysRemaining),
|
|
182
|
-
};
|
|
183
|
-
}
|
|
184
171
|
return {
|
|
185
172
|
valid: true,
|
|
186
173
|
tier: marker.tier,
|
|
@@ -28,7 +28,7 @@ export interface LicenseStatus {
|
|
|
28
28
|
orgId: string | null;
|
|
29
29
|
/** True when the active status is the auto-issued local trial. */
|
|
30
30
|
trial?: boolean;
|
|
31
|
-
/** Trial phase for PLG surfaces. First three days are grace
|
|
31
|
+
/** Trial phase for PLG surfaces. First three days are quiet grace; the rest of the trial uses soft activation prompts. */
|
|
32
32
|
trialPhase?: TrialPhase;
|
|
33
33
|
trialIssuedAt?: number;
|
|
34
34
|
trialGraceEndsAt?: number;
|
|
@@ -75,18 +75,27 @@ export function trialActiveMessage(statusOrExpiresAt) {
|
|
|
75
75
|
?? (expiresAt ? Math.max(0, Math.ceil((expiresAt - Date.now()) / (24 * 60 * 60 * 1000))) : 0);
|
|
76
76
|
if (status?.activationRequired) {
|
|
77
77
|
return [
|
|
78
|
-
`[Nexus Prime] License
|
|
79
|
-
` Agent motion: ask the user to request or activate a Nexus Prime license now
|
|
80
|
-
` Trial window
|
|
78
|
+
`[Nexus Prime] License activation requested.`,
|
|
79
|
+
` Agent motion: ask the user to request or activate a Nexus Prime license now, but do not stop free/trial-safe work unless the trial has expired.`,
|
|
80
|
+
` Trial window: ${daysLeft} day${daysLeft === 1 ? '' : 's'} remaining.`,
|
|
81
81
|
` Request: ${UPGRADE_URL}`,
|
|
82
82
|
` Email: ${LICENSE_TEAM_EMAIL}`,
|
|
83
83
|
` The Nexus Prime team will share licenses within 24 hours.`,
|
|
84
84
|
` Activate: nexus-prime license activate <token>`,
|
|
85
85
|
].join('\n');
|
|
86
86
|
}
|
|
87
|
+
if (status?.trialPhase === 'activation') {
|
|
88
|
+
return [
|
|
89
|
+
`[Nexus Prime] Trial active (${daysLeft} day${daysLeft === 1 ? '' : 's'} remaining).`,
|
|
90
|
+
` Agent motion: the first 3 no-license days are over; ask the user to request or activate a license soon, then keep working.`,
|
|
91
|
+
` Request: ${UPGRADE_URL}`,
|
|
92
|
+
` Email: ${LICENSE_TEAM_EMAIL}`,
|
|
93
|
+
` Licenses are reviewed and shared within 24 hours.`,
|
|
94
|
+
].join('\n');
|
|
95
|
+
}
|
|
87
96
|
return [
|
|
88
97
|
`[Nexus Prime] 3-day no-license grace active (${daysLeft} day${daysLeft === 1 ? '' : 's'} in the trial window).`,
|
|
89
|
-
`
|
|
98
|
+
` No license is mandatory during the first 3 days. Request one soon: ${UPGRADE_URL}`,
|
|
90
99
|
` Email fallback: ${LICENSE_TEAM_EMAIL}`,
|
|
91
100
|
` Licenses are reviewed and shared within 24 hours.`,
|
|
92
101
|
].join('\n');
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nexus-prime",
|
|
3
|
-
"version": "7.9.
|
|
3
|
+
"version": "7.9.17",
|
|
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",
|