@stackmemoryai/stackmemory 1.2.4 → 1.2.7

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/README.md CHANGED
@@ -5,19 +5,26 @@
5
5
  [![Coverage](https://codecov.io/gh/stackmemoryai/stackmemory/branch/main/graph/badge.svg)](https://codecov.io/gh/stackmemoryai/stackmemory)
6
6
  [![npm version](https://img.shields.io/npm/v/@stackmemoryai/stackmemory)](https://www.npmjs.com/package/@stackmemoryai/stackmemory)
7
7
 
8
- Lossless, project-scoped memory for AI coding tools.
8
+ Lossless, project-scoped memory for AI coding tools. **[Website](https://stackmemoryai.github.io/stackmemory/)** | **[MCP Tools](https://stackmemoryai.github.io/stackmemory/tools.html)** | **[Getting Started](./docs/GETTING_STARTED.md)**
9
+
10
+ <p align="center">
11
+ <img src="site/demo.svg" alt="StackMemory setup demo" width="560">
12
+ </p>
9
13
 
10
14
  StackMemory is a **production-ready memory runtime** for AI coding tools that preserves full project context across sessions:
11
15
 
12
16
  - **Zero-config setup** — `stackmemory init` just works
13
- - **25 MCP tools** for Claude Code integration
14
- - **Full Linear integration** with bidirectional sync
17
+ - **32 MCP tools** for Claude Code integration (context, tasks, Linear, traces, discovery, cord, team)
18
+ - **FTS5 full-text search** with BM25 scoring and hybrid retrieval
19
+ - **Full Linear integration** with bidirectional sync and OAuth/API key support
15
20
  - **Context persistence** that survives `/clear` operations
16
21
  - **Hierarchical frame organization** (nested call stack model)
22
+ - **Multi-wrapper support** — `claude-sm`, `codex-sm`, `opencode-sm` with auto context loading
17
23
  - **Skills system** with `/spec` and `/linear-run` for Claude Code
18
24
  - **Automatic hooks** for task tracking, Linear sync, and spec progress
19
25
  - **Memory monitor daemon** with automatic capture/clear on RAM pressure
20
- - **652 tests passing** with comprehensive coverage
26
+ - **Auto-save service** for periodic context persistence
27
+ - **Comprehensive test coverage** across all core modules
21
28
 
22
29
  Instead of a linear chat log, StackMemory organizes memory as a **call stack** of scoped work (frames), with intelligent LLM-driven retrieval and team collaboration features.
23
30
 
@@ -50,13 +57,14 @@ Tools forget decisions and constraints between sessions. StackMemory makes conte
50
57
 
51
58
  ## Features
52
59
 
53
- - **MCP tools** for Claude Code: 25 tools across context, tasks, Linear, traces, and discovery
60
+ - **MCP tools** for Claude Code: 36 tools across context, tasks, Linear, traces, discovery, cord, and team
61
+ - **FTS5 search**: full-text search with BM25 scoring, hybrid retrieval, and smart thresholds
54
62
  - **Skills**: `/spec` (iterative spec generation), `/linear-run` (task execution via RLM)
55
- - **Hooks**: automatic context save, task tracking, Linear sync, PROMPT_PLAN updates
63
+ - **Hooks**: automatic context save, task tracking, Linear sync, PROMPT_PLAN updates, cord tracing
56
64
  - **Prompt Forge**: watches CLAUDE.md and AGENTS.md for prompt optimization (GEPA)
57
65
  - **Safe branches**: worktree isolation with `--worktree` or `-w`
58
66
  - **Persistent context**: frames, anchors, decisions, retrieval
59
- - **Integrations**: Linear, DiffMem, Browser MCP
67
+ - **Integrations**: Linear (API key + OAuth), DiffMem, Browser MCP, log-mcp (log analysis)
60
68
 
61
69
  ---
62
70
 
@@ -347,6 +355,8 @@ See [docs/cli.md](https://github.com/stackmemoryai/stackmemory/blob/main/docs/cl
347
355
 
348
356
  ## Documentation
349
357
 
358
+ - [Getting Started](./docs/GETTING_STARTED.md) — Quick start guide (5 minutes)
359
+ - [MCP Tools Reference](https://stackmemoryai.github.io/stackmemory/tools.html) — All 32 MCP tools
350
360
  - [CLI Reference](./docs/cli.md) — Full command reference
351
361
  - [Setup Guide](./docs/SETUP.md) — Advanced setup options
352
362
  - [Development Guide](./docs/DEVELOPMENT.md) — Contributing and development
@@ -322,6 +322,28 @@ class ClaudeSM {
322
322
  } catch {
323
323
  }
324
324
  }
325
+ getTheoryContent() {
326
+ try {
327
+ let root;
328
+ try {
329
+ root = execSync("git rev-parse --show-toplevel", {
330
+ encoding: "utf-8",
331
+ timeout: 5e3
332
+ }).trim();
333
+ } catch {
334
+ root = process.cwd();
335
+ }
336
+ const theoryPath = path.join(root, "THEORY.MD");
337
+ if (fs.existsSync(theoryPath)) {
338
+ const content = fs.readFileSync(theoryPath, "utf8").trim();
339
+ if (content.length > 0) {
340
+ return content.length > 4e3 ? content.substring(0, 4e3) + "\n\n[...truncated]" : content;
341
+ }
342
+ }
343
+ } catch {
344
+ }
345
+ return null;
346
+ }
325
347
  getHandoffContent() {
326
348
  if (!this.config.contextEnabled) return null;
327
349
  try {
@@ -684,13 +706,20 @@ Session ended (exit ${exitCode ?? 0})`));
684
706
  this.startGEPAWatcher();
685
707
  }
686
708
  let initialInput = "";
687
- const handoffContent = this.getHandoffContent();
688
- if (handoffContent) {
689
- const hasResume = claudeArgs.includes("--continue") || claudeArgs.some((a) => a === "--resume");
690
- if (!hasResume) {
709
+ const hasResume = claudeArgs.includes("--continue") || claudeArgs.some((a) => a === "--resume");
710
+ if (!hasResume) {
711
+ const handoffContent = this.getHandoffContent();
712
+ if (handoffContent) {
691
713
  initialInput = handoffContent;
692
714
  console.log(chalk.gray(" Handoff context ready"));
693
715
  }
716
+ const theoryContent = this.getTheoryContent();
717
+ if (theoryContent) {
718
+ initialInput += (initialInput ? "\n\n---\n\n" : "") + `## Operating Theory (THEORY.MD)
719
+
720
+ ${theoryContent}`;
721
+ console.log(chalk.gray(" Theory context loaded"));
722
+ }
694
723
  }
695
724
  console.log();
696
725
  if (this.config.useSweep) {
@@ -6,7 +6,10 @@ const __dirname = __pathDirname(__filename);
6
6
  import { spawn } from "child_process";
7
7
  import * as path from "path";
8
8
  const codexSmPath = path.join(__dirname, "codex-sm.js");
9
- const args = ["--dangerously-skip-permissions", ...process.argv.slice(2)];
9
+ const args = [
10
+ "--dangerously-bypass-approvals-and-sandbox",
11
+ ...process.argv.slice(2)
12
+ ];
10
13
  const child = spawn("node", [codexSmPath, ...args], {
11
14
  stdio: "inherit",
12
15
  env: process.env
@@ -317,12 +317,12 @@ ${contextResponse.context}`;
317
317
  "Launch Oracle/Worker pattern swarm for cost-effective execution"
318
318
  ).argument("<project>", "Project description for Oracle planning").option(
319
319
  "--oracle <model>",
320
- "Oracle model (default: claude-3-opus)",
321
- "claude-3-opus-20240229"
320
+ "Oracle model (default: claude-sonnet-4-5)",
321
+ "claude-sonnet-4-5-20250929"
322
322
  ).option(
323
323
  "--workers <models>",
324
324
  "Comma-separated worker models",
325
- "claude-3-5-haiku-20241022"
325
+ "claude-haiku-4-5-20251001"
326
326
  ).option("--budget <amount>", "Cost budget in USD", "10.0").option("--max-workers <count>", "Maximum worker agents", "5").option("--hints <hints>", "Comma-separated planning hints").action(async (project, options) => {
327
327
  return trace.command(
328
328
  "ralph-oracle-worker",
@@ -795,6 +795,89 @@ ${result.data.diffStat}`));
795
795
  process.exit(1);
796
796
  }
797
797
  });
798
+ const theoryCmd = skillsCmd.command("theory").description("Maintain a living THEORY.MD at repo root");
799
+ theoryCmd.command("show").description("Display current THEORY.MD content").action(async () => {
800
+ try {
801
+ const { context } = await initializeSkillContext();
802
+ const { TheorySkill } = await import("../../skills/theory-skill.js");
803
+ const skill = new TheorySkill(context);
804
+ const result = skill.show();
805
+ if (result.success) {
806
+ console.log(result.message);
807
+ } else {
808
+ console.log(chalk.red("\u2717"), result.message);
809
+ }
810
+ await context.database.disconnect();
811
+ } catch (error) {
812
+ console.error(chalk.red("Error:"), error.message);
813
+ process.exit(1);
814
+ }
815
+ });
816
+ theoryCmd.command("init <problem>").description("Create THEORY.MD with scaffold sections").action(async (problem) => {
817
+ try {
818
+ const { context } = await initializeSkillContext();
819
+ const { TheorySkill } = await import("../../skills/theory-skill.js");
820
+ const skill = new TheorySkill(context);
821
+ const result = skill.init(problem);
822
+ if (result.success) {
823
+ console.log(chalk.green("\u2713"), result.message);
824
+ } else {
825
+ console.log(chalk.red("\u2717"), result.message);
826
+ }
827
+ await context.database.disconnect();
828
+ } catch (error) {
829
+ console.error(chalk.red("Error:"), error.message);
830
+ process.exit(1);
831
+ }
832
+ });
833
+ theoryCmd.command("update <content>").description("Overwrite THEORY.MD with new content").action(async (content) => {
834
+ try {
835
+ const { context } = await initializeSkillContext();
836
+ const { TheorySkill } = await import("../../skills/theory-skill.js");
837
+ const skill = new TheorySkill(context);
838
+ const result = skill.update(content);
839
+ if (result.success) {
840
+ console.log(chalk.green("\u2713"), result.message);
841
+ if (result.data?.warnings?.length > 0) {
842
+ result.data.warnings.forEach((w) => {
843
+ console.log(chalk.yellow(` \u26A0 ${w}`));
844
+ });
845
+ }
846
+ } else {
847
+ console.log(chalk.red("\u2717"), result.message);
848
+ }
849
+ await context.database.disconnect();
850
+ } catch (error) {
851
+ console.error(chalk.red("Error:"), error.message);
852
+ process.exit(1);
853
+ }
854
+ });
855
+ theoryCmd.command("status").description("Show THEORY.MD metadata").action(async () => {
856
+ try {
857
+ const { context } = await initializeSkillContext();
858
+ const { TheorySkill } = await import("../../skills/theory-skill.js");
859
+ const skill = new TheorySkill(context);
860
+ const result = skill.status();
861
+ if (result.success) {
862
+ console.log(chalk.cyan("THEORY.MD Status:"));
863
+ if (result.data?.exists) {
864
+ console.log(` Lines: ${result.data.lineCount}`);
865
+ console.log(
866
+ ` Sections: ${result.data.sections?.length}/${result.data.totalSections}`
867
+ );
868
+ console.log(` Last modified: ${result.data.lastModified}`);
869
+ } else {
870
+ console.log(chalk.gray(" Not found"));
871
+ }
872
+ } else {
873
+ console.log(chalk.red("\u2717"), result.message);
874
+ }
875
+ await context.database.disconnect();
876
+ } catch (error) {
877
+ console.error(chalk.red("Error:"), error.message);
878
+ process.exit(1);
879
+ }
880
+ });
798
881
  skillsCmd.command("help [skill]").description("Show help for a specific skill").action(async (skill) => {
799
882
  if (skill) {
800
883
  switch (skill) {
@@ -846,6 +929,27 @@ Examples:
846
929
 
847
930
  Apply patches: git apply .stackmemory/patches/<file>.patch
848
931
  Review specs: cd /tmp/sm-spec-* && git log --oneline
932
+ `);
933
+ break;
934
+ case "theory":
935
+ console.log(`
936
+ theory \u2014 Living Operating Theory Document
937
+
938
+ Maintains a THEORY.MD at repo root: a narrative capturing your problem
939
+ thesis, mental model, strategy, discoveries, and open questions.
940
+
941
+ Subcommands:
942
+ show Display current THEORY.MD
943
+ init <problem> Create THEORY.MD with scaffold sections
944
+ update <content> Overwrite THEORY.MD (validates, warns on anti-patterns)
945
+ status Show metadata (lines, sections, last modified)
946
+
947
+ Examples:
948
+ stackmemory skills theory init "Build context-aware memory for AI agents"
949
+ stackmemory skills theory show
950
+ stackmemory skills theory status
951
+
952
+ Based on Theorist by @blader (MIT).
849
953
  `);
850
954
  break;
851
955
  default:
@@ -875,7 +979,10 @@ Review specs: cd /tmp/sm-spec-* && git log --oneline
875
979
  );
876
980
  console.log(" linear-run - Execute Linear tasks via RLM orchestrator");
877
981
  console.log(
878
- " agent - Spawn parallel agents (research, maintain, spec-run)\n"
982
+ " agent - Spawn parallel agents (research, maintain, spec-run)"
983
+ );
984
+ console.log(
985
+ " theory - Maintain a living THEORY.MD (show, init, update, status)\n"
879
986
  );
880
987
  console.log(
881
988
  chalk.yellow(
@@ -113,10 +113,11 @@ class ClaudeAdapter {
113
113
  }
114
114
  async listModels() {
115
115
  return [
116
- "claude-opus-4-20250514",
116
+ "claude-opus-4-6",
117
+ "claude-sonnet-4-5-20250929",
118
+ "claude-haiku-4-5-20251001",
117
119
  "claude-sonnet-4-20250514",
118
- "claude-3-5-haiku-20241022",
119
- "claude-3-opus-20240229"
120
+ "claude-3-5-haiku-20241022"
120
121
  ];
121
122
  }
122
123
  buildRequestBody(messages, options) {
@@ -360,16 +361,7 @@ class GPTAdapter {
360
361
  }
361
362
  }
362
363
  async listModels() {
363
- return [
364
- "gpt-4o",
365
- "gpt-4o-mini",
366
- "gpt-4-turbo",
367
- "gpt-4",
368
- "gpt-3.5-turbo",
369
- "o1",
370
- "o1-mini",
371
- "o1-preview"
372
- ];
364
+ return ["gpt-4o", "gpt-4o-mini", "o3-mini", "o4-mini"];
373
365
  }
374
366
  }
375
367
  function createProvider(id, config) {
@@ -22,16 +22,14 @@ const MODEL_TOKEN_LIMITS = {
22
22
  "claude-sonnet-4-5-20250929": 2e5,
23
23
  "claude-haiku-4-5-20251001": 2e5,
24
24
  "claude-sonnet-4-20250514": 2e5,
25
- // Claude 3.x
25
+ // Claude 3.x (legacy, still functional)
26
26
  "claude-3-5-sonnet-20241022": 2e5,
27
27
  "claude-3-5-haiku-20241022": 2e5,
28
- "claude-3-opus-20240229": 2e5,
29
28
  // OpenAI
30
29
  "gpt-4o": 128e3,
31
- "gpt-4-turbo": 128e3,
32
- "gpt-4": 8192,
33
- o1: 2e5,
30
+ "gpt-4o-mini": 128e3,
34
31
  "o3-mini": 2e5,
32
+ "o4-mini": 2e5,
35
33
  // Qwen
36
34
  "qwen3-max-2025-01-23": 128e3,
37
35
  // Cerebras
@@ -13,7 +13,6 @@ import {
13
13
  import { join, extname, relative } from "path";
14
14
  import { spawn } from "child_process";
15
15
  import { loadConfig } from "./config.js";
16
- import { GraphitiHooks } from "./graphiti-hooks.js";
17
16
  import {
18
17
  hookEmitter
19
18
  } from "./events.js";
@@ -143,13 +142,6 @@ function registerBuiltinHandlers() {
143
142
  hookEmitter.registerHandler("file_change", handleFileChange);
144
143
  hookEmitter.registerHandler("suggestion_ready", handleSuggestionReady);
145
144
  hookEmitter.registerHandler("error", handleError);
146
- try {
147
- if (process.env.GRAPHITI_ENDPOINT || process.env.GRAPHITI_ENABLED === "true") {
148
- const graphiti = new GraphitiHooks();
149
- graphiti.register(hookEmitter);
150
- }
151
- } catch {
152
- }
153
145
  hookEmitter.on("*", () => {
154
146
  state.eventsProcessed++;
155
147
  });
@@ -22,7 +22,6 @@ function getOptionalEnv(key) {
22
22
  class LinearWebhookHandler {
23
23
  syncEngine;
24
24
  taskStore;
25
- graphitiBridge;
26
25
  webhookSecret;
27
26
  constructor(webhookSecret) {
28
27
  this.webhookSecret = webhookSecret || process.env["LINEAR_WEBHOOK_SECRET"];
@@ -39,12 +38,6 @@ class LinearWebhookHandler {
39
38
  setTaskStore(taskStore) {
40
39
  this.taskStore = taskStore;
41
40
  }
42
- /**
43
- * Set the Graphiti bridge for knowledge graph sync
44
- */
45
- setGraphitiBridge(bridge) {
46
- this.graphitiBridge = bridge;
47
- }
48
41
  /**
49
42
  * Verify webhook signature
50
43
  */
@@ -111,15 +104,6 @@ class LinearWebhookHandler {
111
104
  default:
112
105
  logger.warn(`Unknown webhook action: ${payload.action}`);
113
106
  }
114
- if (this.graphitiBridge) {
115
- this.graphitiBridge.processWebhook(payload).catch((err) => {
116
- logger.debug("Linear-Graphiti bridge error", {
117
- action: payload.action,
118
- identifier: payload.data.identifier,
119
- error: err instanceof Error ? err.message : String(err)
120
- });
121
- });
122
- }
123
107
  }
124
108
  /**
125
109
  * Handle issue created in Linear
@@ -99,10 +99,6 @@ class MCPHandlerFactory {
99
99
  return this.taskHandlers.handleGetActiveTasks.bind(this.taskHandlers);
100
100
  case "get_task_metrics":
101
101
  return this.taskHandlers.handleGetTaskMetrics.bind(this.taskHandlers);
102
- case "add_task_dependency":
103
- return this.taskHandlers.handleAddTaskDependency.bind(
104
- this.taskHandlers
105
- );
106
102
  // Linear handlers
107
103
  case "linear_sync":
108
104
  return this.linearHandlers.handleLinearSync.bind(this.linearHandlers);
@@ -119,8 +115,6 @@ class MCPHandlerFactory {
119
115
  // Trace handlers
120
116
  case "get_traces":
121
117
  return this.traceHandlers.handleGetTraces.bind(this.traceHandlers);
122
- case "analyze_traces":
123
- return this.traceHandlers.handleAnalyzeTraces.bind(this.traceHandlers);
124
118
  case "start_browser_debug":
125
119
  return this.traceHandlers.handleStartBrowserDebug.bind(
126
120
  this.traceHandlers
@@ -193,7 +187,6 @@ class MCPHandlerFactory {
193
187
  "update_task_status",
194
188
  "get_active_tasks",
195
189
  "get_task_metrics",
196
- "add_task_dependency",
197
190
  // Linear tools
198
191
  "linear_sync",
199
192
  "linear_update_task",
@@ -201,7 +194,6 @@ class MCPHandlerFactory {
201
194
  "linear_status",
202
195
  // Trace tools
203
196
  "get_traces",
204
- "analyze_traces",
205
197
  "start_browser_debug",
206
198
  "take_screenshot",
207
199
  "execute_script",
@@ -11,6 +11,9 @@ class TraceHandlers {
11
11
  * Get traces with optional filtering
12
12
  */
13
13
  async handleGetTraces(args) {
14
+ if (args.analyze) {
15
+ return this.handleAnalyzeTraces(args);
16
+ }
14
17
  try {
15
18
  const {
16
19
  limit = 20,
@@ -31,7 +31,6 @@ import { LLMContextRetrieval } from "../../core/retrieval/index.js";
31
31
  import { DiscoveryHandlers } from "./handlers/discovery-handlers.js";
32
32
  import { DiffMemHandlers } from "./handlers/diffmem-handlers.js";
33
33
  import { GreptileHandlers } from "./handlers/greptile-handlers.js";
34
- import { GraphitiClient } from "../graphiti/client.js";
35
34
  import { fuzzyEdit } from "../../utils/fuzzy-edit.js";
36
35
  import { v4 as uuidv4 } from "uuid";
37
36
  import {
@@ -67,7 +66,6 @@ class LocalStackMemoryMCP {
67
66
  diffMemHandlers;
68
67
  greptileHandlers;
69
68
  providerHandlers = null;
70
- graphitiClient = null;
71
69
  pendingPlans = /* @__PURE__ */ new Map();
72
70
  constructor() {
73
71
  this.projectRoot = this.findProjectRoot();
@@ -142,15 +140,6 @@ class LocalStackMemoryMCP {
142
140
  this.diffMemHandlers = new DiffMemHandlers();
143
141
  this.greptileHandlers = new GreptileHandlers();
144
142
  this.initProviderHandlers();
145
- if (process.env.GRAPHITI_ENDPOINT) {
146
- this.graphitiClient = new GraphitiClient({
147
- endpoint: process.env.GRAPHITI_ENDPOINT,
148
- projectNamespace: process.env.STACKMEMORY_PROJECT_ID || this.projectId
149
- });
150
- logger.info("Graphiti client initialized", {
151
- endpoint: process.env.GRAPHITI_ENDPOINT
152
- });
153
- }
154
143
  this.setupHandlers();
155
144
  this.loadInitialContext();
156
145
  this.loadPendingPlans();
@@ -711,24 +700,6 @@ ${summary}...`, 0.8);
711
700
  properties: {}
712
701
  }
713
702
  },
714
- {
715
- name: "add_task_dependency",
716
- description: "Add dependency relationship between tasks",
717
- inputSchema: {
718
- type: "object",
719
- properties: {
720
- taskId: {
721
- type: "string",
722
- description: "Task that depends on another"
723
- },
724
- dependsOnId: {
725
- type: "string",
726
- description: "Task ID that this depends on"
727
- }
728
- },
729
- required: ["taskId", "dependsOnId"]
730
- }
731
- },
732
703
  {
733
704
  name: "linear_sync",
734
705
  description: "Sync tasks with Linear",
@@ -1087,51 +1058,6 @@ ${summary}...`, 0.8);
1087
1058
  properties: {}
1088
1059
  }
1089
1060
  },
1090
- // Graphiti tools (only active when GRAPHITI_ENDPOINT is set)
1091
- ...this.graphitiClient ? [
1092
- {
1093
- name: "graphiti_status",
1094
- description: "Check Graphiti temporal knowledge graph connection status",
1095
- inputSchema: {
1096
- type: "object",
1097
- properties: {}
1098
- }
1099
- },
1100
- {
1101
- name: "graphiti_query",
1102
- description: "Query the Graphiti temporal knowledge graph for entities, relations, and episodes",
1103
- inputSchema: {
1104
- type: "object",
1105
- properties: {
1106
- query: {
1107
- type: "string",
1108
- description: "Semantic text query"
1109
- },
1110
- entityTypes: {
1111
- type: "array",
1112
- items: { type: "string" },
1113
- description: 'Entity types to filter (e.g., ["Person", "File", "Issue"])'
1114
- },
1115
- validFrom: {
1116
- type: "number",
1117
- description: "Start of time window (epoch ms)"
1118
- },
1119
- validTo: {
1120
- type: "number",
1121
- description: "End of time window (epoch ms)"
1122
- },
1123
- maxHops: {
1124
- type: "number",
1125
- description: "Graph traversal depth (default 2)"
1126
- },
1127
- k: {
1128
- type: "number",
1129
- description: "Top-k results (default 20)"
1130
- }
1131
- }
1132
- }
1133
- }
1134
- ] : [],
1135
1061
  // Greptile tools (only active when GREPTILE_API_KEY is set)
1136
1062
  ...process.env.GREPTILE_API_KEY ? this.greptileHandlers.getToolDefinitions() : [],
1137
1063
  // Provider tools (only active when STACKMEMORY_MULTI_PROVIDER=true)
@@ -1299,9 +1225,6 @@ ${summary}...`, 0.8);
1299
1225
  case "get_task_metrics":
1300
1226
  result = await this.handleGetTaskMetrics(args);
1301
1227
  break;
1302
- case "add_task_dependency":
1303
- result = await this.handleAddTaskDependency(args);
1304
- break;
1305
1228
  case "linear_sync":
1306
1229
  result = await this.handleLinearSync(args);
1307
1230
  break;
@@ -1456,59 +1379,6 @@ ${summary}...`, 0.8);
1456
1379
  );
1457
1380
  }
1458
1381
  break;
1459
- // Graphiti tools
1460
- case "graphiti_status":
1461
- if (!this.graphitiClient) {
1462
- result = {
1463
- content: [
1464
- {
1465
- type: "text",
1466
- text: JSON.stringify({
1467
- connected: false,
1468
- message: "Graphiti integration disabled (GRAPHITI_ENDPOINT not set)"
1469
- })
1470
- }
1471
- ]
1472
- };
1473
- } else {
1474
- const status = await this.graphitiClient.getStatus();
1475
- result = {
1476
- content: [
1477
- { type: "text", text: JSON.stringify(status, null, 2) }
1478
- ]
1479
- };
1480
- }
1481
- break;
1482
- case "graphiti_query":
1483
- if (!this.graphitiClient) {
1484
- result = {
1485
- content: [
1486
- {
1487
- type: "text",
1488
- text: "Graphiti integration disabled (GRAPHITI_ENDPOINT not set)"
1489
- }
1490
- ]
1491
- };
1492
- } else {
1493
- const gCtx = await this.graphitiClient.queryTemporal({
1494
- query: args.query,
1495
- entityTypes: args.entityTypes,
1496
- validFrom: args.validFrom,
1497
- validTo: args.validTo,
1498
- maxHops: args.maxHops,
1499
- k: args.k
1500
- });
1501
- const text = gCtx.chunks.map((c) => c.text).join("\n\n");
1502
- result = {
1503
- content: [
1504
- {
1505
- type: "text",
1506
- text: text || `No results found (${gCtx.totalTokens} tokens searched)`
1507
- }
1508
- ]
1509
- };
1510
- }
1511
- break;
1512
1382
  default:
1513
1383
  throw new Error(`Unknown tool: ${name}`);
1514
1384
  }