@contextstream/mcp-server 0.3.30 → 0.3.31

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 +305 -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) {
@@ -7936,26 +8020,26 @@ Optionally generates AI editor rules for automatic ContextStream usage.`,
7936
8020
  const result = await client.associateWorkspace(input);
7937
8021
  let rulesGenerated = [];
7938
8022
  if (input.generate_editor_rules) {
7939
- const fs4 = await import("fs");
7940
- const path6 = await import("path");
8023
+ const fs5 = await import("fs");
8024
+ const path7 = await import("path");
7941
8025
  for (const editor of getAvailableEditors()) {
7942
8026
  const rule = generateRuleContent(editor, {
7943
8027
  workspaceName: input.workspace_name,
7944
8028
  workspaceId: input.workspace_id
7945
8029
  });
7946
8030
  if (rule) {
7947
- const filePath = path6.join(input.folder_path, rule.filename);
8031
+ const filePath = path7.join(input.folder_path, rule.filename);
7948
8032
  try {
7949
8033
  let existingContent = "";
7950
8034
  try {
7951
- existingContent = fs4.readFileSync(filePath, "utf-8");
8035
+ existingContent = fs5.readFileSync(filePath, "utf-8");
7952
8036
  } catch {
7953
8037
  }
7954
8038
  if (!existingContent) {
7955
- fs4.writeFileSync(filePath, rule.content);
8039
+ fs5.writeFileSync(filePath, rule.content);
7956
8040
  rulesGenerated.push(rule.filename);
7957
8041
  } else if (!existingContent.includes("ContextStream Integration")) {
7958
- fs4.writeFileSync(filePath, existingContent + "\n\n" + rule.content);
8042
+ fs5.writeFileSync(filePath, existingContent + "\n\n" + rule.content);
7959
8043
  rulesGenerated.push(rule.filename + " (appended)");
7960
8044
  }
7961
8045
  } catch {
@@ -8041,26 +8125,26 @@ Behavior:
8041
8125
  });
8042
8126
  let rulesGenerated = [];
8043
8127
  if (input.generate_editor_rules) {
8044
- const fs4 = await import("fs");
8045
- const path6 = await import("path");
8128
+ const fs5 = await import("fs");
8129
+ const path7 = await import("path");
8046
8130
  for (const editor of getAvailableEditors()) {
8047
8131
  const rule = generateRuleContent(editor, {
8048
8132
  workspaceName: newWorkspace.name || input.workspace_name,
8049
8133
  workspaceId: newWorkspace.id
8050
8134
  });
8051
8135
  if (!rule) continue;
8052
- const filePath = path6.join(folderPath, rule.filename);
8136
+ const filePath = path7.join(folderPath, rule.filename);
8053
8137
  try {
8054
8138
  let existingContent = "";
8055
8139
  try {
8056
- existingContent = fs4.readFileSync(filePath, "utf-8");
8140
+ existingContent = fs5.readFileSync(filePath, "utf-8");
8057
8141
  } catch {
8058
8142
  }
8059
8143
  if (!existingContent) {
8060
- fs4.writeFileSync(filePath, rule.content);
8144
+ fs5.writeFileSync(filePath, rule.content);
8061
8145
  rulesGenerated.push(rule.filename);
8062
8146
  } else if (!existingContent.includes("ContextStream Integration")) {
8063
- fs4.writeFileSync(filePath, existingContent + "\n\n" + rule.content);
8147
+ fs5.writeFileSync(filePath, existingContent + "\n\n" + rule.content);
8064
8148
  rulesGenerated.push(rule.filename + " (appended)");
8065
8149
  }
8066
8150
  } catch {
@@ -8460,8 +8544,8 @@ Supported editors: ${getAvailableEditors().join(", ")}`,
8460
8544
  })
8461
8545
  },
