@contextstream/mcp-server 0.4.15 → 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 +571 -317
- package/dist/test-server.js +16 -16
- package/package.json +1 -1
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(
|
|
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="...")\`
|
|
7606
|
-
3. \`
|
|
7607
|
-
4.
|
|
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", ...)\`
|
|
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",
|
|
@@ -9420,6 +9669,30 @@ Upgrade: ${upgradeUrl2}` : "";
|
|
|
9420
9669
|
}
|
|
9421
9670
|
return { ok: true, resolvedPath };
|
|
9422
9671
|
}
|
|
9672
|
+
function startBackgroundIngest(projectId, resolvedPath, ingestOptions, options = {}) {
|
|
9673
|
+
(async () => {
|
|
9674
|
+
try {
|
|
9675
|
+
if (options.preflight) {
|
|
9676
|
+
const fileCheck = await countIndexableFiles(resolvedPath, { maxFiles: 1 });
|
|
9677
|
+
if (fileCheck.count === 0) {
|
|
9678
|
+
console.error(`[ContextStream] No indexable files found in ${resolvedPath}. Skipping ingest.`);
|
|
9679
|
+
return;
|
|
9680
|
+
}
|
|
9681
|
+
}
|
|
9682
|
+
let totalIndexed = 0;
|
|
9683
|
+
let batchCount = 0;
|
|
9684
|
+
console.error(`[ContextStream] Starting background ingestion for project ${projectId} from ${resolvedPath}`);
|
|
9685
|
+
for await (const batch of readAllFilesInBatches(resolvedPath, { batchSize: 50 })) {
|
|
9686
|
+
const result = await client.ingestFiles(projectId, batch, ingestOptions);
|
|
9687
|
+
totalIndexed += result.data?.files_indexed ?? batch.length;
|
|
9688
|
+
batchCount++;
|
|
9689
|
+
}
|
|
9690
|
+
console.error(`[ContextStream] Completed background ingestion: ${totalIndexed} files in ${batchCount} batches`);
|
|
9691
|
+
} catch (error) {
|
|
9692
|
+
console.error(`[ContextStream] Ingestion failed:`, error);
|
|
9693
|
+
}
|
|
9694
|
+
})();
|
|
9695
|
+
}
|
|
9423
9696
|
registerTool(
|
|
9424
9697
|
"mcp_server_version",
|
|
9425
9698
|
{
|
|
@@ -9742,30 +10015,13 @@ Access: Free`,
|
|
|
9742
10015
|
};
|
|
9743
10016
|
fs3.writeFileSync(configPath, JSON.stringify(config, null, 2));
|
|
9744
10017
|
if (input.generate_editor_rules) {
|
|
9745
|
-
|
|
9746
|
-
|
|
9747
|
-
|
|
9748
|
-
|
|
9749
|
-
|
|
9750
|
-
|
|
9751
|
-
|
|
9752
|
-
try {
|
|
9753
|
-
let existingContent = "";
|
|
9754
|
-
try {
|
|
9755
|
-
existingContent = fs3.readFileSync(filePath, "utf-8");
|
|
9756
|
-
} catch {
|
|
9757
|
-
}
|
|
9758
|
-
if (!existingContent) {
|
|
9759
|
-
fs3.writeFileSync(filePath, rule.content);
|
|
9760
|
-
rulesGenerated.push(rule.filename);
|
|
9761
|
-
} else if (!existingContent.includes("ContextStream")) {
|
|
9762
|
-
fs3.writeFileSync(filePath, existingContent + "\n\n" + rule.content);
|
|
9763
|
-
rulesGenerated.push(rule.filename + " (appended)");
|
|
9764
|
-
}
|
|
9765
|
-
} catch {
|
|
9766
|
-
}
|
|
9767
|
-
}
|
|
9768
|
-
}
|
|
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})`);
|
|
9769
10025
|
}
|
|
9770
10026
|
} catch (err) {
|
|
9771
10027
|
console.error("[ContextStream] Failed to write project config:", err);
|
|
@@ -10356,7 +10612,8 @@ ${formatContent(result)}`
|
|
|
10356
10612
|
title: "Ingest local files",
|
|
10357
10613
|
description: `Read ALL files from a local directory and ingest them for indexing.
|
|
10358
10614
|
This indexes your entire project by reading files in batches.
|
|
10359
|
-
Automatically detects code files and skips ignored directories like node_modules, target, dist, etc
|
|
10615
|
+
Automatically detects code files and skips ignored directories like node_modules, target, dist, etc.
|
|
10616
|
+
Runs in the background and returns immediately; use 'projects_index_status' to monitor progress.`,
|
|
10360
10617
|
inputSchema: external_exports.object({
|
|
10361
10618
|
project_id: external_exports.string().uuid().optional().describe("Project to ingest files into (defaults to current session project)"),
|
|
10362
10619
|
path: external_exports.string().describe("Local directory path to read files from"),
|
|
@@ -10373,31 +10630,11 @@ Automatically detects code files and skips ignored directories like node_modules
|
|
|
10373
10630
|
if (!pathCheck.ok) {
|
|
10374
10631
|
return errorResult(pathCheck.error);
|
|
10375
10632
|
}
|
|
10376
|
-
const fileCheck = await countIndexableFiles(pathCheck.resolvedPath, { maxFiles: 1 });
|
|
10377
|
-
if (fileCheck.count === 0) {
|
|
10378
|
-
return errorResult(
|
|
10379
|
-
`Error: no indexable files found in directory: ${input.path}. The directory may be empty or contain only ignored files/directories. Supported file types include: .ts, .js, .py, .rs, .go, .java, .md, .json, etc.`
|
|
10380
|
-
);
|
|
10381
|
-
}
|
|
10382
10633
|
const ingestOptions = {
|
|
10383
10634
|
...input.write_to_disk !== void 0 && { write_to_disk: input.write_to_disk },
|
|
10384
10635
|
...input.overwrite !== void 0 && { overwrite: input.overwrite }
|
|
10385
10636
|
};
|
|
10386
|
-
(
|
|
10387
|
-
try {
|
|
10388
|
-
let totalIndexed = 0;
|
|
10389
|
-
let batchCount = 0;
|
|
10390
|
-
console.error(`[ContextStream] Starting background ingestion for project ${projectId} from ${pathCheck.resolvedPath}`);
|
|
10391
|
-
for await (const batch of readAllFilesInBatches(pathCheck.resolvedPath, { batchSize: 50 })) {
|
|
10392
|
-
const result = await client.ingestFiles(projectId, batch, ingestOptions);
|
|
10393
|
-
totalIndexed += result.data?.files_indexed ?? batch.length;
|
|
10394
|
-
batchCount++;
|
|
10395
|
-
}
|
|
10396
|
-
console.error(`[ContextStream] Completed background ingestion: ${totalIndexed} files in ${batchCount} batches`);
|
|
10397
|
-
} catch (error) {
|
|
10398
|
-
console.error(`[ContextStream] Ingestion failed:`, error);
|
|
10399
|
-
}
|
|
10400
|
-
})();
|
|
10637
|
+
startBackgroundIngest(projectId, pathCheck.resolvedPath, ingestOptions, { preflight: true });
|
|
10401
10638
|
const summary = {
|
|
10402
10639
|
status: "started",
|
|
10403
10640
|
message: "Ingestion running in background",
|
|
@@ -10733,6 +10970,25 @@ This does semantic search on the first message. You only need context_smart on s
|
|
|
10733
10970
|
if (sessionManager) {
|
|
10734
10971
|
sessionManager.markInitialized(result);
|
|
10735
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
|
+
}
|
|
10736
10992
|
const workspaceId = typeof result.workspace_id === "string" ? result.workspace_id : void 0;
|
|
10737
10993
|
if (workspaceId && AUTO_HIDE_INTEGRATIONS) {
|
|
10738
10994
|
try {
|
|
@@ -10804,6 +11060,19 @@ This does semantic search on the first message. You only need context_smart on s
|
|
|
10804
11060
|
} else if (workspaceWarning) {
|
|
10805
11061
|
text = [`Warning: ${workspaceWarning}`, "", formatContent(result)].join("\n");
|
|
10806
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
|
+
}
|
|
10807
11076
|
return { content: [{ type: "text", text }], structuredContent: toStructured(result) };
|
|
10808
11077
|
}
|
|
10809
11078
|
);
|
|
@@ -10893,32 +11162,13 @@ Optionally generates AI editor rules for automatic ContextStream usage.`,
|
|
|
10893
11162
|
const result = await client.associateWorkspace(input);
|
|
10894
11163
|
let rulesGenerated = [];
|
|
10895
11164
|
if (input.generate_editor_rules) {
|
|
10896
|
-
const
|
|
10897
|
-
|
|
10898
|
-
|
|
10899
|
-
|
|
10900
|
-
|
|
10901
|
-
|
|
10902
|
-
|
|
10903
|
-
if (rule) {
|
|
10904
|
-
const filePath = path7.join(input.folder_path, rule.filename);
|
|
10905
|
-
try {
|
|
10906
|
-
let existingContent = "";
|
|
10907
|
-
try {
|
|
10908
|
-
existingContent = fs6.readFileSync(filePath, "utf-8");
|
|
10909
|
-
} catch {
|
|
10910
|
-
}
|
|
10911
|
-
if (!existingContent) {
|
|
10912
|
-
fs6.writeFileSync(filePath, rule.content);
|
|
10913
|
-
rulesGenerated.push(rule.filename);
|
|
10914
|
-
} else if (!existingContent.includes("ContextStream Integration")) {
|
|
10915
|
-
fs6.writeFileSync(filePath, existingContent + "\n\n" + rule.content);
|
|
10916
|
-
rulesGenerated.push(rule.filename + " (appended)");
|
|
10917
|
-
}
|
|
10918
|
-
} catch {
|
|
10919
|
-
}
|
|
10920
|
-
}
|
|
10921
|
-
}
|
|
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})`);
|
|
10922
11172
|
}
|
|
10923
11173
|
const response = {
|
|
10924
11174
|
...result,
|
|
@@ -10998,31 +11248,13 @@ Behavior:
|
|
|
10998
11248
|
});
|
|
10999
11249
|
let rulesGenerated = [];
|
|
11000
11250
|
if (input.generate_editor_rules) {
|
|
11001
|
-
const
|
|
11002
|
-
|
|
11003
|
-
|
|
11004
|
-
|
|
11005
|
-
|
|
11006
|
-
|
|
11007
|
-
|
|
11008
|
-
if (!rule) continue;
|
|
11009
|
-
const filePath = path7.join(folderPath, rule.filename);
|
|
11010
|
-
try {
|
|
11011
|
-
let existingContent = "";
|
|
11012
|
-
try {
|
|
11013
|
-
existingContent = fs6.readFileSync(filePath, "utf-8");
|
|
11014
|
-
} catch {
|
|
11015
|
-
}
|
|
11016
|
-
if (!existingContent) {
|
|
11017
|
-
fs6.writeFileSync(filePath, rule.content);
|
|
11018
|
-
rulesGenerated.push(rule.filename);
|
|
11019
|
-
} else if (!existingContent.includes("ContextStream Integration")) {
|
|
11020
|
-
fs6.writeFileSync(filePath, existingContent + "\n\n" + rule.content);
|
|
11021
|
-
rulesGenerated.push(rule.filename + " (appended)");
|
|
11022
|
-
}
|
|
11023
|
-
} catch {
|
|
11024
|
-
}
|
|
11025
|
-
}
|
|
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})`);
|
|
11026
11258
|
}
|
|
11027
11259
|
const session = await client.initSession(
|
|
11028
11260
|
{
|
|
@@ -11427,7 +11659,7 @@ Example: "What were the auth decisions?" or "What are my TypeScript preferences?
|
|
|
11427
11659
|
These rules instruct the AI to automatically use ContextStream for memory and context.
|
|
11428
11660
|
Supported editors: ${getAvailableEditors().join(", ")}`,
|
|
11429
11661
|
inputSchema: external_exports.object({
|
|
11430
|
-
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)"),
|
|
11431
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."),
|
|
11432
11664
|
workspace_name: external_exports.string().optional().describe("Workspace name to include in rules"),
|
|
11433
11665
|
workspace_id: external_exports.string().uuid().optional().describe("Workspace ID to include in rules"),
|
|
@@ -11438,58 +11670,48 @@ Supported editors: ${getAvailableEditors().join(", ")}`,
|
|
|
11438
11670
|
})
|
|
11439
11671
|
},
|
|
11440
11672
|
async (input) => {
|
|
11441
|
-
const
|
|
11442
|
-
|
|
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
|
+
}
|
|
11443
11677
|
const editors = input.editors?.includes("all") || !input.editors ? getAvailableEditors() : input.editors.filter((e) => e !== "all");
|
|
11444
11678
|
const results = [];
|
|
11445
|
-
|
|
11446
|
-
const
|
|
11447
|
-
|
|
11448
|
-
|
|
11449
|
-
|
|
11450
|
-
|
|
11451
|
-
|
|
11452
|
-
|
|
11453
|
-
|
|
11454
|
-
|
|
11455
|
-
|
|
11456
|
-
|
|
11457
|
-
|
|
11458
|
-
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
|
+
}
|
|
11459
11692
|
results.push({
|
|
11460
11693
|
editor,
|
|
11461
11694
|
filename: rule.filename,
|
|
11462
|
-
status: "dry run - would
|
|
11695
|
+
status: "dry run - would update",
|
|
11463
11696
|
content: rule.content
|
|
11464
11697
|
});
|
|
11465
|
-
} else {
|
|
11466
|
-
try {
|
|
11467
|
-
let existingContent = "";
|
|
11468
|
-
try {
|
|
11469
|
-
existingContent = fs6.readFileSync(filePath, "utf-8");
|
|
11470
|
-
} catch {
|
|
11471
|
-
}
|
|
11472
|
-
if (existingContent && !existingContent.includes("ContextStream Integration")) {
|
|
11473
|
-
const updatedContent = existingContent + "\n\n" + rule.content;
|
|
11474
|
-
fs6.writeFileSync(filePath, updatedContent);
|
|
11475
|
-
results.push({ editor, filename: rule.filename, status: "appended to existing" });
|
|
11476
|
-
} else {
|
|
11477
|
-
fs6.writeFileSync(filePath, rule.content);
|
|
11478
|
-
results.push({ editor, filename: rule.filename, status: "created" });
|
|
11479
|
-
}
|
|
11480
|
-
} catch (err) {
|
|
11481
|
-
results.push({
|
|
11482
|
-
editor,
|
|
11483
|
-
filename: rule.filename,
|
|
11484
|
-
status: `error: ${err.message}`
|
|
11485
|
-
});
|
|
11486
|
-
}
|
|
11487
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);
|
|
11488
11710
|
}
|
|
11489
11711
|
const summary = {
|
|
11490
|
-
folder:
|
|
11712
|
+
folder: folderPath,
|
|
11491
11713
|
results,
|
|
11492
|
-
message: input.dry_run ? "Dry run complete. Use dry_run: false to write files." : `Generated ${results.filter((r) => r.status === "created" || r.status.
|
|
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.`
|
|
11493
11715
|
};
|
|
11494
11716
|
return { content: [{ type: "text", text: formatContent(summary) }], structuredContent: toStructured(summary) };
|
|
11495
11717
|
}
|
|
@@ -11763,11 +11985,27 @@ This saves ~80% tokens compared to including full chat history.`,
|
|
|
11763
11985
|
const footer = `
|
|
11764
11986
|
---
|
|
11765
11987
|
\u{1F3AF} ${result.sources_used} sources | ~${result.token_estimate} tokens | format: ${result.format}`;
|
|
11766
|
-
const
|
|
11767
|
-
|
|
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
|
+
};
|
|
11768
12006
|
return {
|
|
11769
|
-
content: [{ type: "text", text: result.context + footer + versionNoticeLine }],
|
|
11770
|
-
structuredContent: toStructured(
|
|
12007
|
+
content: [{ type: "text", text: result.context + footer + rulesNoticeLine + versionNoticeLine }],
|
|
12008
|
+
structuredContent: toStructured(enrichedResult)
|
|
11771
12009
|
};
|
|
11772
12010
|
}
|
|
11773
12011
|
);
|
|
@@ -13489,24 +13727,27 @@ Use this to remove a reminder that is no longer relevant.`,
|
|
|
13489
13727
|
if (!validPath.ok) {
|
|
13490
13728
|
return errorResult(validPath.error);
|
|
13491
13729
|
}
|
|
13492
|
-
|
|
13493
|
-
|
|
13494
|
-
|
|
13495
|
-
|
|
13496
|
-
|
|
13497
|
-
overwrite: input.overwrite,
|
|
13498
|
-
write_to_disk: input.write_to_disk
|
|
13499
|
-
});
|
|
13500
|
-
totalFiles += batch.length;
|
|
13501
|
-
batches += 1;
|
|
13502
|
-
}
|
|
13730
|
+
const ingestOptions = {
|
|
13731
|
+
...input.write_to_disk !== void 0 && { write_to_disk: input.write_to_disk },
|
|
13732
|
+
...input.overwrite !== void 0 && { overwrite: input.overwrite }
|
|
13733
|
+
};
|
|
13734
|
+
startBackgroundIngest(projectId, validPath.resolvedPath, ingestOptions);
|
|
13503
13735
|
const result = {
|
|
13736
|
+
status: "started",
|
|
13737
|
+
message: "Ingestion running in background",
|
|
13504
13738
|
project_id: projectId,
|
|
13505
|
-
|
|
13506
|
-
|
|
13507
|
-
|
|
13739
|
+
path: validPath.resolvedPath,
|
|
13740
|
+
...input.write_to_disk !== void 0 && { write_to_disk: input.write_to_disk },
|
|
13741
|
+
...input.overwrite !== void 0 && { overwrite: input.overwrite },
|
|
13742
|
+
note: "Use 'project' with action 'index_status' to monitor progress."
|
|
13743
|
+
};
|
|
13744
|
+
return {
|
|
13745
|
+
content: [{
|
|
13746
|
+
type: "text",
|
|
13747
|
+
text: `Ingestion started in background for directory: ${validPath.resolvedPath}. Use 'project' with action 'index_status' to monitor progress.`
|
|
13748
|
+
}],
|
|
13749
|
+
structuredContent: toStructured(result)
|
|
13508
13750
|
};
|
|
13509
|
-
return { content: [{ type: "text", text: formatContent(result) }], structuredContent: toStructured(result) };
|
|
13510
13751
|
}
|
|
13511
13752
|
default:
|
|
13512
13753
|
return errorResult(`Unknown action: ${input.action}`);
|
|
@@ -14819,6 +15060,12 @@ var SessionManager = class {
|
|
|
14819
15060
|
getContext() {
|
|
14820
15061
|
return this.context;
|
|
14821
15062
|
}
|
|
15063
|
+
/**
|
|
15064
|
+
* Get the current folder path (if known)
|
|
15065
|
+
*/
|
|
15066
|
+
getFolderPath() {
|
|
15067
|
+
return this.folderPath;
|
|
15068
|
+
}
|
|
14822
15069
|
/**
|
|
14823
15070
|
* Mark session as manually initialized (e.g., when session_init is called explicitly)
|
|
14824
15071
|
*/
|
|
@@ -14830,6 +15077,10 @@ var SessionManager = class {
|
|
|
14830
15077
|
if (workspaceId || projectId) {
|
|
14831
15078
|
this.client.setDefaults({ workspace_id: workspaceId, project_id: projectId });
|
|
14832
15079
|
}
|
|
15080
|
+
const contextFolderPath = typeof context.folder_path === "string" ? context.folder_path : void 0;
|
|
15081
|
+
if (contextFolderPath) {
|
|
15082
|
+
this.folderPath = contextFolderPath;
|
|
15083
|
+
}
|
|
14833
15084
|
}
|
|
14834
15085
|
/**
|
|
14835
15086
|
* Set the folder path hint (can be passed from tools that know the workspace path)
|
|
@@ -14921,6 +15172,9 @@ var SessionManager = class {
|
|
|
14921
15172
|
if (this.ideRoots.length === 0 && this.folderPath) {
|
|
14922
15173
|
this.ideRoots = [this.folderPath];
|
|
14923
15174
|
}
|
|
15175
|
+
if (this.ideRoots.length > 0) {
|
|
15176
|
+
this.folderPath = this.ideRoots[0];
|
|
15177
|
+
}
|
|
14924
15178
|
this.initializationPromise = this._doInitialize();
|
|
14925
15179
|
try {
|
|
14926
15180
|
const result = await this.initializationPromise;
|
|
@@ -15366,25 +15620,25 @@ async function runHttpGateway() {
|
|
|
15366
15620
|
|
|
15367
15621
|
// src/index.ts
|
|
15368
15622
|
import { existsSync as existsSync4, mkdirSync as mkdirSync4, writeFileSync as writeFileSync4 } from "fs";
|
|
15369
|
-
import { homedir as
|
|
15623
|
+
import { homedir as homedir5 } from "os";
|
|
15370
15624
|
import { join as join8 } from "path";
|
|
15371
15625
|
|
|
15372
15626
|
// src/setup.ts
|
|
15373
15627
|
import * as fs5 from "node:fs/promises";
|
|
15374
15628
|
import * as path6 from "node:path";
|
|
15375
|
-
import { homedir as
|
|
15629
|
+
import { homedir as homedir4 } from "node:os";
|
|
15376
15630
|
import { stdin, stdout } from "node:process";
|
|
15377
15631
|
import { createInterface } from "node:readline/promises";
|
|
15378
15632
|
|
|
15379
15633
|
// src/credentials.ts
|
|
15380
15634
|
import * as fs4 from "node:fs/promises";
|
|
15381
15635
|
import * as path5 from "node:path";
|
|
15382
|
-
import { homedir as
|
|
15636
|
+
import { homedir as homedir3 } from "node:os";
|
|
15383
15637
|
function normalizeApiUrl(input) {
|
|
15384
15638
|
return String(input ?? "").trim().replace(/\/+$/, "");
|
|
15385
15639
|
}
|
|
15386
15640
|
function credentialsFilePath() {
|
|
15387
|
-
return path5.join(
|
|
15641
|
+
return path5.join(homedir3(), ".contextstream", "credentials.json");
|
|
15388
15642
|
}
|
|
15389
15643
|
function isRecord(value) {
|
|
15390
15644
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
@@ -15482,27 +15736,27 @@ async function fileExists(filePath) {
|
|
|
15482
15736
|
return false;
|
|
15483
15737
|
}
|
|
15484
15738
|
}
|
|
15485
|
-
var
|
|
15486
|
-
var
|
|
15487
|
-
function
|
|
15488
|
-
return `${
|
|
15739
|
+
var CONTEXTSTREAM_START_MARKER2 = "<!-- BEGIN ContextStream -->";
|
|
15740
|
+
var CONTEXTSTREAM_END_MARKER2 = "<!-- END ContextStream -->";
|
|
15741
|
+
function wrapWithMarkers2(content) {
|
|
15742
|
+
return `${CONTEXTSTREAM_START_MARKER2}
|
|
15489
15743
|
${content.trim()}
|
|
15490
|
-
${
|
|
15744
|
+
${CONTEXTSTREAM_END_MARKER2}`;
|
|
15491
15745
|
}
|
|
15492
15746
|
async function upsertTextFile(filePath, content, _marker) {
|
|
15493
15747
|
await fs5.mkdir(path6.dirname(filePath), { recursive: true });
|
|
15494
15748
|
const exists = await fileExists(filePath);
|
|
15495
|
-
const wrappedContent =
|
|
15749
|
+
const wrappedContent = wrapWithMarkers2(content);
|
|
15496
15750
|
if (!exists) {
|
|
15497
15751
|
await fs5.writeFile(filePath, wrappedContent + "\n", "utf8");
|
|
15498
15752
|
return "created";
|
|
15499
15753
|
}
|
|
15500
15754
|
const existing = await fs5.readFile(filePath, "utf8").catch(() => "");
|
|
15501
|
-
const startIdx = existing.indexOf(
|
|
15502
|
-
const endIdx = existing.indexOf(
|
|
15755
|
+
const startIdx = existing.indexOf(CONTEXTSTREAM_START_MARKER2);
|
|
15756
|
+
const endIdx = existing.indexOf(CONTEXTSTREAM_END_MARKER2);
|
|
15503
15757
|
if (startIdx !== -1 && endIdx !== -1 && endIdx > startIdx) {
|
|
15504
15758
|
const before = existing.substring(0, startIdx);
|
|
15505
|
-
const after = existing.substring(endIdx +
|
|
15759
|
+
const after = existing.substring(endIdx + CONTEXTSTREAM_END_MARKER2.length);
|
|
15506
15760
|
const updated = before.trimEnd() + "\n\n" + wrappedContent + "\n" + after.trimStart();
|
|
15507
15761
|
await fs5.writeFile(filePath, updated.trim() + "\n", "utf8");
|
|
15508
15762
|
return "updated";
|
|
@@ -15517,7 +15771,7 @@ async function upsertTextFile(filePath, content, _marker) {
|
|
|
15517
15771
|
return "appended";
|
|
15518
15772
|
}
|
|
15519
15773
|
function globalRulesPathForEditor(editor) {
|
|
15520
|
-
const home =
|
|
15774
|
+
const home = homedir4();
|
|
15521
15775
|
switch (editor) {
|
|
15522
15776
|
case "codex":
|
|
15523
15777
|
return path6.join(home, ".codex", "AGENTS.md");
|
|
@@ -15546,7 +15800,7 @@ async function anyPathExists(paths) {
|
|
|
15546
15800
|
return false;
|
|
15547
15801
|
}
|
|
15548
15802
|
async function isCodexInstalled() {
|
|
15549
|
-
const home =
|
|
15803
|
+
const home = homedir4();
|
|
15550
15804
|
const envHome = process.env.CODEX_HOME;
|
|
15551
15805
|
const candidates = [
|
|
15552
15806
|
envHome,
|
|
@@ -15557,7 +15811,7 @@ async function isCodexInstalled() {
|
|
|
15557
15811
|
return anyPathExists(candidates);
|
|
15558
15812
|
}
|
|
15559
15813
|
async function isClaudeInstalled() {
|
|
15560
|
-
const home =
|
|
15814
|
+
const home = homedir4();
|
|
15561
15815
|
const candidates = [
|
|
15562
15816
|
path6.join(home, ".claude"),
|
|
15563
15817
|
path6.join(home, ".config", "claude")
|
|
@@ -15573,7 +15827,7 @@ async function isClaudeInstalled() {
|
|
|
15573
15827
|
return anyPathExists(candidates);
|
|
15574
15828
|
}
|
|
15575
15829
|
async function isWindsurfInstalled() {
|
|
15576
|
-
const home =
|
|
15830
|
+
const home = homedir4();
|
|
15577
15831
|
const candidates = [
|
|
15578
15832
|
path6.join(home, ".codeium"),
|
|
15579
15833
|
path6.join(home, ".codeium", "windsurf"),
|
|
@@ -15592,7 +15846,7 @@ async function isWindsurfInstalled() {
|
|
|
15592
15846
|
return anyPathExists(candidates);
|
|
15593
15847
|
}
|
|
15594
15848
|
async function isClineInstalled() {
|
|
15595
|
-
const home =
|
|
15849
|
+
const home = homedir4();
|
|
15596
15850
|
const candidates = [
|
|
15597
15851
|
path6.join(home, "Documents", "Cline"),
|
|
15598
15852
|
path6.join(home, ".cline"),
|
|
@@ -15601,7 +15855,7 @@ async function isClineInstalled() {
|
|
|
15601
15855
|
return anyPathExists(candidates);
|
|
15602
15856
|
}
|
|
15603
15857
|
async function isKiloInstalled() {
|
|
15604
|
-
const home =
|
|
15858
|
+
const home = homedir4();
|
|
15605
15859
|
const candidates = [
|
|
15606
15860
|
path6.join(home, ".kilocode"),
|
|
15607
15861
|
path6.join(home, ".config", "kilocode")
|
|
@@ -15609,7 +15863,7 @@ async function isKiloInstalled() {
|
|
|
15609
15863
|
return anyPathExists(candidates);
|
|
15610
15864
|
}
|
|
15611
15865
|
async function isRooInstalled() {
|
|
15612
|
-
const home =
|
|
15866
|
+
const home = homedir4();
|
|
15613
15867
|
const candidates = [
|
|
15614
15868
|
path6.join(home, ".roo"),
|
|
15615
15869
|
path6.join(home, ".config", "roo")
|
|
@@ -15617,7 +15871,7 @@ async function isRooInstalled() {
|
|
|
15617
15871
|
return anyPathExists(candidates);
|
|
15618
15872
|
}
|
|
15619
15873
|
async function isAiderInstalled() {
|
|
15620
|
-
const home =
|
|
15874
|
+
const home = homedir4();
|
|
15621
15875
|
const candidates = [
|
|
15622
15876
|
path6.join(home, ".aider.conf.yml"),
|
|
15623
15877
|
path6.join(home, ".config", "aider")
|
|
@@ -15625,7 +15879,7 @@ async function isAiderInstalled() {
|
|
|
15625
15879
|
return anyPathExists(candidates);
|
|
15626
15880
|
}
|
|
15627
15881
|
async function isCursorInstalled() {
|
|
15628
|
-
const home =
|
|
15882
|
+
const home = homedir4();
|
|
15629
15883
|
const candidates = [path6.join(home, ".cursor")];
|
|
15630
15884
|
if (process.platform === "darwin") {
|
|
15631
15885
|
candidates.push("/Applications/Cursor.app");
|
|
@@ -15773,7 +16027,7 @@ async function upsertJsonVsCodeMcpConfig(filePath, server) {
|
|
|
15773
16027
|
return before === after ? "skipped" : "updated";
|
|
15774
16028
|
}
|
|
15775
16029
|
function claudeDesktopConfigPath() {
|
|
15776
|
-
const home =
|
|
16030
|
+
const home = homedir4();
|
|
15777
16031
|
if (process.platform === "darwin") {
|
|
15778
16032
|
return path6.join(home, "Library", "Application Support", "Claude", "claude_desktop_config.json");
|
|
15779
16033
|
}
|
|
@@ -16177,7 +16431,7 @@ Detected plan: ${planLabel} (graph: ${graphTierLabel})`);
|
|
|
16177
16431
|
if (mcpScope === "project" && editor !== "codex") continue;
|
|
16178
16432
|
try {
|
|
16179
16433
|
if (editor === "codex") {
|
|
16180
|
-
const filePath = path6.join(
|
|
16434
|
+
const filePath = path6.join(homedir4(), ".codex", "config.toml");
|
|
16181
16435
|
if (dryRun) {
|
|
16182
16436
|
writeActions.push({ kind: "mcp-config", target: filePath, status: "dry-run" });
|
|
16183
16437
|
console.log(`- ${EDITOR_LABELS[editor]}: would update ${filePath}`);
|
|
@@ -16189,7 +16443,7 @@ Detected plan: ${planLabel} (graph: ${graphTierLabel})`);
|
|
|
16189
16443
|
continue;
|
|
16190
16444
|
}
|
|
16191
16445
|
if (editor === "windsurf") {
|
|
16192
|
-
const filePath = path6.join(
|
|
16446
|
+
const filePath = path6.join(homedir4(), ".codeium", "windsurf", "mcp_config.json");
|
|
16193
16447
|
if (dryRun) {
|
|
16194
16448
|
writeActions.push({ kind: "mcp-config", target: filePath, status: "dry-run" });
|
|
16195
16449
|
console.log(`- ${EDITOR_LABELS[editor]}: would update ${filePath}`);
|
|
@@ -16223,7 +16477,7 @@ Detected plan: ${planLabel} (graph: ${graphTierLabel})`);
|
|
|
16223
16477
|
continue;
|
|
16224
16478
|
}
|
|
16225
16479
|
if (editor === "cursor") {
|
|
16226
|
-
const filePath = path6.join(
|
|
16480
|
+
const filePath = path6.join(homedir4(), ".cursor", "mcp.json");
|
|
16227
16481
|
if (dryRun) {
|
|
16228
16482
|
writeActions.push({ kind: "mcp-config", target: filePath, status: "dry-run" });
|
|
16229
16483
|
console.log(`- ${EDITOR_LABELS[editor]}: would update ${filePath}`);
|
|
@@ -16450,7 +16704,7 @@ Applying to ${projects.length} project(s)...`);
|
|
|
16450
16704
|
// src/index.ts
|
|
16451
16705
|
var ENABLE_PROMPTS2 = (process.env.CONTEXTSTREAM_ENABLE_PROMPTS || "true").toLowerCase() !== "false";
|
|
16452
16706
|
function showFirstRunMessage() {
|
|
16453
|
-
const configDir = join8(
|
|
16707
|
+
const configDir = join8(homedir5(), ".contextstream");
|
|
16454
16708
|
const starShownFile = join8(configDir, ".star-shown");
|
|
16455
16709
|
if (existsSync4(starShownFile)) {
|
|
16456
16710
|
return;
|
package/dist/test-server.js
CHANGED
|
@@ -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(
|
|
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.
|
|
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",
|