@papyruslabsai/seshat-mcp 0.4.1 → 0.6.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.
@@ -1,9 +1,9 @@
1
1
  /**
2
- * Interpretation Functor Tools
2
+ * Analysis Tools
3
3
  *
4
- * Each functor is I: J -> D — projecting the 9D JSTF-T coordinate space
5
- * onto a domain-specific judgment. These are composite analyses built
6
- * from the primitive dimensions (sigma, epsilon, delta, kappa, chi, tau, rho).
4
+ * Composite analyses built from the extracted code entity graph.
5
+ * Each tool computes derived insights (dead code, layer violations,
6
+ * coupling metrics, auth coverage, etc.) from the entity data.
7
7
  */
8
8
  import { computeBlastRadius } from '../graph.js';
9
9
  import { getLoader, getGraph, validateProject, entityLayer, entitySummary, } from './index.js';
@@ -25,7 +25,7 @@ const LAYER_ORDER = {
25
25
  /**
26
26
  * Estimate the token cost of loading an entity's source code into an LLM context.
27
27
  * Uses real sourceTokens from the extraction pipeline when available (v0.3.2+),
28
- * falls back to heuristic estimation from 9D coordinates for older bundles.
28
+ * falls back to heuristic estimation for older bundles.
29
29
  */
30
30
  export function estimateTokens(e) {
31
31
  // Use real source token count from extraction pipeline
@@ -33,7 +33,7 @@ export function estimateTokens(e) {
33
33
  const st = raw.sourceTokens;
34
34
  if (st?.estimated)
35
35
  return st.estimated;
36
- // Fallback: heuristic from 9D coordinates (pre-v0.3.2 bundles)
36
+ // Fallback: heuristic estimation (pre-v0.3.2 bundles)
37
37
  let tokens = 50; // Base: name, id, layer
38
38
  if (e.struct && typeof e.struct !== 'string') {
39
39
  tokens += 20; // signature
@@ -53,7 +53,7 @@ export function estimateTokens(e) {
53
53
  /**
54
54
  * Detect which estimator was used for an entity.
55
55
  * Returns 'syntactic' if tree-sitter leaf node count was used,
56
- * 'charDiv4' if chars/4 heuristic was used, 'heuristic' for 9D fallback.
56
+ * 'charDiv4' if chars/4 heuristic was used, 'heuristic' for legacy fallback.
57
57
  */
58
58
  function detectEstimator(e) {
59
59
  const raw = e;
@@ -80,7 +80,7 @@ function dominantEstimator(entities) {
80
80
  return 'charDiv4';
81
81
  return 'heuristic';
82
82
  }
83
- // ─── Functor 1: find_dead_code ───────────────────────────────────
83
+ // ─── Tool: find_dead_code ────────────────────────────────────────
84
84
  export function findDeadCode(args) {
85
85
  const projErr = validateProject(args.project);
86
86
  if (projErr)
@@ -150,7 +150,7 @@ export function findDeadCode(args) {
150
150
  dead: deadEntities.slice(0, 100).map(entitySummary),
151
151
  };
152
152
  }
153
- // ─── Functor 2: find_layer_violations ────────────────────────────
153
+ // ─── Tool: find_layer_violations ─────────────────────────────────
154
154
  export function findLayerViolations(args) {
155
155
  const projErr = validateProject(args?.project);
156
156
  if (projErr)
@@ -206,7 +206,7 @@ export function findLayerViolations(args) {
206
206
  violations: violations.slice(0, 100),
207
207
  };
208
208
  }
209
- // ─── Functor 3: get_coupling_metrics ─────────────────────────────
209
+ // ─── Tool: get_coupling_metrics ──────────────────────────────────
210
210
  export function getCouplingMetrics(args) {
211
211
  const projErr = validateProject(args.project);
212
212
  if (projErr)
@@ -278,7 +278,7 @@ export function getCouplingMetrics(args) {
278
278
  metrics: metrics.slice(0, 50),
279
279
  };
280
280
  }
281
- // ─── Functor 4: get_auth_matrix ──────────────────────────────────
281
+ // ─── Tool: get_auth_matrix ───────────────────────────────────────
282
282
  export function getAuthMatrix(args) {
283
283
  const projErr = validateProject(args?.project);
284
284
  if (projErr)
@@ -336,7 +336,7 @@ export function getAuthMatrix(args) {
336
336
  issues: inconsistencies.slice(0, 50),
337
337
  };
338
338
  }
339
- // ─── Functor 5: find_error_gaps ──────────────────────────────────
339
+ // ─── Tool: find_error_gaps ───────────────────────────────────────
340
340
  export function findErrorGaps(args) {
341
341
  const projErr = validateProject(args?.project);
342
342
  if (projErr)
@@ -349,13 +349,13 @@ export function findErrorGaps(args) {
349
349
  for (const e of entities) {
350
350
  if (!e.id)
351
351
  continue;
352
- // Check kappa.throws
352
+ // Check constraints.throws
353
353
  const constraints = e.constraints;
354
354
  if (constraints && !Array.isArray(constraints) && constraints.throws) {
355
355
  fallibleIds.add(e.id);
356
356
  continue;
357
357
  }
358
- // Check tau.self.fallible
358
+ // Check traits.self.fallible
359
359
  const traits = e.traits;
360
360
  if (traits && !Array.isArray(traits) && traits.self?.fallible) {
361
361
  fallibleIds.add(e.id);
@@ -403,7 +403,7 @@ export function findErrorGaps(args) {
403
403
  gaps: gaps.slice(0, 100),
404
404
  };
405
405
  }
406
- // ─── Functor 6: get_test_coverage ────────────────────────────────
406
+ // ─── Tool: get_test_coverage ─────────────────────────────────────
407
407
  export function getTestCoverage(args) {
408
408
  const projErr = validateProject(args.project);
409
409
  if (projErr)
@@ -482,7 +482,7 @@ export function getTestCoverage(args) {
482
482
  }
483
483
  return result;
484
484
  }
485
- // ─── Functor 7: get_optimal_context ──────────────────────────────
485
+ // ─── Tool: get_optimal_context ───────────────────────────────────
486
486
  export function getOptimalContext(args) {
487
487
  const projErr = validateProject(args.project);
488
488
  if (projErr)
@@ -598,7 +598,7 @@ export function getOptimalContext(args) {
598
598
  context: selected,
599
599
  };
600
600
  }
601
- // ─── Functor 8: estimate_task_cost ───────────────────────────────
601
+ // ─── Tool: estimate_task_cost ────────────────────────────────────
602
602
  /**
603
603
  * Estimate token cost of a code change BEFORE starting work.
604
604
  * Computes blast radius, sums source token counts, and projects total burn.
@@ -763,7 +763,7 @@ export async function estimateTaskCost(args) {
763
763
  }
764
764
  return result;
765
765
  }
766
- // ─── Functor 9: report_actual_burn ───────────────────────────────
766
+ // ─── Tool: report_actual_burn ────────────────────────────────────
767
767
  /**
768
768
  * Close the calibration feedback loop by reporting actual token usage
769
769
  * against a prior prediction from estimate_task_cost.
@@ -866,3 +866,129 @@ export async function reportActualBurn(args) {
866
866
  _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
867
  };
868
868
  }
869
+ // ─── Tool: find_runtime_violations (ρ Dimension) ─────────────────
870
+ export function find_runtime_violations(args) {
871
+ const projErr = validateProject(args?.project);
872
+ if (projErr)
873
+ return { error: projErr };
874
+ const g = getGraph(args?.project);
875
+ const violations = [];
876
+ for (const [callerId, calleeIds] of g.callees) {
877
+ const callerEntity = g.entityById.get(callerId);
878
+ if (!callerEntity)
879
+ continue;
880
+ const callerFramework = callerEntity.runtime?.framework || 'agnostic';
881
+ for (const calleeId of calleeIds) {
882
+ const calleeEntity = g.entityById.get(calleeId);
883
+ if (!calleeEntity)
884
+ continue;
885
+ const calleeFramework = calleeEntity.runtime?.framework;
886
+ // If caller is framework-agnostic but calls framework-specific code (e.g., pure logic calling React)
887
+ if (callerFramework === 'agnostic' && calleeFramework && calleeFramework !== 'agnostic') {
888
+ violations.push({
889
+ caller: { ...entitySummary(callerEntity), framework: callerFramework },
890
+ callee: { ...entitySummary(calleeEntity), framework: calleeFramework },
891
+ issue: `Framework leak: Agnostic caller depends on ${calleeFramework}-specific callee`,
892
+ });
893
+ }
894
+ // If mixing frameworks directly (e.g., Vue calling React)
895
+ if (callerFramework !== 'agnostic' && calleeFramework && calleeFramework !== 'agnostic' && callerFramework !== calleeFramework) {
896
+ violations.push({
897
+ caller: { ...entitySummary(callerEntity), framework: callerFramework },
898
+ callee: { ...entitySummary(calleeEntity), framework: calleeFramework },
899
+ issue: `Cross-framework boundary: ${callerFramework} calling ${calleeFramework}`,
900
+ });
901
+ }
902
+ }
903
+ }
904
+ return {
905
+ totalViolations: violations.length,
906
+ _summary: `Found ${violations.length} runtime/framework boundary violations (ρ dimension)`,
907
+ violations: violations.slice(0, 100),
908
+ };
909
+ }
910
+ // ─── Tool: find_ownership_violations (λ Dimension) ───────────────
911
+ export function find_ownership_violations(args) {
912
+ const projErr = validateProject(args?.project);
913
+ if (projErr)
914
+ return { error: projErr };
915
+ const loader = getLoader();
916
+ const entities = loader.getEntities(args?.project);
917
+ const violations = [];
918
+ for (const e of entities) {
919
+ if (!e.ownership || Object.keys(e.ownership).length === 0)
920
+ continue;
921
+ // We look for 'unsafe', 'escapes', 'mutates_borrowed', or complex lifetime constraints
922
+ const own = e.ownership;
923
+ if (own.unsafe) {
924
+ violations.push({
925
+ entity: entitySummary(e),
926
+ ownership_details: own,
927
+ issue: 'Unsafe memory access or pointer manipulation flagged',
928
+ });
929
+ }
930
+ else if (own.escapes) {
931
+ violations.push({
932
+ entity: entitySummary(e),
933
+ ownership_details: own,
934
+ issue: 'Value potentially escapes its lifetime boundary',
935
+ });
936
+ }
937
+ else if (own.mutates_borrowed) {
938
+ violations.push({
939
+ entity: entitySummary(e),
940
+ ownership_details: own,
941
+ issue: 'Attempts to mutate an immutably borrowed reference',
942
+ });
943
+ }
944
+ }
945
+ return {
946
+ totalViolations: violations.length,
947
+ _summary: `Found ${violations.length} entities with strict/violating ownership constraints (λ dimension)`,
948
+ violations: violations.slice(0, 100),
949
+ };
950
+ }
951
+ // ─── Tool: query_traits (τ Dimension) ────────────────────────────
952
+ export function query_traits(args) {
953
+ const projErr = validateProject(args.project);
954
+ if (projErr)
955
+ return { error: projErr };
956
+ const target = args.trait.toLowerCase();
957
+ const loader = getLoader();
958
+ const entities = loader.getEntities(args.project);
959
+ const results = entities.filter(e => {
960
+ if (!e.traits)
961
+ return false;
962
+ // Handle array of strings [ 'asyncContext', 'generator' ]
963
+ if (Array.isArray(e.traits)) {
964
+ return e.traits.some(t => t.toLowerCase().includes(target));
965
+ }
966
+ // Handle structured traits { self: { fallible: true } }
967
+ if (typeof e.traits === 'object') {
968
+ const tr = e.traits;
969
+ if (tr.self && typeof tr.self === 'object') {
970
+ const selfTraits = tr.self;
971
+ for (const [key, val] of Object.entries(selfTraits)) {
972
+ if (key.toLowerCase().includes(target) && val === true)
973
+ return true;
974
+ }
975
+ }
976
+ if (tr.params && typeof tr.params === 'object') {
977
+ const paramTraits = tr.params;
978
+ for (const p of Object.values(paramTraits)) {
979
+ if (p.bounds && Array.isArray(p.bounds) && p.bounds.some((b) => b.toLowerCase().includes(target)))
980
+ return true;
981
+ if (p.markers && Array.isArray(p.markers) && p.markers.some((m) => m.toLowerCase().includes(target)))
982
+ return true;
983
+ }
984
+ }
985
+ }
986
+ return false;
987
+ });
988
+ return {
989
+ trait: args.trait,
990
+ total: results.length,
991
+ _summary: `Found ${results.length} entities implementing the '${args.trait}' trait (τ dimension)`,
992
+ entities: results.slice(0, 100).map(entitySummary),
993
+ };
994
+ }
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Semantic MCP Tool Implementations
3
3
  *
4
- * Each tool exposes a dimension or computation over the 9D JSTF-T coordinate space.
4
+ * Each tool exposes a query or computation over the extracted code entity graph.
5
5
  * Tools operate on the in-memory entity bundle loaded from .seshat/_bundle.json.
6
6
  *
7
7
  * Multi-project: when multiple projects are loaded, each tool accepts an optional
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Semantic MCP Tool Implementations
3
3
  *
4
- * Each tool exposes a dimension or computation over the 9D JSTF-T coordinate space.
4
+ * Each tool exposes a query or computation over the extracted code entity graph.
5
5
  * Tools operate on the in-memory entity bundle loaded from .seshat/_bundle.json.
6
6
  *
7
7
  * Multi-project: when multiple projects are loaded, each tool accepts an optional
@@ -208,25 +208,21 @@ export function getEntity(args) {
208
208
  if (!entity) {
209
209
  return { error: `Entity not found: ${args.id}` };
210
210
  }
211
- // Return the full 9D coordinate dump
212
211
  return {
213
212
  id: entity.id,
214
213
  name: entityName(entity),
215
214
  ...(entity._project ? { project: entity._project } : {}),
216
215
  sourceFile: entity._sourceFile,
217
216
  sourceLanguage: entity._sourceLanguage,
218
- jstfFilename: entity._jstfFilename,
219
- dimensions: {
220
- sigma_struct: entity.struct,
221
- epsilon_edges: entity.edges,
222
- delta_data: entity.data,
223
- kappa_constraints: entity.constraints,
224
- chi_context: entity.context,
225
- lambda_ownership: entity.ownership,
226
- tau_traits: entity.traits,
227
- rho_runtime: entity.runtime,
228
- sigma_semantics: entity.semantics,
229
- },
217
+ structure: entity.struct,
218
+ call_graph: entity.edges,
219
+ data_flow: entity.data,
220
+ constraints: entity.constraints,
221
+ context: entity.context,
222
+ ownership: entity.ownership,
223
+ type_info: entity.traits,
224
+ runtime: entity.runtime,
225
+ logic: entity.semantics,
230
226
  };
231
227
  }
232
228
  // ─── Tool: get_dependencies ───────────────────────────────────────
@@ -258,7 +254,7 @@ export function getDependencies(args) {
258
254
  return e ? entitySummary(e) : { id: cId };
259
255
  });
260
256
  }
261
- // Also include direct imports from ε
257
+ // Also include direct imports
262
258
  if (entity.edges?.imports) {
263
259
  result.imports = entity.edges.imports;
264
260
  }
package/dist/types.d.ts CHANGED
@@ -1,10 +1,9 @@
1
1
  /**
2
- * JSTF-T Entity — 9D Semantic Coordinate
2
+ * Code Entity — the core unit of analysis
3
3
  *
4
4
  * Each entity represents a code unit (function, class, module, schema)
5
- * positioned in the 9-dimensional semantic space 𝕁:
6
- * σ (struct), ε (edges), δ (data), κ (constraints),
7
- * χ (context), λ (ownership), τ (traits), ρ (runtime), Σ (semantics)
5
+ * with extracted properties: structure, call graph, data flow, constraints,
6
+ * context, ownership, type info, runtime, and logic.
8
7
  */
9
8
  export interface JstfEntity {
10
9
  id: string;
@@ -12,7 +11,11 @@ export interface JstfEntity {
12
11
  _sourceFile?: string | null;
13
12
  _sourceLanguage?: string;
14
13
  _project?: string;
15
- /** σ — Structure: function shape, signature, modifiers */
14
+ _sourceLocation?: {
15
+ startLine: number;
16
+ endLine: number;
17
+ };
18
+ /** Structure: function shape, signature, modifiers */
16
19
  struct?: {
17
20
  name?: string;
18
21
  type?: string;
@@ -25,7 +28,7 @@ export interface JstfEntity {
25
28
  returnType?: string;
26
29
  [key: string]: unknown;
27
30
  } | string;
28
- /** ε — Edges: call graph, dependencies, imports */
31
+ /** Call graph: dependencies, imports, callers */
29
32
  edges?: {
30
33
  calls?: Array<{
31
34
  target: string;
@@ -41,7 +44,7 @@ export interface JstfEntity {
41
44
  }>;
42
45
  [key: string]: unknown;
43
46
  };
44
- /** δ — Data: data flow, sources, sinks, mutations */
47
+ /** Data flow: inputs, outputs, mutations */
45
48
  data?: {
46
49
  inputs?: Array<{
47
50
  name: string;
@@ -61,7 +64,7 @@ export interface JstfEntity {
61
64
  returns?: unknown[];
62
65
  [key: string]: unknown;
63
66
  };
64
- /** κ — Constraints: behavioral contracts, validation, purity */
67
+ /** Constraints: behavioral contracts, validation, purity */
65
68
  constraints?: {
66
69
  security?: string[];
67
70
  performance?: Record<string, unknown>;
@@ -82,7 +85,7 @@ export interface JstfEntity {
82
85
  };
83
86
  [key: string]: unknown;
84
87
  } | string[];
85
- /** χ — Context: architectural position, visibility, layer */
88
+ /** Context: architectural position, visibility, layer */
86
89
  context?: {
87
90
  layer?: string;
88
91
  layerSource?: string;
@@ -94,9 +97,9 @@ export interface JstfEntity {
94
97
  criticality?: string;
95
98
  [key: string]: unknown;
96
99
  };
97
- /** λ — Ownership: memory ownership, lifetimes, borrowing */
100
+ /** Ownership: memory management, lifetimes, borrowing (Rust/C++) */
98
101
  ownership?: Record<string, unknown>;
99
- /** τ — Traits: type capabilities, bounds, markers */
102
+ /** Type info: type capabilities, bounds, markers */
100
103
  traits?: string[] | {
101
104
  self?: {
102
105
  asyncContext?: boolean;
@@ -109,14 +112,14 @@ export interface JstfEntity {
109
112
  }>;
110
113
  [key: string]: unknown;
111
114
  };
112
- /** ρ — Runtime: reactive model, async platform, framework */
115
+ /** Runtime: async model, platform, framework */
113
116
  runtime?: {
114
117
  async?: string;
115
118
  framework?: string;
116
119
  platform?: string;
117
120
  [key: string]: unknown;
118
121
  };
119
- /** Σ — Semantics: operational content, normalized logic tree */
122
+ /** Logic: operational content, normalized logic tree */
120
123
  semantics?: unknown[];
121
124
  [key: string]: unknown;
122
125
  }
package/dist/types.js CHANGED
@@ -1,9 +1,8 @@
1
1
  /**
2
- * JSTF-T Entity — 9D Semantic Coordinate
2
+ * Code Entity — the core unit of analysis
3
3
  *
4
4
  * Each entity represents a code unit (function, class, module, schema)
5
- * positioned in the 9-dimensional semantic space 𝕁:
6
- * σ (struct), ε (edges), δ (data), κ (constraints),
7
- * χ (context), λ (ownership), τ (traits), ρ (runtime), Σ (semantics)
5
+ * with extracted properties: structure, call graph, data flow, constraints,
6
+ * context, ownership, type info, runtime, and logic.
8
7
  */
9
8
  export {};
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@papyruslabsai/seshat-mcp",
3
- "version": "0.4.1",
4
- "description": "Semantic MCP server — exposes a codebase's 9D JSTF-T coordinate space as queryable tools",
3
+ "version": "0.6.0",
4
+ "description": "Semantic MCP server — exposes a codebase's structure, dependencies, and constraints as queryable tools",
5
5
  "type": "module",
6
6
  "bin": {
7
7
  "seshat-mcp": "./dist/index.js"
@@ -30,6 +30,12 @@
30
30
  "url": "https://github.com/papyruslabs-ai/seshat.git",
31
31
  "directory": "packages/seshat-mcp"
32
32
  },
33
- "keywords": ["mcp", "jstf", "semantic", "code-analysis", "seshat"],
33
+ "keywords": [
34
+ "mcp",
35
+ "semantic",
36
+ "code-analysis",
37
+ "seshat",
38
+ "static-analysis"
39
+ ],
34
40
  "license": "MIT"
35
41
  }