context-mode 1.0.158 → 1.0.159
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 +1 -1
- package/.codex-plugin/plugin.json +1 -1
- package/.openclaw-plugin/openclaw.plugin.json +1 -1
- package/.openclaw-plugin/package.json +1 -1
- package/build/adapters/codex/index.d.ts +4 -1
- package/build/adapters/codex/index.js +237 -45
- package/cli.bundle.mjs +181 -178
- package/hooks/session-loaders.mjs +218 -3
- package/hooks/sessionstart.mjs +52 -2
- package/openclaw.plugin.json +1 -1
- package/package.json +1 -1
- package/server.bundle.mjs +132 -129
|
@@ -6,9 +6,10 @@
|
|
|
6
6
|
* Fallback: if bundles are missing (marketplace installs), try build/session/*.js.
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
-
import { join } from "node:path";
|
|
9
|
+
import { join, resolve as resolvePath } from "node:path";
|
|
10
10
|
import { pathToFileURL } from "node:url";
|
|
11
|
-
import { existsSync } from "node:fs";
|
|
11
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
12
|
+
import { tmpdir } from "node:os";
|
|
12
13
|
|
|
13
14
|
import { hasPlatformConfig, maybeForward } from "./platform-bridge.mjs";
|
|
14
15
|
import { detectPlatformFromEnv } from "./core/platform-detect.mjs";
|
|
@@ -115,9 +116,25 @@ export function attributeAndInsertEvents(db, sessionId, events, input, projectDi
|
|
|
115
116
|
? db.getSessionRollup(sessionId)
|
|
116
117
|
: null;
|
|
117
118
|
|
|
119
|
+
// v1.0.159: Bash metadata shared across all events from this hook fire.
|
|
120
|
+
// A single Bash tool call may emit multiple canonical events (a `git
|
|
121
|
+
// pull` produces type=git AND type=cwd) — they all share the same
|
|
122
|
+
// command_type / command_tool / exit_code / duration_bucket. Hook
|
|
123
|
+
// metadata (latency, exit_code) is also per-call, not per-event.
|
|
124
|
+
const bashMeta = deriveBashMetadata(input);
|
|
125
|
+
// v1.0.159: latency_ms read from the PreToolUse timestamp stamp.
|
|
126
|
+
// PreToolUse writes ms-precision Date.now() to a tmp file, PostToolUse
|
|
127
|
+
// reads + computes delta + cleans up. Failure → undefined (no field
|
|
128
|
+
// surfaces on the wire; Zod is optional).
|
|
129
|
+
const latencyMs = readLatencyMs(sessionId, input?.tool_name);
|
|
130
|
+
|
|
118
131
|
for (let i = 0; i < events.length; i++) {
|
|
119
132
|
const enriched = enrichEventForPlatform(events[i], attributions[i]);
|
|
120
|
-
const
|
|
133
|
+
const withBash = bashMeta ? { ...enriched, ...bashMeta } : enriched;
|
|
134
|
+
const withLatency = latencyMs !== undefined
|
|
135
|
+
? { ...withBash, latency_ms: latencyMs, duration_bucket: bucketizeDuration(latencyMs) }
|
|
136
|
+
: withBash;
|
|
137
|
+
const payload = rollup ? { ...withLatency, ...rollup } : withLatency;
|
|
121
138
|
maybeForward({ ...payload, session_id: sessionId }, platform);
|
|
122
139
|
}
|
|
123
140
|
}
|
|
@@ -161,6 +178,15 @@ function enrichEventForPlatform(event, attribution) {
|
|
|
161
178
|
enriched.error_tool = cls.error_tool;
|
|
162
179
|
}
|
|
163
180
|
|
|
181
|
+
// blocker_status: derive from the canonical event TYPE, not lexical
|
|
182
|
+
// pattern-matching on prose. session-extract already identifies blocker
|
|
183
|
+
// states semantically (type='blocker' when the agent signals stuck;
|
|
184
|
+
// type='blocker_resolved' on recovery). Regex on error_message would
|
|
185
|
+
// false-positive on the millions of error texts in the wild — we let
|
|
186
|
+
// the extractor's structural judgment be the source of truth.
|
|
187
|
+
if (event?.type === "blocker") enriched.blocker_status = "open";
|
|
188
|
+
else if (event?.type === "blocker_resolved") enriched.blocker_status = "resolved";
|
|
189
|
+
|
|
164
190
|
// Git events: surface commit message + mark has_commit at the event level
|
|
165
191
|
// (rollup-level has_commit comes from the session-wide stamp; both win
|
|
166
192
|
// when set — `{...enriched, ...rollup}` order keeps rollup authoritative
|
|
@@ -205,3 +231,192 @@ function classifyError(message) {
|
|
|
205
231
|
if (/test failed|fail |tests failed|assertion/.test(m)) return { error_category: "test_failed", error_tool: "Bash" };
|
|
206
232
|
return { error_category: "unknown", error_tool: "Bash" };
|
|
207
233
|
}
|
|
234
|
+
|
|
235
|
+
// ── Bash metadata derivation — algorithmic, not enumerative ──────────────
|
|
236
|
+
//
|
|
237
|
+
// A single Bash tool call may emit MULTIPLE canonical events (a `git pull`
|
|
238
|
+
// produces type='git' AND type='cwd'). The platform's command_metadata
|
|
239
|
+
// describes the BASH CALL, not the per-event derivative — so all events
|
|
240
|
+
// from one PostToolUse fire carry the same shape. Non-Bash tool calls
|
|
241
|
+
// return null and the per-event fields stay undefined (Zod optional drops
|
|
242
|
+
// them silently — no NULL noise on the wire).
|
|
243
|
+
//
|
|
244
|
+
// DESIGN: tool ecosystems contain millions of CLI binaries but converge on
|
|
245
|
+
// a tiny canonical verb set (test/build/install/lint/format/run/start/
|
|
246
|
+
// deploy/...). The classifier scans for these verbs at canonical token
|
|
247
|
+
// positions — agnostic of which package manager / language / framework.
|
|
248
|
+
// New tools without a registry change automatically classify correctly as
|
|
249
|
+
// long as they use the verbs (which is the dominant ecosystem convention).
|
|
250
|
+
// This was originally regex-table enumeration; the table never converges.
|
|
251
|
+
const CANONICAL_VERBS = new Set([
|
|
252
|
+
"test", "build", "install", "lint", "format", "run", "start",
|
|
253
|
+
"deploy", "compile", "bundle", "watch", "serve", "publish",
|
|
254
|
+
]);
|
|
255
|
+
// Runners that wrap the actual executable — strip them so command_tool
|
|
256
|
+
// reflects the real binary the user invoked (`bunx pytest` → "pytest",
|
|
257
|
+
// not "bunx"). NODE_ENV=production npm run build → "npm".
|
|
258
|
+
const COMMAND_RUNNERS = new Set([
|
|
259
|
+
"sudo", "doas", "env", "exec", "time",
|
|
260
|
+
"npx", "pnpx", "bunx", "pnpm", "yarn", "bun",
|
|
261
|
+
]);
|
|
262
|
+
const ENV_ASSIGN_RE = /^[A-Z_][A-Z0-9_]*=/;
|
|
263
|
+
|
|
264
|
+
// Tools whose NAME directly implies their type (no subcommand needed).
|
|
265
|
+
// Curated minimum — covers the dominant test/lint/format/build/db/http/
|
|
266
|
+
// deploy invocations across ecosystems. New ecosystem tools land in
|
|
267
|
+
// "other" until added — preferred to a noisy heuristic that misclassifies.
|
|
268
|
+
// Lookup is O(1); contrast with the original regex-table approach which
|
|
269
|
+
// scaled to no boundary and still missed unknowns.
|
|
270
|
+
const CANONICAL_TOOLS = new Map([
|
|
271
|
+
// test runners
|
|
272
|
+
["pytest", "test"], ["jest", "test"], ["vitest", "test"], ["mocha", "test"],
|
|
273
|
+
["ava", "test"], ["jasmine", "test"], ["rspec", "test"], ["junit", "test"],
|
|
274
|
+
["tap", "test"], ["karma", "test"],
|
|
275
|
+
// linters
|
|
276
|
+
["eslint", "lint"], ["tslint", "lint"], ["ruff", "lint"], ["rubocop", "lint"],
|
|
277
|
+
["pylint", "lint"], ["flake8", "lint"], ["clippy", "lint"], ["staticcheck", "lint"],
|
|
278
|
+
["mypy", "lint"], ["shellcheck", "lint"],
|
|
279
|
+
// formatters
|
|
280
|
+
["prettier", "format"], ["black", "format"], ["gofmt", "format"], ["rustfmt", "format"],
|
|
281
|
+
["autopep8", "format"], ["yapf", "format"],
|
|
282
|
+
// bundlers / builders
|
|
283
|
+
["webpack", "build"], ["vite", "build"], ["rollup", "build"], ["esbuild", "build"],
|
|
284
|
+
["parcel", "build"], ["tsc", "build"], ["swc", "build"], ["turbo", "build"],
|
|
285
|
+
// deploy / infra
|
|
286
|
+
["docker", "deploy"], ["kubectl", "deploy"], ["terraform", "deploy"], ["pulumi", "deploy"],
|
|
287
|
+
["ansible", "deploy"], ["helm", "deploy"], ["aws", "deploy"], ["gcloud", "deploy"], ["az", "deploy"],
|
|
288
|
+
// databases
|
|
289
|
+
["psql", "database"], ["mysql", "database"], ["sqlite3", "database"],
|
|
290
|
+
["redis-cli", "database"], ["mongosh", "database"], ["mongo", "database"],
|
|
291
|
+
// http
|
|
292
|
+
["curl", "http"], ["wget", "http"], ["httpie", "http"], ["http", "http"],
|
|
293
|
+
]);
|
|
294
|
+
|
|
295
|
+
function deriveBashMetadata(input) {
|
|
296
|
+
if (input?.tool_name !== "Bash") return null;
|
|
297
|
+
const cmd = String(input?.tool_input?.command ?? "").trim();
|
|
298
|
+
if (!cmd) return { command_type: "other", command_tool: "Bash" };
|
|
299
|
+
|
|
300
|
+
const tokens = cmd.split(/\s+/);
|
|
301
|
+
const command_tool = extractCommandTool(tokens);
|
|
302
|
+
const command_type = classifyCommandType(tokens, command_tool);
|
|
303
|
+
const exit_code = inferExitCode(input?.tool_response);
|
|
304
|
+
return { command_type, command_tool, exit_code };
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
// Strip env-assign prefixes (`FOO=bar`), then strip runner shells,
|
|
308
|
+
// then return the basename of the executable token.
|
|
309
|
+
function extractCommandTool(tokens) {
|
|
310
|
+
let i = 0;
|
|
311
|
+
// Skip env assignments
|
|
312
|
+
while (i < tokens.length && ENV_ASSIGN_RE.test(tokens[i])) i++;
|
|
313
|
+
// Skip runner shells
|
|
314
|
+
while (i < tokens.length && COMMAND_RUNNERS.has(tokens[i].toLowerCase())) {
|
|
315
|
+
i++;
|
|
316
|
+
// Skip subcommands like `pnpm dlx`, `pnpm exec`, `bun run`
|
|
317
|
+
if (i < tokens.length && /^(dlx|exec|run|x)$/i.test(tokens[i])) i++;
|
|
318
|
+
}
|
|
319
|
+
if (i >= tokens.length) return tokens[0] || "Bash";
|
|
320
|
+
const exe = tokens[i];
|
|
321
|
+
// basename of path-like executables (`/usr/local/bin/foo` → "foo")
|
|
322
|
+
const base = exe.split(/[/\\]/).pop() || "Bash";
|
|
323
|
+
// Strip shell quoting if present
|
|
324
|
+
return base.replace(/^['"]|['"]$/g, "");
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
// Type classification — priority order:
|
|
328
|
+
// 1. Tool name implies type (curated CANONICAL_TOOLS map)
|
|
329
|
+
// 2. Canonical verb at subcommand position (`npm test`, `cargo build`)
|
|
330
|
+
// 3. Argument-shape heuristics (test/ dir, .test.ts suffix, --prod flag)
|
|
331
|
+
// 4. Tool-level fallback (git → git, make → build)
|
|
332
|
+
// 5. "other"
|
|
333
|
+
function classifyCommandType(tokens, command_tool) {
|
|
334
|
+
const toolLc = (command_tool || "").toLowerCase();
|
|
335
|
+
|
|
336
|
+
// 1. Tool name itself names the type
|
|
337
|
+
const fromTool = CANONICAL_TOOLS.get(toolLc);
|
|
338
|
+
if (fromTool) return fromTool;
|
|
339
|
+
|
|
340
|
+
// Skip env + runners to find subcommand position
|
|
341
|
+
const lower = tokens.map((t) => t.toLowerCase());
|
|
342
|
+
let start = 0;
|
|
343
|
+
while (start < lower.length && ENV_ASSIGN_RE.test(tokens[start])) start++;
|
|
344
|
+
while (start < lower.length && COMMAND_RUNNERS.has(lower[start])) {
|
|
345
|
+
start++;
|
|
346
|
+
if (start < lower.length && /^(dlx|exec|run|x)$/.test(lower[start])) start++;
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
// 2. Canonical verb scan within next 4 tokens
|
|
350
|
+
const horizon = Math.min(lower.length, start + 4);
|
|
351
|
+
for (let i = start; i < horizon; i++) {
|
|
352
|
+
if (CANONICAL_VERBS.has(lower[i])) return lower[i];
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
// 3. Argument-shape heuristics
|
|
356
|
+
const tail = tokens.slice(start).join(" ");
|
|
357
|
+
if (/\btests?[/\\]|\bspec[/\\]|__tests__|\.(test|spec)\.[mc]?[jt]sx?\b|test_[\w-]+\.py\b|_test\.go\b/.test(tail)) return "test";
|
|
358
|
+
if (/--(prod|production|release|optimize)\b/.test(tail)) return "build";
|
|
359
|
+
if (/\bDockerfile\b|docker-compose/.test(tail)) return "deploy";
|
|
360
|
+
|
|
361
|
+
// 4. Tool-level fallback for tools whose mere presence implies the type
|
|
362
|
+
if (toolLc === "git") return "git";
|
|
363
|
+
if (toolLc === "make" || toolLc === "ninja" || toolLc === "cmake") return "build";
|
|
364
|
+
|
|
365
|
+
return "other";
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
// Exit code best-effort inference from tool_response. Hook stdin does
|
|
369
|
+
// not carry the actual exit code on CC; we read the shape of the output
|
|
370
|
+
// for signals. Engine treats exit_code as soft signal (Anomaly #3 — no
|
|
371
|
+
// pattern in patterns.ts reads it today), so probabilistic stamps are
|
|
372
|
+
// adequate. Captures named exit code when explicit.
|
|
373
|
+
function inferExitCode(response) {
|
|
374
|
+
const r = String(response ?? "");
|
|
375
|
+
if (!r) return 0;
|
|
376
|
+
// Explicit exit-code marker (some wrappers emit "exit status 137" etc.)
|
|
377
|
+
const explicit = r.match(/\bexit (?:status|code)\s+(\d+)\b/i);
|
|
378
|
+
if (explicit) return Number(explicit[1]);
|
|
379
|
+
// "command not found" → POSIX standard 127
|
|
380
|
+
if (/^bash:.*: (?:command not found|No such file)/m.test(r)) return 127;
|
|
381
|
+
// Heuristic non-zero indicators (line-anchored to avoid false positives
|
|
382
|
+
// inside narrative text from successful commands).
|
|
383
|
+
if (/^(?:Error: |Traceback|FAIL\b|✗|✘)/m.test(r)) return 1;
|
|
384
|
+
return 0;
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
// ── Latency timing — reads PreToolUse marker ────────────────────────────
|
|
388
|
+
//
|
|
389
|
+
// PreToolUse already writes `${tmpdir}/context-mode-latency-${sessionId}-
|
|
390
|
+
// ${toolName}.txt` with the start timestamp (pretooluse.mjs:177). We
|
|
391
|
+
// piggyback on that marker — read + compute delta, do NOT unlink (the
|
|
392
|
+
// downstream slow-tool event emission in posttooluse.mjs:128-152 manages
|
|
393
|
+
// the unlink lifecycle). Failure modes (missing marker, parse error,
|
|
394
|
+
// negative delta, sanity-out-of-range) all return undefined — Zod's
|
|
395
|
+
// optional handling drops the field silently. No NULL noise on the wire.
|
|
396
|
+
function readLatencyMs(sessionId, toolName) {
|
|
397
|
+
if (!sessionId || !toolName) return undefined;
|
|
398
|
+
const markerPath = resolvePath(
|
|
399
|
+
tmpdir(),
|
|
400
|
+
`context-mode-latency-${sessionId}-${toolName}.txt`,
|
|
401
|
+
);
|
|
402
|
+
try {
|
|
403
|
+
const start = parseInt(readFileSync(markerPath, "utf8").trim(), 10);
|
|
404
|
+
if (!Number.isFinite(start) || start <= 0) return undefined;
|
|
405
|
+
const delta = Date.now() - start;
|
|
406
|
+
if (delta < 0 || delta > 24 * 3600 * 1000) return undefined;
|
|
407
|
+
return delta;
|
|
408
|
+
} catch {
|
|
409
|
+
return undefined;
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
// ── Duration bucket ──────────────────────────────────────────────────────
|
|
414
|
+
//
|
|
415
|
+
// Open-string label the platform Zod schema accepts (max 20 chars). Three
|
|
416
|
+
// buckets cover the seed.ts shape: <5s | 5-30s | 30s+.
|
|
417
|
+
function bucketizeDuration(ms) {
|
|
418
|
+
if (typeof ms !== "number" || !Number.isFinite(ms) || ms < 0) return undefined;
|
|
419
|
+
if (ms < 5_000) return "<5s";
|
|
420
|
+
if (ms < 30_000) return "5-30s";
|
|
421
|
+
return "30s+";
|
|
422
|
+
}
|
package/hooks/sessionstart.mjs
CHANGED
|
@@ -30,6 +30,7 @@ await runHook(async () => {
|
|
|
30
30
|
readStdin,
|
|
31
31
|
parseStdin,
|
|
32
32
|
getSessionId,
|
|
33
|
+
getInputProjectDir,
|
|
33
34
|
getSessionDBPath,
|
|
34
35
|
getSessionEventsPath,
|
|
35
36
|
getCleanupFlagPath,
|
|
@@ -38,7 +39,7 @@ await runHook(async () => {
|
|
|
38
39
|
const { writeSessionEventsFile, buildSessionDirective, getSessionEvents } = await import(
|
|
39
40
|
"./session-directive.mjs"
|
|
40
41
|
);
|
|
41
|
-
const { createSessionLoaders } = await import("./session-loaders.mjs");
|
|
42
|
+
const { createSessionLoaders, attributeAndInsertEvents } = await import("./session-loaders.mjs");
|
|
42
43
|
const { join, dirname } = await import("node:path");
|
|
43
44
|
const { fileURLToPath } = await import("node:url");
|
|
44
45
|
const { readFileSync, unlinkSync, readdirSync, rmSync, lstatSync } = await import("node:fs");
|
|
@@ -49,7 +50,40 @@ await runHook(async () => {
|
|
|
49
50
|
|
|
50
51
|
// Resolve absolute path for imports (fileURLToPath for Windows compat)
|
|
51
52
|
const HOOK_DIR = dirname(fileURLToPath(import.meta.url));
|
|
52
|
-
const { loadSessionDB } = createSessionLoaders(HOOK_DIR);
|
|
53
|
+
const { loadSessionDB, loadProjectAttribution } = createSessionLoaders(HOOK_DIR);
|
|
54
|
+
|
|
55
|
+
// Emit a `session_start` canonical event at the boundary of each session
|
|
56
|
+
// lifecycle transition (startup / resume / compact). The platform's insight
|
|
57
|
+
// engine joins on `category='session_start'` to compute per-session
|
|
58
|
+
// aggregates (~60 of 180 patterns depend on this anchor row). Bridge
|
|
59
|
+
// forwards via attributeAndInsertEvents which also stamps the rollup
|
|
60
|
+
// snapshot — safe for the FIRST event of a fresh session.
|
|
61
|
+
async function emitSessionStartLifecycle(db, sessionId, source, projectDir, input) {
|
|
62
|
+
try {
|
|
63
|
+
const { resolveProjectAttributions } = await loadProjectAttribution();
|
|
64
|
+
const lifecycleEvent = {
|
|
65
|
+
type: "session_start",
|
|
66
|
+
category: "session_start",
|
|
67
|
+
data: JSON.stringify({
|
|
68
|
+
source,
|
|
69
|
+
project_dir: projectDir,
|
|
70
|
+
started_at: Math.floor(Date.now() / 1000),
|
|
71
|
+
}),
|
|
72
|
+
priority: 1,
|
|
73
|
+
};
|
|
74
|
+
attributeAndInsertEvents(
|
|
75
|
+
db,
|
|
76
|
+
sessionId,
|
|
77
|
+
[lifecycleEvent],
|
|
78
|
+
input,
|
|
79
|
+
projectDir,
|
|
80
|
+
"SessionStart",
|
|
81
|
+
resolveProjectAttributions,
|
|
82
|
+
);
|
|
83
|
+
} catch {
|
|
84
|
+
// Best-effort — lifecycle emission failure MUST NOT block session start.
|
|
85
|
+
}
|
|
86
|
+
}
|
|
53
87
|
|
|
54
88
|
// Self-heal a partial plugin cache install before anything else
|
|
55
89
|
// touches the cache dir. The Algo-D4 boot gate and the #604
|
|
@@ -202,6 +236,13 @@ await runHook(async () => {
|
|
|
202
236
|
} catch { /* best-effort */ }
|
|
203
237
|
}
|
|
204
238
|
|
|
239
|
+
// Emit lifecycle anchor BEFORE close — engine joins on
|
|
240
|
+
// category='session_start' to compute per-session aggregates.
|
|
241
|
+
// Cross-platform projectDir via getInputProjectDir (covers cursor's
|
|
242
|
+
// workspace_roots[], codex/gemini/qwen's *_PROJECT_DIR env vars,
|
|
243
|
+
// CC's CLAUDE_PROJECT_DIR, falls back to input.cwd and process.cwd).
|
|
244
|
+
const projectDirCompact = getInputProjectDir(input);
|
|
245
|
+
await emitSessionStartLifecycle(db, sessionId, "compact", projectDirCompact, input);
|
|
205
246
|
db.close();
|
|
206
247
|
} else if (source === "resume") {
|
|
207
248
|
// User invoked --continue, --resume, or /resume — clear cleanup flag so
|
|
@@ -234,6 +275,10 @@ await runHook(async () => {
|
|
|
234
275
|
}
|
|
235
276
|
}
|
|
236
277
|
|
|
278
|
+
const projectDirResume = getInputProjectDir(input);
|
|
279
|
+
if (sessionId) {
|
|
280
|
+
await emitSessionStartLifecycle(db, sessionId, "resume", projectDirResume, input);
|
|
281
|
+
}
|
|
237
282
|
db.close();
|
|
238
283
|
} else if (source === "startup") {
|
|
239
284
|
// Fresh session (no --continue) — clean slate, capture CLAUDE.md rules.
|
|
@@ -294,6 +339,11 @@ await runHook(async () => {
|
|
|
294
339
|
} catch { /* file doesn't exist — skip */ }
|
|
295
340
|
}
|
|
296
341
|
|
|
342
|
+
// Lifecycle anchor for a fresh session — emits BEFORE the CLAUDE.md
|
|
343
|
+
// rule events have been forwarded so the `session_start` row lands
|
|
344
|
+
// as the very first row the platform sees for this session.
|
|
345
|
+
await emitSessionStartLifecycle(db, sessionId, "startup", projectDir, input);
|
|
346
|
+
|
|
297
347
|
db.close();
|
|
298
348
|
|
|
299
349
|
// Age-gated lazy cleanup of old plugin cache version dirs (#181).
|
package/openclaw.plugin.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"name": "Context Mode",
|
|
4
4
|
"kind": "tool",
|
|
5
5
|
"description": "OpenClaw plugin that saves 98% of your context window. Sandboxed code execution in 11 languages, FTS5 knowledge base with BM25 ranking, and intent-driven search.",
|
|
6
|
-
"version": "1.0.
|
|
6
|
+
"version": "1.0.159",
|
|
7
7
|
"sandbox": {
|
|
8
8
|
"mode": "permissive",
|
|
9
9
|
"filesystem_access": "full",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "context-mode",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.159",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "MCP plugin that saves 98% of your context window. Works with Claude Code, Gemini CLI, VS Code Copilot, OpenCode, and Codex CLI. Sandboxed code execution, FTS5 knowledge base, and intent-driven search.",
|
|
6
6
|
"author": "Mert Koseoğlu",
|