@contextstream/mcp-server 0.4.16 → 0.4.17

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.
package/dist/index.js CHANGED
@@ -4050,6 +4050,131 @@ var coerce = {
4050
4050
  };
4051
4051
  var NEVER = INVALID;
4052
4052
 
4053
+ // src/version.ts
4054
+ import { createRequire } from "module";
4055
+ import { existsSync, readFileSync, writeFileSync, mkdirSync } from "fs";
4056
+ import { homedir } from "os";
4057
+ import { join } from "path";
4058
+ var UPGRADE_COMMAND = "npm update -g @contextstream/mcp-server";
4059
+ var NPM_LATEST_URL = "https://registry.npmjs.org/@contextstream/mcp-server/latest";
4060
+ function getVersion() {
4061
+ try {
4062
+ const require2 = createRequire(import.meta.url);
4063
+ const pkg = require2("../package.json");
4064
+ const version = pkg?.version;
4065
+ if (typeof version === "string" && version.trim()) return version.trim();
4066
+ } catch {
4067
+ }
4068
+ return "unknown";
4069
+ }
4070
+ var VERSION = getVersion();
4071
+ function compareVersions(v1, v2) {
4072
+ const parts1 = v1.split(".").map(Number);
4073
+ const parts2 = v2.split(".").map(Number);
4074
+ for (let i = 0; i < Math.max(parts1.length, parts2.length); i++) {
4075
+ const p1 = parts1[i] ?? 0;
4076
+ const p2 = parts2[i] ?? 0;
4077
+ if (p1 < p2) return -1;
4078
+ if (p1 > p2) return 1;
4079
+ }
4080
+ return 0;
4081
+ }
4082
+ var CACHE_TTL_MS = 24 * 60 * 60 * 1e3;
4083
+ var latestVersionPromise = null;
4084
+ function getCacheFilePath() {
4085
+ return join(homedir(), ".contextstream", "version-cache.json");
4086
+ }
4087
+ function readCache() {
4088
+ try {
4089
+ const cacheFile = getCacheFilePath();
4090
+ if (!existsSync(cacheFile)) return null;
4091
+ const data = JSON.parse(readFileSync(cacheFile, "utf-8"));
4092
+ if (Date.now() - data.checkedAt > CACHE_TTL_MS) return null;
4093
+ return data;
4094
+ } catch {
4095
+ return null;
4096
+ }
4097
+ }
4098
+ function writeCache(latestVersion) {
4099
+ try {
4100
+ const configDir = join(homedir(), ".contextstream");
4101
+ if (!existsSync(configDir)) {
4102
+ mkdirSync(configDir, { recursive: true });
4103
+ }
4104
+ const cacheFile = getCacheFilePath();
4105
+ writeFileSync(cacheFile, JSON.stringify({
4106
+ latestVersion,
4107
+ checkedAt: Date.now()
4108
+ }));
4109
+ } catch {
4110
+ }
4111
+ }
4112
+ async function fetchLatestVersion() {
4113
+ try {
4114
+ const controller = new AbortController();
4115
+ const timeout = setTimeout(() => controller.abort(), 5e3);
4116
+ const response = await fetch(NPM_LATEST_URL, {
4117
+ signal: controller.signal,
4118
+ headers: { "Accept": "application/json" }
4119
+ });
4120
+ clearTimeout(timeout);
4121
+ if (!response.ok) return null;
4122
+ const data = await response.json();
4123
+ return typeof data.version === "string" ? data.version : null;
4124
+ } catch {
4125
+ return null;
4126
+ }
4127
+ }
4128
+ async function resolveLatestVersion() {
4129
+ const cached = readCache();
4130
+ if (cached) return cached.latestVersion;
4131
+ if (!latestVersionPromise) {
4132
+ latestVersionPromise = fetchLatestVersion().finally(() => {
4133
+ latestVersionPromise = null;
4134
+ });
4135
+ }
4136
+ const latestVersion = await latestVersionPromise;
4137
+ if (latestVersion) {
4138
+ writeCache(latestVersion);
4139
+ }
4140
+ return latestVersion;
4141
+ }
4142
+ async function checkForUpdates() {
4143
+ const notice = await getUpdateNotice();
4144
+ if (notice?.behind) {
4145
+ showUpdateWarning(notice.current, notice.latest);
4146
+ }
4147
+ }
4148
+ function showUpdateWarning(currentVersion, latestVersion) {
4149
+ console.error("");
4150
+ console.error("\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501");
4151
+ console.error(`\u26A0\uFE0F Update available: v${currentVersion} \u2192 v${latestVersion}`);
4152
+ console.error("");
4153
+ console.error(` Run: ${UPGRADE_COMMAND}`);
4154
+ console.error("");
4155
+ console.error(" Then restart your AI tool to use the new version.");
4156
+ console.error("\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501");
4157
+ console.error("");
4158
+ }
4159
+ async function getUpdateNotice() {
4160
+ const currentVersion = VERSION;
4161
+ if (currentVersion === "unknown") return null;
4162
+ try {
4163
+ const latestVersion = await resolveLatestVersion();
4164
+ if (!latestVersion) return null;
4165
+ if (compareVersions(currentVersion, latestVersion) < 0) {
4166
+ return {
4167
+ current: currentVersion,
4168
+ latest: latestVersion,
4169
+ behind: true,
4170
+ upgrade_command: UPGRADE_COMMAND
4171
+ };
4172
+ }
4173
+ } catch {
4174
+ }
4175
+ return null;
4176
+ }
4177
+
4053
4178
  // src/config.ts
4054
4179
  var DEFAULT_API_URL = "https://api.contextstream.io";
