context-mode 1.0.97 → 1.0.99
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/README.md +9 -7
- package/build/adapters/claude-code-base.js +4 -4
- package/build/adapters/codex/index.js +23 -1
- package/build/adapters/qwen-code/index.d.ts +1 -1
- package/build/adapters/qwen-code/index.js +110 -4
- package/build/cli.js +2 -0
- package/build/opencode-plugin.js +1 -1
- package/build/server.js +24 -21
- package/build/store.js +51 -4
- package/cli.bundle.mjs +101 -101
- package/configs/codex/AGENTS.md +1 -1
- package/configs/codex/hooks.json +14 -0
- package/configs/kilo/AGENTS.md +1 -1
- package/configs/openclaw/AGENTS.md +1 -1
- package/hooks/codex/stop.mjs +43 -0
- package/hooks/codex/userpromptsubmit.mjs +75 -0
- package/hooks/core/mcp-ready.mjs +57 -14
- package/openclaw.plugin.json +1 -1
- package/package.json +1 -1
- package/server.bundle.mjs +82 -82
- package/skills/context-mode-ops/agent-teams.md +1 -1
package/configs/codex/AGENTS.md
CHANGED
|
@@ -46,7 +46,7 @@ Terse like caveman. Technical substance exact. Only fluff die.
|
|
|
46
46
|
Drop: articles, filler (just/really/basically), pleasantries, hedging. Fragments OK. Short synonyms. Code unchanged.
|
|
47
47
|
Pattern: [thing] [action] [reason]. [next step]. Auto-expand for: security warnings, irreversible actions, user confusion.
|
|
48
48
|
Write artifacts to FILES — never inline. Return: file path + 1-line description.
|
|
49
|
-
Descriptive source labels for `
|
|
49
|
+
Descriptive source labels for `ctx_search(source: "label")`.
|
|
50
50
|
|
|
51
51
|
## ctx commands
|
|
52
52
|
|
package/configs/codex/hooks.json
CHANGED
|
@@ -20,6 +20,20 @@
|
|
|
20
20
|
{ "type": "command", "command": "context-mode hook codex sessionstart" }
|
|
21
21
|
]
|
|
22
22
|
}
|
|
23
|
+
],
|
|
24
|
+
"UserPromptSubmit": [
|
|
25
|
+
{
|
|
26
|
+
"hooks": [
|
|
27
|
+
{ "type": "command", "command": "context-mode hook codex userpromptsubmit" }
|
|
28
|
+
]
|
|
29
|
+
}
|
|
30
|
+
],
|
|
31
|
+
"Stop": [
|
|
32
|
+
{
|
|
33
|
+
"hooks": [
|
|
34
|
+
{ "type": "command", "command": "context-mode hook codex stop" }
|
|
35
|
+
]
|
|
36
|
+
}
|
|
23
37
|
]
|
|
24
38
|
}
|
|
25
39
|
}
|
package/configs/kilo/AGENTS.md
CHANGED
|
@@ -45,7 +45,7 @@ Terse like caveman. Technical substance exact. Only fluff die.
|
|
|
45
45
|
Drop: articles, filler (just/really/basically), pleasantries, hedging. Fragments OK. Short synonyms. Code unchanged.
|
|
46
46
|
Pattern: [thing] [action] [reason]. [next step]. Auto-expand for: security warnings, irreversible actions, user confusion.
|
|
47
47
|
Write artifacts to FILES — never inline. Return: file path + 1-line description.
|
|
48
|
-
Descriptive source labels for `
|
|
48
|
+
Descriptive source labels for `ctx_search(source: "label")`.
|
|
49
49
|
|
|
50
50
|
## ctx commands
|
|
51
51
|
|
|
@@ -45,7 +45,7 @@ Terse like caveman. Technical substance exact. Only fluff die.
|
|
|
45
45
|
Drop: articles, filler (just/really/basically), pleasantries, hedging. Fragments OK. Short synonyms. Code unchanged.
|
|
46
46
|
Pattern: [thing] [action] [reason]. [next step]. Auto-expand for: security warnings, irreversible actions, user confusion.
|
|
47
47
|
Write artifacts to FILES — never inline. Return: file path + 1-line description.
|
|
48
|
-
Descriptive source labels for `
|
|
48
|
+
Descriptive source labels for `ctx_search(source: "label")`.
|
|
49
49
|
|
|
50
50
|
## ctx commands
|
|
51
51
|
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import "../suppress-stderr.mjs";
|
|
3
|
+
import "../ensure-deps.mjs";
|
|
4
|
+
/**
|
|
5
|
+
* Codex CLI Stop hook — record turn/session end state for continuity.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { readStdin, parseStdin, getSessionId, getSessionDBPath, getInputProjectDir, CODEX_OPTS } from "../session-helpers.mjs";
|
|
9
|
+
import { createSessionLoaders } from "../session-loaders.mjs";
|
|
10
|
+
import { dirname } from "node:path";
|
|
11
|
+
import { fileURLToPath } from "node:url";
|
|
12
|
+
|
|
13
|
+
const HOOK_DIR = dirname(fileURLToPath(import.meta.url));
|
|
14
|
+
const { loadSessionDB } = createSessionLoaders(HOOK_DIR);
|
|
15
|
+
const OPTS = CODEX_OPTS;
|
|
16
|
+
|
|
17
|
+
try {
|
|
18
|
+
const raw = await readStdin();
|
|
19
|
+
const input = parseStdin(raw);
|
|
20
|
+
const projectDir = getInputProjectDir(input, OPTS);
|
|
21
|
+
|
|
22
|
+
const { SessionDB } = await loadSessionDB();
|
|
23
|
+
const dbPath = getSessionDBPath(OPTS);
|
|
24
|
+
const db = new SessionDB({ dbPath });
|
|
25
|
+
const sessionId = getSessionId(input, OPTS);
|
|
26
|
+
|
|
27
|
+
db.ensureSession(sessionId, projectDir);
|
|
28
|
+
db.insertEvent(sessionId, {
|
|
29
|
+
type: "session_end",
|
|
30
|
+
status: "completed",
|
|
31
|
+
stop_hook_active: input.stop_hook_active ?? false,
|
|
32
|
+
last_assistant_message: typeof input.last_assistant_message === "string"
|
|
33
|
+
? input.last_assistant_message.slice(0, 2000)
|
|
34
|
+
: null,
|
|
35
|
+
}, "Stop");
|
|
36
|
+
|
|
37
|
+
db.close();
|
|
38
|
+
} catch {
|
|
39
|
+
// Codex hooks must not block the session.
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
process.stdout.write("{}\n");
|
|
43
|
+
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import "../suppress-stderr.mjs";
|
|
3
|
+
import "../ensure-deps.mjs";
|
|
4
|
+
/**
|
|
5
|
+
* Codex CLI UserPromptSubmit hook — capture user prompts for continuity.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { readStdin, parseStdin, getSessionId, getSessionDBPath, getInputProjectDir, CODEX_OPTS } from "../session-helpers.mjs";
|
|
9
|
+
import { createSessionLoaders, attributeAndInsertEvents } from "../session-loaders.mjs";
|
|
10
|
+
import { dirname } from "node:path";
|
|
11
|
+
import { fileURLToPath } from "node:url";
|
|
12
|
+
|
|
13
|
+
const HOOK_DIR = dirname(fileURLToPath(import.meta.url));
|
|
14
|
+
const { loadSessionDB, loadExtract, loadProjectAttribution } = createSessionLoaders(HOOK_DIR);
|
|
15
|
+
const OPTS = CODEX_OPTS;
|
|
16
|
+
|
|
17
|
+
try {
|
|
18
|
+
const raw = await readStdin();
|
|
19
|
+
const input = parseStdin(raw);
|
|
20
|
+
const projectDir = getInputProjectDir(input, OPTS);
|
|
21
|
+
|
|
22
|
+
const prompt = input.prompt ?? input.message ?? "";
|
|
23
|
+
const trimmed = (prompt || "").trim();
|
|
24
|
+
|
|
25
|
+
const isSystemMessage = trimmed.startsWith("<task-notification>")
|
|
26
|
+
|| trimmed.startsWith("<system-reminder>")
|
|
27
|
+
|| trimmed.startsWith("<context_guidance>")
|
|
28
|
+
|| trimmed.startsWith("<tool-result>");
|
|
29
|
+
|
|
30
|
+
if (trimmed.length > 0 && !isSystemMessage) {
|
|
31
|
+
const { SessionDB } = await loadSessionDB();
|
|
32
|
+
const { extractUserEvents } = await loadExtract();
|
|
33
|
+
const { resolveProjectAttributions } = await loadProjectAttribution();
|
|
34
|
+
const dbPath = getSessionDBPath(OPTS);
|
|
35
|
+
const db = new SessionDB({ dbPath });
|
|
36
|
+
const sessionId = getSessionId(input, OPTS);
|
|
37
|
+
|
|
38
|
+
db.ensureSession(sessionId, projectDir);
|
|
39
|
+
|
|
40
|
+
const promptEvent = {
|
|
41
|
+
type: "user_prompt",
|
|
42
|
+
category: "prompt",
|
|
43
|
+
data: prompt,
|
|
44
|
+
priority: 1,
|
|
45
|
+
};
|
|
46
|
+
const promptAttributions = attributeAndInsertEvents(
|
|
47
|
+
db, sessionId, [promptEvent], input, projectDir, "UserPromptSubmit", resolveProjectAttributions,
|
|
48
|
+
);
|
|
49
|
+
|
|
50
|
+
const userEvents = extractUserEvents(trimmed);
|
|
51
|
+
const savedLastKnown = promptAttributions[0]?.projectDir || null;
|
|
52
|
+
const sessionStats = db.getSessionStats(sessionId);
|
|
53
|
+
const lastKnownProjectDir = typeof db.getLatestAttributedProjectDir === "function"
|
|
54
|
+
? db.getLatestAttributedProjectDir(sessionId)
|
|
55
|
+
: null;
|
|
56
|
+
const userAttributions = resolveProjectAttributions(userEvents, {
|
|
57
|
+
sessionOriginDir: sessionStats?.project_dir || projectDir,
|
|
58
|
+
inputProjectDir: projectDir,
|
|
59
|
+
workspaceRoots: Array.isArray(input.workspace_roots) ? input.workspace_roots : [],
|
|
60
|
+
lastKnownProjectDir: savedLastKnown || lastKnownProjectDir,
|
|
61
|
+
});
|
|
62
|
+
for (let i = 0; i < userEvents.length; i++) {
|
|
63
|
+
db.insertEvent(sessionId, userEvents[i], "UserPromptSubmit", userAttributions[i]);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
db.close();
|
|
67
|
+
}
|
|
68
|
+
} catch {
|
|
69
|
+
// Codex hooks must not block the session.
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
process.stdout.write(JSON.stringify({
|
|
73
|
+
hookSpecificOutput: { hookEventName: "UserPromptSubmit", additionalContext: "" },
|
|
74
|
+
}) + "\n");
|
|
75
|
+
|
package/hooks/core/mcp-ready.mjs
CHANGED
|
@@ -1,30 +1,73 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* MCP readiness sentinel — checks if MCP server has started.
|
|
3
|
-
* Server writes sentinel (containing its PID) after connect(),
|
|
4
|
-
* hooks check before denying tools that redirect to MCP alternatives.
|
|
5
3
|
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
4
|
+
* Server writes sentinel (containing its PID) after connect().
|
|
5
|
+
* Hooks scan for any live sentinel to detect MCP readiness.
|
|
6
|
+
*
|
|
7
|
+
* Fix for #347: Claude Code spawns hooks via `bash -c "node ..."` on Linux/WSL2.
|
|
8
|
+
* The intermediate shell makes process.ppid point to a transient bash PID, not
|
|
9
|
+
* Claude Code. Directory-scan + PID liveness probe works regardless of spawn topology.
|
|
10
|
+
*
|
|
11
|
+
* Sentinel path: <tmpRoot>/context-mode-mcp-ready-<MCP_PID>
|
|
12
|
+
* Scan: glob all context-mode-mcp-ready-* files, probe each PID.
|
|
8
13
|
*/
|
|
9
|
-
import { readFileSync } from "node:fs";
|
|
14
|
+
import { readFileSync, readdirSync, unlinkSync } from "node:fs";
|
|
10
15
|
import { tmpdir } from "node:os";
|
|
11
|
-
import {
|
|
16
|
+
import { join } from "node:path";
|
|
17
|
+
|
|
18
|
+
const SENTINEL_PREFIX = "context-mode-mcp-ready-";
|
|
19
|
+
|
|
20
|
+
/** Resolve the temp root — hardcoded /tmp on Unix to avoid TMPDIR mismatch. */
|
|
21
|
+
export function sentinelDir() {
|
|
22
|
+
return process.platform === "win32" ? tmpdir() : "/tmp";
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Build sentinel path for a given PID.
|
|
27
|
+
* Used by server.ts to write its own sentinel.
|
|
28
|
+
*/
|
|
29
|
+
export function sentinelPathForPid(pid) {
|
|
30
|
+
return join(sentinelDir(), `${SENTINEL_PREFIX}${pid}`);
|
|
31
|
+
}
|
|
12
32
|
|
|
13
|
-
/**
|
|
33
|
+
/**
|
|
34
|
+
* @deprecated Use sentinelPathForPid(process.pid) from server.ts.
|
|
35
|
+
* Kept for backward compat during migration — tests that still
|
|
36
|
+
* write sentinels with process.ppid will work for one release cycle.
|
|
37
|
+
*/
|
|
14
38
|
export function sentinelPath() {
|
|
15
|
-
return
|
|
39
|
+
return join(sentinelDir(), `${SENTINEL_PREFIX}${process.ppid}`);
|
|
16
40
|
}
|
|
17
41
|
|
|
18
42
|
/**
|
|
19
|
-
* Check if MCP server is alive by
|
|
20
|
-
*
|
|
21
|
-
*
|
|
43
|
+
* Check if any MCP server is alive by scanning sentinel files.
|
|
44
|
+
*
|
|
45
|
+
* Scans sentinelDir() for context-mode-mcp-ready-* files, reads the PID
|
|
46
|
+
* from each, and probes with kill(pid, 0). Cleans up stale sentinels
|
|
47
|
+
* from crashed servers.
|
|
48
|
+
*
|
|
49
|
+
* Handles:
|
|
50
|
+
* - PPID mismatch (WSL2 shell wrappers) — no ppid dependency
|
|
51
|
+
* - Stale sentinels (SIGKILL, OOM) — PID liveness check
|
|
52
|
+
* - TMPDIR mismatch — hardcoded /tmp on Unix
|
|
22
53
|
*/
|
|
23
54
|
export function isMCPReady() {
|
|
24
55
|
try {
|
|
25
|
-
const
|
|
26
|
-
|
|
27
|
-
|
|
56
|
+
const dir = sentinelDir();
|
|
57
|
+
const files = readdirSync(dir).filter(f => f.startsWith(SENTINEL_PREFIX));
|
|
58
|
+
for (const f of files) {
|
|
59
|
+
const fullPath = join(dir, f);
|
|
60
|
+
try {
|
|
61
|
+
const pid = parseInt(readFileSync(fullPath, "utf8"), 10);
|
|
62
|
+
if (isNaN(pid)) continue;
|
|
63
|
+
process.kill(pid, 0); // throws if process doesn't exist
|
|
64
|
+
return true;
|
|
65
|
+
} catch {
|
|
66
|
+
// Dead PID or unreadable — clean up stale sentinel
|
|
67
|
+
try { unlinkSync(fullPath); } catch {}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
return false;
|
|
28
71
|
} catch {
|
|
29
72
|
return false;
|
|
30
73
|
}
|
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.99",
|
|
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.99",
|
|
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",
|