nexus-prime 4.5.0 → 4.6.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.
Files changed (45) hide show
  1. package/README.md +22 -0
  2. package/dist/agents/adapters/mcp.d.ts +2 -0
  3. package/dist/agents/adapters/mcp.d.ts.map +1 -1
  4. package/dist/agents/adapters/mcp.js +158 -6
  5. package/dist/agents/adapters/mcp.js.map +1 -1
  6. package/dist/dashboard/index.html +52 -0
  7. package/dist/dashboard/server.d.ts.map +1 -1
  8. package/dist/dashboard/server.js +37 -0
  9. package/dist/dashboard/server.js.map +1 -1
  10. package/dist/engines/context-discovery.d.ts +68 -0
  11. package/dist/engines/context-discovery.d.ts.map +1 -0
  12. package/dist/engines/context-discovery.js +210 -0
  13. package/dist/engines/context-discovery.js.map +1 -0
  14. package/dist/engines/event-bus.d.ts +14 -2
  15. package/dist/engines/event-bus.d.ts.map +1 -1
  16. package/dist/engines/event-bus.js.map +1 -1
  17. package/dist/engines/feature-registry.js +1 -1
  18. package/dist/engines/feature-registry.js.map +1 -1
  19. package/dist/engines/gstack-bridge.d.ts +62 -0
  20. package/dist/engines/gstack-bridge.d.ts.map +1 -0
  21. package/dist/engines/gstack-bridge.js +210 -0
  22. package/dist/engines/gstack-bridge.js.map +1 -0
  23. package/dist/engines/instruction-gateway.js +2 -2
  24. package/dist/engines/instruction-gateway.js.map +1 -1
  25. package/dist/engines/ngram-index.d.ts +28 -0
  26. package/dist/engines/ngram-index.d.ts.map +1 -1
  27. package/dist/engines/ngram-index.js +68 -3
  28. package/dist/engines/ngram-index.js.map +1 -1
  29. package/dist/engines/orchestrator.d.ts +9 -0
  30. package/dist/engines/orchestrator.d.ts.map +1 -1
  31. package/dist/engines/orchestrator.js +58 -1
  32. package/dist/engines/orchestrator.js.map +1 -1
  33. package/dist/engines/self-summarizer.d.ts +84 -0
  34. package/dist/engines/self-summarizer.d.ts.map +1 -0
  35. package/dist/engines/self-summarizer.js +201 -0
  36. package/dist/engines/self-summarizer.js.map +1 -0
  37. package/dist/engines/telemetry-remote.d.ts +68 -0
  38. package/dist/engines/telemetry-remote.d.ts.map +1 -0
  39. package/dist/engines/telemetry-remote.js +274 -0
  40. package/dist/engines/telemetry-remote.js.map +1 -0
  41. package/dist/engines/token-supremacy.js +2 -2
  42. package/dist/engines/token-supremacy.js.map +1 -1
  43. package/dist/postinstall-bootstrap.js +11 -0
  44. package/dist/postinstall-bootstrap.js.map +1 -1
  45. package/package.json +7 -1
package/README.md CHANGED
@@ -654,6 +654,28 @@ Inventory Snapshot: 109 skills · 64 workflows · 9 hooks · 5 automations · 7
654
654
  ## 📜 Release History
655
655
 
656
656
  <details open>