8462
8546
  async (input) => {
8463
- const fs4 = await import("fs");
8464
- const path6 = await import("path");
8547
+ const fs5 = await import("fs");
8548
+ const path7 = await import("path");
8465
8549
  const editors = input.editors?.includes("all") || !input.editors ? getAvailableEditors() : input.editors.filter((e) => e !== "all");
8466
8550
  const results = [];
8467
8551
  for (const editor of editors) {
@@ -8476,7 +8560,7 @@ Supported editors: ${getAvailableEditors().join(", ")}`,
8476
8560
  results.push({ editor, filename: "", status: "unknown editor" });
8477
8561
  continue;
8478
8562
  }
8479
- const filePath = path6.join(input.folder_path, rule.filename);
8563
+ const filePath = path7.join(input.folder_path, rule.filename);
8480
8564
  if (input.dry_run) {
8481
8565
  results.push({
8482
8566
  editor,
@@ -8488,15 +8572,15 @@ Supported editors: ${getAvailableEditors().join(", ")}`,
8488
8572
  try {
8489
8573
  let existingContent = "";
8490
8574
  try {
8491
- existingContent = fs4.readFileSync(filePath, "utf-8");
8575
+ existingContent = fs5.readFileSync(filePath, "utf-8");
8492
8576
  } catch {
8493
8577
  }
8494
8578
  if (existingContent && !existingContent.includes("ContextStream Integration")) {
8495
8579
  const updatedContent = existingContent + "\n\n" + rule.content;
8496
- fs4.writeFileSync(filePath, updatedContent);
8580
+ fs5.writeFileSync(filePath, updatedContent);
8497
8581
  results.push({ editor, filename: rule.filename, status: "appended to existing" });
8498
8582
  } else {
8499
- fs4.writeFileSync(filePath, rule.content);
8583
+ fs5.writeFileSync(filePath, rule.content);
8500
8584
  results.push({ editor, filename: rule.filename, status: "created" });
8501
8585
  }
8502
8586
  } catch (err) {
@@ -9166,8 +9250,8 @@ var SessionManager = class {
9166
9250
  /**
9167
9251
  * Set the folder path hint (can be passed from tools that know the workspace path)
9168
9252
  */
9169
- setFolderPath(path6) {
9170
- this.folderPath = path6;
9253
+ setFolderPath(path7) {
9254
+ this.folderPath = path7;
9171
9255
  }
9172
9256
  /**
9173
9257
  * Mark that context_smart has been called in this session
@@ -9234,11 +9318,11 @@ var SessionManager = class {
9234
9318
  }
9235
9319
  if (this.ideRoots.length === 0) {
9236
9320
  const cwd = process.cwd();
9237
- const fs4 = await import("fs");
9321
+ const fs5 = await import("fs");
9238
9322
  const projectIndicators = [".git", "package.json", "Cargo.toml", "pyproject.toml", ".contextstream"];
9239
9323
  const hasProjectIndicator = projectIndicators.some((f) => {
9240
9324
  try {
9241
- return fs4.existsSync(`${cwd}/${f}`);
9325
+ return fs5.existsSync(`${cwd}/${f}`);
9242
9326
  } catch {
9243
9327
  return false;
9244
9328
  }
@@ -9416,15 +9500,79 @@ var SessionManager = class {
9416
9500
 
9417
9501
  // src/index.ts
9418
9502
  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";
9503
+ import { homedir as homedir3 } from "os";
9504
+ import { join as join6 } from "path";
9421
9505
 
9422
9506
  // src/setup.ts
9507
+ import * as fs4 from "node:fs/promises";
9508
+ import * as path6 from "node:path";
9509
+ import { homedir as homedir2 } from "node:os";
9510
+ import { stdin, stdout } from "node:process";
9511
+ import { createInterface } from "node:readline/promises";
9512
+
9513
+ // src/credentials.ts
9423
9514
  import * as fs3 from "node:fs/promises";
9424
9515
  import * as path5 from "node:path";
9425
9516
  import { homedir } from "node:os";
9426
- import { stdin, stdout } from "node:process";
9427
- import { createInterface } from "node:readline/promises";
9517
+ function normalizeApiUrl(input) {
9518
+ return String(input ?? "").trim().replace(/\/+$/, "");
9519
+ }
9520
+ function credentialsFilePath() {
9521
+ return path5.join(homedir(), ".contextstream", "credentials.json");
9522
+ }
9523
+ function isRecord(value) {
9524
+ return typeof value === "object" && value !== null && !Array.isArray(value);
9525
+ }
9526
+ async function readSavedCredentials() {
9527
+ const filePath = credentialsFilePath();
9528
+ try {
9529
+ const raw = await fs3.readFile(filePath, "utf8");
9530
+ const parsed = JSON.parse(raw);
9531
+ if (!isRecord(parsed)) return null;
9532
+ const version = parsed.version;
9533
+ if (version !== 1) return null;
9534
+ const apiUrl = typeof parsed.api_url === "string" ? normalizeApiUrl(parsed.api_url) : "";
9535
+ const apiKey = typeof parsed.api_key === "string" ? parsed.api_key.trim() : "";
9536
+ if (!apiUrl || !apiKey) return null;
9537
+ const email = typeof parsed.email === "string" ? parsed.email.trim() : "";
9538
+ const createdAt = typeof parsed.created_at === "string" ? parsed.created_at : "";
9539
+ const updatedAt = typeof parsed.updated_at === "string" ? parsed.updated_at : "";
9540
+ const now = (/* @__PURE__ */ new Date()).toISOString();
9541
+ return {
9542
+ version: 1,
9543
+ api_url: apiUrl,
9544
+ api_key: apiKey,
9545
+ email: email || void 0,
9546
+ created_at: createdAt || now,
9547
+ updated_at: updatedAt || now
9548
+ };
9549
+ } catch {
9550
+ return null;
9551
+ }
9552
+ }
9553
+ async function writeSavedCredentials(input) {
9554
+ const filePath = credentialsFilePath();
9555
+ await fs3.mkdir(path5.dirname(filePath), { recursive: true });
9556
+ const now = (/* @__PURE__ */ new Date()).toISOString();
9557
+ const existing = await readSavedCredentials();
9558
+ const value = {
9559
+ version: 1,
9560
+ api_url: normalizeApiUrl(input.apiUrl),
9561
+ api_key: input.apiKey.trim(),
9562
+ email: input.email?.trim() || void 0,
9563
+ created_at: existing?.created_at || now,
9564
+ updated_at: now
9565
+ };
9566
+ const body = JSON.stringify(value, null, 2) + "\n";
9567
+ await fs3.writeFile(filePath, body, { encoding: "utf8", mode: 384 });
9568
+ try {
9569
+ await fs3.chmod(filePath, 384);
9570
+ } catch {
9571
+ }
9572
+ return { path: filePath, value };
9573
+ }
9574
+
9575
+ // src/setup.ts
9428
9576
  var EDITOR_LABELS = {
9429
9577
  codex: "Codex CLI",
9430
9578
  claude: "Claude Code",
@@ -9435,6 +9583,9 @@ var EDITOR_LABELS = {
9435
9583
  roo: "Roo Code",
9436
9584
  aider: "Aider"
9437
9585
  };
9586
+ function supportsProjectMcpConfig(editor) {
9587
+ return editor === "cursor" || editor === "claude" || editor === "kilo" || editor === "roo";
9588
+ }
9438
9589
  function normalizeInput(value) {
9439
9590
  return value.trim();
9440
9591
  }
@@ -9459,42 +9610,42 @@ function parseNumberList(input, max) {
9459
9610
  }
9460
9611
  async function fileExists(filePath) {
9461
9612
  try {
9462
- await fs3.stat(filePath);
9613
+ await fs4.stat(filePath);
9463
9614
  return true;
9464
9615
  } catch {
9465
9616
  return false;
9466
9617
  }
9467
9618
  }
9468
9619
  async function upsertTextFile(filePath, content, marker) {
9469
- await fs3.mkdir(path5.dirname(filePath), { recursive: true });
9620
+ await fs4.mkdir(path6.dirname(filePath), { recursive: true });
9470
9621
  const exists = await fileExists(filePath);
9471
9622
  if (!exists) {
9472
- await fs3.writeFile(filePath, content, "utf8");
9623
+ await fs4.writeFile(filePath, content, "utf8");
9473
9624
  return "created";
9474
9625
  }
9475
- const existing = await fs3.readFile(filePath, "utf8").catch(() => "");
9626
+ const existing = await fs4.readFile(filePath, "utf8").catch(() => "");
9476
9627
  if (existing.includes(marker)) return "skipped";
9477
9628
  const joined = existing.trimEnd() + "\n\n" + content.trim() + "\n";
9478
- await fs3.writeFile(filePath, joined, "utf8");
9629
+ await fs4.writeFile(filePath, joined, "utf8");
9479
9630
  return "appended";
9480
9631
  }
9481
9632
  function globalRulesPathForEditor(editor) {
9482
- const home = homedir();
9633
+ const home = homedir2();
9483
9634
  switch (editor) {
9484
9635
  case "codex":
9485
- return path5.join(home, ".codex", "AGENTS.md");
9636
+ return path6.join(home, ".codex", "AGENTS.md");
9486
9637
  case "claude":
9487
- return path5.join(home, ".claude", "CLAUDE.md");
9638
+ return path6.join(home, ".claude", "CLAUDE.md");
9488
9639
  case "windsurf":
9489
- return path5.join(home, ".codeium", "windsurf", "memories", "global_rules.md");
9640
+ return path6.join(home, ".codeium", "windsurf", "memories", "global_rules.md");
9490
9641
  case "cline":
9491
- return path5.join(home, "Documents", "Cline", "Rules", "contextstream.md");
9642
+ return path6.join(home, "Documents", "Cline", "Rules", "contextstream.md");
9492
9643
  case "kilo":
9493
- return path5.join(home, ".kilocode", "rules", "contextstream.md");
9644
+ return path6.join(home, ".kilocode", "rules", "contextstream.md");
9494
9645
  case "roo":
9495
- return path5.join(home, ".roo", "rules", "contextstream.md");
9646
+ return path6.join(home, ".roo", "rules", "contextstream.md");
9496
9647
  case "aider":
9497
- return path5.join(home, ".aider.conf.yml");
9648
+ return path6.join(home, ".aider.conf.yml");
9498
9649
  case "cursor":
9499
9650
  return null;
9500
9651
  default:
@@ -9541,11 +9692,11 @@ function tryParseJsonLike(raw) {
9541
9692
  }
9542
9693
  }
9543
9694
  async function upsertJsonMcpConfig(filePath, server) {
9544
- await fs3.mkdir(path5.dirname(filePath), { recursive: true });
9695
+ await fs4.mkdir(path6.dirname(filePath), { recursive: true });
9545
9696
  const exists = await fileExists(filePath);
9546
9697
  let root = {};
9547
9698
  if (exists) {
9548
- const raw = await fs3.readFile(filePath, "utf8").catch(() => "");
9699
+ const raw = await fs4.readFile(filePath, "utf8").catch(() => "");
9549
9700
  const parsed = tryParseJsonLike(raw);
9550
9701
  if (!parsed.ok) throw new Error(`Invalid JSON in ${filePath}: ${parsed.error}`);
9551
9702
  root = parsed.value;
@@ -9555,16 +9706,16 @@ async function upsertJsonMcpConfig(filePath, server) {
9555
9706
  const before = JSON.stringify(root.mcpServers.contextstream ?? null);
9556
9707
  root.mcpServers.contextstream = server;
9557
9708
  const after = JSON.stringify(root.mcpServers.contextstream ?? null);
9558
- await fs3.writeFile(filePath, JSON.stringify(root, null, 2) + "\n", "utf8");
9709
+ await fs4.writeFile(filePath, JSON.stringify(root, null, 2) + "\n", "utf8");
9559
9710
  if (!exists) return "created";
9560
9711
  return before === after ? "skipped" : "updated";
9561
9712
  }
9562
9713
  async function upsertJsonVsCodeMcpConfig(filePath, server) {
9563
- await fs3.mkdir(path5.dirname(filePath), { recursive: true });
9714
+ await fs4.mkdir(path6.dirname(filePath), { recursive: true });
9564
9715
  const exists = await fileExists(filePath);
9565
9716
  let root = {};
9566
9717
  if (exists) {
9567
- const raw = await fs3.readFile(filePath, "utf8").catch(() => "");
9718
+ const raw = await fs4.readFile(filePath, "utf8").catch(() => "");
9568
9719
  const parsed = tryParseJsonLike(raw);
9569
9720
  if (!parsed.ok) throw new Error(`Invalid JSON in ${filePath}: ${parsed.error}`);
9570
9721
  root = parsed.value;
@@ -9574,25 +9725,25 @@ async function upsertJsonVsCodeMcpConfig(filePath, server) {
9574
9725
  const before = JSON.stringify(root.servers.contextstream ?? null);
9575
9726
  root.servers.contextstream = server;
9576
9727
  const after = JSON.stringify(root.servers.contextstream ?? null);
9577
- await fs3.writeFile(filePath, JSON.stringify(root, null, 2) + "\n", "utf8");
9728
+ await fs4.writeFile(filePath, JSON.stringify(root, null, 2) + "\n", "utf8");
9578
9729
  if (!exists) return "created";
9579
9730
  return before === after ? "skipped" : "updated";
9580
9731
  }
9581
9732
  function claudeDesktopConfigPath() {
9582
- const home = homedir();
9733
+ const home = homedir2();
9583
9734
  if (process.platform === "darwin") {
9584
- return path5.join(home, "Library", "Application Support", "Claude", "claude_desktop_config.json");
9735
+ return path6.join(home, "Library", "Application Support", "Claude", "claude_desktop_config.json");
9585
9736
  }
9586
9737
  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");
9738
+ const appData = process.env.APPDATA || path6.join(home, "AppData", "Roaming");
9739
+ return path6.join(appData, "Claude", "claude_desktop_config.json");
9589
9740
  }
9590
9741
  return null;
9591
9742
  }
9592
9743
  async function upsertCodexTomlConfig(filePath, params) {
9593
- await fs3.mkdir(path5.dirname(filePath), { recursive: true });
9744
+ await fs4.mkdir(path6.dirname(filePath), { recursive: true });
9594
9745
  const exists = await fileExists(filePath);
9595
- const existing = exists ? await fs3.readFile(filePath, "utf8").catch(() => "") : "";
9746
+ const existing = exists ? await fs4.readFile(filePath, "utf8").catch(() => "") : "";
9596
9747
  const marker = "[mcp_servers.contextstream]";
9597
9748
  const envMarker = "[mcp_servers.contextstream.env]";
9598
9749
  const block = `
@@ -9607,15 +9758,15 @@ CONTEXTSTREAM_API_URL = "${params.apiUrl}"
9607
9758
  CONTEXTSTREAM_API_KEY = "${params.apiKey}"
9608
9759
  `;
9609
9760
  if (!exists) {
9610
- await fs3.writeFile(filePath, block.trimStart(), "utf8");
9761
+ await fs4.writeFile(filePath, block.trimStart(), "utf8");
9611
9762
  return "created";
9612
9763
  }
9613
9764
  if (!existing.includes(marker)) {
9614
- await fs3.writeFile(filePath, existing.trimEnd() + block, "utf8");
9765
+ await fs4.writeFile(filePath, existing.trimEnd() + block, "utf8");
9615
9766
  return "updated";
9616
9767
  }
9617
9768
  if (!existing.includes(envMarker)) {
9618
- await fs3.writeFile(filePath, existing.trimEnd() + "\n\n" + envMarker + `
9769
+ await fs4.writeFile(filePath, existing.trimEnd() + "\n\n" + envMarker + `
9619
9770
  CONTEXTSTREAM_API_URL = "${params.apiUrl}"
9620
9771
  CONTEXTSTREAM_API_KEY = "${params.apiKey}"
9621
9772
  `, "utf8");
@@ -9656,18 +9807,18 @@ CONTEXTSTREAM_API_KEY = "${params.apiKey}"
9656
9807
  }
9657
9808
  const updated = out.join("\n");
9658
9809
  if (updated === existing) return "skipped";
9659
- await fs3.writeFile(filePath, updated, "utf8");
9810
+ await fs4.writeFile(filePath, updated, "utf8");
9660
9811
  return "updated";
9661
9812
  }
9662
9813
  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));
9814
+ const entries = await fs4.readdir(parentFolder, { withFileTypes: true });
9815
+ const candidates = entries.filter((e) => e.isDirectory() && !e.name.startsWith(".")).map((e) => path6.join(parentFolder, e.name));
9665
9816
  const projects = [];
9666
9817
  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"));
9818
+ const hasGit = await fileExists(path6.join(dir, ".git"));
9819
+ const hasPkg = await fileExists(path6.join(dir, "package.json"));
9820
+ const hasCargo = await fileExists(path6.join(dir, "Cargo.toml"));
9821
+ const hasPyProject = await fileExists(path6.join(dir, "pyproject.toml"));
9671
9822
  if (hasGit || hasPkg || hasCargo || hasPyProject) projects.push(dir);
9672
9823
  }
9673
9824
  return projects;
@@ -9691,16 +9842,32 @@ async function runSetupWizard(args) {
9691
9842
  console.log("This configures ContextStream MCP + rules for your AI editor(s).");
9692
9843
  if (dryRun) console.log("DRY RUN: no files will be written.\n");
9693
9844
  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;
9845
+ const savedCreds = await readSavedCredentials();
9846
+ const apiUrlDefault = normalizeApiUrl(process.env.CONTEXTSTREAM_API_URL || savedCreds?.api_url || "https://api.contextstream.io");
9847
+ const apiUrl = normalizeApiUrl(
9848
+ normalizeInput(await rl.question(`ContextStream API URL [${apiUrlDefault}]: `)) || apiUrlDefault
9849
+ );
9698
9850
  let apiKey = normalizeInput(process.env.CONTEXTSTREAM_API_KEY || "");
9851
+ let apiKeySource = apiKey ? "env" : "unknown";
9699
9852
  if (apiKey) {
9700
9853
  const confirm = normalizeInput(
9701
9854
  await rl.question(`Use CONTEXTSTREAM_API_KEY from environment (${maskApiKey(apiKey)})? [Y/n]: `)
9702
9855
  );
9703
- if (confirm.toLowerCase() === "n" || confirm.toLowerCase() === "no") apiKey = "";
9856
+ if (confirm.toLowerCase() === "n" || confirm.toLowerCase() === "no") {
9857
+ apiKey = "";
9858
+ apiKeySource = "unknown";
9859
+ }
9860
+ }
9861
+ if (!apiKey && savedCreds?.api_key && normalizeApiUrl(savedCreds.api_url) === apiUrl) {
9862
+ const confirm = normalizeInput(
9863
+ await rl.question(
9864
+ `Use saved API key from ${credentialsFilePath()} (${maskApiKey(savedCreds.api_key)})? [Y/n]: `
9865
+ )
9866
+ );
9867
+ if (!(confirm.toLowerCase() === "n" || confirm.toLowerCase() === "no")) {
9868
+ apiKey = savedCreds.api_key;
9869
+ apiKeySource = "saved";
9870
+ }
9704
9871
  }
9705
9872
  if (!apiKey) {
9706
9873
  console.log("\nAuthentication:");
@@ -9711,6 +9878,7 @@ async function runSetupWizard(args) {
9711
9878
  console.log("\nYou need a ContextStream API key to continue.");
9712
9879
  console.log("Create one here (then paste it): https://app.contextstream.io/settings/api-keys\n");
9713
9880
  apiKey = normalizeInput(await rl.question("CONTEXTSTREAM_API_KEY: "));
9881
+ apiKeySource = "paste";
9714
9882
  } else {
9715
9883
  const anonClient = new ContextStreamClient(buildClientConfig({ apiUrl }));
9716
9884
  let device;
@@ -9773,6 +9941,7 @@ Code: ${device.user_code}`);
9773
9941
  throw new Error("API key creation returned an unexpected response.");
9774
9942
  }
9775
9943
  apiKey = createdKey.secret_key.trim();
9944
+ apiKeySource = "browser";
9776
9945
  console.log(`
9777
9946
  Created API key: ${maskApiKey(apiKey)}
9778
9947
  `);
@@ -9789,6 +9958,17 @@ Created API key: ${maskApiKey(apiKey)}
9789
9958
  const email = typeof me?.data?.email === "string" ? me.data.email : typeof me?.email === "string" ? me.email : void 0;
9790
9959
  console.log(`Authenticated as: ${email || "unknown user"} (${maskApiKey(apiKey)})
9791
9960
  `);
9961
+ if (!dryRun && (apiKeySource === "browser" || apiKeySource === "paste")) {
9962
+ try {
9963
+ const saved = await writeSavedCredentials({ apiUrl, apiKey, email });
9964
+ console.log(`Saved API key for future runs: ${saved.path} (${maskApiKey(apiKey)})
9965
+ `);
9966
+ } catch (err) {
9967
+ const msg = err instanceof Error ? err.message : String(err);
9968
+ console.log(`Warning: failed to save API key for future runs (${credentialsFilePath()}): ${msg}
9969
+ `);
9970
+ }
9971
+ }
9792
9972
  let workspaceId;
9793
9973
  let workspaceName;
9794
9974
  console.log("Workspace setup:");
@@ -9851,6 +10031,8 @@ Created API key: ${maskApiKey(apiKey)}
9851
10031
  const selectedRaw = normalizeInput(await rl.question("Editors [all]: ")) || "all";
9852
10032
  const selectedNums = parseNumberList(selectedRaw, editors.length);
9853
10033
  const selectedEditors = selectedNums.length ? selectedNums.map((n) => editors[n - 1]) : editors;
10034
+ const hasCodex = selectedEditors.includes("codex");
10035
+ const hasProjectMcpEditors = selectedEditors.some((e) => supportsProjectMcpConfig(e));
9854
10036
  console.log("\nInstall rules as:");
9855
10037
  console.log(" 1) Global");
9856
10038
  console.log(" 2) Project");
@@ -9858,20 +10040,31 @@ Created API key: ${maskApiKey(apiKey)}
9858
10040
  const scopeChoice = normalizeInput(await rl.question("Choose [1/2/3] (default 3): ")) || "3";
9859
10041
  const scope = scopeChoice === "1" ? "global" : scopeChoice === "2" ? "project" : "both";
9860
10042
  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";
10043
+ if (hasCodex && !hasProjectMcpEditors) {
10044
+ console.log(" 1) Global (Codex CLI supports global config only)");
10045
+ console.log(" 2) Skip (rules only)");
10046
+ } else {
10047
+ console.log(" 1) Global");
10048
+ console.log(" 2) Project");
10049
+ console.log(" 3) Both");
10050
+ console.log(" 4) Skip (rules only)");
10051
+ if (hasCodex) {
10052
+ console.log(" Note: Codex CLI does not support per-project MCP config; it will be configured globally if selected.");
10053
+ }
10054
+ }
10055
+ const mcpChoiceDefault = hasCodex && !hasProjectMcpEditors ? "1" : "3";
10056
+ const mcpChoice = normalizeInput(await rl.question(`Choose [${hasCodex && !hasProjectMcpEditors ? "1/2" : "1/2/3/4"}] (default ${mcpChoiceDefault}): `)) || mcpChoiceDefault;
10057
+ const mcpScope = mcpChoice === "2" && hasCodex && !hasProjectMcpEditors ? "skip" : mcpChoice === "4" ? "skip" : mcpChoice === "1" ? "global" : mcpChoice === "2" ? "project" : "both";
9867
10058
  const mcpServer = buildContextStreamMcpServer({ apiUrl, apiKey });
9868
10059
  const vsCodeServer = buildContextStreamVsCodeServer({ apiUrl, apiKey });
9869
- if (mcpScope === "global" || mcpScope === "both") {
10060
+ const needsGlobalMcpConfig = mcpScope === "global" || mcpScope === "both" || mcpScope === "project" && hasCodex;
10061
+ if (needsGlobalMcpConfig) {
9870
10062
  console.log("\nInstalling global MCP config...");
9871
10063
  for (const editor of selectedEditors) {
10064
+ if (mcpScope === "project" && editor !== "codex") continue;
9872
10065
  try {
9873
10066
  if (editor === "codex") {
9874
- const filePath = path5.join(homedir(), ".codex", "config.toml");
10067
+ const filePath = path6.join(homedir2(), ".codex", "config.toml");
9875
10068
  if (dryRun) {
9876
10069
  writeActions.push({ kind: "mcp-config", target: filePath, status: "dry-run" });
9877
10070
  console.log(`- ${EDITOR_LABELS[editor]}: would update ${filePath}`);
@@ -9883,7 +10076,7 @@ Created API key: ${maskApiKey(apiKey)}
9883
10076
  continue;
9884
10077
  }
9885
10078
  if (editor === "windsurf") {
9886
- const filePath = path5.join(homedir(), ".codeium", "windsurf", "mcp_config.json");
10079
+ const filePath = path6.join(homedir2(), ".codeium", "windsurf", "mcp_config.json");
9887
10080
  if (dryRun) {
9888
10081
  writeActions.push({ kind: "mcp-config", target: filePath, status: "dry-run" });
9889
10082
  console.log(`- ${EDITOR_LABELS[editor]}: would update ${filePath}`);
@@ -9915,7 +10108,7 @@ Created API key: ${maskApiKey(apiKey)}
9915
10108
  continue;
9916
10109
  }
9917
10110
  if (editor === "cursor") {
9918
- const filePath = path5.join(homedir(), ".cursor", "mcp.json");
10111
+ const filePath = path6.join(homedir2(), ".cursor", "mcp.json");
9919
10112
  if (dryRun) {
9920
10113
  writeActions.push({ kind: "mcp-config", target: filePath, status: "dry-run" });
9921
10114
  console.log(`- ${EDITOR_LABELS[editor]}: would update ${filePath}`);
@@ -9969,12 +10162,12 @@ Created API key: ${maskApiKey(apiKey)}
9969
10162
  }
9970
10163
  }
9971
10164
  const projectPaths = /* @__PURE__ */ new Set();
9972
- const needsProjects = scope === "project" || scope === "both" || mcpScope === "project" || mcpScope === "both";
10165
+ const needsProjects = scope === "project" || scope === "both" || (mcpScope === "project" || mcpScope === "both") && hasProjectMcpEditors;
9973
10166
  if (needsProjects) {
9974
10167
  console.log("\nProject setup...");
9975
10168
  const addCwd = normalizeInput(await rl.question(`Add current folder as a project? [Y/n] (${process.cwd()}): `));
9976
10169
  if (addCwd.toLowerCase() !== "n" && addCwd.toLowerCase() !== "no") {
9977
- projectPaths.add(path5.resolve(process.cwd()));
10170
+ projectPaths.add(path6.resolve(process.cwd()));
9978
10171
  }
9979
10172
  while (true) {
9980
10173
  console.log("\n 1) Add another project path");
@@ -9984,13 +10177,13 @@ Created API key: ${maskApiKey(apiKey)}
9984
10177
  if (choice === "3") break;
9985
10178
  if (choice === "1") {
9986
10179
  const p = normalizeInput(await rl.question("Project folder path: "));
9987
- if (p) projectPaths.add(path5.resolve(p));
10180
+ if (p) projectPaths.add(path6.resolve(p));
9988
10181
  continue;
9989
10182
  }
9990
10183
  if (choice === "2") {
9991
10184
  const parent = normalizeInput(await rl.question("Parent folder path: "));
9992
10185
  if (!parent) continue;
9993
- const parentAbs = path5.resolve(parent);
10186
+ const parentAbs = path6.resolve(parent);
9994
10187
  const projects2 = await discoverProjectsUnderFolder(parentAbs);
9995
10188
  if (projects2.length === 0) {
9996
10189
  console.log(`No projects detected under ${parentAbs} (looked for .git/package.json/Cargo.toml/pyproject.toml).`);
@@ -10020,21 +10213,21 @@ Applying to ${projects.length} project(s)...`);
10020
10213
  workspace_name: workspaceName,
10021
10214
  create_parent_mapping: createParentMapping
10022
10215
  });
10023
- writeActions.push({ kind: "workspace-config", target: path5.join(projectPath, ".contextstream", "config.json"), status: "created" });
10216
+ writeActions.push({ kind: "workspace-config", target: path6.join(projectPath, ".contextstream", "config.json"), status: "created" });
10024
10217
  console.log(`- Linked workspace in ${projectPath}`);
10025
10218
  } catch (err) {
10026
10219
  const message = err instanceof Error ? err.message : String(err);
10027
10220
  console.log(`- Failed to link workspace in ${projectPath}: ${message}`);
10028
10221
  }
10029
10222
  } else if (workspaceId && workspaceId !== "dry-run" && workspaceName && dryRun) {
10030
- writeActions.push({ kind: "workspace-config", target: path5.join(projectPath, ".contextstream", "config.json"), status: "dry-run" });
10223
+ writeActions.push({ kind: "workspace-config", target: path6.join(projectPath, ".contextstream", "config.json"), status: "dry-run" });
10031
10224
  }
10032
10225
  if (mcpScope === "project" || mcpScope === "both") {
10033
10226
  for (const editor of selectedEditors) {
10034
10227
  try {
10035
10228
  if (editor === "cursor") {
10036
- const cursorPath = path5.join(projectPath, ".cursor", "mcp.json");
10037
- const vscodePath = path5.join(projectPath, ".vscode", "mcp.json");
10229
+ const cursorPath = path6.join(projectPath, ".cursor", "mcp.json");
10230
+ const vscodePath = path6.join(projectPath, ".vscode", "mcp.json");
10038
10231
  if (dryRun) {
10039
10232
  writeActions.push({ kind: "mcp-config", target: cursorPath, status: "dry-run" });
10040
10233
  writeActions.push({ kind: "mcp-config", target: vscodePath, status: "dry-run" });
@@ -10047,7 +10240,7 @@ Applying to ${projects.length} project(s)...`);
10047
10240
  continue;
10048
10241
  }
10049
10242
  if (editor === "claude") {
10050
- const mcpPath = path5.join(projectPath, ".mcp.json");
10243
+ const mcpPath = path6.join(projectPath, ".mcp.json");
10051
10244
  if (dryRun) {
10052
10245
  writeActions.push({ kind: "mcp-config", target: mcpPath, status: "dry-run" });
10053
10246
  } else {
@@ -10057,7 +10250,7 @@ Applying to ${projects.length} project(s)...`);
10057
10250
  continue;
10058
10251
  }
10059
10252
  if (editor === "kilo") {
10060
- const kiloPath = path5.join(projectPath, ".kilocode", "mcp.json");
10253
+ const kiloPath = path6.join(projectPath, ".kilocode", "mcp.json");
10061
10254
  if (dryRun) {
10062
10255
  writeActions.push({ kind: "mcp-config", target: kiloPath, status: "dry-run" });
10063
10256
  } else {
@@ -10067,7 +10260,7 @@ Applying to ${projects.length} project(s)...`);
10067
10260
  continue;
10068
10261
  }
10069
10262
  if (editor === "roo") {
10070
- const rooPath = path5.join(projectPath, ".roo", "mcp.json");
10263
+ const rooPath = path6.join(projectPath, ".roo", "mcp.json");
10071
10264
  if (dryRun) {
10072
10265
  writeActions.push({ kind: "mcp-config", target: rooPath, status: "dry-run" });
10073
10266
  } else {
@@ -10087,11 +10280,11 @@ Applying to ${projects.length} project(s)...`);
10087
10280
  const rule = generateRuleContent(editor, {
10088
10281
  workspaceName,
10089
10282
  workspaceId: workspaceId && workspaceId !== "dry-run" ? workspaceId : void 0,
10090
- projectName: path5.basename(projectPath),
10283
+ projectName: path6.basename(projectPath),
10091
10284
  mode
10092
10285
  });
10093
10286
  if (!rule) continue;
10094
- const filePath = path5.join(projectPath, rule.filename);
10287
+ const filePath = path6.join(projectPath, rule.filename);
10095
10288
  if (dryRun) {
10096
10289
  writeActions.push({ kind: "rules", target: filePath, status: "dry-run" });
10097
10290
  continue;
@@ -10124,8 +10317,8 @@ Applying to ${projects.length} project(s)...`);
10124
10317
 
10125
10318
  // src/index.ts
10126
10319
  function showFirstRunMessage() {
10127
- const configDir = join5(homedir2(), ".contextstream");
10128
- const starShownFile = join5(configDir, ".star-shown");
10320
+ const configDir = join6(homedir3(), ".contextstream");
10321
+ const starShownFile = join6(configDir, ".star-shown");
10129
10322
  if (existsSync2(starShownFile)) {
10130
10323
  return;
10131
10324
  }
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.31",
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",