@sdsrs/code-graph 0.8.4 → 0.9.1
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/bin/cli.js +11 -0
- package/claude-plugin/.claude-plugin/plugin.json +1 -1
- package/claude-plugin/scripts/adopt.js +46 -2
- package/claude-plugin/scripts/adopt.test.js +135 -0
- package/claude-plugin/scripts/session-init.js +29 -4
- package/claude-plugin/scripts/session-init.test.js +25 -1
- package/claude-plugin/templates/plugin_code_graph_mcp.md +12 -6
- package/package.json +6 -6
package/bin/cli.js
CHANGED
|
@@ -7,6 +7,17 @@ const path = require("path");
|
|
|
7
7
|
// and detect dev mode from bin/ → repo root (one level up)
|
|
8
8
|
process.env._FIND_BINARY_ROOT = path.resolve(__dirname, "..");
|
|
9
9
|
|
|
10
|
+
// Intercept adopt / unadopt before forwarding — they're node-only concerns
|
|
11
|
+
// (write to ~/.claude/projects/<slug>/memory/) and have no Rust counterpart.
|
|
12
|
+
// Lets `code-graph-mcp adopt` / `unadopt` work uniformly across plugin / npm / npx.
|
|
13
|
+
const sub = process.argv[2];
|
|
14
|
+
if (sub === "adopt" || sub === "unadopt") {
|
|
15
|
+
const { adopt, unadopt, formatResult } = require("../claude-plugin/scripts/adopt");
|
|
16
|
+
const result = sub === "unadopt" ? unadopt() : adopt();
|
|
17
|
+
process.stdout.write(formatResult(sub, result) + "\n");
|
|
18
|
+
process.exit(result.ok === false ? 1 : 0);
|
|
19
|
+
}
|
|
20
|
+
|
|
10
21
|
const { findBinary } = require("../claude-plugin/scripts/find-binary");
|
|
11
22
|
|
|
12
23
|
const binary = findBinary();
|
|
@@ -9,7 +9,11 @@ const os = require('os');
|
|
|
9
9
|
|
|
10
10
|
const SENTINEL_BEGIN = '<!-- code-graph-mcp:begin v1 -->';
|
|
11
11
|
const SENTINEL_END = '<!-- code-graph-mcp:end -->';
|
|
12
|
-
const INDEX_LINE =
|
|
12
|
+
const INDEX_LINE = [
|
|
13
|
+
'- [code-graph-mcp](plugin_code_graph_mcp.md) — 代码理解 12 工具(替代 Grep/Read 多步):',
|
|
14
|
+
' - 问"谁调/改动/模块/概念/HTTP/相似" → `get_call_graph`/`impact_analysis`/`module_overview`/`semantic_code_search`/`trace_http_chain`/`find_similar_code`',
|
|
15
|
+
' - 问"返回型/引用/死码/依赖/架构/看签名" → `ast_search`/`find_references`/`find_dead_code`/`dependency_graph`/`project_map`/`get_ast_node`',
|
|
16
|
+
].join('\n');
|
|
13
17
|
const TEMPLATE_PATH = path.resolve(__dirname, '..', 'templates', 'plugin_code_graph_mcp.md');
|
|
14
18
|
const TARGET_NAME = 'plugin_code_graph_mcp.md';
|
|
15
19
|
|
|
@@ -87,6 +91,43 @@ function adopt({ cwd, home, templatePath } = {}) {
|
|
|
87
91
|
return { ok: true, target, indexPath, indexed: true, healed };
|
|
88
92
|
}
|
|
89
93
|
|
|
94
|
+
// v0.9.0 — "已 adopt" 判定:template 文件在 + MEMORY.md 内有我们的 sentinel 块。
|
|
95
|
+
// 用在 maybeAutoAdopt 里做幂等门,也用在 session-init 里推导 quietHooks。
|
|
96
|
+
function isAdopted({ cwd, home } = {}) {
|
|
97
|
+
const dir = memoryDir(cwd, home);
|
|
98
|
+
const target = path.join(dir, TARGET_NAME);
|
|
99
|
+
const indexPath = path.join(dir, 'MEMORY.md');
|
|
100
|
+
if (!fs.existsSync(target) || !fs.existsSync(indexPath)) return false;
|
|
101
|
+
const index = fs.readFileSync(indexPath, 'utf8');
|
|
102
|
+
return index.includes(SENTINEL_BEGIN) && index.includes(SENTINEL_END);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// 检测脚本是否从 Claude Code 插件 cache 运行。
|
|
106
|
+
// 走 __dirname 而非 CLAUDE_PLUGIN_ROOT — 后者在多插件共存时会互相污染
|
|
107
|
+
// (见 feedback_plugin_env_isolation.md)。
|
|
108
|
+
function isPluginModeInstall(scriptPath = __dirname) {
|
|
109
|
+
const sep = path.sep;
|
|
110
|
+
return scriptPath.includes(`${sep}.claude${sep}plugins${sep}`);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// C' 上下文感知默认(v0.9.0):插件模式下首次 SessionStart 静默 adopt。
|
|
114
|
+
// /plugin install 本身已构成知情同意;npm / npx / 裸 checkout 保持 opt-in。
|
|
115
|
+
// 退出:CODE_GRAPH_NO_AUTO_ADOPT=1。
|
|
116
|
+
function maybeAutoAdopt({ cwd, home, env, scriptPath } = {}) {
|
|
117
|
+
env = env || process.env;
|
|
118
|
+
if (env.CODE_GRAPH_NO_AUTO_ADOPT === '1') {
|
|
119
|
+
return { attempted: false, reason: 'opted-out' };
|
|
120
|
+
}
|
|
121
|
+
if (!isPluginModeInstall(scriptPath || __dirname)) {
|
|
122
|
+
return { attempted: false, reason: 'not-plugin-mode' };
|
|
123
|
+
}
|
|
124
|
+
if (isAdopted({ cwd, home })) {
|
|
125
|
+
return { attempted: false, reason: 'already-adopted' };
|
|
126
|
+
}
|
|
127
|
+
const result = adopt({ cwd, home });
|
|
128
|
+
return { attempted: true, reason: 'adopted', result };
|
|
129
|
+
}
|
|
130
|
+
|
|
90
131
|
function unadopt({ cwd, home } = {}) {
|
|
91
132
|
const blocked = platformGuard();
|
|
92
133
|
if (blocked) return blocked;
|
|
@@ -132,7 +173,9 @@ function formatResult(action, result) {
|
|
|
132
173
|
if (result.healed) lines.push(`[code-graph] Healed malformed sentinel block → ${result.indexPath}`);
|
|
133
174
|
else if (result.indexed) lines.push(`[code-graph] Indexed → ${result.indexPath}`);
|
|
134
175
|
else lines.push(`[code-graph] Index already up-to-date — no write`);
|
|
135
|
-
|
|
176
|
+
// v0.9.0: adoption auto-implies quietHooks; no env var needed for the common case.
|
|
177
|
+
lines.push('[code-graph] Active — quietHooks auto-enabled via adopted state.');
|
|
178
|
+
lines.push('[code-graph] Force inject: CODE_GRAPH_QUIET_HOOKS=0 Force silent: =1');
|
|
136
179
|
return lines.join('\n');
|
|
137
180
|
}
|
|
138
181
|
if (action === 'unadopt') {
|
|
@@ -154,5 +197,6 @@ if (require.main === module) {
|
|
|
154
197
|
|
|
155
198
|
module.exports = {
|
|
156
199
|
adopt, unadopt, memoryDir, formatResult, stripSentinelBlock,
|
|
200
|
+
isAdopted, isPluginModeInstall, maybeAutoAdopt,
|
|
157
201
|
SENTINEL_BEGIN, SENTINEL_END, INDEX_LINE, TEMPLATE_PATH, TARGET_NAME,
|
|
158
202
|
};
|
|
@@ -6,6 +6,7 @@ const path = require('path');
|
|
|
6
6
|
const os = require('os');
|
|
7
7
|
const {
|
|
8
8
|
adopt, unadopt, memoryDir, stripSentinelBlock,
|
|
9
|
+
isAdopted, isPluginModeInstall, maybeAutoAdopt,
|
|
9
10
|
SENTINEL_BEGIN, SENTINEL_END, INDEX_LINE, TEMPLATE_PATH,
|
|
10
11
|
} = require('./adopt');
|
|
11
12
|
|
|
@@ -213,6 +214,140 @@ test('unadopt heals malformed sentinel (orphan BEGIN)', () => {
|
|
|
213
214
|
} finally { sb.cleanup(); }
|
|
214
215
|
});
|
|
215
216
|
|
|
217
|
+
// ──────────────────────────────────────────────────────────────────────────
|
|
218
|
+
// v0.9.0 — C' context-aware auto-adopt
|
|
219
|
+
// ──────────────────────────────────────────────────────────────────────────
|
|
220
|
+
|
|
221
|
+
test('isAdopted returns false on fresh project (no files)', () => {
|
|
222
|
+
const sb = makeSandbox();
|
|
223
|
+
try {
|
|
224
|
+
assert.strictEqual(isAdopted({ cwd: sb.cwd, home: sb.home }), false);
|
|
225
|
+
} finally { sb.cleanup(); }
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
test('isAdopted returns true after adopt()', () => {
|
|
229
|
+
const sb = makeSandbox();
|
|
230
|
+
try {
|
|
231
|
+
adopt({ cwd: sb.cwd, home: sb.home });
|
|
232
|
+
assert.strictEqual(isAdopted({ cwd: sb.cwd, home: sb.home }), true);
|
|
233
|
+
} finally { sb.cleanup(); }
|
|
234
|
+
});
|
|
235
|
+
|
|
236
|
+
test('isAdopted returns false after unadopt()', () => {
|
|
237
|
+
const sb = makeSandbox();
|
|
238
|
+
try {
|
|
239
|
+
adopt({ cwd: sb.cwd, home: sb.home });
|
|
240
|
+
unadopt({ cwd: sb.cwd, home: sb.home });
|
|
241
|
+
assert.strictEqual(isAdopted({ cwd: sb.cwd, home: sb.home }), false);
|
|
242
|
+
} finally { sb.cleanup(); }
|
|
243
|
+
});
|
|
244
|
+
|
|
245
|
+
test('isAdopted returns false when target file exists but index has no sentinel', () => {
|
|
246
|
+
const sb = makeSandbox();
|
|
247
|
+
try {
|
|
248
|
+
const indexPath = path.join(sb.dir, 'MEMORY.md');
|
|
249
|
+
fs.writeFileSync(indexPath, '# Memory Index\n- [foo.md](foo.md) — unrelated\n');
|
|
250
|
+
fs.writeFileSync(path.join(sb.dir, 'plugin_code_graph_mcp.md'), 'stale copy');
|
|
251
|
+
assert.strictEqual(isAdopted({ cwd: sb.cwd, home: sb.home }), false);
|
|
252
|
+
} finally { sb.cleanup(); }
|
|
253
|
+
});
|
|
254
|
+
|
|
255
|
+
test('isPluginModeInstall recognizes ~/.claude/plugins/... paths', () => {
|
|
256
|
+
const pluginPath = '/home/user/.claude/plugins/cache/code-graph-mcp@0.9.0/scripts';
|
|
257
|
+
assert.strictEqual(isPluginModeInstall(pluginPath), true);
|
|
258
|
+
});
|
|
259
|
+
|
|
260
|
+
test('isPluginModeInstall rejects npm global install paths', () => {
|
|
261
|
+
const npmPath = '/usr/local/lib/node_modules/@sdsrs/code-graph/claude-plugin/scripts';
|
|
262
|
+
assert.strictEqual(isPluginModeInstall(npmPath), false);
|
|
263
|
+
});
|
|
264
|
+
|
|
265
|
+
test('isPluginModeInstall rejects dev-checkout paths', () => {
|
|
266
|
+
const devPath = '/mnt/data_ssd/dev/projects/code-graph-mcp/claude-plugin/scripts';
|
|
267
|
+
assert.strictEqual(isPluginModeInstall(devPath), false);
|
|
268
|
+
});
|
|
269
|
+
|
|
270
|
+
test('isPluginModeInstall rejects npx cache paths', () => {
|
|
271
|
+
const npxPath = '/tmp/npx-abc123/node_modules/@sdsrs/code-graph/claude-plugin/scripts';
|
|
272
|
+
assert.strictEqual(isPluginModeInstall(npxPath), false);
|
|
273
|
+
});
|
|
274
|
+
|
|
275
|
+
test('maybeAutoAdopt skips when CODE_GRAPH_NO_AUTO_ADOPT=1', () => {
|
|
276
|
+
const sb = makeSandbox();
|
|
277
|
+
try {
|
|
278
|
+
const res = maybeAutoAdopt({
|
|
279
|
+
cwd: sb.cwd, home: sb.home,
|
|
280
|
+
scriptPath: '/home/u/.claude/plugins/cache/code-graph-mcp/scripts',
|
|
281
|
+
env: { CODE_GRAPH_NO_AUTO_ADOPT: '1' },
|
|
282
|
+
});
|
|
283
|
+
assert.strictEqual(res.attempted, false);
|
|
284
|
+
assert.strictEqual(res.reason, 'opted-out');
|
|
285
|
+
assert.strictEqual(isAdopted({ cwd: sb.cwd, home: sb.home }), false);
|
|
286
|
+
} finally { sb.cleanup(); }
|
|
287
|
+
});
|
|
288
|
+
|
|
289
|
+
test('maybeAutoAdopt skips when not plugin-mode (npm install)', () => {
|
|
290
|
+
const sb = makeSandbox();
|
|
291
|
+
try {
|
|
292
|
+
const res = maybeAutoAdopt({
|
|
293
|
+
cwd: sb.cwd, home: sb.home,
|
|
294
|
+
scriptPath: '/usr/local/lib/node_modules/@sdsrs/code-graph/claude-plugin/scripts',
|
|
295
|
+
env: {},
|
|
296
|
+
});
|
|
297
|
+
assert.strictEqual(res.attempted, false);
|
|
298
|
+
assert.strictEqual(res.reason, 'not-plugin-mode');
|
|
299
|
+
assert.strictEqual(isAdopted({ cwd: sb.cwd, home: sb.home }), false);
|
|
300
|
+
} finally { sb.cleanup(); }
|
|
301
|
+
});
|
|
302
|
+
|
|
303
|
+
test('maybeAutoAdopt skips when already adopted (idempotent)', () => {
|
|
304
|
+
const sb = makeSandbox();
|
|
305
|
+
try {
|
|
306
|
+
adopt({ cwd: sb.cwd, home: sb.home });
|
|
307
|
+
const res = maybeAutoAdopt({
|
|
308
|
+
cwd: sb.cwd, home: sb.home,
|
|
309
|
+
scriptPath: '/home/u/.claude/plugins/cache/code-graph-mcp/scripts',
|
|
310
|
+
env: {},
|
|
311
|
+
});
|
|
312
|
+
assert.strictEqual(res.attempted, false);
|
|
313
|
+
assert.strictEqual(res.reason, 'already-adopted');
|
|
314
|
+
} finally { sb.cleanup(); }
|
|
315
|
+
});
|
|
316
|
+
|
|
317
|
+
test('maybeAutoAdopt runs adopt when plugin-mode + unadopted + no opt-out', () => {
|
|
318
|
+
const sb = makeSandbox();
|
|
319
|
+
try {
|
|
320
|
+
const res = maybeAutoAdopt({
|
|
321
|
+
cwd: sb.cwd, home: sb.home,
|
|
322
|
+
scriptPath: '/home/u/.claude/plugins/cache/code-graph-mcp/scripts',
|
|
323
|
+
env: {},
|
|
324
|
+
});
|
|
325
|
+
assert.strictEqual(res.attempted, true);
|
|
326
|
+
assert.strictEqual(res.result.ok, true);
|
|
327
|
+
assert.strictEqual(res.result.indexed, true);
|
|
328
|
+
assert.strictEqual(isAdopted({ cwd: sb.cwd, home: sb.home }), true);
|
|
329
|
+
} finally { sb.cleanup(); }
|
|
330
|
+
});
|
|
331
|
+
|
|
332
|
+
test('maybeAutoAdopt returns no-memory-dir when project memory missing', () => {
|
|
333
|
+
const home = fs.mkdtempSync(path.join(os.tmpdir(), 'cg-adopt-home-'));
|
|
334
|
+
const cwd = fs.mkdtempSync(path.join(os.tmpdir(), 'cg-adopt-cwd-'));
|
|
335
|
+
try {
|
|
336
|
+
const res = maybeAutoAdopt({
|
|
337
|
+
cwd, home,
|
|
338
|
+
scriptPath: '/home/u/.claude/plugins/cache/code-graph-mcp/scripts',
|
|
339
|
+
env: {},
|
|
340
|
+
});
|
|
341
|
+
// Plugin-mode + not adopted + no opt-out → attempt runs, but adopt() fails gracefully
|
|
342
|
+
assert.strictEqual(res.attempted, true);
|
|
343
|
+
assert.strictEqual(res.result.ok, false);
|
|
344
|
+
assert.strictEqual(res.result.reason, 'no-memory-dir');
|
|
345
|
+
} finally {
|
|
346
|
+
fs.rmSync(home, { recursive: true, force: true });
|
|
347
|
+
fs.rmSync(cwd, { recursive: true, force: true });
|
|
348
|
+
}
|
|
349
|
+
});
|
|
350
|
+
|
|
216
351
|
test('Windows platform is rejected with clear reason', { skip: process.platform === 'win32' }, () => {
|
|
217
352
|
const orig = process.platform;
|
|
218
353
|
Object.defineProperty(process, 'platform', { value: 'win32', configurable: true });
|
|
@@ -9,6 +9,16 @@ const {
|
|
|
9
9
|
cleanupDisabledStatusline, isPluginInactive, readJson, CACHE_DIR,
|
|
10
10
|
} = require('./lifecycle');
|
|
11
11
|
const { readBinaryVersion, isDevMode, getNewestMtime } = require('./version-utils');
|
|
12
|
+
const { maybeAutoAdopt, isAdopted } = require('./adopt');
|
|
13
|
+
|
|
14
|
+
// v0.9.0 — quietHooks 推导:显式 env override > adopted 状态。
|
|
15
|
+
// CODE_GRAPH_QUIET_HOOKS='0' 强制 noisy;'1' 强制 quiet;未设 → 跟随 adopted。
|
|
16
|
+
function computeQuietHooks({ adopted, env = {} } = {}) {
|
|
17
|
+
const envQuiet = env.CODE_GRAPH_QUIET_HOOKS;
|
|
18
|
+
if (envQuiet === '0') return false;
|
|
19
|
+
if (envQuiet === '1') return true;
|
|
20
|
+
return !!adopted;
|
|
21
|
+
}
|
|
12
22
|
|
|
13
23
|
function launchBackgroundAutoUpdate(spawnFn = spawn, env = process.env) {
|
|
14
24
|
try {
|
|
@@ -247,9 +257,23 @@ function runSessionInit() {
|
|
|
247
257
|
|
|
248
258
|
const autoUpdateLaunched = launchBackgroundAutoUpdate();
|
|
249
259
|
const indexFreshness = binaryCheck.available ? ensureIndexFresh() : 'skipped';
|
|
250
|
-
|
|
251
|
-
//
|
|
252
|
-
|
|
260
|
+
|
|
261
|
+
// v0.9.0 C' 上下文感知默认:插件模式下首次 SessionStart 自动 adopt。
|
|
262
|
+
// 仅一次 stderr 提示(采纳成功时),让用户知道发生了什么 + 如何回退。
|
|
263
|
+
const autoAdopt = maybeAutoAdopt({ scriptPath: __dirname });
|
|
264
|
+
if (autoAdopt.attempted && autoAdopt.result && autoAdopt.result.ok) {
|
|
265
|
+
process.stderr.write(
|
|
266
|
+
'[code-graph] Auto-adopted into project MEMORY.md (plugin install → knowing consent).\n' +
|
|
267
|
+
' Opt out: CODE_GRAPH_NO_AUTO_ADOPT=1 in ~/.claude/settings.json env\n' +
|
|
268
|
+
' Reverse: code-graph-mcp unadopt\n'
|
|
269
|
+
);
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
// quietHooks: adopted → quiet by default (rely on MEMORY.md pointer + on-demand
|
|
273
|
+
// project_map tool); env '1'/'0' overrides for explicit control.
|
|
274
|
+
const adopted = isAdopted();
|
|
275
|
+
const quietHooks = computeQuietHooks({ adopted, env: process.env });
|
|
276
|
+
|
|
253
277
|
const mapInjected = binaryCheck.available && !quietHooks ? injectProjectMap() : false;
|
|
254
278
|
const consistencyIssues = binaryCheck.available
|
|
255
279
|
? consistencyCheck(binaryCheck.binary)
|
|
@@ -257,7 +281,7 @@ function runSessionInit() {
|
|
|
257
281
|
return {
|
|
258
282
|
inactive: false, lifecycle,
|
|
259
283
|
autoUpdateLaunched, indexFreshness, mapInjected, binaryCheck, consistencyIssues,
|
|
260
|
-
quietHooks,
|
|
284
|
+
quietHooks, adopted, autoAdopted: autoAdopt.attempted,
|
|
261
285
|
};
|
|
262
286
|
}
|
|
263
287
|
|
|
@@ -298,6 +322,7 @@ module.exports = {
|
|
|
298
322
|
verifyBinary,
|
|
299
323
|
consistencyCheck,
|
|
300
324
|
runSessionInit,
|
|
325
|
+
computeQuietHooks,
|
|
301
326
|
};
|
|
302
327
|
|
|
303
328
|
if (require.main === module) {
|
|
@@ -4,7 +4,7 @@ const assert = require('node:assert/strict');
|
|
|
4
4
|
const fs = require('fs');
|
|
5
5
|
const path = require('path');
|
|
6
6
|
|
|
7
|
-
const { launchBackgroundAutoUpdate, syncLifecycleConfig, ensureIndexFresh, verifyBinary } = require('./session-init');
|
|
7
|
+
const { launchBackgroundAutoUpdate, syncLifecycleConfig, ensureIndexFresh, verifyBinary, computeQuietHooks } = require('./session-init');
|
|
8
8
|
|
|
9
9
|
test('syncLifecycleConfig is exported as a callable helper', () => {
|
|
10
10
|
assert.equal(typeof syncLifecycleConfig, 'function');
|
|
@@ -83,6 +83,30 @@ test('consistencyCheck returns empty array when binary version matches plugin',
|
|
|
83
83
|
assert.ok(Array.isArray(result));
|
|
84
84
|
});
|
|
85
85
|
|
|
86
|
+
// ──────────────────────────────────────────────────────────────────────────
|
|
87
|
+
// v0.9.0 — quietHooks inference from adopted state
|
|
88
|
+
// ──────────────────────────────────────────────────────────────────────────
|
|
89
|
+
|
|
90
|
+
test('computeQuietHooks: env "0" forces noisy regardless of adoption', () => {
|
|
91
|
+
assert.equal(computeQuietHooks({ adopted: true, env: { CODE_GRAPH_QUIET_HOOKS: '0' } }), false);
|
|
92
|
+
assert.equal(computeQuietHooks({ adopted: false, env: { CODE_GRAPH_QUIET_HOOKS: '0' } }), false);
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
test('computeQuietHooks: env "1" forces quiet regardless of adoption', () => {
|
|
96
|
+
assert.equal(computeQuietHooks({ adopted: true, env: { CODE_GRAPH_QUIET_HOOKS: '1' } }), true);
|
|
97
|
+
assert.equal(computeQuietHooks({ adopted: false, env: { CODE_GRAPH_QUIET_HOOKS: '1' } }), true);
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
test('computeQuietHooks: env unset → follows adopted state', () => {
|
|
101
|
+
assert.equal(computeQuietHooks({ adopted: true, env: {} }), true);
|
|
102
|
+
assert.equal(computeQuietHooks({ adopted: false, env: {} }), false);
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
test('computeQuietHooks: env unset, no env arg → follows adopted state', () => {
|
|
106
|
+
assert.equal(computeQuietHooks({ adopted: true }), true);
|
|
107
|
+
assert.equal(computeQuietHooks({ adopted: false }), false);
|
|
108
|
+
});
|
|
109
|
+
|
|
86
110
|
test('consistencyCheck returns version-mismatch when versions differ', (t) => {
|
|
87
111
|
const os = require('os');
|
|
88
112
|
const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'cc-'));
|
|
@@ -6,7 +6,11 @@ type: reference
|
|
|
6
6
|
# code-graph-mcp 插件契约
|
|
7
7
|
|
|
8
8
|
> Invited-memory 模式:MCP `instructions` 仅留指针,决策细则集中在此。
|
|
9
|
-
>
|
|
9
|
+
>
|
|
10
|
+
> **v0.9.0 起**:插件(`/plugin install`)模式下首次 SessionStart 自动 adopt,
|
|
11
|
+
> 本文件自动写入,自动切换 quietHooks(跳过每次 project_map 注入)。
|
|
12
|
+
> 退出:`CODE_GRAPH_NO_AUTO_ADOPT=1` 阻止,`code-graph-mcp unadopt` 回退。
|
|
13
|
+
> 手动强控:`CODE_GRAPH_QUIET_HOOKS=0` 强制注入 / `=1` 强制静默(覆盖 adoption 推导)。
|
|
10
14
|
|
|
11
15
|
## 何时调用 MCP/CLI(替代多步 Grep/Read)
|
|
12
16
|
|
|
@@ -27,9 +31,9 @@ type: reference
|
|
|
27
31
|
|
|
28
32
|
## 不要替代
|
|
29
33
|
|
|
30
|
-
-
|
|
31
|
-
-
|
|
32
|
-
- 即将编辑的具体文件 →
|
|
34
|
+
- 非代码文件(README/JSON/log) → 用内置 `Grep`
|
|
35
|
+
- 代码里查常量/函数名/字符串首选 `code-graph-mcp grep "pattern" [path]`(每个命中带 containing function/module 上下文,结构化);只做纯文本匹配且不关心上下文时用内置 `Grep`
|
|
36
|
+
- 即将编辑的具体文件 → 用 `Read`(`overview <file>` 看概览,`show SYMBOL` 看某符号)
|
|
33
37
|
|
|
34
38
|
## 工作流惯例
|
|
35
39
|
|
|
@@ -65,6 +69,8 @@ code-graph-mcp health-check # 索引健康
|
|
|
65
69
|
- `impact` 在 `--change-type signature` 时返回最严格的破坏面
|
|
66
70
|
- 索引陈旧 → SessionStart 自带 `ensureIndexFresh`;手动跑 `incremental-index`
|
|
67
71
|
|
|
68
|
-
## 卸载
|
|
72
|
+
## 卸载 / 回退
|
|
69
73
|
|
|
70
|
-
`code-graph-mcp unadopt` 精确移除 sentinel 段 +
|
|
74
|
+
- `code-graph-mcp unadopt` — 精确移除 sentinel 段 + 本文件,quietHooks 自动回到 false(下次 SessionStart 恢复 project_map 注入)。
|
|
75
|
+
- `CODE_GRAPH_NO_AUTO_ADOPT=1`(`~/.claude/settings.json` env) — 阻止未来自动 adopt,不影响已 adopted 状态。
|
|
76
|
+
- `CODE_GRAPH_QUIET_HOOKS=0` — 强制恢复 project_map 注入(即使已 adopted)。
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sdsrs/code-graph",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.1",
|
|
4
4
|
"description": "MCP server that indexes codebases into an AST knowledge graph with semantic search, call graph traversal, and HTTP route tracing",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -34,10 +34,10 @@
|
|
|
34
34
|
"node": ">=16"
|
|
35
35
|
},
|
|
36
36
|
"optionalDependencies": {
|
|
37
|
-
"@sdsrs/code-graph-linux-x64": "0.
|
|
38
|
-
"@sdsrs/code-graph-linux-arm64": "0.
|
|
39
|
-
"@sdsrs/code-graph-darwin-x64": "0.
|
|
40
|
-
"@sdsrs/code-graph-darwin-arm64": "0.
|
|
41
|
-
"@sdsrs/code-graph-win32-x64": "0.
|
|
37
|
+
"@sdsrs/code-graph-linux-x64": "0.9.1",
|
|
38
|
+
"@sdsrs/code-graph-linux-arm64": "0.9.1",
|
|
39
|
+
"@sdsrs/code-graph-darwin-x64": "0.9.1",
|
|
40
|
+
"@sdsrs/code-graph-darwin-arm64": "0.9.1",
|
|
41
|
+
"@sdsrs/code-graph-win32-x64": "0.9.1"
|
|
42
42
|
}
|
|
43
43
|
}
|