657
+ <summary><b>v4.6.1</b> · 2026-03-29 · Release corridor stabilization — audited publish path and npm release recovery</summary>
658
+
659
+ - **Publish path repaired**: Patched the vulnerable `path-to-regexp` dependency edges through targeted overrides so `CI & Publish` can clear `npm run audit:prod` and proceed to npm publication.
660
+ - **Lockfile normalized for release**: Refreshed the production lockfile so GitHub Actions, local installs, and release packaging all resolve the same audited dependency graph.
661
+ - **No feature drift from v4.6.0**: This is a release-stability patch on top of Context Ascension, not a new product surface or protocol change.
662
+
663
+ Full notes: [releases/v4.6.1.md](./releases/v4.6.1.md) · Full history: [CHANGELOG.md](./CHANGELOG.md)
664
+ </details>
665
+
666
+ <details>
667
+ <summary><b>v4.6.0</b> · 2026-03-29 · Context Ascension — always-on compression, native search, and operator telemetry</summary>
668
+
669
+ - **Always-on token optimization**: Bootstrap now auto-applies token optimization whenever candidate files are available, and bootstrap/orchestrate responses surface token and USD savings directly instead of hiding the win in diagnostics.
670
+ - **Project-scoped session summaries**: Session close and `nexus_session_dna` now persist reusable project summaries, and the next bootstrap surfaces whether prior context was recovered before any broad file reading begins.
671
+ - **Dynamic context discovery**: MCP `ListTools` now keeps core lifecycle tools expanded while summarizing non-core tools by default, with `nexus_describe_tool` available for on-demand full contracts.
672
+ - **Native search and skill bridge**: Added sparse n-gram backed `nexus_search` plus Nexus-native bridging for installed gstack skills so external workflows appear inside the normal tool surface.
673
+ - **Opt-in telemetry and dashboard signals**: Remote telemetry remains disabled until consent, clears queued events when turned off, and the dashboard now shows savings, search activity, and telemetry status in the main operator banner.
674
+
675
+ Full notes: [releases/v4.6.0.md](./releases/v4.6.0.md) · Full history: [CHANGELOG.md](./CHANGELOG.md)
676
+ </details>
677
+
678
+ <details>
657
679
  <summary><b>v4.5.0</b> · 2026-03-27 · Neural Ascension — Auto-optimization, memory injection, and sci-fi command center</summary>
658
680
 
659
681
  - **Auto token optimization**: Bootstrap auto-applies token planning when 5+ candidate files detected. Quality floor (0.7) ensures task-referenced and recently modified files never get skipped. Zero manual `nexus_optimize_tokens` calls needed.
