@contextstream/mcp-server 0.3.30 → 0.3.32

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 (3) hide show
  1. package/README.md +3 -1
  2. package/dist/index.js +355 -112
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -47,7 +47,9 @@ npx -y @contextstream/mcp-server setup
47
47
  ```
48
48
 
49
49
  Notes:
50
- - Uses browser/device login by default and creates an API key for you (stored locally in the config files it writes).
50
+ - Uses browser/device login by default and creates an API key for you.
51
+ - To avoid re-auth prompts on subsequent runs, the wizard saves that API key to `~/.contextstream/credentials.json` (and also writes it into the MCP config files it generates). Delete that file to force a fresh login.
52
+ - Codex CLI MCP config is global-only (`~/.codex/config.toml`), so the wizard will always write Codex config globally when selected.
51
53
  - Some tools still require UI/CLI-based MCP setup (the wizard will tell you when it can’t write a config).
52
54
  - Preview changes without writing files: `npx -y @contextstream/mcp-server setup --dry-run`
53
55
 
package/dist/index.js CHANGED
@@ -487,8 +487,8 @@ function getErrorMap() {
487
487
 
488
488
  // node_modules/zod/v3/helpers/parseUtil.js
489
489
  var makeIssue = (params) => {
490
- const { data, path: path6, errorMaps, issueData } = params;
491
- const fullPath = [...path6, ...issueData.path || []];
490
+ const { data, path: path7, errorMaps, issueData } = params;
491
+ const fullPath = [...path7, ...issueData.path || []];
492
492
  const fullIssue = {
493
493
  ...issueData,
494
494
  path: fullPath
@@ -604,11 +604,11 @@ var errorUtil;
604
604
 
605
605
  // node_modules/zod/v3/types.js
606
606
  var ParseInputLazyPath = class {
607
- constructor(parent, value, path6, key) {
607
+ constructor(parent, value, path7, key) {
608
608
  this._cachedPath = [];
609
609
  this.parent = parent;
610
610
  this.data = value;
611
- this._path = path6;
611
+ this._path = path7;
612
612
  this._key = key;
613
613
  }
614
614
  get path() {
@@ -4138,9 +4138,9 @@ var BASE_DELAY = 1e3;
4138
4138
  async function sleep(ms) {
4139
4139
  return new Promise((resolve2) => setTimeout(resolve2, ms));
4140
4140
  }
4141
- async function request(config, path6, options = {}) {
4141
+ async function request(config, path7, options = {}) {
4142
4142
  const { apiUrl, apiKey, jwt, userAgent } = config;
4143
- const apiPath = path6.startsWith("/api/") ? path6 : `/api/v1${path6}`;
4143
+ const apiPath = path7.startsWith("/api/") ? path7 : `/api/v1${path7}`;
4144
4144
  const url = `${apiUrl.replace(/\/$/, "")}${apiPath}`;
4145
4145
  const maxRetries = options.retries ?? MAX_RETRIES;
4146
4146
  const baseDelay = options.retryDelay ?? BASE_DELAY;
@@ -4641,6 +4641,29 @@ function unwrapApiResponse(result) {
4641
4641
  }
4642
4642
  return result;
4643
4643
  }
4644
+ function normalizeNodeType(input) {
4645
+ const t = String(input ?? "").trim().toLowerCase();
4646
+ switch (t) {
4647
+ case "fact":
4648
+ case "insight":
4649
+ case "note":
4650
+ return "Fact";
4651
+ case "decision":
4652
+ return "Decision";
4653
+ case "preference":
4654
+ return "Preference";
4655
+ case "constraint":
4656
+ return "Constraint";
4657
+ case "habit":
4658
+ return "Habit";
4659
+ case "lesson":
4660
+ return "Lesson";
4661
+ default:
4662
+ throw new Error(
4663
+ `Invalid node_type: ${JSON.stringify(input)} (expected one of fact|decision|preference|constraint|habit|lesson)`
4664
+ );
4665
+ }
4666
+ }
4644
4667
  var ContextStreamClient = class {
4645
4668
  constructor(config) {
4646
4669
  this.config = config;
@@ -4721,13 +4744,19 @@ var ContextStreamClient = class {
4721
4744
  const result = await request(this.config, "/workspaces", { body: input });
4722
4745
  return unwrapApiResponse(result);
4723
4746
  }
4724
- updateWorkspace(workspaceId, input) {
4747
+ async updateWorkspace(workspaceId, input) {
4725
4748
  uuidSchema.parse(workspaceId);
4726
- return request(this.config, `/workspaces/${workspaceId}`, { method: "PUT", body: input });
4749
+ const result = await request(this.config, `/workspaces/${workspaceId}`, { method: "PUT", body: input });
4750
+ globalCache.delete(CacheKeys.workspace(workspaceId));
4751
+ globalCache.delete(`workspace_overview:${workspaceId}`);
4752
+ return result;
4727
4753
  }
4728
- deleteWorkspace(workspaceId) {
4754
+ async deleteWorkspace(workspaceId) {
4729
4755
  uuidSchema.parse(workspaceId);
4730
- return request(this.config, `/workspaces/${workspaceId}`, { method: "DELETE" });
4756
+ const result = await request(this.config, `/workspaces/${workspaceId}`, { method: "DELETE" });
4757
+ globalCache.delete(CacheKeys.workspace(workspaceId));
4758
+ globalCache.delete(`workspace_overview:${workspaceId}`);
4759
+ return result;
4731
4760
  }
4732
4761
  listProjects(params) {
4733
4762
  const withDefaults = this.withDefaults(params || {});
@@ -4743,13 +4772,19 @@ var ContextStreamClient = class {
4743
4772
  const result = await request(this.config, "/projects", { body: payload });
4744
4773
  return unwrapApiResponse(result);
4745
4774
  }
4746
- updateProject(projectId, input) {
4775
+ async updateProject(projectId, input) {
4747
4776
  uuidSchema.parse(projectId);
4748
- return request(this.config, `/projects/${projectId}`, { method: "PUT", body: input });
4777
+ const result = await request(this.config, `/projects/${projectId}`, { method: "PUT", body: input });
4778
+ globalCache.delete(CacheKeys.project(projectId));
4779
+ globalCache.delete(`project_overview:${projectId}`);
4780
+ return result;
4749
4781
  }
4750
- deleteProject(projectId) {
4782
+ async deleteProject(projectId) {
4751
4783
  uuidSchema.parse(projectId);
4752
- return request(this.config, `/projects/${projectId}`, { method: "DELETE" });
4784
+ const result = await request(this.config, `/projects/${projectId}`, { method: "DELETE" });
4785
+ globalCache.delete(CacheKeys.project(projectId));
4786
+ globalCache.delete(`project_overview:${projectId}`);
4787
+ return result;
4753
4788
  }
4754
4789
  indexProject(projectId) {
4755
4790
  uuidSchema.parse(projectId);
@@ -4818,7 +4853,24 @@ var ContextStreamClient = class {
4818
4853
  return request(this.config, `/memory/events/workspace/${withDefaults.workspace_id}${suffix}`, { method: "GET" });
4819
4854
  }
4820
4855
  createKnowledgeNode(body) {
4821
- return request(this.config, "/memory/nodes", { body: this.withDefaults(body) });
4856
+ const withDefaults = this.withDefaults(body);
4857
+ if (!withDefaults.workspace_id) {
4858
+ throw new Error("workspace_id is required for creating knowledge nodes");
4859
+ }
4860
+ const summary = String(withDefaults.title ?? "").trim() || String(withDefaults.content ?? "").trim().slice(0, 120) || "Untitled";
4861
+ const details = String(withDefaults.content ?? "").trim();
4862
+ const apiBody = {
4863
+ workspace_id: withDefaults.workspace_id,
4864
+ project_id: withDefaults.project_id,
4865
+ node_type: normalizeNodeType(withDefaults.node_type),
4866
+ summary,
4867
+ details: details || void 0,
4868
+ valid_from: (/* @__PURE__ */ new Date()).toISOString()
4869
+ };
4870
+ if (withDefaults.relations && withDefaults.relations.length) {
4871
+ apiBody.context = { relations: withDefaults.relations };
4872
+ }
4873
+ return request(this.config, "/memory/nodes", { body: apiBody });
4822
4874
  }
4823
4875
  listKnowledgeNodes(params) {
4824
4876
  const withDefaults = this.withDefaults(params || {});
@@ -4957,7 +5009,7 @@ var ContextStreamClient = class {
4957
5009
  }
4958
5010
  deleteMemoryEvent(eventId) {
4959
5011
  uuidSchema.parse(eventId);
4960
- return request(this.config, `/memory/events/${eventId}`, { method: "DELETE" });
5012
+ return request(this.config, `/memory/events/${eventId}`, { method: "DELETE" }).then((r) => r === "" || r == null ? { success: true } : r);
4961
5013
  }
4962
5014
  distillMemoryEvent(eventId) {
4963
5015
  uuidSchema.parse(eventId);
@@ -4969,15 +5021,47 @@ var ContextStreamClient = class {
4969
5021
  }
4970
5022
  updateKnowledgeNode(nodeId, body) {
4971
5023
  uuidSchema.parse(nodeId);
4972
- return request(this.config, `/memory/nodes/${nodeId}`, { method: "PUT", body });
5024
+ const apiBody = {};
5025
+ if (body.title !== void 0) apiBody.summary = body.title;
5026
+ if (body.content !== void 0) apiBody.details = body.content;
5027
+ if (body.relations && body.relations.length) apiBody.context = { relations: body.relations };
5028
+ return request(this.config, `/memory/nodes/${nodeId}`, { method: "PUT", body: apiBody });
4973
5029
  }
4974
5030
  deleteKnowledgeNode(nodeId) {
4975
5031
  uuidSchema.parse(nodeId);
4976
- return request(this.config, `/memory/nodes/${nodeId}`, { method: "DELETE" });
5032
+ return request(this.config, `/memory/nodes/${nodeId}`, { method: "DELETE" }).then((r) => r === "" || r == null ? { success: true } : r);
4977
5033
  }
4978
5034
  supersedeKnowledgeNode(nodeId, body) {
4979
5035
  uuidSchema.parse(nodeId);
4980
- return request(this.config, `/memory/nodes/${nodeId}/supersede`, { body });
5036
+ return (async () => {
5037
+ const existingResp = await this.getKnowledgeNode(nodeId);
5038
+ const existing = unwrapApiResponse(existingResp);
5039
+ if (!existing || !existing.workspace_id) {
5040
+ throw new Error("Failed to load existing node before superseding");
5041
+ }
5042
+ const createdResp = await this.createKnowledgeNode({
5043
+ workspace_id: existing.workspace_id,
5044
+ project_id: existing.project_id ?? void 0,
5045
+ node_type: existing.node_type,
5046
+ title: existing.summary ?? "Superseded node",
5047
+ content: body.new_content
5048
+ });
5049
+ const created = unwrapApiResponse(createdResp);
5050
+ if (!created?.id) {
5051
+ throw new Error("Failed to create replacement node for supersede");
5052
+ }
5053
+ await request(this.config, `/memory/nodes/${nodeId}/supersede`, { body: { superseded_by: created.id } });
5054
+ return {
5055
+ success: true,
5056
+ data: {
5057
+ status: "superseded",
5058
+ old_node_id: nodeId,
5059
+ new_node_id: created.id,
5060
+ reason: body.reason ?? null
5061
+ },
5062
+ error: null
5063
+ };
5064
+ })();
4981
5065
  }
4982
5066
  memoryTimeline(workspaceId) {
4983
5067
  uuidSchema.parse(workspaceId);
@@ -5842,9 +5926,9 @@ var ContextStreamClient = class {
5842
5926
  candidateParts.push("## Relevant Code\n");
5843
5927
  currentChars += 18;
5844
5928
  const codeEntries = code.results.map((c) => {
5845
- const path6 = c.file_path || "file";
5929
+ const path7 = c.file_path || "file";
5846
5930
  const content = c.content?.slice(0, 150) || "";
5847
- return { path: path6, entry: `\u2022 ${path6}: ${content}...
5931
+ return { path: path7, entry: `\u2022 ${path7}: ${content}...
5848
5932
  ` };
