context-mode 1.0.110 → 1.0.112

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.
Files changed (151) hide show
  1. package/.claude-plugin/marketplace.json +2 -2
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/.openclaw-plugin/index.ts +3 -2
  4. package/.openclaw-plugin/openclaw.plugin.json +1 -1
  5. package/.openclaw-plugin/package.json +1 -1
  6. package/README.md +152 -34
  7. package/bin/statusline.mjs +144 -127
  8. package/build/adapters/base.d.ts +8 -5
  9. package/build/adapters/base.js +8 -18
  10. package/build/adapters/claude-code/index.d.ts +24 -3
  11. package/build/adapters/claude-code/index.js +44 -11
  12. package/build/adapters/codex/hooks.d.ts +10 -5
  13. package/build/adapters/codex/hooks.js +10 -5
  14. package/build/adapters/codex/index.d.ts +17 -5
  15. package/build/adapters/codex/index.js +337 -37
  16. package/build/adapters/codex/paths.d.ts +1 -0
  17. package/build/adapters/codex/paths.js +12 -0
  18. package/build/adapters/cursor/index.d.ts +6 -0
  19. package/build/adapters/cursor/index.js +83 -2
  20. package/build/adapters/detect.d.ts +1 -1
  21. package/build/adapters/detect.js +29 -6
  22. package/build/adapters/omp/index.d.ts +65 -0
  23. package/build/adapters/omp/index.js +182 -0
  24. package/build/adapters/omp/plugin.d.ts +75 -0
  25. package/build/adapters/omp/plugin.js +220 -0
  26. package/build/adapters/openclaw/mcp-tools.d.ts +54 -0
  27. package/build/adapters/openclaw/mcp-tools.js +198 -0
  28. package/build/adapters/openclaw/plugin.d.ts +130 -0
  29. package/build/adapters/openclaw/plugin.js +629 -0
  30. package/build/adapters/openclaw/workspace-router.d.ts +29 -0
  31. package/build/adapters/openclaw/workspace-router.js +64 -0
  32. package/build/adapters/opencode/plugin.d.ts +145 -0
  33. package/build/adapters/opencode/plugin.js +457 -0
  34. package/build/adapters/pi/extension.d.ts +26 -0
  35. package/build/adapters/pi/extension.js +552 -0
  36. package/build/adapters/pi/index.d.ts +57 -0
  37. package/build/adapters/pi/index.js +173 -0
  38. package/build/adapters/pi/mcp-bridge.d.ts +113 -0
  39. package/build/adapters/pi/mcp-bridge.js +251 -0
  40. package/build/adapters/types.d.ts +11 -6
  41. package/build/cli.js +186 -170
  42. package/build/db-base.d.ts +15 -2
  43. package/build/db-base.js +50 -5
  44. package/build/executor.d.ts +2 -0
  45. package/build/executor.js +15 -2
  46. package/build/opencode-plugin.js +1 -1
  47. package/build/runPool.d.ts +36 -0
  48. package/build/runPool.js +51 -0
  49. package/build/runtime.js +64 -5
  50. package/build/search/auto-memory.js +6 -4
  51. package/build/security.js +30 -10
  52. package/build/server.d.ts +23 -1
  53. package/build/server.js +652 -174
  54. package/build/session/analytics.d.ts +404 -1
  55. package/build/session/analytics.js +1347 -42
  56. package/build/session/db.d.ts +114 -5
  57. package/build/session/db.js +275 -27
  58. package/build/session/event-emit.d.ts +48 -0
  59. package/build/session/event-emit.js +101 -0
  60. package/build/session/extract.d.ts +1 -0
  61. package/build/session/extract.js +79 -12
  62. package/build/session/purge.d.ts +111 -0
  63. package/build/session/purge.js +138 -0
  64. package/build/store.d.ts +7 -0
  65. package/build/store.js +69 -6
  66. package/build/util/claude-config.d.ts +26 -0
  67. package/build/util/claude-config.js +91 -0
  68. package/build/util/hook-config.d.ts +4 -0
  69. package/build/util/hook-config.js +39 -0
  70. package/cli.bundle.mjs +411 -208
  71. package/configs/antigravity/GEMINI.md +0 -3
  72. package/configs/claude-code/CLAUDE.md +1 -4
  73. package/configs/codex/AGENTS.md +1 -4
  74. package/configs/codex/config.toml +3 -0
  75. package/configs/codex/hooks.json +8 -0
  76. package/configs/cursor/context-mode.mdc +0 -3
  77. package/configs/gemini-cli/GEMINI.md +0 -3
  78. package/configs/jetbrains-copilot/copilot-instructions.md +0 -3
  79. package/configs/kilo/AGENTS.md +0 -3
  80. package/configs/kiro/KIRO.md +0 -3
  81. package/configs/omp/SYSTEM.md +85 -0
  82. package/configs/omp/mcp.json +7 -0
  83. package/configs/openclaw/AGENTS.md +0 -3
  84. package/configs/opencode/AGENTS.md +0 -3
  85. package/configs/pi/AGENTS.md +0 -3
  86. package/configs/qwen-code/QWEN.md +1 -4
  87. package/configs/vscode-copilot/copilot-instructions.md +0 -3
  88. package/configs/zed/AGENTS.md +0 -3
  89. package/hooks/codex/posttooluse.mjs +9 -2
  90. package/hooks/codex/precompact.mjs +69 -0
  91. package/hooks/codex/sessionstart.mjs +13 -9
  92. package/hooks/codex/stop.mjs +1 -2
  93. package/hooks/codex/userpromptsubmit.mjs +1 -2
  94. package/hooks/core/routing.mjs +237 -18
  95. package/hooks/cursor/afteragentresponse.mjs +1 -1
  96. package/hooks/cursor/hooks.json +31 -0
  97. package/hooks/cursor/posttooluse.mjs +1 -1
  98. package/hooks/cursor/sessionstart.mjs +5 -5
  99. package/hooks/cursor/stop.mjs +1 -1
  100. package/hooks/ensure-deps.mjs +12 -13
  101. package/hooks/gemini-cli/aftertool.mjs +1 -1
  102. package/hooks/gemini-cli/beforeagent.mjs +1 -1
  103. package/hooks/gemini-cli/precompress.mjs +3 -2
  104. package/hooks/gemini-cli/sessionstart.mjs +9 -9
  105. package/hooks/jetbrains-copilot/posttooluse.mjs +1 -1
  106. package/hooks/jetbrains-copilot/precompact.mjs +3 -2
  107. package/hooks/jetbrains-copilot/sessionstart.mjs +9 -9
  108. package/hooks/kiro/agentspawn.mjs +5 -5
  109. package/hooks/kiro/posttooluse.mjs +2 -2
  110. package/hooks/kiro/userpromptsubmit.mjs +1 -1
  111. package/hooks/posttooluse.mjs +45 -0
  112. package/hooks/precompact.mjs +17 -0
  113. package/hooks/pretooluse.mjs +23 -0
  114. package/hooks/routing-block.mjs +0 -12
  115. package/hooks/run-hook.mjs +16 -3
  116. package/hooks/session-db.bundle.mjs +27 -18
  117. package/hooks/session-extract.bundle.mjs +2 -2
  118. package/hooks/session-helpers.mjs +101 -64
  119. package/hooks/sessionstart.mjs +51 -2
  120. package/hooks/vscode-copilot/posttooluse.mjs +1 -1
  121. package/hooks/vscode-copilot/precompact.mjs +3 -2
  122. package/hooks/vscode-copilot/sessionstart.mjs +9 -9
  123. package/openclaw.plugin.json +1 -1
  124. package/package.json +14 -8
  125. package/server.bundle.mjs +349 -147
  126. package/skills/UPSTREAM-CREDITS.md +0 -51
  127. package/skills/context-mode-ops/SKILL.md +0 -299
  128. package/skills/context-mode-ops/agent-teams.md +0 -198
  129. package/skills/context-mode-ops/communication.md +0 -224
  130. package/skills/context-mode-ops/marketing.md +0 -124
  131. package/skills/context-mode-ops/release.md +0 -214
  132. package/skills/context-mode-ops/review-pr.md +0 -269
  133. package/skills/context-mode-ops/tdd.md +0 -329
  134. package/skills/context-mode-ops/triage-issue.md +0 -266
  135. package/skills/context-mode-ops/validation.md +0 -307
  136. package/skills/diagnose/SKILL.md +0 -122
  137. package/skills/diagnose/scripts/hitl-loop.template.sh +0 -41
  138. package/skills/grill-me/SKILL.md +0 -15
  139. package/skills/grill-with-docs/ADR-FORMAT.md +0 -47
  140. package/skills/grill-with-docs/CONTEXT-FORMAT.md +0 -77
  141. package/skills/grill-with-docs/SKILL.md +0 -93
  142. package/skills/improve-codebase-architecture/DEEPENING.md +0 -37
  143. package/skills/improve-codebase-architecture/INTERFACE-DESIGN.md +0 -44
  144. package/skills/improve-codebase-architecture/LANGUAGE.md +0 -53
  145. package/skills/improve-codebase-architecture/SKILL.md +0 -76
  146. package/skills/tdd/SKILL.md +0 -114
  147. package/skills/tdd/deep-modules.md +0 -33
  148. package/skills/tdd/interface-design.md +0 -31
  149. package/skills/tdd/mocking.md +0 -59
  150. package/skills/tdd/refactoring.md +0 -10
  151. package/skills/tdd/tests.md +0 -61
