memorix 1.8.4 → 1.8.6

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 (88) hide show
  1. package/CHANGELOG.md +52 -0
  2. package/CLAUDE.md +3 -0
  3. package/README.md +8 -6
  4. package/README.zh-CN.md +5 -3
  5. package/assets/star-history-dark.svg +5 -5
  6. package/assets/star-history-light.svg +5 -5
  7. package/assets/star-history.json +35 -5
  8. package/dist/cli/index.js +1848 -754
  9. package/dist/dashboard/static/app.js +29 -885
  10. package/dist/dashboard/static/index.html +1 -5
  11. package/dist/dashboard/static/style.css +36 -503
  12. package/dist/index.d.ts +4 -4
  13. package/dist/index.js +286 -79
  14. package/dist/memcode/index.js +28035 -169
  15. package/dist/memcode-runtime/CHANGELOG.md +52 -0
  16. package/dist/sdk.js +103 -21
  17. package/dist/types.d.ts +1 -1
  18. package/docs/1.8.0-RELEASE-CANDIDATE-SPEC.md +22 -16
  19. package/docs/AGENT_OPERATOR_PLAYBOOK.md +2 -2
  20. package/docs/API_REFERENCE.md +10 -8
  21. package/docs/DASHBOARD.md +23 -0
  22. package/docs/DEVELOPMENT.md +2 -2
  23. package/docs/DOCKER.md +6 -3
  24. package/docs/INTEGRATIONS.md +2 -1
  25. package/docs/MODULES.md +46 -20
  26. package/docs/PERFORMANCE.md +1 -1
  27. package/docs/README.md +8 -7
  28. package/docs/SETUP.md +4 -3
  29. package/package.json +11 -11
  30. package/plugins/antigravity/memorix/plugin.json +1 -1
  31. package/plugins/antigravity/memorix/rules/memorix.md +5 -0
  32. package/plugins/claude/memorix/.claude-plugin/plugin.json +1 -1
  33. package/plugins/claude/memorix/skills/memorix-memory/SKILL.md +3 -0
  34. package/plugins/claude/memorix/skills/memorix-mini-skills/SKILL.md +2 -0
  35. package/plugins/claude/memorix/skills/memorix-orchestrate/SKILL.md +2 -0
  36. package/plugins/codebuddy/memorix/.codebuddy-plugin/plugin.json +1 -1
  37. package/plugins/codebuddy/memorix/skills/memorix-memory/SKILL.md +3 -0
  38. package/plugins/codebuddy/memorix/skills/memorix-mini-skills/SKILL.md +2 -0
  39. package/plugins/codebuddy/memorix/skills/memorix-orchestrate/SKILL.md +2 -0
  40. package/plugins/codex/memorix/.codex-plugin/plugin.json +1 -1
  41. package/plugins/codex/memorix/skills/memorix-memory/SKILL.md +3 -0
  42. package/plugins/codex/memorix/skills/memorix-mini-skills/SKILL.md +2 -0
  43. package/plugins/codex/memorix/skills/memorix-orchestrate/SKILL.md +2 -0
  44. package/plugins/copilot/memorix/plugin.json +1 -1
  45. package/plugins/copilot/memorix/skills/memorix-memory/SKILL.md +3 -0
  46. package/plugins/copilot/memorix/skills/memorix-mini-skills/SKILL.md +2 -0
  47. package/plugins/copilot/memorix/skills/memorix-orchestrate/SKILL.md +2 -0
  48. package/plugins/cursor/memorix/skills/memorix-memory/SKILL.md +3 -0
  49. package/plugins/cursor/memorix/skills/memorix-mini-skills/SKILL.md +2 -0
  50. package/plugins/cursor/memorix/skills/memorix-orchestrate/SKILL.md +2 -0
  51. package/plugins/gemini/memorix/GEMINI.md +5 -0
  52. package/plugins/gemini/memorix/gemini-extension.json +1 -1
  53. package/plugins/hermes/memorix/plugin.yaml +7 -1
  54. package/plugins/omp/memorix/package.json +1 -1
  55. package/plugins/openclaw/memorix/.codex-plugin/plugin.json +1 -1
  56. package/plugins/pi/memorix/package.json +1 -1
  57. package/plugins/pi/memorix/skills/memorix-memory/SKILL.md +3 -0
  58. package/plugins/pi/memorix/skills/memorix-mini-skills/SKILL.md +2 -0
  59. package/plugins/pi/memorix/skills/memorix-orchestrate/SKILL.md +2 -0
  60. package/server.json +2 -2
  61. package/src/cli/command-guide.ts +52 -1
  62. package/src/cli/commands/agent-integrations.ts +1 -0
  63. package/src/cli/commands/background.ts +166 -6
  64. package/src/cli/commands/hooks-install.ts +9 -2
  65. package/src/cli/commands/hooks-preview.ts +5 -0
  66. package/src/cli/commands/integrate.ts +2 -0
  67. package/src/cli/commands/serve-http.ts +73 -80
  68. package/src/cli/commands/serve.ts +95 -93
  69. package/src/cli/commands/setup.ts +11 -1
  70. package/src/cli/commands/uninstall.ts +24 -2
  71. package/src/cli/index.ts +1 -1
  72. package/src/codegraph/task-lens.ts +72 -7
  73. package/src/dashboard/static/index.html +1 -5
  74. package/src/dashboard/static/style.css +36 -503
  75. package/src/hooks/installers/index.ts +58 -0
  76. package/src/hooks/official-skills.ts +13 -6
  77. package/src/hooks/types.ts +2 -0
  78. package/src/integrations/registry.ts +9 -0
  79. package/src/memory/graph.ts +2 -2
  80. package/src/server/mcp-diagnostics.ts +9 -7
  81. package/src/server/modern-mcp-bridge.ts +108 -0
  82. package/src/server/stdio-startup-gate.ts +41 -2
  83. package/src/server/tool-profile.ts +7 -6
  84. package/src/server.ts +1 -1
  85. package/src/store/orama-store.ts +2 -2
  86. package/src/types.ts +1 -1
  87. package/src/wiki/types.ts +2 -2
  88. package/src/workspace/mcp-adapters/workbuddy.ts +71 -0