5849
5933
  });
5850
5934
  for (const c of codeEntries) {
@@ -6776,6 +6860,8 @@ function getVersion() {
6776
6860
  var VERSION = getVersion();
6777
6861
 
6778
6862
  // src/tools.ts
6863
+ var LESSON_DEDUP_WINDOW_MS = 2 * 60 * 1e3;
6864
+ var recentLessonCaptures = /* @__PURE__ */ new Map();
6779
6865
  function formatContent(data) {
6780
6866
  return JSON.stringify(data, null, 2);
6781
6867
  }
@@ -6785,6 +6871,35 @@ function toStructured(data) {
6785
6871
  }
6786
6872
  return void 0;
6787
6873
  }
6874
+ function normalizeLessonField(value) {
6875
+ return value.trim().toLowerCase().replace(/\s+/g, " ");
6876
+ }
6877
+ function buildLessonSignature(input, workspaceId, projectId) {
6878
+ return [
6879
+ workspaceId,
6880
+ projectId || "global",
6881
+ input.category,
6882
+ input.title,
6883
+ input.trigger,
6884
+ input.impact,
6885
+ input.prevention
6886
+ ].map(normalizeLessonField).join("|");
6887
+ }
6888
+ function isDuplicateLessonCapture(signature) {
6889
+ const now = Date.now();
6890
+ for (const [key, ts] of recentLessonCaptures) {
6891
+ if (now - ts > LESSON_DEDUP_WINDOW_MS) {
6892
+ recentLessonCaptures.delete(key);
6893
+ }
6894
+ }
6895
+ const last = recentLessonCaptures.get(signature);
6896
+ if (last && now - last < LESSON_DEDUP_WINDOW_MS) {
6897
+ recentLessonCaptures.set(signature, now);
6898
+ return true;
6899
+ }
6900
+ recentLessonCaptures.set(signature, now);
6901
+ return false;
6902
+ }
6788
6903
  function registerTools(server, client, sessionManager) {
6789
6904
  const upgradeUrl = process.env.CONTEXTSTREAM_UPGRADE_URL || "https://contextstream.io/pricing";
6790
6905
  const defaultProTools = /* @__PURE__ */ new Set([
@@ -7936,26 +8051,26 @@ Optionally generates AI editor rules for automatic ContextStream usage.`,
7936
8051
  const result = await client.associateWorkspace(input);
7937
8052
  let rulesGenerated = [];
7938
8053
  if (input.generate_editor_rules) {
7939
- const fs4 = await import("fs");
7940
- const path6 = await import("path");
8054
+ const fs5 = await import("fs");
8055
+ const path7 = await import("path");
7941
8056
  for (const editor of getAvailableEditors()) {
7942
8057
  const rule = generateRuleContent(editor, {
7943
8058
  workspaceName: input.workspace_name,
7944
8059
  workspaceId: input.workspace_id
7945
8060
  });
7946
8061
  if (rule) {
7947
- const filePath = path6.join(input.folder_path, rule.filename);
8062
+ const filePath = path7.join(input.folder_path, rule.filename);
7948
8063
  try {
7949
8064
  let existingContent = "";
7950
8065
  try {
7951
- existingContent = fs4.readFileSync(filePath, "utf-8");
8066
+ existingContent = fs5.readFileSync(filePath, "utf-8");
7952
8067
  } catch {
7953
8068
  }
7954
8069
  if (!existingContent) {
7955
- fs4.writeFileSync(filePath, rule.content);
8070
+ fs5.writeFileSync(filePath, rule.content);
7956
8071
  rulesGenerated.push(rule.filename);
7957
8072
  } else if (!existingContent.includes("ContextStream Integration")) {
7958
- fs4.writeFileSync(filePath, existingContent + "\n\n" + rule.content);
8073
+ fs5.writeFileSync(filePath, existingContent + "\n\n" + rule.content);
7959
8074
  rulesGenerated.push(rule.filename + " (appended)");
7960
8075
  }
7961
8076
  } catch {
@@ -8041,26 +8156,26 @@ Behavior:
8041
8156
  });
8042
8157
  let rulesGenerated = [];
8043
8158
  if (input.generate_editor_rules) {
8044
- const fs4 = await import("fs");
8045
- const path6 = await import("path");
8159
+ const fs5 = await import("fs");
8160
+ const path7 = await import("path");
8046
8161
  for (const editor of getAvailableEditors()) {
8047
8162
  const rule = generateRuleContent(editor, {
8048
8163
  workspaceName: newWorkspace.name || input.workspace_name,
8049
8164
  workspaceId: newWorkspace.id
8050
8165
  });
8051
8166
  if (!rule) continue;
8052
- const filePath = path6.join(folderPath, rule.filename);
8167
+ const filePath = path7.join(folderPath, rule.filename);
8053
8168
  try {
8054
8169
  let existingContent = "";
8055
8170
  try {
8056
- existingContent = fs4.readFileSync(filePath, "utf-8");
8171
+ existingContent = fs5.readFileSync(filePath, "utf-8");
8057
8172
  } catch {
8058
8173
  }
8059
8174
  if (!existingContent) {
8060
- fs4.writeFileSync(filePath, rule.content);
8175
+ fs5.writeFileSync(filePath, rule.content);
8061
8176
  rulesGenerated.push(rule.filename);
8062
8177
  } else if (!existingContent.includes("ContextStream Integration")) {
8063
- fs4.writeFileSync(filePath, existingContent + "\n\n" + rule.content);
8178
+ fs5.writeFileSync(filePath, existingContent + "\n\n" + rule.content);
8064
8179
  rulesGenerated.push(rule.filename + " (appended)");
8065
8180
  }
8066
8181
  } catch {
@@ -8202,6 +8317,25 @@ The lesson will be tagged with 'lesson' and stored with structured metadata for
8202
8317
  isError: true
8203
8318
  };
8204
8319
  }
8320
+ const lessonSignature = buildLessonSignature({
8321
+ title: input.title,
8322
+ category: input.category,
8323
+ trigger: input.trigger,
8324
+ impact: input.impact,
8325
+ prevention: input.prevention
8326
+ }, workspaceId, projectId);
8327
+ if (isDuplicateLessonCapture(lessonSignature)) {
8328
+ return {
8329
+ content: [{
8330
+ type: "text",
8331
+ text: `\u2139\uFE0F Duplicate lesson capture ignored: "${input.title}" was already recorded recently.`
8332
+ }],
8333
+ structuredContent: {
8334
+ deduped: true,
8335
+ title: input.title
8336
+ }
8337
+ };
8338
+ }
8205
8339
  const lessonContent = [
8206
8340
  `## ${input.title}`,
8207
8341
  "",
@@ -8460,8 +8594,8 @@ Supported editors: ${getAvailableEditors().join(", ")}`,
8460
8594
  })
8461
8595
  },
8462
8596
  async (input) => {
8463
- const fs4 = await import("fs");
8464
- const path6 = await import("path");
8597
+ const fs5 = await import("fs");
8598
+ const path7 = await import("path");
8465
8599
  const editors = input.editors?.includes("all") || !input.editors ? getAvailableEditors() : input.editors.filter((e) => e !== "all");
8466
8600
  const results = [];
8467
8601
  for (const editor of editors) {
@@ -8476,7 +8610,7 @@ Supported editors: ${getAvailableEditors().join(", ")}`,
8476
8610
  results.push({ editor, filename: "", status: "unknown editor" });
8477
8611
  continue;
8478
8612
  }
8479
- const filePath = path6.join(input.folder_path, rule.filename);
8613
+ const filePath = path7.join(input.folder_path, rule.filename);
8480
8614
  if (input.dry_run) {
8481
8615
  results.push({
8482
8616
  editor,
@@ -8488,15 +8622,15 @@ Supported editors: ${getAvailableEditors().join(", ")}`,
8488
8622
  try {
8489
8623
  let existingContent = "";
8490
8624
  try {
8491
- existingContent = fs4.readFileSync(filePath, "utf-8");
8625
+ existingContent = fs5.readFileSync(filePath, "utf-8");
8492
8626
  } catch {
8493
8627
  }
8494
8628
  if (existingContent && !existingContent.includes("ContextStream Integration")) {
8495
8629
  const updatedContent = existingContent + "\n\n" + rule.content;
8496
- fs4.writeFileSync(filePath, updatedContent);
8630
+ fs5.writeFileSync(filePath, updatedContent);
8497
8631
  results.push({ editor, filename: rule.filename, status: "appended to existing" });
8498
8632
  } else {
8499
- fs4.writeFileSync(filePath, rule.content);
8633
+ fs5.writeFileSync(filePath, rule.content);
8500
8634
  results.push({ editor, filename: rule.filename, status: "created" });
8501
8635
  }
8502
8636
  } catch (err) {
@@ -9166,8 +9300,8 @@ var SessionManager = class {
9166
9300
  /**
9167
9301
  * Set the folder path hint (can be passed from tools that know the workspace path)
9168
9302
  */
9169
- setFolderPath(path6) {
9170
- this.folderPath = path6;
9303
+ setFolderPath(path7) {
9304
+ this.folderPath = path7;
9171
9305
  }
9172
9306
  /**
9173
9307
  * Mark that context_smart has been called in this session
@@ -9234,11 +9368,11 @@ var SessionManager = class {
9234
9368
  }
9235
9369
  if (this.ideRoots.length === 0) {
9236
9370
  const cwd = process.cwd();
9237
- const fs4 = await import("fs");
9371
+ const fs5 = await import("fs");
9238
9372
  const projectIndicators = [".git", "package.json", "Cargo.toml", "pyproject.toml", ".contextstream"];
9239
9373
  const hasProjectIndicator = projectIndicators.some((f) => {
9240
9374
  try {
9241
- return fs4.existsSync(`${cwd}/${f}`);
9375
+ return fs5.existsSync(`${cwd}/${f}`);
9242
9376
  } catch {
9243
9377
  return false;
9244
9378
  }
@@ -9416,15 +9550,79 @@ var SessionManager = class {
9416
9550
 
9417
9551
  // src/index.ts
9418
9552
  import { existsSync as existsSync2, mkdirSync as mkdirSync2, writeFileSync as writeFileSync2 } from "fs";
9419
- import { homedir as homedir2 } from "os";
9420
- import { join as join5 } from "path";
9553
+ import { homedir as homedir3 } from "os";
9554
+ import { join as join6 } from "path";
9421
9555
 
9422
9556
  // src/setup.ts
9557
+ import * as fs4 from "node:fs/promises";
9558
+ import * as path6 from "node:path";
9559
+ import { homedir as homedir2 } from "node:os";
9560
+ import { stdin, stdout } from "node:process";
9561
+ import { createInterface } from "node:readline/promises";
9562
+
9563
+ // src/credentials.ts
9423
9564
  import * as fs3 from "node:fs/promises";
9424
9565
  import * as path5 from "node:path";
9425
9566
  import { homedir } from "node:os";
9426
- import { stdin, stdout } from "node:process";
9427
- import { createInterface } from "node:readline/promises";
9567
+ function normalizeApiUrl(input) {
9568
+ return String(input ?? "").trim().replace(/\/+$/, "");
9569
+ }
9570
+ function credentialsFilePath() {
9571
+ return path5.join(homedir(), ".contextstream", "credentials.json");
9572
+ }
9573
+ function isRecord(value) {
9574
+ return typeof value === "object" && value !== null && !Array.isArray(value);
9575
+ }
9576
+ async function readSavedCredentials() {
9577
+ const filePath = credentialsFilePath();
9578
+ try {
9579
+ const raw = await fs3.readFile(filePath, "utf8");
9580
+ const parsed = JSON.parse(raw);
9581
+ if (!isRecord(parsed)) return null;
9582
+ const version = parsed.version;
9583
+ if (version !== 1) return null;
9584
+ const apiUrl = typeof parsed.api_url === "string" ? normalizeApiUrl(parsed.api_url) : "";
9585
+ const apiKey = typeof parsed.api_key === "string" ? parsed.api_key.trim() : "";
9586
+ if (!apiUrl || !apiKey) return null;
9587
+ const email = typeof parsed.email === "string" ? parsed.email.trim() : "";
9588
+ const createdAt = typeof parsed.created_at === "string" ? parsed.created_at : "";
9589
+ const updatedAt = typeof parsed.updated_at === "string" ? parsed.updated_at : "";
9590
+ const now = (/* @__PURE__ */ new Date()).toISOString();
9591
+ return {
9592
+ version: 1,
9593
+ api_url: apiUrl,
9594
+ api_key: apiKey,
9595
+ email: email || void 0,
9596
+ created_at: createdAt || now,
9597
+ updated_at: updatedAt || now
9598
+ };
9599
+ } catch {
9600
+ return null;
9601
+ }
9602
+ }
9603
+ async function writeSavedCredentials(input) {
9604
+ const filePath = credentialsFilePath();
9605
+ await fs3.mkdir(path5.dirname(filePath), { recursive: true });
9606
+ const now = (/* @__PURE__ */ new Date()).toISOString();
9607
+ const existing = await readSavedCredentials();
9608
+ const value = {
9609
+ version: 1,
9610
+ api_url: normalizeApiUrl(input.apiUrl),
9611
+ api_key: input.apiKey.trim(),
9612
+ email: input.email?.trim() || void 0,
9613
+ created_at: existing?.created_at || now,
9614
+ updated_at: now
9615
+ };
9616
+ const body = JSON.stringify(value, null, 2) + "\n";
9617
+ await fs3.writeFile(filePath, body, { encoding: "utf8", mode: 384 });
9618
+ try {
9619
+ await fs3.chmod(filePath, 384);
9620
+ } catch {
9621
+ }
9622
+ return { path: filePath, value };
9623
+ }
9624
+
9625
+ // src/setup.ts
9428
9626
  var EDITOR_LABELS = {
9429
9627
  codex: "Codex CLI",
9430
9628
  claude: "Claude Code",
@@ -9435,6 +9633,9 @@ var EDITOR_LABELS = {
9435
9633
  roo: "Roo Code",
9436
9634
  aider: "Aider"
9437
9635
  };
9636
+ function supportsProjectMcpConfig(editor) {
9637
+ return editor === "cursor" || editor === "claude" || editor === "kilo" || editor === "roo";
9638
+ }
9438
9639
  function normalizeInput(value) {
9439
9640
  return value.trim();
9440
9641
  }
@@ -9459,42 +9660,42 @@ function parseNumberList(input, max) {
9459
9660
  }
9460
9661
  async function fileExists(filePath) {
9461
9662
  try {
9462
- await fs3.stat(filePath);
9663
+ await fs4.stat(filePath);
9463
9664
  return true;
9464
9665
  } catch {
9465
9666
  return false;
9466
9667
  }
9467
9668
  }
9468
9669
  async function upsertTextFile(filePath, content, marker) {
9469
- await fs3.mkdir(path5.dirname(filePath), { recursive: true });
9670
+ await fs4.mkdir(path6.dirname(filePath), { recursive: true });
9470
9671
  const exists = await fileExists(filePath);
9471
9672
  if (!exists) {
9472
- await fs3.writeFile(filePath, content, "utf8");
9673
+ await fs4.writeFile(filePath, content, "utf8");
9473
9674
  return "created";
9474
9675
  }
9475
- const existing = await fs3.readFile(filePath, "utf8").catch(() => "");
9676
+ const existing = await fs4.readFile(filePath, "utf8").catch(() => "");
9476
9677
  if (existing.includes(marker)) return "skipped";
9477
9678
  const joined = existing.trimEnd() + "\n\n" + content.trim() + "\n";
9478
- await fs3.writeFile(filePath, joined, "utf8");
9679
+ await fs4.writeFile(filePath, joined, "utf8");
9479
9680
  return "appended";
9480
9681
  }
9481
9682
  function globalRulesPathForEditor(editor) {
9482
- const home = homedir();
9683
+ const home = homedir2();
9483
9684
  switch (editor) {
9484
9685
  case "codex":
9485
- return path5.join(home, ".codex", "AGENTS.md");
9686
+ return path6.join(home, ".codex", "AGENTS.md");
9486
9687
  case "claude":
9487
- return path5.join(home, ".claude", "CLAUDE.md");
9688
+ return path6.join(home, ".claude", "CLAUDE.md");
9488
9689
  case "windsurf":
9489
- return path5.join(home, ".codeium", "windsurf", "memories", "global_rules.md");
9690
+ return path6.join(home, ".codeium", "windsurf", "memories", "global_rules.md");
9490
9691
  case "cline":
9491
- return path5.join(home, "Documents", "Cline", "Rules", "contextstream.md");
9692
+ return path6.join(home, "Documents", "Cline", "Rules", "contextstream.md");
9492
9693
  case "kilo":
9493
- return path5.join(home, ".kilocode", "rules", "contextstream.md");
9694
+ return path6.join(home, ".kilocode", "rules", "contextstream.md");
9494
9695
  case "roo":
9495
- return path5.join(home, ".roo", "rules", "contextstream.md");
9696
+ return path6.join(home, ".roo", "rules", "contextstream.md");
9496
9697
  case "aider":
9497
- return path5.join(home, ".aider.conf.yml");
9698
+ return path6.join(home, ".aider.conf.yml");
9498
9699
  case "cursor":
9499
9700
  return null;
9500
9701
  default:
@@ -9541,11 +9742,11 @@ function tryParseJsonLike(raw) {
9541
9742
  }
9542
9743
  }
9543
9744
  async function upsertJsonMcpConfig(filePath, server) {
9544
- await fs3.mkdir(path5.dirname(filePath), { recursive: true });
9745
+ await fs4.mkdir(path6.dirname(filePath), { recursive: true });
9545
9746
  const exists = await fileExists(filePath);
9546
9747
  let root = {};
9547
9748
  if (exists) {
9548
- const raw = await fs3.readFile(filePath, "utf8").catch(() => "");
9749
+ const raw = await fs4.readFile(filePath, "utf8").catch(() => "");
9549
9750
  const parsed = tryParseJsonLike(raw);
9550
9751
  if (!parsed.ok) throw new Error(`Invalid JSON in ${filePath}: ${parsed.error}`);
9551
9752
  root = parsed.value;
@@ -9555,16 +9756,16 @@ async function upsertJsonMcpConfig(filePath, server) {
9555
9756
  const before = JSON.stringify(root.mcpServers.contextstream ?? null);
9556
9757
  root.mcpServers.contextstream = server;
9557
9758
  const after = JSON.stringify(root.mcpServers.contextstream ?? null);
9558
- await fs3.writeFile(filePath, JSON.stringify(root, null, 2) + "\n", "utf8");
9759
+ await fs4.writeFile(filePath, JSON.stringify(root, null, 2) + "\n", "utf8");
9559
9760
  if (!exists) return "created";
9560
9761
  return before === after ? "skipped" : "updated";
9561
9762
  }
9562
9763
  async function upsertJsonVsCodeMcpConfig(filePath, server) {
9563
- await fs3.mkdir(path5.dirname(filePath), { recursive: true });
9764
+ await fs4.mkdir(path6.dirname(filePath), { recursive: true });
9564
9765
  const exists = await fileExists(filePath);
9565
9766
  let root = {};
9566
9767
  if (exists) {
9567
- const raw = await fs3.readFile(filePath, "utf8").catch(() => "");
9768
+ const raw = await fs4.readFile(filePath, "utf8").catch(() => "");
9568
9769
  const parsed = tryParseJsonLike(raw);
9569
9770
  if (!parsed.ok) throw new Error(`Invalid JSON in ${filePath}: ${parsed.error}`);
9570
9771
  root = parsed.value;
@@ -9574,25 +9775,25 @@ async function upsertJsonVsCodeMcpConfig(filePath, server) {
9574
9775
  const before = JSON.stringify(root.servers.contextstream ?? null);
9575
9776
  root.servers.contextstream = server;
9576
9777
  const after = JSON.stringify(root.servers.contextstream ?? null);
9577
- await fs3.writeFile(filePath, JSON.stringify(root, null, 2) + "\n", "utf8");
9778
+ await fs4.writeFile(filePath, JSON.stringify(root, null, 2) + "\n", "utf8");
9578
9779
  if (!exists) return "created";
9579
9780
  return before === after ? "skipped" : "updated";
9580
9781
  }
9581
9782
  function claudeDesktopConfigPath() {
9582
- const home = homedir();
9783
+ const home = homedir2();
9583
9784
  if (process.platform === "darwin") {
9584
- return path5.join(home, "Library", "Application Support", "Claude", "claude_desktop_config.json");
9785
+ return path6.join(home, "Library", "Application Support", "Claude", "claude_desktop_config.json");
9585
9786
  }
9586
9787
  if (process.platform === "win32") {
9587
- const appData = process.env.APPDATA || path5.join(home, "AppData", "Roaming");
9588
- return path5.join(appData, "Claude", "claude_desktop_config.json");
9788
+ const appData = process.env.APPDATA || path6.join(home, "AppData", "Roaming");
9789
+ return path6.join(appData, "Claude", "claude_desktop_config.json");
9589
9790
  }
9590
9791
  return null;
9591
9792
  }
9592
9793
  async function upsertCodexTomlConfig(filePath, params) {
9593
- await fs3.mkdir(path5.dirname(filePath), { recursive: true });
9794
+ await fs4.mkdir(path6.dirname(filePath), { recursive: true });
9594
9795
  const exists = await fileExists(filePath);
9595
- const existing = exists ? await fs3.readFile(filePath, "utf8").catch(() => "") : "";
9796
+ const existing = exists ? await fs4.readFile(filePath, "utf8").catch(() => "") : "";
9596
9797
  const marker = "[mcp_servers.contextstream]";
9597
9798
  const envMarker = "[mcp_servers.contextstream.env]";
9598
9799
  const block = `
@@ -9607,15 +9808,15 @@ CONTEXTSTREAM_API_URL = "${params.apiUrl}"
9607
9808
  CONTEXTSTREAM_API_KEY = "${params.apiKey}"
9608
9809
  `;
9609
9810
  if (!exists) {
9610
- await fs3.writeFile(filePath, block.trimStart(), "utf8");
9811
+ await fs4.writeFile(filePath, block.trimStart(), "utf8");
9611
9812
  return "created";
9612
9813
  }
9613
9814
  if (!existing.includes(marker)) {
9614
- await fs3.writeFile(filePath, existing.trimEnd() + block, "utf8");
9815
+ await fs4.writeFile(filePath, existing.trimEnd() + block, "utf8");
9615
9816
  return "updated";
9616
9817
  }
9617
9818
  if (!existing.includes(envMarker)) {
9618
- await fs3.writeFile(filePath, existing.trimEnd() + "\n\n" + envMarker + `
9819
+ await fs4.writeFile(filePath, existing.trimEnd() + "\n\n" + envMarker + `
9619
9820
  CONTEXTSTREAM_API_URL = "${params.apiUrl}"
9620
9821
  CONTEXTSTREAM_API_KEY = "${params.apiKey}"
9621
9822
  `, "utf8");
@@ -9656,18 +9857,18 @@ CONTEXTSTREAM_API_KEY = "${params.apiKey}"
9656
9857
  }
9657
9858
  const updated = out.join("\n");
9658
9859
  if (updated === existing) return "skipped";
9659
- await fs3.writeFile(filePath, updated, "utf8");
9860
+ await fs4.writeFile(filePath, updated, "utf8");
9660
9861
  return "updated";
9661
9862
  }
9662
9863
  async function discoverProjectsUnderFolder(parentFolder) {
9663
- const entries = await fs3.readdir(parentFolder, { withFileTypes: true });
9664
- const candidates = entries.filter((e) => e.isDirectory() && !e.name.startsWith(".")).map((e) => path5.join(parentFolder, e.name));
9864
+ const entries = await fs4.readdir(parentFolder, { withFileTypes: true });
9865
+ const candidates = entries.filter((e) => e.isDirectory() && !e.name.startsWith(".")).map((e) => path6.join(parentFolder, e.name));
9665
9866
  const projects = [];
9666
9867
  for (const dir of candidates) {
9667
- const hasGit = await fileExists(path5.join(dir, ".git"));
9668
- const hasPkg = await fileExists(path5.join(dir, "package.json"));
9669
- const hasCargo = await fileExists(path5.join(dir, "Cargo.toml"));
9670
- const hasPyProject = await fileExists(path5.join(dir, "pyproject.toml"));
9868
+ const hasGit = await fileExists(path6.join(dir, ".git"));
9869
+ const hasPkg = await fileExists(path6.join(dir, "package.json"));
9870
+ const hasCargo = await fileExists(path6.join(dir, "Cargo.toml"));
9871
+ const hasPyProject = await fileExists(path6.join(dir, "pyproject.toml"));
9671
9872
  if (hasGit || hasPkg || hasCargo || hasPyProject) projects.push(dir);
9672
9873
  }
9673
9874
  return projects;
@@ -9691,16 +9892,32 @@ async function runSetupWizard(args) {
9691
9892
  console.log("This configures ContextStream MCP + rules for your AI editor(s).");
9692
9893
  if (dryRun) console.log("DRY RUN: no files will be written.\n");
9693
9894
  else console.log("");
9694
- const apiUrlDefault = process.env.CONTEXTSTREAM_API_URL || "https://api.contextstream.io";
9695
- const apiUrl = normalizeInput(
9696
- await rl.question(`ContextStream API URL [${apiUrlDefault}]: `)
9697
- ) || apiUrlDefault;
9895
+ const savedCreds = await readSavedCredentials();
9896
+ const apiUrlDefault = normalizeApiUrl(process.env.CONTEXTSTREAM_API_URL || savedCreds?.api_url || "https://api.contextstream.io");
9897
+ const apiUrl = normalizeApiUrl(
9898
+ normalizeInput(await rl.question(`ContextStream API URL [${apiUrlDefault}]: `)) || apiUrlDefault
9899
+ );
9698
9900
  let apiKey = normalizeInput(process.env.CONTEXTSTREAM_API_KEY || "");
9901
+ let apiKeySource = apiKey ? "env" : "unknown";
9699
9902
  if (apiKey) {
9700
9903
  const confirm = normalizeInput(
9701
9904
  await rl.question(`Use CONTEXTSTREAM_API_KEY from environment (${maskApiKey(apiKey)})? [Y/n]: `)
9702
9905
  );
9703
- if (confirm.toLowerCase() === "n" || confirm.toLowerCase() === "no") apiKey = "";
9906
+ if (confirm.toLowerCase() === "n" || confirm.toLowerCase() === "no") {
9907
+ apiKey = "";
9908
+ apiKeySource = "unknown";
9909
+ }
9910
+ }
9911
+ if (!apiKey && savedCreds?.api_key && normalizeApiUrl(savedCreds.api_url) === apiUrl) {
9912
+ const confirm = normalizeInput(
9913
+ await rl.question(
9914
+ `Use saved API key from ${credentialsFilePath()} (${maskApiKey(savedCreds.api_key)})? [Y/n]: `
9915
+ )
9916
+ );
9917
+ if (!(confirm.toLowerCase() === "n" || confirm.toLowerCase() === "no")) {
9918
+ apiKey = savedCreds.api_key;
9919
+ apiKeySource = "saved";
9920
+ }
9704
9921
  }
9705
9922
  if (!apiKey) {
9706
9923
  console.log("\nAuthentication:");
@@ -9711,6 +9928,7 @@ async function runSetupWizard(args) {
9711
9928
  console.log("\nYou need a ContextStream API key to continue.");
9712
9929
  console.log("Create one here (then paste it): https://app.contextstream.io/settings/api-keys\n");
9713
9930
  apiKey = normalizeInput(await rl.question("CONTEXTSTREAM_API_KEY: "));
9931
+ apiKeySource = "paste";
9714
9932
  } else {
9715
9933
  const anonClient = new ContextStreamClient(buildClientConfig({ apiUrl }));
9716
9934
  let device;
@@ -9773,6 +9991,7 @@ Code: ${device.user_code}`);
9773
9991
  throw new Error("API key creation returned an unexpected response.");
9774
9992
  }
9775
9993
  apiKey = createdKey.secret_key.trim();
9994
+ apiKeySource = "browser";
9776
9995
  console.log(`
9777
9996
  Created API key: ${maskApiKey(apiKey)}
9778
9997
  `);
@@ -9789,6 +10008,17 @@ Created API key: ${maskApiKey(apiKey)}
9789
10008
  const email = typeof me?.data?.email === "string" ? me.data.email : typeof me?.email === "string" ? me.email : void 0;
9790
10009
  console.log(`Authenticated as: ${email || "unknown user"} (${maskApiKey(apiKey)})
9791
10010
  `);
10011
+ if (!dryRun && (apiKeySource === "browser" || apiKeySource === "paste")) {
10012
+ try {
10013
+ const saved = await writeSavedCredentials({ apiUrl, apiKey, email });
10014
+ console.log(`Saved API key for future runs: ${saved.path} (${maskApiKey(apiKey)})
10015
+ `);
10016
+ } catch (err) {
10017
+ const msg = err instanceof Error ? err.message : String(err);
10018
+ console.log(`Warning: failed to save API key for future runs (${credentialsFilePath()}): ${msg}
10019
+ `);
10020
+ }
10021
+ }
9792
10022
  let workspaceId;
9793
10023
  let workspaceName;
9794
10024
  console.log("Workspace setup:");
@@ -9851,6 +10081,8 @@ Created API key: ${maskApiKey(apiKey)}
9851
10081
  const selectedRaw = normalizeInput(await rl.question("Editors [all]: ")) || "all";
9852
10082
  const selectedNums = parseNumberList(selectedRaw, editors.length);
9853
10083
  const selectedEditors = selectedNums.length ? selectedNums.map((n) => editors[n - 1]) : editors;
10084
+ const hasCodex = selectedEditors.includes("codex");
10085
+ const hasProjectMcpEditors = selectedEditors.some((e) => supportsProjectMcpConfig(e));
9854
10086
  console.log("\nInstall rules as:");
9855
10087
  console.log(" 1) Global");
9856
10088
  console.log(" 2) Project");
@@ -9858,20 +10090,31 @@ Created API key: ${maskApiKey(apiKey)}
9858
10090
  const scopeChoice = normalizeInput(await rl.question("Choose [1/2/3] (default 3): ")) || "3";
9859
10091
  const scope = scopeChoice === "1" ? "global" : scopeChoice === "2" ? "project" : "both";
9860
10092
  console.log("\nInstall MCP server config as:");
9861
- console.log(" 1) Global");
9862
- console.log(" 2) Project");
9863
- console.log(" 3) Both");
9864
- console.log(" 4) Skip (rules only)");
9865
- const mcpChoice = normalizeInput(await rl.question("Choose [1/2/3/4] (default 3): ")) || "3";
9866
- const mcpScope = mcpChoice === "4" ? "skip" : mcpChoice === "1" ? "global" : mcpChoice === "2" ? "project" : "both";
10093
+ if (hasCodex && !hasProjectMcpEditors) {
10094
+ console.log(" 1) Global (Codex CLI supports global config only)");
10095
+ console.log(" 2) Skip (rules only)");
10096
+ } else {
10097
+ console.log(" 1) Global");
10098
+ console.log(" 2) Project");
10099
+ console.log(" 3) Both");
10100
+ console.log(" 4) Skip (rules only)");
10101
+ if (hasCodex) {
10102
+ console.log(" Note: Codex CLI does not support per-project MCP config; it will be configured globally if selected.");
10103
+ }
10104
+ }
10105
+ const mcpChoiceDefault = hasCodex && !hasProjectMcpEditors ? "1" : "3";
10106
+ const mcpChoice = normalizeInput(await rl.question(`Choose [${hasCodex && !hasProjectMcpEditors ? "1/2" : "1/2/3/4"}] (default ${mcpChoiceDefault}): `)) || mcpChoiceDefault;
10107
+ const mcpScope = mcpChoice === "2" && hasCodex && !hasProjectMcpEditors ? "skip" : mcpChoice === "4" ? "skip" : mcpChoice === "1" ? "global" : mcpChoice === "2" ? "project" : "both";
9867
10108
  const mcpServer = buildContextStreamMcpServer({ apiUrl, apiKey });
9868
10109
  const vsCodeServer = buildContextStreamVsCodeServer({ apiUrl, apiKey });
9869
- if (mcpScope === "global" || mcpScope === "both") {
10110
+ const needsGlobalMcpConfig = mcpScope === "global" || mcpScope === "both" || mcpScope === "project" && hasCodex;
10111
+ if (needsGlobalMcpConfig) {
9870
10112
  console.log("\nInstalling global MCP config...");
9871
10113
  for (const editor of selectedEditors) {
10114
+ if (mcpScope === "project" && editor !== "codex") continue;
9872
10115
  try {
9873
10116
  if (editor === "codex") {
9874
- const filePath = path5.join(homedir(), ".codex", "config.toml");
10117
+ const filePath = path6.join(homedir2(), ".codex", "config.toml");
9875
10118
  if (dryRun) {
9876
10119
  writeActions.push({ kind: "mcp-config", target: filePath, status: "dry-run" });
9877
10120
  console.log(`- ${EDITOR_LABELS[editor]}: would update ${filePath}`);
@@ -9883,7 +10126,7 @@ Created API key: ${maskApiKey(apiKey)}
9883
10126
  continue;
9884
10127
  }
9885
10128
  if (editor === "windsurf") {
9886
- const filePath = path5.join(homedir(), ".codeium", "windsurf", "mcp_config.json");
10129
+ const filePath = path6.join(homedir2(), ".codeium", "windsurf", "mcp_config.json");
9887
10130
  if (dryRun) {
9888
10131
  writeActions.push({ kind: "mcp-config", target: filePath, status: "dry-run" });
9889
10132
  console.log(`- ${EDITOR_LABELS[editor]}: would update ${filePath}`);
@@ -9915,7 +10158,7 @@ Created API key: ${maskApiKey(apiKey)}
9915
10158
  continue;
9916
10159
  }
9917
10160
  if (editor === "cursor") {
9918
- const filePath = path5.join(homedir(), ".cursor", "mcp.json");
10161
+ const filePath = path6.join(homedir2(), ".cursor", "mcp.json");
9919
10162
  if (dryRun) {
9920
10163
  writeActions.push({ kind: "mcp-config", target: filePath, status: "dry-run" });
9921
10164
  console.log(`- ${EDITOR_LABELS[editor]}: would update ${filePath}`);
@@ -9969,12 +10212,12 @@ Created API key: ${maskApiKey(apiKey)}
9969
10212
  }
9970
10213
  }
9971
10214
  const projectPaths = /* @__PURE__ */ new Set();
9972
- const needsProjects = scope === "project" || scope === "both" || mcpScope === "project" || mcpScope === "both";
10215
+ const needsProjects = scope === "project" || scope === "both" || (mcpScope === "project" || mcpScope === "both") && hasProjectMcpEditors;
9973
10216
  if (needsProjects) {
9974
10217
  console.log("\nProject setup...");
9975
10218
  const addCwd = normalizeInput(await rl.question(`Add current folder as a project? [Y/n] (${process.cwd()}): `));
9976
10219
  if (addCwd.toLowerCase() !== "n" && addCwd.toLowerCase() !== "no") {
9977
- projectPaths.add(path5.resolve(process.cwd()));
10220
+ projectPaths.add(path6.resolve(process.cwd()));
9978
10221
  }
9979
10222
  while (true) {
9980
10223
  console.log("\n 1) Add another project path");
@@ -9984,13 +10227,13 @@ Created API key: ${maskApiKey(apiKey)}
9984
10227
  if (choice === "3") break;
9985
10228
  if (choice === "1") {
9986
10229
  const p = normalizeInput(await rl.question("Project folder path: "));
9987
- if (p) projectPaths.add(path5.resolve(p));
10230
+ if (p) projectPaths.add(path6.resolve(p));
9988
10231
  continue;
9989
10232
  }
9990
10233
  if (choice === "2") {
9991
10234
  const parent = normalizeInput(await rl.question("Parent folder path: "));
9992
10235
  if (!parent) continue;
9993
- const parentAbs = path5.resolve(parent);
10236
+ const parentAbs = path6.resolve(parent);
9994
10237
  const projects2 = await discoverProjectsUnderFolder(parentAbs);
9995
10238
  if (projects2.length === 0) {
9996
10239
  console.log(`No projects detected under ${parentAbs} (looked for .git/package.json/Cargo.toml/pyproject.toml).`);
@@ -10020,21 +10263,21 @@ Applying to ${projects.length} project(s)...`);
10020
10263
  workspace_name: workspaceName,
10021
10264
  create_parent_mapping: createParentMapping
10022
10265
  });
10023
- writeActions.push({ kind: "workspace-config", target: path5.join(projectPath, ".contextstream", "config.json"), status: "created" });
10266
+ writeActions.push({ kind: "workspace-config", target: path6.join(projectPath, ".contextstream", "config.json"), status: "created" });
10024
10267
  console.log(`- Linked workspace in ${projectPath}`);
10025
10268
  } catch (err) {
10026
10269
  const message = err instanceof Error ? err.message : String(err);
10027
10270
  console.log(`- Failed to link workspace in ${projectPath}: ${message}`);
10028
10271
  }
10029
10272
  } else if (workspaceId && workspaceId !== "dry-run" && workspaceName && dryRun) {
10030
- writeActions.push({ kind: "workspace-config", target: path5.join(projectPath, ".contextstream", "config.json"), status: "dry-run" });
10273
+ writeActions.push({ kind: "workspace-config", target: path6.join(projectPath, ".contextstream", "config.json"), status: "dry-run" });
10031
10274
  }
10032
10275
  if (mcpScope === "project" || mcpScope === "both") {
10033
10276
  for (const editor of selectedEditors) {
10034
10277
  try {
10035
10278
  if (editor === "cursor") {
10036
- const cursorPath = path5.join(projectPath, ".cursor", "mcp.json");
10037
- const vscodePath = path5.join(projectPath, ".vscode", "mcp.json");
10279
+ const cursorPath = path6.join(projectPath, ".cursor", "mcp.json");
10280
+ const vscodePath = path6.join(projectPath, ".vscode", "mcp.json");
10038
10281
  if (dryRun) {
10039
10282
  writeActions.push({ kind: "mcp-config", target: cursorPath, status: "dry-run" });
10040
10283
  writeActions.push({ kind: "mcp-config", target: vscodePath, status: "dry-run" });
@@ -10047,7 +10290,7 @@ Applying to ${projects.length} project(s)...`);
10047
10290
  continue;
10048
10291
  }
10049
10292
  if (editor === "claude") {
10050
- const mcpPath = path5.join(projectPath, ".mcp.json");
10293
+ const mcpPath = path6.join(projectPath, ".mcp.json");
10051
10294
  if (dryRun) {
10052
10295
  writeActions.push({ kind: "mcp-config", target: mcpPath, status: "dry-run" });
10053
10296
  } else {
@@ -10057,7 +10300,7 @@ Applying to ${projects.length} project(s)...`);
10057
10300
  continue;
10058
10301
  }
10059
10302
  if (editor === "kilo") {
10060
- const kiloPath = path5.join(projectPath, ".kilocode", "mcp.json");
10303
+ const kiloPath = path6.join(projectPath, ".kilocode", "mcp.json");
10061
10304
  if (dryRun) {
10062
10305
  writeActions.push({ kind: "mcp-config", target: kiloPath, status: "dry-run" });
10063
10306
  } else {
@@ -10067,7 +10310,7 @@ Applying to ${projects.length} project(s)...`);
10067
10310
  continue;
10068
10311
  }
10069
10312
  if (editor === "roo") {
10070
- const rooPath = path5.join(projectPath, ".roo", "mcp.json");
10313
+ const rooPath = path6.join(projectPath, ".roo", "mcp.json");
10071
10314
  if (dryRun) {
10072
10315
  writeActions.push({ kind: "mcp-config", target: rooPath, status: "dry-run" });
10073
10316
  } else {
@@ -10087,11 +10330,11 @@ Applying to ${projects.length} project(s)...`);
10087
10330
  const rule = generateRuleContent(editor, {
10088
10331
  workspaceName,
10089
10332
  workspaceId: workspaceId && workspaceId !== "dry-run" ? workspaceId : void 0,
10090
- projectName: path5.basename(projectPath),
10333
+ projectName: path6.basename(projectPath),
10091
10334
  mode
10092
10335
  });
10093
10336
  if (!rule) continue;
10094
- const filePath = path5.join(projectPath, rule.filename);
10337
+ const filePath = path6.join(projectPath, rule.filename);
10095
10338
  if (dryRun) {
10096
10339
  writeActions.push({ kind: "rules", target: filePath, status: "dry-run" });
10097
10340
  continue;
@@ -10124,8 +10367,8 @@ Applying to ${projects.length} project(s)...`);
10124
10367
 
10125
10368
  // src/index.ts
10126
10369
  function showFirstRunMessage() {
10127
- const configDir = join5(homedir2(), ".contextstream");
10128
- const starShownFile = join5(configDir, ".star-shown");
10370
+ const configDir = join6(homedir3(), ".contextstream");
10371
+ const starShownFile = join6(configDir, ".star-shown");
10129
10372
  if (existsSync2(starShownFile)) {
10130
10373
  return;
10131
10374
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@contextstream/mcp-server",
3
- "version": "0.3.30",
3
+ "version": "0.3.32",
4
4
  "description": "MCP server exposing ContextStream public API - code context, memory, search, and AI tools for developers",
5
5
  "type": "module",
6
6
  "license": "MIT",