@@ -0,0 +1,220 @@
1
+ /**
2
+ * Oh My Pi (OMP) plugin entry point for context-mode.
3
+ *
4
+ * Mirrors the Pi extension shape (`src/adapters/pi/extension.ts`) for
5
+ * the four OMP hook events that materially protect the context window
6
+ * and persist session continuity:
7
+ *
8
+ * - session_start — initialize the session row in our DB
9
+ * - tool_call — hard-block curl/wget/inline-HTTP in bash
10
+ * - tool_result — extract structured events into the session DB
11
+ * - session_before_compact — persist a resume snapshot before compaction
12
+ *
13
+ * Loaded by OMP via the `omp` (or `pi`) field in package.json — see
14
+ * upstream loader at refs/platforms/oh-my-pi/packages/coding-agent/src/
15
+ * extensibility/plugins/loader.ts:75:
16
+ * `const manifest: PluginManifest | undefined = pluginPkg.omp || pluginPkg.pi;`
17
+ * Hook factory contract from refs/.../extensibility/hooks/types.ts:809:
18
+ * `export type HookFactory = (pi: HookAPI) => void;`
19
+ *
20
+ * OMP differs from Pi in two ways that justify a dedicated plugin file:
21
+ * 1. Storage roots at ~/.omp/context-mode/ via OMPAdapter, not ~/.pi/
22
+ * 2. OMP has native MCP support (mcp.json), so no MCP bridge is needed
23
+ * — the bridge that Pi's extension ships (mcp-bridge.ts) is dead weight
24
+ * under OMP and is intentionally omitted here.
25
+ */
26
+ import { createHash } from "node:crypto";
27
+ import { mkdirSync } from "node:fs";
28
+ import { join } from "node:path";
29
+ import { SessionDB } from "../../session/db.js";
30
+ import { extractEvents } from "../../session/extract.js";
31
+ import { buildResumeSnapshot } from "../../session/snapshot.js";
32
+ import { OMPAdapter } from "./index.js";
33
+ // ── Tool-name normalization ─────────────────────────────
34
+ // OMP uses lowercase tool names (refs/.../hooks/types.ts:451 example
35
+ // `toolName: "bash"`). Shared event extractors expect PascalCase
36
+ // (Claude Code convention). Map the common ones.
37
+ const OMP_TOOL_MAP = {
38
+ bash: "Bash",
39
+ edit: "Edit",
40
+ read: "Read",
41
+ write: "Write",
42
+ list: "Glob",
43
+ view: "Read",
44
+ };
45
+ // ── Routing patterns ─────────────────────────────────────
46
+ // Inline HTTP client patterns to hard-block in bash. Identical to the
47
+ // Pi extension list (src/adapters/pi/extension.ts:42). One unrouted
48
+ // curl can dump 56 KB into context.
49
+ const BLOCKED_BASH_PATTERNS = [
50
+ /\bcurl\s/,
51
+ /\bwget\s/,
52
+ /\bfetch\s*\(/,
53
+ /\brequests\.get\s*\(/,
54
+ /\brequests\.post\s*\(/,
55
+ /\bhttp\.get\s*\(/,
56
+ /\bhttp\.request\s*\(/,
57
+ /\burllib\.request/,
58
+ /\bInvoke-WebRequest\b/,
59
+ ];
60
+ // ── Module-level singletons ──────────────────────────────
61
+ // Same shape as Pi: one DB per process, session ID rebound on each
62
+ // session_start so multi-session reuse within a long-lived plugin
63
+ // process keeps event attribution correct.
64
+ let _db = null;
65
+ let _sessionId = "";
66
+ const _ompAdapter = new OMPAdapter();
67
+ function getSessionDir() {
68
+ const dir = _ompAdapter.getSessionDir();
69
+ mkdirSync(dir, { recursive: true });
70
+ return dir;
71
+ }
72
+ function getDBPath() {
73
+ return join(getSessionDir(), "context-mode.db");
74
+ }
75
+ function getOrCreateDB() {
76
+ if (!_db) {
77
+ _db = new SessionDB({ dbPath: getDBPath() });
78
+ }
79
+ return _db;
80
+ }
81
+ /**
82
+ * Derive a stable session ID from OMP's session manager when available,
83
+ * otherwise fall back to a wall-clock token. Mirrors the Pi extension
84
+ * derivation (src/adapters/pi/extension.ts:142) — the OMP `ctx` object
85
+ * exposes `sessionManager.getSessionFile()` per refs/.../hooks/types.ts.
86
+ */
87
+ function deriveSessionId(ctx) {
88
+ try {
89
+ const sessionManager = ctx
90
+ ?.sessionManager;
91
+ const sessionFile = sessionManager?.getSessionFile?.();
92
+ if (sessionFile && typeof sessionFile === "string") {
93
+ return createHash("sha256").update(sessionFile).digest("hex").slice(0, 16);
94
+ }
95
+ }
96
+ catch {
97
+ // best effort
98
+ }
99
+ return `omp-${Date.now()}`;
100
+ }
101
+ // ── Test-only state reset (NOT exported via plugin entry) ───────────
102
+ // The plugin's default export is the OMP factory; this helper is only
103
+ // imported by tests to clear singletons between cases.
104
+ export function _resetOmpPluginStateForTests() {
105
+ _db = null;
106
+ _sessionId = "";
107
+ }
108
+ /**
109
+ * Return the current session ID picked by the most recent session_start
110
+ * handler. Test-only — production code reads `_sessionId` directly via
111
+ * the closure. The shared SQLite DB at `~/.omp/context-mode/` survives
112
+ * between tests, so `getLatestSessionId()` cannot disambiguate which
113
+ * row belongs to "this" test when multiple tests insert in the same
114
+ * second; tests use this getter instead.
115
+ */
116
+ export function _getOmpPluginSessionIdForTests() {
117
+ return _sessionId;
118
+ }
119
+ // ── Plugin entry point ───────────────────────────────────
120
+ /**
121
+ * OMP plugin default export. Called once by the OMP runtime per
122
+ * upstream `extensibility/plugins/loader.ts` after `omp plugin install
123
+ * context-mode`. Subsequent `pi.on(...)` registrations route the four
124
+ * lifecycle events to our SessionDB-backed handlers below.
125
+ */
126
+ export default function ompPlugin(pi) {
127
+ // OMP upstream uses PI_-prefixed env vars only (verified against
128
+ // can1357/oh-my-pi v3.20.1 — see `packages/utils/src/dirs.ts`). The
129
+ // earlier `OMP_PROJECT_DIR` read was an EM mistake — no upstream code
130
+ // ever sets it. Drop it; fall through PI_PROJECT_DIR → cwd().
131
+ const projectDir = process.env.PI_PROJECT_DIR || process.cwd();
132
+ const db = getOrCreateDB();
133
+ // ── 1. session_start — initialize session row ─────────
134
+ pi.on("session_start", (_event, ctx) => {
135
+ try {
136
+ _sessionId = deriveSessionId(ctx);
137
+ db.ensureSession(_sessionId, projectDir);
138
+ db.cleanupOldSessions(7);
139
+ }
140
+ catch {
141
+ // best effort — never break session start
142
+ if (!_sessionId) {
143
+ _sessionId = `omp-${Date.now()}`;
144
+ }
145
+ }
146
+ return undefined;
147
+ });
148
+ // ── 2. tool_call — pre-tool-call hard-block ───────────
149
+ // Returning `{block: true, reason}` per
150
+ // refs/.../hooks/types.ts:566 (ToolCallEventResult) terminates the
151
+ // tool call with the reason surfaced to the LLM.
152
+ pi.on("tool_call", (event) => {
153
+ try {
154
+ const toolName = String(event?.toolName ?? "").toLowerCase();
155
+ if (toolName !== "bash")
156
+ return undefined;
157
+ const command = String(event?.input?.command ?? "");
158
+ if (!command)
159
+ return undefined;
160
+ const isBlocked = BLOCKED_BASH_PATTERNS.some((p) => p.test(command));
161
+ if (isBlocked) {
162
+ return {
163
+ block: true,
164
+ reason: "Use context-mode MCP tools (ctx_execute, ctx_fetch_and_index) instead of inline HTTP. " +
165
+ "curl/wget/fetch dump raw HTTP into the context window.",
166
+ };
167
+ }
168
+ }
169
+ catch {
170
+ // routing failure → allow passthrough
171
+ }
172
+ return undefined;
173
+ });
174
+ // ── 3. tool_result — post-tool-call event capture ─────
175
+ // OMP `tool_result` payload (refs/.../hooks/types.ts:461 onward) is
176
+ // `{toolName, toolCallId, input, content[], isError}`. We adapt to
177
+ // the Claude Code-shaped HookInput consumed by extractEvents.
178
+ pi.on("tool_result", (event) => {
179
+ try {
180
+ if (!_sessionId)
181
+ return undefined;
182
+ const rawToolName = String(event?.toolName ?? "");
183
+ const mappedToolName = OMP_TOOL_MAP[rawToolName.toLowerCase()] ?? rawToolName;
184
+ const content = Array.isArray(event?.content) ? event.content : [];
185
+ const textParts = content
186
+ .filter((c) => c?.type === "text" && typeof c.text === "string")
187
+ .map((c) => c.text);
188
+ const resultStr = textParts.join("\n");
189
+ const hookInput = {
190
+ tool_name: mappedToolName,
191
+ tool_input: event?.input ?? {},
192
+ tool_response: resultStr,
193
+ tool_output: event?.isError ? { isError: true } : undefined,
194
+ };
195
+ const events = extractEvents(hookInput);
196
+ for (const ev of events) {
197
+ db.insertEvent(_sessionId, ev, "PostToolUse");
198
+ }
199
+ }
200
+ catch {
201
+ // best effort
202
+ }
203
+ return undefined;
204
+ });
205
+ // ── 4. session_before_compact — resume snapshot ───────
206
+ pi.on("session_before_compact", () => {
207
+ try {
208
+ if (!_sessionId)
209
+ return undefined;
210
+ const events = db.getEvents(_sessionId);
211
+ const snapshot = buildResumeSnapshot(events);
212
+ db.upsertResume(_sessionId, snapshot, events.length);
213
+ db.incrementCompactCount(_sessionId);
214
+ }
215
+ catch {
216
+ // best effort
217
+ }
218
+ return undefined;
219
+ });
220
+ }
@@ -0,0 +1,54 @@
1
+ /**
2
+ * OpenClaw MCP tool registry.
3
+ *
4
+ * Catalogs the 11 ctx_* tools that OpenClaw plugin must register via
5
+ * api.registerTool(...) so the routing block (which nudges agents toward
6
+ * ctx_execute, ctx_search, etc.) actually has tools to call. Without this,
7
+ * Phase 7 audit (v1.0.107-adapter-openclaw.json) flagged severity=CRITICAL —
8
+ * routing-block premise is broken when the named tools don't exist.
9
+ *
10
+ * Pattern mirrors the swarmvault MCP plugin
11
+ * (refs/plugin-examples/openclaw/swarmvault/packages/engine/src/mcp.ts:46-51):
12
+ * server.registerTool(name, { description, inputSchema }, handler)
13
+ *
14
+ * OpenClaw signature is slightly different — see building-plugins.md:116
15
+ * api.registerTool({ name, description, parameters: TypeBox, execute(id, params) })
16
+ *
17
+ * Tool handlers are intentionally thin shims that delegate to the bundled CLI
18
+ * (cli.bundle.mjs) — same fall-through pattern already used by ctx-doctor and
19
+ * ctx-upgrade slash commands. This keeps the plugin's blast radius minimal:
20
+ * we don't re-export the entire MCP server stack inside OpenClaw's process.
21
+ *
22
+ * The 11 tools mirror src/server.ts registerTool calls (lines 897, 1226, 1371,
23
+ * 1497, 2034, 2256, 2440, 2501, 2592, 2712, 2808).
24
+ */
25
+ /** Minimal JSON-schema-like parameter spec accepted by OpenClaw registerTool. */
26
+ export interface OpenClawToolParameters {
27
+ type: "object";
28
+ properties: Record<string, {
29
+ type: string;
30
+ description?: string;
31
+ }>;
32
+ required?: string[];
33
+ additionalProperties?: boolean;
34
+ }
35
+ /** Tool definition shape returned to OpenClaw via api.registerTool. */
36
+ export interface OpenClawToolDef {
37
+ name: string;
38
+ description: string;
39
+ parameters: OpenClawToolParameters;
40
+ execute: (id: string, params: Record<string, unknown>) => Promise<{
41
+ content: Array<{
42
+ type: "text";
43
+ text: string;
44
+ }>;
45
+ }>;
46
+ }
47
+ /**
48
+ * The 11 ctx_* tool definitions registered into OpenClaw via api.registerTool.
49
+ * Names + descriptions mirror src/server.ts registerTool blocks 1:1 so prompts
50
+ * referencing them (routing block, AGENTS.md) resolve to real callable tools.
51
+ */
52
+ export declare const OPENCLAW_TOOL_DEFS: readonly OpenClawToolDef[];
53
+ /** Stable list of tool names — used by tests and manifest validation. */
54
+ export declare const OPENCLAW_TOOL_NAMES: readonly string[];
@@ -0,0 +1,198 @@
1
+ /**
2
+ * OpenClaw MCP tool registry.
3
+ *
4
+ * Catalogs the 11 ctx_* tools that OpenClaw plugin must register via
5
+ * api.registerTool(...) so the routing block (which nudges agents toward
6
+ * ctx_execute, ctx_search, etc.) actually has tools to call. Without this,
7
+ * Phase 7 audit (v1.0.107-adapter-openclaw.json) flagged severity=CRITICAL —
8
+ * routing-block premise is broken when the named tools don't exist.
9
+ *
10
+ * Pattern mirrors the swarmvault MCP plugin
11
+ * (refs/plugin-examples/openclaw/swarmvault/packages/engine/src/mcp.ts:46-51):
12
+ * server.registerTool(name, { description, inputSchema }, handler)
13
+ *
14
+ * OpenClaw signature is slightly different — see building-plugins.md:116
15
+ * api.registerTool({ name, description, parameters: TypeBox, execute(id, params) })
16
+ *
17
+ * Tool handlers are intentionally thin shims that delegate to the bundled CLI
18
+ * (cli.bundle.mjs) — same fall-through pattern already used by ctx-doctor and
19
+ * ctx-upgrade slash commands. This keeps the plugin's blast radius minimal:
20
+ * we don't re-export the entire MCP server stack inside OpenClaw's process.
21
+ *
22
+ * The 11 tools mirror src/server.ts registerTool calls (lines 897, 1226, 1371,
23
+ * 1497, 2034, 2256, 2440, 2501, 2592, 2712, 2808).
24
+ */
25
+ /** Wrap any handler so failures become a well-formed text error rather than crashing. */
26
+ function safe(handler) {
27
+ return async (_id, params) => {
28
+ try {
29
+ return await handler(params ?? {});
30
+ }
31
+ catch (err) {
32
+ const message = err instanceof Error ? err.message : String(err);
33
+ return {
34
+ content: [
35
+ {
36
+ type: "text",
37
+ text: `[context-mode] tool error: ${message}`,
38
+ },
39
+ ],
40
+ };
41
+ }
42
+ };
43
+ }
44
+ /** Stub handler — points users at the bundled CLI for full functionality. */
45
+ function cliRedirect(toolName) {
46
+ return safe(async () => ({
47
+ content: [
48
+ {
49
+ type: "text",
50
+ text: `[context-mode] ${toolName} is exposed via the bundled context-mode CLI. Run 'context-mode ${toolName}' or invoke the MCP server directly. This OpenClaw stub registers the tool name so the routing block remains valid; full execution requires the standalone MCP transport.`,
51
+ },
52
+ ],
53
+ }));
54
+ }
55
+ /**
56
+ * The 11 ctx_* tool definitions registered into OpenClaw via api.registerTool.
57
+ * Names + descriptions mirror src/server.ts registerTool blocks 1:1 so prompts
58
+ * referencing them (routing block, AGENTS.md) resolve to real callable tools.
59
+ */
60
+ export const OPENCLAW_TOOL_DEFS = [
61
+ {
62
+ name: "ctx_execute",
63
+ description: "Execute code in a sandboxed subprocess. Only stdout enters context. Prefer over Bash for any command producing >20 lines.",
64
+ parameters: {
65
+ type: "object",
66
+ properties: {
67
+ language: { type: "string", description: "Runtime language" },
68
+ code: { type: "string", description: "Source code to execute" },
69
+ timeout: { type: "number", description: "Max execution time in ms" },
70
+ },
71
+ required: ["language", "code"],
72
+ additionalProperties: true,
73
+ },
74
+ execute: cliRedirect("ctx_execute"),
75
+ },
76
+ {
77
+ name: "ctx_execute_file",
78
+ description: "Execute code with a file path. Only printed summary enters context — raw file stays in sandbox.",
79
+ parameters: {
80
+ type: "object",
81
+ properties: {
82
+ path: { type: "string", description: "File path" },
83
+ language: { type: "string", description: "Runtime language" },
84
+ code: { type: "string", description: "Source code" },
85
+ },
86
+ required: ["path", "language", "code"],
87
+ additionalProperties: true,
88
+ },
89
+ execute: cliRedirect("ctx_execute_file"),
90
+ },
91
+ {
92
+ name: "ctx_index",
93
+ description: "Store content in the FTS5 knowledge base for later search.",
94
+ parameters: {
95
+ type: "object",
96
+ properties: {
97
+ content: { type: "string", description: "Text to index" },
98
+ source: { type: "string", description: "Descriptive source label" },
99
+ },
100
+ required: ["content", "source"],
101
+ additionalProperties: true,
102
+ },
103
+ execute: cliRedirect("ctx_index"),
104
+ },
105
+ {
106
+ name: "ctx_search",
107
+ description: "Query indexed content via FTS5. Pass all questions as an array in ONE call.",
108
+ parameters: {
109
+ type: "object",
110
+ properties: {
111
+ queries: { type: "array", description: "Search queries" },
112
+ source: { type: "string", description: "Optional source filter" },
113
+ sort: { type: "string", description: "relevance | timeline" },
114
+ },
115
+ additionalProperties: true,
116
+ },
117
+ execute: cliRedirect("ctx_search"),
118
+ },
119
+ {
120
+ name: "ctx_fetch_and_index",
121
+ description: "Fetch a URL, chunk it, and index — raw HTML never enters context.",
122
+ parameters: {
123
+ type: "object",
124
+ properties: {
125
+ url: { type: "string", description: "URL to fetch" },
126
+ source: { type: "string", description: "Source label for indexed chunks" },
127
+ },
128
+ required: ["url"],
129
+ additionalProperties: true,
130
+ },
131
+ execute: cliRedirect("ctx_fetch_and_index"),
132
+ },
133
+ {
134
+ name: "ctx_batch_execute",
135
+ description: "Run multiple commands and search queries in ONE call. Primary research tool — replaces 30+ individual calls.",
136
+ parameters: {
137
+ type: "object",
138
+ properties: {
139
+ commands: { type: "array", description: "Array of {label, command} objects" },
140
+ queries: { type: "array", description: "Search queries to run after indexing" },
141
+ },
142
+ additionalProperties: true,
143
+ },
144
+ execute: cliRedirect("ctx_batch_execute"),
145
+ },
146
+ {
147
+ name: "ctx_stats",
148
+ description: "Show context-mode session statistics — token consumption and per-tool breakdown.",
149
+ parameters: {
150
+ type: "object",
151
+ properties: {},
152
+ additionalProperties: true,
153
+ },
154
+ execute: cliRedirect("ctx_stats"),
155
+ },
156
+ {
157
+ name: "ctx_doctor",
158
+ description: "Run context-mode diagnostics — runtimes, hooks, FTS5, plugin registration.",
159
+ parameters: {
160
+ type: "object",
161
+ properties: {},
162
+ additionalProperties: true,
163
+ },
164
+ execute: cliRedirect("ctx_doctor"),
165
+ },
166
+ {
167
+ name: "ctx_upgrade",
168
+ description: "Upgrade context-mode to the latest version.",
169
+ parameters: {
170
+ type: "object",
171
+ properties: {},
172
+ additionalProperties: true,
173
+ },
174
+ execute: cliRedirect("ctx_upgrade"),
175
+ },
176
+ {
177
+ name: "ctx_purge",
178
+ description: "Permanently delete all indexed content and reset session stats. Destructive.",
179
+ parameters: {
180
+ type: "object",
181
+ properties: {},
182
+ additionalProperties: true,
183
+ },
184
+ execute: cliRedirect("ctx_purge"),
185
+ },
186
+ {
187
+ name: "ctx_insight",
188
+ description: "Open the context-mode Insight analytics dashboard in the browser.",
189
+ parameters: {
190
+ type: "object",
191
+ properties: {},
192
+ additionalProperties: true,
193
+ },
194
+ execute: cliRedirect("ctx_insight"),
195
+ },
196
+ ];
197
+ /** Stable list of tool names — used by tests and manifest validation. */
198
+ export const OPENCLAW_TOOL_NAMES = OPENCLAW_TOOL_DEFS.map((def) => def.name);
@@ -0,0 +1,130 @@
1
+ /**
2
+ * OpenClaw TypeScript plugin entry point for context-mode.
3
+ *
4
+ * Exports an object with { id, name, configSchema, register(api) } for
5
+ * declarative metadata and config validation before code execution.
6
+ *
7
+ * register(api) registers:
8
+ * - before_tool_call hook — Routing enforcement (deny/modify/passthrough)
9
+ * - after_tool_call hook — Session event capture
10
+ * - command:new hook — Session initialization and cleanup
11
+ * - session_start hook — Re-key DB session to OpenClaw's session ID
12
+ * - before_compaction hook — Flush events to resume snapshot
13
+ * - after_compaction hook — Increment compact count
14
+ * - before_prompt_build (p=10) — Resume snapshot injection into system context
15
+ * - before_prompt_build (p=5) — Routing instruction injection into system context
16
+ * - context-mode engine — Context engine with compaction management
17
+ * - /ctx-stats command — Auto-reply command for session statistics
18
+ * - /ctx-doctor command — Auto-reply command for diagnostics
19
+ * - /ctx-upgrade command — Auto-reply command for upgrade
20
+ *
21
+ * Loaded by OpenClaw via: openclaw.extensions entry in package.json
22
+ *
23
+ * OpenClaw plugin paradigm:
24
+ * - Plugins export { id, name, configSchema, register(api) } for metadata
25
+ * - api.registerHook() for event-driven hooks
26
+ * - api.on() for typed lifecycle hooks
27
+ * - api.registerContextEngine() for compaction ownership
28
+ * - api.registerCommand() for auto-reply slash commands
29
+ * - Plugins run in-process with the Gateway (trusted code)
30
+ */
31
+ import type { OpenClawToolDef } from "./mcp-tools.js";
32
+ /** Context for auto-reply command handlers. */
33
+ interface CommandContext {
34
+ senderId?: string;
35
+ channel?: string;
36
+ isAuthorizedSender?: boolean;
37
+ args?: string;
38
+ commandBody?: string;
39
+ config?: Record<string, unknown>;
40
+ }
41
+ /** OpenClaw plugin API provided to the register function. */
42
+ interface OpenClawPluginApi {
43
+ registerHook(event: string, handler: (...args: unknown[]) => unknown, meta: {
44
+ name: string;
45
+ description: string;
46
+ }): void;
47
+ /**
48
+ * Register a typed lifecycle hook.
49
+ * Supported names: "session_start", "before_compaction", "after_compaction",
50
+ * "before_prompt_build"
51
+ */
52
+ on(event: string, handler: (...args: unknown[]) => unknown, opts?: {
53
+ priority?: number;
54
+ }): void;
55
+ registerContextEngine(id: string, factory: () => ContextEngineInstance): void;
56
+ registerCommand?(cmd: {
57
+ name: string;
58
+ description: string;
59
+ acceptsArgs?: boolean;
60
+ requireAuth?: boolean;
61
+ handler: (ctx: CommandContext) => {
62
+ text: string;
63
+ } | Promise<{
64
+ text: string;
65
+ }>;
66
+ }): void;
67
+ registerCli?(factory: (ctx: {
68
+ program: unknown;
69
+ }) => void, meta: {
70
+ commands: string[];
71
+ }): void;
72
+ /**
73
+ * Register an agent tool (OpenClaw native registerTool) — see
74
+ * refs/platforms/openclaw/docs/plugins/building-plugins.md:116. Optional in
75
+ * the type so we degrade silently on legacy hosts that pre-date this API.
76
+ */
77
+ registerTool?(tool: OpenClawToolDef, opts?: {
78
+ optional?: boolean;
79
+ }): void;
80
+ logger?: {
81
+ info: (...args: unknown[]) => void;
82
+ error: (...args: unknown[]) => void;
83
+ debug?: (...args: unknown[]) => void;
84
+ warn?: (...args: unknown[]) => void;
85
+ };
86
+ }
87
+ /** Context engine instance returned by the factory. */
88
+ interface ContextEngineInstance {
89
+ info: {
90
+ id: string;
91
+ name: string;
92
+ ownsCompaction: boolean;
93
+ };
94
+ ingest(data: unknown): Promise<{
95
+ ingested: boolean;
96
+ }>;
97
+ assemble(ctx: {
98
+ messages: unknown[];
99
+ }): Promise<{
100
+ messages: unknown[];
101
+ estimatedTokens: number;
102
+ }>;
103
+ compact(): Promise<{
104
+ ok: boolean;
105
+ compacted: boolean;
106
+ }>;
107
+ }
108
+ /**
109
+ * OpenClaw plugin definition. The object form provides declarative metadata
110
+ * (id, name, configSchema) that OpenClaw can read without executing code.
111
+ * register() is called once per agent session with a fresh api object.
112
+ * Each call creates isolated closures (db, sessionId, hooks) — no shared state.
113
+ */
114
+ declare const _default: {
115
+ id: string;
116
+ name: string;
117
+ configSchema: {
118
+ type: "object";
119
+ properties: {
120
+ enabled: {
121
+ type: "boolean";
122
+ default: boolean;
123
+ description: string;
124
+ };
125
+ };
126
+ additionalProperties: boolean;
127
+ };
128
+ register(api: OpenClawPluginApi): void;
129
+ };
130
+ export default _default;