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.
@@ -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**: Stop paid-tier work and ask the user to request or activate a Nexus Prime license now.`
48
- : `- **Agent motion**: 3-day no-license grace is active; ask the user to request a license before day 4.`,
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 = resolve(opts.workspaceRoot ?? process.cwd());
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 = resolve(opts.workspaceRoot ?? process.cwd());
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
- configPath: join(getWorkspaceRoot(), '.mcp.json'),
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, getWorkspaceRoot());
563
+ writeOpencodeConfig(definition.configPath, definition.workspaceRoot);
552
564
  }
553
565
  else {
554
- writeStandardMcpConfig(definition.configPath, getWorkspaceRoot());
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(getWorkspaceRoot()) }]
600
+ servers: [{ id: 'nexus-prime', ...buildStandardMcpServerConfig(definition.workspaceRoot) }]
589
601
  }
590
602
  }
591
603
  : {
592
604
  mcpServers: {
593
- 'nexus-prime': buildStandardMcpServerConfig(getWorkspaceRoot())
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;
@@ -11,6 +11,7 @@ export interface SetupInstructionFile {
11
11
  export interface SetupDefinition {
12
12
  id: SetupClientId;
13
13
  label: string;
14
+ workspaceRoot: string;
14
15
  configPath?: string;
15
16
  instructionFiles: SetupInstructionFile[];
16
17
  }
@@ -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
- export function isStableNexusMcpServerConfig(server, envKey = 'env') {
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
- && typeof server.command === 'string'
34
- && server.command !== 'npx'
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.shortCircuitResult = {
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: true,
117
- title: 'License required',
118
- message: `The 3-day no-license grace period is over. Nexus Prime requires an activated license now; ${daysRemaining} day${daysRemaining === 1 ? '' : 's'} remain in the trial window after activation. Request one in the Nexus account page or email ${LICENSE_TEAM_EMAIL}; the team will share licenses within 24 hours.`,
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. Request a license before day 4; approvals are shared within 24 hours by the Nexus Prime team.`,
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, then activation prompts become direct. */
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 required — the 3-day no-license grace period is over.`,
79
- ` Agent motion: ask the user to request or activate a Nexus Prime license now before continuing.`,
80
- ` Trial window after activation: ${daysLeft} day${daysLeft === 1 ? '' : 's'} remaining.`,
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
- ` Request a license before day 4: ${UPGRADE_URL}`,
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.16",
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",