@papyruslabsai/seshat-mcp 0.8.0 → 0.9.0

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/index.js CHANGED
@@ -34,7 +34,7 @@ import { CallToolRequestSchema, ListToolsRequestSchema, } from '@modelcontextpro
34
34
  import { MultiLoader } from './loader.js';
35
35
  import { bootstrap } from './bootstrap.js';
36
36
  import { initTools, queryEntities, getEntity, getDependencies, getDataFlow, findByConstraint, getBlastRadius, listModules, getTopology, } from './tools/index.js';
37
- import { findDeadCode, findLayerViolations, getCouplingMetrics, getAuthMatrix, findErrorGaps, getTestCoverage, getOptimalContext, estimateTaskCost, reportActualBurn, find_runtime_violations, find_ownership_violations, query_traits, simulate_mutation, query_data_targets, find_exposure_leaks, find_semantic_clones, } from './tools/functors.js';
37
+ import { findDeadCode, findLayerViolations, getCouplingMetrics, getAuthMatrix, findErrorGaps, getTestCoverage, getOptimalContext, estimateTaskCost, reportActualBurn, find_runtime_violations, find_ownership_violations, query_traits, simulate_mutation, query_data_targets, find_exposure_leaks, find_semantic_clones, create_symbol, } from './tools/functors.js';
38
38
  import { diffBundle, conflictMatrix, } from './tools/diff.js';
39
39
  // ─── Project Discovery ───────────────────────────────────────────
