@theihtisham/agent-shadow-brain 7.0.0 → 7.1.3

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 (130) hide show
  1. package/CHANGELOG.md +31 -0
  2. package/README.md +47 -385
  3. package/dist/activity-cli.d.ts +3 -0
  4. package/dist/activity-cli.d.ts.map +1 -0
  5. package/dist/activity-cli.js +78 -0
  6. package/dist/activity-cli.js.map +1 -0
  7. package/dist/adapters/index.d.ts +2 -1
  8. package/dist/adapters/index.d.ts.map +1 -1
  9. package/dist/adapters/index.js +3 -2
  10. package/dist/adapters/index.js.map +1 -1
  11. package/dist/brain/activity-journal.d.ts +82 -0
  12. package/dist/brain/activity-journal.d.ts.map +1 -0
  13. package/dist/brain/activity-journal.js +314 -0
  14. package/dist/brain/activity-journal.js.map +1 -0
  15. package/dist/brain/activity-reporting.d.ts +14 -0
  16. package/dist/brain/activity-reporting.d.ts.map +1 -0
  17. package/dist/brain/activity-reporting.js +17 -0
  18. package/dist/brain/activity-reporting.js.map +1 -0
  19. package/dist/brain/auto-update.js +1 -1
  20. package/dist/brain/brain-portability.js +1 -1
  21. package/dist/brain/client-integrations.d.ts +61 -0
  22. package/dist/brain/client-integrations.d.ts.map +1 -0
  23. package/dist/brain/client-integrations.js +98 -0
  24. package/dist/brain/client-integrations.js.map +1 -0
  25. package/dist/brain/context-assembly.d.ts +76 -0
  26. package/dist/brain/context-assembly.d.ts.map +1 -0
  27. package/dist/brain/context-assembly.js +305 -0
  28. package/dist/brain/context-assembly.js.map +1 -0
  29. package/dist/brain/feature-settings.d.ts +58 -0
  30. package/dist/brain/feature-settings.d.ts.map +1 -0
  31. package/dist/brain/feature-settings.js +241 -0
  32. package/dist/brain/feature-settings.js.map +1 -0
  33. package/dist/brain/global-brain.d.ts +7 -0
  34. package/dist/brain/global-brain.d.ts.map +1 -1
  35. package/dist/brain/global-brain.js +19 -4
  36. package/dist/brain/global-brain.js.map +1 -1
  37. package/dist/brain/mcp-server.d.ts +23 -1
  38. package/dist/brain/mcp-server.d.ts.map +1 -1
  39. package/dist/brain/mcp-server.js +224 -24
  40. package/dist/brain/mcp-server.js.map +1 -1
  41. package/dist/brain/mcp-stdio.d.ts +12 -0
  42. package/dist/brain/mcp-stdio.d.ts.map +1 -0
  43. package/dist/brain/mcp-stdio.js +134 -0
  44. package/dist/brain/mcp-stdio.js.map +1 -0
  45. package/dist/brain/memory-annotations.d.ts +97 -0
  46. package/dist/brain/memory-annotations.d.ts.map +1 -0
  47. package/dist/brain/memory-annotations.js +388 -0
  48. package/dist/brain/memory-annotations.js.map +1 -0
  49. package/dist/brain/memory-graph.d.ts.map +1 -1
  50. package/dist/brain/memory-graph.js +12 -23
  51. package/dist/brain/memory-graph.js.map +1 -1
  52. package/dist/brain/memory-sources.d.ts +8 -0
  53. package/dist/brain/memory-sources.d.ts.map +1 -0
  54. package/dist/brain/memory-sources.js +27 -0
  55. package/dist/brain/memory-sources.js.map +1 -0
  56. package/dist/brain/orchestrator.js +1 -1
  57. package/dist/brain/subconscious.d.ts +21 -24
  58. package/dist/brain/subconscious.d.ts.map +1 -1
  59. package/dist/brain/subconscious.js +82 -218
  60. package/dist/brain/subconscious.js.map +1 -1
  61. package/dist/brain/task-workflow.d.ts +22 -0
  62. package/dist/brain/task-workflow.d.ts.map +1 -0
  63. package/dist/brain/task-workflow.js +182 -0
  64. package/dist/brain/task-workflow.js.map +1 -0
  65. package/dist/brain/workflow-skills.d.ts +86 -0
  66. package/dist/brain/workflow-skills.d.ts.map +1 -0
  67. package/dist/brain/workflow-skills.js +514 -0
  68. package/dist/brain/workflow-skills.js.map +1 -0
  69. package/dist/cli.js +21 -2
  70. package/dist/cli.js.map +1 -1
  71. package/dist/context-cli.d.ts +3 -0
  72. package/dist/context-cli.d.ts.map +1 -0
  73. package/dist/context-cli.js +56 -0
  74. package/dist/context-cli.js.map +1 -0
  75. package/dist/curation-cli.d.ts +4 -0
  76. package/dist/curation-cli.d.ts.map +1 -0
  77. package/dist/curation-cli.js +118 -0
  78. package/dist/curation-cli.js.map +1 -0
  79. package/dist/dashboard/live-workspace-html.d.ts +2 -0
  80. package/dist/dashboard/live-workspace-html.d.ts.map +1 -0
  81. package/dist/dashboard/live-workspace-html.js +893 -0
  82. package/dist/dashboard/live-workspace-html.js.map +1 -0
  83. package/dist/dashboard/server.d.ts +1 -0
  84. package/dist/dashboard/server.d.ts.map +1 -1
  85. package/dist/dashboard/server.js +53 -18
  86. package/dist/dashboard/server.js.map +1 -1
  87. package/dist/dashboard/v6-dashboard-html.d.ts +1 -1
  88. package/dist/dashboard/v6-dashboard-html.d.ts.map +1 -1
  89. package/dist/dashboard/v6-dashboard-html.js +7 -29
  90. package/dist/dashboard/v6-dashboard-html.js.map +1 -1
  91. package/dist/dashboard/workspace-api.d.ts +16 -0
  92. package/dist/dashboard/workspace-api.d.ts.map +1 -0
  93. package/dist/dashboard/workspace-api.js +309 -0
  94. package/dist/dashboard/workspace-api.js.map +1 -0
  95. package/dist/dashboard/workspace-html.d.ts +2 -0
  96. package/dist/dashboard/workspace-html.d.ts.map +1 -0
  97. package/dist/dashboard/workspace-html.js +2132 -0
  98. package/dist/dashboard/workspace-html.js.map +1 -0
  99. package/dist/index.d.ts +14 -0
  100. package/dist/index.d.ts.map +1 -1
  101. package/dist/index.js +10 -0
  102. package/dist/index.js.map +1 -1
  103. package/dist/integration-cli.d.ts +3 -0
  104. package/dist/integration-cli.d.ts.map +1 -0
  105. package/dist/integration-cli.js +14 -0
  106. package/dist/integration-cli.js.map +1 -0
  107. package/dist/types.d.ts +12 -3
  108. package/dist/types.d.ts.map +1 -1
  109. package/dist/workflow-cli.d.ts +3 -0
  110. package/dist/workflow-cli.d.ts.map +1 -0
  111. package/dist/workflow-cli.js +100 -0
  112. package/dist/workflow-cli.js.map +1 -0
  113. package/docs/WORKFLOW_INTEGRATION.md +105 -0
  114. package/docs/WORKSPACE.md +111 -0
  115. package/docs/assets/context-flow-v7.2.png +0 -0
  116. package/docs/assets/live-v7.1.3.png +0 -0
  117. package/docs/assets/memory-detail-v7.1.3.png +0 -0
  118. package/docs/assets/overview-v7.1.3.png +0 -0
  119. package/docs/assets/workspace-graph-v7.2.png +0 -0
  120. package/docs/assets/workspace-overview-v7.2.png +0 -0
  121. package/docs/launch/RELEASE_NOTES_v7.1.0.md +32 -0
  122. package/docs/launch/RELEASE_NOTES_v7.1.3.md +40 -0
  123. package/docs/launch/RELEASE_NOTES_v7.2.0.md +24 -0
  124. package/package.json +112 -207
  125. package/skills/shadow-debug/SKILL.md +16 -0
  126. package/skills/shadow-implement/SKILL.md +16 -0
  127. package/skills/shadow-release/SKILL.md +16 -0
  128. package/skills/shadow-research/SKILL.md +12 -0
  129. package/skills/shadow-review/SKILL.md +14 -0
  130. package/skills/shadow-workflow/SKILL.md +31 -0
