mirror of
https://github.com/mksglu/context-mode.git
synced 2026-10-02 04:14:38 +08:00
refactor: relocate plugin entry files into src/adapters/<platform>/
Pre-fix layout had three platform plugin entry files at the src/ root: src/pi-extension.ts — Pi Coding Agent extension src/pi-mcp-bridge.ts — Pi MCP bridge (added in #426) src/openclaw-plugin.ts — OpenClaw gateway plugin src/opencode-plugin.ts — OpenCode plugin Every other platform follows the src/adapters/<name>/ pattern (config, hooks, index, …). The four root-level files were the last hold-outs: inconsistent layout, plus they made adapter discovery harder for new contributors. ## Changes (file moves) - git mv src/pi-extension.ts → src/adapters/pi/extension.ts - git mv src/pi-mcp-bridge.ts → src/adapters/pi/mcp-bridge.ts - git mv src/openclaw-plugin.ts → src/adapters/openclaw/plugin.ts - git mv src/opencode-plugin.ts → src/adapters/opencode/plugin.ts ## Internal import-path updates inside the moved files - ./session/db.js → ../../session/db.js (depth +2) - ./types.js → ../../types.js - ./adapters/X/Y.js → ./Y.js (now sibling) - ./adapters/types.js → ../types.js (now parent) - ./pi-mcp-bridge.js → ./mcp-bridge.js (renamed + sibling) ## Runtime path-resolution updates The plugins read sibling resources (hooks/, package.json, etc.) via `resolve(buildDir, "..")`. After the move buildDir lives 2 dirs deeper, so every `..` is now `../../..`: - resolve(buildDir, "..") → resolve(buildDir, "..", "..", "..") - resolve(buildDir, "..", "hooks", "core", "routing.mjs") → resolve(buildDir, "..", "..", "..", "hooks", "core", "routing.mjs") - (and similar for routing-block / tool-naming / auto-injection) For opencode/plugin.ts the version-from-package.json walker prepends `../../../package.json` to its search list (keeps the legacy `../package.json` and `./package.json` entries as fall-backs so unbundled or old-layout dev environments still resolve). ## Build-output paths in package.json tsc preserves src/ structure under build/, so: ./build/pi-extension.js → ./build/adapters/pi/extension.js ./build/openclaw-plugin.js → ./build/adapters/openclaw/plugin.js ./build/opencode-plugin.js → ./build/adapters/opencode/plugin.js Updated: - package.json: pi.extensions[0], openclaw.extensions[0], main, exports["."], exports["./plugin"], exports["./openclaw"] - .pi/extensions/context-mode/index.ts: re-export delegate path - .openclaw-plugin/index.ts: re-export delegate path + JSDoc ## Test-side updates - tests/pi-extension.test.ts: dynamic-import paths updated - tests/opencode-plugin.test.ts: dynamic-import paths updated - tests/plugins/openclaw.test.ts: dynamic-import paths updated - tests/core/cli.test.ts: 4 dynamic-import paths + 1 `readFileSync(src/openclaw-plugin.ts)` source-grep updated to the new location - src/adapters/detect.ts: comment-line ref updated - tests/adapters/detect.test.ts: comment-line ref updated ## Test plan - [x] npm run build clean - [x] npm run typecheck clean - [x] npm test 73 files, 2407 pass / 25 skipped / 0 fail - [x] npx vitest run tests/opencode-plugin.test.ts 33/33 pass (regression: marker test that needed package.json walker fix) - [x] npx vitest run tests/plugins/openclaw.test.ts 225/225 pass - [x] npx vitest run tests/pi-extension.test.ts 45/45 pass (incl. the wiring guard added in the previous commit) - [x] npx vitest run tests/core/cli.test.ts -t "openclaw-plugin.ts doctor/upgrade" passes against the new src/adapters/openclaw/plugin.ts location - [x] Manual sanity: every old root-level path (build/pi-extension.js, src/opencode-plugin.ts, etc.) is gone from the repo — grep confirms zero stale refs in src/ + tests/ + package.json + the .pi/.openclaw-plugin/ thin wrappers. Co-Authored-By: Ora Studio <noreply@oratelecom.net>
This commit is contained in:
co-authored by
Ora Studio
parent
5bb1b0f25a
commit
4911c0716a
@@ -6,6 +6,7 @@
|
||||
* discovering plugins from the .openclaw-plugin/ directory.
|
||||
*
|
||||
* The actual plugin definition (object form with id, name, configSchema,
|
||||
* register) lives in src/openclaw-plugin.ts, compiled to build/openclaw-plugin.js.
|
||||
* register) lives in src/adapters/openclaw/plugin.ts, compiled to
|
||||
* build/adapters/openclaw/plugin.js.
|
||||
*/
|
||||
export { default } from "../build/openclaw-plugin.js";
|
||||
export { default } from "../build/adapters/openclaw/plugin.js";
|
||||
|
||||
@@ -1 +1 @@
|
||||
export { default } from "../../../build/pi-extension.js";
|
||||
export { default } from "../../../build/adapters/pi/extension.js";
|
||||
|
||||
+6
-6
@@ -29,7 +29,7 @@
|
||||
"homepage": "https://github.com/mksglu/context-mode#readme",
|
||||
"pi": {
|
||||
"extensions": [
|
||||
"./build/pi-extension.js"
|
||||
"./build/adapters/pi/extension.js"
|
||||
],
|
||||
"skills": [
|
||||
"./skills"
|
||||
@@ -37,15 +37,15 @@
|
||||
},
|
||||
"openclaw": {
|
||||
"extensions": [
|
||||
"./build/openclaw-plugin.js"
|
||||
"./build/adapters/openclaw/plugin.js"
|
||||
]
|
||||
},
|
||||
"bugs": "https://github.com/mksglu/context-mode/issues",
|
||||
"main": "./build/opencode-plugin.js",
|
||||
"main": "./build/adapters/opencode/plugin.js",
|
||||
"exports": {
|
||||
".": "./build/opencode-plugin.js",
|
||||
"./plugin": "./build/opencode-plugin.js",
|
||||
"./openclaw": "./build/openclaw-plugin.js",
|
||||
".": "./build/adapters/opencode/plugin.js",
|
||||
"./plugin": "./build/adapters/opencode/plugin.js",
|
||||
"./openclaw": "./build/adapters/openclaw/plugin.js",
|
||||
"./cli": "./cli.bundle.mjs"
|
||||
},
|
||||
"bin": {
|
||||
|
||||
@@ -67,7 +67,7 @@ export const PLATFORM_ENV_VARS = [
|
||||
// qwen-code — QWEN_PROJECT_DIR per QwenLM/qwen-code docs/users/features/hooks.md.
|
||||
// (QWEN_SESSION_ID removed — 0 hits in qwen-code repository.)
|
||||
["qwen-code", ["QWEN_PROJECT_DIR"]],
|
||||
// pi — PI_PROJECT_DIR consumed by src/pi-extension.ts:154 + src/server.ts:153
|
||||
// pi — PI_PROJECT_DIR consumed by src/adapters/pi/extension.ts:154 + src/server.ts:153
|
||||
// — implies the Pi runtime sets it before invoking the extension.
|
||||
["pi", ["PI_PROJECT_DIR"]],
|
||||
// openclaw — removed (runtime never sets OPENCLAW_HOME or OPENCLAW_CLI;
|
||||
|
||||
@@ -35,17 +35,17 @@ import { homedir } from "node:os";
|
||||
import { dirname, join, resolve } from "node:path";
|
||||
import { fileURLToPath, pathToFileURL } from "node:url";
|
||||
|
||||
import { SessionDB } from "./session/db.js";
|
||||
import { OpenClawSessionDB } from "./adapters/openclaw/session-db.js";
|
||||
import { extractEvents, extractUserEvents } from "./session/extract.js";
|
||||
import type { HookInput } from "./session/extract.js";
|
||||
import { buildResumeSnapshot } from "./session/snapshot.js";
|
||||
import type { SessionEvent } from "./types.js";
|
||||
import { SessionDB } from "../../session/db.js";
|
||||
import { OpenClawSessionDB } from "./session-db.js";
|
||||
import { extractEvents, extractUserEvents } from "../../session/extract.js";
|
||||
import type { HookInput } from "../../session/extract.js";
|
||||
import { buildResumeSnapshot } from "../../session/snapshot.js";
|
||||
import type { SessionEvent } from "../../types.js";
|
||||
|
||||
import { WorkspaceRouter } from "./adapters/openclaw/workspace-router.js";
|
||||
import { buildNodeCommand } from "./adapters/types.js";
|
||||
import { OPENCLAW_TOOL_DEFS } from "./adapters/openclaw/mcp-tools.js";
|
||||
import type { OpenClawToolDef } from "./adapters/openclaw/mcp-tools.js";
|
||||
import { WorkspaceRouter } from "./workspace-router.js";
|
||||
import { buildNodeCommand } from "../types.js";
|
||||
import { OPENCLAW_TOOL_DEFS } from "./mcp-tools.js";
|
||||
import type { OpenClawToolDef } from "./mcp-tools.js";
|
||||
|
||||
// ── System-reminder filter (CCv2 — SLICE OClaw-3) ─────────
|
||||
// Mirror hooks/userpromptsubmit.mjs:30-33: skip system-generated wrappers
|
||||
@@ -244,7 +244,7 @@ export default {
|
||||
// Resolve build dir from compiled JS location
|
||||
const buildDir = dirname(fileURLToPath(import.meta.url));
|
||||
const projectDir = process.cwd();
|
||||
const pluginRoot = resolve(buildDir, "..");
|
||||
const pluginRoot = resolve(buildDir, "..", "..", "..");
|
||||
|
||||
// Structured logger — wraps api.logger, falls back to no-op.
|
||||
// info/error always emit; debug only when api.logger.debug is present
|
||||
@@ -280,17 +280,17 @@ export default {
|
||||
// MCP-prefix substitution stays in lockstep with hooks/routing-block.mjs.
|
||||
let routingInstructions = "";
|
||||
const initPromise = (async () => {
|
||||
const routingPath = resolve(buildDir, "..", "hooks", "core", "routing.mjs");
|
||||
const routingPath = resolve(buildDir, "..", "..", "..", "hooks", "core", "routing.mjs");
|
||||
const routing = await import(pathToFileURL(routingPath).href);
|
||||
await routing.initSecurity(buildDir);
|
||||
|
||||
try {
|
||||
const blockMod = await import(
|
||||
pathToFileURL(resolve(buildDir, "..", "hooks", "routing-block.mjs")).href
|
||||
pathToFileURL(resolve(buildDir, "..", "..", "..", "hooks", "routing-block.mjs")).href
|
||||
);
|
||||
const namingMod = await import(
|
||||
pathToFileURL(
|
||||
resolve(buildDir, "..", "hooks", "core", "tool-naming.mjs"),
|
||||
resolve(buildDir, "..", "..", "..", "hooks", "core", "tool-naming.mjs"),
|
||||
).href
|
||||
);
|
||||
const toolNamer = namingMod.createToolNamer("openclaw");
|
||||
@@ -599,7 +599,7 @@ export default {
|
||||
}
|
||||
const events = extractUserEvents(messageText);
|
||||
for (const ev of events) {
|
||||
db.insertEvent(sid, ev as import("./types.js").SessionEvent, "PostToolUse");
|
||||
db.insertEvent(sid, ev as import("../../types.js").SessionEvent, "PostToolUse");
|
||||
}
|
||||
} catch {
|
||||
// best effort — never break model resolution
|
||||
@@ -25,13 +25,13 @@ import { dirname, resolve, join } from "node:path";
|
||||
import { fileURLToPath, pathToFileURL } from "node:url";
|
||||
import { existsSync, readFileSync } from "node:fs";
|
||||
|
||||
import { SessionDB } from "./session/db.js";
|
||||
import { extractEvents, extractUserEvents } from "./session/extract.js";
|
||||
import type { HookInput } from "./session/extract.js";
|
||||
import { buildResumeSnapshot } from "./session/snapshot.js";
|
||||
import type { SessionEvent } from "./types.js";
|
||||
import { AdapterPlatformType, OpenCodeAdapter } from "./adapters/opencode/index.js";
|
||||
import { PLATFORM_ENV_VARS } from "./adapters/detect.js";
|
||||
import { SessionDB } from "../../session/db.js";
|
||||
import { extractEvents, extractUserEvents } from "../../session/extract.js";
|
||||
import type { HookInput } from "../../session/extract.js";
|
||||
import { buildResumeSnapshot } from "../../session/snapshot.js";
|
||||
import type { SessionEvent } from "../../types.js";
|
||||
import { AdapterPlatformType, OpenCodeAdapter } from "./index.js";
|
||||
import { PLATFORM_ENV_VARS } from "../detect.js";
|
||||
|
||||
// Read package.json version once at module load (not on every hook call).
|
||||
// Used in the resume-injection visible signal so users can confirm in
|
||||
@@ -39,7 +39,11 @@ import { PLATFORM_ENV_VARS } from "./adapters/detect.js";
|
||||
const VERSION: string = (() => {
|
||||
try {
|
||||
const pkgRoot = dirname(fileURLToPath(import.meta.url));
|
||||
for (const rel of ["../package.json", "./package.json"]) {
|
||||
// Search both the legacy depths (when bundled flat under build/) and
|
||||
// the post-refactor depths (when compiled to build/adapters/opencode/).
|
||||
// `../../../package.json` is the canonical location after the
|
||||
// `src/opencode-plugin.ts → src/adapters/opencode/plugin.ts` move.
|
||||
for (const rel of ["../../../package.json", "../package.json", "./package.json"]) {
|
||||
const p = resolve(pkgRoot, rel);
|
||||
if (existsSync(p)) return JSON.parse(readFileSync(p, "utf8")).version ?? "unknown";
|
||||
}
|
||||
@@ -225,17 +229,17 @@ async function createContextModePlugin(ctx: PluginContext) {
|
||||
const buildDir = dirname(fileURLToPath(import.meta.url));
|
||||
|
||||
// Load routing module (ESM .mjs, lives outside build/ in hooks/)
|
||||
const routingPath = resolve(buildDir, "..", "hooks", "core", "routing.mjs");
|
||||
const routingPath = resolve(buildDir, "..", "..", "..", "hooks", "core", "routing.mjs");
|
||||
const routing = await import(pathToFileURL(routingPath).href);
|
||||
await routing.initSecurity(buildDir);
|
||||
|
||||
// OC-1 / OC-3: Load hook helpers once at plugin init. Dynamic import keeps
|
||||
// the .mjs ESM islands isolated from the .ts compile graph.
|
||||
const routingBlockPath = resolve(buildDir, "..", "hooks", "routing-block.mjs");
|
||||
const routingBlockPath = resolve(buildDir, "..", "..", "..", "hooks", "routing-block.mjs");
|
||||
const routingBlockMod = await import(pathToFileURL(routingBlockPath).href);
|
||||
const toolNamingPath = resolve(buildDir, "..", "hooks", "core", "tool-naming.mjs");
|
||||
const toolNamingPath = resolve(buildDir, "..", "..", "..", "hooks", "core", "tool-naming.mjs");
|
||||
const toolNamingMod = await import(pathToFileURL(toolNamingPath).href);
|
||||
const autoInjectionPath = resolve(buildDir, "..", "hooks", "auto-injection.mjs");
|
||||
const autoInjectionPath = resolve(buildDir, "..", "..", "..", "hooks", "auto-injection.mjs");
|
||||
const autoInjectionMod = await import(pathToFileURL(autoInjectionPath).href);
|
||||
|
||||
// Pre-build the routing block once per process — it is platform-specific
|
||||
@@ -16,12 +16,12 @@ import { existsSync, mkdirSync } from "node:fs";
|
||||
import { homedir } from "node:os";
|
||||
import { join, resolve, dirname } from "node:path";
|
||||
import { fileURLToPath, pathToFileURL } from "node:url";
|
||||
import { SessionDB } from "./session/db.js";
|
||||
import { extractEvents, extractUserEvents } from "./session/extract.js";
|
||||
import type { HookInput } from "./session/extract.js";
|
||||
import { buildResumeSnapshot } from "./session/snapshot.js";
|
||||
import type { SessionEvent } from "./types.js";
|
||||
import { bootstrapMCPTools, type BridgeHandle } from "./pi-mcp-bridge.js";
|
||||
import { SessionDB } from "../../session/db.js";
|
||||
import { extractEvents, extractUserEvents } from "../../session/extract.js";
|
||||
import type { HookInput } from "../../session/extract.js";
|
||||
import { buildResumeSnapshot } from "../../session/snapshot.js";
|
||||
import type { SessionEvent } from "../../types.js";
|
||||
import { bootstrapMCPTools, type BridgeHandle } from "./mcp-bridge.js";
|
||||
|
||||
// ── Pi Tool Name Mapping ─────────────────────────────────
|
||||
// Pi uses lowercase; shared extractors expect PascalCase (Claude Code convention).
|
||||
@@ -213,7 +213,7 @@ function handleCommandText(
|
||||
/** Pi extension default export. Called once by Pi runtime with the extension API. */
|
||||
export default function piExtension(pi: any): void {
|
||||
const buildDir = dirname(fileURLToPath(import.meta.url));
|
||||
const pluginRoot = resolve(buildDir, "..");
|
||||
const pluginRoot = resolve(buildDir, "..", "..", "..");
|
||||
const projectDir = process.env.PI_PROJECT_DIR || process.cwd();
|
||||
|
||||
const db = getOrCreateDB();
|
||||
@@ -152,7 +152,7 @@ describe("detectPlatform", () => {
|
||||
|
||||
// ── Pi ─────────────────────────────────────────────────
|
||||
// Pi runtime sets PI_PROJECT_DIR before invoking the extension —
|
||||
// verified by src/pi-extension.ts:154 + src/server.ts:153 consumers.
|
||||
// verified by src/adapters/pi/extension.ts:154 + src/server.ts:153 consumers.
|
||||
|
||||
it("detects pi via PI_PROJECT_DIR env var", () => {
|
||||
process.env.PI_PROJECT_DIR = "/some/project";
|
||||
|
||||
@@ -823,7 +823,7 @@ describe("Bin entry uses cli.bundle.mjs", () => {
|
||||
});
|
||||
|
||||
it("openclaw-plugin.ts doctor/upgrade use cli.bundle.mjs with fallback", () => {
|
||||
const src = readFileSync(resolve(ROOT, "src", "openclaw-plugin.ts"), "utf-8");
|
||||
const src = readFileSync(resolve(ROOT, "src", "adapters", "openclaw", "plugin.ts"), "utf-8");
|
||||
expect(src).toContain("cli.bundle.mjs");
|
||||
// Find the registerCommand blocks, not comments
|
||||
const doctorIdx = src.indexOf('name: "ctx-doctor"');
|
||||
@@ -934,19 +934,19 @@ describe("SKILL.md prefers MCP tool over Bash", () => {
|
||||
|
||||
describe("Package exports", () => {
|
||||
test("named export exposes ContextModePlugin factory", async () => {
|
||||
const mod = await import("../../src/opencode-plugin.js");
|
||||
const mod = await import("../../src/adapters/opencode/plugin.js");
|
||||
expect(mod.ContextModePlugin).toBeDefined();
|
||||
expect(typeof mod.ContextModePlugin).toBe("function");
|
||||
});
|
||||
|
||||
test("default export has KiloCode PluginModule shape { server }", async () => {
|
||||
const mod = (await import("../../src/opencode-plugin.js")) as any;
|
||||
const mod = (await import("../../src/adapters/opencode/plugin.js")) as any;
|
||||
expect(mod.default).toBeDefined();
|
||||
expect(typeof mod.default.server).toBe("function");
|
||||
});
|
||||
|
||||
test("default export does not leak CLI internals", async () => {
|
||||
const mod = (await import("../../src/opencode-plugin.js")) as any;
|
||||
const mod = (await import("../../src/adapters/opencode/plugin.js")) as any;
|
||||
expect(mod.toUnixPath).toBeUndefined();
|
||||
expect(mod.doctor).toBeUndefined();
|
||||
expect(mod.upgrade).toBeUndefined();
|
||||
|
||||
@@ -21,7 +21,7 @@ import { tmpdir } from "node:os";
|
||||
*/
|
||||
async function createTestPlugin(tempDir: string) {
|
||||
// Import the plugin module
|
||||
const { ContextModePlugin } = await import("../src/opencode-plugin.js");
|
||||
const { ContextModePlugin } = await import("../src/adapters/opencode/plugin.js");
|
||||
|
||||
// Monkey-patch the session dir to use temp directory
|
||||
// The plugin uses homedir() internally, but we can control the DB path
|
||||
|
||||
+11
-11
@@ -2,7 +2,7 @@ import "./setup-home";
|
||||
/**
|
||||
* Pi Extension Tests — TDD vertical slices.
|
||||
*
|
||||
* The Pi extension (src/pi-extension.ts) is a default-exported function that
|
||||
* The Pi extension (src/adapters/pi/extension.ts) is a default-exported function that
|
||||
* receives a Pi API object and registers event handlers. Since we cannot test
|
||||
* against a real Pi runtime, we mock the Pi API to capture registered handlers
|
||||
* and invoke them with simulated events.
|
||||
@@ -77,7 +77,7 @@ async function registerPiExtension(
|
||||
process.env.PI_PROJECT_DIR = projectDir;
|
||||
process.env.CLAUDE_PROJECT_DIR = projectDir;
|
||||
|
||||
const mod = await import("../src/pi-extension.js");
|
||||
const mod = await import("../src/adapters/pi/extension.js");
|
||||
const register = mod.default;
|
||||
await register(mockApi);
|
||||
|
||||
@@ -767,7 +767,7 @@ describe("Pi MCP bridge (#426)", () => {
|
||||
}
|
||||
});
|
||||
`);
|
||||
const { MCPStdioClient } = await import("../src/pi-mcp-bridge.js");
|
||||
const { MCPStdioClient } = await import("../src/adapters/pi/mcp-bridge.js");
|
||||
const client = new MCPStdioClient(fakePath);
|
||||
client.start();
|
||||
try {
|
||||
@@ -803,7 +803,7 @@ describe("Pi MCP bridge (#426)", () => {
|
||||
}
|
||||
});
|
||||
`);
|
||||
const { MCPStdioClient } = await import("../src/pi-mcp-bridge.js");
|
||||
const { MCPStdioClient } = await import("../src/adapters/pi/mcp-bridge.js");
|
||||
const client = new MCPStdioClient(fakePath);
|
||||
client.start();
|
||||
try {
|
||||
@@ -822,7 +822,7 @@ describe("Pi MCP bridge (#426)", () => {
|
||||
const fakePath = writeFakeServer(`
|
||||
process.stdin.once("data", () => process.exit(0));
|
||||
`);
|
||||
const { MCPStdioClient } = await import("../src/pi-mcp-bridge.js");
|
||||
const { MCPStdioClient } = await import("../src/adapters/pi/mcp-bridge.js");
|
||||
const client = new MCPStdioClient(fakePath);
|
||||
client.start();
|
||||
const promise = client.request("tools/list", {});
|
||||
@@ -835,7 +835,7 @@ describe("Pi MCP bridge (#426)", () => {
|
||||
process.stdin.on("data", () => {});
|
||||
setInterval(() => {}, 1000);
|
||||
`);
|
||||
const { MCPStdioClient } = await import("../src/pi-mcp-bridge.js");
|
||||
const { MCPStdioClient } = await import("../src/adapters/pi/mcp-bridge.js");
|
||||
const client = new MCPStdioClient(fakePath);
|
||||
client.start();
|
||||
try {
|
||||
@@ -865,7 +865,7 @@ describe("Pi MCP bridge (#426)", () => {
|
||||
}
|
||||
});
|
||||
`);
|
||||
const { MCPStdioClient } = await import("../src/pi-mcp-bridge.js");
|
||||
const { MCPStdioClient } = await import("../src/adapters/pi/mcp-bridge.js");
|
||||
const client = new MCPStdioClient(fakePath);
|
||||
client.start();
|
||||
try {
|
||||
@@ -905,7 +905,7 @@ describe("Pi MCP bridge (#426)", () => {
|
||||
},
|
||||
};
|
||||
|
||||
const { bootstrapMCPTools } = await import("../src/pi-mcp-bridge.js");
|
||||
const { bootstrapMCPTools } = await import("../src/adapters/pi/mcp-bridge.js");
|
||||
bridge = await bootstrapMCPTools(fakePi, mcpEntry, { env: mcpEnv });
|
||||
|
||||
// Pin the canonical names — adding new MCP tools is fine
|
||||
@@ -940,7 +940,7 @@ describe("Pi MCP bridge (#426)", () => {
|
||||
registerTool: (tool: any) => registered.push(tool),
|
||||
};
|
||||
|
||||
const { bootstrapMCPTools } = await import("../src/pi-mcp-bridge.js");
|
||||
const { bootstrapMCPTools } = await import("../src/adapters/pi/mcp-bridge.js");
|
||||
bridge = await bootstrapMCPTools(fakePi, mcpEntry, { env: mcpEnv });
|
||||
|
||||
const indexTool = registered.find((t) => t.name === "ctx_index");
|
||||
@@ -966,7 +966,7 @@ describe("Pi MCP bridge (#426)", () => {
|
||||
//
|
||||
// This is the regression that the rest of the suite does NOT catch: if
|
||||
// a future refactor drops the `bootstrapMCPTools(pi, …)` call from
|
||||
// src/pi-extension.ts but keeps the bridge module intact, every other
|
||||
// src/adapters/pi/extension.ts but keeps the bridge module intact, every other
|
||||
// bridge test stays green and the bug silently re-enters. We assert
|
||||
// here that the extension's default export, after `_mcpBridgeReady`
|
||||
// settles, has actually called `pi.registerTool` for at least the
|
||||
@@ -980,7 +980,7 @@ describe("Pi MCP bridge (#426)", () => {
|
||||
|
||||
// Bootstrap is fire-and-forget on extension load — wait on the
|
||||
// exported promise so the test does not race the spawn.
|
||||
const mod = await import("../src/pi-extension.js");
|
||||
const mod = await import("../src/adapters/pi/extension.js");
|
||||
await mod._mcpBridgeReady;
|
||||
|
||||
const calls = (wireApi.registerTool as any).mock.calls as Array<[any]>;
|
||||
|
||||
@@ -121,7 +121,7 @@ function createMockApiFull() {
|
||||
async function createTestPlugin(tempDir: string) {
|
||||
// Each test gets an isolated DB by running from a unique cwd (tempDir).
|
||||
// The plugin reads process.cwd() for projectDir — no fake env var needed.
|
||||
const { default: plugin } = await import("../../src/openclaw-plugin.js");
|
||||
const { default: plugin } = await import("../../src/adapters/openclaw/plugin.js");
|
||||
const mock = createMockApiFull();
|
||||
await plugin.register(mock.api);
|
||||
return mock;
|
||||
@@ -209,7 +209,7 @@ describe("OpenClawPlugin", () => {
|
||||
|
||||
describe("object export", () => {
|
||||
it("exports object with id, name, configSchema, register", async () => {
|
||||
const { default: plugin } = await import("../../src/openclaw-plugin.js");
|
||||
const { default: plugin } = await import("../../src/adapters/openclaw/plugin.js");
|
||||
expect(plugin.id).toBe("context-mode");
|
||||
expect(plugin.name).toBe("Context Mode");
|
||||
expect(plugin.configSchema).toBeDefined();
|
||||
@@ -218,7 +218,7 @@ describe("OpenClawPlugin", () => {
|
||||
});
|
||||
|
||||
it("configSchema has enabled property", async () => {
|
||||
const { default: plugin } = await import("../../src/openclaw-plugin.js");
|
||||
const { default: plugin } = await import("../../src/adapters/openclaw/plugin.js");
|
||||
expect(plugin.configSchema.properties.enabled).toBeDefined();
|
||||
expect(plugin.configSchema.properties.enabled.type).toBe("boolean");
|
||||
expect(plugin.configSchema.properties.enabled.default).toBe(true);
|
||||
@@ -798,7 +798,7 @@ describe("Plugin exports", () => {
|
||||
beforeEach(() => { vi.resetModules(); });
|
||||
|
||||
test("plugin exports id, name, configSchema, register", async () => {
|
||||
const { default: plugin } = await import("../../src/openclaw-plugin.js");
|
||||
const { default: plugin } = await import("../../src/adapters/openclaw/plugin.js");
|
||||
assert.equal(plugin.id, "context-mode");
|
||||
assert.equal(plugin.name, "Context Mode");
|
||||
assert.ok(plugin.configSchema);
|
||||
@@ -810,7 +810,7 @@ describe("session_start hook", () => {
|
||||
beforeEach(() => { vi.resetModules(); });
|
||||
|
||||
test("session_start hook is registered", async () => {
|
||||
const { default: plugin } = await import("../../src/openclaw-plugin.js");
|
||||
const { default: plugin } = await import("../../src/adapters/openclaw/plugin.js");
|
||||
const { api, typedHooks } = createMockApiHooks();
|
||||
|
||||
plugin.register(api as unknown as Parameters<typeof plugin.register>[0]);
|
||||
@@ -820,7 +820,7 @@ describe("session_start hook", () => {
|
||||
});
|
||||
|
||||
test("session_start hook is registered with no priority (void hook)", async () => {
|
||||
const { default: plugin } = await import("../../src/openclaw-plugin.js");
|
||||
const { default: plugin } = await import("../../src/adapters/openclaw/plugin.js");
|
||||
const { api, typedHooks } = createMockApiHooks();
|
||||
|
||||
plugin.register(api as unknown as Parameters<typeof plugin.register>[0]);
|
||||
@@ -831,7 +831,7 @@ describe("session_start hook", () => {
|
||||
});
|
||||
|
||||
test("session_start handler resets resumeInjected — verified via before_prompt_build sequence", async () => {
|
||||
const { default: plugin } = await import("../../src/openclaw-plugin.js");
|
||||
const { default: plugin } = await import("../../src/adapters/openclaw/plugin.js");
|
||||
const { api, typedHooks } = createMockApiHooks();
|
||||
|
||||
plugin.register(api as unknown as Parameters<typeof plugin.register>[0]);
|
||||
@@ -861,7 +861,7 @@ describe("compaction hooks", () => {
|
||||
beforeEach(() => { vi.resetModules(); });
|
||||
|
||||
test("before_compaction hook is registered", async () => {
|
||||
const { default: plugin } = await import("../../src/openclaw-plugin.js");
|
||||
const { default: plugin } = await import("../../src/adapters/openclaw/plugin.js");
|
||||
const { api, typedHooks } = createMockApiHooks();
|
||||
|
||||
plugin.register(api as unknown as Parameters<typeof plugin.register>[0]);
|
||||
@@ -871,7 +871,7 @@ describe("compaction hooks", () => {
|
||||
});
|
||||
|
||||
test("after_compaction hook is registered", async () => {
|
||||
const { default: plugin } = await import("../../src/openclaw-plugin.js");
|
||||
const { default: plugin } = await import("../../src/adapters/openclaw/plugin.js");
|
||||
const { api, typedHooks } = createMockApiHooks();
|
||||
|
||||
plugin.register(api as unknown as Parameters<typeof plugin.register>[0]);
|
||||
@@ -917,7 +917,7 @@ describe("resume injection (before_prompt_build)", () => {
|
||||
beforeEach(() => { vi.resetModules(); });
|
||||
|
||||
test("before_prompt_build resume hook is registered at priority 10", async () => {
|
||||
const { default: plugin } = await import("../../src/openclaw-plugin.js");
|
||||
const { default: plugin } = await import("../../src/adapters/openclaw/plugin.js");
|
||||
const { api, typedHooks } = createMockApiHooks();
|
||||
|
||||
plugin.register(api as unknown as Parameters<typeof plugin.register>[0]);
|
||||
@@ -1131,7 +1131,7 @@ describe("before_model_resolve hook", () => {
|
||||
beforeEach(() => { vi.resetModules(); });
|
||||
|
||||
test("before_model_resolve hook is registered", async () => {
|
||||
const { default: plugin } = await import("../../src/openclaw-plugin.js");
|
||||
const { default: plugin } = await import("../../src/adapters/openclaw/plugin.js");
|
||||
const { api, typedHooks } = createMockApiHooks();
|
||||
|
||||
plugin.register(api as unknown as Parameters<typeof plugin.register>[0]);
|
||||
@@ -1150,7 +1150,7 @@ describe("before_model_resolve hook", () => {
|
||||
});
|
||||
|
||||
test("before_model_resolve handler runs without throwing on decision message", async () => {
|
||||
const { default: plugin } = await import("../../src/openclaw-plugin.js");
|
||||
const { default: plugin } = await import("../../src/adapters/openclaw/plugin.js");
|
||||
const { api, typedHooks } = createMockApiHooks();
|
||||
|
||||
plugin.register(api as unknown as Parameters<typeof plugin.register>[0]);
|
||||
@@ -1165,7 +1165,7 @@ describe("before_model_resolve hook", () => {
|
||||
});
|
||||
|
||||
test("before_model_resolve is silent when userMessage is empty", async () => {
|
||||
const { default: plugin } = await import("../../src/openclaw-plugin.js");
|
||||
const { default: plugin } = await import("../../src/adapters/openclaw/plugin.js");
|
||||
const { api, typedHooks } = createMockApiHooks();
|
||||
|
||||
plugin.register(api as unknown as Parameters<typeof plugin.register>[0]);
|
||||
@@ -1187,7 +1187,7 @@ describe("command lifecycle hooks", () => {
|
||||
beforeEach(() => { vi.resetModules(); });
|
||||
|
||||
test("command:reset hook is registered", async () => {
|
||||
const { default: plugin } = await import("../../src/openclaw-plugin.js");
|
||||
const { default: plugin } = await import("../../src/adapters/openclaw/plugin.js");
|
||||
const { api, hooks } = createMockApiHooks();
|
||||
|
||||
plugin.register(api as unknown as Parameters<typeof plugin.register>[0]);
|
||||
@@ -1197,7 +1197,7 @@ describe("command lifecycle hooks", () => {
|
||||
});
|
||||
|
||||
test("command:stop hook is registered", async () => {
|
||||
const { default: plugin } = await import("../../src/openclaw-plugin.js");
|
||||
const { default: plugin } = await import("../../src/adapters/openclaw/plugin.js");
|
||||
const { api, hooks } = createMockApiHooks();
|
||||
|
||||
plugin.register(api as unknown as Parameters<typeof plugin.register>[0]);
|
||||
@@ -1207,7 +1207,7 @@ describe("command lifecycle hooks", () => {
|
||||
});
|
||||
|
||||
test("command:reset handler runs cleanupOldSessions without throwing", async () => {
|
||||
const { default: plugin } = await import("../../src/openclaw-plugin.js");
|
||||
const { default: plugin } = await import("../../src/adapters/openclaw/plugin.js");
|
||||
const { api, hooks } = createMockApiHooks();
|
||||
|
||||
plugin.register(api as unknown as Parameters<typeof plugin.register>[0]);
|
||||
@@ -1226,7 +1226,7 @@ describe("verbose logging", () => {
|
||||
beforeEach(() => { vi.resetModules(); });
|
||||
|
||||
test("plugin works without logger (logger is optional)", async () => {
|
||||
const { default: plugin } = await import("../../src/openclaw-plugin.js");
|
||||
const { default: plugin } = await import("../../src/adapters/openclaw/plugin.js");
|
||||
const { api } = createMockApiHooks(false); // no logger
|
||||
|
||||
assert.doesNotThrow(() =>
|
||||
@@ -1235,7 +1235,7 @@ describe("verbose logging", () => {
|
||||
});
|
||||
|
||||
test("session_start emits info log when logger is provided", async () => {
|
||||
const { default: plugin } = await import("../../src/openclaw-plugin.js");
|
||||
const { default: plugin } = await import("../../src/adapters/openclaw/plugin.js");
|
||||
const { api, typedHooks, logLines } = createMockApiHooks(true);
|
||||
|
||||
plugin.register(api as unknown as Parameters<typeof plugin.register>[0]);
|
||||
@@ -1249,7 +1249,7 @@ describe("verbose logging", () => {
|
||||
});
|
||||
|
||||
test("after_tool_call emits debug log for captured events when logger provided", async () => {
|
||||
const { default: plugin } = await import("../../src/openclaw-plugin.js");
|
||||
const { default: plugin } = await import("../../src/adapters/openclaw/plugin.js");
|
||||
const { api, typedHooks, logLines } = createMockApiHooks(true);
|
||||
|
||||
plugin.register(api as unknown as Parameters<typeof plugin.register>[0]);
|
||||
@@ -1268,7 +1268,7 @@ describe("verbose logging", () => {
|
||||
});
|
||||
|
||||
test("before_prompt_build emits debug log when resume is injected", async () => {
|
||||
const { default: plugin } = await import("../../src/openclaw-plugin.js");
|
||||
const { default: plugin } = await import("../../src/adapters/openclaw/plugin.js");
|
||||
const { api, typedHooks, logLines } = createMockApiHooks(true);
|
||||
|
||||
plugin.register(api as unknown as Parameters<typeof plugin.register>[0]);
|
||||
|
||||
Reference in New Issue
Block a user