package/dist/index.js CHANGED
@@ -149968,6 +149968,15 @@ __export(task_lens_exports, {
149968
149968
  scoreLensSource: () => scoreLensSource,
149969
149969
  shouldShowLensSource: () => shouldShowLensSource
149970
149970
  });
149971
+ function hasSubstantiveTask(text2, keyword) {
149972
+ const withoutKeyword = text2.replace(
149973
+ new RegExp(keyword.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"), "gi"),
149974
+ " "
149975
+ );
149976
+ const residual = withoutKeyword.replace(TASK_FILLER_WORDS, " ").replace(TASK_FILLER_PHRASES, " ").replace(/[\s\p{P}]/gu, "");
149977
+ if (/^(?:任务|工作|一下|一起|接着)$/u.test(residual)) return false;
149978
+ return Array.from(residual).length >= MIN_TASK_SUBSTANCE;
149979
+ }
149971
149980
  function normalizePath2(path37) {
149972
149981
  return path37.replace(/\\/g, "/");
149973
149982
  }
@@ -150027,8 +150036,12 @@ function resolveTaskLens(task) {
150027
150036
  }
150028
150037
  function isContinuationTask(task) {
150029
150038
  const normalized = (task ?? "").trim().toLowerCase();
150030
- return normalized.length > 0 && CONTINUATION_KEYWORDS.some(
150031
- (keyword) => containsTaskKeyword(normalized, keyword)
150039
+ if (normalized.length === 0) return false;
150040
+ if (EXPLICIT_HANDOFF_KEYWORDS.some((keyword) => containsTaskKeyword(normalized, keyword))) {
150041
+ return true;
150042
+ }
150043
+ return AMBIGUOUS_CONTINUATION_KEYWORDS.some(
150044
+ (keyword) => containsTaskKeyword(normalized, keyword) && hasSubstantiveTask(normalized, keyword)
150032
150045
  );
150033
150046
  }
150034
150047
  function pathKindScore(path37, lens) {
@@ -150174,7 +150187,7 @@ function shouldShowLensSource(source, lens, task) {
150174
150187
  if (lens.id === "onboarding" || lens.id === "release" || lens.id === "docs") return score >= 40;
150175
150188
  return score > 0;
150176
150189
  }
150177
- var STOP_WORDS, LENSES, KEYWORDS, CONTINUATION_KEYWORDS, LENS_PRIORITY;
150190
+ var STOP_WORDS, LENSES, KEYWORDS, EXPLICIT_HANDOFF_KEYWORDS, AMBIGUOUS_CONTINUATION_KEYWORDS, TASK_FILLER_WORDS, TASK_FILLER_PHRASES, MIN_TASK_SUBSTANCE, LENS_PRIORITY;
150178
150191
  var init_task_lens = __esm({
150179
150192
  "src/codegraph/task-lens.ts"() {
150180
150193
  "use strict";
@@ -150295,18 +150308,31 @@ var init_task_lens = __esm({
150295
150308
  docs: ["doc", "docs", "readme", "\u6587\u6863", "\u8BF4\u660E"],
150296
150309
  test: ["coverage", "fixture", "smoke", "spec", "test", "tests", "testing", "vitest", "\u6D4B\u8BD5"]
150297
150310
  };
150298
- CONTINUATION_KEYWORDS = [
150311
+ EXPLICIT_HANDOFF_KEYWORDS = [
150312
+ "handoff",
150313
+ "hand off",
150314
+ "hand over",
150315
+ "previous session",
150316
+ "last session",
150317
+ "pick up where",
150318
+ "\u4EA4\u63A5",
150319
+ // 覆盖「任务交接」「工作交接」
150320
+ "\u63A5\u624B",
150321
+ "\u4E0A\u6B21\u4F1A\u8BDD",
150322
+ "\u4E0A\u6B21\u7684\u4F1A\u8BDD"
150323
+ ];
150324
+ AMBIGUOUS_CONTINUATION_KEYWORDS = [
150299
150325
  "continue",
150300
150326
  "resume",
150301
- "pick up",
150302
150327
  "carry on",
150303
- "previous session",
150328
+ "pick up",
150304
150329
  "\u7EE7\u7EED",
150305
- "\u63A5\u624B",
150306
150330
  "\u6062\u590D",
150307
- "\u5EF6\u7EED",
150308
- "\u4E0A\u6B21\u4F1A\u8BDD"
150331
+ "\u5EF6\u7EED"
150309
150332
  ];
150333
+ TASK_FILLER_WORDS = /\b(?:please|task|work|the|a|an)\b/giu;
150334
+ TASK_FILLER_PHRASES = /(?:吧|了|呢|啊|吗|嘛|呀|哦|噢|一下|一起|接着|请|帮我)/gu;
150335
+ MIN_TASK_SUBSTANCE = 2;
150310
150336
  LENS_PRIORITY = [
150311
150337
  "bugfix",
150312
150338
  "release",
@@ -156854,17 +156880,25 @@ function resolveToolProfile(opts) {
156854
156880
  return normalize(opts.explicit) ?? normalize(opts.envValue) ?? opts.fallback;
156855
156881
  }
156856
156882
  function describeProfile(profile) {
156883
+ const count2 = countToolsInProfile(profile);
156857
156884
  switch (profile) {
156858
156885
  case "micro":
156859
- return "micro (agent-ready context + bounded recovery/media, ~9 tools)";
156886
+ return `micro (agent-ready context + bounded recovery/media, ${count2} tools)`;
156860
156887
  case "lite":
156861
- return "lite (core memory + sessions, ~18 tools)";
156888
+ return `lite (core memory + sessions, ${count2} tools)`;
156862
156889
  case "team":
156863
- return "team (lite + coordination tools + dashboard + knowledge workspace, ~26 tools)";
156890
+ return `team (lite + coordination tools + dashboard + knowledge workspace, ${count2} tools)`;
156864
156891
  case "full":
156865
- return "full (all tools including advanced / KG-compat)";
156892
+ return `full (all tools including advanced / KG-compat, ${count2} tools)`;
156866
156893
  }
156867
156894
  }
156895
+ function countToolsInProfile(profile) {
156896
+ let n = 0;
156897
+ for (const name of Object.keys(TOOL_PROFILES)) {
156898
+ if (isToolInProfile(name, profile)) n++;
156899
+ }
156900
+ return n;
156901
+ }
156868
156902
  var TOOL_PROFILES;
156869
156903
  var init_tool_profile = __esm({
156870
156904
  "src/server/tool-profile.ts"() {
@@ -158121,7 +158155,7 @@ var init_request_context = __esm({
158121
158155
  function getMcpServerInfo() {
158122
158156
  return {
158123
158157
  name: "memorix",
158124
- version: true ? "1.8.4" : "1.0.1"
158158
+ version: true ? "1.8.6" : "1.0.1"
158125
158159
  };
158126
158160
  }
158127
158161
  function createMcpDiscoverResult(capabilities, serverInfo) {
@@ -166530,6 +166564,9 @@ var init_official_skills = __esm({
166530
166564
  '| Specific past decision, bug, file, or change | `memorix_search` | `memorix memory search --query "<topic>"` |',
166531
166565
  "| Need the full source for a search hit | `memorix_detail` | `memorix memory detail --id <id>` |",
166532
166566
  "| Need the sequence around one memory | `memorix_timeline` | `memorix memory timeline --id <id>` |",
166567
+ "| Check source and freshness for a memory | `memorix_evidence` | `memorix evidence list|get|events` |",
166568
+ "| Record whether a memory helped, conflicted, or was corrected | `memorix_feedback` | `memorix feedback record|show|audit` |",
166569
+ "| Inspect or import controlled media | `memorix_media` | `memorix media import|attach|list|show|status` |",
166533
166570
  '| Learned reusable project knowledge | `memorix_store` | `memorix memory store --type <type> --entity <name> --title "<title>" "<text>"` |',
166534
166571
  "| Task or bug is complete/outdated | `memorix_resolve` | `memorix memory resolve --ids <ids>` |",
166535
166572
  "",
@@ -166660,6 +166697,8 @@ var init_official_skills = __esm({
166660
166697
  "",
166661
166698
  "Promote memories into mini-skills only when they are reusable instructions, not just historical notes.",
166662
166699
  "",
166700
+ "The standard setup uses the `lite` MCP profile. `memorix_skills` and `memorix_promote` are full-profile tools, so use the CLI fallback unless the current server was explicitly started with `MEMORIX_MODE=full` or `--mode full`. Do not probe hidden MCP tools repeatedly.",
166701
+ "",
166663
166702
  "## Tool Router",
166664
166703
  "",
166665
166704
  "| Situation | Prefer | CLI fallback |",
@@ -166695,15 +166734,17 @@ var init_official_skills = __esm({
166695
166734
  "| Situation | Prefer | CLI fallback |",
166696
166735
  "|---|---|---|",
166697
166736
  '| Run managed subagent execution | CLI | `memorix orchestrate --goal "<goal>" --agents claude:1,codex:1` |',
166698
- "| Register coordination identity | `team_manage` action `join` | `memorix team join --agentType <agent>` |",
166699
- "| Create or inspect tasks | `team_task` | `memorix task create|list|claim|complete` |",
166700
- "| Send or read coordination messages | `team_message` | `memorix message send|broadcast|inbox` |",
166701
- "| Share structured handoff | `memorix_handoff` | `memorix handoff send` |",
166702
- "| Avoid file conflicts | `team_file_lock` | `memorix lock lock|unlock|status` |",
166703
- "| Poll joined coordination state | `memorix_poll` | `memorix poll` |",
166737
+ "| Register coordination identity when team MCP tools are available | `team_manage` action `join` | `memorix team join --agentType <agent>` |",
166738
+ "| Create or inspect tasks when team MCP tools are available | `team_task` | `memorix task create|list|claim|complete` |",
166739
+ "| Send or read coordination messages when team MCP tools are available | `team_message` | `memorix message send|broadcast|inbox` |",
166740
+ "| Share structured handoff when team MCP tools are available | `memorix_handoff` | `memorix handoff send` |",
166741
+ "| Avoid file conflicts when team MCP tools are available | `team_file_lock` | `memorix lock lock|unlock|status` |",
166742
+ "| Poll joined coordination state when team MCP tools are available | `memorix_poll` | `memorix poll` |",
166704
166743
  "",
166705
166744
  "## Boundaries",
166706
166745
  "",
166746
+ "The standard setup uses the `lite` MCP profile. Coordination MCP tools are exposed only by `team` or `full`; use the CLI fallback for ordinary installations, or explicitly start the server with `--mode team`. Do not probe unavailable team tools in a loop.",
166747
+ "",
166707
166748
  "- For ordinary memory, do not join coordination state.",
166708
166749
  "- For production multi-agent execution, prefer `memorix orchestrate` so the main process owns planning, dispatch, retries, and verification gates.",
166709
166750
  "- `memorix orchestrate` uses the current checkout for single-worker runs and task worktrees for parallel runs. Use `--isolated` to force worktree isolation, `--no-worktree` to disable it, `--allow-dirty` to run with uncommitted changes, and `--no-auto-merge` to preserve task worktrees for manual review.",
@@ -167318,6 +167359,8 @@ function getProjectConfigPath(agent, projectRoot) {
167318
167359
  return path33.join(projectRoot, ".agents", "hooks.json");
167319
167360
  case "gemini-cli":
167320
167361
  return path33.join(projectRoot, ".gemini", "settings.json");
167362
+ case "workbuddy":
167363
+ return "";
167321
167364
  default:
167322
167365
  return path33.join(projectRoot, ".memorix", "hooks.json");
167323
167366
  }
@@ -167351,6 +167394,8 @@ function getGlobalConfigPath(agent) {
167351
167394
  return path33.join(home, ".trae", "rules", "project_rules.md");
167352
167395
  case "dsh":
167353
167396
  return path33.join(process.env.DSH_HOME?.trim() || path33.join(home, ".dsh"), "AGENTS.md");
167397
+ case "workbuddy":
167398
+ return "";
167354
167399
  default:
167355
167400
  return path33.join(home, ".memorix", "hooks.json");
167356
167401
  }
@@ -167377,6 +167422,8 @@ function getAgentRulesPath(agent, root, global2 = false) {
167377
167422
  return path33.join(root, ".trae", "rules", "project_rules.md");
167378
167423
  case "dsh":
167379
167424
  return path33.join(process.env.DSH_HOME?.trim() || path33.join(root, ".dsh"), "AGENTS.md");
167425
+ case "workbuddy":
167426
+ return "";
167380
167427
  default:
167381
167428
  return path33.join(root, ".agent", "rules", "memorix.md");
167382
167429
  }
@@ -167403,6 +167450,8 @@ function getAgentRulesPath(agent, root, global2 = false) {
167403
167450
  return path33.join(root, ".trae", "rules", "project_rules.md");
167404
167451
  case "dsh":
167405
167452
  return path33.join(root, "AGENTS.md");
167453
+ case "workbuddy":
167454
+ return path33.join(root, "AGENTS.md");
167406
167455
  default:
167407
167456
  return path33.join(root, ".agent", "rules", "memorix.md");
167408
167457
  }
@@ -167491,6 +167540,11 @@ async function detectInstalledAgents() {
167491
167540
  agents.push("dsh");
167492
167541
  } catch {
167493
167542
  }
167543
+ try {
167544
+ await fs21.access(path33.join(home, ".workbuddy"));
167545
+ agents.push("workbuddy");
167546
+ } catch {
167547
+ }
167494
167548
  return agents;
167495
167549
  }
167496
167550
  async function installHooks(agent, projectRoot, global2 = false) {
@@ -167504,6 +167558,16 @@ async function installHooks(agent, projectRoot, global2 = false) {
167504
167558
  }
167505
167559
  };
167506
167560
  }
167561
+ if (agent === "workbuddy" && global2) {
167562
+ return {
167563
+ agent,
167564
+ configPath: "",
167565
+ events: [],
167566
+ generated: {
167567
+ note: "WorkBuddy has no hook system and no user-global guidance file \u2014 MCP only; no global guidance/hooks. Run `memorix setup --agent workbuddy` (without --global) to install project MCP config and AGENTS.md guidance."
167568
+ }
167569
+ };
167570
+ }
167507
167571
  if (global2 && getGlobalConfigPath(agent) === "") {
167508
167572
  return {
167509
167573
  agent,
@@ -167586,6 +167650,17 @@ async function installHooks(agent, projectRoot, global2 = false) {
167586
167650
  }
167587
167651
  };
167588
167652
  }
167653
+ case "workbuddy": {
167654
+ const rulesPath = await installAgentRules(agent, projectRoot, global2);
167655
+ return {
167656
+ agent,
167657
+ configPath: rulesPath,
167658
+ events: [],
167659
+ generated: {
167660
+ note: "WorkBuddy has no hook system \u2014 installed AGENTS.md guidance only; the MCP row is installed by `memorix setup --agent workbuddy`."
167661
+ }
167662
+ };
167663
+ }
167589
167664
  case "opencode": {
167590
167665
  const pluginContent = generateOpenCodePlugin();
167591
167666
  const pluginPath = global2 ? getGlobalConfigPath(agent) : getProjectConfigPath(agent, projectRoot);
@@ -167715,6 +167790,7 @@ async function installHooks(agent, projectRoot, global2 = false) {
167715
167790
  };
167716
167791
  }
167717
167792
  async function installAgentRules(agent, projectRoot, global2 = false) {
167793
+ if (agent === "workbuddy" && global2) return "";
167718
167794
  const rulesContent = getAgentRulesContent(agent, global2 ? "global" : "project");
167719
167795
  const rulesRoot = global2 ? os5.homedir() : projectRoot;
167720
167796
  const rulesPath = getAgentRulesPath(agent, rulesRoot, global2);
@@ -167867,7 +167943,10 @@ alwaysApply: true
167867
167943
  "| `memorix_store` | Save something worth persisting |",
167868
167944
  '| `memorix_store_reasoning` | Save the "why" behind a decision |',
167869
167945
  "| `memorix_resolve` | Mark completed/outdated memories |",
167870
- "| `memorix_session_start` | Load session context (handoff, orchestration coordination) |"
167946
+ "| `memorix_session_start` | Load session context (handoff, orchestration coordination) |",
167947
+ "| `memorix_evidence` | Check a memory source, freshness, and verification state |",
167948
+ "| `memorix_feedback` | Record whether a memory helped, conflicted, or was corrected |",
167949
+ "| `memorix_media` | Inspect or import controlled local media |"
167871
167950
  ].join("\n");
167872
167951
  }
167873
167952
  async function uninstallHooks(agent, projectRoot, global2 = false) {
@@ -167877,6 +167956,9 @@ async function uninstallHooks(agent, projectRoot, global2 = false) {
167877
167956
  if (agent === "pi") {
167878
167957
  return false;
167879
167958
  }
167959
+ if (agent === "workbuddy") {
167960
+ return false;
167961
+ }
167880
167962
  if (global2 && getGlobalConfigPath(agent) === "") {
167881
167963
  return false;
167882
167964
  }
@@ -172907,7 +172989,17 @@ var init_stdio_startup_gate = __esm({
172907
172989
  this.fail(new Error(`stdio input chunk exceeded ${this.maxBufferSize} bytes`));
172908
172990
  return;
172909
172991
  }
172910
- this.input.write(chunk);
172992
+ this.pendingInput += typeof chunk === "string" ? chunk : chunk.toString("utf8");
172993
+ let newline2 = this.pendingInput.indexOf("\n");
172994
+ while (newline2 >= 0 && !this.stopped) {
172995
+ const line = this.pendingInput.slice(0, newline2 + 1);
172996
+ this.pendingInput = this.pendingInput.slice(newline2 + 1);
172997
+ this.handleReadyLine(line);
172998
+ newline2 = this.pendingInput.indexOf("\n");
172999
+ }
173000
+ if (!this.stopped && Buffer.byteLength(this.pendingInput, "utf8") > this.maxBufferSize) {
173001
+ this.fail(new Error(`stdio input exceeded ${this.maxBufferSize} bytes`));
173002
+ }
172911
173003
  return;
172912
173004
  }
172913
173005
  const text2 = typeof chunk === "string" ? chunk : chunk.toString("utf8");
@@ -173006,6 +173098,24 @@ var init_stdio_startup_gate = __esm({
173006
173098
  this.queuedMessages.push(line);
173007
173099
  this.queuedBytes += bytes;
173008
173100
  }
173101
+ handleReadyLine(line) {
173102
+ const parsed = this.parseLine(line);
173103
+ if (parsed && !("error" in parsed) && this.isDiscoveryRequest(parsed.message)) {
173104
+ const response = {
173105
+ jsonrpc: "2.0",
173106
+ id: parsed.message.id,
173107
+ result: createMcpStartupDiscoverResult(this.serverInfo)
173108
+ };
173109
+ try {
173110
+ this.stdout.write(`${JSON.stringify(response)}
173111
+ `);
173112
+ } catch (error) {
173113
+ this.fail(error instanceof Error ? error : new Error(String(error)));
173114
+ }
173115
+ return;
173116
+ }
173117
+ this.input.write(line);
173118
+ }
173009
173119
  parseLine(line) {
173010
173120
  const trimmed = line.endsWith("\n") ? line.slice(0, -1).replace(/\r$/, "") : line;
173011
173121
  if (!trimmed.trim()) return null;
@@ -173044,7 +173154,8 @@ var init_stdio_startup_gate = __esm({
173044
173154
  if (message.method !== MCP_SERVER_DISCOVER_METHOD) return false;
173045
173155
  if (!Object.prototype.hasOwnProperty.call(message, "id")) return false;
173046
173156
  const params = message.params;
173047
- return params === void 0 || typeof params === "object" && params !== null && !Array.isArray(params);
173157
+ if (params === void 0) return true;
173158
+ return typeof params === "object" && params !== null && !Array.isArray(params) && !Object.prototype.hasOwnProperty.call(params, "_meta");
173048
173159
  }
173049
173160
  isValidRequestId(id) {
173050
173161
  return id === null || typeof id === "string" || typeof id === "number" && Number.isFinite(id);
@@ -173123,6 +173234,81 @@ var init_mcp_root_path = __esm({
173123
173234
  }
173124
173235
  });
173125
173236
 
173237
+ // src/server/modern-mcp-bridge.ts
173238
+ var modern_mcp_bridge_exports = {};
173239
+ __export(modern_mcp_bridge_exports, {
173240
+ createModernMcpBridge: () => createModernMcpBridge
173241
+ });
173242
+ import {
173243
+ fromJsonSchema,
173244
+ McpServer as ModernMcpServer
173245
+ } from "@modelcontextprotocol/server";
173246
+ import { Client as LegacyClient } from "@modelcontextprotocol/sdk/client/index.js";
173247
+ import { InMemoryTransport as LegacyInMemoryTransport } from "@modelcontextprotocol/sdk/inMemory.js";
173248
+ async function createModernMcpBridge(options) {
173249
+ const { createMemorixServer: createMemorixServer2 } = await Promise.resolve().then(() => (init_server2(), server_exports2));
173250
+ const legacy = await createMemorixServer2(
173251
+ options.projectRoot,
173252
+ void 0,
173253
+ void 0,
173254
+ {
173255
+ ...options,
173256
+ allowUntrackedFallback: options.allowUntrackedFallback ?? false,
173257
+ deferProjectInitUntilBound: options.deferProjectInitUntilBound ?? true,
173258
+ deferProjectRuntimeInit: options.deferProjectRuntimeInit ?? true
173259
+ }
173260
+ );
173261
+ const [clientTransport, serverTransport] = LegacyInMemoryTransport.createLinkedPair();
173262
+ const legacyClient = new LegacyClient({
173263
+ name: "memorix-modern-bridge",
173264
+ version: getMcpServerInfo().version
173265
+ });
173266
+ await legacy.server.connect(serverTransport);
173267
+ await legacyClient.connect(clientTransport);
173268
+ const listed = await legacyClient.listTools();
173269
+ const modern = new ModernMcpServer(getMcpServerInfo());
173270
+ for (const tool of listed.tools) {
173271
+ modern.registerTool(
173272
+ tool.name,
173273
+ {
173274
+ ...tool.title ? { title: tool.title } : {},
173275
+ ...tool.description ? { description: tool.description } : {},
173276
+ inputSchema: fromJsonSchema(tool.inputSchema)
173277
+ },
173278
+ async (args) => await legacyClient.callTool({
173279
+ name: tool.name,
173280
+ arguments: args
173281
+ })
173282
+ );
173283
+ }
173284
+ const bridge = modern;
173285
+ bridge.memorix = {
173286
+ projectId: legacy.projectId,
173287
+ deferredInit: legacy.deferredInit,
173288
+ switchProject: legacy.switchProject,
173289
+ isExplicitlyBound: legacy.isExplicitlyBound,
173290
+ handleTransportClose: legacy.handleTransportClose
173291
+ };
173292
+ let closed = false;
173293
+ const modernClose = modern.close.bind(modern);
173294
+ modern.close = async () => {
173295
+ if (closed) return;
173296
+ closed = true;
173297
+ await modernClose();
173298
+ await legacyClient.close().catch(() => void 0);
173299
+ await legacy.server.close().catch(() => void 0);
173300
+ legacy.handleTransportClose();
173301
+ };
173302
+ return bridge;
173303
+ }
173304
+ var init_modern_mcp_bridge = __esm({
173305
+ "src/server/modern-mcp-bridge.ts"() {
173306
+ "use strict";
173307
+ init_esm_shims();
173308
+ init_mcp_discovery();
173309
+ }
173310
+ });
173311
+
173126
173312
  // src/cli/commands/serve-shared.ts
173127
173313
  var serve_shared_exports = {};
173128
173314
  __export(serve_shared_exports, {
@@ -173231,7 +173417,7 @@ var init_serve_shared = __esm({
173231
173417
 
173232
173418
  // src/cli/version.ts
173233
173419
  function getCliVersion() {
173234
- return true ? "1.8.4" : pkg.version;
173420
+ return true ? "1.8.6" : pkg.version;
173235
173421
  }
173236
173422
  var init_version3 = __esm({
173237
173423
  "src/cli/version.ts"() {
@@ -173487,6 +173673,14 @@ var init_serve = __esm({
173487
173673
  }
173488
173674
  },
173489
173675
  run: async ({ args }) => {
173676
+ const { serveStdio, StdioServerTransport } = await import("@modelcontextprotocol/server/stdio");
173677
+ const { createModernMcpBridge: createModernMcpBridge2 } = await Promise.resolve().then(() => (init_modern_mcp_bridge(), modern_mcp_bridge_exports));
173678
+ const { detectProject: detectProject2, findGitInSubdirs: findGitInSubdirs2, isSystemDirectory: isSystemDirectory2 } = await Promise.resolve().then(() => (init_detector(), detector_exports));
173679
+ const { homedir: homedir27 } = await import("os");
173680
+ const { writeLastProjectRoot: writeLastProjectRoot2 } = await Promise.resolve().then(() => (init_launch_root(), launch_root_exports));
173681
+ const { resolveServeProject: resolveServeProject2 } = await Promise.resolve().then(() => (init_serve_shared(), serve_shared_exports));
173682
+ let stdioHandle;
173683
+ let stdinEndedBeforeHandle = false;
173490
173684
  const startupGate = new StdioStartupGate({
173491
173685
  stdin: process.stdin,
173492
173686
  stdout: process.stdout,
@@ -173496,16 +173690,17 @@ var init_serve = __esm({
173496
173690
  process.exit(1);
173497
173691
  },
173498
173692
  onEnd: () => {
173499
- console.error("[memorix] stdin closed \u2014 exiting");
173500
- process.exitCode = 0;
173693
+ console.error("[memorix] stdin closed - exiting");
173694
+ if (stdioHandle) {
173695
+ void stdioHandle.close().catch((error) => {
173696
+ console.error(`[memorix] stdio close error: ${error instanceof Error ? error.message : String(error)}`);
173697
+ });
173698
+ } else {
173699
+ stdinEndedBeforeHandle = true;
173700
+ }
173501
173701
  }
173502
173702
  });
173503
173703
  startupGate.start();
173504
- const { StdioServerTransport } = await import("@modelcontextprotocol/sdk/server/stdio.js");
173505
- const { createMemorixServer: createMemorixServer2 } = await Promise.resolve().then(() => (init_server2(), server_exports2));
173506
- const { detectProject: detectProject2, findGitInSubdirs: findGitInSubdirs2, isSystemDirectory: isSystemDirectory2 } = await Promise.resolve().then(() => (init_detector(), detector_exports));
173507
- const { homedir: homedir27 } = await import("os");
173508
- const { resolveServeProject: resolveServeProject2 } = await Promise.resolve().then(() => (init_serve_shared(), serve_shared_exports));
173509
173704
  let safeCwd;
173510
173705
  try {
173511
173706
  safeCwd = process.cwd();
@@ -173522,70 +173717,82 @@ var init_serve = __esm({
173522
173717
  },
173523
173718
  { detectProject: detectProject2, findGitInSubdirs: findGitInSubdirs2, isSystemDirectory: isSystemDirectory2 }
173524
173719
  );
173525
- for (const message of resolution.messages) {
173526
- console.error(message);
173527
- }
173720
+ for (const message of resolution.messages) console.error(message);
173528
173721
  if (!resolution.detectedProject) {
173529
173722
  console.error(`[memorix] [WARN] ${resolution.error}`);
173530
- console.error(`[memorix] Starting in deferred-binding mode \u2014 project will bind via MCP roots or memorix_session_start.`);
173531
- console.error(`[memorix] For non-git directories, use --allow-untracked to enable untracked/ fallback.`);
173723
+ console.error("[memorix] Starting in deferred-binding mode - bind with memorix_session_start(projectRoot=...) when needed.");
173724
+ console.error("[memorix] For non-git directories, use --allow-untracked to enable untracked/ fallback.");
173532
173725
  }
173533
173726
  const detected = resolution.detectedProject;
173534
173727
  const projectRoot = resolution.projectRoot;
173535
- if (detected) {
173536
- const { writeLastProjectRoot: writeLastProjectRoot2 } = await Promise.resolve().then(() => (init_launch_root(), launch_root_exports));
173537
- writeLastProjectRoot2(detected.rootPath);
173538
- }
173728
+ if (detected) writeLastProjectRoot2(detected.rootPath);
173539
173729
  const allowUntracked = args["allow-untracked"] ?? false;
173540
- const toolProfile = resolveToolProfile({ explicit: args.mode, envValue: process.env.MEMORIX_MODE, fallback: "micro" });
173541
- const serverOptions = detected ? { toolProfile, deferProjectRuntimeInit: true } : { allowUntrackedFallback: allowUntracked, deferProjectInitUntilBound: !allowUntracked, deferProjectRuntimeInit: true, toolProfile };
173542
- const { server, projectId, deferredInit, switchProject } = await createMemorixServer2(projectRoot, void 0, void 0, serverOptions);
173730
+ const toolProfile = resolveToolProfile({
173731
+ explicit: args.mode,
173732
+ envValue: process.env.MEMORIX_MODE,
173733
+ fallback: "micro"
173734
+ });
173543
173735
  const transport = new StdioServerTransport(startupGate.input, process.stdout);
173544
- await server.connect(transport);
173545
- startupGate.markReady();
173546
- console.error(`[memorix] MCP Server running on stdio (project: ${projectId})`);
173547
- console.error(`[memorix] Project root: ${detected?.rootPath ?? projectRoot}`);
173548
- const tryRootsSwitch = async () => {
173549
- try {
173550
- const { roots } = await server.server.listRoots();
173551
- if (!roots || roots.length === 0) return;
173552
- for (const root of roots) {
173553
- if (!root.uri.startsWith("file://")) continue;
173554
- const rootPath = mcpFileUriToPath(root.uri);
173555
- if (!rootPath) continue;
173556
- const rootDetected = detectProject2(rootPath);
173557
- if (rootDetected) {
173558
- const switched = await switchProject(rootPath);
173736
+ const createBridge = async () => {
173737
+ const bridge = await createModernMcpBridge2({
173738
+ projectRoot,
173739
+ allowUntrackedFallback: allowUntracked,
173740
+ deferProjectInitUntilBound: !allowUntracked,
173741
+ deferProjectRuntimeInit: true,
173742
+ toolProfile
173743
+ });
173744
+ const tryRootsSwitch = async () => {
173745
+ try {
173746
+ if (bridge.memorix.isExplicitlyBound()) return;
173747
+ const { roots } = await bridge.server.listRoots();
173748
+ for (const root of roots ?? []) {
173749
+ if (!root.uri.startsWith("file://")) continue;
173750
+ const rootPath = mcpFileUriToPath(root.uri);
173751
+ if (!rootPath) continue;
173752
+ const switched = await bridge.memorix.switchProject(rootPath, "mcp-roots");
173559
173753
  if (switched) {
173560
- console.error(`[memorix] [UPDATED] Project updated via MCP roots: ${rootDetected.id}`);
173754
+ console.error(`[memorix] [UPDATED] Project updated via MCP roots: ${rootPath}`);
173755
+ return;
173561
173756
  }
173562
- return;
173563
- }
173564
- const subGit = findGitInSubdirs2(rootPath);
173565
- if (subGit) {
173566
- const switched = await switchProject(subGit);
173567
- if (switched) {
173757
+ const subGit = findGitInSubdirs2(rootPath);
173758
+ if (subGit && await bridge.memorix.switchProject(subGit, "mcp-roots")) {
173568
173759
  console.error(`[memorix] [UPDATED] Project updated via MCP roots (subdir): ${subGit}`);
173760
+ return;
173569
173761
  }
173570
- return;
173571
173762
  }
173763
+ } catch (error) {
173764
+ console.error(`[memorix] MCP roots not available (${error instanceof Error ? error.message : "unsupported"})`);
173572
173765
  }
173573
- } catch (err) {
173574
- console.error(`[memorix] MCP roots not available (${err.message ?? "unsupported"})`);
173575
- }
173576
- };
173577
- try {
173578
- const { RootsListChangedNotificationSchema } = await import("@modelcontextprotocol/sdk/types.js");
173579
- server.server.setNotificationHandler(RootsListChangedNotificationSchema, async () => {
173580
- console.error(`[memorix] Roots changed \u2014 re-detecting project...`);
173766
+ };
173767
+ bridge.server.setNotificationHandler("notifications/roots/list_changed", async () => {
173581
173768
  await tryRootsSwitch();
173582
173769
  });
173583
- } catch {
173770
+ const deferredInitTimer = setTimeout(() => {
173771
+ bridge.memorix.deferredInit().catch((error) => {
173772
+ console.error(`[memorix] Deferred init error: ${error instanceof Error ? error.message : String(error)}`);
173773
+ });
173774
+ }, 5e3);
173775
+ deferredInitTimer.unref?.();
173776
+ const originalClose = bridge.close.bind(bridge);
173777
+ bridge.close = async () => {
173778
+ clearTimeout(deferredInitTimer);
173779
+ await originalClose();
173780
+ };
173781
+ return bridge;
173782
+ };
173783
+ stdioHandle = serveStdio(createBridge, {
173784
+ transport,
173785
+ legacy: "serve",
173786
+ onerror: (error) => console.error(`[memorix] stdio MCP error: ${error.message}`)
173787
+ });
173788
+ startupGate.markReady();
173789
+ if (stdinEndedBeforeHandle) {
173790
+ void stdioHandle.close().catch((error) => {
173791
+ console.error(`[memorix] stdio close error: ${error instanceof Error ? error.message : String(error)}`);
173792
+ });
173584
173793
  }
173585
- const deferredInitTimer = setTimeout(() => {
173586
- deferredInit().catch((e2) => console.error(`[memorix] Deferred init error:`, e2));
173587
- }, 5e3);
173588
- deferredInitTimer.unref?.();
173794
+ console.error(`[memorix] MCP Server running on stdio (profile: ${toolProfile}, project: ${detected?.id ?? "deferred"})`);
173795
+ console.error(`[memorix] Project root: ${detected?.rootPath ?? projectRoot}`);
173589
173796
  Promise.resolve().then(() => (init_update_checker(), update_checker_exports)).then((m2) => m2.checkForUpdates()).catch(() => {
173590
173797
  });
173591
173798
  }