@aaronsb/kg-cli 0.6.5 → 0.7.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.
Files changed (96) hide show
  1. package/dist/api/client.d.ts +127 -1
  2. package/dist/api/client.d.ts.map +1 -1
  3. package/dist/api/client.js +147 -0
  4. package/dist/api/client.js.map +1 -1
  5. package/dist/cli/batch.d.ts +8 -0
  6. package/dist/cli/batch.d.ts.map +1 -0
  7. package/dist/cli/batch.js +225 -0
  8. package/dist/cli/batch.js.map +1 -0
  9. package/dist/cli/commands.d.ts.map +1 -1
  10. package/dist/cli/commands.js +10 -1
  11. package/dist/cli/commands.js.map +1 -1
  12. package/dist/cli/concept.d.ts +9 -0
  13. package/dist/cli/concept.d.ts.map +1 -0
  14. package/dist/cli/concept.js +336 -0
  15. package/dist/cli/concept.js.map +1 -0
  16. package/dist/cli/edge.d.ts +9 -0
  17. package/dist/cli/edge.d.ts.map +1 -0
  18. package/dist/cli/edge.js +364 -0
  19. package/dist/cli/edge.js.map +1 -0
  20. package/dist/cli/jobs.js +111 -3
  21. package/dist/cli/jobs.js.map +1 -1
  22. package/dist/cli/storage.d.ts +10 -0
  23. package/dist/cli/storage.d.ts.map +1 -0
  24. package/dist/cli/storage.js +260 -0
  25. package/dist/cli/storage.js.map +1 -0
  26. package/dist/cli/vocabulary/index.d.ts.map +1 -1
  27. package/dist/cli/vocabulary/index.js +1 -0
  28. package/dist/cli/vocabulary/index.js.map +1 -1
  29. package/dist/cli/vocabulary/similarity.d.ts +1 -0
  30. package/dist/cli/vocabulary/similarity.d.ts.map +1 -1
  31. package/dist/cli/vocabulary/similarity.js +60 -9
  32. package/dist/cli/vocabulary/similarity.js.map +1 -1
  33. package/dist/lib/interactive.d.ts +84 -0
  34. package/dist/lib/interactive.d.ts.map +1 -0
  35. package/dist/lib/interactive.js +296 -0
  36. package/dist/lib/interactive.js.map +1 -0
  37. package/dist/lib/validation.d.ts +106 -0
  38. package/dist/lib/validation.d.ts.map +1 -0
  39. package/dist/lib/validation.js +354 -0
  40. package/dist/lib/validation.js.map +1 -0
  41. package/dist/mcp/formatters/concept.d.ts +24 -0
  42. package/dist/mcp/formatters/concept.d.ts.map +1 -0
  43. package/dist/mcp/formatters/concept.js +243 -0
  44. package/dist/mcp/formatters/concept.js.map +1 -0
  45. package/dist/mcp/formatters/document.d.ts +25 -0
  46. package/dist/mcp/formatters/document.d.ts.map +1 -0
  47. package/dist/mcp/formatters/document.js +178 -0
  48. package/dist/mcp/formatters/document.js.map +1 -0
  49. package/dist/mcp/formatters/epistemic.d.ts +16 -0
  50. package/dist/mcp/formatters/epistemic.d.ts.map +1 -0
  51. package/dist/mcp/formatters/epistemic.js +269 -0
  52. package/dist/mcp/formatters/epistemic.js.map +1 -0
  53. package/dist/mcp/formatters/graph.d.ts +63 -0
  54. package/dist/mcp/formatters/graph.d.ts.map +1 -0
  55. package/dist/mcp/formatters/graph.js +220 -0
  56. package/dist/mcp/formatters/graph.js.map +1 -0
  57. package/dist/mcp/formatters/index.d.ts +18 -0
  58. package/dist/mcp/formatters/index.d.ts.map +1 -0
  59. package/dist/mcp/formatters/index.js +63 -0
  60. package/dist/mcp/formatters/index.js.map +1 -0
  61. package/dist/mcp/formatters/ingest.d.ts +16 -0
  62. package/dist/mcp/formatters/ingest.d.ts.map +1 -0
  63. package/dist/mcp/formatters/ingest.js +169 -0
  64. package/dist/mcp/formatters/ingest.js.map +1 -0
  65. package/dist/mcp/formatters/job.d.ts +13 -0
  66. package/dist/mcp/formatters/job.d.ts.map +1 -0
  67. package/dist/mcp/formatters/job.js +204 -0
  68. package/dist/mcp/formatters/job.js.map +1 -0
  69. package/dist/mcp/formatters/source.d.ts +19 -0
  70. package/dist/mcp/formatters/source.d.ts.map +1 -0
  71. package/dist/mcp/formatters/source.js +182 -0
  72. package/dist/mcp/formatters/source.js.map +1 -0
  73. package/dist/mcp/formatters/system.d.ts +10 -0
  74. package/dist/mcp/formatters/system.d.ts.map +1 -0
  75. package/dist/mcp/formatters/system.js +152 -0
  76. package/dist/mcp/formatters/system.js.map +1 -0
  77. package/dist/mcp/formatters/utils.d.ts +17 -0
  78. package/dist/mcp/formatters/utils.d.ts.map +1 -0
  79. package/dist/mcp/formatters/utils.js +55 -0
  80. package/dist/mcp/formatters/utils.js.map +1 -0
  81. package/dist/mcp/graph-operations.d.ts +242 -0
  82. package/dist/mcp/graph-operations.d.ts.map +1 -0
  83. package/dist/mcp/graph-operations.js +532 -0
  84. package/dist/mcp/graph-operations.js.map +1 -0
  85. package/dist/mcp-server.js +465 -33
  86. package/dist/mcp-server.js.map +1 -1
  87. package/dist/types/index.d.ts +153 -0
  88. package/dist/types/index.d.ts.map +1 -1
  89. package/dist/version.d.ts +3 -3
  90. package/dist/version.js +3 -3
  91. package/dist/version.js.map +1 -1
  92. package/package.json +1 -1
  93. package/dist/mcp/formatters.d.ts +0 -100
  94. package/dist/mcp/formatters.d.ts.map +0 -1
  95. package/dist/mcp/formatters.js +0 -1411
  96. package/dist/mcp/formatters.js.map +0 -1