@@ -2,17 +2,28 @@
2
2
  // Exposes analysis tools via Model Context Protocol
3
3
  // v6.0.0 — Hive Mind Edition (Cursor + Claude Code + Codex + Copilot + sub-agent frameworks)
4
4
  import * as http from 'http';
5
+ import { randomUUID } from 'node:crypto';
6
+ import * as path from 'node:path';
7
+ import { performance } from 'node:perf_hooks';
8
+ const MEMORY_TOOLS = new Set(['global_recall', 'global_recall_scored', 'global_stats', 'global_storage_health',
9
+ 'global_timeline', 'workflow_analyze', 'workflow_skills', 'context_pack', 'feature_flags', 'activity_report']);
5
10
  export class MCPServer {
6
- constructor(orchestrator, options) {
11
+ constructor(orchestrator, options, dependencies = {}) {
12
+ this.dependencies = dependencies;
7
13
  this.server = null;
8
14
  this.sseClients = new Map();
9
15
  this.lastHealthScore = null;
16
+ this.telemetrySession = 'mcp-' + randomUUID();
17
+ this.telemetryAgent = 'mcp-client';
18
+ this.telemetryInitialized = false;
19
+ this.telemetryWarning = false;
10
20
  this.orchestrator = orchestrator;
11
21
  this.options = {
12
22
  port: options?.port ?? 7342,
13
23
  host: options?.host ?? 'localhost',
14
24
  authToken: options?.authToken ?? process.env.SHADOW_BRAIN_MCP_TOKEN ?? '',
15
25
  corsOrigin: options?.corsOrigin ?? `http://${options?.host ?? 'localhost'}:${options?.port ?? 7342}`,
26
+ toolProfile: options?.toolProfile ?? 'full',
16
27
  };
17
28
  this.toolHandlers = {
18
29
  analyze: this.handleAnalyze.bind(this),
@@ -40,6 +51,11 @@ export class MCPServer {
40
51
  global_recall_scored: this.handleGlobalRecallScored.bind(this),
41
52
  global_stats: this.handleGlobalStats.bind(this),
42
53
  global_storage_health: this.handleGlobalStorageHealth.bind(this),
54
+ workflow_analyze: this.handleWorkflowAnalyze.bind(this),
55
+ workflow_skills: this.handleWorkflowSkills.bind(this),
56
+ context_pack: this.handleContextPack.bind(this),
57
+ feature_flags: this.handleFeatureFlags.bind(this),
58
+ activity_report: this.handleActivityReport.bind(this),
43
59
  attach_status: this.handleAttachStatus.bind(this),
44
60
  global_timeline: this.handleGlobalTimeline.bind(this),
45
61
  firewall_check: this.handleFirewallCheck.bind(this),
@@ -312,10 +328,10 @@ export class MCPServer {
312
328
  const tokens = getTokenEconomy();
313
329
  const formal = getFormalBridge();
314
330
  const airgap = getAirGapMode();
315
- const brain = getGlobalBrain();
331
+ const brain = this.dependencies.brain ?? getGlobalBrain();
316
332
  await Promise.all([sabb.init(), causal.init(), collisions.init(), dream.init(), rep.init(), tokens.init(), formal.init(), airgap.init(), brain.init()]);
317
333
  return {
318
- version: '7.0.0',
334
+ version: '7.1.3',
319
335
  modules: {
320
336
  sabb: sabb.getStats(),
321
337
  causal: causal.stats(),
@@ -348,7 +364,7 @@ export class MCPServer {
348
364
  }
349
365
  async handleGlobalRecall(params) {
350
366
  const { getGlobalBrain } = await import('./global-brain.js');
351
- const brain = getGlobalBrain();
367
+ const brain = this.dependencies.brain ?? getGlobalBrain();
352
368
  await brain.init();
353
369
  return brain.recall({
354
370
  projectId: params.projectId,
@@ -361,7 +377,7 @@ export class MCPServer {
361
377
  }
362
378
  async handleGlobalRecallScored(params) {
363
379
  const { getGlobalBrain } = await import('./global-brain.js');
364
- const brain = getGlobalBrain();
380
+ const brain = this.dependencies.brain ?? getGlobalBrain();
365
381
  await brain.init();
366
382
  return brain.recallScored({
367
383
  projectId: params.projectId,
@@ -376,7 +392,7 @@ export class MCPServer {
376
392
  async handleGlobalStats(_params) {
377
393
  const { getGlobalBrain } = await import('./global-brain.js');
378
394
  const { getAllCacheStats } = await import('./l0-cache.js');
379
- const brain = getGlobalBrain();
395
+ const brain = this.dependencies.brain ?? getGlobalBrain();
380
396
  await brain.init();
381
397
  return {
382
398
  brain: brain.getStats(),
@@ -385,7 +401,50 @@ export class MCPServer {
385
401
  }
386
402
  async handleGlobalStorageHealth(_params) {
387
403
  const { getGlobalBrain } = await import('./global-brain.js');
388
- return getGlobalBrain().getStorageHealth();
404
+ return (this.dependencies.brain ?? getGlobalBrain()).getStorageHealth();
405
+ }
406
+ async handleWorkflowAnalyze(params) {
407
+ const { analyzeTask } = await import('./task-workflow.js');
408
+ return analyzeTask(params.request, {
409
+ mode: params.mode,
410
+ taskType: params.taskType,
411
+ complexity: params.complexity,
412
+ });
413
+ }
414
+ async handleWorkflowSkills(params) {
415
+ const { getBundledSkill, listBundledSkills } = await import('./workflow-skills.js');
416
+ if (params.name !== undefined && typeof params.name !== 'string')
417
+ throw new TypeError('name must be a bundled skill name.');
418
+ return params.name === undefined ? listBundledSkills() : getBundledSkill(params.name);
419
+ }
420
+ async handleContextPack(params) {
421
+ const { assembleContext } = await import('./context-assembly.js');
422
+ const { getFeatureSettings } = await import('./feature-settings.js');
423
+ const { getGlobalBrain } = await import('./global-brain.js');
424
+ if (typeof params.projectId !== 'string' || !params.projectId.trim())
425
+ throw new TypeError('A project ID is required.');
426
+ if (params.query !== undefined && typeof params.query !== 'string')
427
+ throw new TypeError('Query must be text.');
428
+ if (params.tokenBudget !== undefined && (!Number.isSafeInteger(params.tokenBudget) || Number(params.tokenBudget) < 0 || Number(params.tokenBudget) > 12000))
429
+ throw new TypeError('Token budget must be an integer from 0 to 12000.');
430
+ if (params.includeCrossProject !== undefined && typeof params.includeCrossProject !== 'boolean')
431
+ throw new TypeError('Cross-project choice must be boolean.');
432
+ const features = (this.dependencies.settings ?? getFeatureSettings()).get().features;
433
+ const brain = this.dependencies.brain ?? getGlobalBrain();
434
+ if (features.contextAssembly) {
435
+ await brain.init();
436
+ await brain.sync();
437
+ if (brain.getStorageHealth().lastError)
438
+ throw new Error('Memory store is not readable. Check global_storage_health.');
439
+ }
440
+ const { memoryAnnotationsFor } = await import('./memory-annotations.js');
441
+ return assembleContext(brain, { projectId: params.projectId, query: params.query,
442
+ tokenBudget: params.tokenBudget, includeCrossProject: params.includeCrossProject, features,
443
+ annotations: features.contextAssembly ? memoryAnnotationsFor(brain).get() : undefined });
444
+ }
445
+ async handleFeatureFlags(_params) {
446
+ const { getFeatureSettings, FEATURE_DEFINITIONS } = await import('./feature-settings.js');
447
+ return { ...(this.dependencies.settings ?? getFeatureSettings()).get(), definitions: FEATURE_DEFINITIONS };
389
448
  }
390
449
  async handleAttachStatus(params) {
391
450
  const { getHookInstaller } = await import('./session-hooks.js');
@@ -396,7 +455,7 @@ export class MCPServer {
396
455
  async handleGlobalTimeline(params) {
397
456
  const { getGlobalBrain, GlobalBrain } = await import('./global-brain.js');
398
457
  const projectDir = params.projectDir;
399
- const brain = getGlobalBrain();
458
+ const brain = this.dependencies.brain ?? getGlobalBrain();
400
459
  await brain.init();
401
460
  return brain.timeline({
402
461
  projectId: projectDir ? GlobalBrain.projectIdFor(projectDir) : params.projectId,
@@ -500,7 +559,7 @@ export class MCPServer {
500
559
  // Lightweight health endpoint for tool connectivity checks
501
560
  this.sendJSON(res, 200, {
502
561
  status: 'ok',
503
- version: '7.0.0',
562
+ version: '7.1.3',
504
563
  uptime: process.uptime(),
505
564
  tools: Object.keys(this.toolHandlers).length,
506
565
  });
@@ -554,14 +613,26 @@ export class MCPServer {
554
613
  }
555
614
  }
556
615
  async handleRequest(request) {
557
- if (request.jsonrpc !== '2.0') {
558
- return this.makeError(request.id, -32600, 'Invalid Request: jsonrpc must be "2.0"');
616
+ if (!request || typeof request !== 'object' || Array.isArray(request) || request.jsonrpc !== '2.0' ||
617
+ typeof request.method !== 'string' || (request.id !== undefined && typeof request.id !== 'string' && typeof request.id !== 'number') ||
618
+ (request.params !== undefined && (!request.params || typeof request.params !== 'object' || Array.isArray(request.params)))) {
619
+ return this.makeError(undefined, -32600, 'Invalid JSON-RPC request.');
559
620
  }
560
621
  const { method, params } = request;
561
622
  try {
562
623
  switch (method) {
563
- case 'initialize':
564
- return this.makeResult(request.id, this.handleInitialize());
624
+ case 'initialize': {
625
+ if (this.options.toolProfile === 'memory') {
626
+ const name = String(params?.clientInfo?.name ?? '').toLowerCase();
627
+ this.telemetryAgent = name.includes('codex') ? 'codex' : name.includes('claude') ? 'claude-code' :
628
+ name.includes('opencode') ? 'opencode' : name.includes('deepseek') ? 'deepseek-harness' : 'mcp-client';
629
+ this.telemetryInitialized = true;
630
+ await this.recordMeasured({ kind: 'session-start' });
631
+ }
632
+ return this.makeResult(request.id, this.handleInitialize(params));
633
+ }
634
+ case 'ping':
635
+ return this.makeResult(request.id, {});
565
636
  case 'notifications/initialized':
566
637
  // Cursor sends this after initialize — acknowledge silently
567
638
  return this.makeResult(request.id, {});
@@ -574,15 +645,44 @@ export class MCPServer {
574
645
  case 'tools/call': {
575
646
  const toolName = params?.name;
576
647
  const toolArgs = params?.arguments ?? {};
577
- if (!toolName) {
648
+ if (typeof toolName !== 'string' || !toolName || !toolArgs || typeof toolArgs !== 'object' || Array.isArray(toolArgs)) {
578
649
  return this.makeError(request.id, -32602, 'Missing tool name in params.name');
579
650
  }
580
651
  const handler = this.toolHandlers[toolName];
581
- if (!handler) {
652
+ if (!Object.hasOwn(this.toolHandlers, toolName) || !handler || (this.options.toolProfile === 'memory' && !MEMORY_TOOLS.has(toolName))) {
582
653
  return this.makeError(request.id, -32601, `Unknown tool: ${toolName}`);
583
654
  }
584
- const result = await handler(toolArgs);
585
- return this.makeResult(request.id, { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] });
655
+ try {
656
+ if (this.options.toolProfile === 'memory')
657
+ this.validateMemoryArguments(toolName, toolArgs);
658
+ const measured = this.options.toolProfile === 'memory' && toolName !== 'activity_report';
659
+ const correlationId = randomUUID();
660
+ const projectId = typeof toolArgs.projectId === 'string' && /^[A-Za-z0-9][A-Za-z0-9_.:-]{0,127}$/.test(toolArgs.projectId)
661
+ ? toolArgs.projectId : undefined;
662
+ if (measured)
663
+ await this.recordMeasured({ kind: 'tool-start', tool: toolName, correlationId, ...(projectId ? { projectId } : {}) });
664
+ const started = performance.now();
665
+ let result;
666
+ try {
667
+ result = await handler(toolArgs);
668
+ if (measured)
669
+ await this.recordMeasured({ kind: 'tool-end', tool: toolName, correlationId, outcome: 'success',
670
+ durationMs: Math.max(0, Math.round((performance.now() - started) * 1000) / 1000), ...(projectId ? { projectId } : {}) });
671
+ }
672
+ catch (error) {
673
+ if (measured)
674
+ await this.recordMeasured({ kind: 'tool-end', tool: toolName, correlationId, outcome: 'error',
675
+ durationMs: Math.max(0, Math.round((performance.now() - started) * 1000) / 1000), ...(projectId ? { projectId } : {}) });
676
+ throw error;
677
+ }
678
+ return this.makeResult(request.id, { content: [{ type: 'text', text: JSON.stringify(result, null, 2) }] });
679
+ }
680
+ catch (error) {
681
+ const message = error instanceof Error ? error.message : 'Tool execution failed.';
682
+ if (error instanceof TypeError || error instanceof RangeError)
683
+ return this.makeError(request.id, -32602, message);
684
+ return this.makeResult(request.id, { content: [{ type: 'text', text: message }], isError: true });
685
+ }
586
686
  }
587
687
  default:
588
688
  return this.makeError(request.id, -32601, `Method not found: ${method}`);
@@ -593,18 +693,77 @@ export class MCPServer {
593
693
  }
594
694
  }
595
695
  // ── Tool Handlers ──────────────────────────────────────────────────────
596
- handleInitialize() {
696
+ async telemetryProject() {
697
+ if (this.dependencies.projectId)
698
+ return this.dependencies.projectId;
699
+ const { GlobalBrain } = await import('./global-brain.js');
700
+ return GlobalBrain.projectIdFor(path.resolve(this.dependencies.projectDir ?? process.cwd()));
701
+ }
702
+ async recordMeasured(event) {
703
+ if (this.options.toolProfile !== 'memory')
704
+ return;
705
+ try {
706
+ const { getFeatureSettings } = await import('./feature-settings.js');
707
+ if (!(this.dependencies.settings ?? getFeatureSettings()).get().features.activityRecording)
708
+ return;
709
+ const { getGlobalBrain } = await import('./global-brain.js');
710
+ const { ActivityJournal, ACTIVITY_JOURNAL_FILENAME } = await import('./activity-journal.js');
711
+ const brain = this.dependencies.brain ?? getGlobalBrain();
712
+ const journal = new ActivityJournal({ filePath: path.join(path.dirname(brain.dbPath), ACTIVITY_JOURNAL_FILENAME), lockTimeoutMs: 250 });
713
+ await journal.append({ projectId: await this.telemetryProject(), sessionId: this.telemetrySession,
714
+ agent: this.telemetryAgent, ...event, source: 'measured', transport: 'mcp' });
715
+ }
716
+ catch {
717
+ if (!this.telemetryWarning) {
718
+ this.telemetryWarning = true;
719
+ console.error('Shadow Brain activity recording is unavailable. Tool execution continues.');
720
+ }
721
+ }
722
+ }
723
+ async finishMemorySession() {
724
+ if (this.telemetryInitialized) {
725
+ this.telemetryInitialized = false;
726
+ await this.recordMeasured({ kind: 'session-end' });
727
+ }
728
+ }
729
+ async handleActivityReport(params) {
730
+ const { reportAgentActivity } = await import('./activity-reporting.js');
731
+ const { getFeatureSettings } = await import('./feature-settings.js');
732
+ const { getGlobalBrain } = await import('./global-brain.js');
733
+ return reportAgentActivity(this.dependencies.brain ?? getGlobalBrain(), this.dependencies.settings ?? getFeatureSettings(), {
734
+ projectId: await this.telemetryProject(), sessionId: this.telemetrySession, agent: this.telemetryAgent, ...params,
735
+ });
736
+ }
737
+ validateMemoryArguments(name, args) {
738
+ if (!['global_recall', 'global_recall_scored', 'global_timeline'].includes(name))
739
+ return;
740
+ if (args.limit !== undefined && (!Number.isSafeInteger(args.limit) || Number(args.limit) < 1 || Number(args.limit) > 200)) {
741
+ throw new TypeError('limit must be an integer from 1 to 200.');
742
+ }
743
+ for (const key of ['projectId', 'projectDir', 'agentTool', 'category']) {
744
+ if (args[key] !== undefined && (typeof args[key] !== 'string' || args[key].length > 1000))
745
+ throw new TypeError(key + ' must be bounded text.');
746
+ }
747
+ for (const key of ['minImportance', 'minConfidence']) {
748
+ if (args[key] !== undefined && (typeof args[key] !== 'number' || !Number.isFinite(args[key]) || Number(args[key]) < 0 || Number(args[key]) > 1))
749
+ throw new TypeError(key + ' must be from 0 to 1.');
750
+ }
751
+ if (args.keywords !== undefined && (!Array.isArray(args.keywords) || args.keywords.length > 32 || args.keywords.some(word => typeof word !== 'string' || word.length > 256))) {
752
+ throw new TypeError('keywords must contain at most 32 text terms of at most 256 characters.');
753
+ }
754
+ }
755
+ handleInitialize(params) {
756
+ const versions = ['2025-06-18', '2024-11-05'];
597
757
  return {
598
- protocolVersion: '2024-11-05',
758
+ protocolVersion: versions.includes(String(params?.protocolVersion)) ? params.protocolVersion : versions[0],
599
759
  capabilities: {
600
760
  tools: { listChanged: false },
601
761
  resources: { subscribe: false, listChanged: false },
602
762
  prompts: { listChanged: false },
603
- logging: {},
604
763
  },
605
764
  serverInfo: {
606
765
  name: 'agent-shadow-brain',
607
- version: '7.0.0',
766
+ version: '7.1.3',
608
767
  description: 'Cross-agent memory and safety layer for AI coding agents',
609
768
  },
610
769
  };
@@ -893,7 +1052,7 @@ export class MCPServer {
893
1052
  async handleStatus(params) {
894
1053
  const status = this.orchestrator.getStatus?.() || {};
895
1054
  return {
896
- version: '7.0.0',
1055
+ version: '7.1.3',
897
1056
  ...status,
898
1057
  };
899
1058
  }
@@ -919,7 +1078,7 @@ export class MCPServer {
919
1078
  const instance = this.orchestrator[mod.key];
920
1079
  modules.push({
921
1080
  name: mod.name,
922
- version: '7.0.0',
1081
+ version: '7.1.3',
923
1082
  status: instance ? 'active' : 'idle',
924
1083
  });
925
1084
  }
@@ -946,7 +1105,14 @@ export class MCPServer {
946
1105
  }
947
1106
  // ── Tool Definitions ───────────────────────────────────────────────────
948
1107
  getToolDefinitions() {
949
- return [
1108
+ const definitions = [
1109
+ { name: 'activity_report', description: 'Explicitly report an agent phase or tool span to the live portal. Writes only bounded activity labels/timing; reports remain labelled host-reported. Do not send request text, arguments, file paths, or secrets.',
1110
+ inputSchema: { type: 'object', additionalProperties: false, required: ['kind'], properties: {
1111
+ kind: { type: 'string', enum: ['session-start', 'phase', 'tool-start', 'tool-end', 'session-end'] },
1112
+ projectId: { type: 'string' }, sessionId: { type: 'string' }, agent: { type: 'string' },
1113
+ phase: { type: 'string', enum: ['understand', 'plan', 'work', 'verify'] }, tool: { type: 'string' }, correlationId: { type: 'string' },
1114
+ outcome: { type: 'string', enum: ['success', 'error', 'cancelled'] }, durationMs: { type: 'number', minimum: 0 },
1115
+ } }, annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: false } },
950
1116
  {
951
1117
  name: 'analyze',
952
1118
  description: 'Run full analysis on project files and return insights',
@@ -1166,6 +1332,37 @@ export class MCPServer {
1166
1332
  description: 'Inspect this process memory-store status, pending operations, last successful save, and last storage error. Does not initialize or flush the store. (v7.0.0)',
1167
1333
  inputSchema: { type: 'object', properties: {}, additionalProperties: false },
1168
1334
  },
1335
+ {
1336
+ name: 'workflow_analyze',
1337
+ description: 'Suggest a focused workflow and relevant bundled skills for a user request. Pure local heuristic: no execution, file changes, provider calls, or permission grants. (v7.1.0)',
1338
+ inputSchema: {
1339
+ type: 'object', required: ['request'], additionalProperties: false,
1340
+ properties: {
1341
+ request: { type: 'string', description: 'The requested task, including scope and planning-only constraints.' },
1342
+ mode: { type: 'string', enum: ['auto', 'plan-only', 'execute'] },
1343
+ taskType: { type: 'string', enum: ['auto', 'implement', 'debug', 'review', 'research', 'release'] },
1344
+ complexity: { type: 'string', enum: ['auto', 'simple', 'complex'] },
1345
+ },
1346
+ },
1347
+ },
1348
+ {
1349
+ name: 'workflow_skills',
1350
+ description: 'List bundled workflow skills, or read one by name. Does not install skills or change client settings. (v7.1.0)',
1351
+ inputSchema: { type: 'object', properties: { name: { type: 'string' } }, additionalProperties: false },
1352
+ },
1353
+ {
1354
+ name: 'context_pack',
1355
+ description: 'Build a bounded reference context pack for a specified project and task, with provenance, selection reasons, and exclusions. Cross-project content requires both the persisted feature and an explicit request. No provider calls or source-file reads. Token counts are estimates. (v7.1.3)',
1356
+ inputSchema: { type: 'object', required: ['projectId'], additionalProperties: false, properties: {
1357
+ projectId: { type: 'string' }, query: { type: 'string' },
1358
+ tokenBudget: { type: 'integer', minimum: 0, maximum: 12000 }, includeCrossProject: { type: 'boolean' },
1359
+ } },
1360
+ },
1361
+ {
1362
+ name: 'feature_flags',
1363
+ description: 'Read the five persisted context, briefing, and activity controls. Does not modify settings or expose provider configuration. (v7.1.3)',
1364
+ inputSchema: { type: 'object', properties: {}, additionalProperties: false },
1365
+ },
1169
1366
  {
1170
1367
  name: 'attach_status',
1171
1368
  description: 'Detect which AI agents are installed on this machine (v5.2.0)',
@@ -1256,6 +1453,9 @@ export class MCPServer {
1256
1453
  },
1257
1454
  },
1258
1455
  ];
1456
+ return this.options.toolProfile === 'memory'
1457
+ ? definitions.filter(tool => MEMORY_TOOLS.has(tool.name)).map(tool => ({ ...tool, annotations: { readOnlyHint: tool.name !== 'activity_report', destructiveHint: false, openWorldHint: false } }))
1458
+ : definitions;
1259
1459
  }
1260
1460
  // ── HTTP Handling ──────────────────────────────────────────────────────
1261
1461
  async handleHTTPMCPRequest(req, res) {