context-mode 1.0.146 → 1.0.148
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/.claude-plugin/marketplace.json +2 -2
- package/.claude-plugin/plugin.json +2 -2
- package/.codex-plugin/plugin.json +1 -1
- package/.openclaw-plugin/openclaw.plugin.json +1 -1
- package/.openclaw-plugin/package.json +1 -1
- package/README.md +26 -23
- package/bin/statusline.mjs +22 -9
- package/build/adapters/base.d.ts +9 -4
- package/build/adapters/base.js +16 -7
- package/build/adapters/codex/index.d.ts +8 -1
- package/build/adapters/codex/index.js +43 -6
- package/build/adapters/openclaw/index.d.ts +11 -2
- package/build/adapters/openclaw/index.js +12 -3
- package/build/adapters/pi/mcp-bridge.d.ts +8 -0
- package/build/adapters/pi/mcp-bridge.js +118 -15
- package/build/adapters/types.d.ts +11 -2
- package/build/cli.d.ts +2 -0
- package/build/cli.js +87 -20
- package/build/search/auto-memory.d.ts +6 -1
- package/build/search/auto-memory.js +11 -2
- package/build/server.js +346 -106
- package/build/session/analytics.d.ts +19 -0
- package/build/session/analytics.js +71 -21
- package/build/session/db.d.ts +81 -0
- package/build/session/db.js +282 -20
- package/build/session/extract.js +16 -0
- package/build/truncate.d.ts +15 -0
- package/build/truncate.js +28 -0
- package/cli.bundle.mjs +435 -350
- package/hooks/core/routing.mjs +4 -4
- package/hooks/routing-block.mjs +18 -23
- package/hooks/session-db.bundle.mjs +21 -19
- package/hooks/session-extract.bundle.mjs +2 -2
- package/hooks/session-helpers.mjs +13 -2
- package/hooks/session-snapshot.bundle.mjs +7 -7
- package/openclaw.plugin.json +1 -1
- package/package.json +4 -2
- package/server.bundle.mjs +383 -300
|
@@ -196,8 +196,14 @@ export interface HookAdapter {
|
|
|
196
196
|
* Directory where persistent per-user memory is stored
|
|
197
197
|
* (e.g., ~/.claude/memory, ~/.codex/memories). Auto-memory scans
|
|
198
198
|
* *.md files in this directory.
|
|
199
|
+
*
|
|
200
|
+
* When `projectDir` is supplied, the path MUST be project-scoped (issue
|
|
201
|
+
* #663) so two projects running in parallel cannot read each other's
|
|
202
|
+
* memory. Adapters scope via `hashProjectDirCanonical(projectDir)`.
|
|
203
|
+
* Callers that pre-date this contract may omit `projectDir`; in that
|
|
204
|
+
* case the unscoped legacy path is returned.
|
|
199
205
|
*/
|
|
200
|
-
getMemoryDir(): string;
|
|
206
|
+
getMemoryDir(projectDir?: string): string;
|
|
201
207
|
/** Generate hook registration config for this platform. */
|
|
202
208
|
generateHookConfig(pluginRoot: string): HookRegistration;
|
|
203
209
|
/** Read current platform settings. */
|
|
@@ -223,7 +229,10 @@ export interface HookAdapter {
|
|
|
223
229
|
getHealthChecks?(pluginRoot: string): readonly HealthCheck[];
|
|
224
230
|
/** Check if the plugin is registered/enabled on this platform. */
|
|
225
231
|
checkPluginRegistration(): DiagnosticResult;
|
|
226
|
-
/**
|
|
232
|
+
/**
|
|
233
|
+
* Get the installed version from this platform's registry/marketplace, or
|
|
234
|
+
* "standalone" when no platform-owned plugin version exists.
|
|
235
|
+
*/
|
|
227
236
|
getInstalledVersion(): string;
|
|
228
237
|
/** Configure all hooks for this platform. Returns change descriptions. */
|
|
229
238
|
configureAllHooks(pluginRoot: string): string[];
|
package/build/cli.d.ts
CHANGED
|
@@ -7,6 +7,8 @@
|
|
|
7
7
|
* context-mode doctor → Diagnose runtime issues, hooks, FTS5, version
|
|
8
8
|
* context-mode upgrade → Fix hooks, permissions, and settings
|
|
9
9
|
* context-mode hook <platform> <event> → Dispatch a hook script (used by platform hook configs)
|
|
10
|
+
* CONTEXT_MODE_DIR=/abs/path context-mode → Override sessions/content storage root
|
|
11
|
+
* Empty/whitespace is ignored; non-empty values must be absolute.
|
|
10
12
|
*
|
|
11
13
|
* Platform auto-detection: CLI detects which platform is running
|
|
12
14
|
* (Claude Code, Gemini CLI, OpenCode, etc.) and uses the appropriate adapter.
|
package/build/cli.js
CHANGED
|
@@ -7,6 +7,8 @@
|
|
|
7
7
|
* context-mode doctor → Diagnose runtime issues, hooks, FTS5, version
|
|
8
8
|
* context-mode upgrade → Fix hooks, permissions, and settings
|
|
9
9
|
* context-mode hook <platform> <event> → Dispatch a hook script (used by platform hook configs)
|
|
10
|
+
* CONTEXT_MODE_DIR=/abs/path context-mode → Override sessions/content storage root
|
|
11
|
+
* Empty/whitespace is ignored; non-empty values must be absolute.
|
|
10
12
|
*
|
|
11
13
|
* Platform auto-detection: CLI detects which platform is running
|
|
12
14
|
* (Claude Code, Gemini CLI, OpenCode, etc.) and uses the appropriate adapter.
|
|
@@ -22,6 +24,7 @@ import { fileURLToPath, pathToFileURL } from "node:url";
|
|
|
22
24
|
import { detectRuntimes, getRuntimeSummary, hasBunRuntime, getAvailableLanguages, } from "./runtime.js";
|
|
23
25
|
import { getHookScriptPaths } from "./util/hook-config.js";
|
|
24
26
|
import { resolveClaudeConfigDir } from "./util/claude-config.js";
|
|
27
|
+
import { ensureWritableStorageDir, formatStorageDirectoryError, resolveContentStorageDir, resolveSessionStorageDir, resolveStatsStorageDir, StorageDirectoryError, } from "./session/db.js";
|
|
25
28
|
// v1.0.128 — Issue #559 sibling MCP kill helpers (see PR-559-560-FIX-DESIGN.md).
|
|
26
29
|
import { discoverSiblingMcpPids, killSiblingMcpServers } from "./util/sibling-mcp.js";
|
|
27
30
|
// v1.0.119 — Issue #523 Layer 5 heal: post-bump assertion on .claude-plugin/plugin.json
|
|
@@ -125,8 +128,26 @@ async function hookDispatch(platform, event) {
|
|
|
125
128
|
/* -------------------------------------------------------
|
|
126
129
|
* Entry point
|
|
127
130
|
* ------------------------------------------------------- */
|
|
131
|
+
const IN_PROCESS_PLUGIN_PLATFORMS = new Set(["opencode", "kilo"]);
|
|
132
|
+
const isInProcessPluginPlatform = (p) => p ? IN_PROCESS_PLUGIN_PLATFORMS.has(p) : false;
|
|
128
133
|
const args = process.argv.slice(2);
|
|
129
|
-
|
|
134
|
+
function printHelp() {
|
|
135
|
+
console.log([
|
|
136
|
+
"Usage:",
|
|
137
|
+
" context-mode Start MCP server (stdio)",
|
|
138
|
+
" context-mode doctor Diagnose runtime issues, hooks, FTS5, version",
|
|
139
|
+
" context-mode upgrade Fix hooks, permissions, and settings",
|
|
140
|
+
" context-mode hook <platform> <event> Dispatch a configured hook script",
|
|
141
|
+
" context-mode statusline Print Claude Code status line",
|
|
142
|
+
"",
|
|
143
|
+
"Environment:",
|
|
144
|
+
" CONTEXT_MODE_DIR=/absolute/path Override sessions/content storage root; empty is ignored, non-empty must be absolute",
|
|
145
|
+
].join("\n"));
|
|
146
|
+
}
|
|
147
|
+
if (args[0] === "--help" || args[0] === "-h" || args[0] === "help") {
|
|
148
|
+
printHelp();
|
|
149
|
+
}
|
|
150
|
+
else if (args[0] === "doctor") {
|
|
130
151
|
doctor().then((code) => process.exit(code));
|
|
131
152
|
}
|
|
132
153
|
else if (args[0] === "upgrade") {
|
|
@@ -236,7 +257,7 @@ function cachePluginRoot(platform) {
|
|
|
236
257
|
}
|
|
237
258
|
function getPluginRoot() {
|
|
238
259
|
const platform = detectPlatform().platform;
|
|
239
|
-
if (platform
|
|
260
|
+
if (isInProcessPluginPlatform(platform)) {
|
|
240
261
|
return cachePluginRoot(platform);
|
|
241
262
|
}
|
|
242
263
|
return defaultPluginRoot();
|
|
@@ -276,6 +297,25 @@ async function fetchLatestVersion() {
|
|
|
276
297
|
/* -------------------------------------------------------
|
|
277
298
|
* Doctor — adapter-aware diagnostics
|
|
278
299
|
* ------------------------------------------------------- */
|
|
300
|
+
function describeStorageSource(dir) {
|
|
301
|
+
return dir.envVar ? dir.envVar : "adapter default";
|
|
302
|
+
}
|
|
303
|
+
function logStorageDir(dir) {
|
|
304
|
+
try {
|
|
305
|
+
ensureWritableStorageDir(dir);
|
|
306
|
+
p.log.success(color.green(`Storage ${dir.kind}: PASS`) +
|
|
307
|
+
color.dim(` — ${dir.path} (${describeStorageSource(dir)})`));
|
|
308
|
+
return 0;
|
|
309
|
+
}
|
|
310
|
+
catch (err) {
|
|
311
|
+
if (err instanceof StorageDirectoryError) {
|
|
312
|
+
p.log.error(color.red(`Storage ${dir.kind}: FAIL`) +
|
|
313
|
+
color.dim(` — ${formatStorageDirectoryError(err)}`));
|
|
314
|
+
return 1;
|
|
315
|
+
}
|
|
316
|
+
throw err;
|
|
317
|
+
}
|
|
318
|
+
}
|
|
279
319
|
async function doctor() {
|
|
280
320
|
if (process.stdout.isTTY)
|
|
281
321
|
console.clear();
|
|
@@ -286,6 +326,29 @@ async function doctor() {
|
|
|
286
326
|
p.log.info(`Platform: ${color.cyan(adapter.name)}` +
|
|
287
327
|
color.dim(` (${detection.confidence} confidence — ${detection.reason})`));
|
|
288
328
|
let criticalFails = 0;
|
|
329
|
+
try {
|
|
330
|
+
const sessionDir = resolveSessionStorageDir(() => adapter.getSessionDir());
|
|
331
|
+
const contentDir = resolveContentStorageDir(() => sessionDir.path);
|
|
332
|
+
const statsDir = resolveStatsStorageDir(() => sessionDir.path);
|
|
333
|
+
p.note([
|
|
334
|
+
`sessions: ${sessionDir.path} (${describeStorageSource(sessionDir)})`,
|
|
335
|
+
`content: ${contentDir.path} (${describeStorageSource(contentDir)})`,
|
|
336
|
+
`stats: ${statsDir.path} (${describeStorageSource(statsDir)})`,
|
|
337
|
+
].join("\n"), "Storage paths");
|
|
338
|
+
criticalFails += logStorageDir(sessionDir);
|
|
339
|
+
criticalFails += logStorageDir(contentDir);
|
|
340
|
+
criticalFails += logStorageDir(statsDir);
|
|
341
|
+
}
|
|
342
|
+
catch (err) {
|
|
343
|
+
if (err instanceof StorageDirectoryError) {
|
|
344
|
+
criticalFails++;
|
|
345
|
+
p.log.error(color.red(`Storage ${err.kind}: FAIL`) +
|
|
346
|
+
color.dim(` — ${formatStorageDirectoryError(err)}`));
|
|
347
|
+
}
|
|
348
|
+
else {
|
|
349
|
+
throw err;
|
|
350
|
+
}
|
|
351
|
+
}
|
|
289
352
|
const s = p.spinner();
|
|
290
353
|
s.start("Running diagnostics");
|
|
291
354
|
let runtimes;
|
|
@@ -700,7 +763,11 @@ async function doctor() {
|
|
|
700
763
|
` — local v${localVersion}, latest v${latestVersion}` +
|
|
701
764
|
color.dim("\n Run: /context-mode:ctx-upgrade"));
|
|
702
765
|
}
|
|
703
|
-
if (installedVersion === "
|
|
766
|
+
if (installedVersion === "standalone") {
|
|
767
|
+
p.log.info(color.dim(`${adapter.name}: standalone MCP mode`) +
|
|
768
|
+
" — no platform plugin version to compare");
|
|
769
|
+
}
|
|
770
|
+
else if (installedVersion === "not installed") {
|
|
704
771
|
p.log.info(color.dim(`${adapter.name}: not installed`) +
|
|
705
772
|
" — using standalone MCP mode");
|
|
706
773
|
}
|
|
@@ -738,8 +805,8 @@ async function insight(port) {
|
|
|
738
805
|
// Detect platform + adapter for correct session/content paths
|
|
739
806
|
const detection = detectPlatform();
|
|
740
807
|
const adapter = await getAdapter(detection.platform);
|
|
741
|
-
const sessDir = adapter.getSessionDir();
|
|
742
|
-
const contentDir =
|
|
808
|
+
const sessDir = ensureWritableStorageDir(resolveSessionStorageDir(() => adapter.getSessionDir()));
|
|
809
|
+
const contentDir = ensureWritableStorageDir(resolveContentStorageDir(() => sessDir));
|
|
743
810
|
const cacheDir = join(dirname(sessDir), "insight-cache");
|
|
744
811
|
if (!existsSync(join(insightSource, "server.mjs"))) {
|
|
745
812
|
console.error("Error: Insight source not found. Try upgrading context-mode.");
|
|
@@ -1141,7 +1208,7 @@ async function upgrade(opts) {
|
|
|
1141
1208
|
timeout: 60000,
|
|
1142
1209
|
});
|
|
1143
1210
|
s.stop("Dependencies ready");
|
|
1144
|
-
if (detection.platform
|
|
1211
|
+
if (!isInProcessPluginPlatform(detection.platform)) {
|
|
1145
1212
|
// Verify native addons through the same bootstrap start.mjs imports.
|
|
1146
1213
|
// On modern Node, the ABI-specific cache file is the compatibility marker;
|
|
1147
1214
|
// the active binding alone may be stale from a previous Node ABI.
|
|
@@ -1203,20 +1270,20 @@ async function upgrade(opts) {
|
|
|
1203
1270
|
color.dim(`\n Try (primary): cd "${pluginRoot}" && npm install better-sqlite3 --no-optional`) +
|
|
1204
1271
|
color.dim("\n Try (fallback): /context-mode:ctx-doctor"));
|
|
1205
1272
|
}
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1273
|
+
// Update global npm
|
|
1274
|
+
s.start("Updating npm global package");
|
|
1275
|
+
try {
|
|
1276
|
+
npmExecFile(["install", "-g", pluginRoot, "--no-audit", "--no-fund"], {
|
|
1277
|
+
stdio: "pipe",
|
|
1278
|
+
timeout: 30000,
|
|
1279
|
+
});
|
|
1280
|
+
s.stop(color.green("npm global updated"));
|
|
1281
|
+
changes.push("Updated npm global package");
|
|
1282
|
+
}
|
|
1283
|
+
catch {
|
|
1284
|
+
s.stop(color.yellow("npm global update skipped"));
|
|
1285
|
+
p.log.info(color.dim(" Could not update global npm — may need sudo or standalone install"));
|
|
1286
|
+
}
|
|
1220
1287
|
}
|
|
1221
1288
|
// Cleanup
|
|
1222
1289
|
rmSync(tmpDir, { recursive: true, force: true });
|
|
@@ -19,7 +19,12 @@ export interface AutoMemoryResult {
|
|
|
19
19
|
export interface AutoMemoryAdapter {
|
|
20
20
|
getConfigDir(): string;
|
|
21
21
|
getInstructionFiles(): string[];
|
|
22
|
-
|
|
22
|
+
/**
|
|
23
|
+
* `projectDir` is optional for backwards compatibility with legacy
|
|
24
|
+
* callers — when supplied, adapters MUST return a project-scoped path
|
|
25
|
+
* (see HookAdapter.getMemoryDir contract, issue #663).
|
|
26
|
+
*/
|
|
27
|
+
getMemoryDir(projectDir?: string): string;
|
|
23
28
|
}
|
|
24
29
|
/**
|
|
25
30
|
* Search auto-memory files for content matching any of the given queries.
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
import { existsSync, readFileSync, readdirSync, statSync } from "node:fs";
|
|
9
9
|
import { join, isAbsolute } from "node:path";
|
|
10
10
|
import { resolveClaudeConfigDir } from "../util/claude-config.js";
|
|
11
|
+
import { hashProjectDirCanonical } from "../session/db.js";
|
|
11
12
|
const DEBUG = process.env.DEBUG?.includes("context-mode");
|
|
12
13
|
/**
|
|
13
14
|
* Search auto-memory files for content matching any of the given queries.
|
|
@@ -38,10 +39,18 @@ export function searchAutoMemory(queries, limit = 5, projectDir, configDir, adap
|
|
|
38
39
|
// CC config trees (and empty/whitespace env doesn't poison the path).
|
|
39
40
|
const adapterRelative = adapterConfigDir ? resolveAgainst(projectDir, adapterConfigDir) : null;
|
|
40
41
|
const effectiveConfigDir = adapterRelative ?? configDir ?? resolveClaudeConfigDir();
|
|
41
|
-
|
|
42
|
+
// Issue #663: scope memory dir by projectDir so parallel projects can't
|
|
43
|
+
// read each other's auto-memory. Adapter-aware path delegates the
|
|
44
|
+
// scoping to the adapter; legacy adapterless fallback applies the same
|
|
45
|
+
// hash directly so the contract holds at both call sites.
|
|
46
|
+
const adapterMemoryDir = adapter?.getMemoryDir(projectDir);
|
|
47
|
+
const fallbackMemoryBase = join(effectiveConfigDir, "memory");
|
|
48
|
+
const fallbackMemoryDir = projectDir
|
|
49
|
+
? join(fallbackMemoryBase, hashProjectDirCanonical(projectDir))
|
|
50
|
+
: fallbackMemoryBase;
|
|
42
51
|
const memoryDir = adapterMemoryDir
|
|
43
52
|
? resolveAgainst(projectDir, adapterMemoryDir)
|
|
44
|
-
:
|
|
53
|
+
: fallbackMemoryDir;
|
|
45
54
|
// Collect candidate files
|
|
46
55
|
const candidates = [];
|
|
47
56
|
// 1. Project-level instruction files
|