4055
4180
  function parseBooleanEnv(value) {
@@ -4065,7 +4190,7 @@ var configSchema = external_exports.object({
4065
4190
  jwt: external_exports.string().min(1).optional(),
4066
4191
  defaultWorkspaceId: external_exports.string().uuid().optional(),
4067
4192
  defaultProjectId: external_exports.string().uuid().optional(),
4068
- userAgent: external_exports.string().default("contextstream-mcp/0.1.0"),
4193
+ userAgent: external_exports.string().default(`contextstream-mcp/${VERSION}`),
4069
4194
  allowHeaderAuth: external_exports.boolean().optional(),
4070
4195
  contextPackEnabled: external_exports.boolean().default(true)
4071
4196
  });
@@ -4732,131 +4857,6 @@ var CacheKeys = {
4732
4857
  };
4733
4858
  var globalCache = new MemoryCache();
4734
4859
 
4735
- // src/version.ts
4736
- import { createRequire } from "module";
4737
- import { existsSync as existsSync2, readFileSync as readFileSync2, writeFileSync as writeFileSync2, mkdirSync as mkdirSync2 } from "fs";
4738
- import { homedir } from "os";
4739
- import { join as join3 } from "path";
4740
- var UPGRADE_COMMAND = "npm update -g @contextstream/mcp-server";
4741
- var NPM_LATEST_URL = "https://registry.npmjs.org/@contextstream/mcp-server/latest";
4742
- function getVersion() {
4743
- try {
4744
- const require2 = createRequire(import.meta.url);
4745
- const pkg = require2("../package.json");
4746
- const version = pkg?.version;
4747
- if (typeof version === "string" && version.trim()) return version.trim();
4748
- } catch {
4749
- }
4750
- return "unknown";
4751
- }
4752
- var VERSION = getVersion();
4753
- function compareVersions(v1, v2) {
4754
- const parts1 = v1.split(".").map(Number);
4755
- const parts2 = v2.split(".").map(Number);
4756
- for (let i = 0; i < Math.max(parts1.length, parts2.length); i++) {
4757
- const p1 = parts1[i] ?? 0;
4758
- const p2 = parts2[i] ?? 0;
4759
- if (p1 < p2) return -1;
4760
- if (p1 > p2) return 1;
4761
- }
4762
- return 0;
4763
- }
4764
- var CACHE_TTL_MS = 24 * 60 * 60 * 1e3;
4765
- var latestVersionPromise = null;
4766
- function getCacheFilePath() {
4767
- return join3(homedir(), ".contextstream", "version-cache.json");
4768
- }
4769
- function readCache() {
4770
- try {
4771
- const cacheFile = getCacheFilePath();
4772
- if (!existsSync2(cacheFile)) return null;
4773
- const data = JSON.parse(readFileSync2(cacheFile, "utf-8"));
4774
- if (Date.now() - data.checkedAt > CACHE_TTL_MS) return null;
4775
- return data;
4776
- } catch {
4777
- return null;
4778
- }
4779
- }
4780
- function writeCache(latestVersion) {
4781
- try {
4782
- const configDir = join3(homedir(), ".contextstream");
4783
- if (!existsSync2(configDir)) {
4784
- mkdirSync2(configDir, { recursive: true });
4785
- }
4786
- const cacheFile = getCacheFilePath();
4787
- writeFileSync2(cacheFile, JSON.stringify({
4788
- latestVersion,
4789
- checkedAt: Date.now()
4790
- }));
4791
- } catch {
4792
- }
4793
- }
4794
- async function fetchLatestVersion() {
4795
- try {
4796
- const controller = new AbortController();
4797
- const timeout = setTimeout(() => controller.abort(), 5e3);
4798
- const response = await fetch(NPM_LATEST_URL, {
4799
- signal: controller.signal,
4800
- headers: { "Accept": "application/json" }
4801
- });
4802
- clearTimeout(timeout);
4803
- if (!response.ok) return null;
4804
- const data = await response.json();
4805
- return typeof data.version === "string" ? data.version : null;
4806
- } catch {
4807
- return null;
4808
- }
4809
- }
4810
- async function resolveLatestVersion() {
4811
- const cached = readCache();
4812
- if (cached) return cached.latestVersion;
4813
- if (!latestVersionPromise) {
4814
- latestVersionPromise = fetchLatestVersion().finally(() => {
4815
- latestVersionPromise = null;
4816
- });
4817
- }
4818
- const latestVersion = await latestVersionPromise;
4819
- if (latestVersion) {
4820
- writeCache(latestVersion);
4821
- }
4822
- return latestVersion;
4823
- }
4824
- async function checkForUpdates() {
4825
- const notice = await getUpdateNotice();
4826
- if (notice?.behind) {
4827
- showUpdateWarning(notice.current, notice.latest);
4828
- }
4829
- }
4830
- function showUpdateWarning(currentVersion, latestVersion) {
4831
- console.error("");
4832
- console.error("\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501");
4833
- console.error(`\u26A0\uFE0F Update available: v${currentVersion} \u2192 v${latestVersion}`);
4834
- console.error("");
4835
- console.error(` Run: ${UPGRADE_COMMAND}`);
4836
- console.error("");
4837
- console.error(" Then restart your AI tool to use the new version.");
4838
- console.error("\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501");
4839
- console.error("");
4840
- }
4841
- async function getUpdateNotice() {
4842
- const currentVersion = VERSION;
4843
- if (currentVersion === "unknown") return null;
4844
- try {
4845
- const latestVersion = await resolveLatestVersion();
4846
- if (!latestVersion) return null;
4847
- if (compareVersions(currentVersion, latestVersion) < 0) {
4848
- return {
4849
- current: currentVersion,
4850
- latest: latestVersion,
4851
- behind: true,
4852
- upgrade_command: UPGRADE_COMMAND
4853
- };
4854
- }
4855
- } catch {
4856
- }
4857
- return null;
4858
- }
4859
-
4860
4860
  // src/client.ts
4861
4861
  var uuidSchema = external_exports.string().uuid();
4862
4862
  function unwrapApiResponse(result) {
@@ -6587,7 +6587,10 @@ var ContextStreamClient = class {
6587
6587
  max_tokens: maxTokens,
6588
6588
  format,
6589
6589
  mode,
6590
- distill: params.distill
6590
+ distill: params.distill,
6591
+ client_version: VERSION,
6592
+ rules_version: VERSION,
6593
+ notice_inline: false
6591
6594
  }
6592
6595
  });
6593
6596
  const data = unwrapApiResponse(apiResult);
@@ -7469,9 +7472,11 @@ W:${wsHint}
7469
7472
  // src/tools.ts
7470
7473
  import * as fs3 from "node:fs";
7471
7474
  import * as path4 from "node:path";
7475
+ import { homedir as homedir2 } from "node:os";
7472
7476
 
7473
7477
  // src/rules-templates.ts
7474
7478
  var DEFAULT_CLAUDE_MCP_SERVER_NAME = "contextstream";