40
40
  /**
@@ -388,10 +388,10 @@ const TOOLS = [
388
388
  },
389
389
  },
390
390
  },
391
- // ─── Semantic (9D) JSTF-T Tools ─────────────────────────────────
391
+ // ─── Analysis & Impact Tools ───────────────────────────────────
392
392
  {
393
393
  name: 'find_runtime_violations',
394
- description: 'Analyze the call graph across the ρ (Runtime) dimension. Finds architectural leaks where framework-agnostic code improperly imports framework-specific code (e.g. pure logic calling React hooks) or where incompatible frameworks mix directly.',
394
+ description: 'Analyze the call graph for runtime environment leaks. Finds architectural boundary issues where framework-agnostic code improperly imports framework-specific code (e.g. pure logic calling React hooks) or where incompatible frameworks mix directly.',
395
395
  inputSchema: {
396
396
  type: 'object',
397
397
  properties: {
@@ -401,7 +401,7 @@ const TOOLS = [
401
401
  },
402
402
  {
403
403
  name: 'find_ownership_violations',
404
- description: 'Analyze the codebase across the λ (Ownership/Lifetimes) dimension. Flags entities with complex memory management constraints, unsafe blocks, escaping boundaries, or illegal mutability patterns on borrowed references.',
404
+ description: 'Analyze the codebase for memory and lifecycle constraints. Flags entities with complex ownership rules, unsafe blocks, escaping boundaries, or illegal mutability patterns on borrowed references.',
405
405
  inputSchema: {
406
406
  type: 'object',
407
407
  properties: {
@@ -411,7 +411,7 @@ const TOOLS = [
411
411
  },
412
412
  {
413
413
  name: 'query_traits',
414
- description: 'Search the codebase across the τ (Traits/Capabilities) dimension. Allows you to find entities by their abstract capabilities (e.g., "fallible", "asyncContext", "generator") regardless of their structural syntax.',
414
+ description: 'Search the codebase for specific functional capabilities. Allows you to find entities by their abstract traits (e.g., "fallible", "asyncContext", "generator") regardless of their structural syntax.',
415
415
  inputSchema: {
416
416
  type: 'object',
417
417
  properties: {
@@ -426,20 +426,20 @@ const TOOLS = [
426
426
  },
427
427
  {
428
428
  name: 'simulate_mutation',
429
- description: 'The Semantic Physics Engine. Proposes a hypothetical change to an entity\'s dimensions (like adding a "fallible" or "auth" trait) and simulates the topological fallout upstream and downstream. Returns a blueprint of exactly which other entities will break and what fixes they require.',
429
+ description: 'The Impact Simulator. Proposes a hypothetical change to an entity (like adding a "fallible" or "auth" requirement) and simulates the architectural fallout upstream and downstream. Returns a blueprint of exactly which other entities will break and what fixes they require.',
430
430
  inputSchema: {
431
431
  type: 'object',
432
432
  properties: {
433
433
  project: projectParam,
434
434
  entity_id: {
435
435
  type: 'string',
436
- description: 'The target entity to mutate.',
436
+ description: 'The target entity to analyze.',
437
437
  },
438
438
  mutation: {
439
439
  type: 'object',
440
440
  description: 'The hypothetical change to apply.',
441
441
  properties: {
442
- dimension: { type: 'string', enum: ['constraints', 'traits'] },
442
+ dimension: { type: 'string', enum: ['constraints', 'traits'], description: 'The attribute scope to mutate.' },
443
443
  change: {
444
444
  type: 'object',
445
445
  properties: {
@@ -456,7 +456,7 @@ const TOOLS = [
456
456
  },
457
457
  {
458
458
  name: 'query_data_targets',
459
- description: 'Search the codebase across the δ (Data) dimension to find all entities that read or write to a specific database table, state object, or data source. This acts as a reverse-index for data flow, essential for planning migrations or state refactors.',
459
+ description: 'Search the codebase for data interactions to find all entities that read or write to a specific database table, state object, or data source. This acts as a reverse-index for data flow, essential for planning migrations or state refactors.',
460
460
  inputSchema: {
461
461
  type: 'object',
462
462
  properties: {
@@ -471,7 +471,7 @@ const TOOLS = [
471
471
  },
472
472
  {
473
473
  name: 'find_exposure_leaks',
474
- description: 'Analyze the call graph across the χ (Context) dimension to find architectural visibility leaks. Flags paths where a "public" or "api" entity directly accesses a "private" entity, potentially leaking sensitive data or bypassing internal service boundaries.',
474
+ description: 'Analyze the call graph for architectural visibility leaks. Flags paths where a "public" or "api" entity directly accesses a "private" internal entity, potentially leaking sensitive data or bypassing internal service boundaries.',
475
475
  inputSchema: {
476
476
  type: 'object',
477
477
  properties: {
@@ -481,7 +481,7 @@ const TOOLS = [
481
481
  },
482
482
  {
483
483
  name: 'find_semantic_clones',
484
- description: 'Analyze the codebase across the Σ (Semantics) dimension to find duplicated logic blocks. Normalizes variables and compares abstract syntax tree shapes to identify identical algorithms written across different files or even different languages.',
484
+ description: 'Analyze the codebase for duplicated logic blocks. Normalizes variables and compares code structure to identify identical algorithms written across different files or even different languages.',
485
485
  inputSchema: {
486
486
  type: 'object',
487
487
  properties: {
@@ -493,10 +493,37 @@ const TOOLS = [
493
493
  },
494
494
  },
495
495
  },
496
- // ─── Diff Tools ─────────────────────────────────────────────────
496
+ {
497
+ name: 'create_symbol',
498
+ description: 'Register a new code symbol in the architectural graph. This does not write to disk, but allows the Impact Simulator and Conflict Matrix to reason about a symbol that is pending creation. Essential for planning new features that introduce new files or modules.',
499
+ inputSchema: {
500
+ type: 'object',
501
+ properties: {
502
+ project: projectParam,
503
+ id: {
504
+ type: 'string',
505
+ description: 'The unique ID or name for the new symbol.',
506
+ },
507
+ source_file: {
508
+ type: 'string',
509
+ description: 'The relative path to the file where this symbol will be created.',
510
+ },
511
+ layer: {
512
+ type: 'string',
513
+ description: 'The architectural layer (e.g., "service", "route", "component").',
514
+ },
515
+ description: {
516
+ type: 'string',
517
+ description: 'Brief description of the symbol\'s purpose.',
518
+ },
519
+ },
520
+ required: ['id', 'source_file'],
521
+ },
522
+ },
523
+ // ─── Diff Tools ─────────────────────────────────────────────────
497
524
  {
498
525
  name: 'diff_bundle',
499
- description: 'Compare entities between a worktree and the loaded project. Shows which entities were added, removed, or modified at the symbol level — not a line diff, but a structural diff showing changed signatures, call graphs, constraints, and logic. Extracts the worktree automatically if no bundle exists.',
526
+ description: 'Compare code structure between a worktree and the loaded project. Shows which symbols were added, removed, or modified — not a line diff, but a structural diff showing changed signatures, dependencies, and implementation logic.',
500
527
  inputSchema: {
501
528
  type: 'object',
502
529
  properties: {
@@ -515,7 +542,7 @@ const TOOLS = [
515
542
  },
516
543
  {
517
544
  name: 'conflict_matrix',
518
- description: 'Given multiple tasks, classify every task pair into conflict tiers bridging JSTF-T theory and Git reality. Tier 1 (different files, safe), Tier 2 (same file, different entities, safe), Tier 3 (same entity, orthogonal Spatial Zones like imports vs logic, risky but parallelizable), Tier 4 (same entity, same Spatial Zone, MUST sequence). Passing "dimensions" per task enables Tier 3 downgrades.',
545
+ description: 'Given multiple tasks, classify every task pair into conflict tiers to determine parallelization safety. Tier 1 (different files, safe), Tier 2 (same file, different symbols, safe), Tier 3 (same symbol, orthogonal changes like imports vs logic, risky but parallelizable), Tier 4 (same symbol, overlapping changes, MUST sequence). Passing "scopes" per task enables Tier 3 downgrades.',
519
546
  inputSchema: {
520
547
  type: 'object',
521
548
  properties: {
@@ -532,16 +559,16 @@ const TOOLS = [
532
559
  entity_ids: {
533
560
  type: 'array',
534
561
  items: { type: 'string' },
535
- description: 'Entity IDs or names that this task will modify',
562
+ description: 'Symbol names or IDs that this task will modify',
536
563
  },
537
564
  dimensions: {
538
565
  type: 'array',
539
566
  items: { type: 'string' },
540
- description: 'Optional: JSTF-T dimensions this task will modify (e.g., "edges", "struct", "semantics", "constraints"). Used to downgrade conflicts via Spatial Zones.',
567
+ description: 'Optional: Code scopes this task will modify (e.g., "edges", "struct", "semantics", "constraints"). Used to downgrade conflicts via spatial separation.',
541
568
  },
542
569
  expand_blast_radius: {
543
570
  type: 'boolean',
544
- description: 'Include transitively affected entities in the conflict check (default: false)',
571
+ description: 'Include transitively affected symbols in the conflict check (default: false)',
545
572
  },
546
573
  },
547
574
  required: ['id', 'entity_ids'],
@@ -697,7 +724,7 @@ async function main() {
697
724
  case 'report_actual_burn':
698
725
  result = await reportActualBurn(args);
699
726
  break;
700
- // Semantic (9D) JSTF-T Tools
727
+ // Analysis & Impact Tools
701
728
  case 'find_runtime_violations':
702
729
  result = find_runtime_violations(args);
703
730
  break;
@@ -719,6 +746,9 @@ async function main() {
719
746
  case 'find_semantic_clones':
720
747
  result = find_semantic_clones(args);
721
748
  break;
749
+ case 'create_symbol':
750
+ result = create_symbol(args);
751
+ break;
722
752
  // Diff Tools
723
753
  case 'diff_bundle':
724
754
  result = await diffBundle(args);
package/dist/loader.d.ts CHANGED
@@ -46,5 +46,10 @@ export declare class MultiLoader {
46
46
  isMultiProject(): boolean;
47
47
  isLoaded(): boolean;
48
48
  hasProject(name: string): boolean;
49
+ /**
50
+ * Register a virtual entity in memory.
51
+ * Used for Phase 1/2 of the Harness to reason about entities that haven't been written to disk yet.
52
+ */
53
+ registerVirtualEntity(entity: JstfEntity, project?: string): void;
49
54
  totalEntities(): number;
