@ken-jo/agent-connector 0.3.1 → 0.4.0
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/README.md +178 -14
- package/dist/action-PLZW5BGX.js +54 -0
- package/dist/action-PLZW5BGX.js.map +1 -0
- package/dist/{amp-YGV66GJT.js → amp-B524U6LO.js} +81 -5
- package/dist/amp-B524U6LO.js.map +1 -0
- package/dist/{antigravity-7IBYFO6P.js → antigravity-ANDKF3K7.js} +4 -4
- package/dist/{antigravity-cli-JEOUP2VN.js → antigravity-cli-LLRPDDOT.js} +4 -4
- package/dist/chunk-22Y24V7O.js +21 -0
- package/dist/chunk-22Y24V7O.js.map +1 -0
- package/dist/chunk-3PFFTFCU.js +190 -0
- package/dist/chunk-3PFFTFCU.js.map +1 -0
- package/dist/{chunk-SCVBYSF7.js → chunk-6XHB6BE3.js} +1 -1
- package/dist/chunk-76FUSVIA.js +43 -0
- package/dist/chunk-76FUSVIA.js.map +1 -0
- package/dist/{chunk-GSGDG2BV.js → chunk-ADTHT2FN.js} +109 -16
- package/dist/chunk-ADTHT2FN.js.map +1 -0
- package/dist/{chunk-ZAM4M7LI.js → chunk-BHUCB6LY.js} +135 -296
- package/dist/chunk-BHUCB6LY.js.map +1 -0
- package/dist/{chunk-MEH7GC7R.js → chunk-BXGFUENQ.js} +20 -3
- package/dist/chunk-BXGFUENQ.js.map +1 -0
- package/dist/chunk-CIRDOY2V.js +351 -0
- package/dist/chunk-CIRDOY2V.js.map +1 -0
- package/dist/{chunk-KMAKDD3Z.js → chunk-G3ER4SY5.js} +37 -12
- package/dist/chunk-G3ER4SY5.js.map +1 -0
- package/dist/{chunk-PD4VFEBY.js → chunk-IW77FFNX.js} +39 -1
- package/dist/chunk-IW77FFNX.js.map +1 -0
- package/dist/chunk-J3D5W5T2.js +83 -0
- package/dist/chunk-J3D5W5T2.js.map +1 -0
- package/dist/{openclaw-UZ5BMCGQ.js → chunk-KGGBNKI4.js} +125 -33
- package/dist/chunk-KGGBNKI4.js.map +1 -0
- package/dist/{chunk-3JCRUROU.js → chunk-KGJWE6A2.js} +13 -4
- package/dist/chunk-KGJWE6A2.js.map +1 -0
- package/dist/{chunk-3RBLIHPZ.js → chunk-KGXDYGNJ.js} +26 -16
- package/dist/chunk-KGXDYGNJ.js.map +1 -0
- package/dist/{chunk-KVAAFYRR.js → chunk-KHO5WNTP.js} +2 -18
- package/dist/chunk-KHO5WNTP.js.map +1 -0
- package/dist/{chunk-KQSNDFBN.js → chunk-LL4OBGRU.js} +3 -3
- package/dist/{chunk-WNREHWKL.js → chunk-MAH6QQTO.js} +3 -3
- package/dist/{claude-code-4275HQU4.js → claude-code-MLWS7CW6.js} +180 -28
- package/dist/claude-code-MLWS7CW6.js.map +1 -0
- package/dist/cli/sdk.js +4 -3
- package/dist/cli/sdk.js.map +1 -1
- package/dist/cli.js +1 -1
- package/dist/{codebuff-LE3KBZGM.js → codebuff-SH2S3QAN.js} +102 -5
- package/dist/codebuff-SH2S3QAN.js.map +1 -0
- package/dist/{codex-4BY2ZJIW.js → codex-BXA4FIF4.js} +3 -3
- package/dist/{copilot-cli-IPISKO3V.js → copilot-cli-ROIBTTDT.js} +3 -3
- package/dist/{crush-X3E25EQG.js → crush-QLEFLHUC.js} +3 -3
- package/dist/{cursor-UH3W622V.js → cursor-ASJPWZ4R.js} +6 -3
- package/dist/cursor-ASJPWZ4R.js.map +1 -0
- package/dist/{detect-U3E7NVNW.js → detect-ZIIS55LD.js} +4 -3
- package/dist/{detect-U3E7NVNW.js.map → detect-ZIIS55LD.js.map} +1 -1
- package/dist/{doctor-DZTWED4O.js → doctor-TJUGSQ5C.js} +16 -12
- package/dist/doctor-TJUGSQ5C.js.map +1 -0
- package/dist/{droid-T5VBRXZF.js → droid-NCSS3B5Y.js} +170 -4
- package/dist/droid-NCSS3B5Y.js.map +1 -0
- package/dist/{gemini-cli-ZSUK55UA.js → gemini-cli-SLVWLXJW.js} +3 -3
- package/dist/{goose-M3RR3CZG.js → goose-PBA7KTE5.js} +100 -5
- package/dist/goose-PBA7KTE5.js.map +1 -0
- package/dist/{hermes-CUNKIAR5.js → hermes-ONDCECP2.js} +3 -3
- package/dist/{hook-EVY7LOUQ.js → hook-OU522ABV.js} +12 -9
- package/dist/{hook-EVY7LOUQ.js.map → hook-OU522ABV.js.map} +1 -1
- package/dist/index.d.ts +71 -3
- package/dist/index.js +22 -3
- package/dist/{install-OWAS5UIE.js → install-UDCBL7HP.js} +11 -9
- package/dist/{install-OWAS5UIE.js.map → install-UDCBL7HP.js.map} +1 -1
- package/dist/introspect-DuZSPSHB.d.ts +53 -0
- package/dist/{jetbrains-copilot-C3HDGGML.js → jetbrains-copilot-YABZ3HFA.js} +3 -3
- package/dist/{kilo-PKAJCWPX.js → kilo-F3ZDZKCT.js} +3 -3
- package/dist/{kilo-cli-QWUVXG2O.js → kilo-cli-3HWPWBY4.js} +3 -3
- package/dist/{kimi-EVD7YKXS.js → kimi-NV72FVAO.js} +3 -3
- package/dist/{kiro-UQRY6EIO.js → kiro-C5W6AGDR.js} +3 -3
- package/dist/{leaderboard-CSWHI4UY.js → leaderboard-TIBVONVT.js} +3 -3
- package/dist/mimo-code-IMM5YM3M.js +754 -0
- package/dist/mimo-code-IMM5YM3M.js.map +1 -0
- package/dist/{mux-5CI5FP2W.js → mux-DSSH4AFS.js} +3 -3
- package/dist/nemoclaw-3EVNKD3I.js +58 -0
- package/dist/nemoclaw-3EVNKD3I.js.map +1 -0
- package/dist/{omp-AXA7XY22.js → omp-Z6FRNDPN.js} +3 -3
- package/dist/openclaw-7G437NT7.js +18 -0
- package/dist/openclaw-7G437NT7.js.map +1 -0
- package/dist/{opencode-NZBRLJN3.js → opencode-Q6KBSAKW.js} +3 -3
- package/dist/{package-WFOS4QVU.js → package-RMPN57YZ.js} +7 -6
- package/dist/{package-WFOS4QVU.js.map → package-RMPN57YZ.js.map} +1 -1
- package/dist/{pi-WMTUX6ES.js → pi-LZT6WWAZ.js} +2 -2
- package/dist/{qwen-code-MRRIUQ3P.js → qwen-code-WQBKRPWJ.js} +3 -3
- package/dist/{roo-code-NI5UU6JB.js → roo-code-GWSNU3OW.js} +137 -4
- package/dist/roo-code-GWSNU3OW.js.map +1 -0
- package/dist/runtime/index.d.ts +96 -2
- package/dist/runtime/index.js +18 -10
- package/dist/sdk/index.d.ts +52 -0
- package/dist/sdk/index.js +81 -0
- package/dist/sdk/index.js.map +1 -0
- package/dist/sdk/test.d.ts +74 -0
- package/dist/sdk/test.js +291 -0
- package/dist/sdk/test.js.map +1 -0
- package/dist/{serve-3C2VFPAY.js → serve-D3GO36UT.js} +12 -9
- package/dist/{serve-3C2VFPAY.js.map → serve-D3GO36UT.js.map} +1 -1
- package/dist/{status-MKQYX5MW.js → status-KOSKCETC.js} +9 -7
- package/dist/{status-MKQYX5MW.js.map → status-KOSKCETC.js.map} +1 -1
- package/dist/statusline-ZNTCL5YC.js +59 -0
- package/dist/statusline-ZNTCL5YC.js.map +1 -0
- package/dist/{telemetry-3DN6XGYB.js → telemetry-XIKUUGTQ.js} +5 -4
- package/dist/{telemetry-3DN6XGYB.js.map → telemetry-XIKUUGTQ.js.map} +1 -1
- package/dist/{trae-CQC72RHH.js → trae-NWT3TMSZ.js} +99 -5
- package/dist/trae-NWT3TMSZ.js.map +1 -0
- package/dist/{types-CNigfEuR.d.ts → types-BEKsAium.d.ts} +268 -6
- package/dist/{uninstall-WG6PFWF3.js → uninstall-2LBLQVFA.js} +11 -9
- package/dist/{uninstall-WG6PFWF3.js.map → uninstall-2LBLQVFA.js.map} +1 -1
- package/dist/{upgrade-32NC2RKI.js → upgrade-ZC2S7VRN.js} +11 -9
- package/dist/{upgrade-32NC2RKI.js.map → upgrade-ZC2S7VRN.js.map} +1 -1
- package/dist/{usage-CJOM2WQM.js → usage-E2A4O2CY.js} +3 -3
- package/dist/{usage-event-472X3DOY.js → usage-event-JKMC4QC4.js} +11 -8
- package/dist/{usage-event-472X3DOY.js.map → usage-event-JKMC4QC4.js.map} +1 -1
- package/dist/{vscode-copilot-4RVRTCKV.js → vscode-copilot-ALV45XF6.js} +3 -3
- package/dist/{warp-X6MB67NT.js → warp-H6IX4U3J.js} +3 -3
- package/dist/{zed-NTCYW4V2.js → zed-RH34TNSW.js} +3 -3
- package/package.json +9 -1
- package/dist/amp-YGV66GJT.js.map +0 -1
- package/dist/chunk-3JCRUROU.js.map +0 -1
- package/dist/chunk-3RBLIHPZ.js.map +0 -1
- package/dist/chunk-GSGDG2BV.js.map +0 -1
- package/dist/chunk-KMAKDD3Z.js.map +0 -1
- package/dist/chunk-KVAAFYRR.js.map +0 -1
- package/dist/chunk-MEH7GC7R.js.map +0 -1
- package/dist/chunk-NJU275US.js +0 -238
- package/dist/chunk-NJU275US.js.map +0 -1
- package/dist/chunk-PD4VFEBY.js.map +0 -1
- package/dist/chunk-ZAM4M7LI.js.map +0 -1
- package/dist/claude-code-4275HQU4.js.map +0 -1
- package/dist/codebuff-LE3KBZGM.js.map +0 -1
- package/dist/cursor-UH3W622V.js.map +0 -1
- package/dist/doctor-DZTWED4O.js.map +0 -1
- package/dist/droid-T5VBRXZF.js.map +0 -1
- package/dist/goose-M3RR3CZG.js.map +0 -1
- package/dist/openclaw-UZ5BMCGQ.js.map +0 -1
- package/dist/roo-code-NI5UU6JB.js.map +0 -1
- package/dist/trae-CQC72RHH.js.map +0 -1
- /package/dist/{antigravity-7IBYFO6P.js.map → antigravity-ANDKF3K7.js.map} +0 -0
- /package/dist/{antigravity-cli-JEOUP2VN.js.map → antigravity-cli-LLRPDDOT.js.map} +0 -0
- /package/dist/{chunk-SCVBYSF7.js.map → chunk-6XHB6BE3.js.map} +0 -0
- /package/dist/{chunk-KQSNDFBN.js.map → chunk-LL4OBGRU.js.map} +0 -0
- /package/dist/{chunk-WNREHWKL.js.map → chunk-MAH6QQTO.js.map} +0 -0
- /package/dist/{codex-4BY2ZJIW.js.map → codex-BXA4FIF4.js.map} +0 -0
- /package/dist/{copilot-cli-IPISKO3V.js.map → copilot-cli-ROIBTTDT.js.map} +0 -0
- /package/dist/{crush-X3E25EQG.js.map → crush-QLEFLHUC.js.map} +0 -0
- /package/dist/{gemini-cli-ZSUK55UA.js.map → gemini-cli-SLVWLXJW.js.map} +0 -0
- /package/dist/{hermes-CUNKIAR5.js.map → hermes-ONDCECP2.js.map} +0 -0
- /package/dist/{jetbrains-copilot-C3HDGGML.js.map → jetbrains-copilot-YABZ3HFA.js.map} +0 -0
- /package/dist/{kilo-PKAJCWPX.js.map → kilo-F3ZDZKCT.js.map} +0 -0
- /package/dist/{kilo-cli-QWUVXG2O.js.map → kilo-cli-3HWPWBY4.js.map} +0 -0
- /package/dist/{kimi-EVD7YKXS.js.map → kimi-NV72FVAO.js.map} +0 -0
- /package/dist/{kiro-UQRY6EIO.js.map → kiro-C5W6AGDR.js.map} +0 -0
- /package/dist/{leaderboard-CSWHI4UY.js.map → leaderboard-TIBVONVT.js.map} +0 -0
- /package/dist/{mux-5CI5FP2W.js.map → mux-DSSH4AFS.js.map} +0 -0
- /package/dist/{omp-AXA7XY22.js.map → omp-Z6FRNDPN.js.map} +0 -0
- /package/dist/{opencode-NZBRLJN3.js.map → opencode-Q6KBSAKW.js.map} +0 -0
- /package/dist/{pi-WMTUX6ES.js.map → pi-LZT6WWAZ.js.map} +0 -0
- /package/dist/{qwen-code-MRRIUQ3P.js.map → qwen-code-WQBKRPWJ.js.map} +0 -0
- /package/dist/{usage-CJOM2WQM.js.map → usage-E2A4O2CY.js.map} +0 -0
- /package/dist/{vscode-copilot-4RVRTCKV.js.map → vscode-copilot-ALV45XF6.js.map} +0 -0
- /package/dist/{warp-X6MB67NT.js.map → warp-H6IX4U3J.js.map} +0 -0
- /package/dist/{zed-NTCYW4V2.js.map → zed-RH34TNSW.js.map} +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/adapters/openclaw/index.ts"],"sourcesContent":["/**\n * adapters/openclaw — OpenClaw (Gateway) platform adapter for agent-connector.\n *\n * OpenClaw is a **ts-plugin** host, but with a twist no other ts-plugin host\n * has: a plugin only delivers its MCP tools to the agent when it is registered\n * in TWO places at once (DUAL REGISTRATION):\n *\n * (a) plugins.entries.<id> = { enabled: true } + plugins.load.paths: [dir]\n * — so the gateway DISCOVERS and LOADS the plugin\n * module (runs register(api), wiring the hooks).\n * NOTE: the entry is { enabled } only — a per-entry\n * `module` field is rejected by `openclaw config\n * validate`, so discovery goes through the\n * plugins.load.paths dir scan instead; and\n * (b) mcp.servers.<id> — nested under a top-level \"mcp\" object, so the\n * plugin's MCP tools SURFACE to the agent.\n *\n * If only (a) is present, the plugin loads but ZERO tools reach the agent.\n * If only (b) is present, the tools are declared but the hook bridge never\n * loads. context-mode's own adapter proved this empirically against OpenClaw\n * 2026.4.22 (src/adapters/openclaw/index.ts checkPluginRegistration: \"in\n * plugins.entries but missing from mcp.servers — plugin loads but no ctx_*\n * tools reach the agent\"). So getHealthChecks() FAILS when the two are\n * inconsistent (entries XOR mcp.servers).\n *\n * Why we BRIDGE instead of importing handlers (mirrors the OpenCode adapter):\n * context-mode could load ITS OWN plugin in-process because the handler code\n * shipped with the package. agent-connector cannot: the connector's hook\n * handlers are arbitrary developer code we must not import into the gateway's\n * runtime (wrong cwd, wrong deps, version skew). So installHooks synthesizes a\n * tiny, fully self-contained ESM plugin module — { id, name, configSchema,\n * register(api) } — that imports NOTHING from agent-connector and, on each\n * hook firing, shells out to the ONE stable home binary's universal entrypoint\n * <homeBin> hook openclaw <event> --connector <id>\n * feeding the event payload on stdin and JSON.parsing the normalized\n * HookResponse back from stdout. Fail-open: any bridge error → no-op. The same\n * universal json-stdio dispatcher every other host uses thus serves OpenClaw.\n *\n * Plugin module shape (grounded in context-mode build/adapters/openclaw/plugin.js):\n * export default { id, name, configSchema, register(api) }\n * register(api) wires typed lifecycle hooks via api.on(event, handler):\n * before_tool_call → block (return { block, blockReason }) / rewrite args\n * (mutate event.params in place); deny+ask both block.\n * after_tool_call → observe (capture result/output).\n * session_start → record the real session id.\n * before_prompt_build → inject SessionStart additionalContext via\n * { appendSystemContext } (the verified context-injection\n * point; session_start itself returns no context payload).\n * subagent_spawned / subagent_ended → observe the subagent lifecycle\n * (SubagentStart / SubagentStop; observe-only — no\n * decision or context payload).\n * api.on() is the correct API for typed lifecycle hooks; api.registerHook() is\n * for generic command hooks. We register defensively (api.on present check).\n *\n * Config file (JSON5 / JSONC — PARSE TOLERANTLY):\n * user scope → resolveOpenClawConfigPath():\n * $OPENCLAW_CONFIG_PATH\n * else $OPENCLAW_STATE_DIR/openclaw.json\n * else ~/.openclaw/openclaw.json\n * (mirrors context-mode openclawConfigPath — the file the\n * gateway actually loads, NOT process.cwd()).\n * project scope → <projectDir>/openclaw.json (also supported).\n * openclaw.json may contain comments + trailing commas (JSON5), so we NEVER\n * use strict JSON.parse — readJson is overridden to strip comments/commas\n * first via the shared core/jsonc parseJsonc. writes are strict JSON\n * (idempotent, comment-free).\n *\n * Plugin module location (project | user):\n * user → <stateDir>/extensions/<id>/index.mjs (stateDir = dir of openclaw.json)\n * project → <projectDir>/.openclaw/extensions/<id>/index.mjs\n * Beside index.mjs we also emit an openclaw.plugin.json manifest. The plugin's\n * DIRECTORY (not the file) is added to plugins.load.paths so the gateway scans\n * it and loads the module; the plugins.entries.<id> = { enabled: true } half\n * then activates it. (There is no per-entry \"module\" field — validate rejects it.)\n *\n * The gateway hot-reloads its config on SIGUSR1 — no action needed here; the\n * next reload (or restart) picks up our entries/servers/module.\n *\n * Capabilities (per OpenClaw hook API):\n * preToolUse / postToolUse / sessionStart / subagentStart / subagentStop\n * true; transports [\"stdio\"].\n * before_tool_call mutates event.params → canModifyArgs true.\n * after_tool_call cannot rewrite the tool result → canModifyOutput false.\n * before_prompt_build injects context → canInjectSessionContext true.\n */\n\nimport {\n chmodSync,\n existsSync,\n mkdirSync,\n readFileSync,\n rmSync,\n writeFileSync,\n} from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { dirname, join, resolve } from \"node:path\";\n\nimport { BaseAdapter } from \"../base.js\";\nimport type {\n Adapter,\n GeneratedPluginFile,\n HookReply,\n InstallContext,\n MemoryTarget,\n NormalizedEvent,\n} from \"../spi.js\";\nimport type {\n ChangeRecord,\n DetectedPlatform,\n HealthCheck,\n HookEventName,\n HookParadigm,\n HookResponse,\n PlatformCapabilities,\n PlatformId,\n PostToolUseEvent,\n PreToolUseEvent,\n ServerDef,\n SessionStartEvent,\n SkillDef,\n SubagentStartEvent,\n SubagentStopEvent,\n} from \"../../core/types.js\";\nimport { resolveEnvRefsDeep } from \"../../core/interpolate.js\";\nimport { parseJsonc } from \"../../core/jsonc.js\";\nimport {\n buildServeWrapperCommand,\n shouldWrapForTelemetry,\n} from \"../../core/spawn.js\";\n\nconst HOST: PlatformId = \"openclaw\";\n\n/**\n * MCP servers live nested under the top-level \"mcp\" object: mcp.servers.<id>\n * (NOT a top-level \"mcpServers\" key). plugins.entries.<id> is the second half of\n * the dual registration.\n */\nconst MCP_ROOT_KEY = \"mcp\";\nconst MCP_SERVERS_KEY = \"servers\";\nconst PLUGINS_KEY = \"plugins\";\nconst PLUGINS_ENTRIES_KEY = \"entries\";\n/**\n * The gateway discovers a synthesized plugin module by scanning the directories\n * listed in plugins.load.paths — it does NOT take a per-entry `module` field\n * (that fails `openclaw config validate`). We add the plugin's own dir here.\n */\nconst PLUGINS_LOAD_KEY = \"load\";\nconst PLUGINS_LOAD_PATHS_KEY = \"paths\";\n/** Manifest the gateway reads inside a plugins.load.paths directory. */\nconst PLUGIN_MANIFEST_FILE = \"openclaw.plugin.json\";\n\n/**\n * Canonical → OpenClaw event name map. A connector hook event is only emitted by\n * the generated plugin when it appears here AND is declared by the connector.\n *\n * SessionStart maps to OpenClaw's session_start (to learn the real session id)\n * plus before_prompt_build (the verified context-injection point — session_start\n * itself returns no context payload upstream).\n */\nconst EVENT_TO_OPENCLAW: Partial<Record<HookEventName, string>> = {\n PreToolUse: \"before_tool_call\",\n PostToolUse: \"after_tool_call\",\n SessionStart: \"session_start\",\n // Subagent lifecycle: OpenClaw observes launch + completion (no decision\n // control on either). PermissionRequest is deliberately ABSENT — OpenClaw's\n // permission gate is the requireApproval RETURN VALUE of before_tool_call,\n // not an observable event; PostToolUseFailure is ABSENT too (a failure\n // arrives merged into after_tool_call, already surfaced as PostToolUse\n // isError). Unmapped declared events are reported as \"unsupported here\".\n SubagentStart: \"subagent_spawned\",\n SubagentStop: \"subagent_ended\",\n};\n\n/** Raw payload the generated plugin posts to the universal hook entrypoint. */\ninterface OpenClawBridgePayload {\n toolName?: string;\n toolInput?: Record<string, unknown>;\n toolOutput?: string;\n isError?: boolean;\n sessionId?: string;\n source?: string;\n projectDir?: string;\n // subagent_spawned / subagent_ended (the generated plugin normalizes the\n // host's field-name variants before posting; empty strings are omitted).\n agentId?: string;\n agentType?: string;\n lastAssistantMessage?: string;\n}\n\n/**\n * Native MCP server entry shapes OpenClaw accepts under mcp.servers.<id>.\n *\n * A stdio sidecar carries NO `transport` field: OpenClaw's config validator\n * only accepts `transport: \"sse\" | \"streamable-http\"` for remote servers and\n * REJECTS `transport: \"stdio\"` (verified against OpenClaw 2026.6.1). A stdio\n * server is INFERRED from the presence of `command`, so we must never write a\n * transport key here.\n */\ninterface OpenClawStdioServer {\n command: string;\n args?: string[];\n env?: Record<string, string>;\n enabled?: boolean;\n}\ninterface OpenClawRemoteServer {\n url: string;\n transport: \"sse\" | \"http\";\n headers?: Record<string, string>;\n enabled?: boolean;\n}\n\n/**\n * plugins.entries.<id> reference shape.\n *\n * `openclaw config validate` REJECTS a `module` field here (it is not part of\n * the entry schema), so the entry is `{ enabled: true }` ONLY. Discovery of the\n * synthesized module is wired separately via `plugins.load.paths` (the dir that\n * holds the module + its openclaw.plugin.json manifest).\n */\ninterface OpenClawPluginEntry {\n enabled: boolean;\n}\n\nexport class OpenClawAdapter extends BaseAdapter implements Adapter {\n readonly id: PlatformId = HOST;\n // Declared as `string` (not the literal \"OpenClaw\") so a fork adapter can\n // override it — NemoClaw extends this class (precedent: AntigravityAdapter,\n // whose name is likewise typed `string` for AntigravityCliAdapter).\n readonly name: string = \"OpenClaw\";\n readonly paradigm: HookParadigm = \"ts-plugin\";\n\n readonly capabilities: PlatformCapabilities = {\n // Memory surface: AGENTS.md-first managed block. OpenClaw's AGENTS.md\n // lives in the AGENT WORKSPACE (default ~/.openclaw/workspace), NOT the\n // user's repo — memoryTargets below maps BOTH scopes there (R2:\n // platforms force scopes; personal-assistant semantics, no project file).\n supportsMemory: true,\n preToolUse: true,\n postToolUse: true,\n // OpenClaw compaction is owned by a context engine, not wired through the\n // universal bridge here.\n preCompact: false,\n sessionStart: true,\n sessionEnd: false,\n userPromptSubmit: false,\n stop: false,\n notification: false,\n // Newer events: OpenClaw observes the full subagent lifecycle via\n // subagent_spawned / subagent_ended (observe-only — no decision control,\n // so a SubagentStop \"deny\" cannot keep the subagent running here).\n // permissionRequest / postToolUseFailure stay unset: the permission gate\n // is a RETURN VALUE of before_tool_call (not an event) and tool failures\n // arrive merged into after_tool_call. Install reports the standard\n // \"unsupported here\" for unmapped declared events.\n subagentStart: true,\n subagentStop: true,\n // before_tool_call mutates event.params in place → input rewrite supported.\n canModifyArgs: true,\n // after_tool_call observes but cannot rewrite the tool result upstream.\n canModifyOutput: false,\n // injected via before_prompt_build at prompt assembly.\n canInjectSessionContext: true,\n // OpenClaw's MCP sidecar registration is stdio-only in practice.\n transports: [\"stdio\"],\n // Content surface: OpenClaw follows the AgentSkills spec (dir-per-skill\n // SKILL.md with {name, description} frontmatter + body). User scope →\n // ~/.openclaw/skills (the `openclaw skills install --global` target);\n // project scope → the resolved <workspace>/skills (the highest-priority\n // documented skill root, the same workspace the memory surface anchors to).\n supportsSkills: true,\n };\n\n // ── Tolerant JSON5/JSONC read (override base strict JSON.parse) ──────────\n\n /**\n * openclaw.json is officially JSON5 (comments + trailing commas allowed). A\n * strict JSON.parse false-fails a perfectly valid commented file, so we strip\n * comments and trailing commas before parsing. Writes remain strict JSON\n * (writeJson in BaseAdapter), which is itself valid JSON5 — so round-trips\n * stay safe and idempotent.\n */\n protected override readJson<T = Record<string, unknown>>(path: string): T | null {\n if (!existsSync(path)) return null;\n let raw: string;\n try {\n raw = readFileSync(path, \"utf8\");\n } catch {\n return null;\n }\n try {\n // Shared, string-aware JSONC stripper (the local stripJsonish whose\n // trailing-comma regex corrupted in-string \",]\"/\",}\"-like values is gone).\n return parseJsonc<T>(raw);\n } catch {\n return null;\n }\n }\n\n // ── Memory surface: agent-workspace AGENTS.md (both scopes) ─────────────\n /**\n * OpenClaw loads AGENTS.md (operating instructions) from its AGENT WORKSPACE\n * every session — `agents.defaults.workspace` in openclaw.json when set,\n * else `<stateDir>/workspace` (default ~/.openclaw/workspace). That file is\n * personal-assistant state, NOT a repo file, so a \"project scope\" write does\n * not apply: BOTH scopes map to the workspace (R2: platforms force scopes),\n * with the reason string flagging the semantics.\n */\n protected override memoryTargets(ctx: InstallContext): MemoryTarget[] {\n if (this.memoryOverride(ctx)?.path) return super.memoryTargets(ctx);\n if (ctx.scope !== \"project\" && ctx.scope !== \"user\") return [];\n return [\n {\n path: join(this.resolveWorkspace(), \"AGENTS.md\"),\n reason:\n \"openclaw agent-workspace AGENTS.md (workspace-scoped operating instructions, \" +\n \"not the project repo — both scopes map here)\",\n },\n ];\n }\n\n /**\n * Resolve OpenClaw's AGENT WORKSPACE — `agents.defaults.workspace` in\n * openclaw.json when set, else `<stateDir>/workspace` (default\n * ~/.openclaw/workspace). The same root the memory surface and the\n * project-scope skills surface both anchor to, so they never diverge.\n */\n private resolveWorkspace(): string {\n const configPath = resolveOpenClawConfigPath();\n const cfg = this.readJson<{ agents?: { defaults?: { workspace?: unknown } } }>(configPath);\n const declared = cfg?.agents?.defaults?.workspace;\n return typeof declared === \"string\" && declared.trim() !== \"\"\n ? declared.startsWith(\"~\")\n ? resolve(homedir(), declared.replace(/^~[/\\\\]?/, \"\"))\n : resolve(declared)\n : join(dirname(configPath), \"workspace\");\n }\n\n // ── Detection ──────────────────────────────────────────────────────────\n\n detectInstalled(projectDir: string): DetectedPlatform {\n const userConfig = resolveOpenClawConfigPath();\n const userDir = join(homedir(), \".openclaw\");\n const projectConfig = join(projectDir, \"openclaw.json\");\n\n // Fork-before-parent at DETECTION: NemoClaw DRIVES ~/.openclaw/openclaw.json,\n // so on a NemoClaw box (its ~/.nemoclaw/ marker present) the user-scope\n // OpenClaw config is nemoclaw-OWNED — defer so the planner does not double-\n // target the shared file as two platforms (an `uninstall openclaw` would\n // otherwise strip the connector's entries out from under nemoclaw). The\n // NemoClaw adapter overrides detectInstalled, so it is unaffected by this.\n const deferToNemoClaw = existsSync(join(homedir(), \".nemoclaw\"));\n const userInstalled =\n !deferToNemoClaw && (existsSync(userConfig) || existsSync(userDir));\n const projInstalled = existsSync(projectConfig);\n const installed = userInstalled || projInstalled;\n\n const scope = projInstalled && !userInstalled ? \"project\" : \"user\";\n const configPath = scope === \"project\" ? projectConfig : userConfig;\n\n return {\n id: this.id,\n name: this.name,\n installed,\n paradigm: this.paradigm,\n capabilities: this.capabilities,\n configPath,\n scope,\n reason: installed\n ? scope === \"project\"\n ? `found project OpenClaw config at ${projectConfig}`\n : `found OpenClaw config at ${configPath}`\n : `no OpenClaw config at ${userConfig} or ${userDir}`,\n confidence: installed ? \"high\" : \"low\",\n };\n }\n\n // ── Native paths ───────────────────────────────────────────────────────\n\n getConfigDir(ctx: InstallContext): string {\n return ctx.scope === \"project\"\n ? ctx.projectDir\n : dirname(resolveOpenClawConfigPath());\n }\n\n getServerConfigPath(ctx: InstallContext): string {\n return ctx.scope === \"project\"\n ? join(ctx.projectDir, \"openclaw.json\")\n : resolveOpenClawConfigPath();\n }\n\n /**\n * For ts-plugin hosts the \"hook config path\" is the generated plugin FILE.\n * OpenClaw additionally needs the plugins.entries reference written into\n * openclaw.json (handled in installHooks); this is the module on disk.\n */\n getHookConfigPath(ctx: InstallContext): string {\n return join(this.pluginDir(ctx), this.pluginFileName());\n }\n\n /** Extensions directory the synthesized plugin module is written into. */\n private pluginDir(ctx: InstallContext): string {\n const base =\n ctx.scope === \"project\"\n ? join(ctx.projectDir, \".openclaw\")\n : dirname(resolveOpenClawConfigPath());\n return join(base, \"extensions\", ctx.connector.id);\n }\n\n /** Plugin module file name (ESM so the gateway loads it without a loader). */\n private pluginFileName(): string {\n return \"index.mjs\";\n }\n\n // ── MCP server install / uninstall (mcp.servers.<id>) ───────────────────\n\n installServer(ctx: InstallContext): ChangeRecord[] {\n const server = this.effectiveServer(ctx);\n const serverPath = this.getServerConfigPath(ctx);\n\n if (!server) {\n return [\n {\n platform: this.id,\n action: \"skip\",\n path: serverPath,\n detail: ctx.connector.server\n ? \"server registration disabled for openclaw\"\n : \"connector declares no MCP server\",\n },\n ];\n }\n\n const entry = this.renderServerEntry(ctx, server);\n return [this.upsertNestedServer(serverPath, ctx.connector.id, entry, ctx.dryRun)];\n }\n\n uninstallServer(ctx: InstallContext): ChangeRecord[] {\n const serverPath = this.getServerConfigPath(ctx);\n return [this.removeNestedServer(serverPath, ctx.connector.id, ctx.dryRun)];\n }\n\n /** Resolve the per-platform server override into an effective ServerDef. */\n private effectiveServer(ctx: InstallContext): ServerDef | undefined {\n const override = ctx.connector.platforms[this.id]?.server;\n if (override === false) return undefined;\n const base = ctx.connector.server;\n if (!base) return undefined;\n return override && typeof override === \"object\" ? { ...base, ...override } : base;\n }\n\n /**\n * Render a normalized ServerDef into OpenClaw's native mcp.servers.<id> entry.\n *\n * stdio → { command, args?, env? } (NO transport key — a stdio sidecar is\n * inferred from `command`; OpenClaw's validator rejects\n * transport:\"stdio\" and only accepts \"sse\"/\"streamable-http\")\n * remote → { url, transport: \"sse\"|\"http\", headers? }\n *\n * OpenClaw documents no native ${env:VAR} token, so refs resolve to literals.\n */\n private renderServerEntry(\n ctx: InstallContext,\n server: ServerDef,\n ): OpenClawStdioServer | OpenClawRemoteServer {\n if (server.transport === \"stdio\") {\n let command = server.command ?? \"\";\n let args = [...(server.args ?? [])];\n\n // Transparent telemetry wrapping: route the real command through\n // `<homeBin> serve --connector <id> -- <command> <args...>`.\n if (shouldWrapForTelemetry(server, ctx.connector.telemetry)) {\n const wrapped = buildServeWrapperCommand(\n ctx.homeBinPath,\n ctx.connector.id,\n command,\n args,\n ctx.scope,\n this.id,\n );\n command = wrapped.command;\n args = wrapped.args;\n }\n\n // NO `transport` key: OpenClaw infers a stdio sidecar from `command` and\n // its validator rejects transport:\"stdio\" (only \"sse\"/\"streamable-http\").\n const entry: OpenClawStdioServer = {\n command: resolveEnvRefsDeep(command),\n };\n const resolvedArgs = resolveEnvRefsDeep(args).filter((s) => s !== \"\");\n if (resolvedArgs.length > 0) entry.args = resolvedArgs;\n const env = this.renderEnv(server.env);\n if (env) entry.env = env;\n if (server.enabled === false) entry.enabled = false;\n return entry;\n }\n\n // sse / http / ws → OpenClaw registers a remote URL sidecar.\n const transport: \"sse\" | \"http\" = server.transport === \"http\" ? \"http\" : \"sse\";\n const entry: OpenClawRemoteServer = {\n url: resolveEnvRefsDeep(server.url ?? \"\"),\n transport,\n };\n if (server.headers && Object.keys(server.headers).length > 0) {\n entry.headers = resolveEnvRefsDeep({ ...server.headers });\n }\n if (server.enabled === false) entry.enabled = false;\n return entry;\n }\n\n /** Resolve every ${env:VAR} in env values to literals (no native token). */\n private renderEnv(\n env: Record<string, string> | undefined,\n ): Record<string, string> | undefined {\n if (!env || Object.keys(env).length === 0) return undefined;\n return resolveEnvRefsDeep({ ...env });\n }\n\n /** Upsert config.mcp.servers.<id> idempotently. */\n private upsertNestedServer(\n path: string,\n id: string,\n entry: unknown,\n dryRun: boolean,\n ): ChangeRecord {\n // OVERWRITE GUARD: never blank a present-but-unparseable openclaw.json.\n if (this.isPresentButUnparseable(path)) {\n return {\n platform: this.id,\n action: \"warn\",\n path,\n detail: `existing ${path} is not parseable; left untouched (back it up / fix it, then re-run)`,\n };\n }\n const cfg = this.readJson<Record<string, unknown>>(path) ?? {};\n const servers = this.nestedServersBucket(cfg);\n const before = JSON.stringify(servers[id]);\n const after = JSON.stringify(entry);\n let action: ChangeRecord[\"action\"];\n if (before === undefined) action = \"create\";\n else if (before === after) action = \"skip\";\n else action = \"update\";\n if (action !== \"skip\") {\n servers[id] = entry;\n this.writeJson(path, cfg, dryRun);\n }\n return {\n platform: this.id,\n action,\n path,\n detail: `${MCP_ROOT_KEY}.${MCP_SERVERS_KEY}.${id}`,\n };\n }\n\n /** Remove config.mcp.servers.<id>. */\n private removeNestedServer(path: string, id: string, dryRun: boolean): ChangeRecord {\n const cfg = this.readJson<Record<string, unknown>>(path);\n const mcp = cfg?.[MCP_ROOT_KEY];\n const servers =\n mcp && typeof mcp === \"object\" && !Array.isArray(mcp)\n ? ((mcp as Record<string, unknown>)[MCP_SERVERS_KEY] as\n | Record<string, unknown>\n | undefined)\n : undefined;\n if (!cfg || !servers || !(id in servers)) {\n return {\n platform: this.id,\n action: \"skip\",\n path,\n detail: `${MCP_ROOT_KEY}.${MCP_SERVERS_KEY}.${id} absent`,\n };\n }\n delete servers[id];\n this.writeJson(path, cfg, dryRun);\n return {\n platform: this.id,\n action: \"remove\",\n path,\n detail: `${MCP_ROOT_KEY}.${MCP_SERVERS_KEY}.${id}`,\n };\n }\n\n /** Get-or-create config.mcp.servers as a mutable object. */\n private nestedServersBucket(cfg: Record<string, unknown>): Record<string, unknown> {\n let mcp = cfg[MCP_ROOT_KEY];\n if (!mcp || typeof mcp !== \"object\" || Array.isArray(mcp)) {\n mcp = {};\n cfg[MCP_ROOT_KEY] = mcp;\n }\n const mcpObj = mcp as Record<string, unknown>;\n let servers = mcpObj[MCP_SERVERS_KEY];\n if (!servers || typeof servers !== \"object\" || Array.isArray(servers)) {\n servers = {};\n mcpObj[MCP_SERVERS_KEY] = servers;\n }\n return servers as Record<string, unknown>;\n }\n\n // ── Hook install / uninstall (ts-plugin + DUAL REGISTRATION) ────────────\n\n installHooks(ctx: InstallContext): ChangeRecord[] {\n const pluginPath = this.getHookConfigPath(ctx);\n const configPath = this.getServerConfigPath(ctx);\n\n if (ctx.connector.platforms[this.id]?.hooks === false) {\n return [\n { platform: this.id, action: \"skip\", path: pluginPath, detail: `hooks disabled for ${this.id}` },\n ];\n }\n if (ctx.connector.hookEvents.length === 0) {\n return [\n { platform: this.id, action: \"skip\", path: pluginPath, detail: \"connector declares no hooks\" },\n ];\n }\n\n const changes: ChangeRecord[] = [];\n\n // 1. Write the synthesized plugin module(s).\n for (const file of this.synthesizePlugin(ctx)) {\n const before = existsSync(file.path) ? this.safeRead(file.path) : undefined;\n let action: ChangeRecord[\"action\"];\n if (before === undefined) action = \"create\";\n else if (before === file.contents) action = \"skip\";\n else action = \"update\";\n\n if (action !== \"skip\" && !ctx.dryRun) {\n ensureDir(dirname(file.path));\n writeFileSync(file.path, file.contents, \"utf8\");\n chmodSync(file.path, file.executable ? 0o755 : 0o644);\n }\n changes.push({\n platform: this.id,\n action,\n path: file.path,\n detail: `openclaw plugin module (${this.hookDetail(ctx)})`,\n });\n }\n\n // 2. DUAL REGISTRATION half (a): enable plugins.entries.<id> AND add the\n // plugin DIR to plugins.load.paths so the gateway discovers + loads the\n // module. (half (b), mcp.servers.<id>, is written by installServer — both\n // are required for tools to reach the agent.)\n changes.push(this.upsertPluginEntry(configPath, ctx, this.pluginDir(ctx)));\n\n return changes;\n }\n\n /**\n * Human-facing summary of which declared events the synthesized module ACTUALLY\n * wires. Only events present in EVENT_TO_OPENCLAW are mapped/wired; any declared\n * event with no OpenClaw mapping (e.g. UserPromptSubmit) is reported separately\n * as \"unsupported here\" so the detail never overstates coverage.\n */\n private hookDetail(ctx: InstallContext): string {\n const declared = ctx.connector.hookEvents;\n const mapped = declared.filter((e) => EVENT_TO_OPENCLAW[e] !== undefined);\n const unsupported = declared.filter((e) => EVENT_TO_OPENCLAW[e] === undefined);\n const base = mapped.join(\",\");\n return unsupported.length > 0\n ? `${base}; unsupported here: ${unsupported.join(\",\")}`\n : base;\n }\n\n uninstallHooks(ctx: InstallContext): ChangeRecord[] {\n const pluginPath = this.getHookConfigPath(ctx);\n const configPath = this.getServerConfigPath(ctx);\n const changes: ChangeRecord[] = [];\n\n // 1. Remove the plugins.entries.<id> reference AND drop the plugin dir from\n // plugins.load.paths.\n changes.push(\n this.removePluginEntry(configPath, ctx.connector.id, this.pluginDir(ctx), ctx.dryRun),\n );\n\n // 2. Remove the plugin module + its manifest on disk.\n const manifestPath = join(this.pluginDir(ctx), PLUGIN_MANIFEST_FILE);\n for (const [path, label] of [\n [pluginPath, \"openclaw plugin module\"],\n [manifestPath, \"openclaw plugin manifest\"],\n ] as const) {\n if (existsSync(path)) {\n if (!ctx.dryRun) rmSync(path, { force: true });\n changes.push({ platform: this.id, action: \"remove\", path, detail: label });\n } else {\n changes.push({\n platform: this.id,\n action: \"skip\",\n path,\n detail: `no ${label} present`,\n });\n }\n }\n\n // 3. Drop the now-empty plugin dir (only if WE own its full contents).\n changes.push(this.removeDirIfEmpty(this.pluginDir(ctx), ctx.dryRun));\n\n return changes;\n }\n\n /**\n * Upsert plugins.entries.<id> = { enabled: true } AND add `pluginDir` to\n * plugins.load.paths idempotently.\n *\n * `openclaw config validate` rejects a per-entry `module` field, so the entry\n * carries ONLY `{ enabled: true }`. The gateway discovers the synthesized\n * module by scanning the directories in plugins.load.paths (the dir holding\n * index.mjs + openclaw.plugin.json), so the dir is added there.\n */\n private upsertPluginEntry(\n configPath: string,\n ctx: InstallContext,\n pluginDir: string,\n ): ChangeRecord {\n // OVERWRITE GUARD: never blank a present-but-unparseable openclaw.json.\n if (this.isPresentButUnparseable(configPath)) {\n return {\n platform: this.id,\n action: \"warn\",\n path: configPath,\n detail: `existing ${configPath} is not parseable; left untouched (back it up / fix it, then re-run)`,\n };\n }\n const cfg = this.readJson<Record<string, unknown>>(configPath) ?? {};\n const entries = this.pluginEntriesBucket(cfg);\n const id = ctx.connector.id;\n const desired: OpenClawPluginEntry = { enabled: true };\n const entryBefore = JSON.stringify(entries[id]);\n const entryAfter = JSON.stringify(desired);\n\n // plugins.load.paths: add the plugin dir if absent.\n const loadPaths = this.pluginLoadPathsBucket(cfg);\n const pathPresent = loadPaths.includes(pluginDir);\n\n const entryChanged = entryBefore !== entryAfter;\n const pathChanged = !pathPresent;\n let action: ChangeRecord[\"action\"];\n if (entryBefore === undefined) action = \"create\";\n else if (!entryChanged && !pathChanged) action = \"skip\";\n else action = \"update\";\n\n if (action !== \"skip\") {\n entries[id] = desired;\n if (!pathPresent) loadPaths.push(pluginDir);\n this.writeJson(configPath, cfg, ctx.dryRun);\n }\n return {\n platform: this.id,\n action,\n path: configPath,\n detail: `${PLUGINS_KEY}.${PLUGINS_ENTRIES_KEY}.${id} + ${PLUGINS_KEY}.${PLUGINS_LOAD_KEY}.${PLUGINS_LOAD_PATHS_KEY}`,\n };\n }\n\n /** Remove plugins.entries.<id> AND drop `pluginDir` from plugins.load.paths. */\n private removePluginEntry(\n configPath: string,\n id: string,\n pluginDir: string,\n dryRun: boolean,\n ): ChangeRecord {\n const cfg = this.readJson<Record<string, unknown>>(configPath);\n const plugins = cfg?.[PLUGINS_KEY];\n const pluginsObj =\n plugins && typeof plugins === \"object\" && !Array.isArray(plugins)\n ? (plugins as Record<string, unknown>)\n : undefined;\n const entries = pluginsObj?.[PLUGINS_ENTRIES_KEY] as\n | Record<string, unknown>\n | undefined;\n const load = pluginsObj?.[PLUGINS_LOAD_KEY] as Record<string, unknown> | undefined;\n const loadPaths =\n load && Array.isArray(load[PLUGINS_LOAD_PATHS_KEY])\n ? (load[PLUGINS_LOAD_PATHS_KEY] as unknown[])\n : undefined;\n\n const entryPresent = Boolean(entries && id in entries);\n const pathIdx = loadPaths ? loadPaths.indexOf(pluginDir) : -1;\n\n if (!cfg || (!entryPresent && pathIdx < 0)) {\n return {\n platform: this.id,\n action: \"skip\",\n path: configPath,\n detail: `${PLUGINS_KEY}.${PLUGINS_ENTRIES_KEY}.${id} absent`,\n };\n }\n if (entryPresent && entries) delete entries[id];\n if (loadPaths && pathIdx >= 0) loadPaths.splice(pathIdx, 1);\n this.writeJson(configPath, cfg, dryRun);\n return {\n platform: this.id,\n action: \"remove\",\n path: configPath,\n detail: `${PLUGINS_KEY}.${PLUGINS_ENTRIES_KEY}.${id} + ${PLUGINS_KEY}.${PLUGINS_LOAD_KEY}.${PLUGINS_LOAD_PATHS_KEY}`,\n };\n }\n\n /** Get-or-create config.plugins.entries as a mutable object. */\n private pluginEntriesBucket(cfg: Record<string, unknown>): Record<string, unknown> {\n let plugins = cfg[PLUGINS_KEY];\n if (!plugins || typeof plugins !== \"object\" || Array.isArray(plugins)) {\n plugins = {};\n cfg[PLUGINS_KEY] = plugins;\n }\n const pluginsObj = plugins as Record<string, unknown>;\n let entries = pluginsObj[PLUGINS_ENTRIES_KEY];\n if (!entries || typeof entries !== \"object\" || Array.isArray(entries)) {\n entries = {};\n pluginsObj[PLUGINS_ENTRIES_KEY] = entries;\n }\n return entries as Record<string, unknown>;\n }\n\n /** Get-or-create config.plugins.load.paths as a mutable string array. */\n private pluginLoadPathsBucket(cfg: Record<string, unknown>): string[] {\n let plugins = cfg[PLUGINS_KEY];\n if (!plugins || typeof plugins !== \"object\" || Array.isArray(plugins)) {\n plugins = {};\n cfg[PLUGINS_KEY] = plugins;\n }\n const pluginsObj = plugins as Record<string, unknown>;\n let load = pluginsObj[PLUGINS_LOAD_KEY];\n if (!load || typeof load !== \"object\" || Array.isArray(load)) {\n load = {};\n pluginsObj[PLUGINS_LOAD_KEY] = load;\n }\n const loadObj = load as Record<string, unknown>;\n const existing = loadObj[PLUGINS_LOAD_PATHS_KEY];\n // Normalize to a fresh string[] (drop any non-string a user may have placed\n // here) and write it back so the caller mutates the live array.\n const paths = Array.isArray(existing)\n ? existing.filter((p): p is string => typeof p === \"string\")\n : [];\n loadObj[PLUGINS_LOAD_PATHS_KEY] = paths;\n return paths;\n }\n\n // ── Content surface: skills (dir-per-skill SKILL.md) ────────────────────\n // CONTENT-ONLY: pure native-file writers, mirroring codex/claude-code\n // installSkills + renderSkill. No runtime dispatch, no home-bin pointer, no\n // telemetry wrap. Each write is idempotent (byte-identical → skip) via\n // writeContentFile and reversible via removeContentFile + removeDirIfEmpty\n // (never rm -rf a shared dir). Honors platforms[\"openclaw\"].skills === false.\n //\n // Native locations (AgentSkills spec — dir-per-skill SKILL.md + resources):\n // user → ~/.openclaw/skills/<name>/SKILL.md (`openclaw skills install\n // --global` targets this dir)\n // project → <workspace>/skills/<name>/SKILL.md (the highest-priority\n // documented skill root; <workspace> is the SAME root the memory\n // surface resolves, so both content surfaces stay consistent).\n\n /**\n * Per-skill directory for ctx.scope:\n * user → ~/.openclaw/skills/<name> (`--global` install target)\n * project → <workspace>/skills/<name> (resolved agent workspace —\n * consistent with this adapter's memoryTargets resolution).\n */\n private skillDir(ctx: InstallContext, name: string): string {\n const base =\n ctx.scope === \"project\"\n ? join(this.resolveWorkspace(), \"skills\")\n : join(dirname(resolveOpenClawConfigPath()), \"skills\");\n return join(base, name);\n }\n\n override installSkills(ctx: InstallContext): ChangeRecord[] {\n const { connector } = ctx;\n if (connector.platforms[this.id]?.skills === false) {\n return [{ platform: this.id, action: \"skip\", detail: `skills disabled for ${this.id}` }];\n }\n if (connector.skills.length === 0) {\n return [{ platform: this.id, action: \"skip\", detail: \"connector declares no skills\" }];\n }\n const changes: ChangeRecord[] = [];\n for (const skill of connector.skills) {\n const dir = this.skillDir(ctx, skill.name);\n changes.push(\n this.writeContentFile(join(dir, \"SKILL.md\"), this.renderSkill(skill), ctx.dryRun),\n );\n // Bundle any resource files beside SKILL.md (relative path → contents).\n // Defense-in-depth: skip+warn on any key that escapes the skill dir\n // (config-time validation already rejects these, but never trust input).\n for (const [rel, contents] of Object.entries(skill.resources ?? {})) {\n const target = this.resolveWithin(dir, rel);\n if (target === null) {\n changes.push({\n platform: this.id,\n action: \"warn\",\n detail: `skill resource \"${rel}\" escapes the skill dir; skipped`,\n });\n continue;\n }\n changes.push(this.writeContentFile(target, contents, ctx.dryRun));\n }\n }\n return changes;\n }\n\n override uninstallSkills(ctx: InstallContext): ChangeRecord[] {\n const { connector } = ctx;\n if (connector.skills.length === 0) {\n return [{ platform: this.id, action: \"skip\", detail: \"connector declares no skills\" }];\n }\n const changes: ChangeRecord[] = [];\n for (const skill of connector.skills) {\n const dir = this.skillDir(ctx, skill.name);\n // Remove only the files we wrote (SKILL.md + declared resources), then the\n // skill dir itself when we own its full contents.\n changes.push(this.removeContentFile(join(dir, \"SKILL.md\"), ctx.dryRun));\n for (const rel of Object.keys(skill.resources ?? {})) {\n const target = this.resolveWithin(dir, rel);\n if (target === null) continue; // never delete outside the skill dir\n changes.push(this.removeContentFile(target, ctx.dryRun));\n }\n // Only remove the skill dir when WE own its full contents — never rm -rf a\n // dir that still holds user-added / sibling-tool / shared files.\n changes.push(this.removeDirIfEmpty(dir, ctx.dryRun));\n }\n return changes;\n }\n\n /**\n * Render a skill's SKILL.md: frontmatter (name, description + optional model,\n * allowed-tools, disable-model-invocation) + body. UNIFORM with codex /\n * claude-code — only the parent dir differs (single-line frontmatter keys;\n * OpenClaw follows the AgentSkills spec).\n */\n private renderSkill(skill: SkillDef): string {\n const frontmatter: Record<string, unknown> = {\n name: skill.name,\n description: skill.description,\n };\n if (skill.model !== undefined) frontmatter.model = skill.model;\n const allow = skill.tools?.allow;\n if (allow && allow.length > 0) frontmatter[\"allowed-tools\"] = allow.join(\", \");\n if (skill.disableModelInvocation !== undefined) {\n frontmatter[\"disable-model-invocation\"] = skill.disableModelInvocation;\n }\n if (skill.extra) Object.assign(frontmatter, skill.extra);\n return this.renderFrontmatterMd(frontmatter, skill.body);\n }\n\n // ── ts-plugin synthesis ────────────────────────────────────────────────\n\n /**\n * Build ONE self-contained ESM plugin module for OpenClaw.\n *\n * The module imports nothing from agent-connector. It embeds two constants\n * (the absolute home-bin path and the connector id) and a `bridge()` helper\n * that shells out to the universal hook entrypoint via execFileSync, feeding\n * the OpenClaw event payload on stdin and JSON.parsing the normalized\n * HookResponse back from stdout (fail-open: any error → null). Its default\n * export is the OpenClaw plugin definition { id, name, configSchema,\n * register(api) }; register wires api.on(...) handlers for the events this\n * connector actually declares.\n */\n synthesizePlugin(ctx: InstallContext): GeneratedPluginFile[] {\n const path = this.getHookConfigPath(ctx);\n const contents = this.buildPluginSource(ctx);\n // The gateway scans plugins.load.paths dirs for a manifest, so emit an\n // openclaw.plugin.json beside index.mjs pointing at the module entry.\n const manifestPath = join(this.pluginDir(ctx), PLUGIN_MANIFEST_FILE);\n const manifest = this.buildPluginManifest(ctx);\n return [\n { path, contents, executable: false },\n { path: manifestPath, contents: manifest, executable: false },\n ];\n }\n\n /**\n * Build the openclaw.plugin.json manifest the gateway reads inside a\n * plugins.load.paths directory. It names the plugin and points at the ESM\n * module entry (index.mjs) so the loader knows what to import.\n */\n private buildPluginManifest(ctx: InstallContext): string {\n const manifest = {\n id: ctx.connector.id,\n name: ctx.connector.displayName || ctx.connector.id,\n main: this.pluginFileName(),\n enabled: true,\n };\n return `${JSON.stringify(manifest, null, 2)}\\n`;\n }\n\n /** Compose the generated plugin source with plain string concatenation. */\n private buildPluginSource(ctx: InstallContext): string {\n const homeBin = JSON.stringify(ctx.homeBinPath);\n const connectorId = JSON.stringify(ctx.connector.id);\n const connectorName = JSON.stringify(ctx.connector.displayName || ctx.connector.id);\n\n const events = ctx.connector.hookEvents.filter(\n (e): e is HookEventName => EVENT_TO_OPENCLAW[e] !== undefined,\n );\n const has = (e: HookEventName) => events.includes(e);\n\n const header =\n \"/**\\n\" +\n \" * AUTO-GENERATED by agent-connector — DO NOT EDIT.\\n\" +\n \" *\\n\" +\n \" * Self-contained OpenClaw plugin bridge for connector \" +\n ctx.connector.id +\n \".\\n\" +\n \" * It imports nothing from agent-connector: every hook invocation shells out\\n\" +\n \" * to the stable home binary's universal entrypoint and JSON-parses the\\n\" +\n \" * normalized response. Fail-open: any bridge error degrades to a no-op.\\n\" +\n \" *\\n\" +\n \" * Registered via DUAL REGISTRATION in openclaw.json: plugins.entries.<id>\\n\" +\n \" * (loads this module) + mcp.servers.<id> (surfaces the MCP tools). The\\n\" +\n \" * gateway hot-reloads its config on SIGUSR1.\\n\" +\n \" */\\n\" +\n 'import { execFileSync, execSync } from \"node:child_process\";\\n\\n' +\n \"const HOME_BIN = \" +\n homeBin +\n \";\\n\" +\n \"const CONNECTOR_ID = \" +\n connectorId +\n \";\\n\\n\" +\n \"/**\\n\" +\n \" * Invoke the universal hook entrypoint for one canonical event.\\n\" +\n \" * @param {string} event canonical event name\\n\" +\n \" * (PreToolUse|PostToolUse|SessionStart|SubagentStart|SubagentStop)\\n\" +\n \" * @param {object} payload OpenClaw-shaped payload posted on stdin\\n\" +\n \" * @returns {object|null} normalized HookResponse, or null on any failure\\n\" +\n \" */\\n\" +\n \"function bridge(event, payload) {\\n\" +\n \" try {\\n\" +\n \" // On Windows HOME_BIN is the agent-connector.cmd launcher: Node cannot\\n\" +\n \" // execFile a batch file, and shell+args is deprecated (DEP0190), so run\\n\" +\n \" // one quoted command line via a shell. POSIX keeps the direct execFile.\\n\" +\n ' const args = [\"hook\", ' + JSON.stringify(this.id) + ', event, \"--connector\", CONNECTOR_ID];\\n' +\n ' const opts = { input: JSON.stringify(payload), encoding: \"utf8\" };\\n' +\n \" const stdout =\\n\" +\n ' process.platform === \"win32\"\\n' +\n \" ? execSync([HOME_BIN, ...args].map((a) => '\\\"' + a + '\\\"').join(\\\" \\\"), opts)\\n\" +\n \" : execFileSync(HOME_BIN, args, opts);\\n\" +\n ' const text = (stdout || \"\").trim();\\n' +\n ' if (text === \"\") return { decision: \"allow\" };\\n' +\n \" return JSON.parse(text);\\n\" +\n \" } catch {\\n\" +\n \" // Fail-open — never wedge a tool call on a bridge error.\\n\" +\n \" return null;\\n\" +\n \" }\\n\" +\n \"}\\n\\n\" +\n \"// Module-scoped context the prompt-build hook injects at session start.\\n\" +\n \"// before_prompt_build is the verified injection point (session_start itself\\n\" +\n \"// returns no context payload). The flag prevents double-injection.\\n\" +\n \"let PROJECT_DIR = process.cwd();\\n\" +\n \"let SESSION_ID = \\\"\\\";\\n\" +\n \"let pendingContext = null;\\n\" +\n \"let contextInjected = false;\\n\\n\";\n\n // register(api) body — wire only the handlers this connector declares.\n const reg: string[] = [];\n\n reg.push(\n \" register(api) {\\n\" +\n \" PROJECT_DIR = process.cwd();\\n\" +\n \" const on = (event, handler) => {\\n\" +\n ' if (typeof api?.on === \"function\") {\\n' +\n \" try { api.on(event, handler); return; } catch { /* fall through */ }\\n\" +\n \" }\\n\" +\n ' if (typeof api?.registerHook === \"function\") {\\n' +\n \" try {\\n\" +\n ' api.registerHook(event, handler, { name: CONNECTOR_ID + \":\" + event, description: \"agent-connector bridge\" });\\n' +\n \" } catch { /* best effort */ }\\n\" +\n \" }\\n\" +\n \" };\\n\",\n );\n\n if (has(\"PreToolUse\")) {\n reg.push(\n \"\\n\" +\n \" // PreToolUse → before_tool_call: block (return { block, blockReason })\\n\" +\n \" // for deny/ask; rewrite args by mutating event.params in place for modify.\\n\" +\n ' on(\"before_tool_call\", async (event) => {\\n' +\n \" const e = event || {};\\n\" +\n \" const toolInput = e.params || {};\\n\" +\n \" const res = bridge(\\\"PreToolUse\\\", {\\n\" +\n ' toolName: e.toolName || \"\",\\n' +\n \" toolInput,\\n\" +\n \" sessionId: SESSION_ID,\\n\" +\n \" projectDir: PROJECT_DIR,\\n\" +\n \" });\\n\" +\n \" if (!res) return undefined;\\n\" +\n \" // OpenClaw has no separate ask gate — deny and ask both block (safe).\\n\" +\n ' if (res.decision === \"deny\" || res.decision === \"ask\") {\\n' +\n ' return { block: true, blockReason: res.reason || (\"Blocked by \" + CONNECTOR_ID) };\\n' +\n \" }\\n\" +\n ' if (res.decision === \"modify\" && res.updatedInput && typeof toolInput === \"object\") {\\n' +\n \" Object.assign(toolInput, res.updatedInput);\\n\" +\n \" }\\n\" +\n \" return undefined;\\n\" +\n \" });\\n\",\n );\n }\n\n if (has(\"PostToolUse\")) {\n reg.push(\n \"\\n\" +\n \" // PostToolUse → after_tool_call: observe the completed tool call.\\n\" +\n \" // OpenClaw exposes the result (v2+) or output (older builds); it cannot\\n\" +\n \" // rewrite the tool result, so updatedOutput is intentionally dropped.\\n\" +\n ' on(\"after_tool_call\", async (event) => {\\n' +\n \" const e = event || {};\\n\" +\n \" const rawResult = e.result !== undefined ? e.result : e.output;\\n\" +\n \" const toolOutput =\\n\" +\n ' typeof rawResult === \"string\"\\n' +\n \" ? rawResult\\n\" +\n \" : rawResult != null\\n\" +\n \" ? JSON.stringify(rawResult)\\n\" +\n \" : undefined;\\n\" +\n \" bridge(\\\"PostToolUse\\\", {\\n\" +\n ' toolName: e.toolName || \"\",\\n' +\n \" toolInput: e.params || {},\\n\" +\n \" toolOutput,\\n\" +\n \" isError: Boolean(e.error || e.isError),\\n\" +\n \" sessionId: SESSION_ID,\\n\" +\n \" projectDir: PROJECT_DIR,\\n\" +\n \" });\\n\" +\n \" return undefined;\\n\" +\n \" });\\n\",\n );\n }\n\n if (has(\"SubagentStart\")) {\n reg.push(\n \"\\n\" +\n \" // SubagentStart → subagent_spawned: observe-only (OpenClaw exposes no\\n\" +\n \" // decision or context-injection payload for subagent launches). Field\\n\" +\n \" // names vary across builds, so the common variants are normalized;\\n\" +\n \" // empty values are omitted so the dispatcher never matcher-filters on\\n\" +\n ' // an empty agent type (fail-open).\\n' +\n ' on(\"subagent_spawned\", async (event) => {\\n' +\n \" const e = event || {};\\n\" +\n \" bridge(\\\"SubagentStart\\\", {\\n\" +\n \" agentId: e.agentId || e.subagentId || undefined,\\n\" +\n \" agentType: e.agentType || e.subagentType || e.agent || undefined,\\n\" +\n \" sessionId: SESSION_ID,\\n\" +\n \" projectDir: PROJECT_DIR,\\n\" +\n \" });\\n\" +\n \" return undefined;\\n\" +\n \" });\\n\",\n );\n }\n\n if (has(\"SubagentStop\")) {\n reg.push(\n \"\\n\" +\n \" // SubagentStop → subagent_ended: observe-only completion. A normalized\\n\" +\n \" // 'deny' cannot keep the subagent running on OpenClaw, so the bridge\\n\" +\n \" // reply is intentionally ignored.\\n\" +\n ' on(\"subagent_ended\", async (event) => {\\n' +\n \" const e = event || {};\\n\" +\n \" const rawResult = e.result !== undefined ? e.result : e.output;\\n\" +\n \" bridge(\\\"SubagentStop\\\", {\\n\" +\n \" agentId: e.agentId || e.subagentId || undefined,\\n\" +\n \" agentType: e.agentType || e.subagentType || e.agent || undefined,\\n\" +\n \" lastAssistantMessage:\\n\" +\n ' typeof rawResult === \"string\" && rawResult !== \"\" ? rawResult : undefined,\\n' +\n \" sessionId: SESSION_ID,\\n\" +\n \" projectDir: PROJECT_DIR,\\n\" +\n \" });\\n\" +\n \" return undefined;\\n\" +\n \" });\\n\",\n );\n }\n\n if (has(\"SessionStart\")) {\n reg.push(\n \"\\n\" +\n \" // SessionStart → session_start records the real session id and fetches\\n\" +\n \" // the additionalContext to inject; before_prompt_build performs the\\n\" +\n \" // injection (the verified context-injection point upstream).\\n\" +\n ' on(\"session_start\", async (event) => {\\n' +\n \" const e = event || {};\\n\" +\n \" SESSION_ID = e.sessionId || e.sessionKey || SESSION_ID;\\n\" +\n \" const res = bridge(\\\"SessionStart\\\", {\\n\" +\n \" sessionId: SESSION_ID,\\n\" +\n ' source: e.resumedFrom ? \"resume\" : \"startup\",\\n' +\n \" projectDir: PROJECT_DIR,\\n\" +\n \" });\\n\" +\n \" contextInjected = false;\\n\" +\n \" pendingContext =\\n\" +\n ' res && typeof res.additionalContext === \"string\" && res.additionalContext\\n' +\n \" ? res.additionalContext\\n\" +\n \" : null;\\n\" +\n \" return undefined;\\n\" +\n \" });\\n\" +\n \"\\n\" +\n \" // Inject the session-start context once, at prompt-build time.\\n\" +\n ' on(\"before_prompt_build\", () => {\\n' +\n \" if (contextInjected || !pendingContext) return undefined;\\n\" +\n \" contextInjected = true;\\n\" +\n \" return { appendSystemContext: pendingContext };\\n\" +\n \" });\\n\",\n );\n }\n\n reg.push(\" },\\n\");\n\n const definition =\n \"const plugin = {\\n\" +\n \" id: CONNECTOR_ID,\\n\" +\n \" name: \" +\n connectorName +\n \",\\n\" +\n \" configSchema: {\\n\" +\n ' type: \"object\",\\n' +\n \" properties: {\\n\" +\n \" enabled: {\\n\" +\n ' type: \"boolean\",\\n' +\n \" default: true,\\n\" +\n ' description: \"Enable or disable the \" + CONNECTOR_ID + \" plugin.\",\\n' +\n \" },\\n\" +\n \" },\\n\" +\n \" additionalProperties: false,\\n\" +\n \" },\\n\" +\n reg.join(\"\") +\n \"};\\n\\n\" +\n \"export default plugin;\\n\";\n\n return header + definition;\n }\n\n // ── Runtime: parse OUR bridge payload → normalized event ───────────────\n\n /**\n * `raw` is the payload OUR generated plugin posts (NOT a host-native shape):\n * { toolName, toolInput, toolOutput?, isError?, sessionId, source?, projectDir }\n * so this maps straight through.\n */\n parseEvent(event: HookEventName, raw: unknown): NormalizedEvent {\n const input = (raw ?? {}) as OpenClawBridgePayload;\n const base = {\n hostPlatform: this.id,\n connectorId: \"\",\n sessionId: typeof input.sessionId === \"string\" ? input.sessionId : \"\",\n raw,\n ...(typeof input.projectDir === \"string\" ? { projectDir: input.projectDir } : {}),\n } as const;\n\n switch (event) {\n case \"PreToolUse\": {\n const ev: PreToolUseEvent = {\n ...base,\n toolName: input.toolName ?? \"\",\n toolInput: input.toolInput ?? {},\n };\n return ev;\n }\n case \"PostToolUse\": {\n const ev: PostToolUseEvent = {\n ...base,\n toolName: input.toolName ?? \"\",\n toolInput: input.toolInput ?? {},\n ...(typeof input.toolOutput === \"string\" ? { toolOutput: input.toolOutput } : {}),\n ...(typeof input.isError === \"boolean\" ? { isError: input.isError } : {}),\n };\n return ev;\n }\n case \"SessionStart\": {\n const source: SessionStartEvent[\"source\"] =\n input.source === \"resume\"\n ? \"resume\"\n : input.source === \"compact\"\n ? \"compact\"\n : input.source === \"clear\"\n ? \"clear\"\n : \"startup\";\n const ev: SessionStartEvent = { ...base, source };\n return ev;\n }\n case \"SubagentStart\": {\n // Empty strings are dropped so the runtime matcher never filters a\n // real spawn on an unknown agent type (fail-open, per the dispatcher).\n const ev: SubagentStartEvent = {\n ...base,\n ...(isNonEmptyString(input.agentId) ? { agentId: input.agentId } : {}),\n ...(isNonEmptyString(input.agentType)\n ? { agentType: input.agentType }\n : {}),\n };\n return ev;\n }\n case \"SubagentStop\": {\n const ev: SubagentStopEvent = {\n ...base,\n ...(isNonEmptyString(input.agentId) ? { agentId: input.agentId } : {}),\n ...(isNonEmptyString(input.agentType)\n ? { agentType: input.agentType }\n : {}),\n ...(isNonEmptyString(input.lastAssistantMessage)\n ? { lastAssistantMessage: input.lastAssistantMessage }\n : {}),\n };\n return ev;\n }\n default:\n // Other canonical events are not surfaced by OpenClaw; treat as a\n // session-start-shaped no-op so the dispatcher fails open gracefully.\n return { ...base, source: \"startup\" } satisfies SessionStartEvent;\n }\n }\n\n // ── Runtime: normalized response → reply the generated bridge parses ───\n\n /**\n * Unlike json-stdio hosts (whose reply is the host's NATIVE control payload),\n * OUR generated bridge consumes this stdout directly. So the reply body is the\n * NORMALIZED HookResponse itself — the bridge JSON.parses it and reads\n * decision / updatedInput / additionalContext.\n */\n formatReply(_event: HookEventName, response: HookResponse): HookReply {\n return {\n exitCode: 0,\n stdout: JSON.stringify(response ?? { decision: \"allow\" }),\n };\n }\n\n // ── Diagnostics ────────────────────────────────────────────────────────\n\n override getHealthChecks(ctx: InstallContext): readonly HealthCheck[] {\n const configPath = this.getServerConfigPath(ctx);\n const pluginPath = this.getHookConfigPath(ctx);\n const pluginDir = this.pluginDir(ctx);\n const id = ctx.connector.id;\n const hasHooks = ctx.connector.hookEvents.length > 0;\n const hasServer = Boolean(ctx.connector.server);\n\n return [\n {\n name: `${this.name}: openclaw.json present`,\n check: () =>\n existsSync(configPath)\n ? { status: \"OK\", detail: configPath }\n : { status: \"FAIL\", detail: `not found: ${configPath}` },\n },\n {\n // HARDEST PART — dual registration must be CONSISTENT. The plugin only\n // delivers tools when it is LOADED (plugins.entries.<id> enabled AND its\n // dir in plugins.load.paths) AND in mcp.servers. A config with one half\n // but not the other is a tool-less (or never-loaded) install, so FAIL on\n // loaded XOR mcp.servers. (We assert plugins.load.paths — NOT a per-entry\n // `module` field, which openclaw config validate rejects.)\n name: `${this.name}: dual registration (plugins.entries+load.paths + mcp.servers.${id})`,\n check: () => {\n // Only assert what the connector declares: a catalog-only connector\n // (no MCP server, no hooks) never writes either half of the dual\n // registration, so absence — even of the config file — is healthy.\n if (!hasServer && !hasHooks) {\n return { status: \"OK\", detail: \"no MCP server or hooks declared\" };\n }\n const cfg = this.readJson<Record<string, unknown>>(configPath);\n if (!cfg) return { status: \"FAIL\", detail: `cannot read ${configPath}` };\n\n const inEntries = this.hasPluginEntry(cfg, id) && this.hasLoadPath(cfg, pluginDir);\n const inMcp = this.hasMcpServer(cfg, id);\n\n // A hooks-only connector (no MCP server declared) does not need the\n // mcp.servers half — the load half alone is correct and complete.\n if (!hasServer) {\n return inEntries || !hasHooks\n ? { status: \"OK\", detail: \"hooks-only connector (no MCP server)\" }\n : {\n status: \"FAIL\",\n detail: `${id} not enabled in ${PLUGINS_KEY}.${PLUGINS_ENTRIES_KEY} + ${PLUGINS_KEY}.${PLUGINS_LOAD_KEY}.${PLUGINS_LOAD_PATHS_KEY} (plugin will not load)`,\n };\n }\n\n if (inEntries && inMcp) {\n return {\n status: \"OK\",\n detail: `${PLUGINS_KEY}.${PLUGINS_ENTRIES_KEY}.${id}+${PLUGINS_KEY}.${PLUGINS_LOAD_KEY}.${PLUGINS_LOAD_PATHS_KEY} + ${MCP_ROOT_KEY}.${MCP_SERVERS_KEY}.${id}`,\n };\n }\n if (inEntries && !inMcp) {\n return {\n status: \"FAIL\",\n detail: `loaded (${PLUGINS_KEY}.${PLUGINS_ENTRIES_KEY}+${PLUGINS_LOAD_KEY}.${PLUGINS_LOAD_PATHS_KEY}) but missing from ${MCP_ROOT_KEY}.${MCP_SERVERS_KEY} — plugin loads but no tools reach the agent`,\n };\n }\n if (!inEntries && inMcp) {\n return {\n status: \"FAIL\",\n detail: `in ${MCP_ROOT_KEY}.${MCP_SERVERS_KEY} but not loaded (missing ${PLUGINS_KEY}.${PLUGINS_ENTRIES_KEY} or ${PLUGINS_LOAD_KEY}.${PLUGINS_LOAD_PATHS_KEY}) — tools declared but plugin never loads`,\n };\n }\n return {\n status: \"FAIL\",\n detail: `not loaded (${PLUGINS_KEY}.${PLUGINS_ENTRIES_KEY}+${PLUGINS_LOAD_KEY}.${PLUGINS_LOAD_PATHS_KEY}) and not in ${MCP_ROOT_KEY}.${MCP_SERVERS_KEY}`,\n };\n },\n },\n {\n name: `${this.name}: plugin module present`,\n check: () => {\n if (!hasHooks) return { status: \"OK\", detail: \"no hooks declared\" };\n return existsSync(pluginPath)\n ? { status: \"OK\", detail: pluginPath }\n : { status: \"FAIL\", detail: `not found: ${pluginPath}` };\n },\n },\n ];\n }\n\n /** True when config.plugins.entries.<id> exists (and is not disabled). */\n private hasPluginEntry(cfg: Record<string, unknown>, id: string): boolean {\n const plugins = cfg[PLUGINS_KEY];\n if (!plugins || typeof plugins !== \"object\" || Array.isArray(plugins)) return false;\n const entries = (plugins as Record<string, unknown>)[PLUGINS_ENTRIES_KEY];\n if (!entries || typeof entries !== \"object\" || Array.isArray(entries)) return false;\n const entry = (entries as Record<string, unknown>)[id];\n if (entry === undefined) return false;\n // An explicit { enabled: false } means the gateway will not load it.\n return !(\n entry &&\n typeof entry === \"object\" &&\n (entry as Record<string, unknown>).enabled === false\n );\n }\n\n /** True when config.plugins.load.paths includes `pluginDir`. */\n private hasLoadPath(cfg: Record<string, unknown>, pluginDir: string): boolean {\n const plugins = cfg[PLUGINS_KEY];\n if (!plugins || typeof plugins !== \"object\" || Array.isArray(plugins)) return false;\n const load = (plugins as Record<string, unknown>)[PLUGINS_LOAD_KEY];\n if (!load || typeof load !== \"object\" || Array.isArray(load)) return false;\n const paths = (load as Record<string, unknown>)[PLUGINS_LOAD_PATHS_KEY];\n return Array.isArray(paths) && paths.includes(pluginDir);\n }\n\n /** True when config.mcp.servers.<id> exists. */\n private hasMcpServer(cfg: Record<string, unknown>, id: string): boolean {\n const mcp = cfg[MCP_ROOT_KEY];\n if (!mcp || typeof mcp !== \"object\" || Array.isArray(mcp)) return false;\n const servers = (mcp as Record<string, unknown>)[MCP_SERVERS_KEY];\n if (!servers || typeof servers !== \"object\" || Array.isArray(servers)) return false;\n return id in (servers as Record<string, unknown>);\n }\n\n /** Read a file, returning undefined on any error (idempotency compare). */\n private safeRead(path: string): string | undefined {\n try {\n return readFileSync(path, \"utf8\");\n } catch {\n return undefined;\n }\n }\n}\n\n/**\n * Resolve the openclaw.json the gateway actually loads (mirrors context-mode's\n * openclawConfigPath): $OPENCLAW_CONFIG_PATH, else $OPENCLAW_STATE_DIR/openclaw.json,\n * else ~/.openclaw/openclaw.json. The gateway never loads a CWD/project-local\n * openclaw.json for user scope, so this is the canonical user-scope path.\n */\nfunction resolveOpenClawConfigPath(env: NodeJS.ProcessEnv = process.env): string {\n if (env.OPENCLAW_CONFIG_PATH) return resolve(env.OPENCLAW_CONFIG_PATH);\n const stateDir = env.OPENCLAW_STATE_DIR\n ? resolve(env.OPENCLAW_STATE_DIR)\n : resolve(homedir(), \".openclaw\");\n return resolve(stateDir, \"openclaw.json\");\n}\n\n/** Create a directory (recursive) if it does not already exist. */\nfunction ensureDir(dir: string): void {\n if (!existsSync(dir)) mkdirSync(dir, { recursive: true });\n}\n\n/** Narrow to a non-empty string (the bridge omits empties, but stay defensive). */\nfunction isNonEmptyString(value: unknown): value is string {\n return typeof value === \"string\" && value !== \"\";\n}\n\nexport const adapter = new OpenClawAdapter();\nexport default adapter;\n"],"mappings":";;;;;;;;;;;;;;AAsFA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,eAAe;AACxB,SAAS,SAAS,MAAM,eAAe;AAmCvC,IAAM,OAAmB;AAOzB,IAAM,eAAe;AACrB,IAAM,kBAAkB;AACxB,IAAM,cAAc;AACpB,IAAM,sBAAsB;AAM5B,IAAM,mBAAmB;AACzB,IAAM,yBAAyB;AAE/B,IAAM,uBAAuB;AAU7B,IAAM,oBAA4D;AAAA,EAChE,YAAY;AAAA,EACZ,aAAa;AAAA,EACb,cAAc;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOd,eAAe;AAAA,EACf,cAAc;AAChB;AAoDO,IAAM,kBAAN,cAA8B,YAA+B;AAAA,EACzD,KAAiB;AAAA;AAAA;AAAA;AAAA,EAIjB,OAAe;AAAA,EACf,WAAyB;AAAA,EAEzB,eAAqC;AAAA;AAAA;AAAA;AAAA;AAAA,IAK5C,gBAAgB;AAAA,IAChB,YAAY;AAAA,IACZ,aAAa;AAAA;AAAA;AAAA,IAGb,YAAY;AAAA,IACZ,cAAc;AAAA,IACd,YAAY;AAAA,IACZ,kBAAkB;AAAA,IAClB,MAAM;AAAA,IACN,cAAc;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAQd,eAAe;AAAA,IACf,cAAc;AAAA;AAAA,IAEd,eAAe;AAAA;AAAA,IAEf,iBAAiB;AAAA;AAAA,IAEjB,yBAAyB;AAAA;AAAA,IAEzB,YAAY,CAAC,OAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAMpB,gBAAgB;AAAA,EAClB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWmB,SAAsC,MAAwB;AAC/E,QAAI,CAAC,WAAW,IAAI,EAAG,QAAO;AAC9B,QAAI;AACJ,QAAI;AACF,YAAM,aAAa,MAAM,MAAM;AAAA,IACjC,QAAQ;AACN,aAAO;AAAA,IACT;AACA,QAAI;AAGF,aAAO,WAAc,GAAG;AAAA,IAC1B,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWmB,cAAc,KAAqC;AACpE,QAAI,KAAK,eAAe,GAAG,GAAG,KAAM,QAAO,MAAM,cAAc,GAAG;AAClE,QAAI,IAAI,UAAU,aAAa,IAAI,UAAU,OAAQ,QAAO,CAAC;AAC7D,WAAO;AAAA,MACL;AAAA,QACE,MAAM,KAAK,KAAK,iBAAiB,GAAG,WAAW;AAAA,QAC/C,QACE;AAAA,MAEJ;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQQ,mBAA2B;AACjC,UAAM,aAAa,0BAA0B;AAC7C,UAAM,MAAM,KAAK,SAA8D,UAAU;AACzF,UAAM,WAAW,KAAK,QAAQ,UAAU;AACxC,WAAO,OAAO,aAAa,YAAY,SAAS,KAAK,MAAM,KACvD,SAAS,WAAW,GAAG,IACrB,QAAQ,QAAQ,GAAG,SAAS,QAAQ,YAAY,EAAE,CAAC,IACnD,QAAQ,QAAQ,IAClB,KAAK,QAAQ,UAAU,GAAG,WAAW;AAAA,EAC3C;AAAA;AAAA,EAIA,gBAAgB,YAAsC;AACpD,UAAM,aAAa,0BAA0B;AAC7C,UAAM,UAAU,KAAK,QAAQ,GAAG,WAAW;AAC3C,UAAM,gBAAgB,KAAK,YAAY,eAAe;AAQtD,UAAM,kBAAkB,WAAW,KAAK,QAAQ,GAAG,WAAW,CAAC;AAC/D,UAAM,gBACJ,CAAC,oBAAoB,WAAW,UAAU,KAAK,WAAW,OAAO;AACnE,UAAM,gBAAgB,WAAW,aAAa;AAC9C,UAAM,YAAY,iBAAiB;AAEnC,UAAM,QAAQ,iBAAiB,CAAC,gBAAgB,YAAY;AAC5D,UAAM,aAAa,UAAU,YAAY,gBAAgB;AAEzD,WAAO;AAAA,MACL,IAAI,KAAK;AAAA,MACT,MAAM,KAAK;AAAA,MACX;AAAA,MACA,UAAU,KAAK;AAAA,MACf,cAAc,KAAK;AAAA,MACnB;AAAA,MACA;AAAA,MACA,QAAQ,YACJ,UAAU,YACR,oCAAoC,aAAa,KACjD,4BAA4B,UAAU,KACxC,yBAAyB,UAAU,OAAO,OAAO;AAAA,MACrD,YAAY,YAAY,SAAS;AAAA,IACnC;AAAA,EACF;AAAA;AAAA,EAIA,aAAa,KAA6B;AACxC,WAAO,IAAI,UAAU,YACjB,IAAI,aACJ,QAAQ,0BAA0B,CAAC;AAAA,EACzC;AAAA,EAEA,oBAAoB,KAA6B;AAC/C,WAAO,IAAI,UAAU,YACjB,KAAK,IAAI,YAAY,eAAe,IACpC,0BAA0B;AAAA,EAChC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,kBAAkB,KAA6B;AAC7C,WAAO,KAAK,KAAK,UAAU,GAAG,GAAG,KAAK,eAAe,CAAC;AAAA,EACxD;AAAA;AAAA,EAGQ,UAAU,KAA6B;AAC7C,UAAM,OACJ,IAAI,UAAU,YACV,KAAK,IAAI,YAAY,WAAW,IAChC,QAAQ,0BAA0B,CAAC;AACzC,WAAO,KAAK,MAAM,cAAc,IAAI,UAAU,EAAE;AAAA,EAClD;AAAA;AAAA,EAGQ,iBAAyB;AAC/B,WAAO;AAAA,EACT;AAAA;AAAA,EAIA,cAAc,KAAqC;AACjD,UAAM,SAAS,KAAK,gBAAgB,GAAG;AACvC,UAAM,aAAa,KAAK,oBAAoB,GAAG;AAE/C,QAAI,CAAC,QAAQ;AACX,aAAO;AAAA,QACL;AAAA,UACE,UAAU,KAAK;AAAA,UACf,QAAQ;AAAA,UACR,MAAM;AAAA,UACN,QAAQ,IAAI,UAAU,SAClB,8CACA;AAAA,QACN;AAAA,MACF;AAAA,IACF;AAEA,UAAM,QAAQ,KAAK,kBAAkB,KAAK,MAAM;AAChD,WAAO,CAAC,KAAK,mBAAmB,YAAY,IAAI,UAAU,IAAI,OAAO,IAAI,MAAM,CAAC;AAAA,EAClF;AAAA,EAEA,gBAAgB,KAAqC;AACnD,UAAM,aAAa,KAAK,oBAAoB,GAAG;AAC/C,WAAO,CAAC,KAAK,mBAAmB,YAAY,IAAI,UAAU,IAAI,IAAI,MAAM,CAAC;AAAA,EAC3E;AAAA;AAAA,EAGQ,gBAAgB,KAA4C;AAClE,UAAM,WAAW,IAAI,UAAU,UAAU,KAAK,EAAE,GAAG;AACnD,QAAI,aAAa,MAAO,QAAO;AAC/B,UAAM,OAAO,IAAI,UAAU;AAC3B,QAAI,CAAC,KAAM,QAAO;AAClB,WAAO,YAAY,OAAO,aAAa,WAAW,EAAE,GAAG,MAAM,GAAG,SAAS,IAAI;AAAA,EAC/E;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYQ,kBACN,KACA,QAC4C;AAC5C,QAAI,OAAO,cAAc,SAAS;AAChC,UAAI,UAAU,OAAO,WAAW;AAChC,UAAI,OAAO,CAAC,GAAI,OAAO,QAAQ,CAAC,CAAE;AAIlC,UAAI,uBAAuB,QAAQ,IAAI,UAAU,SAAS,GAAG;AAC3D,cAAM,UAAU;AAAA,UACd,IAAI;AAAA,UACJ,IAAI,UAAU;AAAA,UACd;AAAA,UACA;AAAA,UACA,IAAI;AAAA,UACJ,KAAK;AAAA,QACP;AACA,kBAAU,QAAQ;AAClB,eAAO,QAAQ;AAAA,MACjB;AAIA,YAAMA,SAA6B;AAAA,QACjC,SAAS,mBAAmB,OAAO;AAAA,MACrC;AACA,YAAM,eAAe,mBAAmB,IAAI,EAAE,OAAO,CAAC,MAAM,MAAM,EAAE;AACpE,UAAI,aAAa,SAAS,EAAG,CAAAA,OAAM,OAAO;AAC1C,YAAM,MAAM,KAAK,UAAU,OAAO,GAAG;AACrC,UAAI,IAAK,CAAAA,OAAM,MAAM;AACrB,UAAI,OAAO,YAAY,MAAO,CAAAA,OAAM,UAAU;AAC9C,aAAOA;AAAA,IACT;AAGA,UAAM,YAA4B,OAAO,cAAc,SAAS,SAAS;AACzE,UAAM,QAA8B;AAAA,MAClC,KAAK,mBAAmB,OAAO,OAAO,EAAE;AAAA,MACxC;AAAA,IACF;AACA,QAAI,OAAO,WAAW,OAAO,KAAK,OAAO,OAAO,EAAE,SAAS,GAAG;AAC5D,YAAM,UAAU,mBAAmB,EAAE,GAAG,OAAO,QAAQ,CAAC;AAAA,IAC1D;AACA,QAAI,OAAO,YAAY,MAAO,OAAM,UAAU;AAC9C,WAAO;AAAA,EACT;AAAA;AAAA,EAGQ,UACN,KACoC;AACpC,QAAI,CAAC,OAAO,OAAO,KAAK,GAAG,EAAE,WAAW,EAAG,QAAO;AAClD,WAAO,mBAAmB,EAAE,GAAG,IAAI,CAAC;AAAA,EACtC;AAAA;AAAA,EAGQ,mBACN,MACA,IACA,OACA,QACc;AAEd,QAAI,KAAK,wBAAwB,IAAI,GAAG;AACtC,aAAO;AAAA,QACL,UAAU,KAAK;AAAA,QACf,QAAQ;AAAA,QACR;AAAA,QACA,QAAQ,YAAY,IAAI;AAAA,MAC1B;AAAA,IACF;AACA,UAAM,MAAM,KAAK,SAAkC,IAAI,KAAK,CAAC;AAC7D,UAAM,UAAU,KAAK,oBAAoB,GAAG;AAC5C,UAAM,SAAS,KAAK,UAAU,QAAQ,EAAE,CAAC;AACzC,UAAM,QAAQ,KAAK,UAAU,KAAK;AAClC,QAAI;AACJ,QAAI,WAAW,OAAW,UAAS;AAAA,aAC1B,WAAW,MAAO,UAAS;AAAA,QAC/B,UAAS;AACd,QAAI,WAAW,QAAQ;AACrB,cAAQ,EAAE,IAAI;AACd,WAAK,UAAU,MAAM,KAAK,MAAM;AAAA,IAClC;AACA,WAAO;AAAA,MACL,UAAU,KAAK;AAAA,MACf;AAAA,MACA;AAAA,MACA,QAAQ,GAAG,YAAY,IAAI,eAAe,IAAI,EAAE;AAAA,IAClD;AAAA,EACF;AAAA;AAAA,EAGQ,mBAAmB,MAAc,IAAY,QAA+B;AAClF,UAAM,MAAM,KAAK,SAAkC,IAAI;AACvD,UAAM,MAAM,MAAM,YAAY;AAC9B,UAAM,UACJ,OAAO,OAAO,QAAQ,YAAY,CAAC,MAAM,QAAQ,GAAG,IAC9C,IAAgC,eAAe,IAGjD;AACN,QAAI,CAAC,OAAO,CAAC,WAAW,EAAE,MAAM,UAAU;AACxC,aAAO;AAAA,QACL,UAAU,KAAK;AAAA,QACf,QAAQ;AAAA,QACR;AAAA,QACA,QAAQ,GAAG,YAAY,IAAI,eAAe,IAAI,EAAE;AAAA,MAClD;AAAA,IACF;AACA,WAAO,QAAQ,EAAE;AACjB,SAAK,UAAU,MAAM,KAAK,MAAM;AAChC,WAAO;AAAA,MACL,UAAU,KAAK;AAAA,MACf,QAAQ;AAAA,MACR;AAAA,MACA,QAAQ,GAAG,YAAY,IAAI,eAAe,IAAI,EAAE;AAAA,IAClD;AAAA,EACF;AAAA;AAAA,EAGQ,oBAAoB,KAAuD;AACjF,QAAI,MAAM,IAAI,YAAY;AAC1B,QAAI,CAAC,OAAO,OAAO,QAAQ,YAAY,MAAM,QAAQ,GAAG,GAAG;AACzD,YAAM,CAAC;AACP,UAAI,YAAY,IAAI;AAAA,IACtB;AACA,UAAM,SAAS;AACf,QAAI,UAAU,OAAO,eAAe;AACpC,QAAI,CAAC,WAAW,OAAO,YAAY,YAAY,MAAM,QAAQ,OAAO,GAAG;AACrE,gBAAU,CAAC;AACX,aAAO,eAAe,IAAI;AAAA,IAC5B;AACA,WAAO;AAAA,EACT;AAAA;AAAA,EAIA,aAAa,KAAqC;AAChD,UAAM,aAAa,KAAK,kBAAkB,GAAG;AAC7C,UAAM,aAAa,KAAK,oBAAoB,GAAG;AAE/C,QAAI,IAAI,UAAU,UAAU,KAAK,EAAE,GAAG,UAAU,OAAO;AACrD,aAAO;AAAA,QACL,EAAE,UAAU,KAAK,IAAI,QAAQ,QAAQ,MAAM,YAAY,QAAQ,sBAAsB,KAAK,EAAE,GAAG;AAAA,MACjG;AAAA,IACF;AACA,QAAI,IAAI,UAAU,WAAW,WAAW,GAAG;AACzC,aAAO;AAAA,QACL,EAAE,UAAU,KAAK,IAAI,QAAQ,QAAQ,MAAM,YAAY,QAAQ,8BAA8B;AAAA,MAC/F;AAAA,IACF;AAEA,UAAM,UAA0B,CAAC;AAGjC,eAAW,QAAQ,KAAK,iBAAiB,GAAG,GAAG;AAC7C,YAAM,SAAS,WAAW,KAAK,IAAI,IAAI,KAAK,SAAS,KAAK,IAAI,IAAI;AAClE,UAAI;AACJ,UAAI,WAAW,OAAW,UAAS;AAAA,eAC1B,WAAW,KAAK,SAAU,UAAS;AAAA,UACvC,UAAS;AAEd,UAAI,WAAW,UAAU,CAAC,IAAI,QAAQ;AACpC,kBAAU,QAAQ,KAAK,IAAI,CAAC;AAC5B,sBAAc,KAAK,MAAM,KAAK,UAAU,MAAM;AAC9C,kBAAU,KAAK,MAAM,KAAK,aAAa,MAAQ,GAAK;AAAA,MACtD;AACA,cAAQ,KAAK;AAAA,QACX,UAAU,KAAK;AAAA,QACf;AAAA,QACA,MAAM,KAAK;AAAA,QACX,QAAQ,2BAA2B,KAAK,WAAW,GAAG,CAAC;AAAA,MACzD,CAAC;AAAA,IACH;AAMA,YAAQ,KAAK,KAAK,kBAAkB,YAAY,KAAK,KAAK,UAAU,GAAG,CAAC,CAAC;AAEzE,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQQ,WAAW,KAA6B;AAC9C,UAAM,WAAW,IAAI,UAAU;AAC/B,UAAM,SAAS,SAAS,OAAO,CAAC,MAAM,kBAAkB,CAAC,MAAM,MAAS;AACxE,UAAM,cAAc,SAAS,OAAO,CAAC,MAAM,kBAAkB,CAAC,MAAM,MAAS;AAC7E,UAAM,OAAO,OAAO,KAAK,GAAG;AAC5B,WAAO,YAAY,SAAS,IACxB,GAAG,IAAI,uBAAuB,YAAY,KAAK,GAAG,CAAC,KACnD;AAAA,EACN;AAAA,EAEA,eAAe,KAAqC;AAClD,UAAM,aAAa,KAAK,kBAAkB,GAAG;AAC7C,UAAM,aAAa,KAAK,oBAAoB,GAAG;AAC/C,UAAM,UAA0B,CAAC;AAIjC,YAAQ;AAAA,MACN,KAAK,kBAAkB,YAAY,IAAI,UAAU,IAAI,KAAK,UAAU,GAAG,GAAG,IAAI,MAAM;AAAA,IACtF;AAGA,UAAM,eAAe,KAAK,KAAK,UAAU,GAAG,GAAG,oBAAoB;AACnE,eAAW,CAAC,MAAM,KAAK,KAAK;AAAA,MAC1B,CAAC,YAAY,wBAAwB;AAAA,MACrC,CAAC,cAAc,0BAA0B;AAAA,IAC3C,GAAY;AACV,UAAI,WAAW,IAAI,GAAG;AACpB,YAAI,CAAC,IAAI,OAAQ,QAAO,MAAM,EAAE,OAAO,KAAK,CAAC;AAC7C,gBAAQ,KAAK,EAAE,UAAU,KAAK,IAAI,QAAQ,UAAU,MAAM,QAAQ,MAAM,CAAC;AAAA,MAC3E,OAAO;AACL,gBAAQ,KAAK;AAAA,UACX,UAAU,KAAK;AAAA,UACf,QAAQ;AAAA,UACR;AAAA,UACA,QAAQ,MAAM,KAAK;AAAA,QACrB,CAAC;AAAA,MACH;AAAA,IACF;AAGA,YAAQ,KAAK,KAAK,iBAAiB,KAAK,UAAU,GAAG,GAAG,IAAI,MAAM,CAAC;AAEnE,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWQ,kBACN,YACA,KACA,WACc;AAEd,QAAI,KAAK,wBAAwB,UAAU,GAAG;AAC5C,aAAO;AAAA,QACL,UAAU,KAAK;AAAA,QACf,QAAQ;AAAA,QACR,MAAM;AAAA,QACN,QAAQ,YAAY,UAAU;AAAA,MAChC;AAAA,IACF;AACA,UAAM,MAAM,KAAK,SAAkC,UAAU,KAAK,CAAC;AACnE,UAAM,UAAU,KAAK,oBAAoB,GAAG;AAC5C,UAAM,KAAK,IAAI,UAAU;AACzB,UAAM,UAA+B,EAAE,SAAS,KAAK;AACrD,UAAM,cAAc,KAAK,UAAU,QAAQ,EAAE,CAAC;AAC9C,UAAM,aAAa,KAAK,UAAU,OAAO;AAGzC,UAAM,YAAY,KAAK,sBAAsB,GAAG;AAChD,UAAM,cAAc,UAAU,SAAS,SAAS;AAEhD,UAAM,eAAe,gBAAgB;AACrC,UAAM,cAAc,CAAC;AACrB,QAAI;AACJ,QAAI,gBAAgB,OAAW,UAAS;AAAA,aAC/B,CAAC,gBAAgB,CAAC,YAAa,UAAS;AAAA,QAC5C,UAAS;AAEd,QAAI,WAAW,QAAQ;AACrB,cAAQ,EAAE,IAAI;AACd,UAAI,CAAC,YAAa,WAAU,KAAK,SAAS;AAC1C,WAAK,UAAU,YAAY,KAAK,IAAI,MAAM;AAAA,IAC5C;AACA,WAAO;AAAA,MACL,UAAU,KAAK;AAAA,MACf;AAAA,MACA,MAAM;AAAA,MACN,QAAQ,GAAG,WAAW,IAAI,mBAAmB,IAAI,EAAE,MAAM,WAAW,IAAI,gBAAgB,IAAI,sBAAsB;AAAA,IACpH;AAAA,EACF;AAAA;AAAA,EAGQ,kBACN,YACA,IACA,WACA,QACc;AACd,UAAM,MAAM,KAAK,SAAkC,UAAU;AAC7D,UAAM,UAAU,MAAM,WAAW;AACjC,UAAM,aACJ,WAAW,OAAO,YAAY,YAAY,CAAC,MAAM,QAAQ,OAAO,IAC3D,UACD;AACN,UAAM,UAAU,aAAa,mBAAmB;AAGhD,UAAM,OAAO,aAAa,gBAAgB;AAC1C,UAAM,YACJ,QAAQ,MAAM,QAAQ,KAAK,sBAAsB,CAAC,IAC7C,KAAK,sBAAsB,IAC5B;AAEN,UAAM,eAAe,QAAQ,WAAW,MAAM,OAAO;AACrD,UAAM,UAAU,YAAY,UAAU,QAAQ,SAAS,IAAI;AAE3D,QAAI,CAAC,OAAQ,CAAC,gBAAgB,UAAU,GAAI;AAC1C,aAAO;AAAA,QACL,UAAU,KAAK;AAAA,QACf,QAAQ;AAAA,QACR,MAAM;AAAA,QACN,QAAQ,GAAG,WAAW,IAAI,mBAAmB,IAAI,EAAE;AAAA,MACrD;AAAA,IACF;AACA,QAAI,gBAAgB,QAAS,QAAO,QAAQ,EAAE;AAC9C,QAAI,aAAa,WAAW,EAAG,WAAU,OAAO,SAAS,CAAC;AAC1D,SAAK,UAAU,YAAY,KAAK,MAAM;AACtC,WAAO;AAAA,MACL,UAAU,KAAK;AAAA,MACf,QAAQ;AAAA,MACR,MAAM;AAAA,MACN,QAAQ,GAAG,WAAW,IAAI,mBAAmB,IAAI,EAAE,MAAM,WAAW,IAAI,gBAAgB,IAAI,sBAAsB;AAAA,IACpH;AAAA,EACF;AAAA;AAAA,EAGQ,oBAAoB,KAAuD;AACjF,QAAI,UAAU,IAAI,WAAW;AAC7B,QAAI,CAAC,WAAW,OAAO,YAAY,YAAY,MAAM,QAAQ,OAAO,GAAG;AACrE,gBAAU,CAAC;AACX,UAAI,WAAW,IAAI;AAAA,IACrB;AACA,UAAM,aAAa;AACnB,QAAI,UAAU,WAAW,mBAAmB;AAC5C,QAAI,CAAC,WAAW,OAAO,YAAY,YAAY,MAAM,QAAQ,OAAO,GAAG;AACrE,gBAAU,CAAC;AACX,iBAAW,mBAAmB,IAAI;AAAA,IACpC;AACA,WAAO;AAAA,EACT;AAAA;AAAA,EAGQ,sBAAsB,KAAwC;AACpE,QAAI,UAAU,IAAI,WAAW;AAC7B,QAAI,CAAC,WAAW,OAAO,YAAY,YAAY,MAAM,QAAQ,OAAO,GAAG;AACrE,gBAAU,CAAC;AACX,UAAI,WAAW,IAAI;AAAA,IACrB;AACA,UAAM,aAAa;AACnB,QAAI,OAAO,WAAW,gBAAgB;AACtC,QAAI,CAAC,QAAQ,OAAO,SAAS,YAAY,MAAM,QAAQ,IAAI,GAAG;AAC5D,aAAO,CAAC;AACR,iBAAW,gBAAgB,IAAI;AAAA,IACjC;AACA,UAAM,UAAU;AAChB,UAAM,WAAW,QAAQ,sBAAsB;AAG/C,UAAM,QAAQ,MAAM,QAAQ,QAAQ,IAChC,SAAS,OAAO,CAAC,MAAmB,OAAO,MAAM,QAAQ,IACzD,CAAC;AACL,YAAQ,sBAAsB,IAAI;AAClC,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAsBQ,SAAS,KAAqB,MAAsB;AAC1D,UAAM,OACJ,IAAI,UAAU,YACV,KAAK,KAAK,iBAAiB,GAAG,QAAQ,IACtC,KAAK,QAAQ,0BAA0B,CAAC,GAAG,QAAQ;AACzD,WAAO,KAAK,MAAM,IAAI;AAAA,EACxB;AAAA,EAES,cAAc,KAAqC;AAC1D,UAAM,EAAE,UAAU,IAAI;AACtB,QAAI,UAAU,UAAU,KAAK,EAAE,GAAG,WAAW,OAAO;AAClD,aAAO,CAAC,EAAE,UAAU,KAAK,IAAI,QAAQ,QAAQ,QAAQ,uBAAuB,KAAK,EAAE,GAAG,CAAC;AAAA,IACzF;AACA,QAAI,UAAU,OAAO,WAAW,GAAG;AACjC,aAAO,CAAC,EAAE,UAAU,KAAK,IAAI,QAAQ,QAAQ,QAAQ,+BAA+B,CAAC;AAAA,IACvF;AACA,UAAM,UAA0B,CAAC;AACjC,eAAW,SAAS,UAAU,QAAQ;AACpC,YAAM,MAAM,KAAK,SAAS,KAAK,MAAM,IAAI;AACzC,cAAQ;AAAA,QACN,KAAK,iBAAiB,KAAK,KAAK,UAAU,GAAG,KAAK,YAAY,KAAK,GAAG,IAAI,MAAM;AAAA,MAClF;AAIA,iBAAW,CAAC,KAAK,QAAQ,KAAK,OAAO,QAAQ,MAAM,aAAa,CAAC,CAAC,GAAG;AACnE,cAAM,SAAS,KAAK,cAAc,KAAK,GAAG;AAC1C,YAAI,WAAW,MAAM;AACnB,kBAAQ,KAAK;AAAA,YACX,UAAU,KAAK;AAAA,YACf,QAAQ;AAAA,YACR,QAAQ,mBAAmB,GAAG;AAAA,UAChC,CAAC;AACD;AAAA,QACF;AACA,gBAAQ,KAAK,KAAK,iBAAiB,QAAQ,UAAU,IAAI,MAAM,CAAC;AAAA,MAClE;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAAA,EAES,gBAAgB,KAAqC;AAC5D,UAAM,EAAE,UAAU,IAAI;AACtB,QAAI,UAAU,OAAO,WAAW,GAAG;AACjC,aAAO,CAAC,EAAE,UAAU,KAAK,IAAI,QAAQ,QAAQ,QAAQ,+BAA+B,CAAC;AAAA,IACvF;AACA,UAAM,UAA0B,CAAC;AACjC,eAAW,SAAS,UAAU,QAAQ;AACpC,YAAM,MAAM,KAAK,SAAS,KAAK,MAAM,IAAI;AAGzC,cAAQ,KAAK,KAAK,kBAAkB,KAAK,KAAK,UAAU,GAAG,IAAI,MAAM,CAAC;AACtE,iBAAW,OAAO,OAAO,KAAK,MAAM,aAAa,CAAC,CAAC,GAAG;AACpD,cAAM,SAAS,KAAK,cAAc,KAAK,GAAG;AAC1C,YAAI,WAAW,KAAM;AACrB,gBAAQ,KAAK,KAAK,kBAAkB,QAAQ,IAAI,MAAM,CAAC;AAAA,MACzD;AAGA,cAAQ,KAAK,KAAK,iBAAiB,KAAK,IAAI,MAAM,CAAC;AAAA,IACrD;AACA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQQ,YAAY,OAAyB;AAC3C,UAAM,cAAuC;AAAA,MAC3C,MAAM,MAAM;AAAA,MACZ,aAAa,MAAM;AAAA,IACrB;AACA,QAAI,MAAM,UAAU,OAAW,aAAY,QAAQ,MAAM;AACzD,UAAM,QAAQ,MAAM,OAAO;AAC3B,QAAI,SAAS,MAAM,SAAS,EAAG,aAAY,eAAe,IAAI,MAAM,KAAK,IAAI;AAC7E,QAAI,MAAM,2BAA2B,QAAW;AAC9C,kBAAY,0BAA0B,IAAI,MAAM;AAAA,IAClD;AACA,QAAI,MAAM,MAAO,QAAO,OAAO,aAAa,MAAM,KAAK;AACvD,WAAO,KAAK,oBAAoB,aAAa,MAAM,IAAI;AAAA,EACzD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAgBA,iBAAiB,KAA4C;AAC3D,UAAM,OAAO,KAAK,kBAAkB,GAAG;AACvC,UAAM,WAAW,KAAK,kBAAkB,GAAG;AAG3C,UAAM,eAAe,KAAK,KAAK,UAAU,GAAG,GAAG,oBAAoB;AACnE,UAAM,WAAW,KAAK,oBAAoB,GAAG;AAC7C,WAAO;AAAA,MACL,EAAE,MAAM,UAAU,YAAY,MAAM;AAAA,MACpC,EAAE,MAAM,cAAc,UAAU,UAAU,YAAY,MAAM;AAAA,IAC9D;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOQ,oBAAoB,KAA6B;AACvD,UAAM,WAAW;AAAA,MACf,IAAI,IAAI,UAAU;AAAA,MAClB,MAAM,IAAI,UAAU,eAAe,IAAI,UAAU;AAAA,MACjD,MAAM,KAAK,eAAe;AAAA,MAC1B,SAAS;AAAA,IACX;AACA,WAAO,GAAG,KAAK,UAAU,UAAU,MAAM,CAAC,CAAC;AAAA;AAAA,EAC7C;AAAA;AAAA,EAGQ,kBAAkB,KAA6B;AACrD,UAAM,UAAU,KAAK,UAAU,IAAI,WAAW;AAC9C,UAAM,cAAc,KAAK,UAAU,IAAI,UAAU,EAAE;AACnD,UAAM,gBAAgB,KAAK,UAAU,IAAI,UAAU,eAAe,IAAI,UAAU,EAAE;AAElF,UAAM,SAAS,IAAI,UAAU,WAAW;AAAA,MACtC,CAAC,MAA0B,kBAAkB,CAAC,MAAM;AAAA,IACtD;AACA,UAAM,MAAM,CAAC,MAAqB,OAAO,SAAS,CAAC;AAEnD,UAAM,SACJ,+HAIA,IAAI,UAAU,KACd;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,qBAWA,UACA,6BAEA,cACA,0oBAa+B,KAAK,UAAU,KAAK,EAAE,IAAI;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAuB3D,UAAM,MAAgB,CAAC;AAEvB,QAAI;AAAA,MACF;AAAA,IAYF;AAEA,QAAI,IAAI,YAAY,GAAG;AACrB,UAAI;AAAA,QACF;AAAA,MAsBF;AAAA,IACF;AAEA,QAAI,IAAI,aAAa,GAAG;AACtB,UAAI;AAAA,QACF;AAAA,MAuBF;AAAA,IACF;AAEA,QAAI,IAAI,eAAe,GAAG;AACxB,UAAI;AAAA,QACF;AAAA,MAgBF;AAAA,IACF;AAEA,QAAI,IAAI,cAAc,GAAG;AACvB,UAAI;AAAA,QACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAiBF;AAAA,IACF;AAEA,QAAI,IAAI,cAAc,GAAG;AACvB,UAAI;AAAA,QACF;AAAA,MA0BF;AAAA,IACF;AAEA,QAAI,KAAK,QAAQ;AAEjB,UAAM,aACJ,oDAGA,gBACA,6QAYA,IAAI,KAAK,EAAE,IACX;AAGF,WAAO,SAAS;AAAA,EAClB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,WAAW,OAAsB,KAA+B;AAC9D,UAAM,QAAS,OAAO,CAAC;AACvB,UAAM,OAAO;AAAA,MACX,cAAc,KAAK;AAAA,MACnB,aAAa;AAAA,MACb,WAAW,OAAO,MAAM,cAAc,WAAW,MAAM,YAAY;AAAA,MACnE;AAAA,MACA,GAAI,OAAO,MAAM,eAAe,WAAW,EAAE,YAAY,MAAM,WAAW,IAAI,CAAC;AAAA,IACjF;AAEA,YAAQ,OAAO;AAAA,MACb,KAAK,cAAc;AACjB,cAAM,KAAsB;AAAA,UAC1B,GAAG;AAAA,UACH,UAAU,MAAM,YAAY;AAAA,UAC5B,WAAW,MAAM,aAAa,CAAC;AAAA,QACjC;AACA,eAAO;AAAA,MACT;AAAA,MACA,KAAK,eAAe;AAClB,cAAM,KAAuB;AAAA,UAC3B,GAAG;AAAA,UACH,UAAU,MAAM,YAAY;AAAA,UAC5B,WAAW,MAAM,aAAa,CAAC;AAAA,UAC/B,GAAI,OAAO,MAAM,eAAe,WAAW,EAAE,YAAY,MAAM,WAAW,IAAI,CAAC;AAAA,UAC/E,GAAI,OAAO,MAAM,YAAY,YAAY,EAAE,SAAS,MAAM,QAAQ,IAAI,CAAC;AAAA,QACzE;AACA,eAAO;AAAA,MACT;AAAA,MACA,KAAK,gBAAgB;AACnB,cAAM,SACJ,MAAM,WAAW,WACb,WACA,MAAM,WAAW,YACf,YACA,MAAM,WAAW,UACf,UACA;AACV,cAAM,KAAwB,EAAE,GAAG,MAAM,OAAO;AAChD,eAAO;AAAA,MACT;AAAA,MACA,KAAK,iBAAiB;AAGpB,cAAM,KAAyB;AAAA,UAC7B,GAAG;AAAA,UACH,GAAI,iBAAiB,MAAM,OAAO,IAAI,EAAE,SAAS,MAAM,QAAQ,IAAI,CAAC;AAAA,UACpE,GAAI,iBAAiB,MAAM,SAAS,IAChC,EAAE,WAAW,MAAM,UAAU,IAC7B,CAAC;AAAA,QACP;AACA,eAAO;AAAA,MACT;AAAA,MACA,KAAK,gBAAgB;AACnB,cAAM,KAAwB;AAAA,UAC5B,GAAG;AAAA,UACH,GAAI,iBAAiB,MAAM,OAAO,IAAI,EAAE,SAAS,MAAM,QAAQ,IAAI,CAAC;AAAA,UACpE,GAAI,iBAAiB,MAAM,SAAS,IAChC,EAAE,WAAW,MAAM,UAAU,IAC7B,CAAC;AAAA,UACL,GAAI,iBAAiB,MAAM,oBAAoB,IAC3C,EAAE,sBAAsB,MAAM,qBAAqB,IACnD,CAAC;AAAA,QACP;AACA,eAAO;AAAA,MACT;AAAA,MACA;AAGE,eAAO,EAAE,GAAG,MAAM,QAAQ,UAAU;AAAA,IACxC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,YAAY,QAAuB,UAAmC;AACpE,WAAO;AAAA,MACL,UAAU;AAAA,MACV,QAAQ,KAAK,UAAU,YAAY,EAAE,UAAU,QAAQ,CAAC;AAAA,IAC1D;AAAA,EACF;AAAA;AAAA,EAIS,gBAAgB,KAA6C;AACpE,UAAM,aAAa,KAAK,oBAAoB,GAAG;AAC/C,UAAM,aAAa,KAAK,kBAAkB,GAAG;AAC7C,UAAM,YAAY,KAAK,UAAU,GAAG;AACpC,UAAM,KAAK,IAAI,UAAU;AACzB,UAAM,WAAW,IAAI,UAAU,WAAW,SAAS;AACnD,UAAM,YAAY,QAAQ,IAAI,UAAU,MAAM;AAE9C,WAAO;AAAA,MACL;AAAA,QACE,MAAM,GAAG,KAAK,IAAI;AAAA,QAClB,OAAO,MACL,WAAW,UAAU,IACjB,EAAE,QAAQ,MAAM,QAAQ,WAAW,IACnC,EAAE,QAAQ,QAAQ,QAAQ,cAAc,UAAU,GAAG;AAAA,MAC7D;AAAA,MACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,QAOE,MAAM,GAAG,KAAK,IAAI,iEAAiE,EAAE;AAAA,QACrF,OAAO,MAAM;AAIX,cAAI,CAAC,aAAa,CAAC,UAAU;AAC3B,mBAAO,EAAE,QAAQ,MAAM,QAAQ,kCAAkC;AAAA,UACnE;AACA,gBAAM,MAAM,KAAK,SAAkC,UAAU;AAC7D,cAAI,CAAC,IAAK,QAAO,EAAE,QAAQ,QAAQ,QAAQ,eAAe,UAAU,GAAG;AAEvE,gBAAM,YAAY,KAAK,eAAe,KAAK,EAAE,KAAK,KAAK,YAAY,KAAK,SAAS;AACjF,gBAAM,QAAQ,KAAK,aAAa,KAAK,EAAE;AAIvC,cAAI,CAAC,WAAW;AACd,mBAAO,aAAa,CAAC,WACjB,EAAE,QAAQ,MAAM,QAAQ,uCAAuC,IAC/D;AAAA,cACE,QAAQ;AAAA,cACR,QAAQ,GAAG,EAAE,mBAAmB,WAAW,IAAI,mBAAmB,MAAM,WAAW,IAAI,gBAAgB,IAAI,sBAAsB;AAAA,YACnI;AAAA,UACN;AAEA,cAAI,aAAa,OAAO;AACtB,mBAAO;AAAA,cACL,QAAQ;AAAA,cACR,QAAQ,GAAG,WAAW,IAAI,mBAAmB,IAAI,EAAE,IAAI,WAAW,IAAI,gBAAgB,IAAI,sBAAsB,MAAM,YAAY,IAAI,eAAe,IAAI,EAAE;AAAA,YAC7J;AAAA,UACF;AACA,cAAI,aAAa,CAAC,OAAO;AACvB,mBAAO;AAAA,cACL,QAAQ;AAAA,cACR,QAAQ,WAAW,WAAW,IAAI,mBAAmB,IAAI,gBAAgB,IAAI,sBAAsB,sBAAsB,YAAY,IAAI,eAAe;AAAA,YAC1J;AAAA,UACF;AACA,cAAI,CAAC,aAAa,OAAO;AACvB,mBAAO;AAAA,cACL,QAAQ;AAAA,cACR,QAAQ,MAAM,YAAY,IAAI,eAAe,4BAA4B,WAAW,IAAI,mBAAmB,OAAO,gBAAgB,IAAI,sBAAsB;AAAA,YAC9J;AAAA,UACF;AACA,iBAAO;AAAA,YACL,QAAQ;AAAA,YACR,QAAQ,eAAe,WAAW,IAAI,mBAAmB,IAAI,gBAAgB,IAAI,sBAAsB,gBAAgB,YAAY,IAAI,eAAe;AAAA,UACxJ;AAAA,QACF;AAAA,MACF;AAAA,MACA;AAAA,QACE,MAAM,GAAG,KAAK,IAAI;AAAA,QAClB,OAAO,MAAM;AACX,cAAI,CAAC,SAAU,QAAO,EAAE,QAAQ,MAAM,QAAQ,oBAAoB;AAClE,iBAAO,WAAW,UAAU,IACxB,EAAE,QAAQ,MAAM,QAAQ,WAAW,IACnC,EAAE,QAAQ,QAAQ,QAAQ,cAAc,UAAU,GAAG;AAAA,QAC3D;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA;AAAA,EAGQ,eAAe,KAA8B,IAAqB;AACxE,UAAM,UAAU,IAAI,WAAW;AAC/B,QAAI,CAAC,WAAW,OAAO,YAAY,YAAY,MAAM,QAAQ,OAAO,EAAG,QAAO;AAC9E,UAAM,UAAW,QAAoC,mBAAmB;AACxE,QAAI,CAAC,WAAW,OAAO,YAAY,YAAY,MAAM,QAAQ,OAAO,EAAG,QAAO;AAC9E,UAAM,QAAS,QAAoC,EAAE;AACrD,QAAI,UAAU,OAAW,QAAO;AAEhC,WAAO,EACL,SACA,OAAO,UAAU,YAChB,MAAkC,YAAY;AAAA,EAEnD;AAAA;AAAA,EAGQ,YAAY,KAA8B,WAA4B;AAC5E,UAAM,UAAU,IAAI,WAAW;AAC/B,QAAI,CAAC,WAAW,OAAO,YAAY,YAAY,MAAM,QAAQ,OAAO,EAAG,QAAO;AAC9E,UAAM,OAAQ,QAAoC,gBAAgB;AAClE,QAAI,CAAC,QAAQ,OAAO,SAAS,YAAY,MAAM,QAAQ,IAAI,EAAG,QAAO;AACrE,UAAM,QAAS,KAAiC,sBAAsB;AACtE,WAAO,MAAM,QAAQ,KAAK,KAAK,MAAM,SAAS,SAAS;AAAA,EACzD;AAAA;AAAA,EAGQ,aAAa,KAA8B,IAAqB;AACtE,UAAM,MAAM,IAAI,YAAY;AAC5B,QAAI,CAAC,OAAO,OAAO,QAAQ,YAAY,MAAM,QAAQ,GAAG,EAAG,QAAO;AAClE,UAAM,UAAW,IAAgC,eAAe;AAChE,QAAI,CAAC,WAAW,OAAO,YAAY,YAAY,MAAM,QAAQ,OAAO,EAAG,QAAO;AAC9E,WAAO,MAAO;AAAA,EAChB;AAAA;AAAA,EAGQ,SAAS,MAAkC;AACjD,QAAI;AACF,aAAO,aAAa,MAAM,MAAM;AAAA,IAClC,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF;AACF;AAQA,SAAS,0BAA0B,MAAyB,QAAQ,KAAa;AAC/E,MAAI,IAAI,qBAAsB,QAAO,QAAQ,IAAI,oBAAoB;AACrE,QAAM,WAAW,IAAI,qBACjB,QAAQ,IAAI,kBAAkB,IAC9B,QAAQ,QAAQ,GAAG,WAAW;AAClC,SAAO,QAAQ,UAAU,eAAe;AAC1C;AAGA,SAAS,UAAU,KAAmB;AACpC,MAAI,CAAC,WAAW,GAAG,EAAG,WAAU,KAAK,EAAE,WAAW,KAAK,CAAC;AAC1D;AAGA,SAAS,iBAAiB,OAAiC;AACzD,SAAO,OAAO,UAAU,YAAY,UAAU;AAChD;AAEO,IAAM,UAAU,IAAI,gBAAgB;AAC3C,IAAO,mBAAQ;","names":["entry"]}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
defineConnector
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-ADTHT2FN.js";
|
|
5
5
|
import {
|
|
6
6
|
connectorDir,
|
|
7
7
|
connectorsDir,
|
|
@@ -73,7 +73,7 @@ function serializablePlatforms(platforms) {
|
|
|
73
73
|
}
|
|
74
74
|
return out;
|
|
75
75
|
}
|
|
76
|
-
function registerConnector(connector, modulePath) {
|
|
76
|
+
function registerConnector(connector, modulePath, scope) {
|
|
77
77
|
const meta = {
|
|
78
78
|
id: connector.id,
|
|
79
79
|
displayName: connector.displayName,
|
|
@@ -88,7 +88,11 @@ function registerConnector(connector, modulePath) {
|
|
|
88
88
|
subagents: connector.subagents,
|
|
89
89
|
memory: connector.memory,
|
|
90
90
|
targets: connector.targets,
|
|
91
|
-
platforms: serializablePlatforms(connector.platforms)
|
|
91
|
+
platforms: serializablePlatforms(connector.platforms),
|
|
92
|
+
// Persist the install scope when the caller supplied one (the installer
|
|
93
|
+
// passes its install scope). Omitted from the record when undefined so an
|
|
94
|
+
// ad-hoc register stays minimal and round-trips as "no scope known".
|
|
95
|
+
...scope !== void 0 ? { scope } : {}
|
|
92
96
|
};
|
|
93
97
|
const dir = connectorDir(connector.id);
|
|
94
98
|
ensureDir(dir);
|
|
@@ -140,6 +144,11 @@ function connectorFromMeta(meta) {
|
|
|
140
144
|
skills: meta.skills ?? [],
|
|
141
145
|
subagents: meta.subagents ?? [],
|
|
142
146
|
memory: meta.memory ?? [],
|
|
147
|
+
// Actions carry live `run` handlers, so they are NOT serialized into the
|
|
148
|
+
// record (like the statusline render). A handler-less meta-derived connector
|
|
149
|
+
// gets [] — inspection/uninstall never dispatch action handlers, and the
|
|
150
|
+
// BaseAdapter action default already tolerates an empty list.
|
|
151
|
+
actions: [],
|
|
143
152
|
platforms: meta.platforms ?? {},
|
|
144
153
|
targets: meta.targets
|
|
145
154
|
};
|
|
@@ -165,4 +174,4 @@ export {
|
|
|
165
174
|
connectorFromMeta,
|
|
166
175
|
listRegisteredConnectors
|
|
167
176
|
};
|
|
168
|
-
//# sourceMappingURL=chunk-
|
|
177
|
+
//# sourceMappingURL=chunk-KGJWE6A2.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/core/load-connector.ts"],"sourcesContent":["/**\n * core/load-connector — discover, load, and register connector definitions.\n *\n * Responsibilities:\n * 1. Locate the developer's `agent-connector.config.{mjs,js,json}` by walking\n * upward from a start directory (the project root convention).\n * 2. Load a config from a path into a LIVE ResolvedConnector (with handlers).\n * 3. Register a connector by persisting SERIALIZABLE metadata (no functions)\n * to `connectorDir(id)/connector.json`, pointing at the source module so\n * live handlers can be re-imported at runtime from a stable record.\n *\n * Why split live vs. serialized? Hook handlers are functions and cannot survive\n * JSON. The registry stores only what JSON can hold plus an absolute\n * `modulePath`; the runtime re-imports that module to recover the live handlers.\n */\n\nimport { existsSync, readdirSync, readFileSync, realpathSync, rmSync, writeFileSync } from \"node:fs\";\nimport { dirname, isAbsolute, join, resolve } from \"node:path\";\nimport { pathToFileURL } from \"node:url\";\n\nimport type {\n CommandDef,\n HookEventName,\n InstallScope,\n MemoryDef,\n PlatformId,\n PlatformOverride,\n ResolvedConnector,\n ServerDef,\n SkillDef,\n SubagentDef,\n} from \"./types.js\";\nimport { defineConnector } from \"./define-connector.js\";\nimport { connectorDir, connectorsDir, ensureDir } from \"./paths.js\";\n\n/** Candidate config filenames, in resolution-precedence order. */\nconst CONFIG_FILENAMES = [\n \"agent-connector.config.mjs\",\n \"agent-connector.config.js\",\n \"agent-connector.config.json\",\n] as const;\n\n/**\n * The serializable subset of a connector persisted to `connector.json`.\n * Hook handler functions are intentionally absent — only the absolute\n * `modulePath` is stored so the live ResolvedConnector can be re-imported.\n */\nexport interface RegisteredMeta {\n id: string;\n displayName: string;\n version: string;\n /** Absolute path to the source module that produced this connector. */\n modulePath: string;\n telemetry: ResolvedConnector[\"telemetry\"];\n /** Canonical event names the connector handles (handlers themselves stripped). */\n hookEvents: HookEventName[];\n hasServer: boolean;\n server: ServerDef | null;\n /**\n * Content surfaces (commands/skills/subagents). These are JSON-serializable\n * (no functions) so they persist cleanly and let uninstall locate the files\n * to remove even when the source module is gone.\n */\n commands: CommandDef[];\n skills: SkillDef[];\n subagents: SubagentDef[];\n /**\n * Memory entries (managed-block content surface). Plain content, persisted\n * whole so uninstall normally has the full entry list even when the source\n * module is gone (the marker prefix-scan is the fallback beyond that).\n */\n memory: MemoryDef[];\n targets: ResolvedConnector[\"targets\"];\n /** Per-platform overrides with any hook handler functions stripped. */\n platforms: Partial<Record<PlatformId, PlatformOverride>>;\n /**\n * The install scope this connector was registered under, persisted so the\n * runtime entrypoints (hook/statusline/action) can recover it cheaply (sync)\n * and stamp it onto the HostCtx/event — scope is an install-time property the\n * runtime otherwise has no access to. OPTIONAL: absent for an ad-hoc register\n * that passed no scope, or a record written before this field existed.\n * This is the install's RUN-WIDE DEFAULT scope; it can differ from the\n * effective per-host scope when a `platforms[host].scope` override is set (the\n * record is keyed by connector id only and holds no per-host scope map).\n */\n scope?: InstallScope;\n}\n\n/**\n * Search `startDir` and each ancestor for a connector config file. Returns the\n * absolute path to the first match (filesystem-root-stopping), or null.\n */\nexport function findConnectorConfig(startDir: string): string | null {\n let dir = resolve(startDir);\n // Walk upward until `dirname(dir) === dir` (filesystem root).\n for (;;) {\n for (const name of CONFIG_FILENAMES) {\n const candidate = join(dir, name);\n if (existsSync(candidate)) return candidate;\n }\n const parent = dirname(dir);\n if (parent === dir) break;\n dir = parent;\n }\n return null;\n}\n\n/** True if a value already looks like a ResolvedConnector (vs. a raw config). */\nfunction isResolvedConnector(value: unknown): value is ResolvedConnector {\n return (\n typeof value === \"object\" &&\n value !== null &&\n Array.isArray((value as { hookEvents?: unknown }).hookEvents)\n );\n}\n\n/**\n * Load a connector from an absolute or relative path.\n * - `.json` → JSON.parse, then defineConnector().\n * - `.mjs` / `.js` → dynamic import (via pathToFileURL, Windows-safe),\n * take the default export. If it already looks like a\n * ResolvedConnector use it as-is; otherwise treat it as\n * a ConnectorConfig and run it through defineConnector().\n * Returns the live connector plus the absolute module path it came from.\n */\nexport async function loadConnectorFromPath(\n path: string,\n): Promise<{ connector: ResolvedConnector; modulePath: string }> {\n let modulePath = isAbsolute(path) ? path : resolve(path);\n // Canonicalize before building the file:// URL for dynamic import. On Windows a\n // short (8.3) temp path like C:\\Users\\RUNNER~1\\...\\x.mjs round-trips the \"~\" as\n // %7E and fails to load; realpathSync.native expands it to the real long path.\n // It also resolves symlinked temp roots (e.g. macOS /var -> /private/var).\n // If the file does not exist yet, fall through with the resolve()'d path so the\n // subsequent read/import throws the real not-found error.\n try {\n modulePath = realpathSync.native(modulePath);\n } catch {\n /* keep the resolve()'d path */\n }\n\n if (modulePath.endsWith(\".json\")) {\n const text = readFileSync(modulePath, \"utf8\");\n const config = JSON.parse(text) as unknown;\n const connector = defineConnector(config as Parameters<typeof defineConnector>[0]);\n return { connector, modulePath };\n }\n\n // .mjs / .js — dynamic ESM import. pathToFileURL keeps Windows paths valid.\n const mod = (await import(pathToFileURL(modulePath).href)) as {\n default?: unknown;\n };\n const exported = mod.default;\n if (exported == null) {\n throw new Error(\n `Connector module has no default export: ${modulePath}`,\n );\n }\n const connector = isResolvedConnector(exported)\n ? exported\n : defineConnector(exported as Parameters<typeof defineConnector>[0]);\n return { connector, modulePath };\n}\n\n/**\n * Strip any function-valued `hooks` from per-platform overrides so the result\n * is JSON-serializable. A boolean `hooks` override is preserved; an object\n * override is dropped (it can only carry handler functions, which are not\n * serializable). `nativeHooks` declarations are persisted HANDLER-LESS (event\n * name + matcher only) so meta-based inspection (doctor / health checks / the\n * hook CLI) can still see WHICH native events were declared — the live handlers\n * are re-imported from `modulePath` at runtime, exactly like normalized hooks.\n * Everything else on the override is kept verbatim — notably `configPatch`\n * declarations, which are pure JSON (key/value/reason/docsUrl, no functions)\n * and persist WHOLE so uninstall/doctor can reason about them even when the\n * source module is gone.\n */\nfunction serializablePlatforms(\n platforms: Partial<Record<PlatformId, PlatformOverride>>,\n): Partial<Record<PlatformId, PlatformOverride>> {\n const out: Partial<Record<PlatformId, PlatformOverride>> = {};\n for (const [id, override] of Object.entries(platforms) as [\n PlatformId,\n PlatformOverride | undefined,\n ][]) {\n if (!override) continue;\n const { hooks, nativeHooks, ...rest } = override;\n const clean: PlatformOverride = { ...rest };\n // Keep only a boolean hooks flag; object hooks carry handler functions.\n if (typeof hooks === \"boolean\") clean.hooks = hooks;\n if (nativeHooks && typeof nativeHooks === \"object\") {\n const stripped: Record<string, { matcher?: string }> = {};\n for (const [event, def] of Object.entries(nativeHooks)) {\n stripped[event] =\n typeof def?.matcher === \"string\" ? { matcher: def.matcher } : {};\n }\n // Cast: the persisted record deliberately omits the (non-serializable)\n // handler; consumers of meta-derived connectors never dispatch handlers.\n clean.nativeHooks = stripped as PlatformOverride[\"nativeHooks\"];\n }\n out[id] = clean;\n }\n return out;\n}\n\n/**\n * Persist a connector's serializable metadata to `connectorDir(id)/connector.json`.\n * Handlers are NOT serialized — they are re-imported from `modulePath` at runtime.\n * The optional `scope` (the install scope the caller deployed under) is persisted\n * so the runtime entrypoints can recover it and stamp it onto the HostCtx/event.\n * Returns the absolute path of the written record.\n */\nexport function registerConnector(\n connector: ResolvedConnector,\n modulePath: string,\n scope?: InstallScope,\n): string {\n const meta: RegisteredMeta = {\n id: connector.id,\n displayName: connector.displayName,\n version: connector.version,\n modulePath: resolve(modulePath),\n telemetry: connector.telemetry,\n hookEvents: connector.hookEvents,\n hasServer: !!connector.server,\n server: connector.server ?? null,\n commands: connector.commands,\n skills: connector.skills,\n subagents: connector.subagents,\n memory: connector.memory,\n targets: connector.targets,\n platforms: serializablePlatforms(connector.platforms),\n // Persist the install scope when the caller supplied one (the installer\n // passes its install scope). Omitted from the record when undefined so an\n // ad-hoc register stays minimal and round-trips as \"no scope known\".\n ...(scope !== undefined ? { scope } : {}),\n };\n\n const dir = connectorDir(connector.id);\n ensureDir(dir);\n const outPath = join(dir, \"connector.json\");\n writeFileSync(outPath, `${JSON.stringify(meta, null, 2)}\\n`, \"utf8\");\n return outPath;\n}\n\n/**\n * Deregister a connector by removing its DATA-dir record directory\n * (`connectorDir(id)`) recursively. This is the inverse of {@link registerConnector}:\n * registerConnector writes `connectorDir(id)/connector.json`, but per-target\n * uninstall only strips host-native registrations — it never removes this record,\n * leaving an orphan behind. Best-effort + guarded: returns the directory path and\n * whether it existed before removal.\n */\nexport function deregisterConnector(id: string): {\n removed: boolean;\n path: string;\n} {\n const dir = connectorDir(id);\n const existed = existsSync(dir);\n if (existed) rmSync(dir, { recursive: true, force: true });\n return { removed: existed, path: dir };\n}\n\n/**\n * Read the registered metadata record for `id`, or null if not registered or\n * the record is unreadable/corrupt.\n */\nexport function readRegisteredMeta(id: string): RegisteredMeta | null {\n const recordPath = join(connectorDir(id), \"connector.json\");\n if (!existsSync(recordPath)) return null;\n try {\n return JSON.parse(readFileSync(recordPath, \"utf8\")) as RegisteredMeta;\n } catch {\n return null;\n }\n}\n\n/**\n * Load the LIVE ResolvedConnector (with hook handlers) for a registered id by\n * re-importing its source module. Throws a clear error when the connector is\n * not registered or its source module no longer resolves to it.\n */\nexport async function loadRegisteredConnector(\n id: string,\n): Promise<ResolvedConnector> {\n const meta = readRegisteredMeta(id);\n if (!meta) {\n throw new Error(\n `Connector \"${id}\" is not registered (no record at ${join(connectorDir(id), \"connector.json\")}). ` +\n `Run an install/register step first.`,\n );\n }\n if (!meta.modulePath || !existsSync(meta.modulePath)) {\n throw new Error(\n `Connector \"${id}\" record points at a missing module: ${meta.modulePath}`,\n );\n }\n const { connector } = await loadConnectorFromPath(meta.modulePath);\n return connector;\n}\n\n/**\n * Build a handler-less ResolvedConnector from stored metadata. Suitable for\n * inspection/doctor where live hook handlers are not needed (and where the\n * source module may even be gone). `hooks` is empty; `hookEvents` is preserved.\n */\nexport function connectorFromMeta(meta: RegisteredMeta): ResolvedConnector {\n return {\n id: meta.id,\n displayName: meta.displayName,\n version: meta.version,\n ...(meta.server ? { server: meta.server } : {}),\n hooks: {},\n hookEvents: meta.hookEvents ?? [],\n telemetry: meta.telemetry,\n commands: meta.commands ?? [],\n skills: meta.skills ?? [],\n subagents: meta.subagents ?? [],\n memory: meta.memory ?? [],\n // Actions carry live `run` handlers, so they are NOT serialized into the\n // record (like the statusline render). A handler-less meta-derived connector\n // gets [] — inspection/uninstall never dispatch action handlers, and the\n // BaseAdapter action default already tolerates an empty list.\n actions: [],\n platforms: meta.platforms ?? {},\n targets: meta.targets,\n };\n}\n\n/**\n * List every registered connector as a handler-less ResolvedConnector (read\n * from `connectorsDir()`). Used by doctor to health-check what is actually\n * installed, rather than guessing from the local working directory.\n */\nexport function listRegisteredConnectors(): ResolvedConnector[] {\n const dir = connectorsDir();\n if (!existsSync(dir)) return [];\n const out: ResolvedConnector[] = [];\n for (const entry of readdirSync(dir)) {\n const meta = readRegisteredMeta(entry);\n if (meta) out.push(connectorFromMeta(meta));\n }\n return out;\n}\n"],"mappings":"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","names":["connector"]}
|
|
@@ -73,28 +73,36 @@ function renderInstallResult(result, verb) {
|
|
|
73
73
|
return lines.join("\n");
|
|
74
74
|
}
|
|
75
75
|
var COMMANDS = {
|
|
76
|
-
detect: () => import("./detect-
|
|
77
|
-
install: () => import("./install-
|
|
78
|
-
uninstall: () => import("./uninstall-
|
|
76
|
+
detect: () => import("./detect-ZIIS55LD.js"),
|
|
77
|
+
install: () => import("./install-UDCBL7HP.js"),
|
|
78
|
+
uninstall: () => import("./uninstall-2LBLQVFA.js"),
|
|
79
79
|
// `upgrade` is the single "bring everything current" verb (re-render host
|
|
80
80
|
// config + refresh the home pointer + managed channel guidance). `sync` and
|
|
81
81
|
// `update` are kept as back-compat aliases that route to the same module so
|
|
82
82
|
// existing scripts/docs keep working without a second concept to learn.
|
|
83
|
-
upgrade: () => import("./upgrade-
|
|
84
|
-
sync: () => import("./upgrade-
|
|
85
|
-
update: () => import("./upgrade-
|
|
86
|
-
package: () => import("./package-
|
|
87
|
-
doctor: () => import("./doctor-
|
|
88
|
-
status: () => import("./status-
|
|
89
|
-
telemetry: () => import("./telemetry-
|
|
90
|
-
usage: () => import("./usage-
|
|
91
|
-
leaderboard: () => import("./leaderboard-
|
|
92
|
-
hook: () => import("./hook-
|
|
93
|
-
|
|
83
|
+
upgrade: () => import("./upgrade-ZC2S7VRN.js"),
|
|
84
|
+
sync: () => import("./upgrade-ZC2S7VRN.js"),
|
|
85
|
+
update: () => import("./upgrade-ZC2S7VRN.js"),
|
|
86
|
+
package: () => import("./package-RMPN57YZ.js"),
|
|
87
|
+
doctor: () => import("./doctor-TJUGSQ5C.js"),
|
|
88
|
+
status: () => import("./status-KOSKCETC.js"),
|
|
89
|
+
telemetry: () => import("./telemetry-XIKUUGTQ.js"),
|
|
90
|
+
usage: () => import("./usage-E2A4O2CY.js"),
|
|
91
|
+
leaderboard: () => import("./leaderboard-TIBVONVT.js"),
|
|
92
|
+
hook: () => import("./hook-OU522ABV.js"),
|
|
93
|
+
// Internal (omitted from USAGE): the statusline (HUD) entrypoint a host's
|
|
94
|
+
// status line config points at. Fail-safe: always exits 0 with at most a
|
|
95
|
+
// rendered line. See cli/commands/statusline.ts.
|
|
96
|
+
statusline: () => import("./statusline-ZNTCL5YC.js"),
|
|
97
|
+
// Internal (omitted from USAGE): the user-invokable action entrypoint a future
|
|
98
|
+
// host affordance points at. USER-TRIGGERED: surfaces errors (exit 1 + stderr),
|
|
99
|
+
// unlike the fail-open hook / fail-safe statusline. See cli/commands/action.ts.
|
|
100
|
+
action: () => import("./action-PLZW5BGX.js"),
|
|
101
|
+
serve: () => import("./serve-D3GO36UT.js"),
|
|
94
102
|
// Hidden (omitted from USAGE): the opt-in host-native turn-usage entrypoint an
|
|
95
103
|
// AfterModel / PostInvocation hook points at. Always exits 0; records a
|
|
96
104
|
// distinct `model_turn` row. See cli/commands/usage-event.ts.
|
|
97
|
-
"usage-event": () => import("./usage-event-
|
|
105
|
+
"usage-event": () => import("./usage-event-JKMC4QC4.js")
|
|
98
106
|
};
|
|
99
107
|
var DEFAULT_PROGRAM_NAME = "agent-connector";
|
|
100
108
|
var COMMAND_USAGE = {
|
|
@@ -111,6 +119,8 @@ var COMMAND_USAGE = {
|
|
|
111
119
|
usage: "usage report|export|leaderboard [--by <dim>] [--since <dur>] [--platform <id>] [--format csv|json] [--out <file>] [--json]",
|
|
112
120
|
leaderboard: "leaderboard [--since <dur>] [--connector <id>] [--scope <slice>] [--json]",
|
|
113
121
|
hook: "hook <platform> <event> --connector <id> (internal \u2014 host hook configs point here)",
|
|
122
|
+
statusline: "statusline <platform> --connector <id> (internal \u2014 host status line configs point here)",
|
|
123
|
+
action: "action <platform> <actionId> --connector <id> (internal \u2014 host action affordances point here)",
|
|
114
124
|
serve: "serve --connector <id> [--scope user|project] [--host <platformId>] -- <command> [args...] (internal \u2014 host MCP entries point here)"
|
|
115
125
|
};
|
|
116
126
|
function buildUsage(programName) {
|
|
@@ -188,4 +198,4 @@ export {
|
|
|
188
198
|
renderInstallResult,
|
|
189
199
|
main
|
|
190
200
|
};
|
|
191
|
-
//# sourceMappingURL=chunk-
|
|
201
|
+
//# sourceMappingURL=chunk-KGXDYGNJ.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/cli/app.ts"],"sourcesContent":["/**\n * cli/app — shared CLI helpers + command dispatch (NO side effects).\n *\n * Command modules import the shared helpers (print, fail, parse-flags,\n * renderInstallResult) from here, and main() dispatches the first positional to a\n * command module.\n * This module never auto-runs — `cli/index.ts` is the thin bin entry that calls\n * `main()`. Keeping the auto-run out of here is what prevents a dispatch recursion\n * (a command module importing a helper must not re-trigger the program) and makes\n * it robust to bundler entry-splitting (the old import.meta.url entry-guard broke\n * once tsup hoisted this code into a shared chunk).\n */\n\nimport { createRequire } from \"node:module\";\n\nimport type {\n ChangeRecord,\n InstallResult,\n InstallScope,\n PlatformId,\n} from \"../core/types.js\";\n\n// ─────────────────────────────────────────────────────────────────────────\n// Shared helpers (imported by the command modules)\n// ─────────────────────────────────────────────────────────────────────────\n\n/** Print a line to stdout (machine-readable payloads must stay on stdout). */\nexport function print(line: string): void {\n process.stdout.write(`${line}\\n`);\n}\n\n/**\n * The brand active for THIS invocation. main() sets it from\n * {@link MainOptions.programName} before dispatch, so error messages printed by\n * command modules via {@link fail} read as the embedding tool (e.g. `acme-db:`)\n * instead of always `agent-connector:`.\n */\nlet activeProgramName = \"agent-connector\";\n\n/** Print an error to stderr (branded) and return a non-zero exit code (default 2). */\nexport function fail(message: string, code = 2): number {\n process.stderr.write(`${activeProgramName}: ${message}\\n`);\n return code;\n}\n\n/**\n * Resolve agent-connector's own package version at runtime. Works from both the\n * bundled dist layout (dist/*.js → ../package.json) and the src layout under\n * tsx/vitest (src/cli/ → ../../package.json); the name check guards against\n * accidentally reading some other package.json on the walk.\n */\nexport function resolveOwnVersion(): string {\n const req = createRequire(import.meta.url);\n for (const rel of [\"../package.json\", \"../../package.json\", \"../../../package.json\"]) {\n try {\n const pkg = req(rel) as { name?: string; version?: string };\n if (pkg.name === \"@ken-jo/agent-connector\" && typeof pkg.version === \"string\") {\n return pkg.version;\n }\n } catch {\n /* keep walking */\n }\n }\n return \"0.0.0\";\n}\n\n/** Parse a --scope value the CLI accepts (user|project) into an InstallScope. */\nexport function parseScope(value: string | undefined): InstallScope | null {\n if (value === \"user\" || value === \"project\") return value;\n return null;\n}\n\n/**\n * Parse a comma-separated --targets value into PlatformId[]. Returns undefined\n * when the flag is absent/empty so callers can fall back to connector/detection.\n */\nexport function parseTargets(value: string | undefined): PlatformId[] | undefined {\n if (value == null || value.trim() === \"\") return undefined;\n const ids = value\n .split(\",\")\n .map((s) => s.trim())\n .filter((s) => s !== \"\") as PlatformId[];\n return ids.length > 0 ? ids : undefined;\n}\n\nconst ACTION_GLYPH: Record<ChangeRecord[\"action\"], string> = {\n create: \"+\",\n update: \"~\",\n remove: \"-\",\n skip: \"=\",\n warn: \"!\",\n};\n\n/**\n * Render an InstallResult as a readable diff: one line per ChangeRecord (glyph,\n * platform, detail, path) followed by any warnings and a summary tally. Used by\n * install / upgrade / uninstall.\n */\nexport function renderInstallResult(\n result: InstallResult,\n verb: \"install\" | \"upgrade\" | \"uninstall\",\n): string {\n const lines: string[] = [];\n const mode = result.dryRun ? \" (dry-run — nothing written)\" : \"\";\n lines.push(`${verb} \"${result.connectorId}\"${mode}`);\n\n if (result.changes.length === 0) {\n lines.push(\" (no changes)\");\n } else {\n for (const c of result.changes) {\n const glyph = ACTION_GLYPH[c.action];\n const where = c.path ? ` ${c.path}` : \"\";\n lines.push(` ${glyph} [${c.platform}] ${c.action}: ${c.detail}${where}`);\n }\n }\n\n if (result.warnings.length > 0) {\n lines.push(\"\");\n lines.push(\"warnings:\");\n for (const w of result.warnings) lines.push(` ! ${w}`);\n }\n\n const tally = result.changes.reduce<Record<ChangeRecord[\"action\"], number>>(\n (acc, c) => {\n acc[c.action] += 1;\n return acc;\n },\n { create: 0, update: 0, remove: 0, skip: 0, warn: 0 },\n );\n lines.push(\"\");\n lines.push(\n `summary: ${tally.create} created, ${tally.update} updated, ` +\n `${tally.remove} removed, ${tally.skip} skipped, ${tally.warn} warning(s)`,\n );\n\n return lines.join(\"\\n\");\n}\n\n// ─────────────────────────────────────────────────────────────────────────\n// Command dispatch\n// ─────────────────────────────────────────────────────────────────────────\n\n/** A command module: takes the post-command argv slice, returns an exit code. */\ntype CommandModule = { run: (argv: string[]) => Promise<number> | number };\n\n/** Lazy command loaders — keyed by the first positional. Imported on demand. */\nconst COMMANDS: Record<string, () => Promise<CommandModule>> = {\n detect: () => import(\"./commands/detect.js\"),\n install: () => import(\"./commands/install.js\"),\n uninstall: () => import(\"./commands/uninstall.js\"),\n // `upgrade` is the single \"bring everything current\" verb (re-render host\n // config + refresh the home pointer + managed channel guidance). `sync` and\n // `update` are kept as back-compat aliases that route to the same module so\n // existing scripts/docs keep working without a second concept to learn.\n upgrade: () => import(\"./commands/upgrade.js\"),\n sync: () => import(\"./commands/upgrade.js\"),\n update: () => import(\"./commands/upgrade.js\"),\n package: () => import(\"./commands/package.js\"),\n doctor: () => import(\"./commands/doctor.js\"),\n status: () => import(\"./commands/status.js\"),\n telemetry: () => import(\"./commands/telemetry.js\"),\n usage: () => import(\"./commands/usage.js\"),\n leaderboard: () => import(\"./commands/leaderboard.js\"),\n hook: () => import(\"./commands/hook.js\"),\n // Internal (omitted from USAGE): the statusline (HUD) entrypoint a host's\n // status line config points at. Fail-safe: always exits 0 with at most a\n // rendered line. See cli/commands/statusline.ts.\n statusline: () => import(\"./commands/statusline.js\"),\n // Internal (omitted from USAGE): the user-invokable action entrypoint a future\n // host affordance points at. USER-TRIGGERED: surfaces errors (exit 1 + stderr),\n // unlike the fail-open hook / fail-safe statusline. See cli/commands/action.ts.\n action: () => import(\"./commands/action.js\"),\n serve: () => import(\"./commands/serve.js\"),\n // Hidden (omitted from USAGE): the opt-in host-native turn-usage entrypoint an\n // AfterModel / PostInvocation hook points at. Always exits 0; records a\n // distinct `model_turn` row. See cli/commands/usage-event.ts.\n \"usage-event\": () => import(\"./commands/usage-event.js\"),\n};\n\n/** Default program name; an embedding SDK CLI overrides it via {@link MainOptions}. */\nexport const DEFAULT_PROGRAM_NAME = \"agent-connector\";\n\n/**\n * One-line usage signature per command — the single central copy behind\n * `<command> --help` and the friendly bad-flag error. Command modules use\n * node:util parseArgs (strict), which THROWS on an unknown flag; without the\n * dispatcher-level handling in {@link main}, `agent-connector install --help`\n * would die with a raw ERR_PARSE_ARGS stack trace — the very invocation the\n * root help tells users to run.\n */\nconst COMMAND_USAGE: Record<string, string> = {\n detect: \"detect [--json] [--project <dir>]\",\n install:\n \"install [--method direct|marketplace] [--connector <path>] [--scope user|project] [--targets a,b] [--project <dir>] [--dry-run] [--force]\",\n uninstall:\n \"uninstall [--method auto|direct|marketplace] [--connector <path>] [--connector-id <id>] [--scope user|project] [--targets a,b] [--project <dir>] [--dry-run] [--purge]\",\n upgrade:\n \"upgrade [--method direct|marketplace] [--channel stable|latest] [--connector <path>] [--scope user|project] [--targets a,b] [--project <dir>] [--dry-run]\",\n sync: \"sync — alias of upgrade (see `upgrade --help`)\",\n update: \"update — alias of upgrade (see `upgrade --help`)\",\n package:\n \"package [--connector <path>] [--format <fmt>|all] [--out <dir>] [--project <dir>] [--dry-run]\",\n doctor:\n \"doctor [--targets a,b] [--connector <path>] [--scope user|project] [--project <dir>] [--probe] [--json]\",\n status: \"status [--connector <path>] [--scope user|project] [--project <dir>] [--json]\",\n telemetry:\n \"telemetry report|export|leaderboard [--by <dim>] [--since <dur>] [--connector <id>] [--scope <slice>] [--format csv|json] [--out <file>] [--json]\",\n usage:\n \"usage report|export|leaderboard [--by <dim>] [--since <dur>] [--platform <id>] [--format csv|json] [--out <file>] [--json]\",\n leaderboard: \"leaderboard [--since <dur>] [--connector <id>] [--scope <slice>] [--json]\",\n hook: \"hook <platform> <event> --connector <id> (internal — host hook configs point here)\",\n statusline:\n \"statusline <platform> --connector <id> (internal — host status line configs point here)\",\n action:\n \"action <platform> <actionId> --connector <id> (internal — host action affordances point here)\",\n serve:\n \"serve --connector <id> [--scope user|project] [--host <platformId>] -- <command> [args...] (internal — host MCP entries point here)\",\n};\n\n/**\n * Build the top-level usage string for a given program name. The brand replaces\n * \"agent-connector\" in the title, the `usage:` line, and the per-command help\n * footer so an embedded CLI (e.g. `acme-db`) reads as its own tool.\n */\nfunction buildUsage(programName: string): string {\n return `${programName} — write your MCP server + hooks once, install everywhere.\n\nusage: ${programName} <command> [flags]\n\ncommands:\n detect List the AI-agent platforms installed on this machine.\n install Deploy a connector across its target platforms (--method direct writes host config; --method marketplace drives the host's plugin install).\n uninstall Remove a connector's registrations (--method auto reverses whichever method is actually installed).\n upgrade Bring everything current: re-render host config + heal the home pointer + managed update guidance (alias: update, sync).\n package Emit a marketplace/extension bundle (9 host formats, or the standard artifacts mcp-server-json | mcpb).\n doctor Health-check every detected platform; non-zero exit on any failure.\n status Light install-state summary: which connectors are present on which hosts (always exits 0).\n telemetry Inspect local per-tool token telemetry (report | export | leaderboard).\n usage Inspect host-native token usage from agent CLI logs (report | export | leaderboard).\n leaderboard Three leaderboards: 🔌 MCP/plugin (mcp-self) + 🖥️ host/user (host-scan-logs) + 🛰️ host-native turns (host-native-live) — never summed.\n hook Universal json-stdio hook entrypoint (hosts call this).\n serve Telemetry-wrapping MCP stdio proxy (wraps a real server command).\n\nRun \\`${programName} <command> --help\\` for command-specific flags.`;\n}\n\n/** Options accepted by {@link main}. */\nexport interface MainOptions {\n /**\n * The brand shown in usage/help text. Defaults to {@link DEFAULT_PROGRAM_NAME}.\n * An embedding SDK CLI (see cli/sdk.ts) passes its own bin name so every\n * subcommand's help reads as the developer's tool.\n */\n programName?: string;\n}\n\nexport async function main(argv: string[], opts: MainOptions = {}): Promise<number> {\n const programName = opts.programName ?? DEFAULT_PROGRAM_NAME;\n activeProgramName = programName; // brand every fail() in this invocation\n const usage = buildUsage(programName);\n const command = argv[0];\n\n if (command == null || command === \"--help\" || command === \"-h\" || command === \"help\") {\n print(usage);\n return command == null ? 1 : 0;\n }\n if (command === \"--version\" || command === \"-v\") {\n print(`${programName} ${resolveOwnVersion()}`);\n return 0;\n }\n\n const loader = COMMANDS[command];\n if (!loader) {\n process.stderr.write(`${programName}: unknown command \"${command}\"\\n\\n`);\n process.stderr.write(`${usage}\\n`);\n return 2;\n }\n\n // Per-command help: no command module defines a --help flag (strict parseArgs\n // would throw on it), so answer it centrally from COMMAND_USAGE.\n const rest = argv.slice(1);\n if (rest.includes(\"--help\") || rest.includes(\"-h\")) {\n const sig = COMMAND_USAGE[command];\n if (sig) {\n print(`usage: ${programName} ${sig}`);\n return 0;\n }\n }\n\n const mod = await loader();\n try {\n return await mod.run(rest);\n } catch (err) {\n // Friendly bad-flag errors: strict parseArgs throws ERR_PARSE_ARGS_* for an\n // unknown/malformed option — print the message + the usage line instead of\n // letting a raw stack trace reach the user. Everything else still rethrows\n // (the bin entry reports those as fatal).\n const code = (err as { code?: string }).code;\n if (typeof code === \"string\" && code.startsWith(\"ERR_PARSE_ARGS\")) {\n const message = err instanceof Error ? err.message : String(err);\n const sig = COMMAND_USAGE[command];\n if (sig) process.stderr.write(`usage: ${programName} ${sig}\\n`);\n return fail(message);\n }\n throw err;\n }\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1,7 +1,4 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
resolveSpawnCommand
|
|
4
|
-
} from "./chunk-MEH7GC7R.js";
|
|
5
2
|
|
|
6
3
|
// src/core/logger.ts
|
|
7
4
|
var ORDER = {
|
|
@@ -27,20 +24,7 @@ var log = {
|
|
|
27
24
|
debug: (...args) => emit("debug", args)
|
|
28
25
|
};
|
|
29
26
|
|
|
30
|
-
// src/core/spawn-child.ts
|
|
31
|
-
import { spawn } from "child_process";
|
|
32
|
-
function winQuoteArg(s) {
|
|
33
|
-
return `"${s.replace(/"/g, '""')}"`;
|
|
34
|
-
}
|
|
35
|
-
function spawnChild(command, args, options) {
|
|
36
|
-
const resolved = resolveSpawnCommand(command);
|
|
37
|
-
if (!resolved.needsShell) return spawn(resolved.file, args, options);
|
|
38
|
-
const line = [resolved.file, ...args].map(winQuoteArg).join(" ");
|
|
39
|
-
return spawn(line, { ...options, shell: true });
|
|
40
|
-
}
|
|
41
|
-
|
|
42
27
|
export {
|
|
43
|
-
log
|
|
44
|
-
spawnChild
|
|
28
|
+
log
|
|
45
29
|
};
|
|
46
|
-
//# sourceMappingURL=chunk-
|
|
30
|
+
//# sourceMappingURL=chunk-KHO5WNTP.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/core/logger.ts"],"sourcesContent":["/**\n * core/logger — minimal leveled logger. Writes human output to stderr so stdout\n * stays clean for machine-readable payloads (hook replies, --json output).\n */\n\nexport type LogLevel = \"silent\" | \"error\" | \"warn\" | \"info\" | \"debug\";\n\nconst ORDER: Record<LogLevel, number> = {\n silent: 0,\n error: 1,\n warn: 2,\n info: 3,\n debug: 4,\n};\n\nfunction currentLevel(): LogLevel {\n const env = (process.env.AGENT_CONNECTOR_LOG ?? \"info\").toLowerCase();\n return (env in ORDER ? env : \"info\") as LogLevel;\n}\n\nfunction emit(level: Exclude<LogLevel, \"silent\">, args: unknown[]): void {\n if (ORDER[currentLevel()] < ORDER[level]) return;\n const prefix = { error: \"✗\", warn: \"!\", info: \"›\", debug: \"·\" }[level];\n // eslint-disable-next-line no-console\n console.error(prefix, ...args);\n}\n\nexport const log = {\n error: (...args: unknown[]) => emit(\"error\", args),\n warn: (...args: unknown[]) => emit(\"warn\", args),\n info: (...args: unknown[]) => emit(\"info\", args),\n debug: (...args: unknown[]) => emit(\"debug\", args),\n};\n"],"mappings":";;;AAOA,IAAM,QAAkC;AAAA,EACtC,QAAQ;AAAA,EACR,OAAO;AAAA,EACP,MAAM;AAAA,EACN,MAAM;AAAA,EACN,OAAO;AACT;AAEA,SAAS,eAAyB;AAChC,QAAM,OAAO,QAAQ,IAAI,uBAAuB,QAAQ,YAAY;AACpE,SAAQ,OAAO,QAAQ,MAAM;AAC/B;AAEA,SAAS,KAAK,OAAoC,MAAuB;AACvE,MAAI,MAAM,aAAa,CAAC,IAAI,MAAM,KAAK,EAAG;AAC1C,QAAM,SAAS,EAAE,OAAO,UAAK,MAAM,KAAK,MAAM,UAAK,OAAO,OAAI,EAAE,KAAK;AAErE,UAAQ,MAAM,QAAQ,GAAG,IAAI;AAC/B;AAEO,IAAM,MAAM;AAAA,EACjB,OAAO,IAAI,SAAoB,KAAK,SAAS,IAAI;AAAA,EACjD,MAAM,IAAI,SAAoB,KAAK,QAAQ,IAAI;AAAA,EAC/C,MAAM,IAAI,SAAoB,KAAK,QAAQ,IAAI;AAAA,EAC/C,OAAO,IAAI,SAAoB,KAAK,SAAS,IAAI;AACnD;","names":[]}
|
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
} from "./chunk-DBQMX75U.js";
|
|
5
5
|
import {
|
|
6
6
|
BaseAdapter
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-IW77FFNX.js";
|
|
8
8
|
import {
|
|
9
9
|
buildHomeBinHookCommand,
|
|
10
10
|
buildServeWrapperCommand,
|
|
@@ -13,7 +13,7 @@ import {
|
|
|
13
13
|
isHostNativeUsageEnabled,
|
|
14
14
|
isUsageEventCommand,
|
|
15
15
|
shouldWrapForTelemetry
|
|
16
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-BXGFUENQ.js";
|
|
17
17
|
|
|
18
18
|
// src/adapters/antigravity/index.ts
|
|
19
19
|
import { existsSync } from "fs";
|
|
@@ -710,4 +710,4 @@ export {
|
|
|
710
710
|
adapter,
|
|
711
711
|
antigravity_default
|
|
712
712
|
};
|
|
713
|
-
//# sourceMappingURL=chunk-
|
|
713
|
+
//# sourceMappingURL=chunk-LL4OBGRU.js.map
|
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
isConcreteSemver,
|
|
8
8
|
isPlaceholderVersion,
|
|
9
9
|
registryTransportType
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-ADTHT2FN.js";
|
|
11
11
|
import {
|
|
12
12
|
writeTomlString
|
|
13
13
|
} from "./chunk-OPXAP3AC.js";
|
|
@@ -20,7 +20,7 @@ import {
|
|
|
20
20
|
buildHomeBinHookCommand,
|
|
21
21
|
buildServeWrapperCommand,
|
|
22
22
|
shouldWrapForTelemetry
|
|
23
|
-
} from "./chunk-
|
|
23
|
+
} from "./chunk-BXGFUENQ.js";
|
|
24
24
|
import {
|
|
25
25
|
ensureDir,
|
|
26
26
|
homeBinPath
|
|
@@ -1040,4 +1040,4 @@ export {
|
|
|
1040
1040
|
packageConnectorAll,
|
|
1041
1041
|
installInstructions
|
|
1042
1042
|
};
|
|
1043
|
-
//# sourceMappingURL=chunk-
|
|
1043
|
+
//# sourceMappingURL=chunk-MAH6QQTO.js.map
|