7479
+ var RULES_VERSION = VERSION === "unknown" ? "0.0.0" : VERSION;
7475
7480
  var CONTEXTSTREAM_TOOL_NAMES = [
7476
7481
  // Standalone tools (always present)
7477
7482
  "session_init",
@@ -7507,6 +7512,7 @@ var CONTEXTSTREAM_RULES_FULL = `
7507
7512
 
7508
7513
  You have access to ContextStream MCP tools for persistent memory and context.
7509
7514
  v0.4.x uses **~11 consolidated domain tools** for ~75% token reduction vs previous versions.
7515
+ Rules Version: ${RULES_VERSION}
7510
7516
 
7511
7517
  ## TL;DR - REQUIRED EVERY MESSAGE
7512
7518
 
@@ -7578,6 +7584,13 @@ If context still feels missing, use \`session(action="recall", query="...")\` fo
7578
7584
 
7579
7585
  ---
7580
7586
 
7587
+ ### Rules Update Notices
7588
+
7589
+ - If you see **[RULES_NOTICE]**, update rules via \`generate_editor_rules(folder_path="<cwd>")\` (or rerun setup).
7590
+ - If you see **[VERSION_NOTICE]**, tell the user to update MCP using the provided command.
7591
+
7592
+ ---
7593
+
7581
7594
  ### Preferences & Lessons (Use Early)
7582
7595
 
7583
7596
  - If preferences/style matter: \`session(action="user_context")\`
@@ -7595,6 +7608,7 @@ Before searching files or code, confirm the project is indexed and the graph is
7595
7608
  - Local repo: \`project(action="ingest_local", path="<cwd>")\`
7596
7609
  - Otherwise: \`project(action="index")\`
7597
7610
  3. If graph queries are empty/unavailable: \`graph(action="ingest")\`
7611
+ 4. If indexing is in progress, tell the user and wait; do not fall back to local scans.
7598
7612
 
7599
7613
  Only after this preflight, proceed with search/analysis below.
7600
7614
 
@@ -7602,9 +7616,12 @@ Only after this preflight, proceed with search/analysis below.
7602
7616
 
7603
7617
  **Search order:**
7604
7618
  1. \`session(action="smart_search", query="...")\` - context-enriched
7605
- 2. \`search(mode="hybrid", query="...")\` - semantic + keyword
7606
- 3. \`graph(action="dependencies", ...)\` - code structure
7607
- 4. Local repo scans (rg/ls/find) - only if ContextStream returns no results
7619
+ 2. \`search(mode="hybrid", query="...")\` or \`search(mode="keyword", query="<filename>")\`
7620
+ 3. \`project(action="files")\` - file tree/list (only when needed)
7621
+ 4. \`graph(action="dependencies", ...)\` - code structure
7622
+ 5. Local repo scans (rg/ls/find) - only if ContextStream returns no results or is unavailable
7623
+
7624
+ Use ContextStream results directly; only open files if you need exact code.
7608
7625
 
7609
7626
  **Code Analysis:**
7610
7627
  - Dependencies: \`graph(action="dependencies", file_path="...")\`
@@ -7684,6 +7701,7 @@ var CONTEXTSTREAM_RULES_MINIMAL = `
7684
7701
  ## ContextStream v0.4.x (Consolidated Domain Tools)
7685
7702
 
7686
7703
  v0.4.x uses ~11 consolidated domain tools for ~75% token reduction vs previous versions.
7704
+ Rules Version: ${RULES_VERSION}
7687
7705
 
7688
7706
  ### Required Every Message
7689
7707
 
@@ -7705,7 +7723,7 @@ v0.4.x uses ~11 consolidated domain tools for ~75% token reduction vs previous v
7705
7723
  | \`session\` | \`session(action="capture", ...)\` \u2014 actions: capture, capture_lesson, get_lessons, recall, remember, user_context, summary, compress, delta, smart_search |
7706
7724
  | \`memory\` | \`memory(action="list_events", ...)\` \u2014 CRUD for events/nodes, search, decisions, timeline, summary |
7707
7725
  | \`graph\` | \`graph(action="dependencies", ...)\` \u2014 dependencies, impact, call_path, related, ingest |
7708
- | \`project\` | \`project(action="list", ...)\` \u2014 list, get, create, update, index, statistics |
7726
+ | \`project\` | \`project(action="list", ...)\` - list, get, create, update, index, overview, statistics, files, index_status, ingest_local |
7709
7727
  | \`workspace\` | \`workspace(action="list", ...)\` \u2014 list, get, associate, bootstrap |
7710
7728
  | \`integration\` | \`integration(provider="github", action="search", ...)\` \u2014 GitHub/Slack integration |
7711
7729
  | \`help\` | \`help(action="tools")\` \u2014 tools, auth, version, editor_rules |
@@ -7715,8 +7733,10 @@ v0.4.x uses ~11 consolidated domain tools for ~75% token reduction vs previous v
7715
7733
  - **First message**: Always call \`session_init\` with context_hint
7716
7734
  - **Every message after**: Always call \`context_smart\` BEFORE responding (semantic search for relevant context)
7717
7735
  - **Before searching files/code**: Check \`project(action="index_status")\`; if missing/stale run \`project(action="ingest_local", path="<cwd>")\` or \`project(action="index")\`, and use \`graph(action="ingest")\` if needed
7718
- - **For discovery**: Use \`session(action="smart_search")\` or \`search(mode="hybrid")\` before local repo scans
7736
+ - **For discovery**: Use \`session(action="smart_search")\` or \`search(mode="hybrid")\` before any local repo scans
7737
+ - **For file/function/config lookups**: Use \`search\`/\`graph\` first; only fall back to rg/ls/find if ContextStream returns no results
7719
7738
  - **For code analysis**: Use \`graph(action="dependencies")\` or \`graph(action="impact")\` for call/dependency analysis
7739
+ - **On [RULES_NOTICE]**: Use \`generate_editor_rules(folder_path="<cwd>")\` to update rules
7720
7740
  - **After completing work**: Always capture decisions/insights with \`session(action="capture")\`
7721
7741
  - **On mistakes/corrections**: Immediately capture lessons with \`session(action="capture_lesson")\`
7722
7742
 
@@ -8042,6 +8062,235 @@ function normalizeUuid(value) {
8042
8062
  if (!value) return void 0;
8043
8063
  return uuidSchema2.safeParse(value).success ? value : void 0;
8044
8064
  }
8065
+ var RULES_NOTICE_CACHE_TTL_MS = 10 * 60 * 1e3;
8066
+ var RULES_VERSION_REGEX = /Rules Version:\s*([0-9][0-9A-Za-z.\-]*)/i;
8067
+ var RULES_PROJECT_FILES = {
8068
+ codex: "AGENTS.md",
8069
+ claude: "CLAUDE.md",
8070
+ cursor: ".cursorrules",
8071
+ windsurf: ".windsurfrules",
8072
+ cline: ".clinerules",
8073
+ kilo: path4.join(".kilocode", "rules", "contextstream.md"),
8074
+ roo: path4.join(".roo", "rules", "contextstream.md"),
8075
+ aider: ".aider.conf.yml"
8076
+ };
8077
+ var RULES_GLOBAL_FILES = {
8078
+ codex: [path4.join(homedir2(), ".codex", "AGENTS.md")],
8079
+ windsurf: [path4.join(homedir2(), ".codeium", "windsurf", "memories", "global_rules.md")],
8080
+ kilo: [path4.join(homedir2(), ".kilocode", "rules", "contextstream.md")],
8081
+ roo: [path4.join(homedir2(), ".roo", "rules", "contextstream.md")]
8082
+ };
8083
+ var rulesNoticeCache = /* @__PURE__ */ new Map();
8084
+ function compareVersions2(v1, v2) {
8085
+ const parts1 = v1.split(".").map(Number);
8086
+ const parts2 = v2.split(".").map(Number);
8087
+ for (let i = 0; i < Math.max(parts1.length, parts2.length); i++) {
8088
+ const p1 = parts1[i] ?? 0;
8089
+ const p2 = parts2[i] ?? 0;
8090
+ if (p1 < p2) return -1;
8091
+ if (p1 > p2) return 1;
8092
+ }
8093
+ return 0;
8094
+ }
8095
+ function extractRulesVersion(content) {
8096
+ const match = content.match(RULES_VERSION_REGEX);
8097
+ return match?.[1]?.trim() ?? null;
8098
+ }
8099
+ function detectEditorFromClientName(clientName) {
8100
+ if (!clientName) return null;
8101
+ const normalized = clientName.toLowerCase().trim();
8102
+ if (normalized.includes("cursor")) return "cursor";
8103
+ if (normalized.includes("windsurf") || normalized.includes("codeium")) return "windsurf";
8104
+ if (normalized.includes("claude")) return "claude";
8105
+ if (normalized.includes("cline")) return "cline";
8106
+ if (normalized.includes("kilo")) return "kilo";
8107
+ if (normalized.includes("roo")) return "roo";
8108
+ if (normalized.includes("codex")) return "codex";
8109
+ if (normalized.includes("aider")) return "aider";
8110
+ return null;
8111
+ }
8112
+ function resolveRulesCandidatePaths(folderPath, editorKey) {
8113
+ const candidates = /* @__PURE__ */ new Set();
8114
+ const addProject = (key) => {
8115
+ if (!folderPath) return;
8116
+ const rel = RULES_PROJECT_FILES[key];
8117
+ if (rel) {
8118
+ candidates.add(path4.join(folderPath, rel));
8119
+ }
8120
+ };
8121
+ const addGlobal = (key) => {
8122
+ const paths = RULES_GLOBAL_FILES[key];
8123
+ if (!paths) return;
8124
+ for (const p of paths) {
8125
+ candidates.add(p);
8126
+ }
8127
+ };
8128
+ if (editorKey) {
8129
+ addProject(editorKey);
8130
+ addGlobal(editorKey);
8131
+ } else {
8132
+ for (const key of Object.keys(RULES_PROJECT_FILES)) {
8133
+ addProject(key);
8134
+ addGlobal(key);
8135
+ }
8136
+ }
8137
+ return Array.from(candidates);
8138
+ }
8139
+ function resolveFolderPath(inputPath, sessionManager) {
8140
+ if (inputPath) return inputPath;
8141
+ const fromSession = sessionManager?.getFolderPath();
8142
+ if (fromSession) return fromSession;
8143
+ const ctxPath = sessionManager?.getContext();
8144
+ const contextFolder = ctxPath && typeof ctxPath.folder_path === "string" ? ctxPath.folder_path : null;
8145
+ if (contextFolder) return contextFolder;
8146
+ const cwd = process.cwd();
8147
+ const indicators = [".git", "package.json", "Cargo.toml", "pyproject.toml", ".contextstream"];
8148
+ const hasIndicator = indicators.some((entry) => {
8149
+ try {
8150
+ return fs3.existsSync(path4.join(cwd, entry));
8151
+ } catch {
8152
+ return false;
8153
+ }
8154
+ });
8155
+ return hasIndicator ? cwd : null;
8156
+ }
8157
+ function getRulesNotice(folderPath, clientName) {
8158
+ if (!RULES_VERSION || RULES_VERSION === "0.0.0") return null;
8159
+ const editorKey = detectEditorFromClientName(clientName);
8160
+ if (!folderPath && !editorKey) {
8161
+ return null;
8162
+ }
8163
+ const cacheKey = `${folderPath ?? "none"}|${editorKey ?? "all"}`;
8164
+ const cached = rulesNoticeCache.get(cacheKey);
8165
+ if (cached && Date.now() - cached.checkedAt < RULES_NOTICE_CACHE_TTL_MS) {
8166
+ return cached.notice;
8167
+ }
8168
+ const candidates = resolveRulesCandidatePaths(folderPath, editorKey);
8169
+ const existing = candidates.filter((filePath) => fs3.existsSync(filePath));
8170
+ if (existing.length === 0) {
8171
+ const updateCommand2 = folderPath ? `generate_editor_rules(folder_path="${folderPath}")` : 'generate_editor_rules(folder_path="<cwd>")';
8172
+ const notice2 = {
8173
+ status: "missing",
8174
+ latest: RULES_VERSION,
8175
+ files_checked: candidates,
8176
+ update_tool: "generate_editor_rules",
8177
+ update_args: {
8178
+ ...folderPath ? { folder_path: folderPath } : {},
8179
+ editors: editorKey ? [editorKey] : ["all"]
8180
+ },
8181
+ update_command: updateCommand2
8182
+ };
8183
+ rulesNoticeCache.set(cacheKey, { checkedAt: Date.now(), notice: notice2 });
8184
+ return notice2;
8185
+ }
8186
+ const filesMissingVersion = [];
8187
+ const filesOutdated = [];
8188
+ const versions = [];
8189
+ for (const filePath of existing) {
8190
+ try {
8191
+ const content = fs3.readFileSync(filePath, "utf-8");
8192
+ const version = extractRulesVersion(content);
8193
+ if (!version) {
8194
+ filesMissingVersion.push(filePath);
8195
+ continue;
8196
+ }
8197
+ versions.push(version);
8198
+ if (compareVersions2(version, RULES_VERSION) < 0) {
8199
+ filesOutdated.push(filePath);
8200
+ }
8201
+ } catch {
8202
+ filesMissingVersion.push(filePath);
8203
+ }
8204
+ }
8205
+ if (filesOutdated.length === 0 && filesMissingVersion.length === 0) {
8206
+ rulesNoticeCache.set(cacheKey, { checkedAt: Date.now(), notice: null });
8207
+ return null;
8208
+ }
8209
+ const current = versions.sort(compareVersions2).at(-1);
8210
+ const updateCommand = folderPath ? `generate_editor_rules(folder_path="${folderPath}")` : 'generate_editor_rules(folder_path="<cwd>")';
8211
+ const notice = {
8212
+ status: filesOutdated.length > 0 ? "behind" : "unknown",
8213
+ current,
8214
+ latest: RULES_VERSION,
8215
+ files_checked: existing,
8216
+ ...filesOutdated.length > 0 ? { files_outdated: filesOutdated } : {},
8217
+ ...filesMissingVersion.length > 0 ? { files_missing_version: filesMissingVersion } : {},
8218
+ update_tool: "generate_editor_rules",
8219
+ update_args: {
8220
+ ...folderPath ? { folder_path: folderPath } : {},
8221
+ editors: editorKey ? [editorKey] : ["all"]
8222
+ },
8223
+ update_command: updateCommand
8224
+ };
8225
+ rulesNoticeCache.set(cacheKey, { checkedAt: Date.now(), notice });
8226
+ return notice;
8227
+ }
8228
+ var CONTEXTSTREAM_START_MARKER = "<!-- BEGIN ContextStream -->";
8229
+ var CONTEXTSTREAM_END_MARKER = "<!-- END ContextStream -->";
8230
+ function wrapWithMarkers(content) {
8231
+ return `${CONTEXTSTREAM_START_MARKER}
8232
+ ${content.trim()}
8233
+ ${CONTEXTSTREAM_END_MARKER}`;
8234
+ }
8235
+ async function upsertRuleFile(filePath, content) {
8236
+ await fs3.promises.mkdir(path4.dirname(filePath), { recursive: true });
8237
+ const wrappedContent = wrapWithMarkers(content);
8238
+ let existing = "";
8239
+ try {
8240
+ existing = await fs3.promises.readFile(filePath, "utf8");
8241
+ } catch {
8242
+ }
8243
+ if (!existing) {
8244
+ await fs3.promises.writeFile(filePath, wrappedContent + "\n", "utf8");
8245
+ return "created";
8246
+ }
8247
+ const startIdx = existing.indexOf(CONTEXTSTREAM_START_MARKER);
8248
+ const endIdx = existing.indexOf(CONTEXTSTREAM_END_MARKER);
8249
+ if (startIdx !== -1 && endIdx !== -1 && endIdx > startIdx) {
8250
+ const before = existing.substring(0, startIdx);
8251
+ const after = existing.substring(endIdx + CONTEXTSTREAM_END_MARKER.length);
8252
+ const updated = before.trimEnd() + "\n\n" + wrappedContent + "\n" + after.trimStart();
8253
+ await fs3.promises.writeFile(filePath, updated.trim() + "\n", "utf8");
8254
+ return "updated";
8255
+ }
8256
+ const joined = existing.trimEnd() + "\n\n" + wrappedContent + "\n";
8257
+ await fs3.promises.writeFile(filePath, joined, "utf8");
8258
+ return "appended";
8259
+ }
8260
+ async function writeEditorRules(options) {
8261
+ const editors = options.editors && options.editors.length > 0 ? options.editors : getAvailableEditors();
8262
+ const results = [];
8263
+ for (const editor of editors) {
8264
+ const rule = generateRuleContent(editor, {
8265
+ workspaceName: options.workspaceName,
8266
+ workspaceId: options.workspaceId,
8267
+ projectName: options.projectName,
8268
+ additionalRules: options.additionalRules,
8269
+ mode: options.mode
8270
+ });
8271
+ if (!rule) {
8272
+ results.push({ editor, filename: "", status: "unknown editor" });
8273
+ continue;
8274
+ }
8275
+ const filePath = path4.join(options.folderPath, rule.filename);
8276
+ try {
8277
+ const status = await upsertRuleFile(filePath, rule.content);
8278
+ results.push({ editor, filename: rule.filename, status });
8279
+ } catch (err) {
8280
+ results.push({
8281
+ editor,
8282
+ filename: rule.filename,
8283
+ status: `error: ${err.message}`
8284
+ });
8285
+ }
8286
+ }
8287
+ for (const key of rulesNoticeCache.keys()) {
8288
+ if (key.startsWith(`${options.folderPath}|`)) {
8289
+ rulesNoticeCache.delete(key);
8290
+ }
8291
+ }
8292
+ return results;
8293
+ }
8045
8294
  var WRITE_VERBS = /* @__PURE__ */ new Set([
8046
8295
  "create",
8047
8296
  "update",
@@ -9766,30 +10015,13 @@ Access: Free`,
9766
10015
  };
