@memoraone/mcp 0.1.38 → 0.1.39

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 (4) hide show
  1. package/dist/cli.cjs +2091 -398
  2. package/dist/daemon.cjs +526 -89
  3. package/dist/index.cjs +525 -88
  4. package/package.json +11 -11
package/dist/daemon.cjs CHANGED
@@ -89,7 +89,15 @@ var HASH_SOCKET_FILENAME_RE = new RegExp(
89
89
  `^mcp-[0-9a-f]{${BINDING_SOCKET_HASH_LENGTH}}\\.sock$`,
90
90
  "i"
91
91
  );
92
- var IDE_TYPES = ["cursor", "copilot-vscode", "jetbrains"];
92
+ var IDE_TYPES = [
93
+ "cursor",
94
+ "copilot-vscode",
95
+ "jetbrains",
96
+ "claude-code",
97
+ "windsurf",
98
+ "opencode",
99
+ "codex"
100
+ ];
93
101
  var IDE_TYPE_SET = new Set(IDE_TYPES);
94
102
  function parseIdeType(value) {
95
103
  if (value === void 0 || value.trim() === "" || !IDE_TYPE_SET.has(value)) {
@@ -107,16 +115,19 @@ function parseIdeTypeFromArgv(args) {
107
115
  }
108
116
  return parseIdeType(args[idx + 1]);
109
117
  }
110
- function resolveBindingIdeType(env2 = process.env) {
118
+ function resolveBindingIdeType(env2 = process.env, ideTypeOverride) {
119
+ if (ideTypeOverride !== void 0) {
120
+ return ideTypeOverride;
121
+ }
111
122
  return resolveIdeTypeFromEnv(env2) ?? "";
112
123
  }
113
- function getBindingSocketFilename(binding, env2 = process.env) {
114
- const ideType = resolveBindingIdeType(env2);
124
+ function getBindingSocketFilename(binding, env2 = process.env, ideTypeOverride) {
125
+ const ideType = resolveBindingIdeType(env2, ideTypeOverride);
115
126
  const hash = hashBindingIdentity(binding.repositoryBindingId, binding.workspaceRoot, ideType);
116
127
  return `mcp-${hash}.sock`;
117
128
  }
118
- function getBindingSocketPath(binding, env2 = process.env) {
119
- return path2.join(BASE_DIR, getBindingSocketFilename(binding, env2));
129
+ function getBindingSocketPath(binding, env2 = process.env, ideTypeOverride) {
130
+ return path2.join(BASE_DIR, getBindingSocketFilename(binding, env2, ideTypeOverride));
120
131
  }
121
132
  function ensureBaseDir() {
122
133
  fs.mkdirSync(BASE_DIR, { recursive: true });
@@ -1501,7 +1512,7 @@ var EnvSchema = import_v4.z.object({
1501
1512
  MEMORAONE_AGENT_NAME: import_v4.z.string().min(1).optional(),
1502
1513
  MEMORAONE_AGENT_TYPE: import_v4.z.string().min(1).optional(),
1503
1514
  MEMORAONE_SOURCE: import_v4.z.string().min(1).optional(),
1504
- MEMORAONE_IDE_TYPE: import_v4.z.enum(["cursor", "copilot-vscode", "jetbrains"]).optional(),
1515
+ MEMORAONE_IDE_TYPE: import_v4.z.enum(["cursor", "copilot-vscode", "jetbrains", "claude-code", "windsurf", "opencode", "codex"]).optional(),
1505
1516
  MEMORAONE_WORKLOG: import_v4.z.string().min(1).optional(),
1506
1517
  MEMORAONE_HEARTBEAT: import_v4.z.string().min(1).optional(),
1507
1518
  MEMORAONE_HEARTBEAT_INTERVAL_MS: import_v4.z.string().min(1).optional()
@@ -1550,7 +1561,9 @@ var config2 = {
1550
1561
  devMode: parseBooleanFlag2(parsed.data.MEMORAONE_DEV_MODE, false),
1551
1562
  worklogEnabled: parseBooleanFlag2(parsed.data.MEMORAONE_WORKLOG, true),
1552
1563
  heartbeatEnabled: parseBooleanFlag2(parsed.data.MEMORAONE_HEARTBEAT, true),
1553
- heartbeatIntervalMs: Number.parseInt(parsed.data.MEMORAONE_HEARTBEAT_INTERVAL_MS ?? "30000", 10)
1564
+ // Cadence is owned by LOCAL_MCP_HEARTBEAT_INTERVAL_MS in heartbeat.ts (1_000).
1565
+ // Env override is accepted for forward-compat but the timer path ignores it.
1566
+ heartbeatIntervalMs: Number.parseInt(parsed.data.MEMORAONE_HEARTBEAT_INTERVAL_MS ?? "1000", 10)
1554
1567
  };
1555
1568
 
1556
1569
  // src/initializeBinding.ts
@@ -1842,8 +1855,79 @@ var logCommandShape = {
1842
1855
  // src/tools/bindingStatus.ts
1843
1856
  var bindingStatusShape = {};
1844
1857
 
1845
- // src/tools/handlers/postEvent.ts
1858
+ // src/tools/listTimeline.ts
1846
1859
  var import_v411 = require("zod/v4");
1860
+ var listTimelineDescription = "List timeline events for the project bound to this Local MCP installation.";
1861
+ var listTimelineInputSchema = import_v411.z.object({
1862
+ since: import_v411.z.string().optional(),
1863
+ concept: import_v411.z.string().optional(),
1864
+ kind: import_v411.z.union([import_v411.z.string(), import_v411.z.array(import_v411.z.string())]).optional(),
1865
+ sort: import_v411.z.enum(["newest", "oldest"]).optional(),
1866
+ limit: import_v411.z.number().int().min(1).max(200).optional(),
1867
+ cursor: import_v411.z.string().optional()
1868
+ }).strict();
1869
+
1870
+ // src/tools/listConcepts.ts
1871
+ var import_v412 = require("zod/v4");
1872
+ var listConceptsDescription = "List concepts for the project bound to this Local MCP installation.";
1873
+ var listConceptsInputSchema = import_v412.z.object({
1874
+ q: import_v412.z.string().min(1).optional(),
1875
+ tag: import_v412.z.string().min(1).optional(),
1876
+ parent_id: import_v412.z.string().min(1).optional(),
1877
+ limit: import_v412.z.number().int().min(1).max(200).optional(),
1878
+ cursor: import_v412.z.string().min(1).optional()
1879
+ }).strict();
1880
+
1881
+ // src/tools/getConcept.ts
1882
+ var import_v413 = require("zod/v4");
1883
+ var getConceptDescription = "Get one concept by ID from the project bound to this Local MCP installation.";
1884
+ var getConceptInputSchema = import_v413.z.object({
1885
+ id: import_v413.z.string().trim().min(1)
1886
+ }).strict();
1887
+
1888
+ // src/tools/createConceptVersion.ts
1889
+ var import_v414 = require("zod/v4");
1890
+ var createConceptVersionDescription = "Create a version of a concept in the project bound to this Local MCP installation.";
1891
+ var createConceptVersionInputSchema = import_v414.z.object({
1892
+ id: import_v414.z.string().trim().min(1),
1893
+ value: import_v414.z.unknown(),
1894
+ reason: import_v414.z.string().optional(),
1895
+ confidence: import_v414.z.number().finite().min(0).max(1).optional(),
1896
+ source_ref: import_v414.z.string().optional(),
1897
+ tags: import_v414.z.array(import_v414.z.string()).optional(),
1898
+ parent_id: import_v414.z.union([import_v414.z.string(), import_v414.z.null()]).optional()
1899
+ }).strict();
1900
+ function isJsonValue(value) {
1901
+ if (value === null) return true;
1902
+ if (typeof value === "boolean" || typeof value === "string") return true;
1903
+ if (typeof value === "number") return Number.isFinite(value);
1904
+ if (Array.isArray(value)) return value.every(isJsonValue);
1905
+ if (typeof value !== "object") return false;
1906
+ const prototype = Object.getPrototypeOf(value);
1907
+ if (prototype !== Object.prototype && prototype !== null) return false;
1908
+ return Object.values(value).every(isJsonValue);
1909
+ }
1910
+
1911
+ // src/tools/toolInventory.ts
1912
+ var LOCAL_MCP_TOOL_NAMES = [
1913
+ "memora_ask_with_memory",
1914
+ "memora_post_event",
1915
+ "memora_create_fact",
1916
+ "memora_add_personal_context",
1917
+ "memora_get_personal_context",
1918
+ "memora_log_intent",
1919
+ "memora_log_change_summary",
1920
+ "memora_log_tool_result",
1921
+ "memora_log_command",
1922
+ "memora_status",
1923
+ "memora_list_timeline",
1924
+ "memora_list_concepts",
1925
+ "memora_get_concept",
1926
+ "memora_create_concept_version"
1927
+ ];
1928
+
1929
+ // src/tools/handlers/postEvent.ts
1930
+ var import_v415 = require("zod/v4");
1847
1931
  var crypto4 = __toESM(require("crypto"), 1);
1848
1932
 
1849
1933
  // src/runContext.ts
@@ -1899,14 +1983,14 @@ function generateRunId() {
1899
1983
  }
1900
1984
 
1901
1985
  // src/tools/handlers/postEvent.ts
1902
- var postEventInputSchema = import_v411.z.object({
1903
- kind: import_v411.z.string().min(1),
1904
- actor: import_v411.z.object({
1905
- identifier: import_v411.z.string().min(1),
1906
- id: import_v411.z.string().min(1).optional()
1986
+ var postEventInputSchema = import_v415.z.object({
1987
+ kind: import_v415.z.string().min(1),
1988
+ actor: import_v415.z.object({
1989
+ identifier: import_v415.z.string().min(1),
1990
+ id: import_v415.z.string().min(1).optional()
1907
1991
  }),
1908
- content: import_v411.z.record(import_v411.z.string(), import_v411.z.any()),
1909
- metadata: import_v411.z.record(import_v411.z.string(), import_v411.z.any()).optional()
1992
+ content: import_v415.z.record(import_v415.z.string(), import_v415.z.any()),
1993
+ metadata: import_v415.z.record(import_v415.z.string(), import_v415.z.any()).optional()
1910
1994
  });
1911
1995
  function buildPostEventContentFields(content) {
1912
1996
  if (typeof content.message === "string") {
@@ -1978,10 +2062,10 @@ async function handlePostEvent(client, args) {
1978
2062
  }
1979
2063
 
1980
2064
  // src/tools/handlers/createFact.ts
1981
- var import_v412 = require("zod/v4");
1982
- var createFactInputSchema = import_v412.z.object({
1983
- content: import_v412.z.string().min(1),
1984
- metadata: import_v412.z.record(import_v412.z.string(), import_v412.z.any()).optional()
2065
+ var import_v416 = require("zod/v4");
2066
+ var createFactInputSchema = import_v416.z.object({
2067
+ content: import_v416.z.string().min(1),
2068
+ metadata: import_v416.z.record(import_v416.z.string(), import_v416.z.any()).optional()
1985
2069
  });
1986
2070
  async function handleCreateFact(client, args) {
1987
2071
  const parsed2 = createFactInputSchema.parse(args ?? {});
@@ -2026,13 +2110,13 @@ async function handleCreateFact(client, args) {
2026
2110
  }
2027
2111
 
2028
2112
  // src/tools/handlers/addPersonalContext.ts
2029
- var import_v413 = require("zod/v4");
2030
- var addPersonalContextInputSchema = import_v413.z.object({
2031
- content: import_v413.z.string().min(1),
2032
- category: import_v413.z.string().optional(),
2033
- tags: import_v413.z.array(import_v413.z.string()).optional(),
2034
- scope_type: import_v413.z.enum(["general", "project"]).optional(),
2035
- scope_id: import_v413.z.string().optional()
2113
+ var import_v417 = require("zod/v4");
2114
+ var addPersonalContextInputSchema = import_v417.z.object({
2115
+ content: import_v417.z.string().min(1),
2116
+ category: import_v417.z.string().optional(),
2117
+ tags: import_v417.z.array(import_v417.z.string()).optional(),
2118
+ scope_type: import_v417.z.enum(["general", "project"]).optional(),
2119
+ scope_id: import_v417.z.string().optional()
2036
2120
  });
2037
2121
  async function handleAddPersonalContext(client, args) {
2038
2122
  const parsed2 = addPersonalContextInputSchema.parse(args ?? {});
@@ -2068,12 +2152,12 @@ async function handleAddPersonalContext(client, args) {
2068
2152
  }
2069
2153
 
2070
2154
  // src/tools/handlers/getPersonalContext.ts
2071
- var import_v414 = require("zod/v4");
2072
- var getPersonalContextInputSchema = import_v414.z.object({
2073
- query: import_v414.z.string().optional(),
2074
- scope_type: import_v414.z.enum(["general", "project"]).optional(),
2075
- scope_id: import_v414.z.string().optional(),
2076
- limit: import_v414.z.number().int().positive().optional()
2155
+ var import_v418 = require("zod/v4");
2156
+ var getPersonalContextInputSchema = import_v418.z.object({
2157
+ query: import_v418.z.string().optional(),
2158
+ scope_type: import_v418.z.enum(["general", "project"]).optional(),
2159
+ scope_id: import_v418.z.string().optional(),
2160
+ limit: import_v418.z.number().int().positive().optional()
2077
2161
  });
2078
2162
  function buildPersonalContextPath(parsed2) {
2079
2163
  const params = new URLSearchParams();
@@ -2110,13 +2194,13 @@ async function handleGetPersonalContext(client, args) {
2110
2194
  }
2111
2195
 
2112
2196
  // src/tools/handlers/askWithMemory.ts
2113
- var import_v415 = require("zod/v4");
2114
- var askWithMemoryInputSchema = import_v415.z.object({
2115
- question: import_v415.z.string().min(1),
2116
- code_context: import_v415.z.object({
2117
- file_path: import_v415.z.string().optional(),
2118
- selected_text: import_v415.z.string().optional(),
2119
- language: import_v415.z.string().optional()
2197
+ var import_v419 = require("zod/v4");
2198
+ var askWithMemoryInputSchema = import_v419.z.object({
2199
+ question: import_v419.z.string().min(1),
2200
+ code_context: import_v419.z.object({
2201
+ file_path: import_v419.z.string().optional(),
2202
+ selected_text: import_v419.z.string().optional(),
2203
+ language: import_v419.z.string().optional()
2120
2204
  }).optional()
2121
2205
  });
2122
2206
  function isAskWithMemoryResponse(value) {
@@ -2152,13 +2236,13 @@ async function handleAskWithMemory(client, args) {
2152
2236
  }
2153
2237
 
2154
2238
  // src/tools/handlers/logIntent.ts
2155
- var import_v416 = require("zod/v4");
2156
- var logIntentInputSchema = import_v416.z.object({
2157
- intent: import_v416.z.enum(["task", "decision"]),
2158
- message: import_v416.z.string().min(1),
2159
- context: import_v416.z.record(import_v416.z.string(), import_v416.z.any()).optional(),
2160
- intent_source: import_v416.z.string().optional().default("cursor_chat"),
2161
- run_id: import_v416.z.string().min(1).optional()
2239
+ var import_v420 = require("zod/v4");
2240
+ var logIntentInputSchema = import_v420.z.object({
2241
+ intent: import_v420.z.enum(["task", "decision"]),
2242
+ message: import_v420.z.string().min(1),
2243
+ context: import_v420.z.record(import_v420.z.string(), import_v420.z.any()).optional(),
2244
+ intent_source: import_v420.z.string().optional().default("cursor_chat"),
2245
+ run_id: import_v420.z.string().min(1).optional()
2162
2246
  });
2163
2247
  async function handleLogIntent(client, args) {
2164
2248
  const parsed2 = logIntentInputSchema.parse(args ?? {});
@@ -2200,18 +2284,18 @@ async function handleLogIntent(client, args) {
2200
2284
  }
2201
2285
 
2202
2286
  // src/tools/handlers/logChangeSummary.ts
2203
- var import_v417 = require("zod/v4");
2204
- var logChangeSummaryInputSchema = import_v417.z.object({
2205
- summary: import_v417.z.string().min(1),
2206
- scope: import_v417.z.string().min(1).optional(),
2207
- files: import_v417.z.array(import_v417.z.string().min(1)).optional(),
2208
- stats: import_v417.z.object({
2209
- files: import_v417.z.number().int().nonnegative().optional(),
2210
- add: import_v417.z.number().int().nonnegative().optional(),
2211
- del: import_v417.z.number().int().nonnegative().optional()
2287
+ var import_v421 = require("zod/v4");
2288
+ var logChangeSummaryInputSchema = import_v421.z.object({
2289
+ summary: import_v421.z.string().min(1),
2290
+ scope: import_v421.z.string().min(1).optional(),
2291
+ files: import_v421.z.array(import_v421.z.string().min(1)).optional(),
2292
+ stats: import_v421.z.object({
2293
+ files: import_v421.z.number().int().nonnegative().optional(),
2294
+ add: import_v421.z.number().int().nonnegative().optional(),
2295
+ del: import_v421.z.number().int().nonnegative().optional()
2212
2296
  }).optional(),
2213
- commit: import_v417.z.string().min(1).optional(),
2214
- run_id: import_v417.z.string().min(1).optional()
2297
+ commit: import_v421.z.string().min(1).optional(),
2298
+ run_id: import_v421.z.string().min(1).optional()
2215
2299
  });
2216
2300
  async function handleLogChangeSummary(client, args) {
2217
2301
  const parsed2 = logChangeSummaryInputSchema.parse(args ?? {});
@@ -2246,17 +2330,17 @@ async function handleLogChangeSummary(client, args) {
2246
2330
  }
2247
2331
 
2248
2332
  // src/tools/handlers/logToolResult.ts
2249
- var import_v418 = require("zod/v4");
2250
- var logToolResultInputSchema = import_v418.z.object({
2251
- tool: import_v418.z.string().min(1),
2252
- status: import_v418.z.enum(["ok", "error", "partial"]),
2253
- summary: import_v418.z.string().min(1),
2254
- run_id: import_v418.z.string().min(1).optional(),
2255
- duration_ms: import_v418.z.number().int().nonnegative().optional(),
2256
- error_code: import_v418.z.string().min(1).optional(),
2257
- error_message: import_v418.z.string().min(1).optional(),
2258
- error_kind: import_v418.z.enum(["infra", "logic", "auth", "rate_limit", "validation", "unknown"]).optional(),
2259
- stats: import_v418.z.record(import_v418.z.string(), import_v418.z.any()).optional()
2333
+ var import_v422 = require("zod/v4");
2334
+ var logToolResultInputSchema = import_v422.z.object({
2335
+ tool: import_v422.z.string().min(1),
2336
+ status: import_v422.z.enum(["ok", "error", "partial"]),
2337
+ summary: import_v422.z.string().min(1),
2338
+ run_id: import_v422.z.string().min(1).optional(),
2339
+ duration_ms: import_v422.z.number().int().nonnegative().optional(),
2340
+ error_code: import_v422.z.string().min(1).optional(),
2341
+ error_message: import_v422.z.string().min(1).optional(),
2342
+ error_kind: import_v422.z.enum(["infra", "logic", "auth", "rate_limit", "validation", "unknown"]).optional(),
2343
+ stats: import_v422.z.record(import_v422.z.string(), import_v422.z.any()).optional()
2260
2344
  });
2261
2345
  async function handleLogToolResult(client, args) {
2262
2346
  const parsed2 = logToolResultInputSchema.parse(args ?? {});
@@ -2294,15 +2378,15 @@ async function handleLogToolResult(client, args) {
2294
2378
  }
2295
2379
 
2296
2380
  // src/tools/handlers/logCommand.ts
2297
- var import_v419 = require("zod/v4");
2298
- var logCommandInputSchema = import_v419.z.object({
2299
- cmd: import_v419.z.string().min(1),
2300
- summary: import_v419.z.string().min(1),
2301
- cwd: import_v419.z.string().min(1).optional(),
2302
- exit_code: import_v419.z.number().int().optional(),
2303
- duration_ms: import_v419.z.number().int().nonnegative().optional(),
2304
- run_id: import_v419.z.string().min(1).optional(),
2305
- stats: import_v419.z.record(import_v419.z.string(), import_v419.z.any()).optional()
2381
+ var import_v423 = require("zod/v4");
2382
+ var logCommandInputSchema = import_v423.z.object({
2383
+ cmd: import_v423.z.string().min(1),
2384
+ summary: import_v423.z.string().min(1),
2385
+ cwd: import_v423.z.string().min(1).optional(),
2386
+ exit_code: import_v423.z.number().int().optional(),
2387
+ duration_ms: import_v423.z.number().int().nonnegative().optional(),
2388
+ run_id: import_v423.z.string().min(1).optional(),
2389
+ stats: import_v423.z.record(import_v423.z.string(), import_v423.z.any()).optional()
2306
2390
  });
2307
2391
  async function handleLogCommand(client, args) {
2308
2392
  const parsed2 = logCommandInputSchema.parse(args ?? {});
@@ -2337,6 +2421,244 @@ async function handleLogCommand(client, args) {
2337
2421
  return { ok: true };
2338
2422
  }
2339
2423
 
2424
+ // src/tools/responseProjection.ts
2425
+ var timelineItemKeys = [
2426
+ "id",
2427
+ "ts",
2428
+ "kind",
2429
+ "concept",
2430
+ "old_value",
2431
+ "new_value",
2432
+ "reason",
2433
+ "confidence",
2434
+ "links",
2435
+ "source_ref",
2436
+ "redacted",
2437
+ "redaction_reason",
2438
+ "summary",
2439
+ "consolidated_of"
2440
+ ];
2441
+ var conceptVersionKeys = [
2442
+ "version",
2443
+ "ts",
2444
+ "reason",
2445
+ "confidence",
2446
+ "source_ref",
2447
+ "value"
2448
+ ];
2449
+ function invalidResponse() {
2450
+ throw new Error("Invalid Memora response");
2451
+ }
2452
+ function isRecord(value) {
2453
+ return typeof value === "object" && value !== null && !Array.isArray(value);
2454
+ }
2455
+ function pickFields(raw, keys) {
2456
+ const result = {};
2457
+ for (const key of keys) {
2458
+ if (Object.prototype.hasOwnProperty.call(raw, key) && raw[key] !== void 0) {
2459
+ result[key] = raw[key];
2460
+ }
2461
+ }
2462
+ return result;
2463
+ }
2464
+ function pickConceptVersion(raw) {
2465
+ return pickFields(raw, conceptVersionKeys);
2466
+ }
2467
+ function pickConceptItem(raw) {
2468
+ if (typeof raw.id !== "string" || raw.id.trim() === "") invalidResponse();
2469
+ const item = { id: raw.id };
2470
+ if (Object.prototype.hasOwnProperty.call(raw, "tags")) {
2471
+ if (!Array.isArray(raw.tags) || !raw.tags.every((tag) => typeof tag === "string")) {
2472
+ invalidResponse();
2473
+ }
2474
+ item.tags = raw.tags;
2475
+ }
2476
+ if (Object.prototype.hasOwnProperty.call(raw, "parent_id")) {
2477
+ if (raw.parent_id !== null && typeof raw.parent_id !== "string") invalidResponse();
2478
+ item.parent_id = raw.parent_id;
2479
+ }
2480
+ if (Object.prototype.hasOwnProperty.call(raw, "latest")) {
2481
+ if (raw.latest === null) {
2482
+ item.latest = null;
2483
+ } else if (isRecord(raw.latest)) {
2484
+ item.latest = pickConceptVersion(raw.latest);
2485
+ } else {
2486
+ invalidResponse();
2487
+ }
2488
+ }
2489
+ return item;
2490
+ }
2491
+ function normalizeCursor(raw) {
2492
+ for (const key of ["next_cursor", "nextCursor"]) {
2493
+ if (!Object.prototype.hasOwnProperty.call(raw, key)) continue;
2494
+ const value = raw[key];
2495
+ if (value === null) return null;
2496
+ if (typeof value === "string") return value;
2497
+ invalidResponse();
2498
+ }
2499
+ return null;
2500
+ }
2501
+ function projectTimelineResponse(data) {
2502
+ if (!isRecord(data) || !Array.isArray(data.items) || !isRecord(data.page)) {
2503
+ invalidResponse();
2504
+ }
2505
+ if (typeof data.page.limit !== "number" || !Number.isFinite(data.page.limit) || data.page.sort !== "newest" && data.page.sort !== "oldest") {
2506
+ invalidResponse();
2507
+ }
2508
+ const items = data.items.map((entry) => {
2509
+ if (!isRecord(entry)) invalidResponse();
2510
+ return pickFields(entry, timelineItemKeys);
2511
+ });
2512
+ return {
2513
+ items,
2514
+ page: {
2515
+ limit: data.page.limit,
2516
+ sort: data.page.sort,
2517
+ next_cursor: normalizeCursor(data.page)
2518
+ }
2519
+ };
2520
+ }
2521
+ function projectConceptListResponse(data, requestedLimit) {
2522
+ if (!isRecord(data)) invalidResponse();
2523
+ let entries;
2524
+ if (Object.prototype.hasOwnProperty.call(data, "rows")) {
2525
+ entries = data.rows;
2526
+ } else if (Object.prototype.hasOwnProperty.call(data, "items")) {
2527
+ entries = data.items;
2528
+ } else {
2529
+ invalidResponse();
2530
+ }
2531
+ if (!Array.isArray(entries)) invalidResponse();
2532
+ let cursorSource = data;
2533
+ if (!Object.prototype.hasOwnProperty.call(data, "next_cursor") && !Object.prototype.hasOwnProperty.call(data, "nextCursor") && Object.prototype.hasOwnProperty.call(data, "page")) {
2534
+ if (!isRecord(data.page)) invalidResponse();
2535
+ cursorSource = data.page;
2536
+ }
2537
+ return {
2538
+ items: entries.map((entry) => {
2539
+ if (!isRecord(entry)) invalidResponse();
2540
+ return pickConceptItem(entry);
2541
+ }),
2542
+ page: {
2543
+ limit: requestedLimit ?? 50,
2544
+ next_cursor: normalizeCursor(cursorSource)
2545
+ }
2546
+ };
2547
+ }
2548
+ function projectConceptResponse(data) {
2549
+ if (!isRecord(data)) invalidResponse();
2550
+ const item = pickConceptItem(data);
2551
+ if (!Object.prototype.hasOwnProperty.call(data, "history")) {
2552
+ return { ...item, history: [] };
2553
+ }
2554
+ if (!Array.isArray(data.history)) invalidResponse();
2555
+ const history = data.history.map((entry) => {
2556
+ if (!isRecord(entry)) invalidResponse();
2557
+ return pickConceptVersion(entry);
2558
+ });
2559
+ return { ...item, history };
2560
+ }
2561
+ function projectCreatedConceptVersionResponse(data) {
2562
+ if (!isRecord(data)) invalidResponse();
2563
+ return pickConceptItem(data);
2564
+ }
2565
+
2566
+ // src/tools/handlers/toolRequestError.ts
2567
+ function rethrowToolRequestError(toolName, error) {
2568
+ if (error instanceof SyntaxError) {
2569
+ throw new Error("Invalid Memora response");
2570
+ }
2571
+ if (!(error instanceof MemoraOneHttpError)) throw error;
2572
+ let detail = "request failed";
2573
+ if (error.status === 401) detail = "authentication failed";
2574
+ else if (error.status === 403) detail = "connection unavailable";
2575
+ else if (error.status === 404) detail = "resource not found";
2576
+ else if (error.status === 409) detail = "conflict";
2577
+ else if (error.status >= 500) detail = "backend error";
2578
+ throw new Error(`${toolName} failed: ${error.status} ${detail}`);
2579
+ }
2580
+
2581
+ // src/tools/handlers/listTimeline.ts
2582
+ function buildQuery(input) {
2583
+ const parts = [];
2584
+ const append = (key, value) => {
2585
+ parts.push(`${encodeURIComponent(key)}=${encodeURIComponent(value)}`);
2586
+ };
2587
+ if (input.since !== void 0) append("since", input.since);
2588
+ if (input.concept !== void 0) append("concept", input.concept);
2589
+ if (input.kind !== void 0) {
2590
+ for (const kind of Array.isArray(input.kind) ? input.kind : [input.kind]) {
2591
+ append("kind", kind);
2592
+ }
2593
+ }
2594
+ if (input.sort !== void 0) append("sort", input.sort);
2595
+ if (input.limit !== void 0) append("limit", String(input.limit));
2596
+ if (input.cursor !== void 0) append("cursor", input.cursor);
2597
+ return parts.length === 0 ? "" : `?${parts.join("&")}`;
2598
+ }
2599
+ async function handleListTimeline(client, args) {
2600
+ const input = listTimelineInputSchema.parse(args ?? {});
2601
+ try {
2602
+ return projectTimelineResponse(await client.get(`/timeline${buildQuery(input)}`));
2603
+ } catch (error) {
2604
+ rethrowToolRequestError("memora_list_timeline", error);
2605
+ }
2606
+ }
2607
+
2608
+ // src/tools/handlers/listConcepts.ts
2609
+ function buildQuery2(input) {
2610
+ const parts = [];
2611
+ const append = (key, value) => {
2612
+ parts.push(`${encodeURIComponent(key)}=${encodeURIComponent(value)}`);
2613
+ };
2614
+ if (input.q !== void 0) append("q", input.q);
2615
+ if (input.tag !== void 0) append("tag", input.tag);
2616
+ if (input.parent_id !== void 0) append("parent_id", input.parent_id);
2617
+ if (input.limit !== void 0) append("limit", String(input.limit));
2618
+ if (input.cursor !== void 0) append("cursor", input.cursor);
2619
+ return parts.length === 0 ? "" : `?${parts.join("&")}`;
2620
+ }
2621
+ async function handleListConcepts(client, args) {
2622
+ const input = listConceptsInputSchema.parse(args ?? {});
2623
+ try {
2624
+ const data = await client.get(`/concepts${buildQuery2(input)}`);
2625
+ return projectConceptListResponse(data, input.limit);
2626
+ } catch (error) {
2627
+ rethrowToolRequestError("memora_list_concepts", error);
2628
+ }
2629
+ }
2630
+
2631
+ // src/tools/handlers/getConcept.ts
2632
+ async function handleGetConcept(client, args) {
2633
+ const input = getConceptInputSchema.parse(args ?? {});
2634
+ try {
2635
+ const data = await client.get(`/concepts/${encodeURIComponent(input.id)}`);
2636
+ return projectConceptResponse(data);
2637
+ } catch (error) {
2638
+ rethrowToolRequestError("memora_get_concept", error);
2639
+ }
2640
+ }
2641
+
2642
+ // src/tools/handlers/createConceptVersion.ts
2643
+ async function handleCreateConceptVersion(client, args) {
2644
+ const input = createConceptVersionInputSchema.parse(args ?? {});
2645
+ if (!isJsonValue(input.value)) {
2646
+ throw new Error("Invalid arguments: value must be a valid JSON value");
2647
+ }
2648
+ const body = { value: input.value };
2649
+ if (input.reason !== void 0) body.reason = input.reason;
2650
+ if (input.confidence !== void 0) body.confidence = input.confidence;
2651
+ if (input.source_ref !== void 0) body.source_ref = input.source_ref;
2652
+ if (input.tags !== void 0) body.tags = input.tags;
2653
+ if (input.parent_id !== void 0) body.parent_id = input.parent_id;
2654
+ try {
2655
+ const path14 = `/concepts/${encodeURIComponent(input.id)}/versions`;
2656
+ return projectCreatedConceptVersionResponse(await client.post(path14, body));
2657
+ } catch (error) {
2658
+ rethrowToolRequestError("memora_create_concept_version", error);
2659
+ }
2660
+ }
2661
+
2340
2662
  // src/tools/handlers/bindingStatus.ts
2341
2663
  function buildBindingStatus(binding, options = {}) {
2342
2664
  const status = {
@@ -2387,8 +2709,9 @@ function isHeartbeatDebugEnabled() {
2387
2709
  const value = String(process.env.MEMORAONE_DEBUG_HEARTBEAT ?? "").trim().toLowerCase();
2388
2710
  return ["1", "true", "yes", "on"].includes(value);
2389
2711
  }
2712
+ var LOCAL_MCP_HEARTBEAT_INTERVAL_MS = 1e3;
2390
2713
  function resolveHeartbeatIntervalMs() {
2391
- return Number.isFinite(config2.heartbeatIntervalMs) ? Math.max(1e3, config2.heartbeatIntervalMs) : 3e4;
2714
+ return LOCAL_MCP_HEARTBEAT_INTERVAL_MS;
2392
2715
  }
2393
2716
  function redactSensitiveText(text) {
2394
2717
  return text.replace(/mcs_[A-Za-z0-9_-]+/g, "mcs_[redacted]").replace(/mia_[A-Za-z0-9_-]+/g, "mia_[redacted]").replace(/mir_[A-Za-z0-9_-]+/g, "mir_[redacted]").replace(/mcc_[A-Za-z0-9_-]+/g, "mcc_[redacted]").replace(/Bearer\s+\S+/gi, "Bearer [redacted]");
@@ -2498,6 +2821,7 @@ async function sendProjectHeartbeat(client, ctx) {
2498
2821
  }
2499
2822
  function createDaemonHeartbeat(opts) {
2500
2823
  let interval = null;
2824
+ let runGeneration = 0;
2501
2825
  let client = null;
2502
2826
  let announced = false;
2503
2827
  let studioActive = null;
@@ -2566,21 +2890,24 @@ function createDaemonHeartbeat(opts) {
2566
2890
  studioActive = true;
2567
2891
  }
2568
2892
  };
2569
- const tick = async () => {
2570
- if (!client) return;
2893
+ const tick = async (generation) => {
2894
+ if (!client || generation !== runGeneration) return;
2571
2895
  const outcome = await sendProjectHeartbeat(client, ctx);
2896
+ if (generation !== runGeneration || !interval) return;
2572
2897
  applyHeartbeatOutcome(outcome);
2573
2898
  };
2574
2899
  const beginInterval = () => {
2575
2900
  if (interval) return;
2576
2901
  const intervalMs = resolveHeartbeatIntervalMs();
2902
+ const generation = runGeneration;
2577
2903
  log2(
2578
2904
  `daemon owns heartbeat for binding=${opts.binding.repositoryBindingId} project=${opts.binding.projectId} ideType=${ctx.ideType ?? "unknown"} interval=${intervalMs}ms`
2579
2905
  );
2580
- void tick();
2581
2906
  interval = setInterval(() => {
2582
- void tick();
2907
+ void tick(generation);
2583
2908
  }, intervalMs);
2909
+ interval.unref?.();
2910
+ void tick(generation);
2584
2911
  };
2585
2912
  const start = async () => {
2586
2913
  if (!config2.heartbeatEnabled) {
@@ -2613,6 +2940,7 @@ function createDaemonHeartbeat(opts) {
2613
2940
  }
2614
2941
  };
2615
2942
  const stop = () => {
2943
+ runGeneration += 1;
2616
2944
  if (interval) {
2617
2945
  clearInterval(interval);
2618
2946
  interval = null;
@@ -2632,7 +2960,7 @@ function createDaemonHeartbeat(opts) {
2632
2960
  return;
2633
2961
  }
2634
2962
  if (client && interval) {
2635
- void tick();
2963
+ void tick(runGeneration);
2636
2964
  }
2637
2965
  };
2638
2966
  const getIdeType = () => ctx.ideType;
@@ -2652,12 +2980,52 @@ function createDaemonHeartbeat(opts) {
2652
2980
  }
2653
2981
 
2654
2982
  // src/ideType.ts
2983
+ function mapReliableClientInfoName(name) {
2984
+ if (typeof name !== "string") {
2985
+ return void 0;
2986
+ }
2987
+ const normalized = name.trim().toLowerCase();
2988
+ if (normalized === "") {
2989
+ return void 0;
2990
+ }
2991
+ if (normalized === "claude-code") {
2992
+ return "claude-code";
2993
+ }
2994
+ if (normalized === "devin") {
2995
+ return "windsurf";
2996
+ }
2997
+ if (normalized === "windsurf" || /^windsurf[\s_-].+$/.test(normalized)) {
2998
+ return "windsurf";
2999
+ }
3000
+ return void 0;
3001
+ }
3002
+ function mapReliableHostIdentity(env2) {
3003
+ if (env2.WINDSURF_IDE_TYPE === "windsurf") {
3004
+ return "windsurf";
3005
+ }
3006
+ if (env2.ACP_BACKEND === "windsurf") {
3007
+ return "windsurf";
3008
+ }
3009
+ if (env2.__CFBundleIdentifier === "com.exafunction.windsurf") {
3010
+ return "windsurf";
3011
+ }
3012
+ return void 0;
3013
+ }
2655
3014
  function inferIdeType(params, options = {}) {
2656
3015
  const env2 = options.env ?? process.env;
2657
3016
  const argv = (options.argv ?? process.argv).join(" ").toLowerCase();
2658
- const configIdeType = options.configIdeType ?? config2.ideType;
2659
- if (configIdeType) {
2660
- return configIdeType;
3017
+ const hasExplicitConfigOption = Object.prototype.hasOwnProperty.call(options, "configIdeType");
3018
+ const explicitHint = hasExplicitConfigOption ? options.configIdeType : resolveIdeTypeFromEnv(env2) ?? config2.ideType;
3019
+ const fromClientInfo = mapReliableClientInfoName(params?.clientInfo?.name);
3020
+ if (fromClientInfo) {
3021
+ return fromClientInfo;
3022
+ }
3023
+ const fromHost = mapReliableHostIdentity(env2);
3024
+ if (fromHost) {
3025
+ return fromHost;
3026
+ }
3027
+ if (explicitHint) {
3028
+ return explicitHint;
2661
3029
  }
2662
3030
  const clientInfoName = String(params?.clientInfo?.name ?? "").toLowerCase();
2663
3031
  const clientInfoVersion = String(params?.clientInfo?.version ?? "").toLowerCase();
@@ -2814,7 +3182,11 @@ async function main(opts = {}) {
2814
3182
  `[memoraone-mcp] refreshed stale cached binding ${reconciled.binding.repositoryBindingId}: project=${reconciled.binding.projectId}`
2815
3183
  );
2816
3184
  try {
2817
- const socketPath = getBindingSocketPath(opts.daemonBindingHint);
3185
+ const socketPath = getBindingSocketPath(
3186
+ opts.daemonBindingHint,
3187
+ process.env,
3188
+ runtime.ideType ?? ""
3189
+ );
2818
3190
  writeBindingSidecar(socketPath, reconciled.binding, runtime.ideType ?? "");
2819
3191
  } catch (err) {
2820
3192
  console.error(
@@ -3007,6 +3379,71 @@ async function main(opts = {}) {
3007
3379
  }
3008
3380
  );
3009
3381
  registeredToolNames.push("memora_log_command");
3382
+ server.registerTool(
3383
+ "memora_list_timeline",
3384
+ {
3385
+ description: listTimelineDescription,
3386
+ inputSchema: listTimelineInputSchema
3387
+ },
3388
+ async (args) => runWithSessionContext(sessionContext, async () => {
3389
+ if (!runtime.client || !runtime.projectId) return notInitializedResult;
3390
+ const result = await handleListTimeline(runtime.client, args);
3391
+ return {
3392
+ content: [{ type: "text", text: JSON.stringify(result) }]
3393
+ };
3394
+ })
3395
+ );
3396
+ registeredToolNames.push("memora_list_timeline");
3397
+ server.registerTool(
3398
+ "memora_list_concepts",
3399
+ {
3400
+ description: listConceptsDescription,
3401
+ inputSchema: listConceptsInputSchema
3402
+ },
3403
+ async (args) => runWithSessionContext(sessionContext, async () => {
3404
+ if (!runtime.client || !runtime.projectId) return notInitializedResult;
3405
+ const result = await handleListConcepts(runtime.client, args);
3406
+ return {
3407
+ content: [{ type: "text", text: JSON.stringify(result) }]
3408
+ };
3409
+ })
3410
+ );
3411
+ registeredToolNames.push("memora_list_concepts");
3412
+ server.registerTool(
3413
+ "memora_get_concept",
3414
+ {
3415
+ description: getConceptDescription,
3416
+ inputSchema: getConceptInputSchema
3417
+ },
3418
+ async (args) => runWithSessionContext(sessionContext, async () => {
3419
+ if (!runtime.client || !runtime.projectId) return notInitializedResult;
3420
+ const result = await handleGetConcept(runtime.client, args);
3421
+ return {
3422
+ content: [{ type: "text", text: JSON.stringify(result) }]
3423
+ };
3424
+ })
3425
+ );
3426
+ registeredToolNames.push("memora_get_concept");
3427
+ server.registerTool(
3428
+ "memora_create_concept_version",
3429
+ {
3430
+ description: createConceptVersionDescription,
3431
+ inputSchema: createConceptVersionInputSchema
3432
+ },
3433
+ async (args) => runWithSessionContext(sessionContext, async () => {
3434
+ if (!runtime.client || !runtime.projectId) return notInitializedResult;
3435
+ const result = await handleCreateConceptVersion(runtime.client, args);
3436
+ return {
3437
+ content: [{ type: "text", text: JSON.stringify(result) }]
3438
+ };
3439
+ })
3440
+ );
3441
+ registeredToolNames.push("memora_create_concept_version");
3442
+ if (registeredToolNames.length !== LOCAL_MCP_TOOL_NAMES.length || registeredToolNames.some(
3443
+ (name) => !LOCAL_MCP_TOOL_NAMES.includes(name)
3444
+ )) {
3445
+ throw new Error("Local MCP tool registration inventory mismatch");
3446
+ }
3010
3447
  server.server.setRequestHandler(
3011
3448
  import_types.InitializeRequestSchema,
3012
3449
  async (request) => runWithSessionContext(sessionContext, async () => {
@@ -3249,7 +3686,7 @@ async function runDaemon() {
3249
3686
  const repositoryBindingId = parseBindingIdFromArgv();
3250
3687
  const binding = parseBindingFromEnv(repositoryBindingId);
3251
3688
  const ideType = parseIdeTypeFromArgv(process.argv.slice(2)) ?? config2.ideType ?? resolveIdeTypeFromEnv();
3252
- const socketPath = getBindingSocketPath(binding, process.env);
3689
+ const socketPath = getBindingSocketPath(binding, process.env, ideType);
3253
3690
  let nextSessionId = 1;
3254
3691
  let activeSessions = 0;
3255
3692
  let shuttingDown = false;