@memoraone/mcp 0.1.38 → 0.1.40

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 +10630 -2440
  2. package/dist/daemon.cjs +634 -90
  3. package/dist/index.cjs +770 -226
  4. package/package.json +4 -2
package/dist/daemon.cjs CHANGED
@@ -89,8 +89,50 @@ 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
+ "zed",
101
+ "kiro",
102
+ "visual-studio",
103
+ "cline",
104
+ "roo-code",
105
+ // dormant: unsupported for setup/connect
106
+ "auggie",
107
+ "continue",
108
+ // dormant: unsupported for setup/connect
109
+ "copilot-cli",
110
+ "kiro-cli",
111
+ "cline-cli",
112
+ "continue-cli",
113
+ // dormant: unsupported (no writer; wire id only)
114
+ "claude-desktop",
115
+ "gemini-cli",
116
+ // dormant: individual-user CLI unsupported; writer kept internal
117
+ "antigravity",
118
+ "antigravity-cli",
119
+ // Antigravity CLI (agy); shares MCP config with IDE; identity from clientInfo
120
+ "goose",
121
+ "junie",
122
+ "xcode",
123
+ "copilot-jetbrains",
124
+ "copilot-visual-studio"
125
+ ];
93
126
  var IDE_TYPE_SET = new Set(IDE_TYPES);