9767
10016
  fs3.writeFileSync(configPath, JSON.stringify(config, null, 2));
9768
10017
  if (input.generate_editor_rules) {
9769
- for (const editor of getAvailableEditors()) {
9770
- const rule = generateRuleContent(editor, {
9771
- workspaceId,
9772
- projectName: input.name
9773
- });
9774
- if (rule) {
9775
- const filePath = path4.join(input.folder_path, rule.filename);
9776
- try {
9777
- let existingContent = "";
9778
- try {
9779
- existingContent = fs3.readFileSync(filePath, "utf-8");
9780
- } catch {
9781
- }
9782
- if (!existingContent) {
9783
- fs3.writeFileSync(filePath, rule.content);
9784
- rulesGenerated.push(rule.filename);
9785
- } else if (!existingContent.includes("ContextStream")) {
9786
- fs3.writeFileSync(filePath, existingContent + "\n\n" + rule.content);
9787
- rulesGenerated.push(rule.filename + " (appended)");
9788
- }
9789
- } catch {
9790
- }
9791
- }
9792
- }
10018
+ const ruleResults = await writeEditorRules({
10019
+ folderPath: input.folder_path,
10020
+ editors: getAvailableEditors(),
10021
+ workspaceId,
10022
+ projectName: input.name
10023
+ });
10024
+ rulesGenerated = ruleResults.filter((r) => r.status === "created" || r.status === "updated" || r.status === "appended").map((r) => r.status === "created" ? r.filename : `${r.filename} (${r.status})`);
9793
10025
  }