@@ -39,6 +39,9 @@ var __importStar = (this && this.__importStar) || (function () {
39
39
  return result;
40
40
  };
41
41
  })();
42
+ var __importDefault = (this && this.__importDefault) || function (mod) {
43
+ return (mod && mod.__esModule) ? mod : { "default": mod };
44
+ };
42
45
  Object.defineProperty(exports, "__esModule", { value: true });
43
46
  const index_js_1 = require("@modelcontextprotocol/sdk/server/index.js");
44
47
  const stdio_js_1 = require("@modelcontextprotocol/sdk/server/stdio.js");
@@ -46,9 +49,11 @@ const types_js_1 = require("@modelcontextprotocol/sdk/types.js");
46
49
  const client_js_1 = require("./api/client.js");
47
50
  const auth_client_js_1 = require("./lib/auth/auth-client.js");
48
51
  const mcp_allowlist_js_1 = require("./lib/mcp-allowlist.js");
49
- const formatters_js_1 = require("./mcp/formatters.js");
52
+ const index_js_2 = require("./mcp/formatters/index.js");
53
+ const graph_operations_js_1 = require("./mcp/graph-operations.js");
50
54
  const fs = __importStar(require("fs"));
51
55
  const path = __importStar(require("path"));
56
+ const package_json_1 = __importDefault(require("../package.json"));
52
57
  /**
53
58
  * Default parameters for graph queries (ADR-048 Query Safety)
54
59
  *
@@ -64,7 +69,7 @@ const DEFAULT_MAX_DEPTH = 2; // Related concepts neighborhood depth
64
69
  // Create server instance
65
70
  const server = new index_js_1.Server({
66
71
  name: 'knowledge-graph-server',
67
- version: '0.1.0',
72
+ version: package_json_1.default.version,
68
73
  }, {
69
74
  capabilities: {
70
75
  tools: {},
@@ -403,28 +408,56 @@ PERFORMANCE CRITICAL: For "connect" action, use threshold >= 0.75 to avoid datab
403
408
  },
404
409
  {
405
410
  name: 'job',
406
- description: 'Manage ingestion jobs: get status, list jobs, approve, or cancel. Use action parameter to specify operation.',
411
+ description: 'Manage ingestion jobs: get status, list jobs, approve, cancel, delete, or cleanup. Use action parameter to specify operation.',
407
412
  inputSchema: {
408
413
  type: 'object',
409
414
  properties: {
410
415
  action: {
411
416
  type: 'string',
412
- enum: ['status', 'list', 'approve', 'cancel'],
413
- description: 'Operation: "status" (get job status), "list" (list jobs), "approve" (approve job), "cancel" (cancel job)',
417
+ enum: ['status', 'list', 'approve', 'cancel', 'delete', 'cleanup'],
418
+ description: 'Operation: "status" (get job status), "list" (list jobs), "approve" (approve job), "cancel" (cancel job), "delete" (permanently delete single job), "cleanup" (delete jobs matching filters)',
414
419
  },
415
420
  job_id: {
416
421
  type: 'string',
417
- description: 'Job ID (required for status, approve, cancel)',
422
+ description: 'Job ID (required for status, approve, cancel, delete)',
418
423
  },
419
424
  status: {
420
425
  type: 'string',
421
- description: 'Filter by status for list (pending, awaiting_approval, running, completed, failed)',
426
+ description: 'Filter by status for list/cleanup (pending, awaiting_approval, running, completed, failed)',
422
427
  },
423
428
  limit: {
424
429
  type: 'number',
425
430
  description: 'Max jobs to return for list (default: 50)',
426
431
  default: 50,
427
432
  },
433
+ force: {
434
+ type: 'boolean',
435
+ description: 'Force delete even if job is processing (for delete action)',
436
+ default: false,
437
+ },
438
+ system_only: {
439
+ type: 'boolean',
440
+ description: 'Only delete system/scheduled jobs (for cleanup action)',
441
+ default: false,
442
+ },
443
+ older_than: {
444
+ type: 'string',
445
+ description: 'Delete jobs older than duration: 1h, 24h, 7d, 30d (for cleanup action)',
446
+ },
447
+ job_type: {
448
+ type: 'string',
449
+ description: 'Filter by job type for cleanup (ingestion, epistemic_remeasurement, projection, etc)',
450
+ },
451
+ dry_run: {
452
+ type: 'boolean',
453
+ description: 'Preview what would be deleted without deleting (for cleanup, default: true)',
454
+ default: true,
455
+ },
456
+ confirm: {
457
+ type: 'boolean',
458
+ description: 'Confirm deletion - set to true to actually delete (for cleanup action)',
459
+ default: false,
460
+ },
428
461
  },
429
462
  required: ['action'],
430
463
  },
@@ -745,6 +778,193 @@ Use search tool with type="documents" to find documents semantically.`,
745
778
  required: ['action'],
746
779
  },
747
780
  },
781
+ // ADR-089 Phase 3a: Graph CRUD Tool
782
+ {
783
+ name: 'graph',
784
+ description: `Create, edit, delete, and list concepts and edges in the knowledge graph (ADR-089).
785
+
786
+ This tool provides deterministic graph editing without going through the LLM ingest pipeline.
787
+ Use for manual curation, agent-driven knowledge building, and precise graph manipulation.
788
+
789
+ **Actions:**
790
+ - "create": Create a new concept or edge
791
+ - "edit": Update an existing concept or edge
792
+ - "delete": Delete a concept or edge
793
+ - "list": List concepts or edges with filters
794
+
795
+ **Entity Types:**
796
+ - "concept": Knowledge graph concepts (nodes)
797
+ - "edge": Relationships between concepts
798
+
799
+ **Matching Modes (for create):**
800
+ - "auto": Link to existing if match found, create if not (default)
801
+ - "force_create": Always create new, even if similar exists
802
+ - "match_only": Only link to existing, error if no match
803
+
804
+ **Semantic Resolution:**
805
+ - Use \`from_label\`/\`to_label\` to reference concepts by name instead of ID
806
+ - Resolution uses vector similarity (85% threshold) to find matching concepts
807
+
808
+ **Examples:**
809
+ - Create concept: \`{action: "create", entity: "concept", label: "CAP Theorem", ontology: "distributed-systems"}\`
810
+ - Create edge: \`{action: "create", entity: "edge", from_label: "CAP Theorem", to_label: "Partition Tolerance", relationship_type: "REQUIRES"}\`
811
+ - List concepts: \`{action: "list", entity: "concept", ontology: "distributed-systems"}\`
812
+ - Delete concept: \`{action: "delete", entity: "concept", concept_id: "c_abc123"}\`
813
+
814
+ **Queue Mode** (batch multiple operations in one call):
815
+ \`\`\`json
816
+ {
817
+ "action": "queue",
818
+ "operations": [
819
+ {"op": "create", "entity": "concept", "label": "A", "ontology": "test"},
820
+ {"op": "create", "entity": "concept", "label": "B", "ontology": "test"},
821
+ {"op": "create", "entity": "edge", "from_label": "A", "to_label": "B", "relationship_type": "IMPLIES"}
822
+ ]
823
+ }
824
+ \`\`\`
825
+ Queue executes sequentially, stops on first error (unless continue_on_error=true). Max 20 operations.`,
826
+ inputSchema: {
827
+ type: 'object',
828
+ properties: {
829
+ action: {
830
+ type: 'string',
831
+ enum: ['create', 'edit', 'delete', 'list', 'queue'],
832
+ description: 'Operation to perform. Use "queue" to batch multiple operations.',
833
+ },
834
+ entity: {
835
+ type: 'string',
836
+ enum: ['concept', 'edge'],
837
+ description: 'Entity type (required for create/edit/delete/list, not for queue)',
838
+ },
839
+ // Queue fields
840
+ operations: {
841
+ type: 'array',
842
+ items: {
843
+ type: 'object',
844
+ properties: {
845
+ op: { type: 'string', enum: ['create', 'edit', 'delete', 'list'], description: 'Operation' },
846
+ entity: { type: 'string', enum: ['concept', 'edge'] },
847
+ label: { type: 'string' },
848
+ ontology: { type: 'string' },
849
+ description: { type: 'string' },
850
+ search_terms: { type: 'array', items: { type: 'string' } },
851
+ matching_mode: { type: 'string', enum: ['auto', 'force_create', 'match_only'] },
852
+ concept_id: { type: 'string' },
853
+ from_concept_id: { type: 'string' },
854
+ to_concept_id: { type: 'string' },
855
+ from_label: { type: 'string' },
856
+ to_label: { type: 'string' },
857
+ relationship_type: { type: 'string' },
858
+ category: { type: 'string' },
859
+ confidence: { type: 'number' },
860
+ limit: { type: 'number' },
861
+ offset: { type: 'number' },
862
+ cascade: { type: 'boolean' },
863
+ },
864
+ required: ['op', 'entity'],
865
+ },
866
+ description: 'Array of operations for queue action (max 20). Each has op, entity, and action-specific fields.',
867
+ },
868
+ continue_on_error: {
869
+ type: 'boolean',
870
+ description: 'For queue: continue executing after errors (default: false, stop on first error)',
871
+ default: false,
872
+ },
873
+ // Concept fields
874
+ label: {
875
+ type: 'string',
876
+ description: 'Concept label (required for create concept)',
877
+ },
878
+ ontology: {
879
+ type: 'string',
880
+ description: 'Ontology/namespace (required for create concept, optional filter for list)',
881
+ },
882
+ description: {
883
+ type: 'string',
884
+ description: 'Concept description (optional)',
885
+ },
886
+ search_terms: {
887
+ type: 'array',
888
+ items: { type: 'string' },
889
+ description: 'Alternative search terms for the concept',
890
+ },
891
+ matching_mode: {
892
+ type: 'string',
893
+ enum: ['auto', 'force_create', 'match_only'],
894
+ description: 'How to handle similar existing concepts (default: auto)',
895
+ default: 'auto',
896
+ },
897
+ // Edge fields
898
+ from_concept_id: {
899
+ type: 'string',
900
+ description: 'Source concept ID (for edge create/delete)',
901
+ },
902
+ to_concept_id: {
903
+ type: 'string',
904
+ description: 'Target concept ID (for edge create/delete)',
905
+ },
906
+ from_label: {
907
+ type: 'string',
908
+ description: 'Source concept by label (semantic resolution)',
909
+ },
910
+ to_label: {
911
+ type: 'string',
912
+ description: 'Target concept by label (semantic resolution)',
913
+ },
914
+ relationship_type: {
915
+ type: 'string',
916
+ description: 'Edge relationship type (e.g., IMPLIES, SUPPORTS, CONTRADICTS)',
917
+ },
918
+ category: {
919
+ type: 'string',
920
+ enum: ['logical_truth', 'empirical_claim', 'value_judgment', 'conceptual', 'temporal_sequence', 'causal', 'other'],
921
+ description: 'Semantic category of the relationship (default: logical_truth)',
922
+ default: 'logical_truth',
923
+ },
924
+ confidence: {
925
+ type: 'number',
926
+ description: 'Edge confidence 0.0-1.0 (default: 1.0)',
927
+ default: 1.0,
928
+ },
929
+ // Identifiers for edit/delete
930
+ concept_id: {
931
+ type: 'string',
932
+ description: 'Concept ID (for edit/delete concept)',
933
+ },
934
+ // List filters
935
+ label_contains: {
936
+ type: 'string',
937
+ description: 'Filter concepts by label substring (for list)',
938
+ },
939
+ creation_method: {
940
+ type: 'string',
941
+ description: 'Filter by creation method (for list)',
942
+ },
943
+ source: {
944
+ type: 'string',
945
+ description: 'Filter edges by source (for list)',
946
+ },
947
+ // Pagination
948
+ limit: {
949
+ type: 'number',
950
+ description: 'Max results to return (default: 20)',
951
+ default: 20,
952
+ },
953
+ offset: {
954
+ type: 'number',
955
+ description: 'Number to skip for pagination (default: 0)',
956
+ default: 0,
957
+ },
958
+ // Delete option
959
+ cascade: {
960
+ type: 'boolean',
961
+ description: 'For concept delete: also delete orphaned synthetic sources (default: false)',
962
+ default: false,
963
+ },
964
+ },
965
+ required: ['action'],
966
+ },
967
+ },
748
968
  ],
749
969
  };
750
970
  });
@@ -802,7 +1022,7 @@ server.setRequestHandler(types_js_1.ReadResourceRequestSchema, async (request) =
802
1022
  contents: [{
803
1023
  uri,
804
1024
  mimeType: 'text/plain',
805
- text: (0, formatters_js_1.formatDatabaseStats)(result)
1025
+ text: (0, index_js_2.formatDatabaseStats)(result)
806
1026
  }]
807
1027
  };
808
1028
  }
@@ -812,7 +1032,7 @@ server.setRequestHandler(types_js_1.ReadResourceRequestSchema, async (request) =
812
1032
  contents: [{
813
1033
  uri,
814
1034
  mimeType: 'text/plain',
815
- text: (0, formatters_js_1.formatDatabaseInfo)(result)
1035
+ text: (0, index_js_2.formatDatabaseInfo)(result)
816
1036
  }]
817
1037
  };
818
1038
  }
@@ -822,7 +1042,7 @@ server.setRequestHandler(types_js_1.ReadResourceRequestSchema, async (request) =
822
1042
  contents: [{
823
1043
  uri,
824
1044
  mimeType: 'text/plain',
825
- text: (0, formatters_js_1.formatDatabaseHealth)(result)
1045
+ text: (0, index_js_2.formatDatabaseHealth)(result)
826
1046
  }]
827
1047
  };
828
1048
  }
@@ -832,7 +1052,7 @@ server.setRequestHandler(types_js_1.ReadResourceRequestSchema, async (request) =
832
1052
  contents: [{
833
1053
  uri,
834
1054
  mimeType: 'text/plain',
835
- text: (0, formatters_js_1.formatSystemStatus)(result)
1055
+ text: (0, index_js_2.formatSystemStatus)(result)
836
1056
  }]
837
1057
  };
838
1058
  }
@@ -842,7 +1062,7 @@ server.setRequestHandler(types_js_1.ReadResourceRequestSchema, async (request) =
842
1062
  contents: [{
843
1063
  uri,
844
1064
  mimeType: 'text/plain',
845
- text: (0, formatters_js_1.formatApiHealth)(result)
1065
+ text: (0, index_js_2.formatApiHealth)(result)
846
1066
  }]
847
1067
  };
848
1068
  }
@@ -854,7 +1074,7 @@ server.setRequestHandler(types_js_1.ReadResourceRequestSchema, async (request) =
854
1074
  contents: [{
855
1075
  uri,
856
1076
  mimeType: 'text/plain',
857
- text: (0, formatters_js_1.formatMcpAllowedPaths)({
1077
+ text: (0, index_js_2.formatMcpAllowedPaths)({
858
1078
  configured: false,
859
1079
  message: 'Allowlist not initialized. Run: kg mcp-config init-allowlist',
860
1080
  hint: 'Initialize with default safe patterns for .md, .txt, .pdf, .png, .jpg files'
@@ -866,7 +1086,7 @@ server.setRequestHandler(types_js_1.ReadResourceRequestSchema, async (request) =
866
1086
  contents: [{
867
1087
  uri,
868
1088
  mimeType: 'text/plain',
869
- text: (0, formatters_js_1.formatMcpAllowedPaths)({
1089
+ text: (0, index_js_2.formatMcpAllowedPaths)({
870
1090
  configured: true,
871
1091
  version: config.version,
872
1092
  allowed_directories: config.allowed_directories,
@@ -944,7 +1164,7 @@ server.setRequestHandler(types_js_1.CallToolRequestSchema, async (request) => {
944
1164
  include_concepts: true,
945
1165
  include_full_text: true,
946
1166
  });
947
- const formattedText = (0, formatters_js_1.formatSourceSearchResults)(result);
1167
+ const formattedText = (0, index_js_2.formatSourceSearchResults)(result);
948
1168
  return {
949
1169
  content: [{ type: 'text', text: formattedText }],
950
1170
  };
@@ -959,7 +1179,7 @@ server.setRequestHandler(types_js_1.CallToolRequestSchema, async (request) => {
959
1179
  });
960
1180
  // Add query to result for formatting
961
1181
  const resultWithQuery = { ...result, query };
962
- const formattedText = (0, formatters_js_1.formatDocumentSearchResults)(resultWithQuery);
1182
+ const formattedText = (0, index_js_2.formatDocumentSearchResults)(resultWithQuery);
963
1183
  return {
964
1184
  content: [{ type: 'text', text: formattedText }],
965
1185
  };
@@ -976,7 +1196,7 @@ server.setRequestHandler(types_js_1.CallToolRequestSchema, async (request) => {
976
1196
  include_diversity: true,
977
1197
  diversity_max_hops: 2,
978
1198
  });
979
- const formattedText = (0, formatters_js_1.formatSearchResults)(result);
1199
+ const formattedText = (0, index_js_2.formatSearchResults)(result);
980
1200
  return {
981
1201
  content: [{ type: 'text', text: formattedText }],
982
1202
  };
@@ -991,7 +1211,7 @@ server.setRequestHandler(types_js_1.CallToolRequestSchema, async (request) => {
991
1211
  const diversityMaxHops = toolArgs.diversity_max_hops || 2;
992
1212
  const truncateEvidence = toolArgs.truncate_evidence !== false; // Default true
993
1213
  const result = await client.getConceptDetails(toolArgs.concept_id, includeGrounding, includeDiversity, diversityMaxHops);
994
- const formattedText = (0, formatters_js_1.formatConceptDetails)(result, truncateEvidence);
1214
+ const formattedText = (0, index_js_2.formatConceptDetails)(result, truncateEvidence);
995
1215
  return {
996
1216
  content: [{ type: 'text', text: formattedText }],
997
1217
  };
@@ -1005,7 +1225,7 @@ server.setRequestHandler(types_js_1.CallToolRequestSchema, async (request) => {
1005
1225
  include_epistemic_status: toolArgs.include_epistemic_status,
1006
1226
  exclude_epistemic_status: toolArgs.exclude_epistemic_status,
1007
1227
  });
1008
- const formattedText = (0, formatters_js_1.formatRelatedConcepts)(result);
1228
+ const formattedText = (0, index_js_2.formatRelatedConcepts)(result);
1009
1229
  return {
1010
1230
  content: [{ type: 'text', text: formattedText }],
1011
1231
  };
@@ -1041,7 +1261,7 @@ server.setRequestHandler(types_js_1.CallToolRequestSchema, async (request) => {
1041
1261
  include_epistemic_status: toolArgs.include_epistemic_status,
1042
1262
  exclude_epistemic_status: toolArgs.exclude_epistemic_status,
1043
1263
  });
1044
- const formattedText = (0, formatters_js_1.formatConnectionPaths)(result);
1264
+ const formattedText = (0, index_js_2.formatConnectionPaths)(result);
1045
1265
  return {
1046
1266
  content: [{ type: 'text', text: formattedText }],
1047
1267
  };
@@ -1087,14 +1307,14 @@ server.setRequestHandler(types_js_1.CallToolRequestSchema, async (request) => {
1087
1307
  switch (action) {
1088
1308
  case 'status': {
1089
1309
  const result = await client.getJobStatus(toolArgs.job_id);
1090
- const formattedText = (0, formatters_js_1.formatJobStatus)(result);
1310
+ const formattedText = (0, index_js_2.formatJobStatus)(result);
1091
1311
  return {
1092
1312
  content: [{ type: 'text', text: formattedText }],
1093
1313
  };
1094
1314
  }
1095
1315
  case 'list': {
1096
1316
  const result = await client.listJobs(toolArgs.status, undefined, toolArgs.limit || 50);
1097
- const formattedText = (0, formatters_js_1.formatJobList)(result);
1317
+ const formattedText = (0, index_js_2.formatJobList)(result);
1098
1318
  return {
1099
1319
  content: [{ type: 'text', text: formattedText }],
1100
1320
  };
@@ -1111,6 +1331,49 @@ server.setRequestHandler(types_js_1.CallToolRequestSchema, async (request) => {
1111
1331
  content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
1112
1332
  };
1113
1333
  }
1334
+ case 'delete': {
1335
+ const result = await client.deleteJob(toolArgs.job_id, {
1336
+ purge: true,
1337
+ force: toolArgs.force || false
1338
+ });
1339
+ return {
1340
+ content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
1341
+ };
1342
+ }
1343
+ case 'cleanup': {
1344
+ const result = await client.deleteJobs({
1345
+ dryRun: toolArgs.dry_run !== false && !toolArgs.confirm,
1346
+ confirm: toolArgs.confirm || false,
1347
+ status: toolArgs.status,
1348
+ system: toolArgs.system_only || false,
1349
+ olderThan: toolArgs.older_than,
1350
+ jobType: toolArgs.job_type
1351
+ });
1352
+ let output = '';
1353
+ if (result.dry_run) {
1354
+ output = `## Cleanup Preview (dry run)\n\n`;
1355
+ output += `Jobs matching filters: ${result.jobs_to_delete}\n\n`;
1356
+ if (result.jobs && result.jobs.length > 0) {
1357
+ output += `| Job ID | Type | Status | Created |\n`;
1358
+ output += `|--------|------|--------|--------|\n`;
1359
+ for (const job of result.jobs.slice(0, 20)) {
1360
+ output += `| ${job.job_id.substring(0, 16)} | ${job.job_type} | ${job.status} | ${job.created_at} |\n`;
1361
+ }
1362
+ if (result.jobs.length > 20) {
1363
+ output += `\n... and ${result.jobs.length - 20} more\n`;
1364
+ }
1365
+ }
1366
+ output += `\nTo delete, use confirm: true`;
1367
+ }
1368
+ else {
1369
+ output = `## Cleanup Complete\n\n`;
1370
+ output += `Jobs deleted: ${result.jobs_deleted}\n`;
1371
+ output += `\n${result.message}`;
1372
+ }
1373
+ return {
1374
+ content: [{ type: 'text', text: output }],
1375
+ };
1376
+ }
1114
1377
  default:
1115
1378
  throw new Error(`Unknown job action: ${action}`);
1116
1379
  }
@@ -1197,7 +1460,7 @@ server.setRequestHandler(types_js_1.CallToolRequestSchema, async (request) => {
1197
1460
  content: [
1198
1461
  {
1199
1462
  type: 'text',
1200
- text: (0, formatters_js_1.formatInspectFileResult)(result),
1463
+ text: (0, index_js_2.formatInspectFileResult)(result),
1201
1464
  },
1202
1465
  ],
1203
1466
  };
@@ -1293,7 +1556,7 @@ server.setRequestHandler(types_js_1.CallToolRequestSchema, async (request) => {
1293
1556
  content: [
1294
1557
  {
1295
1558
  type: 'text',
1296
- text: (0, formatters_js_1.formatIngestFileResult)(result),
1559
+ text: (0, index_js_2.formatIngestFileResult)(result),
1297
1560
  },
1298
1561
  ],
1299
1562
  };
@@ -1376,7 +1639,7 @@ server.setRequestHandler(types_js_1.CallToolRequestSchema, async (request) => {
1376
1639
  content: [
1377
1640
  {
1378
1641
  type: 'text',
1379
- text: (0, formatters_js_1.formatIngestDirectoryResult)(result),
1642
+ text: (0, index_js_2.formatIngestDirectoryResult)(result),
1380
1643
  },
1381
1644
  ],
1382
1645
  };
@@ -1445,7 +1708,7 @@ server.setRequestHandler(types_js_1.CallToolRequestSchema, async (request) => {
1445
1708
  case 'list': {
1446
1709
  const statusFilter = toolArgs.status_filter;
1447
1710
  const result = await client.listEpistemicStatus(statusFilter);
1448
- const output = (0, formatters_js_1.formatEpistemicStatusList)(result);
1711
+ const output = (0, index_js_2.formatEpistemicStatusList)(result);
1449
1712
  return {
1450
1713
  content: [{ type: 'text', text: output }],
1451
1714
  };
@@ -1456,7 +1719,7 @@ server.setRequestHandler(types_js_1.CallToolRequestSchema, async (request) => {
1456
1719
  throw new Error('relationship_type is required for show action');
1457
1720
  }
1458
1721
  const result = await client.getEpistemicStatus(relationshipType);
1459
- const output = (0, formatters_js_1.formatEpistemicStatusDetails)(result);
1722
+ const output = (0, index_js_2.formatEpistemicStatusDetails)(result);
1460
1723
  return {
1461
1724
  content: [{ type: 'text', text: output }],
1462
1725
  };
@@ -1470,7 +1733,7 @@ server.setRequestHandler(types_js_1.CallToolRequestSchema, async (request) => {
1470
1733
  store: store,
1471
1734
  verbose: verbose,
1472
1735
  });
1473
- const output = (0, formatters_js_1.formatEpistemicStatusMeasurement)(result);
1736
+ const output = (0, index_js_2.formatEpistemicStatusMeasurement)(result);
1474
1737
  return {
1475
1738
  content: [{ type: 'text', text: output }],
1476
1739
  };
@@ -1488,7 +1751,7 @@ server.setRequestHandler(types_js_1.CallToolRequestSchema, async (request) => {
1488
1751
  max_candidates: toolArgs.max_candidates || 20,
1489
1752
  max_hops: toolArgs.max_hops || 2,
1490
1753
  });
1491
- const formattedText = (0, formatters_js_1.formatPolarityAxisResults)(result);
1754
+ const formattedText = (0, index_js_2.formatPolarityAxisResults)(result);
1492
1755
  return {
1493
1756
  content: [{ type: 'text', text: formattedText }],
1494
1757
  };
@@ -1592,7 +1855,7 @@ server.setRequestHandler(types_js_1.CallToolRequestSchema, async (request) => {
1592
1855
  limit: toolArgs.limit || 50,
1593
1856
  offset: toolArgs.offset || 0,
1594
1857
  });
1595
- const formattedText = (0, formatters_js_1.formatDocumentList)(result);
1858
+ const formattedText = (0, index_js_2.formatDocumentList)(result);
1596
1859
  return {
1597
1860
  content: [{ type: 'text', text: formattedText }],
1598
1861
  };
@@ -1603,7 +1866,7 @@ server.setRequestHandler(types_js_1.CallToolRequestSchema, async (request) => {
1603
1866
  throw new Error('document_id is required for show action');
1604
1867
  }
1605
1868
  const result = await client.getDocumentContent(documentId);
1606
- const formattedText = (0, formatters_js_1.formatDocumentContent)(result);
1869
+ const formattedText = (0, index_js_2.formatDocumentContent)(result);
1607
1870
  return {
1608
1871
  content: [{ type: 'text', text: formattedText }],
1609
1872
  };
@@ -1632,13 +1895,13 @@ server.setRequestHandler(types_js_1.CallToolRequestSchema, async (request) => {
1632
1895
  });
1633
1896
  }
1634
1897
  }
1635
- const formattedText = (0, formatters_js_1.formatDocumentConceptsDetailed)(result, conceptDetails);
1898
+ const formattedText = (0, index_js_2.formatDocumentConceptsDetailed)(result, conceptDetails);
1636
1899
  return {
1637
1900
  content: [{ type: 'text', text: formattedText }],
1638
1901
  };
1639
1902
  }
1640
1903
  else {
1641
- const formattedText = (0, formatters_js_1.formatDocumentConcepts)(result);
1904
+ const formattedText = (0, index_js_2.formatDocumentConcepts)(result);
1642
1905
  return {
1643
1906
  content: [{ type: 'text', text: formattedText }],
1644
1907
  };
@@ -1648,6 +1911,175 @@ server.setRequestHandler(types_js_1.CallToolRequestSchema, async (request) => {
1648
1911
  throw new Error(`Unknown document action: ${action}`);
1649
1912
  }
1650
1913
  }
1914
+ // ADR-089 Phase 3a: Graph CRUD Tool Handler (Refactored)
1915
+ case 'graph': {
1916
+ const action = toolArgs.action;
1917
+ const entity = toolArgs.entity;
1918
+ // Entity required for all actions except queue
1919
+ if (action !== 'queue' && !entity) {
1920
+ throw new Error('entity is required (concept or edge)');
1921
+ }
1922
+ // Create executor instance for this request
1923
+ const executor = new graph_operations_js_1.GraphOperationExecutor(client);
1924
+ switch (action) {
1925
+ case 'create': {
1926
+ if (entity === 'concept') {
1927
+ const result = await executor.createConcept({
1928
+ label: toolArgs.label,
1929
+ ontology: toolArgs.ontology,
1930
+ description: toolArgs.description,
1931
+ search_terms: toolArgs.search_terms,
1932
+ matching_mode: toolArgs.matching_mode,
1933
+ });
1934
+ if (!result.success)
1935
+ throw new Error(result.error);
1936
+ return {
1937
+ content: [{ type: 'text', text: (0, index_js_2.formatGraphConceptResult)(result.data, 'create') }],
1938
+ };
1939
+ }
1940
+ else if (entity === 'edge') {
1941
+ const result = await executor.createEdge({
1942
+ from_concept_id: toolArgs.from_concept_id,
1943
+ from_label: toolArgs.from_label,
1944
+ to_concept_id: toolArgs.to_concept_id,
1945
+ to_label: toolArgs.to_label,
1946
+ relationship_type: toolArgs.relationship_type,
1947
+ category: toolArgs.category,
1948
+ confidence: toolArgs.confidence,
1949
+ });
1950
+ if (!result.success)
1951
+ throw new Error(result.error);
1952
+ return {
1953
+ content: [{ type: 'text', text: (0, index_js_2.formatGraphEdgeResult)(result.data, 'create') }],
1954
+ };
1955
+ }
1956
+ else {
1957
+ throw new Error(`Unknown entity type: ${entity}`);
1958
+ }
1959
+ }
1960
+ case 'list': {
1961
+ if (entity === 'concept') {
1962
+ const result = await executor.listConcepts({
1963
+ ontology: toolArgs.ontology,
1964
+ label_contains: toolArgs.label_contains,
1965
+ creation_method: toolArgs.creation_method,
1966
+ offset: toolArgs.offset,
1967
+ limit: toolArgs.limit,
1968
+ });
1969
+ if (!result.success)
1970
+ throw new Error(result.error);
1971
+ return {
1972
+ content: [{ type: 'text', text: (0, index_js_2.formatGraphConceptList)(result.data) }],
1973
+ };
1974
+ }
1975
+ else if (entity === 'edge') {
1976
+ const result = await executor.listEdges({
1977
+ from_concept_id: toolArgs.from_concept_id,
1978
+ from_label: toolArgs.from_label,
1979
+ to_concept_id: toolArgs.to_concept_id,
1980
+ to_label: toolArgs.to_label,
1981
+ relationship_type: toolArgs.relationship_type,
1982
+ category: toolArgs.category,
1983
+ source: toolArgs.source,
1984
+ offset: toolArgs.offset,
1985
+ limit: toolArgs.limit,
1986
+ });
1987
+ if (!result.success)
1988
+ throw new Error(result.error);
1989
+ return {
1990
+ content: [{ type: 'text', text: (0, index_js_2.formatGraphEdgeList)(result.data) }],
1991
+ };
1992
+ }
1993
+ else {
1994
+ throw new Error(`Unknown entity type: ${entity}`);
1995
+ }
1996
+ }
1997
+ case 'edit': {
1998
+ if (entity === 'concept') {
1999
+ const result = await executor.editConcept({
2000
+ concept_id: toolArgs.concept_id,
2001
+ label: toolArgs.label,
2002
+ description: toolArgs.description,
2003
+ search_terms: toolArgs.search_terms,
2004
+ });
2005
+ if (!result.success)
2006
+ throw new Error(result.error);
2007
+ return {
2008
+ content: [{ type: 'text', text: (0, index_js_2.formatGraphConceptResult)(result.data, 'edit') }],
2009
+ };
2010
+ }
2011
+ else if (entity === 'edge') {
2012
+ const result = await executor.editEdge({
2013
+ from_concept_id: toolArgs.from_concept_id,
2014
+ from_label: toolArgs.from_label,
2015
+ to_concept_id: toolArgs.to_concept_id,
2016
+ to_label: toolArgs.to_label,
2017
+ relationship_type: toolArgs.relationship_type,
2018
+ confidence: toolArgs.confidence,
2019
+ category: toolArgs.category,
2020
+ });
2021
+ if (!result.success)
2022
+ throw new Error(result.error);
2023
+ return {
2024
+ content: [{ type: 'text', text: (0, index_js_2.formatGraphEdgeResult)(result.data, 'edit') }],
2025
+ };
2026
+ }
2027
+ else {
2028
+ throw new Error(`Unknown entity type: ${entity}`);
2029
+ }
2030
+ }
2031
+ case 'delete': {
2032
+ if (entity === 'concept') {
2033
+ const result = await executor.deleteConcept({
2034
+ concept_id: toolArgs.concept_id,
2035
+ cascade: toolArgs.cascade,
2036
+ });
2037
+ if (!result.success)
2038
+ throw new Error(result.error);
2039
+ return {
2040
+ content: [{ type: 'text', text: (0, index_js_2.formatGraphConceptResult)(result.data, 'delete') }],
2041
+ };
2042
+ }
2043
+ else if (entity === 'edge') {
2044
+ const result = await executor.deleteEdge({
2045
+ from_concept_id: toolArgs.from_concept_id,
2046
+ from_label: toolArgs.from_label,
2047
+ to_concept_id: toolArgs.to_concept_id,
2048
+ to_label: toolArgs.to_label,
2049
+ relationship_type: toolArgs.relationship_type,
2050
+ });
2051
+ if (!result.success)
2052
+ throw new Error(result.error);
2053
+ return {
2054
+ content: [{ type: 'text', text: (0, index_js_2.formatGraphEdgeResult)(result.data, 'delete') }],
2055
+ };
2056
+ }
2057
+ else {
2058
+ throw new Error(`Unknown entity type: ${entity}`);
2059
+ }
2060
+ }
2061
+ case 'queue': {
2062
+ const operations = toolArgs.operations;
2063
+ const continueOnError = toolArgs.continue_on_error === true;
2064
+ if (!operations || !Array.isArray(operations)) {
2065
+ throw new Error('operations array is required for queue action');
2066
+ }
2067
+ if (operations.length === 0) {
2068
+ throw new Error('operations array cannot be empty');
2069
+ }
2070
+ if (operations.length > 20) {
2071
+ throw new Error(`Queue too large: ${operations.length} operations (max 20)`);
2072
+ }
2073
+ const queueResult = await executor.executeQueue(operations, continueOnError);
2074
+ const formattedOutput = (0, index_js_2.formatGraphQueueResult)(queueResult, operations.length);
2075
+ return {
2076
+ content: [{ type: 'text', text: formattedOutput }],
2077
+ };
2078
+ }
2079
+ default:
2080
+ throw new Error(`Unknown graph action: ${action}. Use: create, edit, delete, list, or queue`);
2081
+ }
2082
+ }
1651
2083
  default:
1652
2084
  throw new Error(`Unknown tool: ${name}`);
1653
2085
  }