@contextstream/mcp-server 0.4.16 → 0.4.19
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 +627 -284
- 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",
|
|
@@ -7499,7 +7504,7 @@ var CONTEXTSTREAM_TOOL_NAMES = [
|
|
|
7499
7504
|
];
|
|
7500
7505
|
function applyMcpToolPrefix(markdown, toolPrefix) {
|
|
7501
7506
|
const toolPattern = CONTEXTSTREAM_TOOL_NAMES.join("|");
|
|
7502
|
-
const toolRegex = new RegExp(`(?<!__)\\b(${toolPattern})\\b`, "g");
|
|
7507
|
+
const toolRegex = new RegExp(`(?<!__)\\b(${toolPattern})\\b(?=\\s*\\()`, "g");
|
|
7503
7508
|
return markdown.replace(toolRegex, `${toolPrefix}$1`);
|
|
7504
7509
|
}
|
|
7505
7510
|
var CONTEXTSTREAM_RULES_FULL = `
|
|
@@ -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
|
|
|
@@ -7523,6 +7529,8 @@ v0.4.x uses **~11 consolidated domain tools** for ~75% token reduction vs previo
|
|
|
7523
7529
|
|
|
7524
7530
|
**Context Pack (Pro+):** If enabled, use \`context_smart(..., mode="pack", distill=true)\` for code/file queries. If unavailable, omit \`mode\` and use standard \`context_smart\`.
|
|
7525
7531
|
|
|
7532
|
+
**Tool naming:** Use the exact tool names exposed by your MCP client. Claude Code typically uses \`mcp__<server>__<tool>\` where \`<server>\` matches your MCP config (often \`contextstream\`). If a tool call fails with "No such tool available", refresh rules and match the tool list.
|
|
7533
|
+
|
|
7526
7534
|
---
|
|
7527
7535
|
|
|
7528
7536
|
## Consolidated Domain Tools Architecture
|
|
@@ -7578,6 +7586,13 @@ If context still feels missing, use \`session(action="recall", query="...")\` fo
|
|
|
7578
7586
|
|
|
7579
7587
|
---
|
|
7580
7588
|
|
|
7589
|
+
### Rules Update Notices
|
|
7590
|
+
|
|
7591
|
+
- If you see **[RULES_NOTICE]**, update rules via \`generate_editor_rules(folder_path="<cwd>")\` (or rerun setup).
|
|
7592
|
+
- If you see **[VERSION_NOTICE]**, tell the user to update MCP using the provided command.
|
|
7593
|
+
|
|
7594
|
+
---
|
|
7595
|
+
|
|
7581
7596
|
### Preferences & Lessons (Use Early)
|
|
7582
7597
|
|
|
7583
7598
|
- If preferences/style matter: \`session(action="user_context")\`
|
|
@@ -7595,6 +7610,7 @@ Before searching files or code, confirm the project is indexed and the graph is
|
|
|
7595
7610
|
- Local repo: \`project(action="ingest_local", path="<cwd>")\`
|
|
7596
7611
|
- Otherwise: \`project(action="index")\`
|
|
7597
7612
|
3. If graph queries are empty/unavailable: \`graph(action="ingest")\`
|
|
7613
|
+
4. If indexing is in progress, tell the user and wait; do not fall back to local scans.
|
|
7598
7614
|
|
|
7599
7615
|
Only after this preflight, proceed with search/analysis below.
|
|
7600
7616
|
|
|
@@ -7602,9 +7618,12 @@ Only after this preflight, proceed with search/analysis below.
|
|
|
7602
7618
|
|
|
7603
7619
|
**Search order:**
|
|
7604
7620
|
1. \`session(action="smart_search", query="...")\` - context-enriched
|
|
7605
|
-
2. \`search(mode="hybrid", query="...")\`
|
|
7606
|
-
3. \`
|
|
7607
|
-
4.
|
|
7621
|
+
2. \`search(mode="hybrid", query="...")\` or \`search(mode="keyword", query="<filename>")\`
|
|
7622
|
+
3. \`project(action="files")\` - file tree/list (only when needed)
|
|
7623
|
+
4. \`graph(action="dependencies", ...)\` - code structure
|
|
7624
|
+
5. Local repo scans (rg/ls/find) - only if ContextStream returns no results or is unavailable
|
|
7625
|
+
|
|
7626
|
+
Use ContextStream results directly; only open files if you need exact code.
|
|
7608
7627
|
|
|
7609
7628
|
**Code Analysis:**
|
|
7610
7629
|
- Dependencies: \`graph(action="dependencies", file_path="...")\`
|
|
@@ -7684,6 +7703,7 @@ var CONTEXTSTREAM_RULES_MINIMAL = `
|
|
|
7684
7703
|
## ContextStream v0.4.x (Consolidated Domain Tools)
|
|
7685
7704
|
|
|
7686
7705
|
v0.4.x uses ~11 consolidated domain tools for ~75% token reduction vs previous versions.
|
|
7706
|
+
Rules Version: ${RULES_VERSION}
|
|
7687
7707
|
|
|
7688
7708
|
### Required Every Message
|
|
7689
7709
|
|
|
@@ -7697,6 +7717,8 @@ v0.4.x uses ~11 consolidated domain tools for ~75% token reduction vs previous v
|
|
|
7697
7717
|
|
|
7698
7718
|
**Context Pack (Pro+):** If enabled, use \`context_smart(..., mode="pack", distill=true)\` for code/file queries. If unavailable, omit \`mode\`.
|
|
7699
7719
|
|
|
7720
|
+
**Tool naming:** Use the exact tool names exposed by your MCP client. Claude Code typically uses \`mcp__<server>__<tool>\` where \`<server>\` matches your MCP config (often \`contextstream\`). If a tool call fails with "No such tool available", refresh rules and match the tool list.
|
|
7721
|
+
|
|
7700
7722
|
### Quick Reference: Domain Tools
|
|
7701
7723
|
|
|
7702
7724
|
| Tool | Common Usage |
|
|
@@ -7705,7 +7727,7 @@ v0.4.x uses ~11 consolidated domain tools for ~75% token reduction vs previous v
|
|
|
7705
7727
|
| \`session\` | \`session(action="capture", ...)\` \u2014 actions: capture, capture_lesson, get_lessons, recall, remember, user_context, summary, compress, delta, smart_search |
|
|
7706
7728
|
| \`memory\` | \`memory(action="list_events", ...)\` \u2014 CRUD for events/nodes, search, decisions, timeline, summary |
|
|
7707
7729
|
| \`graph\` | \`graph(action="dependencies", ...)\` \u2014 dependencies, impact, call_path, related, ingest |
|
|
7708
|
-
| \`project\` | \`project(action="list", ...)\`
|
|
7730
|
+
| \`project\` | \`project(action="list", ...)\` - list, get, create, update, index, overview, statistics, files, index_status, ingest_local |
|
|
7709
7731
|
| \`workspace\` | \`workspace(action="list", ...)\` \u2014 list, get, associate, bootstrap |
|
|
7710
7732
|
| \`integration\` | \`integration(provider="github", action="search", ...)\` \u2014 GitHub/Slack integration |
|
|
7711
7733
|
| \`help\` | \`help(action="tools")\` \u2014 tools, auth, version, editor_rules |
|
|
@@ -7715,8 +7737,10 @@ v0.4.x uses ~11 consolidated domain tools for ~75% token reduction vs previous v
|
|
|
7715
7737
|
- **First message**: Always call \`session_init\` with context_hint
|
|
7716
7738
|
- **Every message after**: Always call \`context_smart\` BEFORE responding (semantic search for relevant context)
|
|
7717
7739
|
- **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
|
|
7740
|
+
- **For discovery**: Use \`session(action="smart_search")\` or \`search(mode="hybrid")\` before any local repo scans
|
|
7741
|
+
- **For file/function/config lookups**: Use \`search\`/\`graph\` first; only fall back to rg/ls/find if ContextStream returns no results
|
|
7719
7742
|
- **For code analysis**: Use \`graph(action="dependencies")\` or \`graph(action="impact")\` for call/dependency analysis
|
|
7743
|
+
- **On [RULES_NOTICE]**: Use \`generate_editor_rules(folder_path="<cwd>")\` to update rules
|
|
7720
7744
|
- **After completing work**: Always capture decisions/insights with \`session(action="capture")\`
|
|
7721
7745
|
- **On mistakes/corrections**: Immediately capture lessons with \`session(action="capture_lesson")\`
|
|
7722
7746
|
|
|
@@ -8042,6 +8066,284 @@ function normalizeUuid(value) {
|
|
|
8042
8066
|
if (!value) return void 0;
|
|
8043
8067
|
return uuidSchema2.safeParse(value).success ? value : void 0;
|
|
8044
8068
|
}
|
|
8069
|
+
var RULES_NOTICE_CACHE_TTL_MS = 10 * 60 * 1e3;
|
|
8070
|
+
var RULES_VERSION_REGEX = /Rules Version:\s*([0-9][0-9A-Za-z.\-]*)/i;
|
|
8071
|
+
var RULES_PROJECT_FILES = {
|
|
8072
|
+
codex: "AGENTS.md",
|
|
8073
|
+
claude: "CLAUDE.md",
|
|
8074
|
+
cursor: ".cursorrules",
|
|
8075
|
+
windsurf: ".windsurfrules",
|
|
8076
|
+
cline: ".clinerules",
|
|
8077
|
+
kilo: path4.join(".kilocode", "rules", "contextstream.md"),
|
|
8078
|
+
roo: path4.join(".roo", "rules", "contextstream.md"),
|
|
8079
|
+
aider: ".aider.conf.yml"
|
|
8080
|
+
};
|
|
8081
|
+
var RULES_GLOBAL_FILES = {
|
|
8082
|
+
codex: [path4.join(homedir2(), ".codex", "AGENTS.md")],
|
|
8083
|
+
windsurf: [path4.join(homedir2(), ".codeium", "windsurf", "memories", "global_rules.md")],
|
|
8084
|
+
kilo: [path4.join(homedir2(), ".kilocode", "rules", "contextstream.md")],
|
|
8085
|
+
roo: [path4.join(homedir2(), ".roo", "rules", "contextstream.md")]
|
|
8086
|
+
};
|
|
8087
|
+
var rulesNoticeCache = /* @__PURE__ */ new Map();
|
|
8088
|
+
function compareVersions2(v1, v2) {
|
|
8089
|
+
const parts1 = v1.split(".").map(Number);
|
|
8090
|
+
const parts2 = v2.split(".").map(Number);
|
|
8091
|
+
for (let i = 0; i < Math.max(parts1.length, parts2.length); i++) {
|
|
8092
|
+
const p1 = parts1[i] ?? 0;
|
|
8093
|
+
const p2 = parts2[i] ?? 0;
|
|
8094
|
+
if (p1 < p2) return -1;
|
|
8095
|
+
if (p1 > p2) return 1;
|
|
8096
|
+
}
|
|
8097
|
+
return 0;
|
|
8098
|
+
}
|
|
8099
|
+
function extractRulesVersion(content) {
|
|
8100
|
+
const match = content.match(RULES_VERSION_REGEX);
|
|
8101
|
+
return match?.[1]?.trim() ?? null;
|
|
8102
|
+
}
|
|
8103
|
+
function detectEditorFromClientName(clientName) {
|
|
8104
|
+
if (!clientName) return null;
|
|
8105
|
+
const normalized = clientName.toLowerCase().trim();
|
|
8106
|
+
if (normalized.includes("cursor")) return "cursor";
|
|
8107
|
+
if (normalized.includes("windsurf") || normalized.includes("codeium")) return "windsurf";
|
|
8108
|
+
if (normalized.includes("claude")) return "claude";
|
|
8109
|
+
if (normalized.includes("cline")) return "cline";
|
|
8110
|
+
if (normalized.includes("kilo")) return "kilo";
|
|
8111
|
+
if (normalized.includes("roo")) return "roo";
|
|
8112
|
+
if (normalized.includes("codex")) return "codex";
|
|
8113
|
+
if (normalized.includes("aider")) return "aider";
|
|
8114
|
+
return null;
|
|
8115
|
+
}
|
|
8116
|
+
function resolveRulesCandidatePaths(folderPath, editorKey) {
|
|
8117
|
+
const candidates = /* @__PURE__ */ new Set();
|
|
8118
|
+
const addProject = (key) => {
|
|
8119
|
+
if (!folderPath) return;
|
|
8120
|
+
const rel = RULES_PROJECT_FILES[key];
|
|
8121
|
+
if (rel) {
|
|
8122
|
+
candidates.add(path4.join(folderPath, rel));
|
|
8123
|
+
}
|
|
8124
|
+
};
|
|
8125
|
+
const addGlobal = (key) => {
|
|
8126
|
+
const paths = RULES_GLOBAL_FILES[key];
|
|
8127
|
+
if (!paths) return;
|
|
8128
|
+
for (const p of paths) {
|
|
8129
|
+
candidates.add(p);
|
|
8130
|
+
}
|
|
8131
|
+
};
|
|
8132
|
+
if (editorKey) {
|
|
8133
|
+
addProject(editorKey);
|
|
8134
|
+
addGlobal(editorKey);
|
|
8135
|
+
} else {
|
|
8136
|
+
for (const key of Object.keys(RULES_PROJECT_FILES)) {
|
|
8137
|
+
addProject(key);
|
|
8138
|
+
addGlobal(key);
|
|
8139
|
+
}
|
|
8140
|
+
}
|
|
8141
|
+
return Array.from(candidates);
|
|
8142
|
+
}
|
|
8143
|
+
function resolveFolderPath(inputPath, sessionManager) {
|
|
8144
|
+
if (inputPath) return inputPath;
|
|
8145
|
+
const fromSession = sessionManager?.getFolderPath();
|
|
8146
|
+
if (fromSession) return fromSession;
|
|
8147
|
+
const ctxPath = sessionManager?.getContext();
|
|
8148
|
+
const contextFolder = ctxPath && typeof ctxPath.folder_path === "string" ? ctxPath.folder_path : null;
|
|
8149
|
+
if (contextFolder) return contextFolder;
|
|
8150
|
+
const cwd = process.cwd();
|
|
8151
|
+
const indicators = [".git", "package.json", "Cargo.toml", "pyproject.toml", ".contextstream"];
|
|
8152
|
+
const hasIndicator = indicators.some((entry) => {
|
|
8153
|
+
try {
|
|
8154
|
+
return fs3.existsSync(path4.join(cwd, entry));
|
|
8155
|
+
} catch {
|
|
8156
|
+
return false;
|
|
8157
|
+
}
|
|
8158
|
+
});
|
|
8159
|
+
return hasIndicator ? cwd : null;
|
|
8160
|
+
}
|
|
8161
|
+
function getRulesNotice(folderPath, clientName) {
|
|
8162
|
+
if (!RULES_VERSION || RULES_VERSION === "0.0.0") return null;
|
|
8163
|
+
const editorKey = detectEditorFromClientName(clientName);
|
|
8164
|
+
if (!folderPath && !editorKey) {
|
|
8165
|
+
return null;
|
|
8166
|
+
}
|
|
8167
|
+
const cacheKey = `${folderPath ?? "none"}|${editorKey ?? "all"}`;
|
|
8168
|
+
const cached = rulesNoticeCache.get(cacheKey);
|
|
8169
|
+
if (cached && Date.now() - cached.checkedAt < RULES_NOTICE_CACHE_TTL_MS) {
|
|
8170
|
+
return cached.notice;
|
|
8171
|
+
}
|
|
8172
|
+
const candidates = resolveRulesCandidatePaths(folderPath, editorKey);
|
|
8173
|
+
const existing = candidates.filter((filePath) => fs3.existsSync(filePath));
|
|
8174
|
+
if (existing.length === 0) {
|
|
8175
|
+
const updateCommand2 = folderPath ? `generate_editor_rules(folder_path="${folderPath}")` : 'generate_editor_rules(folder_path="<cwd>")';
|
|
8176
|
+
const notice2 = {
|
|
8177
|
+
status: "missing",
|
|
8178
|
+
latest: RULES_VERSION,
|
|
8179
|
+
files_checked: candidates,
|
|
8180
|
+
update_tool: "generate_editor_rules",
|
|
8181
|
+
update_args: {
|
|
8182
|
+
...folderPath ? { folder_path: folderPath } : {},
|
|
8183
|
+
editors: editorKey ? [editorKey] : ["all"]
|
|
8184
|
+
},
|
|
8185
|
+
update_command: updateCommand2
|
|
8186
|
+
};
|
|
8187
|
+
rulesNoticeCache.set(cacheKey, { checkedAt: Date.now(), notice: notice2 });
|
|
8188
|
+
return notice2;
|
|
8189
|
+
}
|
|
8190
|
+
const filesMissingVersion = [];
|
|
8191
|
+
const filesOutdated = [];
|
|
8192
|
+
const versions = [];
|
|
8193
|
+
for (const filePath of existing) {
|
|
8194
|
+
try {
|
|
8195
|
+
const content = fs3.readFileSync(filePath, "utf-8");
|
|
8196
|
+
const version = extractRulesVersion(content);
|
|
8197
|
+
if (!version) {
|
|
8198
|
+
filesMissingVersion.push(filePath);
|
|
8199
|
+
continue;
|
|
8200
|
+
}
|
|
8201
|
+
versions.push(version);
|
|
8202
|
+
if (compareVersions2(version, RULES_VERSION) < 0) {
|
|
8203
|
+
filesOutdated.push(filePath);
|
|
8204
|
+
}
|
|
8205
|
+
} catch {
|
|
8206
|
+
filesMissingVersion.push(filePath);
|
|
8207
|
+
}
|
|
8208
|
+
}
|
|
8209
|
+
if (filesOutdated.length === 0 && filesMissingVersion.length === 0) {
|
|
8210
|
+
rulesNoticeCache.set(cacheKey, { checkedAt: Date.now(), notice: null });
|
|
8211
|
+
return null;
|
|
8212
|
+
}
|
|
8213
|
+
const current = versions.sort(compareVersions2).at(-1);
|
|
8214
|
+
const updateCommand = folderPath ? `generate_editor_rules(folder_path="${folderPath}")` : 'generate_editor_rules(folder_path="<cwd>")';
|
|
8215
|
+
const notice = {
|
|
8216
|
+
status: filesOutdated.length > 0 ? "behind" : "unknown",
|
|
8217
|
+
current,
|
|
8218
|
+
latest: RULES_VERSION,
|
|
8219
|
+
files_checked: existing,
|
|
8220
|
+
...filesOutdated.length > 0 ? { files_outdated: filesOutdated } : {},
|
|
8221
|
+
...filesMissingVersion.length > 0 ? { files_missing_version: filesMissingVersion } : {},
|
|
8222
|
+
update_tool: "generate_editor_rules",
|
|
8223
|
+
update_args: {
|
|
8224
|
+
...folderPath ? { folder_path: folderPath } : {},
|
|
8225
|
+
editors: editorKey ? [editorKey] : ["all"]
|
|
8226
|
+
},
|
|
8227
|
+
update_command: updateCommand
|
|
8228
|
+
};
|
|
8229
|
+
rulesNoticeCache.set(cacheKey, { checkedAt: Date.now(), notice });
|
|
8230
|
+
return notice;
|
|
8231
|
+
}
|
|
8232
|
+
var CONTEXTSTREAM_START_MARKER = "<!-- BEGIN ContextStream -->";
|
|
8233
|
+
var CONTEXTSTREAM_END_MARKER = "<!-- END ContextStream -->";
|
|
8234
|
+
var LEGACY_CONTEXTSTREAM_HINTS = [
|
|
8235
|
+
"contextstream integration",
|
|
8236
|
+
"contextstream v0.4",
|
|
8237
|
+
"contextstream v0.3",
|
|
8238
|
+
"contextstream (standard)",
|
|
8239
|
+
"contextstream (consolidated",
|
|
8240
|
+
"contextstream mcp",
|
|
8241
|
+
"contextstream tools"
|
|
8242
|
+
];
|
|
8243
|
+
var LEGACY_CONTEXTSTREAM_ALLOWED_HEADINGS = [
|
|
8244
|
+
"contextstream",
|
|
8245
|
+
"tl;dr",
|
|
8246
|
+
"required every message",
|
|
8247
|
+
"quick reference",
|
|
8248
|
+
"tool catalog",
|
|
8249
|
+
"consolidated domain tools",
|
|
8250
|
+
"standalone tools",
|
|
8251
|
+
"domain tools",
|
|
8252
|
+
"why context_smart",
|
|
8253
|
+
"recommended token budgets",
|
|
8254
|
+
"rules update notices",
|
|
8255
|
+
"preferences & lessons",
|
|
8256
|
+
"index & graph preflight",
|
|
8257
|
+
"search & code intelligence",
|
|
8258
|
+
"distillation",
|
|
8259
|
+
"when to capture",
|
|
8260
|
+
"behavior rules",
|
|
8261
|
+
"plans & tasks",
|
|
8262
|
+
"complete action reference"
|
|
8263
|
+
];
|
|
8264
|
+
function wrapWithMarkers(content) {
|
|
8265
|
+
return `${CONTEXTSTREAM_START_MARKER}
|
|
8266
|
+
${content.trim()}
|
|
8267
|
+
${CONTEXTSTREAM_END_MARKER}`;
|
|
8268
|
+
}
|
|
8269
|
+
function isLegacyContextStreamRules(content) {
|
|
8270
|
+
const lower = content.toLowerCase();
|
|
8271
|
+
if (!lower.includes("contextstream")) return false;
|
|
8272
|
+
if (!LEGACY_CONTEXTSTREAM_HINTS.some((hint) => lower.includes(hint))) return false;
|
|
8273
|
+
const headingRegex = /^#{1,6}\s+(.+)$/gm;
|
|
8274
|
+
let hasHeading = false;
|
|
8275
|
+
let match;
|
|
8276
|
+
while ((match = headingRegex.exec(content)) !== null) {
|
|
8277
|
+
hasHeading = true;
|
|
8278
|
+
const heading = match[1].trim().toLowerCase();
|
|
8279
|
+
const allowed = LEGACY_CONTEXTSTREAM_ALLOWED_HEADINGS.some((prefix) => heading.startsWith(prefix));
|
|
8280
|
+
if (!allowed) return false;
|
|
8281
|
+
}
|
|
8282
|
+
return hasHeading;
|
|
8283
|
+
}
|
|
8284
|
+
async function upsertRuleFile(filePath, content) {
|
|
8285
|
+
await fs3.promises.mkdir(path4.dirname(filePath), { recursive: true });
|
|
8286
|
+
const wrappedContent = wrapWithMarkers(content);
|
|
8287
|
+
let existing = "";
|
|
8288
|
+
try {
|
|
8289
|
+
existing = await fs3.promises.readFile(filePath, "utf8");
|
|
8290
|
+
} catch {
|
|
8291
|
+
}
|
|
8292
|
+
if (!existing) {
|
|
8293
|
+
await fs3.promises.writeFile(filePath, wrappedContent + "\n", "utf8");
|
|
8294
|
+
return "created";
|
|
8295
|
+
}
|
|
8296
|
+
const startIdx = existing.indexOf(CONTEXTSTREAM_START_MARKER);
|
|
8297
|
+
const endIdx = existing.indexOf(CONTEXTSTREAM_END_MARKER);
|
|
8298
|
+
if (startIdx !== -1 && endIdx !== -1 && endIdx > startIdx) {
|
|
8299
|
+
const before = existing.substring(0, startIdx);
|
|
8300
|
+
const after = existing.substring(endIdx + CONTEXTSTREAM_END_MARKER.length);
|
|
8301
|
+
const updated = before.trimEnd() + "\n\n" + wrappedContent + "\n" + after.trimStart();
|
|
8302
|
+
await fs3.promises.writeFile(filePath, updated.trim() + "\n", "utf8");
|
|
8303
|
+
return "updated";
|
|
8304
|
+
}
|
|
8305
|
+
if (isLegacyContextStreamRules(existing)) {
|
|
8306
|
+
await fs3.promises.writeFile(filePath, wrappedContent + "\n", "utf8");
|
|
8307
|
+
return "updated";
|
|
8308
|
+
}
|
|
8309
|
+
const joined = existing.trimEnd() + "\n\n" + wrappedContent + "\n";
|
|
8310
|
+
await fs3.promises.writeFile(filePath, joined, "utf8");
|
|
8311
|
+
return "appended";
|
|
8312
|
+
}
|
|
8313
|
+
async function writeEditorRules(options) {
|
|
8314
|
+
const editors = options.editors && options.editors.length > 0 ? options.editors : getAvailableEditors();
|
|
8315
|
+
const results = [];
|
|
8316
|
+
for (const editor of editors) {
|
|
8317
|
+
const rule = generateRuleContent(editor, {
|
|
8318
|
+
workspaceName: options.workspaceName,
|
|
8319
|
+
workspaceId: options.workspaceId,
|
|
8320
|
+
projectName: options.projectName,
|
|
8321
|
+
additionalRules: options.additionalRules,
|
|
8322
|
+
mode: options.mode
|
|
8323
|
+
});
|
|
8324
|
+
if (!rule) {
|
|
8325
|
+
results.push({ editor, filename: "", status: "unknown editor" });
|
|
8326
|
+
continue;
|
|
8327
|
+
}
|
|
8328
|
+
const filePath = path4.join(options.folderPath, rule.filename);
|
|
8329
|
+
try {
|
|
8330
|
+
const status = await upsertRuleFile(filePath, rule.content);
|
|
8331
|
+
results.push({ editor, filename: rule.filename, status });
|
|
8332
|
+
} catch (err) {
|
|
8333
|
+
results.push({
|
|
8334
|
+
editor,
|
|
8335
|
+
filename: rule.filename,
|
|
8336
|
+
status: `error: ${err.message}`
|
|
8337
|
+
});
|
|
8338
|
+
}
|
|
8339
|
+
}
|
|
8340
|
+
for (const key of rulesNoticeCache.keys()) {
|
|
8341
|
+
if (key.startsWith(`${options.folderPath}|`)) {
|
|
8342
|
+
rulesNoticeCache.delete(key);
|
|
8343
|
+
}
|
|
8344
|
+
}
|
|
8345
|
+
return results;
|
|
8346
|
+
}
|
|
8045
8347
|
var WRITE_VERBS = /* @__PURE__ */ new Set([
|
|
8046
8348
|
"create",
|
|
8047
8349
|
"update",
|
|
@@ -9766,30 +10068,13 @@ Access: Free`,
|
|
|
9766
10068
|
};
|
|
9767
10069
|
fs3.writeFileSync(configPath, JSON.stringify(config, null, 2));
|
|
9768
10070
|
if (input.generate_editor_rules) {
|
|
9769
|
-
|
|
9770
|
-
|
|
9771
|
-
|
|
9772
|
-
|
|
9773
|
-
|
|
9774
|
-
|
|
9775
|
-
|
|
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
|
-
}
|
|
10071
|
+
const ruleResults = await writeEditorRules({
|
|
10072
|
+
folderPath: input.folder_path,
|
|
10073
|
+
editors: getAvailableEditors(),
|
|
10074
|
+
workspaceId,
|
|
10075
|
+
projectName: input.name
|
|
10076
|
+
});
|
|
10077
|
+
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
10078
|
}
|
|
9794
10079
|
} catch (err) {
|
|
9795
10080
|
console.error("[ContextStream] Failed to write project config:", err);
|
|
@@ -10738,6 +11023,25 @@ This does semantic search on the first message. You only need context_smart on s
|
|
|
10738
11023
|
if (sessionManager) {
|
|
10739
11024
|
sessionManager.markInitialized(result);
|
|
10740
11025
|
}
|
|
11026
|
+
const folderPathForRules = input.folder_path || ideRoots[0] || resolveFolderPath(void 0, sessionManager);
|
|
11027
|
+
if (sessionManager && folderPathForRules) {
|
|
11028
|
+
sessionManager.setFolderPath(folderPathForRules);
|
|
11029
|
+
}
|
|
11030
|
+
let rulesNotice = null;
|
|
11031
|
+
if (folderPathForRules || detectedClientInfo?.name) {
|
|
11032
|
+
rulesNotice = getRulesNotice(folderPathForRules, detectedClientInfo?.name);
|
|
11033
|
+
if (rulesNotice) {
|
|
11034
|
+
result.rules_notice = rulesNotice;
|
|
11035
|
+
}
|
|
11036
|
+
}
|
|
11037
|
+
let versionNotice = null;
|
|
11038
|
+
try {
|
|
11039
|
+
versionNotice = await getUpdateNotice();
|
|
11040
|
+
} catch {
|
|
11041
|
+
}
|
|
11042
|
+
if (versionNotice) {
|
|
11043
|
+
result.version_notice = versionNotice;
|
|
11044
|
+
}
|
|
10741
11045
|
const workspaceId = typeof result.workspace_id === "string" ? result.workspace_id : void 0;
|
|
10742
11046
|
if (workspaceId && AUTO_HIDE_INTEGRATIONS) {
|
|
10743
11047
|
try {
|
|
@@ -10809,6 +11113,19 @@ This does semantic search on the first message. You only need context_smart on s
|
|
|
10809
11113
|
} else if (workspaceWarning) {
|
|
10810
11114
|
text = [`Warning: ${workspaceWarning}`, "", formatContent(result)].join("\n");
|
|
10811
11115
|
}
|
|
11116
|
+
const noticeLines = [];
|
|
11117
|
+
if (rulesNotice) {
|
|
11118
|
+
const current = rulesNotice.current ?? "unknown";
|
|
11119
|
+
noticeLines.push(`[RULES_NOTICE] status=${rulesNotice.status} current=${current} latest=${rulesNotice.latest} update="${rulesNotice.update_command}"`);
|
|
11120
|
+
}
|
|
11121
|
+
if (versionNotice?.behind) {
|
|
11122
|
+
noticeLines.push(`[VERSION_NOTICE] current=${versionNotice.current} latest=${versionNotice.latest} upgrade="${versionNotice.upgrade_command}"`);
|
|
11123
|
+
}
|
|
11124
|
+
if (noticeLines.length > 0) {
|
|
11125
|
+
text = `${text}
|
|
11126
|
+
|
|
11127
|
+
${noticeLines.join("\n")}`;
|
|
11128
|
+
}
|
|
10812
11129
|
return { content: [{ type: "text", text }], structuredContent: toStructured(result) };
|
|
10813
11130
|
}
|
|
10814
11131
|
);
|
|
@@ -10898,32 +11215,13 @@ Optionally generates AI editor rules for automatic ContextStream usage.`,
|
|
|
10898
11215
|
const result = await client.associateWorkspace(input);
|
|
10899
11216
|
let rulesGenerated = [];
|
|
10900
11217
|
if (input.generate_editor_rules) {
|
|
10901
|
-
const
|
|
10902
|
-
|
|
10903
|
-
|
|
10904
|
-
|
|
10905
|
-
|
|
10906
|
-
|
|
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
|
-
}
|
|
11218
|
+
const ruleResults = await writeEditorRules({
|
|
11219
|
+
folderPath: input.folder_path,
|
|
11220
|
+
editors: getAvailableEditors(),
|
|
11221
|
+
workspaceName: input.workspace_name,
|
|
11222
|
+
workspaceId: input.workspace_id
|
|
11223
|
+
});
|
|
11224
|
+
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
11225
|
}
|
|
10928
11226
|
const response = {
|
|
10929
11227
|
...result,
|
|
@@ -11003,31 +11301,13 @@ Behavior:
|
|
|
11003
11301
|
});
|
|
11004
11302
|
let rulesGenerated = [];
|
|
11005
11303
|
if (input.generate_editor_rules) {
|
|
11006
|
-
const
|
|
11007
|
-
|
|
11008
|
-
|
|
11009
|
-
|
|
11010
|
-
|
|
11011
|
-
|
|
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
|
-
}
|
|
11304
|
+
const ruleResults = await writeEditorRules({
|
|
11305
|
+
folderPath,
|
|
11306
|
+
editors: getAvailableEditors(),
|
|
11307
|
+
workspaceName: newWorkspace.name || input.workspace_name,
|
|
11308
|
+
workspaceId: newWorkspace.id
|
|
11309
|
+
});
|
|
11310
|
+
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
11311
|
}
|
|
11032
11312
|
const session = await client.initSession(
|
|
11033
11313
|
{
|
|
@@ -11432,7 +11712,7 @@ Example: "What were the auth decisions?" or "What are my TypeScript preferences?
|
|
|
11432
11712
|
These rules instruct the AI to automatically use ContextStream for memory and context.
|
|
11433
11713
|
Supported editors: ${getAvailableEditors().join(", ")}`,
|
|
11434
11714
|
inputSchema: external_exports.object({
|
|
11435
|
-
folder_path: external_exports.string().describe("Absolute path to the project folder"),
|
|
11715
|
+
folder_path: external_exports.string().optional().describe("Absolute path to the project folder (defaults to IDE root/cwd)"),
|
|
11436
11716
|
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
11717
|
workspace_name: external_exports.string().optional().describe("Workspace name to include in rules"),
|
|
11438
11718
|
workspace_id: external_exports.string().uuid().optional().describe("Workspace ID to include in rules"),
|
|
@@ -11443,58 +11723,48 @@ Supported editors: ${getAvailableEditors().join(", ")}`,
|
|
|
11443
11723
|
})
|
|
11444
11724
|
},
|
|
11445
11725
|
async (input) => {
|
|
11446
|
-
const
|
|
11447
|
-
|
|
11726
|
+
const folderPath = resolveFolderPath(input.folder_path, sessionManager);
|
|
11727
|
+
if (!folderPath) {
|
|
11728
|
+
return errorResult("Error: folder_path is required. Provide folder_path or run from a project directory.");
|
|
11729
|
+
}
|
|
11448
11730
|
const editors = input.editors?.includes("all") || !input.editors ? getAvailableEditors() : input.editors.filter((e) => e !== "all");
|
|
11449
11731
|
const results = [];
|
|
11450
|
-
|
|
11451
|
-
const
|
|
11452
|
-
|
|
11453
|
-
|
|
11454
|
-
|
|
11455
|
-
|
|
11456
|
-
|
|
11457
|
-
|
|
11458
|
-
|
|
11459
|
-
|
|
11460
|
-
|
|
11461
|
-
|
|
11462
|
-
|
|
11463
|
-
if (input.dry_run) {
|
|
11732
|
+
if (input.dry_run) {
|
|
11733
|
+
for (const editor of editors) {
|
|
11734
|
+
const rule = generateRuleContent(editor, {
|
|
11735
|
+
workspaceName: input.workspace_name,
|
|
11736
|
+
workspaceId: input.workspace_id,
|
|
11737
|
+
projectName: input.project_name,
|
|
11738
|
+
additionalRules: input.additional_rules,
|
|
11739
|
+
mode: input.mode
|
|
11740
|
+
});
|
|
11741
|
+
if (!rule) {
|
|
11742
|
+
results.push({ editor, filename: "", status: "unknown editor" });
|
|
11743
|
+
continue;
|
|
11744
|
+
}
|
|
11464
11745
|
results.push({
|
|
11465
11746
|
editor,
|
|
11466
11747
|
filename: rule.filename,
|
|
11467
|
-
status: "dry run - would
|
|
11748
|
+
status: "dry run - would update",
|
|
11468
11749
|
content: rule.content
|
|
11469
11750
|
});
|
|
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
11751
|
}
|
|
11752
|
+
} else {
|
|
11753
|
+
const writeResults = await writeEditorRules({
|
|
11754
|
+
folderPath,
|
|
11755
|
+
editors,
|
|
11756
|
+
workspaceName: input.workspace_name,
|
|
11757
|
+
workspaceId: input.workspace_id,
|
|
11758
|
+
projectName: input.project_name,
|
|
11759
|
+
additionalRules: input.additional_rules,
|
|
11760
|
+
mode: input.mode
|
|
11761
|
+
});
|
|
11762
|
+
results.push(...writeResults);
|
|
11493
11763
|
}
|
|
11494
11764
|
const summary = {
|
|
11495
|
-
folder:
|
|
11765
|
+
folder: folderPath,
|
|
11496
11766
|
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.
|
|
11767
|
+
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
11768
|
};
|
|
11499
11769
|
return { content: [{ type: "text", text: formatContent(summary) }], structuredContent: toStructured(summary) };
|
|
11500
11770
|
}
|
|
@@ -11768,11 +12038,27 @@ This saves ~80% tokens compared to including full chat history.`,
|
|
|
11768
12038
|
const footer = `
|
|
11769
12039
|
---
|
|
11770
12040
|
\u{1F3AF} ${result.sources_used} sources | ~${result.token_estimate} tokens | format: ${result.format}`;
|
|
11771
|
-
const
|
|
11772
|
-
|
|
12041
|
+
const folderPathForRules = resolveFolderPath(void 0, sessionManager);
|
|
12042
|
+
const rulesNotice = getRulesNotice(folderPathForRules, detectedClientInfo?.name);
|
|
12043
|
+
let versionNotice = result.version_notice;
|
|
12044
|
+
if (!versionNotice) {
|
|
12045
|
+
try {
|
|
12046
|
+
versionNotice = await getUpdateNotice();
|
|
12047
|
+
} catch {
|
|
12048
|
+
}
|
|
12049
|
+
}
|
|
12050
|
+
const rulesNoticeLine = rulesNotice ? `
|
|
12051
|
+
[RULES_NOTICE] status=${rulesNotice.status} current=${rulesNotice.current ?? "unknown"} latest=${rulesNotice.latest} update="${rulesNotice.update_command}"` : "";
|
|
12052
|
+
const versionNoticeLine = versionNotice?.behind ? `
|
|
12053
|
+
[VERSION_NOTICE] current=${versionNotice.current} latest=${versionNotice.latest} upgrade="${versionNotice.upgrade_command}"` : "";
|
|
12054
|
+
const enrichedResult = {
|
|
12055
|
+
...result,
|
|
12056
|
+
...rulesNotice ? { rules_notice: rulesNotice } : {},
|
|
12057
|
+
...versionNotice ? { version_notice: versionNotice } : {}
|
|
12058
|
+
};
|
|
11773
12059
|
return {
|
|
11774
|
-
content: [{ type: "text", text: result.context + footer + versionNoticeLine }],
|
|
11775
|
-
structuredContent: toStructured(
|
|
12060
|
+
content: [{ type: "text", text: result.context + footer + rulesNoticeLine + versionNoticeLine }],
|
|
12061
|
+
structuredContent: toStructured(enrichedResult)
|
|
11776
12062
|
};
|
|
11777
12063
|
}
|
|
11778
12064
|
);
|
|
@@ -14827,6 +15113,12 @@ var SessionManager = class {
|
|
|
14827
15113
|
getContext() {
|
|
14828
15114
|
return this.context;
|
|
14829
15115
|
}
|
|
15116
|
+
/**
|
|
15117
|
+
* Get the current folder path (if known)
|
|
15118
|
+
*/
|
|
15119
|
+
getFolderPath() {
|
|
15120
|
+
return this.folderPath;
|
|
15121
|
+
}
|
|
14830
15122
|
/**
|
|
14831
15123
|
* Mark session as manually initialized (e.g., when session_init is called explicitly)
|
|
14832
15124
|
*/
|
|
@@ -14838,6 +15130,10 @@ var SessionManager = class {
|
|
|
14838
15130
|
if (workspaceId || projectId) {
|
|
14839
15131
|
this.client.setDefaults({ workspace_id: workspaceId, project_id: projectId });
|
|
14840
15132
|
}
|
|
15133
|
+
const contextFolderPath = typeof context.folder_path === "string" ? context.folder_path : void 0;
|
|
15134
|
+
if (contextFolderPath) {
|
|
15135
|
+
this.folderPath = contextFolderPath;
|
|
15136
|
+
}
|
|
14841
15137
|
}
|
|
14842
15138
|
/**
|
|
14843
15139
|
* Set the folder path hint (can be passed from tools that know the workspace path)
|
|
@@ -14929,6 +15225,9 @@ var SessionManager = class {
|
|
|
14929
15225
|
if (this.ideRoots.length === 0 && this.folderPath) {
|
|
14930
15226
|
this.ideRoots = [this.folderPath];
|
|
14931
15227
|
}
|
|
15228
|
+
if (this.ideRoots.length > 0) {
|
|
15229
|
+
this.folderPath = this.ideRoots[0];
|
|
15230
|
+
}
|
|
14932
15231
|
this.initializationPromise = this._doInitialize();
|
|
14933
15232
|
try {
|
|
14934
15233
|
const result = await this.initializationPromise;
|
|
@@ -15374,25 +15673,25 @@ async function runHttpGateway() {
|
|
|
15374
15673
|
|
|
15375
15674
|
// src/index.ts
|
|
15376
15675
|
import { existsSync as existsSync4, mkdirSync as mkdirSync4, writeFileSync as writeFileSync4 } from "fs";
|
|
15377
|
-
import { homedir as
|
|
15676
|
+
import { homedir as homedir5 } from "os";
|
|
15378
15677
|
import { join as join8 } from "path";
|
|
15379
15678
|
|
|
15380
15679
|
// src/setup.ts
|
|
15381
15680
|
import * as fs5 from "node:fs/promises";
|
|
15382
15681
|
import * as path6 from "node:path";
|
|
15383
|
-
import { homedir as
|
|
15682
|
+
import { homedir as homedir4 } from "node:os";
|
|
15384
15683
|
import { stdin, stdout } from "node:process";
|
|
15385
15684
|
import { createInterface } from "node:readline/promises";
|
|
15386
15685
|
|
|
15387
15686
|
// src/credentials.ts
|
|
15388
15687
|
import * as fs4 from "node:fs/promises";
|
|
15389
15688
|
import * as path5 from "node:path";
|
|
15390
|
-
import { homedir as
|
|
15689
|
+
import { homedir as homedir3 } from "node:os";
|
|
15391
15690
|
function normalizeApiUrl(input) {
|
|
15392
15691
|
return String(input ?? "").trim().replace(/\/+$/, "");
|
|
15393
15692
|
}
|
|
15394
15693
|
function credentialsFilePath() {
|
|
15395
|
-
return path5.join(
|
|
15694
|
+
return path5.join(homedir3(), ".contextstream", "credentials.json");
|
|
15396
15695
|
}
|
|
15397
15696
|
function isRecord(value) {
|
|
15398
15697
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
@@ -15490,34 +15789,78 @@ async function fileExists(filePath) {
|
|
|
15490
15789
|
return false;
|
|
15491
15790
|
}
|
|
15492
15791
|
}
|
|
15493
|
-
var
|
|
15494
|
-
var
|
|
15495
|
-
|
|
15496
|
-
|
|
15792
|
+
var CONTEXTSTREAM_START_MARKER2 = "<!-- BEGIN ContextStream -->";
|
|
15793
|
+
var CONTEXTSTREAM_END_MARKER2 = "<!-- END ContextStream -->";
|
|
15794
|
+
var LEGACY_CONTEXTSTREAM_HINTS2 = [
|
|
15795
|
+
"contextstream integration",
|
|
15796
|
+
"contextstream v0.4",
|
|
15797
|
+
"contextstream v0.3",
|
|
15798
|
+
"contextstream (standard)",
|
|
15799
|
+
"contextstream (consolidated",
|
|
15800
|
+
"contextstream mcp",
|
|
15801
|
+
"contextstream tools"
|
|
15802
|
+
];
|
|
15803
|
+
var LEGACY_CONTEXTSTREAM_ALLOWED_HEADINGS2 = [
|
|
15804
|
+
"contextstream",
|
|
15805
|
+
"tl;dr",
|
|
15806
|
+
"required every message",
|
|
15807
|
+
"quick reference",
|
|
15808
|
+
"tool catalog",
|
|
15809
|
+
"consolidated domain tools",
|
|
15810
|
+
"standalone tools",
|
|
15811
|
+
"domain tools",
|
|
15812
|
+
"why context_smart",
|
|
15813
|
+
"recommended token budgets",
|
|
15814
|
+
"rules update notices",
|
|
15815
|
+
"preferences & lessons",
|
|
15816
|
+
"index & graph preflight",
|
|
15817
|
+
"search & code intelligence",
|
|
15818
|
+
"distillation",
|
|
15819
|
+
"when to capture",
|
|
15820
|
+
"behavior rules",
|
|
15821
|
+
"plans & tasks",
|
|
15822
|
+
"complete action reference"
|
|
15823
|
+
];
|
|
15824
|
+
function wrapWithMarkers2(content) {
|
|
15825
|
+
return `${CONTEXTSTREAM_START_MARKER2}
|
|
15497
15826
|
${content.trim()}
|
|
15498
|
-
${
|
|
15827
|
+
${CONTEXTSTREAM_END_MARKER2}`;
|
|
15828
|
+
}
|
|
15829
|
+
function isLegacyContextStreamRules2(content) {
|
|
15830
|
+
const lower = content.toLowerCase();
|
|
15831
|
+
if (!lower.includes("contextstream")) return false;
|
|
15832
|
+
if (!LEGACY_CONTEXTSTREAM_HINTS2.some((hint) => lower.includes(hint))) return false;
|
|
15833
|
+
const headingRegex = /^#{1,6}\s+(.+)$/gm;
|
|
15834
|
+
let hasHeading = false;
|
|
15835
|
+
let match;
|
|
15836
|
+
while ((match = headingRegex.exec(content)) !== null) {
|
|
15837
|
+
hasHeading = true;
|
|
15838
|
+
const heading = match[1].trim().toLowerCase();
|
|
15839
|
+
const allowed = LEGACY_CONTEXTSTREAM_ALLOWED_HEADINGS2.some((prefix) => heading.startsWith(prefix));
|
|
15840
|
+
if (!allowed) return false;
|
|
15841
|
+
}
|
|
15842
|
+
return hasHeading;
|
|
15499
15843
|
}
|
|
15500
15844
|
async function upsertTextFile(filePath, content, _marker) {
|
|
15501
15845
|
await fs5.mkdir(path6.dirname(filePath), { recursive: true });
|
|
15502
15846
|
const exists = await fileExists(filePath);
|
|
15503
|
-
const wrappedContent =
|
|
15847
|
+
const wrappedContent = wrapWithMarkers2(content);
|
|
15504
15848
|
if (!exists) {
|
|
15505
15849
|
await fs5.writeFile(filePath, wrappedContent + "\n", "utf8");
|
|
15506
15850
|
return "created";
|
|
15507
15851
|
}
|
|
15508
15852
|
const existing = await fs5.readFile(filePath, "utf8").catch(() => "");
|
|
15509
|
-
const startIdx = existing.indexOf(
|
|
15510
|
-
const endIdx = existing.indexOf(
|
|
15853
|
+
const startIdx = existing.indexOf(CONTEXTSTREAM_START_MARKER2);
|
|
15854
|
+
const endIdx = existing.indexOf(CONTEXTSTREAM_END_MARKER2);
|
|
15511
15855
|
if (startIdx !== -1 && endIdx !== -1 && endIdx > startIdx) {
|
|
15512
15856
|
const before = existing.substring(0, startIdx);
|
|
15513
|
-
const after = existing.substring(endIdx +
|
|
15857
|
+
const after = existing.substring(endIdx + CONTEXTSTREAM_END_MARKER2.length);
|
|
15514
15858
|
const updated = before.trimEnd() + "\n\n" + wrappedContent + "\n" + after.trimStart();
|
|
15515
15859
|
await fs5.writeFile(filePath, updated.trim() + "\n", "utf8");
|
|
15516
15860
|
return "updated";
|
|
15517
15861
|
}
|
|
15518
|
-
if (existing
|
|
15519
|
-
|
|
15520
|
-
await fs5.writeFile(filePath, joined2, "utf8");
|
|
15862
|
+
if (isLegacyContextStreamRules2(existing)) {
|
|
15863
|
+
await fs5.writeFile(filePath, wrappedContent + "\n", "utf8");
|
|
15521
15864
|
return "updated";
|
|
15522
15865
|
}
|
|
15523
15866
|
const joined = existing.trimEnd() + "\n\n" + wrappedContent + "\n";
|
|
@@ -15525,7 +15868,7 @@ async function upsertTextFile(filePath, content, _marker) {
|
|
|
15525
15868
|
return "appended";
|
|
15526
15869
|
}
|
|
15527
15870
|
function globalRulesPathForEditor(editor) {
|
|
15528
|
-
const home =
|
|
15871
|
+
const home = homedir4();
|
|
15529
15872
|
switch (editor) {
|
|
15530
15873
|
case "codex":
|
|
15531
15874
|
return path6.join(home, ".codex", "AGENTS.md");
|
|
@@ -15554,7 +15897,7 @@ async function anyPathExists(paths) {
|
|
|
15554
15897
|
return false;
|
|
15555
15898
|
}
|
|
15556
15899
|
async function isCodexInstalled() {
|
|
15557
|
-
const home =
|
|
15900
|
+
const home = homedir4();
|
|
15558
15901
|
const envHome = process.env.CODEX_HOME;
|
|
15559
15902
|
const candidates = [
|
|
15560
15903
|
envHome,
|
|
@@ -15565,7 +15908,7 @@ async function isCodexInstalled() {
|
|
|
15565
15908
|
return anyPathExists(candidates);
|
|
15566
15909
|
}
|
|
15567
15910
|
async function isClaudeInstalled() {
|
|
15568
|
-
const home =
|
|
15911
|
+
const home = homedir4();
|
|
15569
15912
|
const candidates = [
|
|
15570
15913
|
path6.join(home, ".claude"),
|
|
15571
15914
|
path6.join(home, ".config", "claude")
|
|
@@ -15581,7 +15924,7 @@ async function isClaudeInstalled() {
|
|
|
15581
15924
|
return anyPathExists(candidates);
|
|
15582
15925
|
}
|
|
15583
15926
|
async function isWindsurfInstalled() {
|
|
15584
|
-
const home =
|
|
15927
|
+
const home = homedir4();
|
|
15585
15928
|
const candidates = [
|
|
15586
15929
|
path6.join(home, ".codeium"),
|
|
15587
15930
|
path6.join(home, ".codeium", "windsurf"),
|
|
@@ -15600,7 +15943,7 @@ async function isWindsurfInstalled() {
|
|
|
15600
15943
|
return anyPathExists(candidates);
|
|
15601
15944
|
}
|
|
15602
15945
|
async function isClineInstalled() {
|
|
15603
|
-
const home =
|
|
15946
|
+
const home = homedir4();
|
|
15604
15947
|
const candidates = [
|
|
15605
15948
|
path6.join(home, "Documents", "Cline"),
|
|
15606
15949
|
path6.join(home, ".cline"),
|
|
@@ -15609,7 +15952,7 @@ async function isClineInstalled() {
|
|
|
15609
15952
|
return anyPathExists(candidates);
|
|
15610
15953
|
}
|
|
15611
15954
|
async function isKiloInstalled() {
|
|
15612
|
-
const home =
|
|
15955
|
+
const home = homedir4();
|
|
15613
15956
|
const candidates = [
|
|
15614
15957
|
path6.join(home, ".kilocode"),
|
|
15615
15958
|
path6.join(home, ".config", "kilocode")
|
|
@@ -15617,7 +15960,7 @@ async function isKiloInstalled() {
|
|
|
15617
15960
|
return anyPathExists(candidates);
|
|
15618
15961
|
}
|
|
15619
15962
|
async function isRooInstalled() {
|
|
15620
|
-
const home =
|
|
15963
|
+
const home = homedir4();
|
|
15621
15964
|
const candidates = [
|
|
15622
15965
|
path6.join(home, ".roo"),
|
|
15623
15966
|
path6.join(home, ".config", "roo")
|
|
@@ -15625,7 +15968,7 @@ async function isRooInstalled() {
|
|
|
15625
15968
|
return anyPathExists(candidates);
|
|
15626
15969
|
}
|
|
15627
15970
|
async function isAiderInstalled() {
|
|
15628
|
-
const home =
|
|
15971
|
+
const home = homedir4();
|
|
15629
15972
|
const candidates = [
|
|
15630
15973
|
path6.join(home, ".aider.conf.yml"),
|
|
15631
15974
|
path6.join(home, ".config", "aider")
|
|
@@ -15633,7 +15976,7 @@ async function isAiderInstalled() {
|
|
|
15633
15976
|
return anyPathExists(candidates);
|
|
15634
15977
|
}
|
|
15635
15978
|
async function isCursorInstalled() {
|
|
15636
|
-
const home =
|
|
15979
|
+
const home = homedir4();
|
|
15637
15980
|
const candidates = [path6.join(home, ".cursor")];
|
|
15638
15981
|
if (process.platform === "darwin") {
|
|
15639
15982
|
candidates.push("/Applications/Cursor.app");
|
|
@@ -15781,7 +16124,7 @@ async function upsertJsonVsCodeMcpConfig(filePath, server) {
|
|
|
15781
16124
|
return before === after ? "skipped" : "updated";
|
|
15782
16125
|
}
|
|
15783
16126
|
function claudeDesktopConfigPath() {
|
|
15784
|
-
const home =
|
|
16127
|
+
const home = homedir4();
|
|
15785
16128
|
if (process.platform === "darwin") {
|
|
15786
16129
|
return path6.join(home, "Library", "Application Support", "Claude", "claude_desktop_config.json");
|
|
15787
16130
|
}
|
|
@@ -16185,7 +16528,7 @@ Detected plan: ${planLabel} (graph: ${graphTierLabel})`);
|
|
|
16185
16528
|
if (mcpScope === "project" && editor !== "codex") continue;
|
|
16186
16529
|
try {
|
|
16187
16530
|
if (editor === "codex") {
|
|
16188
|
-
const filePath = path6.join(
|
|
16531
|
+
const filePath = path6.join(homedir4(), ".codex", "config.toml");
|
|
16189
16532
|
if (dryRun) {
|
|
16190
16533
|
writeActions.push({ kind: "mcp-config", target: filePath, status: "dry-run" });
|
|
16191
16534
|
console.log(`- ${EDITOR_LABELS[editor]}: would update ${filePath}`);
|
|
@@ -16197,7 +16540,7 @@ Detected plan: ${planLabel} (graph: ${graphTierLabel})`);
|
|
|
16197
16540
|
continue;
|
|
16198
16541
|
}
|
|
16199
16542
|
if (editor === "windsurf") {
|
|
16200
|
-
const filePath = path6.join(
|
|
16543
|
+
const filePath = path6.join(homedir4(), ".codeium", "windsurf", "mcp_config.json");
|
|
16201
16544
|
if (dryRun) {
|
|
16202
16545
|
writeActions.push({ kind: "mcp-config", target: filePath, status: "dry-run" });
|
|
16203
16546
|
console.log(`- ${EDITOR_LABELS[editor]}: would update ${filePath}`);
|
|
@@ -16231,7 +16574,7 @@ Detected plan: ${planLabel} (graph: ${graphTierLabel})`);
|
|
|
16231
16574
|
continue;
|
|
16232
16575
|
}
|
|
16233
16576
|
if (editor === "cursor") {
|
|
16234
|
-
const filePath = path6.join(
|
|
16577
|
+
const filePath = path6.join(homedir4(), ".cursor", "mcp.json");
|
|
16235
16578
|
if (dryRun) {
|
|
16236
16579
|
writeActions.push({ kind: "mcp-config", target: filePath, status: "dry-run" });
|
|
16237
16580
|
console.log(`- ${EDITOR_LABELS[editor]}: would update ${filePath}`);
|
|
@@ -16458,7 +16801,7 @@ Applying to ${projects.length} project(s)...`);
|
|
|
16458
16801
|
// src/index.ts
|
|
16459
16802
|
var ENABLE_PROMPTS2 = (process.env.CONTEXTSTREAM_ENABLE_PROMPTS || "true").toLowerCase() !== "false";
|
|
16460
16803
|
function showFirstRunMessage() {
|
|
16461
|
-
const configDir = join8(
|
|
16804
|
+
const configDir = join8(homedir5(), ".contextstream");
|
|
16462
16805
|
const starShownFile = join8(configDir, ".star-shown");
|
|
16463
16806
|
if (existsSync4(starShownFile)) {
|
|
16464
16807
|
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.19",
|
|
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",
|