9794
10026
  } catch (err) {
9795
10027
  console.error("[ContextStream] Failed to write project config:", err);
@@ -10738,6 +10970,25 @@ This does semantic search on the first message. You only need context_smart on s
10738
10970
  if (sessionManager) {
10739
10971
  sessionManager.markInitialized(result);
10740
10972
  }
10973
+ const folderPathForRules = input.folder_path || ideRoots[0] || resolveFolderPath(void 0, sessionManager);
10974
+ if (sessionManager && folderPathForRules) {
10975
+ sessionManager.setFolderPath(folderPathForRules);
10976
+ }
10977
+ let rulesNotice = null;
10978
+ if (folderPathForRules || detectedClientInfo?.name) {
10979
+ rulesNotice = getRulesNotice(folderPathForRules, detectedClientInfo?.name);
10980
+ if (rulesNotice) {
10981
+ result.rules_notice = rulesNotice;
10982
+ }
10983
+ }
10984
+ let versionNotice = null;
10985
+ try {
10986
+ versionNotice = await getUpdateNotice();
10987
+ } catch {
10988
+ }
10989
+ if (versionNotice) {
10990
+ result.version_notice = versionNotice;
10991
+ }
10741
10992
  const workspaceId = typeof result.workspace_id === "string" ? result.workspace_id : void 0;
10742
10993
  if (workspaceId && AUTO_HIDE_INTEGRATIONS) {
10743
10994
  try {
@@ -10809,6 +11060,19 @@ This does semantic search on the first message. You only need context_smart on s
10809
11060
  } else if (workspaceWarning) {
10810
11061
  text = [`Warning: ${workspaceWarning}`, "", formatContent(result)].join("\n");
10811
11062
  }
11063
+ const noticeLines = [];
11064
+ if (rulesNotice) {
11065
+ const current = rulesNotice.current ?? "unknown";
11066
+ noticeLines.push(`[RULES_NOTICE] status=${rulesNotice.status} current=${current} latest=${rulesNotice.latest} update="${rulesNotice.update_command}"`);
11067
+ }
11068
+ if (versionNotice?.behind) {
11069
+ noticeLines.push(`[VERSION_NOTICE] current=${versionNotice.current} latest=${versionNotice.latest} upgrade="${versionNotice.upgrade_command}"`);
11070
+ }
11071
+ if (noticeLines.length > 0) {
11072
+ text = `${text}
11073
+
11074
+ ${noticeLines.join("\n")}`;
11075
+ }
10812
11076
  return { content: [{ type: "text", text }], structuredContent: toStructured(result) };
10813
11077
  }
10814
11078
  );
@@ -10898,32 +11162,13 @@ Optionally generates AI editor rules for automatic ContextStream usage.`,
10898
11162
  const result = await client.associateWorkspace(input);
10899
11163
  let rulesGenerated = [];
10900
11164
  if (input.generate_editor_rules) {
10901
- const fs6 = await import("fs");
10902
- const path7 = await import("path");
10903
- for (const editor of getAvailableEditors()) {
10904
- const rule = generateRuleContent(editor, {
10905
- workspaceName: input.workspace_name,
10906
- workspaceId: input.workspace_id
10907
- });
10908
- if (rule) {
10909
- const filePath = path7.join(input.folder_path, rule.filename);
10910
- try {
10911
- let existingContent = "";
10912
- try {
10913
- existingContent = fs6.readFileSync(filePath, "utf-8");
10914
- } catch {
10915
- }
10916
- if (!existingContent) {
10917
- fs6.writeFileSync(filePath, rule.content);
10918
- rulesGenerated.push(rule.filename);
10919
- } else if (!existingContent.includes("ContextStream Integration")) {
10920
- fs6.writeFileSync(filePath, existingContent + "\n\n" + rule.content);
10921
- rulesGenerated.push(rule.filename + " (appended)");
10922
- }
10923
- } catch {
10924
- }
10925
- }
10926
- }
11165
+ const ruleResults = await writeEditorRules({
11166
+ folderPath: input.folder_path,
11167
+ editors: getAvailableEditors(),
11168
+ workspaceName: input.workspace_name,
11169
+ workspaceId: input.workspace_id
11170
+ });
11171
+ rulesGenerated = ruleResults.filter((r) => r.status === "created" || r.status === "updated" || r.status === "appended").map((r) => r.status === "created" ? r.filename : `${r.filename} (${r.status})`);
10927
11172
  }
10928
11173
  const response = {
10929
11174
  ...result,
@@ -11003,31 +11248,13 @@ Behavior:
11003
11248
  });
11004
11249
  let rulesGenerated = [];
11005
11250
  if (input.generate_editor_rules) {
11006
- const fs6 = await import("fs");
11007
- const path7 = await import("path");
11008
- for (const editor of getAvailableEditors()) {
11009
- const rule = generateRuleContent(editor, {
11010
- workspaceName: newWorkspace.name || input.workspace_name,
11011
- workspaceId: newWorkspace.id
11012
- });
11013
- if (!rule) continue;
11014
- const filePath = path7.join(folderPath, rule.filename);
11015
- try {
11016
- let existingContent = "";
11017
- try {
11018
- existingContent = fs6.readFileSync(filePath, "utf-8");
11019
- } catch {
11020
- }
11021
- if (!existingContent) {
11022
- fs6.writeFileSync(filePath, rule.content);
11023
- rulesGenerated.push(rule.filename);
11024
- } else if (!existingContent.includes("ContextStream Integration")) {
11025
- fs6.writeFileSync(filePath, existingContent + "\n\n" + rule.content);
11026
- rulesGenerated.push(rule.filename + " (appended)");
11027
- }
11028
- } catch {
11029
- }
11030
- }
11251
+ const ruleResults = await writeEditorRules({
11252
+ folderPath,
11253
+ editors: getAvailableEditors(),
11254
+ workspaceName: newWorkspace.name || input.workspace_name,
11255
+ workspaceId: newWorkspace.id
11256
+ });
11257
+ rulesGenerated = ruleResults.filter((r) => r.status === "created" || r.status === "updated" || r.status === "appended").map((r) => r.status === "created" ? r.filename : `${r.filename} (${r.status})`);
11031
11258
  }
11032
11259
  const session = await client.initSession(
11033
11260
  {
@@ -11432,7 +11659,7 @@ Example: "What were the auth decisions?" or "What are my TypeScript preferences?
11432
11659
  These rules instruct the AI to automatically use ContextStream for memory and context.
11433
11660
  Supported editors: ${getAvailableEditors().join(", ")}`,