50
55
  }
package/dist/loader.js CHANGED
@@ -190,6 +190,28 @@ export class MultiLoader {
190
190
  hasProject(name) {
191
191
  return this.projects.has(name);
192
192
  }
193
+ /**
194
+ * Register a virtual entity in memory.
195
+ * Used for Phase 1/2 of the Harness to reason about entities that haven't been written to disk yet.
196
+ */
197
+ registerVirtualEntity(entity, project) {
198
+ if (!this.loaded)
199
+ this.load();
200
+ const p = this.resolveProject(project);
201
+ if (!p)
202
+ return;
203
+ const entities = this.projectEntities.get(p) || [];
204
+ entity._project = p;
205
+ // If entity already exists, update it, otherwise append
206
+ const existingIdx = entities.findIndex(e => e.id === entity.id);
207
+ if (existingIdx !== -1) {
208
+ entities[existingIdx] = { ...entities[existingIdx], ...entity };
209
+ }
210
+ else {
211
+ entities.push(entity);
212
+ }
213
+ this.projectEntities.set(p, entities);
214
+ }
193
215
  totalEntities() {
194
216
  let total = 0;
195
217
  for (const entities of this.projectEntities.values()) {
@@ -262,13 +262,13 @@ export async function diffBundle(args) {
262
262
  return result;
263
263
  }
264
264
  // ─── Conflict Tier Classification ─────────────────────────────────
265
- const ZONE_1 = new Set(['edges', 'imports', 'ε']); // Header / Far from body
266
- const ZONE_2 = new Set(['struct', 'σ', 'constraints', 'κ', 'traits', 'τ', 'ownership', 'λ']); // Signature / Decorators (High collision risk)
267
- const ZONE_3 = new Set(['semantics', 'Σ', 'data', 'δ', 'runtime', 'ρ']); // Body / Implementation
268
- function getZones(dimensions) {
265
+ const ZONE_1 = new Set(['edges', 'imports']); // Header / Dependencies
266
+ const ZONE_2 = new Set(['struct', 'constraints', 'traits', 'ownership']); // Signature / Modifiers
267
+ const ZONE_3 = new Set(['semantics', 'data', 'runtime']); // Logic / Implementation
268
+ function getZones(scopes) {
269
269
  const zones = new Set();
270
- for (const d of dimensions) {
271
- const lower = d.toLowerCase();
270
+ for (const s of scopes) {
271
+ const lower = s.toLowerCase();
272
272
  if (ZONE_1.has(lower))
273
273
  zones.add(1);
274
274
  if (ZONE_2.has(lower))
@@ -279,7 +279,7 @@ function getZones(dimensions) {
279
279
  return zones;
280
280
  }
281
281
  function classifyConflictTier(taskA, taskB) {
282
- // Check entity overlap
282
+ // Check symbol overlap
283
283
  const sharedEntities = [];
284
284
  for (const id of taskA.entityIds) {
285
285
  if (taskB.entityIds.has(id)) {
@@ -287,7 +287,7 @@ function classifyConflictTier(taskA, taskB) {
287
287
  }
288
288
  }
289
289
  if (sharedEntities.length > 0) {
290
- // Both touch same entity. Check dimensions to see if we can downgrade from Tier 4 (Sequential) to Tier 3 (Parallelizable Orthogonal)
290
+ // Both touch same symbol. Check scopes to see if we can downgrade from Tier 4 (Sequential) to Tier 3 (Parallelizable Orthogonal)
291
291
  if (taskA.dimensions.size > 0 && taskB.dimensions.size > 0) {
292
292
  const zonesA = getZones(taskA.dimensions);
293
293
  const zonesB = getZones(taskB.dimensions);
@@ -299,7 +299,7 @@ function classifyConflictTier(taskA, taskB) {
299
299
  if (!spatialCollision) {
300
300
  return {
301
301
  tier: 3,
302
- reason: `${sharedEntities.length} shared entities, but orthogonal Spatial Zones (Tier 3) — safe to parallelize`,
302
+ reason: `${sharedEntities.length} shared symbols, but orthogonal change scopes (Tier 3) — safe to parallelize`,
303
303
  sharedFiles: [],
304
304
  sharedEntities,
305
305
  };
@@ -307,7 +307,7 @@ function classifyConflictTier(taskA, taskB) {
307
307
  }
308
308
  return {
309
309
  tier: 4,
310
- reason: `${sharedEntities.length} shared entities in same/unknown Spatial Zone (Tier 4) — MUST sequence to prevent git conflict`,
310
+ reason: `${sharedEntities.length} shared symbols in same/unknown change scope (Tier 4) — MUST sequence to prevent merge conflict`,
311
311
  sharedFiles: [],
312
312
  sharedEntities,
313
313
  };
@@ -329,7 +329,7 @@ function classifyConflictTier(taskA, taskB) {
329
329
  }
330
330
  return {
331
331
  tier: 2,
332
- reason: `${sharedFiles.length} shared files but different entitiesgit auto-merge handles it`,
332
+ reason: `${sharedFiles.length} shared files but different symbolssafe to parallelize`,
333
333
  sharedFiles,
334
334
  sharedEntities: [],
335
335
  };
@@ -98,3 +98,10 @@ export declare function find_semantic_clones(args?: {
98
98
  project?: string;
99
99
  min_complexity?: number;
100
100
  }): unknown;
101
+ export declare function create_symbol(args: {
102
+ id: string;
103
+ source_file: string;
104
+ layer?: string;
105
+ project?: string;
106
+ description?: string;
107
+ }): unknown;
@@ -5,6 +5,7 @@
5
5
  * Each tool computes derived insights (dead code, layer violations,
6
6
  * coupling metrics, auth coverage, etc.) from the entity data.
7
7
  */
8
+ import path from 'path';
8
9
  import { computeBlastRadius } from '../graph.js';
9
10
  import { getLoader, getGraph, validateProject, entityName, entityLayer, entitySummary, } from './index.js';
10
11
  import { isSupabaseConfigured, insertPrediction, updateActualBurn, abandonPrediction, listPredictions, } from '../supabase.js';
@@ -866,7 +867,7 @@ export async function reportActualBurn(args) {
866
867
  _summary: `Prediction ${updated.id.slice(0, 8)}… closed. Predicted ${updated.predicted_total} tokens, actual ${updated.actual_total_tokens} tokens. Drift: ${updated.drift_ratio != null ? `${(updated.drift_ratio * 100).toFixed(1)}%` : 'N/A'}.`,
867
868
  };
868
869
  }
869
- // ─── Tool: find_runtime_violations (ρ Dimension) ─────────────────
870
+ // ─── Tool: find_runtime_violations (Runtime Context) ────────────
870
871
  export function find_runtime_violations(args) {
871
872
  const projErr = validateProject(args?.project);
872
873
  if (projErr)
@@ -903,11 +904,11 @@ export function find_runtime_violations(args) {
903
904
  }
904
905
  return {
905
906
  totalViolations: violations.length,
906
- _summary: `Found ${violations.length} runtime/framework boundary violations (ρ dimension)`,
907
+ _summary: `Found ${violations.length} runtime/framework boundary violations`,
907
908
  violations: violations.slice(0, 100),
908
909
  };
909
910
  }
910
- // ─── Tool: find_ownership_violations (λ Dimension) ───────────────
911
+ // ─── Tool: find_ownership_violations (Ownership & Lifetimes) ─────
911
912
  export function find_ownership_violations(args) {
912
913
  const projErr = validateProject(args?.project);
913
914
  if (projErr)
@@ -944,11 +945,11 @@ export function find_ownership_violations(args) {
944
945
  }
945
946
  return {
946
947
  totalViolations: violations.length,
947
- _summary: `Found ${violations.length} entities with strict/violating ownership constraints (λ dimension)`,
948
+ _summary: `Found ${violations.length} symbols with strict/violating ownership constraints`,
948
949
  violations: violations.slice(0, 100),
949
950
  };
950
951
  }
951
- // ─── Tool: query_traits (τ Dimension) ────────────────────────────
952
+ // ─── Tool: query_traits (Trait Search) ───────────────────────────
952
953
  export function query_traits(args) {
953
954
  const projErr = validateProject(args.project);
954
955
  if (projErr)
@@ -988,11 +989,11 @@ export function query_traits(args) {
988
989
  return {
989
990
  trait: args.trait,
990
991
  total: results.length,
991
- _summary: `Found ${results.length} entities implementing the '${args.trait}' trait (τ dimension)`,
992
+ _summary: `Found ${results.length} symbols implementing the '${args.trait}' trait`,
992
993
  entities: results.slice(0, 100).map(entitySummary),
993
994
  };
994
995
  }
995
- // ─── Tool: simulate_mutation (The Physics Engine) ────────────────
996
+ // ─── Tool: simulate_mutation (Impact Simulator) ──────────────────
996
997
  export function simulate_mutation(args) {
997
998
  const projErr = validateProject(args.project);
998
999
  if (projErr)
@@ -1002,7 +1003,7 @@ export function simulate_mutation(args) {
1002
1003
  const targetEntity = loader.getEntityById(args.entity_id, args.project)
1003
1004
  || loader.getEntityByName(args.entity_id, args.project);
1004
1005
  if (!targetEntity) {
1005
- return { error: `Entity not found: ${args.entity_id}` };
1006
+ return { error: `Symbol not found: ${args.entity_id}` };
1006
1007
  }
1007
1008
  const targetId = targetEntity.id;
1008
1009
  const { dimension, change } = args.mutation;
@@ -1037,7 +1038,7 @@ export function simulate_mutation(args) {
1037
1038
  fallout.push({
1038
1039
  entity: entitySummary(callerEntity),
1039
1040
  distance: depth + 1,
1040
- reason: `Calls a newly fallible pipeline but lacks error handling.`,
1041
+ reason: `Calls a newly fallible path but lacks error handling.`,
1041
1042
  requiredFix: `Wrap call to ${currentId} in try/catch or propagate error.`,
1042
1043
  });
1043
1044
  // Error propagates up if not caught, so we continue queueing
@@ -1068,12 +1069,12 @@ export function simulate_mutation(args) {
1068
1069
  return {
1069
1070
  target: entitySummary(targetEntity),
1070
1071
  mutation: args.mutation,
1071
- affectedEntitiesCount: fallout.length,
1072
- _summary: `Simulating adding [${addedTags.join(', ')}] to ${entityName(targetEntity)}. This structurally breaks ${fallout.length} upstream entities.`,
1072
+ affectedSymbolsCount: fallout.length,
1073
+ _summary: `Simulating adding [${addedTags.join(', ')}] to ${entityName(targetEntity)}. This structurally impacts ${fallout.length} upstream symbols.`,
1073
1074
  fallout,
1074
1075
  };
1075
1076
  }
1076
- // ─── Tool: query_data_targets (δ Dimension Reverse-Index) ────────
1077
+ // ─── Tool: query_data_targets (Data Flow Analysis) ──────────────
1077
1078
  export function query_data_targets(args) {
1078
1079
  const projErr = validateProject(args.project);
1079
1080
  if (projErr)
@@ -1122,12 +1123,12 @@ export function query_data_targets(args) {
1122
1123
  totalInteractions: readers.length + writers.length,
1123
1124
  writersCount: writers.length,
1124
1125
  readersCount: readers.length,
1125
- _summary: `Found ${writers.length} entities mutating and ${readers.length} entities reading data target '${args.target_name}' (δ dimension reverse-index)`,
1126
+ _summary: `Found ${writers.length} symbols mutating and ${readers.length} symbols reading data target '${args.target_name}'`,
1126
1127
  writers: writers.slice(0, 50),
1127
1128
  readers: readers.slice(0, 50),
1128
1129
  };
1129
1130
  }
1130
- // ─── Tool: find_exposure_leaks (χ Context Dimension) ─────────────
1131
+ // ─── Tool: find_exposure_leaks (Architectural Visibility) ───────
1131
1132
  export function find_exposure_leaks(args) {
1132
1133
  const projErr = validateProject(args?.project);
1133
1134
  if (projErr)
@@ -1150,18 +1151,18 @@ export function find_exposure_leaks(args) {
1150
1151
  leaks.push({
1151
1152
  publicCaller: entitySummary(callerEntity),
1152
1153
  privateCallee: entitySummary(calleeEntity),
1153
- issue: `Exposure Leak: Public/API entity directly calls deeply private entity.`,
1154
+ issue: `Exposure Leak: Public/API symbol directly calls deeply private internal implementation.`,
1154
1155
  });
1155
1156
  }
1156
1157
  }
1157
1158
  }
1158
1159
  return {
1159
1160
  totalLeaks: leaks.length,
1160
- _summary: `Found ${leaks.length} architectural visibility leaks where public edges bypass internal boundaries to reach private entities (χ dimension)`,
1161
+ _summary: `Found ${leaks.length} architectural visibility leaks where public paths bypass internal boundaries`,
1161
1162
  leaks: leaks.slice(0, 100),
1162
1163
  };
1163
1164
  }
1164
- // ─── Tool: find_semantic_clones (Σ Logic Dimension) ──────────────
1165
+ // ─── Tool: find_semantic_clones (Logic Analysis) ────────────────
1165
1166
  import { createHash } from 'crypto';
1166
1167
  export function find_semantic_clones(args) {
1167
1168
  const projErr = validateProject(args?.project);
@@ -1205,8 +1206,44 @@ export function find_semantic_clones(args) {
1205
1206
  totalDuplicatedEntities += c.count;
1206
1207
  return {
1207
1208
  cloneGroupsFound: clones.length,
1208
- totalDuplicatedEntities,
1209
- _summary: `Found ${clones.length} semantic clone groups involving ${totalDuplicatedEntities} total entities (Σ dimension analysis)`,
1209
+ totalDuplicatedSymbols: totalDuplicatedEntities,
1210
+ _summary: `Found ${clones.length} logic clone groups involving ${totalDuplicatedEntities} symbols`,
1210
1211
  cloneGroups: clones.slice(0, 50),
1211
1212
  };
1212
1213
  }
1214
+ // ─── Tool: create_symbol (Virtual Entry) ─────────────────────────
1215
+ export function create_symbol(args) {
1216
+ const projErr = validateProject(args.project);
1217
+ if (projErr)
1218
+ return { error: projErr };
1219
+ const loader = getLoader();
1220
+ // Create a skeleton JSTF-T entity
1221
+ const virtualEntity = {
1222
+ id: args.id,
1223
+ _sourceFile: args.source_file,
1224
+ sourceFile: args.source_file,
1225
+ context: {
1226
+ layer: args.layer || 'other',
1227
+ visibility: 'public',
1228
+ module: path.basename(args.source_file, path.extname(args.source_file)),
1229
+ },
1230
+ struct: {
1231
+ name: args.id,
1232
+ type: 'pending_creation'
1233
+ },
1234
+ constraints: {},
1235
+ traits: { self: {} },
1236
+ runtime: { framework: 'agnostic' },
1237
+ edges: { calls: [], imports: [] },
1238
+ semantics: [],
1239
+ _virtual: true,
1240
+ _description: args.description
1241
+ };
1242
+ loader.registerVirtualEntity(virtualEntity, args.project);
1243
+ return {
1244
+ success: true,
1245
+ id: args.id,
1246
+ sourceFile: args.source_file,
1247
+ _summary: `Registered virtual symbol '${args.id}' in ${args.source_file}. Other tools can now reason about this symbol prior to its physical creation.`,
1248
+ };
1249
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@papyruslabsai/seshat-mcp",
3
- "version": "0.8.0",
3
+ "version": "0.9.0",
4
4
  "description": "Semantic MCP server — exposes a codebase's structure, dependencies, and constraints as queryable tools",
5
5
  "type": "module",
6
6
  "bin": {