context-mode 1.0.125 → 1.0.126
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/.openclaw-plugin/openclaw.plugin.json +1 -1
- package/.openclaw-plugin/package.json +1 -1
- package/build/adapters/claude-code/hooks.d.ts +10 -4
- package/build/adapters/claude-code/hooks.js +22 -12
- package/build/adapters/claude-code/index.d.ts +24 -1
- package/build/adapters/claude-code/index.js +67 -11
- package/build/adapters/types.d.ts +57 -0
- package/build/adapters/types.js +29 -0
- package/build/cli.js +38 -13
- package/build/util/hook-config.d.ts +24 -1
- package/build/util/hook-config.js +39 -2
- package/build/util/plugin-cache-integrity.d.ts +37 -0
- package/build/util/plugin-cache-integrity.js +105 -0
- package/cli.bundle.mjs +122 -122
- package/openclaw.plugin.json +1 -1
- package/package.json +2 -1
- package/scripts/plugin-cache-integrity.mjs +168 -0
- package/server.bundle.mjs +88 -88
- package/start.mjs +37 -0
- package/skills/UPSTREAM-CREDITS.md +0 -51
- package/skills/diagnose/SKILL.md +0 -122
- package/skills/diagnose/scripts/hitl-loop.template.sh +0 -41
- package/skills/grill-me/SKILL.md +0 -15
- package/skills/grill-with-docs/ADR-FORMAT.md +0 -47
- package/skills/grill-with-docs/CONTEXT-FORMAT.md +0 -77
- package/skills/grill-with-docs/SKILL.md +0 -93
- package/skills/improve-codebase-architecture/DEEPENING.md +0 -37
- package/skills/improve-codebase-architecture/INTERFACE-DESIGN.md +0 -44
- package/skills/improve-codebase-architecture/LANGUAGE.md +0 -53
- package/skills/improve-codebase-architecture/SKILL.md +0 -76
- package/skills/tdd/SKILL.md +0 -114
- package/skills/tdd/deep-modules.md +0 -33
- package/skills/tdd/interface-design.md +0 -31
- package/skills/tdd/mocking.md +0 -59
- package/skills/tdd/refactoring.md +0 -10
- package/skills/tdd/tests.md +0 -61
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.126",
|
|
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.126",
|
|
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",
|
|
@@ -79,6 +79,7 @@
|
|
|
79
79
|
"scripts/postinstall.mjs",
|
|
80
80
|
"scripts/heal-better-sqlite3.mjs",
|
|
81
81
|
"scripts/heal-installed-plugins.mjs",
|
|
82
|
+
"scripts/plugin-cache-integrity.mjs",
|
|
82
83
|
"README.md",
|
|
83
84
|
"LICENSE"
|
|
84
85
|
],
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Plugin cache integrity check (Algo-D4 + Algo-D5).
|
|
3
|
+
*
|
|
4
|
+
* Algorithmic defense against #550: a partial install (interrupted npm
|
|
5
|
+
* install, broken marketplace pull, half-finished /ctx-upgrade) leaves
|
|
6
|
+
* start.mjs spawnable but a critical sibling (server.bundle.mjs,
|
|
7
|
+
* cli.bundle.mjs, hooks/<event>.mjs, …) missing. The MCP child then
|
|
8
|
+
* dies silently downstream and the user sees an opaque "MCP server
|
|
9
|
+
* failed to start" with no actionable signal.
|
|
10
|
+
*
|
|
11
|
+
* The expected sibling tree is DERIVED from `package.json files[]` —
|
|
12
|
+
* the npm publish source of truth. Adding a new entry there auto-
|
|
13
|
+
* extends the integrity check; no parallel hardcoded list to maintain
|
|
14
|
+
* (the trap that bites every project that hand-rolls "list of files
|
|
15
|
+
* that must exist at runtime").
|
|
16
|
+
*
|
|
17
|
+
* Two consumers:
|
|
18
|
+
* 1. start.mjs at boot — calls assertPluginCacheIntegrity, on !ok
|
|
19
|
+
* writes a structured CONTEXT_MODE_PARTIAL_INSTALL stderr block
|
|
20
|
+
* and exits 2. Fail-fast — the alternative is a downstream stack
|
|
21
|
+
* trace from `import("./server.bundle.mjs")` that hides the
|
|
22
|
+
* actual root cause.
|
|
23
|
+
* 2. src/cli.ts ctx doctor (Algo-D5) — same helper, same answer,
|
|
24
|
+
* surfaced as a HealthCheck so users get the diagnostic without
|
|
25
|
+
* restarting the MCP server.
|
|
26
|
+
*
|
|
27
|
+
* Pure JS, Node.js built-ins only. Ships in package.json files[] so
|
|
28
|
+
* users running off the npm tarball get the same code path the
|
|
29
|
+
* developer ran during `pretest`.
|
|
30
|
+
*/
|
|
31
|
+
import { existsSync, readFileSync, readdirSync, statSync } from "node:fs";
|
|
32
|
+
import { join, relative } from "node:path";
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Walk a directory recursively, returning a flat list of relative file
|
|
36
|
+
* paths (using `/` as separator inside the returned strings). Skips
|
|
37
|
+
* unreadable entries silently — the integrity check operates on what
|
|
38
|
+
* IS readable; missing entries are reported by the caller.
|
|
39
|
+
*/
|
|
40
|
+
function listFilesRecursive(absDir, baseAbs) {
|
|
41
|
+
const out = [];
|
|
42
|
+
let entries;
|
|
43
|
+
try {
|
|
44
|
+
entries = readdirSync(absDir);
|
|
45
|
+
} catch {
|
|
46
|
+
return out; // unreadable — caller will report the parent as missing
|
|
47
|
+
}
|
|
48
|
+
for (const name of entries) {
|
|
49
|
+
const full = join(absDir, name);
|
|
50
|
+
let st;
|
|
51
|
+
try {
|
|
52
|
+
st = statSync(full);
|
|
53
|
+
} catch {
|
|
54
|
+
continue;
|
|
55
|
+
}
|
|
56
|
+
if (st.isDirectory()) {
|
|
57
|
+
out.push(...listFilesRecursive(full, baseAbs));
|
|
58
|
+
} else {
|
|
59
|
+
out.push(relative(baseAbs, full));
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
return out;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Compute the expected sibling tree for a given pluginRoot, derived
|
|
67
|
+
* from the supplied `package.json files[]` array.
|
|
68
|
+
*
|
|
69
|
+
* Algorithm:
|
|
70
|
+
* - Each entry in files[] is resolved against pluginRoot.
|
|
71
|
+
* - If it points to a directory → list every file inside recursively.
|
|
72
|
+
* - If it points to a file → kept as-is.
|
|
73
|
+
* - Entries that don't exist at probe-time are EXCLUDED from the
|
|
74
|
+
* manifest (they show up as `missing` in the assert step instead).
|
|
75
|
+
* This avoids the trap of "manifest contains paths that have never
|
|
76
|
+
* existed" — the manifest is a snapshot of WHAT IS, not WHAT WAS
|
|
77
|
+
* PUBLISHED.
|
|
78
|
+
*
|
|
79
|
+
* Returns relative paths (relative to pluginRoot). Used by both
|
|
80
|
+
* assertPluginCacheIntegrity and the doctor surface.
|
|
81
|
+
*/
|
|
82
|
+
export function derivePluginManifest({ pkg, pluginRoot }) {
|
|
83
|
+
if (!pkg || !Array.isArray(pkg.files)) return [];
|
|
84
|
+
const manifest = new Set();
|
|
85
|
+
for (const entry of pkg.files) {
|
|
86
|
+
if (typeof entry !== "string" || !entry) continue;
|
|
87
|
+
const absEntry = join(pluginRoot, entry);
|
|
88
|
+
if (!existsSync(absEntry)) continue;
|
|
89
|
+
let st;
|
|
90
|
+
try {
|
|
91
|
+
st = statSync(absEntry);
|
|
92
|
+
} catch {
|
|
93
|
+
continue;
|
|
94
|
+
}
|
|
95
|
+
if (st.isDirectory()) {
|
|
96
|
+
for (const f of listFilesRecursive(absEntry, pluginRoot)) manifest.add(f);
|
|
97
|
+
} else {
|
|
98
|
+
manifest.add(entry);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
return [...manifest];
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* REQUIRED_RUNTIME_SIBLINGS — the minimum set of files start.mjs must
|
|
106
|
+
* find at boot. These are the files start.mjs actively `import()`s or
|
|
107
|
+
* needs to re-symlink against. The check is intentionally narrower
|
|
108
|
+
* than the full manifest:
|
|
109
|
+
*
|
|
110
|
+
* - server.bundle.mjs / cli.bundle.mjs are produced by `npm run
|
|
111
|
+
* bundle`. Without server.bundle.mjs the server can't start;
|
|
112
|
+
* without cli.bundle.mjs `context-mode doctor` can't run.
|
|
113
|
+
* - hooks/{5 hook scripts}.mjs are spawned per Claude Code event.
|
|
114
|
+
* Missing any one produces a silent hook failure.
|
|
115
|
+
*
|
|
116
|
+
* Other files in package.json files[] (insight/, configs/, README, …)
|
|
117
|
+
* are not boot-critical, so missing them is a "warn"-class issue
|
|
118
|
+
* surfaced only via the doctor — never enough to fail-fast at boot.
|
|
119
|
+
*/
|
|
120
|
+
const REQUIRED_RUNTIME_SIBLINGS = Object.freeze([
|
|
121
|
+
"server.bundle.mjs",
|
|
122
|
+
"cli.bundle.mjs",
|
|
123
|
+
join("hooks", "pretooluse.mjs"),
|
|
124
|
+
join("hooks", "posttooluse.mjs"),
|
|
125
|
+
join("hooks", "precompact.mjs"),
|
|
126
|
+
join("hooks", "sessionstart.mjs"),
|
|
127
|
+
join("hooks", "userpromptsubmit.mjs"),
|
|
128
|
+
]);
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Verify boot-critical siblings exist at pluginRoot.
|
|
132
|
+
*
|
|
133
|
+
* Returns `{ ok, missing }`. Pure — does NOT touch process.exit or
|
|
134
|
+
* stderr. The caller (start.mjs at boot, src/cli.ts at doctor) decides
|
|
135
|
+
* the failure surface (fail-fast exit 2 vs. doctor diagnostic).
|
|
136
|
+
*
|
|
137
|
+
* Uses package.json (read from pluginRoot) only as a source-of-truth
|
|
138
|
+
* cross-check; the actual REQUIRED list is hardcoded above to keep the
|
|
139
|
+
* runtime contract independent of package.json being readable. If
|
|
140
|
+
* package.json IS readable AND files[] omits something we require, the
|
|
141
|
+
* check fails — that's the "drift between contract and tarball" trap.
|
|
142
|
+
*/
|
|
143
|
+
export function assertPluginCacheIntegrity({ pluginRoot }) {
|
|
144
|
+
const missing = [];
|
|
145
|
+
for (const rel of REQUIRED_RUNTIME_SIBLINGS) {
|
|
146
|
+
const abs = join(pluginRoot, rel);
|
|
147
|
+
if (!existsSync(abs)) missing.push(abs);
|
|
148
|
+
}
|
|
149
|
+
return { ok: missing.length === 0, missing };
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Format the structured stderr block start.mjs emits when integrity
|
|
154
|
+
* fails. Marker line `CONTEXT_MODE_PARTIAL_INSTALL` lets external
|
|
155
|
+
* monitoring grep for the exact failure mode without parsing free-form
|
|
156
|
+
* text. Keep the format stable across versions.
|
|
157
|
+
*/
|
|
158
|
+
export function formatPartialInstallReport({ pluginRoot, missing }) {
|
|
159
|
+
const lines = [
|
|
160
|
+
"CONTEXT_MODE_PARTIAL_INSTALL",
|
|
161
|
+
` pluginRoot: ${pluginRoot}`,
|
|
162
|
+
" missing:",
|
|
163
|
+
...missing.map((m) => ` - ${m}`),
|
|
164
|
+
" fix: rm -rf the install dir and re-pull (marketplace) or run `npm install -g context-mode` again.",
|
|
165
|
+
"",
|
|
166
|
+
];
|
|
167
|
+
return lines.join("\n");
|
|
168
|
+
}
|