11434
11661
  inputSchema: external_exports.object({
11435
- folder_path: external_exports.string().describe("Absolute path to the project folder"),
11662
+ folder_path: external_exports.string().optional().describe("Absolute path to the project folder (defaults to IDE root/cwd)"),
11436
11663
  editors: external_exports.array(external_exports.enum(["codex", "windsurf", "cursor", "cline", "kilo", "roo", "claude", "aider", "all"])).optional().describe("Which editors to generate rules for. Defaults to all."),
11437
11664
  workspace_name: external_exports.string().optional().describe("Workspace name to include in rules"),
11438
11665
  workspace_id: external_exports.string().uuid().optional().describe("Workspace ID to include in rules"),
@@ -11443,58 +11670,48 @@ Supported editors: ${getAvailableEditors().join(", ")}`,
11443
11670
  })
11444
11671
  },
11445
11672
  async (input) => {
11446
- const fs6 = await import("fs");
11447
- const path7 = await import("path");
11673
+ const folderPath = resolveFolderPath(input.folder_path, sessionManager);
11674
+ if (!folderPath) {
11675
+ return errorResult("Error: folder_path is required. Provide folder_path or run from a project directory.");
11676
+ }
11448
11677
  const editors = input.editors?.includes("all") || !input.editors ? getAvailableEditors() : input.editors.filter((e) => e !== "all");
11449
11678
  const results = [];
11450
- for (const editor of editors) {
11451
- const rule = generateRuleContent(editor, {
11452
- workspaceName: input.workspace_name,
11453
- workspaceId: input.workspace_id,
11454
- projectName: input.project_name,
11455
- additionalRules: input.additional_rules,
11456
- mode: input.mode
11457
- });
11458
- if (!rule) {
11459
- results.push({ editor, filename: "", status: "unknown editor" });
11460
- continue;
11461
- }
11462
- const filePath = path7.join(input.folder_path, rule.filename);
11463
- if (input.dry_run) {
11679
+ if (input.dry_run) {
11680
+ for (const editor of editors) {
11681
+ const rule = generateRuleContent(editor, {
11682
+ workspaceName: input.workspace_name,
11683
+ workspaceId: input.workspace_id,
11684
+ projectName: input.project_name,
11685
+ additionalRules: input.additional_rules,
11686
+ mode: input.mode
11687
+ });
11688
+ if (!rule) {
11689
+ results.push({ editor, filename: "", status: "unknown editor" });
11690
+ continue;
11691
+ }
11464
11692
  results.push({
11465
11693
  editor,
11466
11694
  filename: rule.filename,
11467
- status: "dry run - would create",
11695
+ status: "dry run - would update",
11468
11696
  content: rule.content
11469
11697
  });
11470
- } else {
11471
- try {
11472
- let existingContent = "";
11473
- try {
11474
- existingContent = fs6.readFileSync(filePath, "utf-8");
11475
- } catch {
11476
- }
11477
- if (existingContent && !existingContent.includes("ContextStream Integration")) {
11478
- const updatedContent = existingContent + "\n\n" + rule.content;
11479
- fs6.writeFileSync(filePath, updatedContent);
11480
- results.push({ editor, filename: rule.filename, status: "appended to existing" });
11481
- } else {
11482
- fs6.writeFileSync(filePath, rule.content);
11483
- results.push({ editor, filename: rule.filename, status: "created" });
11484
- }
11485
- } catch (err) {
11486
- results.push({
11487
- editor,
11488
- filename: rule.filename,
11489
- status: `error: ${err.message}`
11490
- });
11491
- }
11492
11698
  }
11699
+ } else {
11700
+ const writeResults = await writeEditorRules({
11701
+ folderPath,
11702
+ editors,
11703
+ workspaceName: input.workspace_name,
11704
+ workspaceId: input.workspace_id,
11705
+ projectName: input.project_name,
11706
+ additionalRules: input.additional_rules,
11707
+ mode: input.mode
11708
+ });
11709
+ results.push(...writeResults);
11493
11710
  }
11494
11711
  const summary = {
11495
- folder: input.folder_path,
11712
+ folder: folderPath,
11496
11713
  results,
11497
- message: input.dry_run ? "Dry run complete. Use dry_run: false to write files." : `Generated ${results.filter((r) => r.status === "created" || r.status.includes("appended")).length} rule files.`
11714
+ message: input.dry_run ? "Dry run complete. Use dry_run: false to write files." : `Generated ${results.filter((r) => r.status === "created" || r.status === "updated" || r.status === "appended").length} rule files.`
11498
11715
  };
11499
11716
  return { content: [{ type: "text", text: formatContent(summary) }], structuredContent: toStructured(summary) };
11500
11717
  }
@@ -11768,11 +11985,27 @@ This saves ~80% tokens compared to including full chat history.`,
11768
11985
  const footer = `
11769
11986
  ---
11770
11987
  \u{1F3AF} ${result.sources_used} sources | ~${result.token_estimate} tokens | format: ${result.format}`;
11771
- const versionNoticeLine = result.version_notice?.behind ? `
11772
- [VERSION_NOTICE] current=${result.version_notice.current} latest=${result.version_notice.latest} upgrade="${result.version_notice.upgrade_command}"` : "";
11988
+ const folderPathForRules = resolveFolderPath(void 0, sessionManager);
11989
+ const rulesNotice = getRulesNotice(folderPathForRules, detectedClientInfo?.name);
11990
+ let versionNotice = result.version_notice;
11991
+ if (!versionNotice) {
11992
+ try {
11993
+ versionNotice = await getUpdateNotice();
11994
+ } catch {
11995
+ }
11996
+ }
11997
+ const rulesNoticeLine = rulesNotice ? `
11998
+ [RULES_NOTICE] status=${rulesNotice.status} current=${rulesNotice.current ?? "unknown"} latest=${rulesNotice.latest} update="${rulesNotice.update_command}"` : "";
11999
+ const versionNoticeLine = versionNotice?.behind ? `
12000
+ [VERSION_NOTICE] current=${versionNotice.current} latest=${versionNotice.latest} upgrade="${versionNotice.upgrade_command}"` : "";
12001
+ const enrichedResult = {
12002
+ ...result,
12003
+ ...rulesNotice ? { rules_notice: rulesNotice } : {},
12004
+ ...versionNotice ? { version_notice: versionNotice } : {}
12005
+ };
11773
12006
  return {
11774
- content: [{ type: "text", text: result.context + footer + versionNoticeLine }],
11775
- structuredContent: toStructured(result)
12007
+ content: [{ type: "text", text: result.context + footer + rulesNoticeLine + versionNoticeLine }],
12008
+ structuredContent: toStructured(enrichedResult)
11776
12009
  };
11777
12010
  }
11778
12011
  );