@@ -19,6 +19,7 @@ export declare class MCPAdapter implements Adapter {
19
19
  private lifecyclePolicy;
20
20
  private memoryInjectionCache;
21
21
  private lastMemoryInjectionAt;
22
+ private currentTask;
22
23
  private sciFiMatrixLog;
23
24
  private classifyToolCategory;
24
25
  private sciFiToolHeader;
@@ -38,6 +39,7 @@ export declare class MCPAdapter implements Adapter {
38
39
  private injectMemoryContext;
39
40
  private describeClientInstructionStatus;
40
41
  private finalizeToolDefinitions;
42
+ private getDecoratedToolDefinitions;
41
43
  private decorateToolDescription;
42
44
  debugListTools(profile?: McpToolProfile): McpToolDefinition[];
43
45
  private buildToolDefinitions;
@@ -1 +1 @@
1
- {"version":3,"file":"mcp.d.ts","sourceRoot":"","sources":["../../../src/agents/adapters/mcp.ts"],"names":[],"mappings":"AAaA,OAAO,EAAE,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAC3D,OAAO,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AA0E5C,KAAK,cAAc,GAAG,YAAY,GAAG,MAAM,CAAC;AAE5C,KAAK,iBAAiB,GAAG;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACxC,CAAC;AAqTF,qBAAa,UAAW,YAAW,OAAO;IACtC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAG,KAAK,CAAU;IACtB,SAAS,UAAS;IAClB,MAAM,EAAE,MAAM,EAAE,CAAM;IAEtB,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,QAAQ,CAAC,CAAa;IAC9B,OAAO,CAAC,SAAS,CAA4C;IAC7D,OAAO,CAAC,UAAU,CAAoB;IACtC,OAAO,CAAC,OAAO,CAAC,CAAkB;IAClC,OAAO,CAAC,eAAe,CAAyB;IAChD,OAAO,CAAC,oBAAoB,CAAgG;IAC5H,OAAO,CAAC,qBAAqB,CAAK;IAElC,OAAO,CAAC,cAAc;IA6BtB,OAAO,CAAC,oBAAoB;IAS5B,OAAO,CAAC,eAAe;IAqEvB,OAAO,CAAC,GAAG;;IAmBX,OAAO,CAAC,gBAAgB;IA4BxB,WAAW,CAAC,KAAK,EAAE,UAAU;IAI7B,OAAO,CAAC,UAAU;IAYlB,OAAO,CAAC,eAAe;IAOvB,OAAO,CAAC,cAAc;IAMtB,OAAO,CAAC,uBAAuB;IAY/B,OAAO,CAAC,4BAA4B;IAWpC,OAAO,CAAC,qBAAqB;IAiB7B,OAAO,CAAC,yBAAyB;IA2CjC,OAAO,CAAC,mBAAmB;IAO3B,OAAO,CAAC,YAAY;YAON,mBAAmB;IA0DjC,OAAO,CAAC,+BAA+B;IAMvC,OAAO,CAAC,uBAAuB;IAqB/B,OAAO,CAAC,uBAAuB;IAkC/B,cAAc,CAAC,OAAO,GAAE,cAAsC,GAAG,iBAAiB,EAAE;IAIpF,OAAO,CAAC,oBAAoB;IAkzB5B,OAAO,CAAC,iBAAiB;YA6FX,cAAc;IAk7D5B,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,EAAE;IAItC,OAAO,CAAC,IAAI;IAmBN,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAOxB,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAoB3B,IAAI,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC;IAYlD,OAAO,CAAC,OAAO,EAAE,cAAc,GAAG,IAAI;CAOzC"}
1
+ {"version":3,"file":"mcp.d.ts","sourceRoot":"","sources":["../../../src/agents/adapters/mcp.ts"],"names":[],"mappings":"AAaA,OAAO,EAAE,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAC3D,OAAO,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAqF5C,KAAK,cAAc,GAAG,YAAY,GAAG,MAAM,CAAC;AAE5C,KAAK,iBAAiB,GAAG;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACxC,CAAC;AAuTF,qBAAa,UAAW,YAAW,OAAO;IACtC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAG,KAAK,CAAU;IACtB,SAAS,UAAS;IAClB,MAAM,EAAE,MAAM,EAAE,CAAM;IAEtB,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,QAAQ,CAAC,CAAa;IAC9B,OAAO,CAAC,SAAS,CAA4C;IAC7D,OAAO,CAAC,UAAU,CAAoB;IACtC,OAAO,CAAC,OAAO,CAAC,CAAkB;IAClC,OAAO,CAAC,eAAe,CAAyB;IAChD,OAAO,CAAC,oBAAoB,CAAgG;IAC5H,OAAO,CAAC,qBAAqB,CAAK;IAClC,OAAO,CAAC,WAAW,CAAM;IAEzB,OAAO,CAAC,cAAc;IA6BtB,OAAO,CAAC,oBAAoB;IAS5B,OAAO,CAAC,eAAe;IAqEvB,OAAO,CAAC,GAAG;;IAmBX,OAAO,CAAC,gBAAgB;IA4BxB,WAAW,CAAC,KAAK,EAAE,UAAU;IAI7B,OAAO,CAAC,UAAU;IAYlB,OAAO,CAAC,eAAe;IAOvB,OAAO,CAAC,cAAc;IAMtB,OAAO,CAAC,uBAAuB;IAY/B,OAAO,CAAC,4BAA4B;IAWpC,OAAO,CAAC,qBAAqB;IAiB7B,OAAO,CAAC,yBAAyB;IA2CjC,OAAO,CAAC,mBAAmB;IAO3B,OAAO,CAAC,YAAY;YAON,mBAAmB;IA0DjC,OAAO,CAAC,+BAA+B;IAMvC,OAAO,CAAC,uBAAuB;IA0B/B,OAAO,CAAC,2BAA2B;IAqBnC,OAAO,CAAC,uBAAuB;IAkC/B,cAAc,CAAC,OAAO,GAAE,cAAsC,GAAG,iBAAiB,EAAE;IAIpF,OAAO,CAAC,oBAAoB;IA80B5B,OAAO,CAAC,iBAAiB;YA6FX,cAAc;IAwhE5B,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,EAAE;IAItC,OAAO,CAAC,IAAI;IAmBN,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAOxB,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAoB3B,IAAI,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC;IAYlD,OAAO,CAAC,OAAO,EAAE,cAAc,GAAG,IAAI;CAOzC"}
@@ -24,6 +24,10 @@ import { LifecyclePolicy } from '../../engines/lifecycle-policy.js';
24
24
  import { entanglementEngine, ContinuousAttentionStream, createKVBridge, nxl, OrchestratorEngine } from '../../engines/index.js';
25
25
  import { FederationEngine } from '../../engines/federation.js';
26
26
  import { TokenAnalyticsEngine } from '../../engines/token-analytics.js';
27
+ import { getSharedNgramIndex } from '../../engines/ngram-index.js';
28
+ import { getSharedTelemetry } from '../../engines/telemetry-remote.js';
29
+ import { getGstackBridge } from '../../engines/gstack-bridge.js';
30
+ import { getSharedContextDiscovery } from '../../engines/context-discovery.js';
27
31
  import { synapseToolDefinitions, handleSynapseToolCall } from '../../synapse/index.js';
28
32
  import { architectsToolDefinitions, handleArchitectsToolCall } from '../../architects/index.js';
29
33
  const tokenEngine = new TokenSupremacyEngine();
@@ -59,6 +63,13 @@ function getHybridRetriever() {
59
63
  _hybridRetriever = new HybridRetriever(getGraphEngine());
60
64
  return _hybridRetriever;
61
65
  }
66
+ // Lazy-initialized N-gram index for fast search
67
+ let _ngramIndex = null;
68
+ function getNgramIndexInstance() {
69
+ if (!_ngramIndex)
70
+ _ngramIndex = getSharedNgramIndex();
71
+ return _ngramIndex;
72
+ }
62
73
  // Derive project root from this file's location (dist/agents/adapters/mcp.js → project root)
63
74
  const __filename = fileURLToPath(import.meta.url);
64
75
  const PROJECT_ROOT = path.resolve(path.dirname(__filename), '..', '..', '..');
@@ -69,6 +80,8 @@ const AUTONOMOUS_TOOL_ORDER = [
69
80
  'nexus_recall_memory',
70
81
  'nexus_memory_stats',
71
82
  'nexus_store_memory',
83
+ 'nexus_search',
84
+ 'nexus_describe_tool',
72
85
  'nexus_optimize_tokens',
73
86
  'nexus_mindkit_check',
74
87
  'nexus_ghost_pass',
@@ -248,7 +261,7 @@ class SessionTelemetry {
248
261
  return false;
249
262
  if (this.tokenAutoApplied)
250
263
  return false;
251
- return this.fileReadIntentCount >= 3 && !this.optimizeTokensCalled;
264
+ return this.fileReadIntentCount >= 1 && !this.optimizeTokensCalled;
252
265
  }
253
266
  markTokenAutoApplied() {
254
267
  this.tokenAutoApplied = true;
@@ -365,6 +378,7 @@ export class MCPAdapter {
365
378
  lifecyclePolicy = new LifecyclePolicy();
366
379
  memoryInjectionCache = new Map();
367
380
  lastMemoryInjectionAt = 0;
381
+ currentTask = '';
368
382
  sciFiMatrixLog(title, metrics, intent) {
369
383
  const width = 76;
370
384
  console.error(`\n\x1b[36m╔═══ [ \x1b[37m\x1b[1mNEXUS PRIME · ORCHESTRATION MATRIX\x1b[0m\x1b[36m ] ${'═'.repeat(Math.max(0, width - 48))}╗\x1b[0m`);
@@ -675,6 +689,7 @@ export class MCPAdapter {
675
689
  : 'Full MCP profile active. Low-level and authoring tools are exposed.';
676
690
  }
677
691
  finalizeToolDefinitions(tools, profile = this.getToolProfile()) {
692
+ const taskContext = this.currentTask || this.getRuntime().getUsageSnapshot()?.orchestration?.lastPrompt || '';
678
693
  const scoped = profile === 'full'
679
694
  ? tools.slice()
680
695
  : tools.filter((tool) => AUTONOMOUS_TOOL_SET.has(tool.name));
@@ -682,6 +697,28 @@ export class MCPAdapter {
682
697
  ? [...AUTONOMOUS_TOOL_ORDER, ...scoped.map((tool) => tool.name).filter((name) => !AUTONOMOUS_TOOL_SET.has(name))]
683
698
  : [...AUTONOMOUS_TOOL_ORDER];
684
699
  const orderIndex = new Map(order.map((name, index) => [name, index]));
700
+ const decorated = scoped
701
+ .map((tool) => ({
702
+ ...tool,
703
+ description: this.decorateToolDescription(tool.name, tool.description, profile),
704
+ }))
705
+ .sort((left, right) => {
706
+ const leftIndex = orderIndex.get(left.name) ?? Number.MAX_SAFE_INTEGER;
707
+ const rightIndex = orderIndex.get(right.name) ?? Number.MAX_SAFE_INTEGER;
708
+ return leftIndex - rightIndex || left.name.localeCompare(right.name);
709
+ });
710
+ const discovery = getSharedContextDiscovery();
711
+ discovery.registerTools(decorated);
712
+ return discovery.applyToTools(taskContext, decorated);
713
+ }
714
+ getDecoratedToolDefinitions(profile = this.getToolProfile()) {
715
+ const scoped = profile === 'full'
716
+ ? this.buildToolDefinitions().slice()
717
+ : this.buildToolDefinitions().filter((tool) => AUTONOMOUS_TOOL_SET.has(tool.name));
718
+ const order = profile === 'full'
719
+ ? [...AUTONOMOUS_TOOL_ORDER, ...scoped.map((tool) => tool.name).filter((name) => !AUTONOMOUS_TOOL_SET.has(name))]
720
+ : [...AUTONOMOUS_TOOL_ORDER];
721
+ const orderIndex = new Map(order.map((name, index) => [name, index]));
685
722
  return scoped
686
723
  .map((tool) => ({
687
724
  ...tool,
@@ -704,7 +741,7 @@ export class MCPAdapter {
704
741
  return 'Optional: Inspect the execution ledger before calling nexus_orchestrate. Skip unless you need pre-run visibility into what Nexus will choose.';
705
742
  }
706
743
  if (name === 'nexus_optimize_tokens') {
707
- return 'MANDATORY before reading 3+ files. Returns a token-saving reading plan. Follow it exactly and do not bulk-read the repo.';
744
+ return 'Always-on token optimization. Automatically generates token-saving reading plans for any file reads. Follow the plan exactly and do not bulk-read the repo.';
708
745
  }
709
746
  if (name === 'nexus_mindkit_check') {
710
747
  return 'MANDATORY before any file modification or destructive operation. Returns PASS/FAIL. Do NOT proceed if it returns FAIL.';
@@ -868,7 +905,7 @@ export class MCPAdapter {
868
905
  },
869
906
  {
870
907
  name: 'nexus_optimize_tokens',
871
- description: 'Generate a token-efficient file reading plan BEFORE reading files. MANDATORY when reading 3+ files. Returns which files to read fully, outline-only, or skip. Typically saves 50-90% tokens per session.',
908
+ description: 'Generate a token-efficient file reading plan. Always-on: auto-applies during bootstrap for any files. Returns which files to read fully, outline-only, or skip. Typically saves 50-90% tokens per session.',
872
909
  inputSchema: {
873
910
  type: 'object',
874
911
  properties: {
@@ -880,6 +917,32 @@ export class MCPAdapter {
880
917
  required: [],
881
918
  },
882
919
  },
920
+ // ── Search ──────────────────────────────────────────────────────
921
+ {
922
+ name: 'nexus_search',
923
+ description: 'Fast codebase search using sparse n-gram index. Returns matching documents ranked by relevance. Much faster and cheaper than reading full files — reports token savings vs brute-force file reads.',
924
+ inputSchema: {
925
+ type: 'object',
926
+ properties: {
927
+ query: { type: 'string', description: 'Search query (text or pattern)' },
928
+ limit: { type: 'number', description: 'Max results to return (default 20)' },
929
+ sparse: { type: 'boolean', description: 'Use sparse n-gram search for higher selectivity (default false)' },
930
+ },
931
+ required: ['query'],
932
+ },
933
+ },
934
+ // ── Context Discovery ────────────────────────────────────────────
935
+ {
936
+ name: 'nexus_describe_tool',
937
+ description: 'Get full description and schema for any Nexus tool on demand. Use when you need details about a specific capability without loading all tool descriptions upfront. Saves tokens via lazy loading.',
938
+ inputSchema: {
939
+ type: 'object',
940
+ properties: {
941
+ tool_name: { type: 'string', description: 'Name of the Nexus tool to describe' },
942
+ },
943
+ required: ['tool_name'],
944
+ },
945
+ },
883
946
  // ── Mindkit ──────────────────────────────────────────────────────
884
947
  {
885
948
  name: 'nexus_mindkit_check',
@@ -1542,6 +1605,8 @@ export class MCPAdapter {
1542
1605
  },
1543
1606
  ...synapseToolDefinitions,
1544
1607
  ...architectsToolDefinitions,
1608
+ // ── Embedded capabilities (auto-detected from installed skills) ──
1609
+ ...getGstackBridge().getToolDefinitions(),
1545
1610
  ];
1546
1611
  }
1547
1612
  setupToolHandlers() {
@@ -1666,9 +1731,24 @@ export class MCPAdapter {
1666
1731
  if (architectsResponse) {
1667
1732
  return architectsResponse;
1668
1733
  }
1734
+ // Handle embedded gstack skill calls
1735
+ const gstackBridge = getGstackBridge();
1736
+ if (gstackBridge.detect() && gstackBridge.listSkills().some(s => s.toolName === toolName)) {
1737
+ const result = await gstackBridge.execute(toolName, args);
1738
+ getSharedTelemetry().trackFeatureUsage(toolName, { success: result.success });
1739
+ return {
1740
+ content: [{
1741
+ type: 'text',
1742
+ text: result.success
1743
+ ? result.output
1744
+ : `Execution failed (exit ${result.exitCode}): ${result.output.slice(0, 500)}`,
1745
+ }],
1746
+ };
1747
+ }
1669
1748
  switch (request.params.name) {
1670
1749
  case 'nexus_session_bootstrap': {
1671
1750
  const bootstrapGoal = String(request.params.arguments?.goal ?? request.params.arguments?.prompt ?? '');
1751
+ this.currentTask = bootstrapGoal;
1672
1752
  const files = Array.isArray(request.params.arguments?.files)
1673
1753
  ? request.params.arguments.files.map(String)
1674
1754
  : undefined;
@@ -1687,6 +1767,16 @@ export class MCPAdapter {
1687
1767
  tokenAutoApplied: autoTokenApplied,
1688
1768
  toolProfile: this.getToolProfile(),
1689
1769
  });
1770
+ // Remote telemetry: track session start (privacy-safe, opt-in only)
1771
+ try {
1772
+ const remoteTelemetry = getSharedTelemetry();
1773
+ remoteTelemetry.trackSessionStart();
1774
+ remoteTelemetry.trackFeatureUsage('session_bootstrap');
1775
+ if (autoTokenApplied && bootstrap.tokenOptimization?.planMetrics?.savings) {
1776
+ remoteTelemetry.trackTokenSavings(Number(bootstrap.tokenOptimization.planMetrics.savings));
1777
+ }
1778
+ }
1779
+ catch { /* best-effort telemetry */ }
1690
1780
  // Auto-generate a project-scoped memory on bootstrap so dashboard always has something to show
1691
1781
  try {
1692
1782
  this.nexusRef.storeMemory(`Session bootstrap: ${bootstrapGoal || 'interactive session'}. Memory: prefrontal=${bootstrap.memoryStats?.prefrontal ?? 0}, hippocampus=${bootstrap.memoryStats?.hippocampus ?? 0}, cortex=${bootstrap.memoryStats?.cortex ?? 0}.`, 0.5, ['#session-start', '#auto', '#project']);
@@ -1709,6 +1799,7 @@ export class MCPAdapter {
1709
1799
  taskGraphPreview: bootstrap.taskGraphPreview,
1710
1800
  workerPlanPreview: bootstrap.workerPlanPreview,
1711
1801
  knowledgeFabric: bootstrap.knowledgeFabric,
1802
+ sessionSummaryBootstrap: bootstrap.sessionSummaryBootstrap,
1712
1803
  mcpToolProfile: this.getToolProfile(),
1713
1804
  };
1714
1805
  return {
@@ -1722,13 +1813,16 @@ export class MCPAdapter {
1722
1813
  `Memory stats: prefrontal ${bootstrap.memoryStats?.prefrontal ?? 0} · hippocampus ${bootstrap.memoryStats?.hippocampus ?? 0} · cortex ${bootstrap.memoryStats?.cortex ?? 0}`,
1723
1814
  `Recommended next step: ${bootstrap.recommendedNextStep || 'nexus_orchestrate'}`,
1724
1815
  `Execution mode: ${bootstrap.recommendedExecutionMode || 'autonomous'}`,
1725
- `Token optimization: ${bootstrap.tokenOptimization?.autoApplied ? 'auto-applied during bootstrap' : (bootstrap.tokenOptimization?.required ? 'required before broad reading' : 'not required yet')}`,
1816
+ `Token optimization: ${bootstrap.tokenOptimization?.autoApplied ? `auto-applied saved ${Number(bootstrap.tokenOptimization?.planMetrics?.savings ?? 0).toLocaleString()} tokens (${bootstrap.tokenOptimization?.planMetrics?.pct ?? 0}% reduction)` : (bootstrap.tokenOptimization?.required ? 'required before broad reading' : 'not required yet')}`,
1726
1817
  `Catalog health: ${bootstrap.catalogHealth?.overall || 'unknown'} · selected ${bootstrap.artifactSelectionAudit?.selected?.length || 0}`,
1727
1818
  `Shortlist: ${bootstrap.shortlist?.skills?.slice(0, 3).join(', ') || 'none'} (skills), ${bootstrap.shortlist?.specialists?.slice(0, 3).join(', ') || 'none'} (specialists)`,
1728
1819
  `Knowledge fabric: ${bootstrap.sourceMixRecommendation?.dominantSource || bootstrap.knowledgeFabric?.dominantSource || 'awaiting source mix'}`,
1729
1820
  `RAG: ${bootstrap.ragCandidateStatus?.attachedCollections || 0} attached · ${bootstrap.ragCandidateStatus?.retrievedChunks || 0} retrieved`,
1730
1821
  `Task graph: ${bootstrap.taskGraphPreview?.phases?.length || 0} phases · ${bootstrap.taskGraphPreview?.independentBranches || 0} branches`,
1731
1822
  `Worker plan: ${bootstrap.workerPlanPreview?.totalWorkers || 0} lanes planned`,
1823
+ bootstrap.sessionSummaryBootstrap
1824
+ ? `Session summary: reused ${Number(bootstrap.sessionSummaryBootstrap.savedTokens || 0).toLocaleString()} tokens from the previous visit`
1825
+ : 'Session summary: none available yet',
1732
1826
  bootstrap.autoGhostPass?.applied
1733
1827
  ? `Auto ghost-pass: ${bootstrap.autoGhostPass.riskAreas.length} risk area(s) · ${bootstrap.autoGhostPass.workerApproaches} approach(es)`
1734
1828
  : `Auto ghost-pass: skipped`,
@@ -1745,6 +1839,7 @@ export class MCPAdapter {
1745
1839
  }
1746
1840
  case 'nexus_orchestrate': {
1747
1841
  const prompt = String(request.params.arguments?.prompt ?? request.params.arguments?.goal ?? '');
1842
+ this.currentTask = prompt;
1748
1843
  const files = Array.isArray(request.params.arguments?.files)
1749
1844
  ? request.params.arguments.files.map(String)
1750
1845
  : undefined;
@@ -1787,11 +1882,13 @@ export class MCPAdapter {
1787
1882
  const verifiedWorkers = execution.workerResults.filter((worker) => worker.verified).length;
1788
1883
  const tokenPlan = execution?.knowledgeFabric?.repo?.readingPlan;
1789
1884
  const canAutoApplyTokenPlan = Boolean(tokenPlan
1790
- && Number(tokenPlan.savings || 0) > 5000
1885
+ && Number(tokenPlan.savings || 0) > 0
1791
1886
  && !this.getRuntime().getUsageSnapshot()?.tokenOptimizationApplied);
1792
1887
  let autoTokenApplyNote = '';
1793
1888
  if (canAutoApplyTokenPlan) {
1794
1889
  const savings = Number(tokenPlan.savings || 0);
1890
+ const totalBeforeOpt = savings + Number(tokenPlan.totalEstimatedTokens || 0);
1891
+ const pctSaved = totalBeforeOpt > 0 ? Math.round(savings / totalBeforeOpt * 100) : 0;
1795
1892
  this.telemetry.recordTokens(savings);
1796
1893
  this.getRuntime().recordClientToolCall('nexus_orchestrate', {
1797
1894
  orchestrateCalled: true,
@@ -1799,7 +1896,8 @@ export class MCPAdapter {
1799
1896
  tokenOptimizationApplied: true,
1800
1897
  toolProfile: this.getToolProfile(),
1801
1898
  });
1802
- autoTokenApplyNote = `Auto-applied token optimization (${savings.toLocaleString()} estimated token savings).`;
1899
+ autoTokenApplyNote = `Token savings: ${savings.toLocaleString()} tokens saved (${pctSaved}% reduction).`;
1900
+ nexusEventBus.emit('tokens.optimized', { savings, pct: pctSaved, source: 'orchestrate' });
1803
1901
  }
1804
1902
  // Auto-store run summary memory so dashboard and future sessions can see what happened
1805
1903
  try {
@@ -2173,6 +2271,55 @@ export class MCPAdapter {
2173
2271
  }],
2174
2272
  };
2175
2273
  }
2274
+ case 'nexus_describe_tool': {
2275
+ const requestedTool = String(request.params.arguments?.tool_name ?? '');
2276
+ if (!requestedTool) {
2277
+ return { content: [{ type: 'text', text: 'tool_name is required.' }] };
2278
+ }
2279
+ const allToolDefs = this.getDecoratedToolDefinitions(this.getToolProfile());
2280
+ const found = allToolDefs.find(t => t.name === requestedTool);
2281
+ if (!found) {
2282
+ const available = allToolDefs.map(t => t.name).join(', ');
2283
+ return { content: [{ type: 'text', text: `Tool "${requestedTool}" not found. Available: ${available}` }] };
2284
+ }
2285
+ return {
2286
+ content: [{
2287
+ type: 'text',
2288
+ text: `## ${found.name}\n\n${found.description}\n\n**Schema:**\n\`\`\`json\n${JSON.stringify(found.inputSchema, null, 2)}\n\`\`\``,
2289
+ }],
2290
+ };
2291
+ }
2292
+ case 'nexus_search': {
2293
+ const query = String(request.params.arguments?.query ?? '');
2294
+ const limit = Number(request.params.arguments?.limit ?? 20);
2295
+ const useSparse = Boolean(request.params.arguments?.sparse);
2296
+ if (!query.trim()) {
2297
+ return { content: [{ type: 'text', text: 'Search query is required.' }] };
2298
+ }
2299
+ const ngramIndex = getNgramIndexInstance();
2300
+ const { results, tokensSaved, totalCandidateTokens } = ngramIndex.searchWithStats(query, limit);
2301
+ if (results.length === 0) {
2302
+ return { content: [{ type: 'text', text: `No results found for "${query}".` }] };
2303
+ }
2304
+ const sparseResults = useSparse ? ngramIndex.searchSparse(query, limit) : null;
2305
+ const displayResults = sparseResults ?? results;
2306
+ const lines = displayResults.map((r, i) => `${i + 1}. ${r.docId} (score: ${r.score})`);
2307
+ const stats = ngramIndex.getSearchStats();
2308
+ const savingsLine = `\n📊 Token savings: ~${tokensSaved.toLocaleString()} tokens saved vs reading all ${results.length} matched files.\n` +
2309
+ ` Lifetime search savings: ${stats.totalTokensSaved.toLocaleString()} tokens across ${stats.totalQueries} queries.`;
2310
+ nexusEventBus.emit('tokens.searchSaved', {
2311
+ query: query.slice(0, 100),
2312
+ resultCount: displayResults.length,
2313
+ tokensSaved,
2314
+ source: 'nexus_search',
2315
+ });
2316
+ return {
2317
+ content: [{
2318
+ type: 'text',
2319
+ text: `Search results for "${query}" (${displayResults.length} matches):\n\n${lines.join('\n')}${savingsLine}`,
2320
+ }],
2321
+ };
2322
+ }
2176
2323
  case 'nexus_optimize_tokens': {
2177
2324
  const task = String(request.params.arguments?.goal ?? request.params.arguments?.task ?? '');
2178
2325
  const rawFiles = Array.isArray(request.params.arguments?.files)
@@ -2539,6 +2686,11 @@ export class MCPAdapter {
2539
2686
  });
2540
2687
  const dna = this.sessionDNA.flush();
2541
2688
  const formatted = SessionDNAManager.format(dna);
2689
+ // Trigger self-summarization at session end
2690
+ try {
2691
+ this.getOrchestrator().persistSessionSummary(telemetry.tokensOptimized || this.getRuntime().getUsageSnapshot().tokens?.grossInputTokens || 0);
2692
+ }
2693
+ catch { /* non-fatal */ }
2542
2694
  return {
2543
2695
  content: [{
2544
2696
  type: 'text',