127
+ var IDE_TYPE_CLI_CHOICES = IDE_TYPES.join("|");
128
+ var IDE_TYPE_ALTERNATION = [...IDE_TYPES].sort((a, b) => b.length - a.length).join("|");
129
+ var LEGACY_SOCKET_FILENAME_RE = new RegExp(
130
+ `^mcp-([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})(?:-([0-9a-f]{12}))?(?:-(${IDE_TYPE_ALTERNATION}))?\\.sock$`,
131
+ "i"
132
+ );
133
+ var IDE_FROM_COMMAND_LINE_RE = new RegExp(
134
+ `--ide\\s+(${IDE_TYPE_ALTERNATION})(?:\\s|$)`
135
+ );
94
136
  function parseIdeType(value) {
95
137
  if (value === void 0 || value.trim() === "" || !IDE_TYPE_SET.has(value)) {
96
138
  return void 0;
@@ -107,16 +149,19 @@ function parseIdeTypeFromArgv(args) {
107
149
  }
108
150
  return parseIdeType(args[idx + 1]);
109
151
  }
110
- function resolveBindingIdeType(env2 = process.env) {
152
+ function resolveBindingIdeType(env2 = process.env, ideTypeOverride) {
153
+ if (ideTypeOverride !== void 0) {
154
+ return ideTypeOverride;
155
+ }
111
156
  return resolveIdeTypeFromEnv(env2) ?? "";
112
157
  }
113
- function getBindingSocketFilename(binding, env2 = process.env) {
114
- const ideType = resolveBindingIdeType(env2);
158
+ function getBindingSocketFilename(binding, env2 = process.env, ideTypeOverride) {
159
+ const ideType = resolveBindingIdeType(env2, ideTypeOverride);
115
160
  const hash = hashBindingIdentity(binding.repositoryBindingId, binding.workspaceRoot, ideType);
116
161
  return `mcp-${hash}.sock`;
117
162
  }
118
- function getBindingSocketPath(binding, env2 = process.env) {
119
- return path2.join(BASE_DIR, getBindingSocketFilename(binding, env2));
163
+ function getBindingSocketPath(binding, env2 = process.env, ideTypeOverride) {
164
+ return path2.join(BASE_DIR, getBindingSocketFilename(binding, env2, ideTypeOverride));
120
165
  }
121
166
  function ensureBaseDir() {
122
167
  fs.mkdirSync(BASE_DIR, { recursive: true });
@@ -1501,7 +1546,7 @@ var EnvSchema = import_v4.z.object({
1501
1546
  MEMORAONE_AGENT_NAME: import_v4.z.string().min(1).optional(),
1502
1547
  MEMORAONE_AGENT_TYPE: import_v4.z.string().min(1).optional(),
1503
1548
  MEMORAONE_SOURCE: import_v4.z.string().min(1).optional(),
1504
- MEMORAONE_IDE_TYPE: import_v4.z.enum(["cursor", "copilot-vscode", "jetbrains"]).optional(),
1549
+ MEMORAONE_IDE_TYPE: import_v4.z.enum(IDE_TYPES).optional(),
1505
1550
  MEMORAONE_WORKLOG: import_v4.z.string().min(1).optional(),
1506
1551
  MEMORAONE_HEARTBEAT: import_v4.z.string().min(1).optional(),
1507
1552
  MEMORAONE_HEARTBEAT_INTERVAL_MS: import_v4.z.string().min(1).optional()
@@ -1550,7 +1595,9 @@ var config2 = {
1550
1595
  devMode: parseBooleanFlag2(parsed.data.MEMORAONE_DEV_MODE, false),
1551
1596
  worklogEnabled: parseBooleanFlag2(parsed.data.MEMORAONE_WORKLOG, true),
1552
1597
  heartbeatEnabled: parseBooleanFlag2(parsed.data.MEMORAONE_HEARTBEAT, true),
1553
- heartbeatIntervalMs: Number.parseInt(parsed.data.MEMORAONE_HEARTBEAT_INTERVAL_MS ?? "30000", 10)
1598
+ // Cadence is owned by LOCAL_MCP_HEARTBEAT_INTERVAL_MS in heartbeat.ts (1_000).
1599
+ // Env override is accepted for forward-compat but the timer path ignores it.
1600
+ heartbeatIntervalMs: Number.parseInt(parsed.data.MEMORAONE_HEARTBEAT_INTERVAL_MS ?? "1000", 10)
1554
1601
  };
1555
1602
 
1556
1603
  // src/initializeBinding.ts
@@ -1842,8 +1889,79 @@ var logCommandShape = {
1842
1889
  // src/tools/bindingStatus.ts
1843
1890
  var bindingStatusShape = {};
1844
1891
 
1845
- // src/tools/handlers/postEvent.ts
1892
+ // src/tools/listTimeline.ts
1846
1893
  var import_v411 = require("zod/v4");
1894
+ var listTimelineDescription = "List timeline events for the project bound to this Local MCP installation.";
1895
+ var listTimelineInputSchema = import_v411.z.object({
1896
+ since: import_v411.z.string().optional(),
1897
+ concept: import_v411.z.string().optional(),
1898
+ kind: import_v411.z.union([import_v411.z.string(), import_v411.z.array(import_v411.z.string())]).optional(),
1899
+ sort: import_v411.z.enum(["newest", "oldest"]).optional(),
1900
+ limit: import_v411.z.number().int().min(1).max(200).optional(),
1901
+ cursor: import_v411.z.string().optional()
1902
+ }).strict();
1903
+
1904
+ // src/tools/listConcepts.ts
1905
+ var import_v412 = require("zod/v4");
1906
+ var listConceptsDescription = "List concepts for the project bound to this Local MCP installation.";
1907
+ var listConceptsInputSchema = import_v412.z.object({
1908
+ q: import_v412.z.string().min(1).optional(),
1909
+ tag: import_v412.z.string().min(1).optional(),
1910
+ parent_id: import_v412.z.string().min(1).optional(),
1911
+ limit: import_v412.z.number().int().min(1).max(200).optional(),
1912
+ cursor: import_v412.z.string().min(1).optional()
1913
+ }).strict();
1914
+
1915
+ // src/tools/getConcept.ts
1916
+ var import_v413 = require("zod/v4");
1917
+ var getConceptDescription = "Get one concept by ID from the project bound to this Local MCP installation.";
1918
+ var getConceptInputSchema = import_v413.z.object({
1919
+ id: import_v413.z.string().trim().min(1)
1920
+ }).strict();
1921
+
1922
+ // src/tools/createConceptVersion.ts
1923
+ var import_v414 = require("zod/v4");
1924
+ var createConceptVersionDescription = "Create a version of a concept in the project bound to this Local MCP installation.";
1925
+ var createConceptVersionInputSchema = import_v414.z.object({
1926
+ id: import_v414.z.string().trim().min(1),
1927
+ value: import_v414.z.unknown(),
1928
+ reason: import_v414.z.string().optional(),
1929
+ confidence: import_v414.z.number().finite().min(0).max(1).optional(),
1930
+ source_ref: import_v414.z.string().optional(),
1931
+ tags: import_v414.z.array(import_v414.z.string()).optional(),
1932
+ parent_id: import_v414.z.union([import_v414.z.string(), import_v414.z.null()]).optional()
1933
+ }).strict();
1934
+ function isJsonValue(value) {
1935
+ if (value === null) return true;
1936
+ if (typeof value === "boolean" || typeof value === "string") return true;
1937
+ if (typeof value === "number") return Number.isFinite(value);
1938
+ if (Array.isArray(value)) return value.every(isJsonValue);
1939
+ if (typeof value !== "object") return false;
1940
+ const prototype = Object.getPrototypeOf(value);
1941
+ if (prototype !== Object.prototype && prototype !== null) return false;
1942
+ return Object.values(value).every(isJsonValue);
1943
+ }
1944
+
1945
+ // src/tools/toolInventory.ts
1946
+ var LOCAL_MCP_TOOL_NAMES = [
1947
+ "memora_ask_with_memory",
1948
+ "memora_post_event",
1949
+ "memora_create_fact",
1950
+ "memora_add_personal_context",
1951
+ "memora_get_personal_context",
1952
+ "memora_log_intent",
1953
+ "memora_log_change_summary",
1954
+ "memora_log_tool_result",
1955
+ "memora_log_command",
1956
+ "memora_status",
1957
+ "memora_list_timeline",
1958
+ "memora_list_concepts",
1959
+ "memora_get_concept",
1960
+ "memora_create_concept_version"
1961
+ ];
1962
+
1963
+ // src/tools/handlers/postEvent.ts
1964
+ var import_v415 = require("zod/v4");
1847
1965
  var crypto4 = __toESM(require("crypto"), 1);
1848
1966
 
1849
1967
  // src/runContext.ts
@@ -1899,14 +2017,14 @@ function generateRunId() {
1899
2017
  }
1900
2018
 
1901
2019
  // 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()
2020
+ var postEventInputSchema = import_v415.z.object({
2021
+ kind: import_v415.z.string().min(1),
2022
+ actor: import_v415.z.object({
2023
+ identifier: import_v415.z.string().min(1),
2024
+ id: import_v415.z.string().min(1).optional()
1907
2025
  }),
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()
2026
+ content: import_v415.z.record(import_v415.z.string(), import_v415.z.any()),
2027
+ metadata: import_v415.z.record(import_v415.z.string(), import_v415.z.any()).optional()
1910
2028
  });
1911
2029
  function buildPostEventContentFields(content) {
1912
2030
  if (typeof content.message === "string") {
@@ -1978,10 +2096,10 @@ async function handlePostEvent(client, args) {
1978
2096
  }
1979
2097
 
1980
2098
  // 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()
2099
+ var import_v416 = require("zod/v4");
2100
+ var createFactInputSchema = import_v416.z.object({
2101
+ content: import_v416.z.string().min(1),
2102
+ metadata: import_v416.z.record(import_v416.z.string(), import_v416.z.any()).optional()
1985
2103
  });
1986
2104
  async function handleCreateFact(client, args) {
1987
2105
  const parsed2 = createFactInputSchema.parse(args ?? {});
@@ -2026,13 +2144,13 @@ async function handleCreateFact(client, args) {
2026
2144
  }
2027
2145
 
2028
2146
  // 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()
2147
+ var import_v417 = require("zod/v4");
2148
+ var addPersonalContextInputSchema = import_v417.z.object({
2149
+ content: import_v417.z.string().min(1),
2150
+ category: import_v417.z.string().optional(),
2151
+ tags: import_v417.z.array(import_v417.z.string()).optional(),
2152
+ scope_type: import_v417.z.enum(["general", "project"]).optional(),
2153
+ scope_id: import_v417.z.string().optional()
2036
2154
  });
2037
2155
  async function handleAddPersonalContext(client, args) {
2038
2156
  const parsed2 = addPersonalContextInputSchema.parse(args ?? {});
@@ -2068,12 +2186,12 @@ async function handleAddPersonalContext(client, args) {
2068
2186
  }
2069
2187
 
2070
2188
  // 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()
2189
+ var import_v418 = require("zod/v4");
2190
+ var getPersonalContextInputSchema = import_v418.z.object({
2191
+ query: import_v418.z.string().optional(),
2192
+ scope_type: import_v418.z.enum(["general", "project"]).optional(),
2193
+ scope_id: import_v418.z.string().optional(),
2194
+ limit: import_v418.z.number().int().positive().optional()
2077
2195
  });
2078
2196
  function buildPersonalContextPath(parsed2) {
2079
2197
  const params = new URLSearchParams();
@@ -2110,13 +2228,13 @@ async function handleGetPersonalContext(client, args) {
2110
2228
  }
2111
2229
 
2112
2230
  // 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()
2231
+ var import_v419 = require("zod/v4");
2232
+ var askWithMemoryInputSchema = import_v419.z.object({
2233
+ question: import_v419.z.string().min(1),
2234
+ code_context: import_v419.z.object({
2235
+ file_path: import_v419.z.string().optional(),
2236
+ selected_text: import_v419.z.string().optional(),
2237
+ language: import_v419.z.string().optional()
2120
2238
  }).optional()
2121
2239
  });
2122
2240
  function isAskWithMemoryResponse(value) {
@@ -2152,13 +2270,13 @@ async function handleAskWithMemory(client, args) {
2152
2270
  }
2153
2271
 
2154
2272
  // 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()
2273
+ var import_v420 = require("zod/v4");
2274
+ var logIntentInputSchema = import_v420.z.object({
2275
+ intent: import_v420.z.enum(["task", "decision"]),
2276
+ message: import_v420.z.string().min(1),
2277
+ context: import_v420.z.record(import_v420.z.string(), import_v420.z.any()).optional(),
2278
+ intent_source: import_v420.z.string().optional().default("cursor_chat"),
2279
+ run_id: import_v420.z.string().min(1).optional()
2162
2280
  });
2163
2281
  async function handleLogIntent(client, args) {
2164
2282
  const parsed2 = logIntentInputSchema.parse(args ?? {});
@@ -2200,18 +2318,18 @@ async function handleLogIntent(client, args) {
2200
2318
  }
2201
2319
 
2202
2320
  // 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()
2321
+ var import_v421 = require("zod/v4");
2322
+ var logChangeSummaryInputSchema = import_v421.z.object({
2323
+ summary: import_v421.z.string().min(1),
2324
+ scope: import_v421.z.string().min(1).optional(),
2325
+ files: import_v421.z.array(import_v421.z.string().min(1)).optional(),
2326
+ stats: import_v421.z.object({
2327
+ files: import_v421.z.number().int().nonnegative().optional(),
2328
+ add: import_v421.z.number().int().nonnegative().optional(),
2329
+ del: import_v421.z.number().int().nonnegative().optional()
2212
2330
  }).optional(),
2213
- commit: import_v417.z.string().min(1).optional(),
2214
- run_id: import_v417.z.string().min(1).optional()
2331
+ commit: import_v421.z.string().min(1).optional(),
2332
+ run_id: import_v421.z.string().min(1).optional()
2215
2333
  });
2216
2334
  async function handleLogChangeSummary(client, args) {
2217
2335
  const parsed2 = logChangeSummaryInputSchema.parse(args ?? {});
@@ -2246,17 +2364,17 @@ async function handleLogChangeSummary(client, args) {
2246
2364
  }
2247
2365
 
2248
2366
  // 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()
2367
+ var import_v422 = require("zod/v4");
2368
+ var logToolResultInputSchema = import_v422.z.object({
2369
+ tool: import_v422.z.string().min(1),
2370
+ status: import_v422.z.enum(["ok", "error", "partial"]),
2371
+ summary: import_v422.z.string().min(1),
2372
+ run_id: import_v422.z.string().min(1).optional(),
2373
+ duration_ms: import_v422.z.number().int().nonnegative().optional(),
2374
+ error_code: import_v422.z.string().min(1).optional(),
2375
+ error_message: import_v422.z.string().min(1).optional(),
2376
+ error_kind: import_v422.z.enum(["infra", "logic", "auth", "rate_limit", "validation", "unknown"]).optional(),
2377
+ stats: import_v422.z.record(import_v422.z.string(), import_v422.z.any()).optional()
2260
2378
  });
2261
2379
  async function handleLogToolResult(client, args) {
2262
2380
  const parsed2 = logToolResultInputSchema.parse(args ?? {});
@@ -2294,15 +2412,15 @@ async function handleLogToolResult(client, args) {
2294
2412
  }
2295
2413
 
2296
2414
  // 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()
2415
+ var import_v423 = require("zod/v4");
2416
+ var logCommandInputSchema = import_v423.z.object({
2417
+ cmd: import_v423.z.string().min(1),
2418
+ summary: import_v423.z.string().min(1),
2419
+ cwd: import_v423.z.string().min(1).optional(),
2420
+ exit_code: import_v423.z.number().int().optional(),
2421
+ duration_ms: import_v423.z.number().int().nonnegative().optional(),
2422
+ run_id: import_v423.z.string().min(1).optional(),
2423
+ stats: import_v423.z.record(import_v423.z.string(), import_v423.z.any()).optional()
2306
2424
  });
2307
2425
  async function handleLogCommand(client, args) {
2308
2426
  const parsed2 = logCommandInputSchema.parse(args ?? {});
@@ -2337,6 +2455,244 @@ async function handleLogCommand(client, args) {
2337
2455
  return { ok: true };
2338
2456
  }
2339
2457
 
2458
+ // src/tools/responseProjection.ts
2459
+ var timelineItemKeys = [
2460
+ "id",
2461
+ "ts",
2462
+ "kind",
2463
+ "concept",
2464
+ "old_value",
2465
+ "new_value",
2466
+ "reason",
2467
+ "confidence",
2468
+ "links",
2469
+ "source_ref",
2470
+ "redacted",
2471
+ "redaction_reason",
2472
+ "summary",
2473
+ "consolidated_of"
2474
+ ];
2475
+ var conceptVersionKeys = [
2476
+ "version",
2477
+ "ts",
2478
+ "reason",
2479
+ "confidence",
2480
+ "source_ref",
2481
+ "value"
2482
+ ];
2483
+ function invalidResponse() {
2484
+ throw new Error("Invalid Memora response");
2485
+ }
2486
+ function isRecord(value) {
2487
+ return typeof value === "object" && value !== null && !Array.isArray(value);
2488
+ }
2489
+ function pickFields(raw, keys) {
2490
+ const result = {};
2491
+ for (const key of keys) {
2492
+ if (Object.prototype.hasOwnProperty.call(raw, key) && raw[key] !== void 0) {
2493
+ result[key] = raw[key];
2494
+ }
2495
+ }
2496
+ return result;
2497
+ }
2498
+ function pickConceptVersion(raw) {
2499
+ return pickFields(raw, conceptVersionKeys);
2500
+ }
2501
+ function pickConceptItem(raw) {
2502
+ if (typeof raw.id !== "string" || raw.id.trim() === "") invalidResponse();
2503
+ const item = { id: raw.id };
2504
+ if (Object.prototype.hasOwnProperty.call(raw, "tags")) {
2505
+ if (!Array.isArray(raw.tags) || !raw.tags.every((tag) => typeof tag === "string")) {
2506
+ invalidResponse();
2507
+ }
2508
+ item.tags = raw.tags;
2509
+ }
2510
+ if (Object.prototype.hasOwnProperty.call(raw, "parent_id")) {
2511
+ if (raw.parent_id !== null && typeof raw.parent_id !== "string") invalidResponse();
2512
+ item.parent_id = raw.parent_id;
2513
+ }
2514
+ if (Object.prototype.hasOwnProperty.call(raw, "latest")) {
2515
+ if (raw.latest === null) {
2516
+ item.latest = null;
2517
+ } else if (isRecord(raw.latest)) {
2518
+ item.latest = pickConceptVersion(raw.latest);
2519
+ } else {
2520
+ invalidResponse();
2521
+ }
2522
+ }
2523
+ return item;
2524
+ }
2525
+ function normalizeCursor(raw) {
2526
+ for (const key of ["next_cursor", "nextCursor"]) {
2527
+ if (!Object.prototype.hasOwnProperty.call(raw, key)) continue;
2528
+ const value = raw[key];
2529
+ if (value === null) return null;
2530
+ if (typeof value === "string") return value;
2531
+ invalidResponse();
2532
+ }
2533
+ return null;
2534
+ }
2535
+ function projectTimelineResponse(data) {
2536
+ if (!isRecord(data) || !Array.isArray(data.items) || !isRecord(data.page)) {
2537
+ invalidResponse();
2538
+ }
2539
+ if (typeof data.page.limit !== "number" || !Number.isFinite(data.page.limit) || data.page.sort !== "newest" && data.page.sort !== "oldest") {
2540
+ invalidResponse();
2541
+ }
2542
+ const items = data.items.map((entry) => {
2543
+ if (!isRecord(entry)) invalidResponse();
2544
+ return pickFields(entry, timelineItemKeys);
2545
+ });
2546
+ return {
2547
+ items,
2548
+ page: {
2549
+ limit: data.page.limit,
2550
+ sort: data.page.sort,
2551
+ next_cursor: normalizeCursor(data.page)
2552
+ }
2553
+ };
2554
+ }
2555
+ function projectConceptListResponse(data, requestedLimit) {
2556
+ if (!isRecord(data)) invalidResponse();
2557
+ let entries;
2558
+ if (Object.prototype.hasOwnProperty.call(data, "rows")) {
2559
+ entries = data.rows;
2560
+ } else if (Object.prototype.hasOwnProperty.call(data, "items")) {
2561
+ entries = data.items;
2562
+ } else {
2563
+ invalidResponse();
2564
+ }
2565
+ if (!Array.isArray(entries)) invalidResponse();
2566
+ let cursorSource = data;
2567
+ if (!Object.prototype.hasOwnProperty.call(data, "next_cursor") && !Object.prototype.hasOwnProperty.call(data, "nextCursor") && Object.prototype.hasOwnProperty.call(data, "page")) {
2568
+ if (!isRecord(data.page)) invalidResponse();
2569
+ cursorSource = data.page;
2570
+ }
2571
+ return {
2572
+ items: entries.map((entry) => {
2573
+ if (!isRecord(entry)) invalidResponse();
2574
+ return pickConceptItem(entry);
2575
+ }),
2576
+ page: {
2577
+ limit: requestedLimit ?? 50,
2578
+ next_cursor: normalizeCursor(cursorSource)
2579
+ }
2580
+ };
2581
+ }
2582
+ function projectConceptResponse(data) {
2583
+ if (!isRecord(data)) invalidResponse();
2584
+ const item = pickConceptItem(data);
2585
+ if (!Object.prototype.hasOwnProperty.call(data, "history")) {
2586
+ return { ...item, history: [] };
2587
+ }
2588
+ if (!Array.isArray(data.history)) invalidResponse();
2589
+ const history = data.history.map((entry) => {
2590
+ if (!isRecord(entry)) invalidResponse();
2591
+ return pickConceptVersion(entry);
2592
+ });
2593
+ return { ...item, history };
2594
+ }
2595
+ function projectCreatedConceptVersionResponse(data) {
2596
+ if (!isRecord(data)) invalidResponse();
2597
+ return pickConceptItem(data);
2598
+ }
2599
+
2600
+ // src/tools/handlers/toolRequestError.ts
2601
+ function rethrowToolRequestError(toolName, error) {
2602
+ if (error instanceof SyntaxError) {
2603
+ throw new Error("Invalid Memora response");
2604
+ }
2605
+ if (!(error instanceof MemoraOneHttpError)) throw error;
2606
+ let detail = "request failed";
2607
+ if (error.status === 401) detail = "authentication failed";
2608
+ else if (error.status === 403) detail = "connection unavailable";
2609
+ else if (error.status === 404) detail = "resource not found";
2610
+ else if (error.status === 409) detail = "conflict";
2611
+ else if (error.status >= 500) detail = "backend error";
2612
+ throw new Error(`${toolName} failed: ${error.status} ${detail}`);
2613
+ }
2614
+
2615
+ // src/tools/handlers/listTimeline.ts
2616
+ function buildQuery(input) {
2617
+ const parts = [];
2618
+ const append = (key, value) => {
2619
+ parts.push(`${encodeURIComponent(key)}=${encodeURIComponent(value)}`);
2620
+ };
2621
+ if (input.since !== void 0) append("since", input.since);
2622
+ if (input.concept !== void 0) append("concept", input.concept);
2623
+ if (input.kind !== void 0) {
2624
+ for (const kind of Array.isArray(input.kind) ? input.kind : [input.kind]) {
2625
+ append("kind", kind);
2626
+ }
2627
+ }
2628
+ if (input.sort !== void 0) append("sort", input.sort);
2629
+ if (input.limit !== void 0) append("limit", String(input.limit));
2630
+ if (input.cursor !== void 0) append("cursor", input.cursor);
2631
+ return parts.length === 0 ? "" : `?${parts.join("&")}`;
2632
+ }
2633
+ async function handleListTimeline(client, args) {
2634
+ const input = listTimelineInputSchema.parse(args ?? {});
2635
+ try {
2636
+ return projectTimelineResponse(await client.get(`/timeline${buildQuery(input)}`));
2637
+ } catch (error) {
2638
+ rethrowToolRequestError("memora_list_timeline", error);
2639
+ }
2640
+ }
2641
+
2642
+ // src/tools/handlers/listConcepts.ts
2643
+ function buildQuery2(input) {
2644
+ const parts = [];
2645
+ const append = (key, value) => {
2646
+ parts.push(`${encodeURIComponent(key)}=${encodeURIComponent(value)}`);
2647
+ };
2648
+ if (input.q !== void 0) append("q", input.q);
2649
+ if (input.tag !== void 0) append("tag", input.tag);
2650
+ if (input.parent_id !== void 0) append("parent_id", input.parent_id);
2651
+ if (input.limit !== void 0) append("limit", String(input.limit));
2652
+ if (input.cursor !== void 0) append("cursor", input.cursor);
2653
+ return parts.length === 0 ? "" : `?${parts.join("&")}`;
2654
+ }
2655
+ async function handleListConcepts(client, args) {
2656
+ const input = listConceptsInputSchema.parse(args ?? {});
2657
+ try {
2658
+ const data = await client.get(`/concepts${buildQuery2(input)}`);
2659
+ return projectConceptListResponse(data, input.limit);
2660
+ } catch (error) {
2661
+ rethrowToolRequestError("memora_list_concepts", error);
2662
+ }
2663
+ }
2664
+
2665
+ // src/tools/handlers/getConcept.ts
2666
+ async function handleGetConcept(client, args) {
2667
+ const input = getConceptInputSchema.parse(args ?? {});
2668
+ try {
2669
+ const data = await client.get(`/concepts/${encodeURIComponent(input.id)}`);
2670
+ return projectConceptResponse(data);
2671
+ } catch (error) {
2672
+ rethrowToolRequestError("memora_get_concept", error);
2673
+ }
2674
+ }
2675
+
2676
+ // src/tools/handlers/createConceptVersion.ts
2677
+ async function handleCreateConceptVersion(client, args) {
2678
+ const input = createConceptVersionInputSchema.parse(args ?? {});
2679
+ if (!isJsonValue(input.value)) {
2680
+ throw new Error("Invalid arguments: value must be a valid JSON value");
2681
+ }
2682
+ const body = { value: input.value };
2683
+ if (input.reason !== void 0) body.reason = input.reason;
2684
+ if (input.confidence !== void 0) body.confidence = input.confidence;
2685
+ if (input.source_ref !== void 0) body.source_ref = input.source_ref;
2686
+ if (input.tags !== void 0) body.tags = input.tags;
2687
+ if (input.parent_id !== void 0) body.parent_id = input.parent_id;
2688
+ try {
2689
+ const path14 = `/concepts/${encodeURIComponent(input.id)}/versions`;
2690
+ return projectCreatedConceptVersionResponse(await client.post(path14, body));
2691
+ } catch (error) {
2692
+ rethrowToolRequestError("memora_create_concept_version", error);
2693
+ }
2694
+ }
2695
+
2340
2696
  // src/tools/handlers/bindingStatus.ts
2341
2697
  function buildBindingStatus(binding, options = {}) {
2342
2698
  const status = {
@@ -2387,8 +2743,9 @@ function isHeartbeatDebugEnabled() {
2387
2743
  const value = String(process.env.MEMORAONE_DEBUG_HEARTBEAT ?? "").trim().toLowerCase();
2388
2744
  return ["1", "true", "yes", "on"].includes(value);
2389
2745
  }
2746
+ var LOCAL_MCP_HEARTBEAT_INTERVAL_MS = 1e3;
2390
2747
  function resolveHeartbeatIntervalMs() {
2391
- return Number.isFinite(config2.heartbeatIntervalMs) ? Math.max(1e3, config2.heartbeatIntervalMs) : 3e4;
2748
+ return LOCAL_MCP_HEARTBEAT_INTERVAL_MS;
2392
2749
  }
2393
2750
  function redactSensitiveText(text) {
2394
2751
  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 +2855,7 @@ async function sendProjectHeartbeat(client, ctx) {
2498
2855
  }
2499
2856
  function createDaemonHeartbeat(opts) {
2500
2857
  let interval = null;
2858
+ let runGeneration = 0;
2501
2859
  let client = null;
2502
2860
  let announced = false;
2503
2861
  let studioActive = null;
@@ -2566,21 +2924,24 @@ function createDaemonHeartbeat(opts) {
2566
2924
  studioActive = true;
2567
2925
  }
2568
2926
  };
2569
- const tick = async () => {
2570
- if (!client) return;
2927
+ const tick = async (generation) => {
2928
+ if (!client || generation !== runGeneration) return;
2571
2929
  const outcome = await sendProjectHeartbeat(client, ctx);
2930
+ if (generation !== runGeneration || !interval) return;
2572
2931
  applyHeartbeatOutcome(outcome);
2573
2932
  };
2574
2933
  const beginInterval = () => {
2575
2934
  if (interval) return;
2576
2935
  const intervalMs = resolveHeartbeatIntervalMs();
2936
+ const generation = runGeneration;
2577
2937
  log2(
2578
2938
  `daemon owns heartbeat for binding=${opts.binding.repositoryBindingId} project=${opts.binding.projectId} ideType=${ctx.ideType ?? "unknown"} interval=${intervalMs}ms`
2579
2939
  );
2580
- void tick();
2581
2940
  interval = setInterval(() => {
2582
- void tick();
2941
+ void tick(generation);
2583
2942
  }, intervalMs);
2943
+ interval.unref?.();
2944
+ void tick(generation);
2584
2945
  };
2585
2946
  const start = async () => {
2586
2947
  if (!config2.heartbeatEnabled) {
@@ -2613,6 +2974,7 @@ function createDaemonHeartbeat(opts) {
2613
2974
  }
2614
2975
  };
2615
2976
  const stop = () => {
2977
+ runGeneration += 1;
2616
2978
  if (interval) {
2617
2979
  clearInterval(interval);
2618
2980
  interval = null;
@@ -2632,7 +2994,7 @@ function createDaemonHeartbeat(opts) {
2632
2994
  return;
2633
2995
  }
2634
2996
  if (client && interval) {
2635
- void tick();
2997
+ void tick(runGeneration);
2636
2998
  }
2637
2999
  };
2638
3000
  const getIdeType = () => ctx.ideType;
@@ -2652,12 +3014,125 @@ function createDaemonHeartbeat(opts) {
2652
3014
  }
2653
3015
 
2654
3016
  // src/ideType.ts
3017
+ var RELIABLE_CLIENT_INFO_NAMES = /* @__PURE__ */ new Map([
3018
+ // Existing
3019
+ ["claude-code", "claude-code"],
3020
+ ["devin", "windsurf"],
3021
+ ["windsurf", "windsurf"],
3022
+ // Zed
3023
+ ["zed", "zed"],
3024
+ // Kiro IDE (exact only — not generic "kiro …" mcp-remote wrappers)
3025
+ ["kiro", "kiro"],
3026
+ // Visual Studio (never Visual Studio Code)
3027
+ ["visual studio", "visual-studio"],
3028
+ ["visual-studio", "visual-studio"],
3029
+ // Cline IDE
3030
+ ["cline", "cline"],
3031
+ // Roo Code
3032
+ ["roo code", "roo-code"],
3033
+ ["roo-code", "roo-code"],
3034
+ // Auggie / Augment Code (canonical wire ID: auggie)
3035
+ ["auggie", "auggie"],
3036
+ ["augment", "auggie"],
3037
+ ["augment code", "auggie"],
3038
+ ["augment-code", "auggie"],
3039
+ // Continue IDE (not bare "continue")
3040
+ ["continue-client", "continue"],
3041
+ // Continue CLI
3042
+ ["continue-cli-client", "continue-cli"],
3043
+ ["continue-cli", "continue-cli"],
3044
+ ["continue cli", "continue-cli"],
3045
+ // Copilot CLI (not GitHub Copilot in VS Code)
3046
+ ["github-copilot-developer", "copilot-cli"],
3047
+ ["copilot-cli", "copilot-cli"],
3048
+ ["copilot cli", "copilot-cli"],
3049
+ // Kiro CLI (explicit CLI names only — not Amazon Q / Q-DEV-CLI)
3050
+ ["kiro-cli", "kiro-cli"],
3051
+ ["kiro cli", "kiro-cli"],
3052
+ // Cline CLI
3053
+ ["cline-cli", "cline-cli"],
3054
+ ["cline cli", "cline-cli"],
3055
+ // Claude Desktop (never bare "claude"; never claude-code)
3056
+ ["claude-ai", "claude-desktop"],
3057
+ ["claude-desktop", "claude-desktop"],
3058
+ ["claude desktop", "claude-desktop"],
3059
+ // Gemini CLI (not bare "gemini")
3060
+ ["gemini-cli", "gemini-cli"],
3061
+ ["gemini cli", "gemini-cli"],
3062
+ // Google Antigravity IDE vs CLI (shared MCP config; clientInfo distinguishes)
3063
+ ["antigravity", "antigravity"],
3064
+ ["antigravity ide", "antigravity"],
3065
+ ["antigravity-client", "antigravity-cli"],
3066
+ // Goose
3067
+ ["goose", "goose"],
3068
+ // JetBrains Junie (distinct from generic jetbrains / copilot-jetbrains)
3069
+ ["junie", "junie"],
3070
+ // GitHub Copilot for Xcode
3071
+ ["xcode", "xcode"],
3072
+ ["copilot-xcode", "xcode"],
3073
+ ["github-copilot-xcode", "xcode"],
3074
+ // GitHub Copilot for JetBrains (distinct from jetbrains AI Assistant)
3075
+ ["copilot-jetbrains", "copilot-jetbrains"],
3076
+ ["github-copilot-jetbrains", "copilot-jetbrains"],
3077
+ ["github copilot jetbrains", "copilot-jetbrains"],
3078
+ // GitHub Copilot in Visual Studio (distinct from visual-studio / copilot-vscode)
3079
+ ["copilot-visual-studio", "copilot-visual-studio"],
3080
+ ["github-copilot-visual-studio", "copilot-visual-studio"],
3081
+ ["github copilot visual studio", "copilot-visual-studio"]
3082
+ ]);
3083
+ function mapReliableClientInfoName(name) {
3084
+ if (typeof name !== "string") {
3085
+ return void 0;
3086
+ }
3087
+ const normalized = name.trim().toLowerCase();
3088
+ if (normalized === "") {
3089
+ return void 0;
3090
+ }
3091
+ const exact = RELIABLE_CLIENT_INFO_NAMES.get(normalized);
3092
+ if (exact) {
3093
+ return exact;
3094
+ }
3095
+ if (/^windsurf[\s_-].+$/.test(normalized)) {
3096
+ return "windsurf";
3097
+ }
3098
+ return void 0;
3099
+ }
3100
+ function mapReliableHostIdentity(env2) {
3101
+ if (env2.WINDSURF_IDE_TYPE === "windsurf") {
3102
+ return "windsurf";
3103
+ }
3104
+ if (env2.ACP_BACKEND === "windsurf") {
3105
+ return "windsurf";
3106
+ }
3107
+ if (env2.__CFBundleIdentifier === "com.exafunction.windsurf") {
3108
+ return "windsurf";
3109
+ }
3110
+ if (env2.__CFBundleIdentifier === "com.anthropic.claudefordesktop") {
3111
+ return "claude-desktop";
3112
+ }
3113
+ if (env2.__CFBundleIdentifier === "dev.zed.Zed") {
3114
+ return "zed";
3115
+ }
3116
+ if (Object.prototype.hasOwnProperty.call(env2, "COPILOT_CLI")) {
3117
+ return "copilot-cli";
3118
+ }
3119
+ return void 0;
3120
+ }
2655
3121
  function inferIdeType(params, options = {}) {
2656
3122
  const env2 = options.env ?? process.env;
2657
3123
  const argv = (options.argv ?? process.argv).join(" ").toLowerCase();
2658
- const configIdeType = options.configIdeType ?? config2.ideType;
2659
- if (configIdeType) {
2660
- return configIdeType;
3124
+ const hasExplicitConfigOption = Object.prototype.hasOwnProperty.call(options, "configIdeType");
3125
+ const explicitHint = hasExplicitConfigOption ? options.configIdeType : resolveIdeTypeFromEnv(env2) ?? config2.ideType;
3126
+ const fromClientInfo = mapReliableClientInfoName(params?.clientInfo?.name);
3127
+ if (fromClientInfo) {
3128
+ return fromClientInfo;
3129
+ }
3130
+ const fromHost = mapReliableHostIdentity(env2);
3131
+ if (fromHost) {
3132
+ return fromHost;
3133
+ }
3134
+ if (explicitHint) {
3135
+ return explicitHint;
2661
3136
  }
2662
3137
  const clientInfoName = String(params?.clientInfo?.name ?? "").toLowerCase();
2663
3138
  const clientInfoVersion = String(params?.clientInfo?.version ?? "").toLowerCase();
@@ -2682,7 +3157,7 @@ function inferIdeType(params, options = {}) {
2682
3157
  if (hasJetBrainsSignals) {
2683
3158
  return "jetbrains";
2684
3159
  }
2685
- const hasVsCodeSignals = envKeys.some((key) => key.startsWith("VSCODE_")) || /(visual studio code|vscode|vs code|github copilot)/.test(clientInfoName) || /(visual studio code|vscode|vs code)/.test(argv);
3160
+ const hasVsCodeSignals = envKeys.some((key) => key.startsWith("VSCODE_")) || /(visual studio code|vscode|vs code)/.test(clientInfoName) || /(visual studio code|vscode|vs code)/.test(argv);
2686
3161
  if (hasVsCodeSignals) {
2687
3162
  return "copilot-vscode";
2688
3163
  }
@@ -2814,7 +3289,11 @@ async function main(opts = {}) {
2814
3289
  `[memoraone-mcp] refreshed stale cached binding ${reconciled.binding.repositoryBindingId}: project=${reconciled.binding.projectId}`
2815
3290
  );
2816
3291
  try {
2817
- const socketPath = getBindingSocketPath(opts.daemonBindingHint);
3292
+ const socketPath = getBindingSocketPath(
3293
+ opts.daemonBindingHint,
3294
+ process.env,
3295
+ runtime.ideType ?? ""
3296
+ );
2818
3297
  writeBindingSidecar(socketPath, reconciled.binding, runtime.ideType ?? "");
2819
3298
  } catch (err) {
2820
3299
  console.error(
@@ -3007,6 +3486,71 @@ async function main(opts = {}) {
3007
3486
  }
3008
3487
  );
3009
3488
  registeredToolNames.push("memora_log_command");
3489
+ server.registerTool(
3490
+ "memora_list_timeline",
3491
+ {
3492
+ description: listTimelineDescription,
3493
+ inputSchema: listTimelineInputSchema
3494
+ },
3495
+ async (args) => runWithSessionContext(sessionContext, async () => {
3496
+ if (!runtime.client || !runtime.projectId) return notInitializedResult;
3497
+ const result = await handleListTimeline(runtime.client, args);
3498
+ return {
3499
+ content: [{ type: "text", text: JSON.stringify(result) }]
3500
+ };
3501
+ })
3502
+ );
3503
+ registeredToolNames.push("memora_list_timeline");
3504
+ server.registerTool(
3505
+ "memora_list_concepts",
3506
+ {
3507
+ description: listConceptsDescription,
3508
+ inputSchema: listConceptsInputSchema
3509
+ },
3510
+ async (args) => runWithSessionContext(sessionContext, async () => {
3511
+ if (!runtime.client || !runtime.projectId) return notInitializedResult;
3512
+ const result = await handleListConcepts(runtime.client, args);
3513
+ return {
3514
+ content: [{ type: "text", text: JSON.stringify(result) }]
3515
+ };
3516
+ })
3517
+ );
3518
+ registeredToolNames.push("memora_list_concepts");
3519
+ server.registerTool(
3520
+ "memora_get_concept",
3521
+ {
3522
+ description: getConceptDescription,
3523
+ inputSchema: getConceptInputSchema
3524
+ },
3525
+ async (args) => runWithSessionContext(sessionContext, async () => {
3526
+ if (!runtime.client || !runtime.projectId) return notInitializedResult;
3527
+ const result = await handleGetConcept(runtime.client, args);
3528
+ return {
3529
+ content: [{ type: "text", text: JSON.stringify(result) }]
3530
+ };
3531
+ })
3532
+ );
3533
+ registeredToolNames.push("memora_get_concept");
3534
+ server.registerTool(
3535
+ "memora_create_concept_version",
3536
+ {
3537
+ description: createConceptVersionDescription,
3538
+ inputSchema: createConceptVersionInputSchema
3539
+ },
3540
+ async (args) => runWithSessionContext(sessionContext, async () => {
3541
+ if (!runtime.client || !runtime.projectId) return notInitializedResult;
3542
+ const result = await handleCreateConceptVersion(runtime.client, args);
3543
+ return {
3544
+ content: [{ type: "text", text: JSON.stringify(result) }]
3545
+ };
3546
+ })
3547
+ );
3548
+ registeredToolNames.push("memora_create_concept_version");
3549
+ if (registeredToolNames.length !== LOCAL_MCP_TOOL_NAMES.length || registeredToolNames.some(
3550
+ (name) => !LOCAL_MCP_TOOL_NAMES.includes(name)
3551
+ )) {
3552
+ throw new Error("Local MCP tool registration inventory mismatch");
3553
+ }
3010
3554
  server.server.setRequestHandler(
3011
3555
  import_types.InitializeRequestSchema,
3012
3556
  async (request) => runWithSessionContext(sessionContext, async () => {
@@ -3249,7 +3793,7 @@ async function runDaemon() {
3249
3793
  const repositoryBindingId = parseBindingIdFromArgv();
3250
3794
  const binding = parseBindingFromEnv(repositoryBindingId);
3251
3795
  const ideType = parseIdeTypeFromArgv(process.argv.slice(2)) ?? config2.ideType ?? resolveIdeTypeFromEnv();
3252
- const socketPath = getBindingSocketPath(binding, process.env);
3796
+ const socketPath = getBindingSocketPath(binding, process.env, ideType);
3253
3797
  let nextSessionId = 1;
3254
3798
  let activeSessions = 0;
3255
3799
  let shuttingDown = false;