@@ -14827,6 +15060,12 @@ var SessionManager = class {
14827
15060
  getContext() {
14828
15061
  return this.context;
14829
15062
  }
15063
+ /**
15064
+ * Get the current folder path (if known)
15065
+ */
15066
+ getFolderPath() {
15067
+ return this.folderPath;
15068
+ }
14830
15069
  /**
14831
15070
  * Mark session as manually initialized (e.g., when session_init is called explicitly)
14832
15071
  */
@@ -14838,6 +15077,10 @@ var SessionManager = class {
14838
15077
  if (workspaceId || projectId) {
14839
15078
  this.client.setDefaults({ workspace_id: workspaceId, project_id: projectId });
14840
15079
  }
15080
+ const contextFolderPath = typeof context.folder_path === "string" ? context.folder_path : void 0;
15081
+ if (contextFolderPath) {
15082
+ this.folderPath = contextFolderPath;
15083
+ }
14841
15084
  }
14842
15085
  /**
14843
15086
  * Set the folder path hint (can be passed from tools that know the workspace path)
@@ -14929,6 +15172,9 @@ var SessionManager = class {
14929
15172
  if (this.ideRoots.length === 0 && this.folderPath) {
14930
15173
  this.ideRoots = [this.folderPath];
14931
15174
  }
15175
+ if (this.ideRoots.length > 0) {
15176
+ this.folderPath = this.ideRoots[0];
15177
+ }
14932
15178
  this.initializationPromise = this._doInitialize();
14933
15179
  try {
14934
15180
  const result = await this.initializationPromise;
@@ -15374,25 +15620,25 @@ async function runHttpGateway() {
15374
15620
 
15375
15621
  // src/index.ts
15376
15622
  import { existsSync as existsSync4, mkdirSync as mkdirSync4, writeFileSync as writeFileSync4 } from "fs";
15377
- import { homedir as homedir4 } from "os";
15623
+ import { homedir as homedir5 } from "os";
15378
15624
  import { join as join8 } from "path";
15379
15625
 
15380
15626
  // src/setup.ts
15381
15627
  import * as fs5 from "node:fs/promises";
15382
15628
  import * as path6 from "node:path";
15383
- import { homedir as homedir3 } from "node:os";
15629
+ import { homedir as homedir4 } from "node:os";
15384
15630
  import { stdin, stdout } from "node:process";
15385
15631
  import { createInterface } from "node:readline/promises";
15386
15632
 
15387
15633
  // src/credentials.ts
15388
15634
  import * as fs4 from "node:fs/promises";
15389
15635
  import * as path5 from "node:path";
15390
- import { homedir as homedir2 } from "node:os";
15636
+ import { homedir as homedir3 } from "node:os";
15391
15637
  function normalizeApiUrl(input) {
15392
15638
  return String(input ?? "").trim().replace(/\/+$/, "");
15393
15639
  }
15394
15640
  function credentialsFilePath() {
15395
- return path5.join(homedir2(), ".contextstream", "credentials.json");
15641
+ return path5.join(homedir3(), ".contextstream", "credentials.json");
15396
15642
  }
15397
15643
  function isRecord(value) {
15398
15644
  return typeof value === "object" && value !== null && !Array.isArray(value);
@@ -15490,27 +15736,27 @@ async function fileExists(filePath) {
15490
15736
  return false;
15491
15737
  }
15492
15738
  }
15493
- var CONTEXTSTREAM_START_MARKER = "<!-- BEGIN ContextStream -->";
15494
- var CONTEXTSTREAM_END_MARKER = "<!-- END ContextStream -->";
15495
- function wrapWithMarkers(content) {
15496
- return `${CONTEXTSTREAM_START_MARKER}
15739
+ var CONTEXTSTREAM_START_MARKER2 = "<!-- BEGIN ContextStream -->";
15740
+ var CONTEXTSTREAM_END_MARKER2 = "<!-- END ContextStream -->";
15741
+ function wrapWithMarkers2(content) {
15742
+ return `${CONTEXTSTREAM_START_MARKER2}
15497
15743
  ${content.trim()}
15498
- ${CONTEXTSTREAM_END_MARKER}`;
15744
+ ${CONTEXTSTREAM_END_MARKER2}`;
15499
15745
  }
15500
15746
  async function upsertTextFile(filePath, content, _marker) {
15501
15747
  await fs5.mkdir(path6.dirname(filePath), { recursive: true });
15502
15748
  const exists = await fileExists(filePath);
15503
- const wrappedContent = wrapWithMarkers(content);
15749
+ const wrappedContent = wrapWithMarkers2(content);
15504
15750
  if (!exists) {
15505
15751
  await fs5.writeFile(filePath, wrappedContent + "\n", "utf8");
15506
15752
  return "created";
15507
15753
  }
15508
15754
  const existing = await fs5.readFile(filePath, "utf8").catch(() => "");
15509
- const startIdx = existing.indexOf(CONTEXTSTREAM_START_MARKER);
15510
- const endIdx = existing.indexOf(CONTEXTSTREAM_END_MARKER);
15755
+ const startIdx = existing.indexOf(CONTEXTSTREAM_START_MARKER2);
15756
+ const endIdx = existing.indexOf(CONTEXTSTREAM_END_MARKER2);
15511
15757
  if (startIdx !== -1 && endIdx !== -1 && endIdx > startIdx) {
15512
15758
  const before = existing.substring(0, startIdx);
15513
- const after = existing.substring(endIdx + CONTEXTSTREAM_END_MARKER.length);
15759
+ const after = existing.substring(endIdx + CONTEXTSTREAM_END_MARKER2.length);
15514
15760
  const updated = before.trimEnd() + "\n\n" + wrappedContent + "\n" + after.trimStart();
15515
15761
  await fs5.writeFile(filePath, updated.trim() + "\n", "utf8");
15516
15762
  return "updated";
@@ -15525,7 +15771,7 @@ async function upsertTextFile(filePath, content, _marker) {
15525
15771
  return "appended";
15526
15772
  }
15527
15773
  function globalRulesPathForEditor(editor) {
15528
- const home = homedir3();
15774
+ const home = homedir4();
15529
15775
  switch (editor) {
15530
15776
  case "codex":
15531
15777
  return path6.join(home, ".codex", "AGENTS.md");
@@ -15554,7 +15800,7 @@ async function anyPathExists(paths) {
15554
15800
  return false;
15555
15801
  }
15556
15802
  async function isCodexInstalled() {
15557
- const home = homedir3();
15803
+ const home = homedir4();
15558
15804
  const envHome = process.env.CODEX_HOME;
15559
15805
  const candidates = [
15560
15806
  envHome,
@@ -15565,7 +15811,7 @@ async function isCodexInstalled() {
15565
15811
  return anyPathExists(candidates);
15566
15812
  }
15567
15813
  async function isClaudeInstalled() {
15568
- const home = homedir3();
15814
+ const home = homedir4();
15569
15815
  const candidates = [
15570
15816
  path6.join(home, ".claude"),
15571
15817
  path6.join(home, ".config", "claude")
@@ -15581,7 +15827,7 @@ async function isClaudeInstalled() {
15581
15827
  return anyPathExists(candidates);
15582
15828
  }
15583
15829
  async function isWindsurfInstalled() {
15584
- const home = homedir3();
15830
+ const home = homedir4();
15585
15831
  const candidates = [
15586
15832
  path6.join(home, ".codeium"),
15587
15833
  path6.join(home, ".codeium", "windsurf"),
@@ -15600,7 +15846,7 @@ async function isWindsurfInstalled() {
15600
15846
  return anyPathExists(candidates);
15601
15847
  }
15602
15848
  async function isClineInstalled() {
15603
- const home = homedir3();
15849
+ const home = homedir4();
15604
15850
  const candidates = [
15605
15851
  path6.join(home, "Documents", "Cline"),
15606
15852
  path6.join(home, ".cline"),
@@ -15609,7 +15855,7 @@ async function isClineInstalled() {
15609
15855
  return anyPathExists(candidates);
15610
15856
  }
15611
15857
  async function isKiloInstalled() {
15612
- const home = homedir3();
15858
+ const home = homedir4();
15613
15859
  const candidates = [
15614
15860
  path6.join(home, ".kilocode"),
15615
15861
  path6.join(home, ".config", "kilocode")
@@ -15617,7 +15863,7 @@ async function isKiloInstalled() {
15617
15863
  return anyPathExists(candidates);
15618
15864
  }
15619
15865
  async function isRooInstalled() {
15620
- const home = homedir3();
15866
+ const home = homedir4();
15621
15867
  const candidates = [
15622
15868
  path6.join(home, ".roo"),
15623
15869
  path6.join(home, ".config", "roo")
@@ -15625,7 +15871,7 @@ async function isRooInstalled() {
15625
15871
  return anyPathExists(candidates);
15626
15872
  }
15627
15873
  async function isAiderInstalled() {
15628
- const home = homedir3();
15874
+ const home = homedir4();
15629
15875
  const candidates = [
15630
15876
  path6.join(home, ".aider.conf.yml"),
15631
15877
  path6.join(home, ".config", "aider")
@@ -15633,7 +15879,7 @@ async function isAiderInstalled() {
15633
15879
  return anyPathExists(candidates);
15634
15880
  }
15635
15881
  async function isCursorInstalled() {
15636
- const home = homedir3();
15882
+ const home = homedir4();
15637
15883
  const candidates = [path6.join(home, ".cursor")];
15638
15884
  if (process.platform === "darwin") {
15639
15885
  candidates.push("/Applications/Cursor.app");
@@ -15781,7 +16027,7 @@ async function upsertJsonVsCodeMcpConfig(filePath, server) {
15781
16027
  return before === after ? "skipped" : "updated";
15782
16028
  }
15783
16029
  function claudeDesktopConfigPath() {
15784
- const home = homedir3();
16030
+ const home = homedir4();
15785
16031
  if (process.platform === "darwin") {
15786
16032
  return path6.join(home, "Library", "Application Support", "Claude", "claude_desktop_config.json");
15787
16033
  }
@@ -16185,7 +16431,7 @@ Detected plan: ${planLabel} (graph: ${graphTierLabel})`);
16185
16431
  if (mcpScope === "project" && editor !== "codex") continue;
16186
16432
  try {
16187
16433
  if (editor === "codex") {
16188
- const filePath = path6.join(homedir3(), ".codex", "config.toml");
16434
+ const filePath = path6.join(homedir4(), ".codex", "config.toml");
16189
16435
  if (dryRun) {
16190
16436
  writeActions.push({ kind: "mcp-config", target: filePath, status: "dry-run" });
16191
16437
  console.log(`- ${EDITOR_LABELS[editor]}: would update ${filePath}`);
@@ -16197,7 +16443,7 @@ Detected plan: ${planLabel} (graph: ${graphTierLabel})`);
16197
16443
  continue;
16198
16444
  }
16199
16445
  if (editor === "windsurf") {
16200
- const filePath = path6.join(homedir3(), ".codeium", "windsurf", "mcp_config.json");
16446
+ const filePath = path6.join(homedir4(), ".codeium", "windsurf", "mcp_config.json");
16201
16447
  if (dryRun) {
16202
16448
  writeActions.push({ kind: "mcp-config", target: filePath, status: "dry-run" });
16203
16449
  console.log(`- ${EDITOR_LABELS[editor]}: would update ${filePath}`);
@@ -16231,7 +16477,7 @@ Detected plan: ${planLabel} (graph: ${graphTierLabel})`);
16231
16477
  continue;
16232
16478
  }
16233
16479
  if (editor === "cursor") {
16234
- const filePath = path6.join(homedir3(), ".cursor", "mcp.json");
16480
+ const filePath = path6.join(homedir4(), ".cursor", "mcp.json");
16235
16481
  if (dryRun) {
16236
16482
  writeActions.push({ kind: "mcp-config", target: filePath, status: "dry-run" });
16237
16483
  console.log(`- ${EDITOR_LABELS[editor]}: would update ${filePath}`);
@@ -16458,7 +16704,7 @@ Applying to ${projects.length} project(s)...`);
16458
16704
  // src/index.ts
16459
16705
  var ENABLE_PROMPTS2 = (process.env.CONTEXTSTREAM_ENABLE_PROMPTS || "true").toLowerCase() !== "false";
16460
16706
  function showFirstRunMessage() {
16461
- const configDir = join8(homedir4(), ".contextstream");
16707
+ const configDir = join8(homedir5(), ".contextstream");
16462
16708
  const starShownFile = join8(configDir, ".star-shown");
16463
16709
  if (existsSync4(starShownFile)) {
16464
16710
  return;
@@ -4050,6 +4050,21 @@ var coerce = {
4050
4050
  };
4051
4051
  var NEVER = INVALID;
4052
4052
 
4053
+ // src/version.ts
4054
+ import { createRequire } from "module";
4055
+ function getVersion() {
4056
+ try {
4057
+ const require2 = createRequire(import.meta.url);
4058
+ const pkg = require2("../package.json");
4059
+ const version = pkg?.version;
4060
+ if (typeof version === "string" && version.trim()) return version.trim();
4061
+ } catch {
4062
+ }
4063
+ return "unknown";
4064
+ }
4065
+ var VERSION = getVersion();
4066
+ var CACHE_TTL_MS = 24 * 60 * 60 * 1e3;
4067
+
4053
4068
  // src/config.ts
4054
4069
  var DEFAULT_API_URL = "https://api.contextstream.io";
4055
4070
  function parseBooleanEnv(value) {
@@ -4065,7 +4080,7 @@ var configSchema = external_exports.object({
4065
4080
  jwt: external_exports.string().min(1).optional(),
4066
4081
  defaultWorkspaceId: external_exports.string().uuid().optional(),
4067
4082
  defaultProjectId: external_exports.string().uuid().optional(),
4068
- userAgent: external_exports.string().default("contextstream-mcp/0.1.0"),
4083
+ userAgent: external_exports.string().default(`contextstream-mcp/${VERSION}`),
4069
4084
  allowHeaderAuth: external_exports.boolean().optional(),
4070
4085
  contextPackEnabled: external_exports.boolean().default(true)
4071
4086
  });
@@ -4097,21 +4112,6 @@ function loadConfig() {
4097
4112
  return parsed.data;
4098
4113
  }
4099
4114
 
4100
- // src/version.ts
4101
- import { createRequire } from "module";
4102
- function getVersion() {
4103
- try {
4104
- const require2 = createRequire(import.meta.url);
4105
- const pkg = require2("../package.json");
4106
- const version = pkg?.version;
4107
- if (typeof version === "string" && version.trim()) return version.trim();
4108
- } catch {
4109
- }
4110
- return "unknown";
4111
- }
4112
- var VERSION = getVersion();
4113
- var CACHE_TTL_MS = 24 * 60 * 60 * 1e3;
4114
-
4115
4115
  // src/test-server.ts
4116
4116
  var PORT = parseInt(process.env.MCP_TEST_PORT || "3099", 10);
4117
4117
  var pendingRequests = /* @__PURE__ */ new Map();
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@contextstream/mcp-server",
3
3
  "mcpName": "io.github.contextstreamio/mcp-server",
4
- "version": "0.4.16",
4
+ "version": "0.4.17",
5
5
  "description": "ContextStream MCP server - v0.4.x with consolidated domain tools (~11 tools, ~75% token reduction). Code context, memory, search, and AI tools.",
6
6
  "type": "module",
7
7
  "license": "MIT",