@ken-jo/agent-connector 0.1.0 → 0.3.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 +183 -24
- package/dist/{amp-QSFH2V7Y.js → amp-YGV66GJT.js} +9 -2
- package/dist/amp-YGV66GJT.js.map +1 -0
- package/dist/{antigravity-CX2YLSY7.js → antigravity-7IBYFO6P.js} +4 -3
- package/dist/{antigravity-cli-YQDFVV4U.js → antigravity-cli-JEOUP2VN.js} +4 -3
- package/dist/{antigravity-cli-YQDFVV4U.js.map → antigravity-cli-JEOUP2VN.js.map} +1 -1
- package/dist/{chunk-LTT56GI3.js → chunk-3JCRUROU.js} +18 -5
- package/dist/chunk-3JCRUROU.js.map +1 -0
- package/dist/chunk-44HUXXC6.js +284 -0
- package/dist/chunk-44HUXXC6.js.map +1 -0
- package/dist/{chunk-54EMKTTX.js → chunk-DS3LUFVN.js} +21 -21
- package/dist/chunk-DS3LUFVN.js.map +1 -0
- package/dist/chunk-GSGDG2BV.js +568 -0
- package/dist/chunk-GSGDG2BV.js.map +1 -0
- package/dist/{chunk-TRKWUNO4.js → chunk-KQSNDFBN.js} +13 -2
- package/dist/chunk-KQSNDFBN.js.map +1 -0
- package/dist/{chunk-KHO5WNTP.js → chunk-KVAAFYRR.js} +18 -2
- package/dist/chunk-KVAAFYRR.js.map +1 -0
- package/dist/chunk-N6HH7K6P.js +494 -0
- package/dist/chunk-N6HH7K6P.js.map +1 -0
- package/dist/{chunk-XUCWLJY5.js → chunk-NJU275US.js} +30 -30
- package/dist/{chunk-WCETQWWK.js → chunk-OP4KBXUO.js} +1 -17
- package/dist/chunk-OP4KBXUO.js.map +1 -0
- package/dist/{chunk-TIIP3RG2.js → chunk-PD4VFEBY.js} +342 -2
- package/dist/chunk-PD4VFEBY.js.map +1 -0
- package/dist/chunk-QADSG2JY.js +1989 -0
- package/dist/chunk-QADSG2JY.js.map +1 -0
- package/dist/{chunk-WV63X7IK.js → chunk-SCVBYSF7.js} +2 -2
- package/dist/chunk-SCVBYSF7.js.map +1 -0
- package/dist/{package-DLOVE2E4.js → chunk-WNREHWKL.js} +26 -115
- package/dist/chunk-WNREHWKL.js.map +1 -0
- package/dist/{chunk-YNZU6PAV.js → chunk-ZAM4M7LI.js} +74 -21
- package/dist/chunk-ZAM4M7LI.js.map +1 -0
- package/dist/claude-code-4275HQU4.js +1432 -0
- package/dist/claude-code-4275HQU4.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-QX57FJDN.js → codebuff-LE3KBZGM.js} +9 -2
- package/dist/codebuff-LE3KBZGM.js.map +1 -0
- package/dist/{codex-JFQTS6LU.js → codex-4BY2ZJIW.js} +148 -7
- package/dist/codex-4BY2ZJIW.js.map +1 -0
- package/dist/{copilot-cli-MTCGHZ2T.js → copilot-cli-IPISKO3V.js} +109 -2
- package/dist/copilot-cli-IPISKO3V.js.map +1 -0
- package/dist/{crush-I7PK3FGI.js → crush-X3E25EQG.js} +31 -3
- package/dist/crush-X3E25EQG.js.map +1 -0
- package/dist/{cursor-4TMXKJOZ.js → cursor-UH3W622V.js} +66 -5
- package/dist/cursor-UH3W622V.js.map +1 -0
- package/dist/{detect-WIAGVYS4.js → detect-MNDHGLSV.js} +7 -3
- package/dist/detect-MNDHGLSV.js.map +1 -0
- package/dist/{doctor-EZW2K4NI.js → doctor-N5KZDD55.js} +45 -7
- package/dist/doctor-N5KZDD55.js.map +1 -0
- package/dist/{droid-KN6VRMMT.js → droid-T5VBRXZF.js} +32 -3
- package/dist/droid-T5VBRXZF.js.map +1 -0
- package/dist/{gemini-cli-Y35FFK4M.js → gemini-cli-ZSUK55UA.js} +51 -3
- package/dist/gemini-cli-ZSUK55UA.js.map +1 -0
- package/dist/{goose-ZTGTSUFJ.js → goose-M3RR3CZG.js} +63 -4
- package/dist/goose-M3RR3CZG.js.map +1 -0
- package/dist/{hermes-H2KV44GK.js → hermes-CUNKIAR5.js} +76 -3
- package/dist/hermes-CUNKIAR5.js.map +1 -0
- package/dist/{hook-YVDILAMZ.js → hook-7LUOKIXH.js} +28 -13
- package/dist/hook-7LUOKIXH.js.map +1 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.js +3 -1
- package/dist/install-TQTT4F3I.js +89 -0
- package/dist/install-TQTT4F3I.js.map +1 -0
- package/dist/{jetbrains-copilot-HWA3DMH7.js → jetbrains-copilot-C3HDGGML.js} +16 -2
- package/dist/jetbrains-copilot-C3HDGGML.js.map +1 -0
- package/dist/kilo-PKAJCWPX.js +852 -0
- package/dist/kilo-PKAJCWPX.js.map +1 -0
- package/dist/{kilo-cli-EAQTHXUW.js → kilo-cli-QWUVXG2O.js} +186 -7
- package/dist/kilo-cli-QWUVXG2O.js.map +1 -0
- package/dist/{kimi-GQ7VXNYT.js → kimi-EVD7YKXS.js} +167 -9
- package/dist/kimi-EVD7YKXS.js.map +1 -0
- package/dist/{kiro-VQTT6LO2.js → kiro-UQRY6EIO.js} +98 -4
- package/dist/kiro-UQRY6EIO.js.map +1 -0
- package/dist/{leaderboard-K6ON3SWW.js → leaderboard-MUJ7DURM.js} +3 -3
- package/dist/{mux-T2TV4CIQ.js → mux-5CI5FP2W.js} +9 -2
- package/dist/mux-5CI5FP2W.js.map +1 -0
- package/dist/{omp-PB4VDKS6.js → omp-AXA7XY22.js} +13 -2
- package/dist/omp-AXA7XY22.js.map +1 -0
- package/dist/{openclaw-ETN2M63O.js → openclaw-UZ5BMCGQ.js} +101 -4
- package/dist/openclaw-UZ5BMCGQ.js.map +1 -0
- package/dist/{opencode-FZ33JKUZ.js → opencode-NZBRLJN3.js} +53 -7
- package/dist/opencode-NZBRLJN3.js.map +1 -0
- package/dist/package-SYPA5POO.js +130 -0
- package/dist/package-SYPA5POO.js.map +1 -0
- package/dist/{pi-CIU2QHT4.js → pi-WMTUX6ES.js} +106 -23
- package/dist/pi-WMTUX6ES.js.map +1 -0
- package/dist/{qwen-code-5POCNU6P.js → qwen-code-MRRIUQ3P.js} +187 -6
- package/dist/qwen-code-MRRIUQ3P.js.map +1 -0
- package/dist/{roo-code-IOIUXRDE.js → roo-code-NI5UU6JB.js} +26 -2
- package/dist/roo-code-NI5UU6JB.js.map +1 -0
- package/dist/runtime/index.d.ts +38 -4
- package/dist/runtime/index.js +11 -6
- package/dist/{serve-HVWWY4B6.js → serve-XJOSA7BY.js} +9 -8
- package/dist/{serve-HVWWY4B6.js.map → serve-XJOSA7BY.js.map} +1 -1
- package/dist/{status-FE7TECZD.js → status-DYSS6BOR.js} +19 -9
- package/dist/status-DYSS6BOR.js.map +1 -0
- package/dist/{telemetry-36GESKQQ.js → telemetry-IJ4GP2Q3.js} +5 -4
- package/dist/{telemetry-36GESKQQ.js.map → telemetry-IJ4GP2Q3.js.map} +1 -1
- package/dist/{trae-JSNDZFKL.js → trae-CQC72RHH.js} +9 -2
- package/dist/trae-CQC72RHH.js.map +1 -0
- package/dist/types-CNigfEuR.d.ts +757 -0
- package/dist/uninstall-3DXIBRCV.js +162 -0
- package/dist/uninstall-3DXIBRCV.js.map +1 -0
- package/dist/{upgrade-JV2VK242.js → upgrade-GJEB3ITY.js} +29 -10
- package/dist/upgrade-GJEB3ITY.js.map +1 -0
- package/dist/{usage-6ER6EMEY.js → usage-2BJLM3GJ.js} +3 -3
- package/dist/{usage-event-JKBI6XCF.js → usage-event-472X3DOY.js} +8 -7
- package/dist/{usage-event-JKBI6XCF.js.map → usage-event-472X3DOY.js.map} +1 -1
- package/dist/{vscode-copilot-CK3NO54M.js → vscode-copilot-4RVRTCKV.js} +53 -4
- package/dist/vscode-copilot-4RVRTCKV.js.map +1 -0
- package/dist/{warp-QNVDXOG4.js → warp-X6MB67NT.js} +110 -4
- package/dist/warp-X6MB67NT.js.map +1 -0
- package/dist/{zed-VRJKWYUR.js → zed-NTCYW4V2.js} +120 -5
- package/dist/zed-NTCYW4V2.js.map +1 -0
- package/package.json +4 -3
- package/dist/amp-QSFH2V7Y.js.map +0 -1
- package/dist/chunk-54EMKTTX.js.map +0 -1
- package/dist/chunk-7MSDGHJW.js +0 -316
- package/dist/chunk-7MSDGHJW.js.map +0 -1
- package/dist/chunk-KHO5WNTP.js.map +0 -1
- package/dist/chunk-LTT56GI3.js.map +0 -1
- package/dist/chunk-TIIP3RG2.js.map +0 -1
- package/dist/chunk-TRKWUNO4.js.map +0 -1
- package/dist/chunk-WCETQWWK.js.map +0 -1
- package/dist/chunk-WV63X7IK.js.map +0 -1
- package/dist/chunk-XNAM7F35.js +0 -276
- package/dist/chunk-XNAM7F35.js.map +0 -1
- package/dist/chunk-YNZU6PAV.js.map +0 -1
- package/dist/claude-code-HKDV7T32.js +0 -637
- package/dist/claude-code-HKDV7T32.js.map +0 -1
- package/dist/codebuff-QX57FJDN.js.map +0 -1
- package/dist/codex-JFQTS6LU.js.map +0 -1
- package/dist/copilot-cli-MTCGHZ2T.js.map +0 -1
- package/dist/crush-I7PK3FGI.js.map +0 -1
- package/dist/cursor-4TMXKJOZ.js.map +0 -1
- package/dist/detect-WIAGVYS4.js.map +0 -1
- package/dist/doctor-EZW2K4NI.js.map +0 -1
- package/dist/droid-KN6VRMMT.js.map +0 -1
- package/dist/gemini-cli-Y35FFK4M.js.map +0 -1
- package/dist/goose-ZTGTSUFJ.js.map +0 -1
- package/dist/hermes-H2KV44GK.js.map +0 -1
- package/dist/hook-YVDILAMZ.js.map +0 -1
- package/dist/install-HQRYZOQ2.js +0 -60
- package/dist/install-HQRYZOQ2.js.map +0 -1
- package/dist/jetbrains-copilot-HWA3DMH7.js.map +0 -1
- package/dist/kilo-QXJRCSLT.js +0 -384
- package/dist/kilo-QXJRCSLT.js.map +0 -1
- package/dist/kilo-cli-EAQTHXUW.js.map +0 -1
- package/dist/kimi-GQ7VXNYT.js.map +0 -1
- package/dist/kiro-VQTT6LO2.js.map +0 -1
- package/dist/mux-T2TV4CIQ.js.map +0 -1
- package/dist/omp-PB4VDKS6.js.map +0 -1
- package/dist/openclaw-ETN2M63O.js.map +0 -1
- package/dist/opencode-FZ33JKUZ.js.map +0 -1
- package/dist/package-DLOVE2E4.js.map +0 -1
- package/dist/pi-CIU2QHT4.js.map +0 -1
- package/dist/qwen-code-5POCNU6P.js.map +0 -1
- package/dist/roo-code-IOIUXRDE.js.map +0 -1
- package/dist/status-FE7TECZD.js.map +0 -1
- package/dist/trae-JSNDZFKL.js.map +0 -1
- package/dist/types-CYUB1OTr.d.ts +0 -427
- package/dist/uninstall-IGCKNOSF.js +0 -72
- package/dist/uninstall-IGCKNOSF.js.map +0 -1
- package/dist/upgrade-JV2VK242.js.map +0 -1
- package/dist/vscode-copilot-CK3NO54M.js.map +0 -1
- package/dist/warp-QNVDXOG4.js.map +0 -1
- package/dist/zed-VRJKWYUR.js.map +0 -1
- /package/dist/{antigravity-CX2YLSY7.js.map → antigravity-7IBYFO6P.js.map} +0 -0
- /package/dist/{chunk-XUCWLJY5.js.map → chunk-NJU275US.js.map} +0 -0
- /package/dist/{leaderboard-K6ON3SWW.js.map → leaderboard-MUJ7DURM.js.map} +0 -0
- /package/dist/{usage-6ER6EMEY.js.map → usage-2BJLM3GJ.js.map} +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/adapters/pi/index.ts"],"sourcesContent":["/**\n * adapters/pi — Pi platform adapter for agent-connector.\n *\n * Pi is a file-based-skills host with NO writable MCP config and a native\n * prompt-template (slash command) surface. It has no lifecycle hook system in\n * the json-stdio or ts-plugin sense. Its extensibility surfaces are:\n *\n * - server → single \"skip\" (Pi has no writable MCP config).\n * - hooks → single \"skip\" (no json-stdio / ts-plugin hook layer).\n * - commands → write prompt templates under <piPromptsDir>/<name>.md.\n * project scope → <projectDir>/.pi/prompts/<name>.md\n * user scope → ~/.pi/agent/prompts/<name>.md\n * - skills → write <piSkillsDir>/<name>/SKILL.md (+ declared resources).\n * project scope → <projectDir>/.pi/skills/<name>/SKILL.md\n * user scope → ~/.pi/agent/skills/<name>/SKILL.md\n * - subagents → unsupported (BaseAdapter skip/warn).\n *\n * Ground-truth refs (docs/research/kilo-pi-ground-truth.md):\n * - prompt templates: docs/prompt-templates.md → ~/.pi/agent/prompts/*.md\n * and .pi/prompts/*.md, invoked as /name.\n * - global skills: ~/.pi/agent/skills/<n>/SKILL.md (NOT ~/.pi/skills/).\n * - project skills: .pi/skills/<n>/SKILL.md (unchanged).\n * - allowed-tools: space-delimited (NOT comma-delimited).\n */\n\nimport { existsSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\n\nimport { BaseAdapter } from \"../base.js\";\nimport type { Adapter, InstallContext } from \"../spi.js\";\nimport type {\n ChangeRecord,\n CommandDef,\n DetectedPlatform,\n HealthCheck,\n HookParadigm,\n PlatformCapabilities,\n PlatformId,\n SkillDef,\n} from \"../../core/types.js\";\n\nconst HOST: PlatformId = \"pi\";\n\nexport class PiAdapter extends BaseAdapter implements Adapter {\n readonly id: PlatformId = HOST;\n readonly name = \"Pi\";\n /**\n * Pi has no MCP surface at all — the paradigm label \"mcp-only\" is backwards\n * for a host with NO writable MCP config. Pi is purely a content-surface host\n * (skills + prompt templates). Use \"mcp-only\" only because the HookParadigm\n * union has no \"no-mcp\" variant; MCP is explicitly unsupported below.\n */\n readonly paradigm: HookParadigm = \"mcp-only\";\n\n readonly capabilities: PlatformCapabilities = {\n // Memory surface: AGENTS.md-first managed block via the BaseAdapter default\n // (user scope: ~/.pi/agent/AGENTS.md per base.ts AGENTS_MD_USER_PATHS).\n supportsMemory: true,\n // Pi has no json-stdio / ts-plugin lifecycle hook system.\n preToolUse: false,\n postToolUse: false,\n preCompact: false,\n sessionStart: false,\n sessionEnd: false,\n userPromptSubmit: false,\n stop: false,\n notification: false,\n canModifyArgs: false,\n canModifyOutput: false,\n canInjectSessionContext: false,\n // No writable MCP config.\n transports: [],\n // Content surfaces: prompt-template commands + skills.\n supportsCommands: true,\n supportsSkills: true,\n supportsSubagents: false,\n };\n\n // ── Detection ────────────────────────────────────────────────────────────\n\n detectInstalled(projectDir: string): DetectedPlatform {\n const userDir = join(homedir(), \".pi\");\n const projDir = join(projectDir, \".pi\");\n\n const userInstalled = existsSync(userDir);\n const projInstalled = existsSync(projDir);\n const installed = userInstalled || projInstalled;\n const scope = projInstalled && !userInstalled ? \"project\" : \"user\";\n const configPath = scope === \"project\" ? projDir : userDir;\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 ? `found Pi config (${scope}) at ${configPath}`\n : `no .pi config at ${userDir} or ${projDir}`,\n confidence: installed ? \"high\" : \"low\",\n };\n }\n\n // ── Native paths ─────────────────────────────────────────────────────────\n\n /**\n * Base config dir (used for server/hook doctor paths only; content surfaces\n * use dedicated helpers below so the scope split is explicit).\n */\n getConfigDir(ctx: InstallContext): string {\n return ctx.scope === \"project\"\n ? join(ctx.projectDir, \".pi\")\n : join(homedir(), \".pi\");\n }\n\n /**\n * Pi has no writable MCP config. Returning the config dir keeps the generic\n * doctor/backup sensible while installServer always skips.\n */\n getServerConfigPath(ctx: InstallContext): string {\n return this.getConfigDir(ctx);\n }\n\n /** Pi has no hook file — point at the config dir for generic doctor/backup. */\n getHookConfigPath(ctx: InstallContext): string {\n return this.getConfigDir(ctx);\n }\n\n /**\n * Prompt-templates dir (slash commands):\n * project scope → <projectDir>/.pi/prompts/\n * user scope → ~/.pi/agent/prompts/\n * (ground truth: docs/prompt-templates.md)\n */\n private promptsDir(ctx: InstallContext): string {\n return ctx.scope === \"project\"\n ? join(ctx.projectDir, \".pi\", \"prompts\")\n : join(homedir(), \".pi\", \"agent\", \"prompts\");\n }\n\n /**\n * Skills dir:\n * project scope → <projectDir>/.pi/skills/\n * user scope → ~/.pi/agent/skills/\n * (ground truth: ~/.pi/agent/skills/ is what Pi actually reads for global skills)\n */\n private skillsDir(ctx: InstallContext): string {\n return ctx.scope === \"project\"\n ? join(ctx.projectDir, \".pi\", \"skills\")\n : join(homedir(), \".pi\", \"agent\", \"skills\");\n }\n\n /** Native skill dir: <skillsDir>/<name>. */\n private skillDir(ctx: InstallContext, name: string): string {\n return join(this.skillsDir(ctx), name);\n }\n\n // ── MCP server (unavailable — Pi has no writable MCP config) ─────────────\n\n installServer(_ctx: InstallContext): ChangeRecord[] {\n return [\n {\n platform: this.id,\n action: \"skip\",\n detail: \"Pi has no writable MCP config\",\n },\n ];\n }\n\n uninstallServer(_ctx: InstallContext): ChangeRecord[] {\n return [\n {\n platform: this.id,\n action: \"skip\",\n detail: \"Pi has no writable MCP config\",\n },\n ];\n }\n\n // ── Hooks (unavailable — Pi has no json-stdio/ts-plugin hook layer) ───────\n\n installHooks(_ctx: InstallContext): ChangeRecord[] {\n return [\n {\n platform: this.id,\n action: \"skip\",\n detail: \"hooks unavailable (Pi has no hook layer)\",\n },\n ];\n }\n\n uninstallHooks(_ctx: InstallContext): ChangeRecord[] {\n return [\n {\n platform: this.id,\n action: \"skip\",\n detail: \"hooks unavailable (Pi has no hook layer)\",\n },\n ];\n }\n\n // ── Content surface: commands (prompt templates) ─────────────────────────\n // Pi slash commands are prompt template files: <promptsDir>/<name>.md.\n // Idempotent (byte-identical → skip) via BaseAdapter.writeContentFile and\n // reversible via removeContentFile. Honors platforms[\"pi\"].commands === false.\n\n /** Native prompt-template file path: <promptsDir>/<name>.md. */\n private commandPath(ctx: InstallContext, name: string): string {\n return join(this.promptsDir(ctx), `${name}.md`);\n }\n\n override installCommands(ctx: InstallContext): ChangeRecord[] {\n const { connector } = ctx;\n if (connector.platforms[HOST]?.commands === false) {\n return [{ platform: this.id, action: \"skip\", detail: \"commands disabled for pi\" }];\n }\n if (connector.commands.length === 0) {\n return [{ platform: this.id, action: \"skip\", detail: \"connector declares no commands\" }];\n }\n return connector.commands.map((cmd) =>\n this.writeContentFile(\n this.commandPath(ctx, cmd.name),\n this.renderCommand(cmd),\n ctx.dryRun,\n ),\n );\n }\n\n override uninstallCommands(ctx: InstallContext): ChangeRecord[] {\n const { connector } = ctx;\n if (connector.commands.length === 0) {\n return [{ platform: this.id, action: \"skip\", detail: \"connector declares no commands\" }];\n }\n return connector.commands.map((cmd) =>\n this.removeContentFile(this.commandPath(ctx, cmd.name), ctx.dryRun),\n );\n }\n\n /**\n * Render a command as a Pi prompt template (md+frontmatter).\n * Pi's format mirrors the generic command render: description, optional model,\n * optional argument-hint. The body is the prompt template text.\n */\n private renderCommand(cmd: CommandDef): string {\n const frontmatter: Record<string, unknown> = {};\n if (cmd.description !== undefined) frontmatter.description = cmd.description;\n if (cmd.model !== undefined) frontmatter.model = cmd.model;\n if (cmd.argumentHint !== undefined) frontmatter[\"argument-hint\"] = cmd.argumentHint;\n if (cmd.extra) Object.assign(frontmatter, cmd.extra);\n return this.renderFrontmatterMd(frontmatter, cmd.prompt);\n }\n\n // ── Content surface: skills ──────────────────────────────────────────────\n // CONTENT-ONLY: pure native-file writer under <skillsDir>/<name>.\n // Idempotent (byte-identical → skip) via BaseAdapter.writeContentFile and\n // reversible via removeContentFile. Honors platforms[\"pi\"].skills === false.\n\n override installSkills(ctx: InstallContext): ChangeRecord[] {\n const { connector } = ctx;\n if (connector.platforms[HOST]?.skills === false) {\n return [{ platform: this.id, action: \"skip\", detail: \"skills disabled for pi\" }];\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 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 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;\n changes.push(this.removeContentFile(target, ctx.dryRun));\n }\n // Only remove the skill dir when WE own its full contents.\n changes.push(this.removeDirIfEmpty(dir, ctx.dryRun));\n }\n return changes;\n }\n\n /**\n * Render a skill's SKILL.md.\n *\n * Pi's allowed-tools field is SPACE-delimited (not comma-delimited).\n * Every other field follows the uniform SKILL.md convention.\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 // Pi reads allowed-tools as space-separated — NOT the \", \" used by other hosts.\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 // ── Diagnostics ──────────────────────────────────────────────────────────\n\n override getHealthChecks(ctx: InstallContext): readonly HealthCheck[] {\n const checks: HealthCheck[] = [];\n\n // Command (prompt-template) checks.\n for (const cmd of ctx.connector.commands) {\n const p = this.commandPath(ctx, cmd.name);\n checks.push({\n name: `${this.name}: command ${cmd.name} present`,\n check: () =>\n existsSync(p)\n ? { status: \"OK\", detail: p }\n : { status: \"FAIL\", detail: `not found: ${p}` },\n });\n }\n\n // Skill-surface checks.\n for (const skill of ctx.connector.skills) {\n const p = join(this.skillDir(ctx, skill.name), \"SKILL.md\");\n checks.push({\n name: `${this.name}: skill ${skill.name} present`,\n check: () =>\n existsSync(p)\n ? { status: \"OK\", detail: p }\n : { status: \"FAIL\", detail: `not found: ${p}` },\n });\n }\n return checks;\n }\n}\n\nexport const adapter = new PiAdapter();\nexport default adapter;\n"],"mappings":"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","names":[]}
|
|
@@ -7,14 +7,17 @@ import {
|
|
|
7
7
|
} from "./chunk-DBQMX75U.js";
|
|
8
8
|
import {
|
|
9
9
|
BaseAdapter
|
|
10
|
-
} from "./chunk-
|
|
11
|
-
import
|
|
10
|
+
} from "./chunk-PD4VFEBY.js";
|
|
11
|
+
import {
|
|
12
|
+
renderSkillMd
|
|
13
|
+
} from "./chunk-7L6ITC4T.js";
|
|
12
14
|
import {
|
|
13
15
|
buildHomeBinHookCommand,
|
|
14
16
|
buildServeWrapperCommand,
|
|
15
17
|
isHomeBinHookCommand,
|
|
16
18
|
shouldWrapForTelemetry
|
|
17
19
|
} from "./chunk-MEH7GC7R.js";
|
|
20
|
+
import "./chunk-N6HH7K6P.js";
|
|
18
21
|
import "./chunk-TRQKHP7D.js";
|
|
19
22
|
|
|
20
23
|
// src/adapters/qwen-code/index.ts
|
|
@@ -28,6 +31,11 @@ var QwenCodeAdapter = class extends BaseAdapter {
|
|
|
28
31
|
name = "Qwen CLI";
|
|
29
32
|
paradigm = "json-stdio";
|
|
30
33
|
capabilities = {
|
|
34
|
+
// Memory surface: AGENTS.md-first managed block (project <projectDir>/AGENTS.md
|
|
35
|
+
// via the base default — Qwen reads repo AGENTS.md natively alongside QWEN.md,
|
|
36
|
+
// so no QWEN.md duplicate; user scope → ~/.qwen/QWEN.md below, the only
|
|
37
|
+
// documented user-scope memory file).
|
|
38
|
+
supportsMemory: true,
|
|
31
39
|
preToolUse: true,
|
|
32
40
|
postToolUse: true,
|
|
33
41
|
preCompact: true,
|
|
@@ -36,6 +44,12 @@ var QwenCodeAdapter = class extends BaseAdapter {
|
|
|
36
44
|
userPromptSubmit: true,
|
|
37
45
|
stop: true,
|
|
38
46
|
notification: true,
|
|
47
|
+
// E1 events — all four are Qwen-native (its 16-event surface is strictly
|
|
48
|
+
// wider than the canonical union).
|
|
49
|
+
permissionRequest: true,
|
|
50
|
+
postToolUseFailure: true,
|
|
51
|
+
subagentStart: true,
|
|
52
|
+
subagentStop: true,
|
|
39
53
|
// Qwen's PreToolUse can rewrite input (updatedInput). It CANNOT rewrite
|
|
40
54
|
// already-emitted tool output — `updatedMCPToolOutput` does not exist in
|
|
41
55
|
// qwen 0.17.1, so canModifyOutput is false (like the Claude-family hosts).
|
|
@@ -43,10 +57,12 @@ var QwenCodeAdapter = class extends BaseAdapter {
|
|
|
43
57
|
canModifyOutput: false,
|
|
44
58
|
canInjectSessionContext: true,
|
|
45
59
|
transports: ["stdio", "sse", "http"],
|
|
46
|
-
// Content surfaces: Qwen ships native slash commands (TOML)
|
|
47
|
-
// (md+frontmatter)
|
|
48
|
-
//
|
|
60
|
+
// Content surfaces: Qwen ships native slash commands (TOML), subagents
|
|
61
|
+
// (md+frontmatter), and skills (SKILL.md under .qwen/skills/<name>/).
|
|
62
|
+
// Confirmed dir: .qwen/skills/ (project), ~/.qwen/skills/ (user scope).
|
|
63
|
+
// Ground truth: kilo-pi-ground-truth.md § "Already-known skills gaps".
|
|
49
64
|
supportsCommands: true,
|
|
65
|
+
supportsSkills: true,
|
|
50
66
|
supportsSubagents: true
|
|
51
67
|
};
|
|
52
68
|
// ── Detection ────────────────────────────────────────────────────────────
|
|
@@ -72,6 +88,23 @@ var QwenCodeAdapter = class extends BaseAdapter {
|
|
|
72
88
|
confidence: installed ? "high" : "low"
|
|
73
89
|
};
|
|
74
90
|
}
|
|
91
|
+
// ── Memory surface: ~/.qwen/QWEN.md at user scope ────────────────────────
|
|
92
|
+
// Project scope stays on the AGENTS.md base default (Qwen reads the repo
|
|
93
|
+
// AGENTS.md natively in ADDITION to QWEN.md — one canonical copy, never a
|
|
94
|
+
// QWEN.md duplicate). User scope targets ~/.qwen/QWEN.md: Qwen has no
|
|
95
|
+
// user-scope AGENTS.md, so the host's own global memory file is the only
|
|
96
|
+
// file it actually reads there.
|
|
97
|
+
memoryTargets(ctx) {
|
|
98
|
+
if (this.memoryOverride(ctx)?.path || ctx.scope !== "user") {
|
|
99
|
+
return super.memoryTargets(ctx);
|
|
100
|
+
}
|
|
101
|
+
return [
|
|
102
|
+
{
|
|
103
|
+
path: join(homedir(), ".qwen", "QWEN.md"),
|
|
104
|
+
reason: "qwen-code global memory (~/.qwen/QWEN.md; no user-scope AGENTS.md exists)"
|
|
105
|
+
}
|
|
106
|
+
];
|
|
107
|
+
}
|
|
75
108
|
// ── Native paths ─────────────────────────────────────────────────────────
|
|
76
109
|
getConfigDir(ctx) {
|
|
77
110
|
return ctx.scope === "project" ? join(ctx.projectDir, ".qwen") : join(homedir(), ".qwen");
|
|
@@ -284,6 +317,9 @@ var QwenCodeAdapter = class extends BaseAdapter {
|
|
|
284
317
|
commandsDir(ctx) {
|
|
285
318
|
return join(this.getConfigDir(ctx), "commands");
|
|
286
319
|
}
|
|
320
|
+
skillsDir(ctx) {
|
|
321
|
+
return join(this.getConfigDir(ctx), "skills");
|
|
322
|
+
}
|
|
287
323
|
agentsDir(ctx) {
|
|
288
324
|
return join(this.getConfigDir(ctx), "agents");
|
|
289
325
|
}
|
|
@@ -291,6 +327,10 @@ var QwenCodeAdapter = class extends BaseAdapter {
|
|
|
291
327
|
commandPath(ctx, name) {
|
|
292
328
|
return join(this.commandsDir(ctx), `${name}.toml`);
|
|
293
329
|
}
|
|
330
|
+
/** Native skill dir: <qwenDir>/skills/<name>. */
|
|
331
|
+
skillDir(ctx, name) {
|
|
332
|
+
return join(this.skillsDir(ctx), name);
|
|
333
|
+
}
|
|
294
334
|
/** Native subagent file path: <qwenDir>/agents/<name>.md. */
|
|
295
335
|
subagentPath(ctx, name) {
|
|
296
336
|
return join(this.agentsDir(ctx), `${name}.md`);
|
|
@@ -328,6 +368,61 @@ var QwenCodeAdapter = class extends BaseAdapter {
|
|
|
328
368
|
obj.prompt = cmd.prompt;
|
|
329
369
|
return writeTomlString(obj);
|
|
330
370
|
}
|
|
371
|
+
// ── Skills ────────────────────────────────────────────────────────────────
|
|
372
|
+
// Qwen reads SKILL.md from <qwenDir>/skills/<name>/SKILL.md.
|
|
373
|
+
// Project dir: <projectDir>/.qwen/skills/<name>/SKILL.md
|
|
374
|
+
// User dir: ~/.qwen/skills/<name>/SKILL.md
|
|
375
|
+
// Confirmed: kilo-pi-ground-truth.md § "Already-known skills gaps" (.qwen/skills).
|
|
376
|
+
installSkills(ctx) {
|
|
377
|
+
const { connector } = ctx;
|
|
378
|
+
if (connector.platforms[HOST]?.skills === false) {
|
|
379
|
+
return [{ platform: this.id, action: "skip", detail: "skills disabled for qwen-code" }];
|
|
380
|
+
}
|
|
381
|
+
if (connector.skills.length === 0) {
|
|
382
|
+
return [{ platform: this.id, action: "skip", detail: "connector declares no skills" }];
|
|
383
|
+
}
|
|
384
|
+
const changes = [];
|
|
385
|
+
for (const skill of connector.skills) {
|
|
386
|
+
const dir = this.skillDir(ctx, skill.name);
|
|
387
|
+
changes.push(
|
|
388
|
+
this.writeContentFile(join(dir, "SKILL.md"), this.renderSkill(skill), ctx.dryRun)
|
|
389
|
+
);
|
|
390
|
+
for (const [rel, contents] of Object.entries(skill.resources ?? {})) {
|
|
391
|
+
const target = this.resolveWithin(dir, rel);
|
|
392
|
+
if (target === null) {
|
|
393
|
+
changes.push({
|
|
394
|
+
platform: this.id,
|
|
395
|
+
action: "warn",
|
|
396
|
+
detail: `skill resource "${rel}" escapes the skill dir; skipped`
|
|
397
|
+
});
|
|
398
|
+
continue;
|
|
399
|
+
}
|
|
400
|
+
changes.push(this.writeContentFile(target, contents, ctx.dryRun));
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
return changes;
|
|
404
|
+
}
|
|
405
|
+
uninstallSkills(ctx) {
|
|
406
|
+
const { connector } = ctx;
|
|
407
|
+
if (connector.skills.length === 0) {
|
|
408
|
+
return [{ platform: this.id, action: "skip", detail: "connector declares no skills" }];
|
|
409
|
+
}
|
|
410
|
+
const changes = [];
|
|
411
|
+
for (const skill of connector.skills) {
|
|
412
|
+
const dir = this.skillDir(ctx, skill.name);
|
|
413
|
+
changes.push(this.removeContentFile(join(dir, "SKILL.md"), ctx.dryRun));
|
|
414
|
+
for (const rel of Object.keys(skill.resources ?? {})) {
|
|
415
|
+
const target = this.resolveWithin(dir, rel);
|
|
416
|
+
if (target === null) continue;
|
|
417
|
+
changes.push(this.removeContentFile(target, ctx.dryRun));
|
|
418
|
+
}
|
|
419
|
+
changes.push(this.removeDirIfEmpty(dir, ctx.dryRun));
|
|
420
|
+
}
|
|
421
|
+
return changes;
|
|
422
|
+
}
|
|
423
|
+
renderSkill(skill) {
|
|
424
|
+
return renderSkillMd(skill);
|
|
425
|
+
}
|
|
331
426
|
// ── Subagents ──────────────────────────────────────────────────────────────
|
|
332
427
|
installSubagents(ctx) {
|
|
333
428
|
const { connector } = ctx;
|
|
@@ -404,6 +499,13 @@ var QwenCodeAdapter = class extends BaseAdapter {
|
|
|
404
499
|
check: () => existsSync(p) ? { status: "OK", detail: p } : { status: "FAIL", detail: `not found: ${p}` }
|
|
405
500
|
});
|
|
406
501
|
}
|
|
502
|
+
for (const skill of ctx.connector.skills) {
|
|
503
|
+
const p = join(this.skillDir(ctx, skill.name), "SKILL.md");
|
|
504
|
+
checks.push({
|
|
505
|
+
name: `${this.name}: skill ${skill.name} present`,
|
|
506
|
+
check: () => existsSync(p) ? { status: "OK", detail: p } : { status: "FAIL", detail: `not found: ${p}` }
|
|
507
|
+
});
|
|
508
|
+
}
|
|
407
509
|
for (const agent of ctx.connector.subagents) {
|
|
408
510
|
const p = this.subagentPath(ctx, agent.name);
|
|
409
511
|
checks.push({
|
|
@@ -486,6 +588,45 @@ var QwenCodeAdapter = class extends BaseAdapter {
|
|
|
486
588
|
};
|
|
487
589
|
return ev;
|
|
488
590
|
}
|
|
591
|
+
case "PermissionRequest": {
|
|
592
|
+
const ev = {
|
|
593
|
+
...base,
|
|
594
|
+
toolName: input.tool_name ?? "",
|
|
595
|
+
toolInput: input.tool_input ?? {},
|
|
596
|
+
...Array.isArray(input.permission_suggestions) ? { permissionSuggestions: input.permission_suggestions } : {}
|
|
597
|
+
};
|
|
598
|
+
return ev;
|
|
599
|
+
}
|
|
600
|
+
case "PostToolUseFailure": {
|
|
601
|
+
const ev = {
|
|
602
|
+
...base,
|
|
603
|
+
toolName: input.tool_name ?? "",
|
|
604
|
+
toolInput: input.tool_input ?? {},
|
|
605
|
+
error: typeof input.error === "string" ? input.error : "",
|
|
606
|
+
...typeof input.tool_use_id === "string" ? { toolUseId: input.tool_use_id } : {},
|
|
607
|
+
...typeof input.is_interrupt === "boolean" ? { isInterrupt: input.is_interrupt } : {}
|
|
608
|
+
};
|
|
609
|
+
return ev;
|
|
610
|
+
}
|
|
611
|
+
case "SubagentStart": {
|
|
612
|
+
const ev = {
|
|
613
|
+
...base,
|
|
614
|
+
...typeof input.agent_id === "string" ? { agentId: input.agent_id } : {},
|
|
615
|
+
...typeof input.agent_type === "string" ? { agentType: input.agent_type } : {}
|
|
616
|
+
};
|
|
617
|
+
return ev;
|
|
618
|
+
}
|
|
619
|
+
case "SubagentStop": {
|
|
620
|
+
const ev = {
|
|
621
|
+
...base,
|
|
622
|
+
...typeof input.agent_id === "string" ? { agentId: input.agent_id } : {},
|
|
623
|
+
...typeof input.agent_type === "string" ? { agentType: input.agent_type } : {},
|
|
624
|
+
...typeof input.agent_transcript_path === "string" ? { agentTranscriptPath: input.agent_transcript_path } : {},
|
|
625
|
+
...typeof input.last_assistant_message === "string" ? { lastAssistantMessage: input.last_assistant_message } : {},
|
|
626
|
+
...typeof input.stop_hook_active === "boolean" ? { stopHookActive: input.stop_hook_active } : {}
|
|
627
|
+
};
|
|
628
|
+
return ev;
|
|
629
|
+
}
|
|
489
630
|
default: {
|
|
490
631
|
const _never = event;
|
|
491
632
|
throw new Error(`unsupported qwen-code hook event: ${String(_never)}`);
|
|
@@ -496,6 +637,46 @@ var QwenCodeAdapter = class extends BaseAdapter {
|
|
|
496
637
|
formatReply(event, response) {
|
|
497
638
|
const hookEventName = event;
|
|
498
639
|
const decision = response.decision ?? "allow";
|
|
640
|
+
if (event === "PermissionRequest") {
|
|
641
|
+
if (response.decision === "deny") {
|
|
642
|
+
return this.stdout({
|
|
643
|
+
hookSpecificOutput: {
|
|
644
|
+
hookEventName,
|
|
645
|
+
decision: {
|
|
646
|
+
behavior: "deny",
|
|
647
|
+
message: response.reason ?? "Blocked by hook"
|
|
648
|
+
}
|
|
649
|
+
}
|
|
650
|
+
});
|
|
651
|
+
}
|
|
652
|
+
if (response.decision === "allow" || response.decision === "modify" && response.updatedInput) {
|
|
653
|
+
return this.stdout({
|
|
654
|
+
hookSpecificOutput: {
|
|
655
|
+
hookEventName,
|
|
656
|
+
decision: {
|
|
657
|
+
behavior: "allow",
|
|
658
|
+
...response.updatedInput ? { updatedInput: response.updatedInput } : {}
|
|
659
|
+
}
|
|
660
|
+
}
|
|
661
|
+
});
|
|
662
|
+
}
|
|
663
|
+
return { exitCode: 0 };
|
|
664
|
+
}
|
|
665
|
+
if (event === "PostToolUseFailure" || event === "SubagentStart") {
|
|
666
|
+
const context = decision === "context" ? response.additionalContext : decision === "deny" ? response.reason ?? response.additionalContext : void 0;
|
|
667
|
+
if (context) {
|
|
668
|
+
return this.stdout({
|
|
669
|
+
hookSpecificOutput: { hookEventName, additionalContext: context }
|
|
670
|
+
});
|
|
671
|
+
}
|
|
672
|
+
return { exitCode: 0 };
|
|
673
|
+
}
|
|
674
|
+
if (decision === "deny" && event === "SubagentStop") {
|
|
675
|
+
return this.stdout({
|
|
676
|
+
decision: "block",
|
|
677
|
+
reason: response.reason ?? "Blocked by hook"
|
|
678
|
+
});
|
|
679
|
+
}
|
|
499
680
|
if (decision === "deny") {
|
|
500
681
|
return this.stdout({
|
|
501
682
|
hookSpecificOutput: {
|
|
@@ -570,4 +751,4 @@ export {
|
|
|
570
751
|
adapter,
|
|
571
752
|
qwen_code_default as default
|
|
572
753
|
};
|
|
573
|
-
//# sourceMappingURL=qwen-code-
|
|
754
|
+
//# sourceMappingURL=qwen-code-MRRIUQ3P.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/adapters/qwen-code/index.ts"],"sourcesContent":["/**\n * adapters/qwen-code — Qwen Code (Qwen CLI) platform adapter for agent-connector.\n *\n * Qwen Code is a Gemini-CLI-derived host, but — unlike Gemini CLI — its hook\n * WIRE PROTOCOL is Claude-compatible (verified against context-mode's proven\n * qwen-code adapter, which extends the shared ClaudeCodeBaseAdapter):\n *\n * - Hook event names are PascalCase, identical to Claude Code:\n * PreToolUse, PostToolUse, PreCompact, SessionStart, SessionEnd,\n * UserPromptSubmit, Stop, Notification — plus the E1 extension events\n * PermissionRequest, PostToolUseFailure, SubagentStart and SubagentStop,\n * all Qwen-native (verified against the upstream\n * docs/users/features/hooks.md: PermissionRequest takes the nested\n * hookSpecificOutput.decision{behavior} envelope, PostToolUseFailure /\n * SubagentStart are additionalContext feedback, SubagentStop blocks via\n * the TOP-LEVEL {\"decision\":\"block\",\"reason\"} Stop shape).\n * (NOT Gemini's BeforeTool/AfterTool/PreCompress vocabulary.)\n * - Hook stdin JSON carries snake_case fields: session_id, transcript_path,\n * cwd, tool_name, tool_input, tool_response, source, reason, prompt,\n * trigger, stop_hook_active, message.\n * - Reply is exit-code 0 + a `hookSpecificOutput` JSON object on stdout\n * (permissionDecision allow|deny|ask, updatedInput, additionalContext) —\n * the Claude reply shape. Qwen's PreToolUse CAN rewrite tool input\n * (updatedInput; capabilities.canModifyArgs = true), but — verified against\n * qwen 0.17.1 — there is NO `updatedMCPToolOutput` honor on PostToolUse, so\n * this host CANNOT rewrite already-emitted tool output\n * (capabilities.canModifyOutput = false, like the Claude-family hosts).\n * - Native tool names are Qwen/Gemini-flavored (run_shell_command, read_file,\n * write_file, grep_search, …) — used only inside matcher strings; the wire\n * field names are unchanged from Claude.\n *\n * Native config (JSONC — Qwen shares Gemini's tolerant settings loader; we write\n * strict JSON and MERGE into any existing settings so user keys survive):\n * - MCP servers: user → ~/.qwen/settings.json; project → <projectDir>/.qwen/\n * settings.json. Root key \"mcpServers\". Qwen is a Gemini-CLI fork, so — like\n * Gemini — the MCP TRANSPORT IS SELECTED BY WHICH KEY IS PRESENT, not a\n * `type` field: stdio → {command,args,env(,cwd)}; SSE → {url, headers?};\n * streamable-HTTP → {httpUrl, headers?}.\n * - Hooks: the SAME settings.json, top-level sibling \"hooks\" key, keyed by the\n * PascalCase event name, each value an array of\n * `{ matcher, hooks:[{ type:\"command\", command }] }`.\n *\n * Env handling: Qwen's settings loader has no `${env:VAR}` interpolation of our\n * framework's dialect, so env / header / url refs resolve to literals at install\n * time via resolveEnvRefsDeep — the safe default shared with the Gemini / Codex\n * adapters.\n */\n\nimport { existsSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\n\nimport { BaseAdapter } from \"../base.js\";\nimport type { Adapter, HookReply, InstallContext, MemoryTarget, NormalizedEvent } from \"../spi.js\";\nimport type {\n ChangeRecord,\n CommandDef,\n DetectedPlatform,\n HealthCheck,\n HookEventName,\n HookParadigm,\n HookResponse,\n NotificationEvent,\n PermissionRequestEvent,\n PlatformCapabilities,\n PlatformId,\n PostToolUseEvent,\n PostToolUseFailureEvent,\n PreCompactEvent,\n PreToolUseEvent,\n ServerDef,\n SessionEndEvent,\n SessionStartEvent,\n SkillDef,\n StopEvent,\n SubagentDef,\n SubagentStartEvent,\n SubagentStopEvent,\n Transport,\n UserPromptSubmitEvent,\n} from \"../../core/types.js\";\nimport { renderSkillMd } from \"../claude-code/render.js\";\nimport { resolveEnvRefsDeep } from \"../../core/interpolate.js\";\nimport { writeTomlString } from \"../../core/toml.js\";\nimport {\n buildHomeBinHookCommand,\n buildServeWrapperCommand,\n isHomeBinHookCommand,\n shouldWrapForTelemetry,\n} from \"../../core/spawn.js\";\n\nconst HOST: PlatformId = \"qwen-code\";\nconst MCP_ROOT_KEY = \"mcpServers\";\n\n/** A single hook registration entry as Qwen stores it (Claude-shaped, nested). */\ninterface QwenHookEntry {\n matcher: string;\n hooks: Array<{ type: \"command\"; command: string }>;\n}\n\n/** Shape of Qwen's settings.json (only the parts we touch). */\ninterface QwenSettingsFile {\n mcpServers?: Record<string, unknown>;\n hooks?: Record<string, QwenHookEntry[]>;\n [key: string]: unknown;\n}\n\n/**\n * Native MCP server entry shapes Qwen accepts under `mcpServers`. Qwen is a\n * Gemini-CLI fork, so the REMOTE transport is selected by WHICH KEY is present\n * (NOT a `type` field): SSE → `url`, streamable-HTTP → `httpUrl`. The stdio\n * entry keeps its (harmless, Claude-style) `type:\"stdio\"` tag — Qwen accepts it\n * and stdio is unambiguous by its command/args anyway.\n */\ninterface QwenStdioServer {\n type: \"stdio\";\n command: string;\n args: string[];\n env?: Record<string, string>;\n cwd?: string;\n}\ninterface QwenSseServer {\n url: string;\n headers?: Record<string, string>;\n}\ninterface QwenHttpServer {\n httpUrl: string;\n headers?: Record<string, string>;\n}\n\n/** Raw Qwen hook stdin payload (Claude-compatible snake_case wire fields). */\ninterface QwenWireInput {\n session_id?: string;\n transcript_path?: string;\n cwd?: string;\n hook_event_name?: string;\n\n // tool events\n tool_name?: string;\n tool_input?: Record<string, unknown>;\n /** PostToolUse result payload (string or structured). */\n tool_response?: unknown;\n\n // PermissionRequest — suggested permission entries the dialog would offer.\n permission_suggestions?: unknown[];\n\n // PostToolUseFailure (Qwen documents tool_use_id/error/is_interrupt; there is\n // no duration_ms on this host's payload).\n tool_use_id?: string;\n error?: string;\n is_interrupt?: boolean;\n\n // SubagentStart / SubagentStop — treat both as optional everywhere (the\n // Claude-family quirk: agent_type is not reliably populated on stop).\n agent_id?: string;\n agent_type?: string;\n // SubagentStop — the subagent's OWN transcript + its final message.\n agent_transcript_path?: string;\n last_assistant_message?: string;\n\n // SessionStart\n source?: string;\n // SessionEnd\n reason?: string;\n // UserPromptSubmit\n prompt?: string;\n // PreCompact\n trigger?: string;\n // Stop\n stop_hook_active?: boolean;\n // Notification\n message?: string;\n\n /** Injected by the entrypoint so the runtime knows which connector to dispatch. */\n connector?: unknown;\n}\n\nexport class QwenCodeAdapter extends BaseAdapter implements Adapter {\n readonly id: PlatformId = HOST;\n readonly name = \"Qwen CLI\";\n readonly paradigm: HookParadigm = \"json-stdio\";\n\n readonly capabilities: PlatformCapabilities = {\n // Memory surface: AGENTS.md-first managed block (project <projectDir>/AGENTS.md\n // via the base default — Qwen reads repo AGENTS.md natively alongside QWEN.md,\n // so no QWEN.md duplicate; user scope → ~/.qwen/QWEN.md below, the only\n // documented user-scope memory file).\n supportsMemory: true,\n preToolUse: true,\n postToolUse: true,\n preCompact: true,\n sessionStart: true,\n sessionEnd: true,\n userPromptSubmit: true,\n stop: true,\n notification: true,\n // E1 events — all four are Qwen-native (its 16-event surface is strictly\n // wider than the canonical union).\n permissionRequest: true,\n postToolUseFailure: true,\n subagentStart: true,\n subagentStop: true,\n // Qwen's PreToolUse can rewrite input (updatedInput). It CANNOT rewrite\n // already-emitted tool output — `updatedMCPToolOutput` does not exist in\n // qwen 0.17.1, so canModifyOutput is false (like the Claude-family hosts).\n canModifyArgs: true,\n canModifyOutput: false,\n canInjectSessionContext: true,\n transports: [\"stdio\", \"sse\", \"http\"],\n // Content surfaces: Qwen ships native slash commands (TOML), subagents\n // (md+frontmatter), and skills (SKILL.md under .qwen/skills/<name>/).\n // Confirmed dir: .qwen/skills/ (project), ~/.qwen/skills/ (user scope).\n // Ground truth: kilo-pi-ground-truth.md § \"Already-known skills gaps\".\n supportsCommands: true,\n supportsSkills: true,\n supportsSubagents: true,\n };\n\n // ── Detection ────────────────────────────────────────────────────────────\n\n detectInstalled(projectDir: string): DetectedPlatform {\n const userDir = join(homedir(), \".qwen\");\n const userSettings = join(userDir, \"settings.json\");\n const projectDirQwen = join(projectDir, \".qwen\");\n const projectSettings = join(projectDirQwen, \"settings.json\");\n const userInstalled = existsSync(userDir) || existsSync(userSettings);\n const projInstalled = existsSync(projectDirQwen) || existsSync(projectSettings);\n const installed = userInstalled || projInstalled;\n // Report the scope/path that actually matched, so a project-only install\n // isn't misreported as a (non-existent) user install.\n const scope = projInstalled && !userInstalled ? \"project\" : \"user\";\n const configPath = scope === \"project\" ? projectSettings : userSettings;\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 Qwen CLI config at ${projectSettings}`\n : `found Qwen CLI config under ${userDir}`\n : `no Qwen CLI config at ${userDir}`,\n confidence: installed ? \"high\" : \"low\",\n };\n }\n\n // ── Memory surface: ~/.qwen/QWEN.md at user scope ────────────────────────\n // Project scope stays on the AGENTS.md base default (Qwen reads the repo\n // AGENTS.md natively in ADDITION to QWEN.md — one canonical copy, never a\n // QWEN.md duplicate). User scope targets ~/.qwen/QWEN.md: Qwen has no\n // user-scope AGENTS.md, so the host's own global memory file is the only\n // file it actually reads there.\n protected override memoryTargets(ctx: InstallContext): MemoryTarget[] {\n if (this.memoryOverride(ctx)?.path || ctx.scope !== \"user\") {\n return super.memoryTargets(ctx);\n }\n return [\n {\n path: join(homedir(), \".qwen\", \"QWEN.md\"),\n reason: \"qwen-code global memory (~/.qwen/QWEN.md; no user-scope AGENTS.md exists)\",\n },\n ];\n }\n\n // ── Native paths ─────────────────────────────────────────────────────────\n\n getConfigDir(ctx: InstallContext): string {\n return ctx.scope === \"project\"\n ? join(ctx.projectDir, \".qwen\")\n : join(homedir(), \".qwen\");\n }\n\n /** MCP servers live in settings.json under `mcpServers`. */\n getServerConfigPath(ctx: InstallContext): string {\n return join(this.getConfigDir(ctx), \"settings.json\");\n }\n\n /** Hooks live in the SAME settings.json under the sibling `hooks` key. */\n getHookConfigPath(ctx: InstallContext): string {\n return join(this.getConfigDir(ctx), \"settings.json\");\n }\n\n // ── MCP server install / uninstall ───────────────────────────────────────\n\n installServer(ctx: InstallContext): ChangeRecord[] {\n const { connector } = ctx;\n const override = connector.platforms[HOST]?.server;\n if (!connector.server || override === false) {\n return [\n {\n platform: this.id,\n action: \"skip\",\n detail: connector.server\n ? \"server registration disabled for qwen-code\"\n : \"connector declares no MCP server\",\n },\n ];\n }\n\n // Shallow-merge any per-platform server override into the base ServerDef.\n const server: ServerDef =\n override && typeof override === \"object\"\n ? { ...connector.server, ...override }\n : connector.server;\n\n const serverPath = this.getServerConfigPath(ctx);\n const entry = this.renderServerEntry(ctx, server);\n\n return [\n this.upsertServerInJson(serverPath, MCP_ROOT_KEY, connector.id, entry, ctx.dryRun),\n ];\n }\n\n uninstallServer(ctx: InstallContext): ChangeRecord[] {\n const serverPath = this.getServerConfigPath(ctx);\n return [\n this.removeServerFromJson(serverPath, MCP_ROOT_KEY, ctx.connector.id, ctx.dryRun),\n ];\n }\n\n /**\n * Render a normalized ServerDef into Qwen's native mcpServers entry. As a\n * Gemini-CLI fork, the transport is encoded by WHICH KEY is present (NOT a\n * `type` field): command/args/env (stdio), url (sse), httpUrl (http).\n */\n private renderServerEntry(\n ctx: InstallContext,\n server: ServerDef,\n ): QwenStdioServer | QwenSseServer | QwenHttpServer {\n const transport: Transport = server.transport;\n\n if (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 const entry: QwenStdioServer = {\n type: \"stdio\",\n command: resolveEnvRefsDeep(command),\n args: args.map((a) => resolveEnvRefsDeep(a)),\n };\n const env = this.renderEnv(server.env);\n if (env) entry.env = env;\n if (server.cwd) entry.cwd = resolveEnvRefsDeep(server.cwd);\n return entry;\n }\n\n // SSE transport → `url` key.\n if (transport === \"sse\") {\n const entry: QwenSseServer = { url: resolveEnvRefsDeep(server.url ?? \"\") };\n const headers = this.renderEnv(server.headers);\n if (headers) entry.headers = headers;\n return entry;\n }\n\n // http (streamable-HTTP) and any other remote transport → `httpUrl` key.\n const entry: QwenHttpServer = { httpUrl: resolveEnvRefsDeep(server.url ?? \"\") };\n const headers = this.renderEnv(server.headers);\n if (headers) entry.headers = headers;\n return entry;\n }\n\n /**\n * Render env/header values. Qwen's settings loader does not interpret our\n * `${env:VAR}` dialect, so refs resolve to literals at install time — the safe\n * default shared with the Gemini / Codex adapters.\n */\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 // ── Hook install / uninstall ─────────────────────────────────────────────\n\n installHooks(ctx: InstallContext): ChangeRecord[] {\n const { connector } = ctx;\n if (connector.platforms[HOST]?.hooks === false) {\n return [{ platform: this.id, action: \"skip\", detail: \"hooks disabled for qwen-code\" }];\n }\n if (connector.hookEvents.length === 0) {\n return [{ platform: this.id, action: \"skip\", detail: \"connector declares no hooks\" }];\n }\n\n const settingsPath = this.getHookConfigPath(ctx);\n // MERGE into any existing settings (JSONC written as strict JSON) so the\n // user's own mcpServers / theme / other keys are preserved.\n const settings = this.readJson<QwenSettingsFile>(settingsPath) ?? {};\n const hooks = (settings.hooks ??= {});\n\n const changes: ChangeRecord[] = [];\n let mutated = false;\n\n for (const event of connector.hookEvents) {\n // Qwen's hook event names are Claude-identical (PascalCase) — register the\n // canonical event name directly. Write-all is AUDITED here: every canonical\n // event (incl. PermissionRequest / PostToolUseFailure / SubagentStart /\n // SubagentStop) exists natively on Qwen, whose 16-event surface is strictly\n // wider than the canonical union.\n const command = buildHomeBinHookCommand(ctx.homeBinPath, HOST, event, connector.id);\n const matcher = connector.hooks[event]?.matcher ?? \"\";\n const entry: QwenHookEntry = {\n matcher,\n hooks: [{ type: \"command\", command }],\n };\n\n const bucket = (hooks[event] ??= []);\n const existingIdx = bucket.findIndex((e) => this.entryHasOurCommand(e, ctx));\n\n if (existingIdx >= 0) {\n if (JSON.stringify(bucket[existingIdx]) === JSON.stringify(entry)) {\n changes.push({\n platform: this.id,\n action: \"skip\",\n path: settingsPath,\n detail: `hooks.${event} already registered`,\n });\n continue;\n }\n bucket[existingIdx] = entry;\n changes.push({\n platform: this.id,\n action: \"update\",\n path: settingsPath,\n detail: `hooks.${event}`,\n });\n } else {\n bucket.push(entry);\n changes.push({\n platform: this.id,\n action: \"create\",\n path: settingsPath,\n detail: `hooks.${event}`,\n });\n }\n mutated = true;\n }\n\n if (mutated) this.writeJson(settingsPath, settings, ctx.dryRun);\n return changes;\n }\n\n uninstallHooks(ctx: InstallContext): ChangeRecord[] {\n const settingsPath = this.getHookConfigPath(ctx);\n const settings = this.readJson<QwenSettingsFile>(settingsPath);\n const hooks = settings?.hooks;\n if (!settings || !hooks) {\n return [\n {\n platform: this.id,\n action: \"skip\",\n path: settingsPath,\n detail: \"no hooks section present\",\n },\n ];\n }\n\n const changes: ChangeRecord[] = [];\n let mutated = false;\n\n for (const event of Object.keys(hooks)) {\n const bucket = hooks[event];\n if (!Array.isArray(bucket)) continue;\n\n // Strip our hook command from each entry; drop entries left empty so we\n // never remove another connector's (or the user's own) hook commands. The\n // id token is anchored (isHomeBinHookCommand) so a shared-prefix connector\n // id is never affected.\n const next: QwenHookEntry[] = [];\n let removed = 0;\n for (const e of bucket) {\n const innerBefore = e.hooks?.length ?? 0;\n const inner = (e.hooks ?? []).filter((h) => !this.isOurCommand(h.command, ctx));\n removed += innerBefore - inner.length;\n if (inner.length > 0) next.push({ matcher: e.matcher ?? \"\", hooks: inner });\n }\n\n if (removed > 0) {\n if (next.length > 0) hooks[event] = next;\n else delete hooks[event];\n changes.push({\n platform: this.id,\n action: \"remove\",\n path: settingsPath,\n detail: `hooks.${event} (${removed})`,\n });\n mutated = true;\n }\n }\n\n if (mutated) this.writeJson(settingsPath, settings, ctx.dryRun);\n if (changes.length === 0) {\n changes.push({\n platform: this.id,\n action: \"skip\",\n path: settingsPath,\n detail: \"no matching hook entries\",\n });\n }\n return changes;\n }\n\n private entryHasOurCommand(entry: QwenHookEntry, ctx: InstallContext): boolean {\n return (entry.hooks ?? []).some((h) => this.isOurCommand(h.command, ctx));\n }\n\n /** True when a hook command references our home binary AND this connector id\n * (anchored so a shared-prefix id can't collide — see isHomeBinHookCommand). */\n private isOurCommand(command: string | undefined, ctx: InstallContext): boolean {\n return isHomeBinHookCommand(command, ctx.homeBinPath, ctx.connector.id);\n }\n\n // ── Content surfaces: commands / subagents ───────────────────────────────\n // CONTENT-ONLY: pure native-file writers under <qwenDir>/{commands,agents}. No\n // runtime dispatch, no home-bin pointer, no telemetry wrap. Each method is\n // idempotent (byte-identical → skip) via BaseAdapter.writeContentFile and\n // reversible via removeContentFile. Honors platforms[\"qwen-code\"] per-surface\n // false to skip. Qwen has NO Agent-Skills surface, so skills are left to the\n // BaseAdapter skip/warn default (supportsSkills stays false).\n\n private commandsDir(ctx: InstallContext): string {\n return join(this.getConfigDir(ctx), \"commands\");\n }\n private skillsDir(ctx: InstallContext): string {\n return join(this.getConfigDir(ctx), \"skills\");\n }\n private agentsDir(ctx: InstallContext): string {\n return join(this.getConfigDir(ctx), \"agents\");\n }\n\n /** Native command file path: <qwenDir>/commands/<name>.toml. */\n private commandPath(ctx: InstallContext, name: string): string {\n return join(this.commandsDir(ctx), `${name}.toml`);\n }\n /** Native skill dir: <qwenDir>/skills/<name>. */\n private skillDir(ctx: InstallContext, name: string): string {\n return join(this.skillsDir(ctx), name);\n }\n /** Native subagent file path: <qwenDir>/agents/<name>.md. */\n private subagentPath(ctx: InstallContext, name: string): string {\n return join(this.agentsDir(ctx), `${name}.md`);\n }\n\n // ── Commands ──────────────────────────────────────────────────────────────\n\n override installCommands(ctx: InstallContext): ChangeRecord[] {\n const { connector } = ctx;\n if (connector.platforms[HOST]?.commands === false) {\n return [{ platform: this.id, action: \"skip\", detail: \"commands disabled for qwen-code\" }];\n }\n if (connector.commands.length === 0) {\n return [{ platform: this.id, action: \"skip\", detail: \"connector declares no commands\" }];\n }\n return connector.commands.map((cmd) =>\n this.writeContentFile(\n this.commandPath(ctx, cmd.name),\n this.renderCommand(cmd),\n ctx.dryRun,\n ),\n );\n }\n\n override uninstallCommands(ctx: InstallContext): ChangeRecord[] {\n const { connector } = ctx;\n if (connector.commands.length === 0) {\n return [{ platform: this.id, action: \"skip\", detail: \"connector declares no commands\" }];\n }\n return connector.commands.map((cmd) =>\n this.removeContentFile(this.commandPath(ctx, cmd.name), ctx.dryRun),\n );\n }\n\n /** Render a command to Qwen's native TOML (description, prompt). */\n private renderCommand(cmd: CommandDef): string {\n const obj: Record<string, unknown> = {};\n if (cmd.description !== undefined) obj.description = cmd.description;\n obj.prompt = cmd.prompt;\n return writeTomlString(obj);\n }\n\n // ── Skills ────────────────────────────────────────────────────────────────\n // Qwen reads SKILL.md from <qwenDir>/skills/<name>/SKILL.md.\n // Project dir: <projectDir>/.qwen/skills/<name>/SKILL.md\n // User dir: ~/.qwen/skills/<name>/SKILL.md\n // Confirmed: kilo-pi-ground-truth.md § \"Already-known skills gaps\" (.qwen/skills).\n\n override installSkills(ctx: InstallContext): ChangeRecord[] {\n const { connector } = ctx;\n if (connector.platforms[HOST]?.skills === false) {\n return [{ platform: this.id, action: \"skip\", detail: \"skills disabled for qwen-code\" }];\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 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 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;\n changes.push(this.removeContentFile(target, ctx.dryRun));\n }\n changes.push(this.removeDirIfEmpty(dir, ctx.dryRun));\n }\n return changes;\n }\n\n private renderSkill(skill: SkillDef): string {\n return renderSkillMd(skill);\n }\n\n // ── Subagents ──────────────────────────────────────────────────────────────\n\n override installSubagents(ctx: InstallContext): ChangeRecord[] {\n const { connector } = ctx;\n if (connector.platforms[HOST]?.subagents === false) {\n return [{ platform: this.id, action: \"skip\", detail: \"subagents disabled for qwen-code\" }];\n }\n if (connector.subagents.length === 0) {\n return [{ platform: this.id, action: \"skip\", detail: \"connector declares no subagents\" }];\n }\n return connector.subagents.map((agent) =>\n this.writeContentFile(\n this.subagentPath(ctx, agent.name),\n this.renderSubagent(agent),\n ctx.dryRun,\n ),\n );\n }\n\n override uninstallSubagents(ctx: InstallContext): ChangeRecord[] {\n const { connector } = ctx;\n if (connector.subagents.length === 0) {\n return [{ platform: this.id, action: \"skip\", detail: \"connector declares no subagents\" }];\n }\n return connector.subagents.map((agent) =>\n this.removeContentFile(this.subagentPath(ctx, agent.name), ctx.dryRun),\n );\n }\n\n /** Render a subagent to md+frontmatter (name, description, tools, model) + prompt body. */\n private renderSubagent(agent: SubagentDef): string {\n const frontmatter: Record<string, unknown> = {\n name: agent.name,\n description: agent.description,\n };\n const allow = agent.tools?.allow;\n if (allow && allow.length > 0) frontmatter.tools = allow.join(\", \");\n if (agent.model !== undefined) frontmatter.model = agent.model;\n if (agent.extra) Object.assign(frontmatter, agent.extra);\n return this.renderFrontmatterMd(frontmatter, agent.prompt);\n }\n\n // ── Diagnostics ──────────────────────────────────────────────────────────\n\n override getHealthChecks(ctx: InstallContext): readonly HealthCheck[] {\n const settingsPath = this.getHookConfigPath(ctx);\n const connectorId = ctx.connector.id;\n const homeBin = ctx.homeBinPath;\n const hookEvents = ctx.connector.hookEvents;\n const checks: HealthCheck[] = [\n {\n name: `${this.name}: settings.json present`,\n check: () =>\n existsSync(settingsPath)\n ? { status: \"OK\", detail: settingsPath }\n : { status: \"FAIL\", detail: `not found: ${settingsPath}` },\n },\n {\n name: `${this.name}: hook command registered`,\n check: () => {\n if (hookEvents.length === 0) {\n return { status: \"OK\", detail: \"no hooks declared\" };\n }\n const settings = this.readJson<QwenSettingsFile>(settingsPath);\n if (!settings) return { status: \"FAIL\", detail: `cannot read ${settingsPath}` };\n const hooks = settings.hooks ?? {};\n const registered = Object.values(hooks).some((entries) =>\n (entries ?? []).some((e) =>\n (e.hooks ?? []).some((h) =>\n isHomeBinHookCommand(h.command, homeBin, connectorId),\n ),\n ),\n );\n return registered\n ? { status: \"OK\", detail: \"hook command present\" }\n : { status: \"FAIL\", detail: `no hook for ${connectorId} in ${settingsPath}` };\n },\n },\n ];\n\n // Content-surface checks: assert presence of all three content surfaces\n // (commands, skills, subagents) this connector declares.\n for (const cmd of ctx.connector.commands) {\n const p = this.commandPath(ctx, cmd.name);\n checks.push({\n name: `${this.name}: command ${cmd.name} present`,\n check: () =>\n existsSync(p) ? { status: \"OK\", detail: p } : { status: \"FAIL\", detail: `not found: ${p}` },\n });\n }\n for (const skill of ctx.connector.skills) {\n const p = join(this.skillDir(ctx, skill.name), \"SKILL.md\");\n checks.push({\n name: `${this.name}: skill ${skill.name} present`,\n check: () =>\n existsSync(p) ? { status: \"OK\", detail: p } : { status: \"FAIL\", detail: `not found: ${p}` },\n });\n }\n for (const agent of ctx.connector.subagents) {\n const p = this.subagentPath(ctx, agent.name);\n checks.push({\n name: `${this.name}: subagent ${agent.name} present`,\n check: () =>\n existsSync(p) ? { status: \"OK\", detail: p } : { status: \"FAIL\", detail: `not found: ${p}` },\n });\n }\n return checks;\n }\n\n // ── Runtime: parse Qwen stdin JSON → normalized event ────────────────────\n\n parseEvent(event: HookEventName, raw: unknown): NormalizedEvent {\n const input = (raw ?? {}) as QwenWireInput;\n const connectorId = typeof input.connector === \"string\" ? input.connector : \"\";\n const sessionId = extractSessionId(input);\n const projectDir = typeof input.cwd === \"string\" ? input.cwd : undefined;\n\n const base = {\n hostPlatform: HOST,\n connectorId,\n sessionId,\n raw,\n ...(projectDir !== undefined ? { projectDir } : {}),\n } as const;\n\n switch (event) {\n case \"PreToolUse\": {\n const ev: PreToolUseEvent = {\n ...base,\n toolName: input.tool_name ?? \"\",\n toolInput: input.tool_input ?? {},\n };\n return ev;\n }\n case \"PostToolUse\": {\n const ev: PostToolUseEvent = {\n ...base,\n toolName: input.tool_name ?? \"\",\n toolInput: input.tool_input ?? {},\n ...(toolResponseToString(input.tool_response) !== undefined\n ? { toolOutput: toolResponseToString(input.tool_response) }\n : {}),\n };\n return ev;\n }\n case \"SessionStart\": {\n const ev: SessionStartEvent = {\n ...base,\n source: normalizeSessionSource(input.source),\n };\n return ev;\n }\n case \"SessionEnd\": {\n const ev: SessionEndEvent = {\n ...base,\n ...(typeof input.reason === \"string\" ? { reason: input.reason } : {}),\n };\n return ev;\n }\n case \"UserPromptSubmit\": {\n const ev: UserPromptSubmitEvent = {\n ...base,\n prompt: typeof input.prompt === \"string\" ? input.prompt : \"\",\n };\n return ev;\n }\n case \"PreCompact\": {\n const ev: PreCompactEvent = {\n ...base,\n ...(input.trigger === \"auto\" || input.trigger === \"manual\"\n ? { trigger: input.trigger }\n : {}),\n };\n return ev;\n }\n case \"Stop\": {\n const ev: StopEvent = {\n ...base,\n ...(typeof input.stop_hook_active === \"boolean\"\n ? { stopHookActive: input.stop_hook_active }\n : {}),\n };\n return ev;\n }\n case \"Notification\": {\n const ev: NotificationEvent = {\n ...base,\n message: typeof input.message === \"string\" ? input.message : \"\",\n };\n return ev;\n }\n case \"PermissionRequest\": {\n const ev: PermissionRequestEvent = {\n ...base,\n toolName: input.tool_name ?? \"\",\n toolInput: input.tool_input ?? {},\n ...(Array.isArray(input.permission_suggestions)\n ? { permissionSuggestions: input.permission_suggestions }\n : {}),\n };\n return ev;\n }\n case \"PostToolUseFailure\": {\n // durationMs stays unset — Qwen's failure payload has no duration_ms.\n const ev: PostToolUseFailureEvent = {\n ...base,\n toolName: input.tool_name ?? \"\",\n toolInput: input.tool_input ?? {},\n error: typeof input.error === \"string\" ? input.error : \"\",\n ...(typeof input.tool_use_id === \"string\"\n ? { toolUseId: input.tool_use_id }\n : {}),\n ...(typeof input.is_interrupt === \"boolean\"\n ? { isInterrupt: input.is_interrupt }\n : {}),\n };\n return ev;\n }\n case \"SubagentStart\": {\n const ev: SubagentStartEvent = {\n ...base,\n ...(typeof input.agent_id === \"string\" ? { agentId: input.agent_id } : {}),\n ...(typeof input.agent_type === \"string\"\n ? { agentType: input.agent_type }\n : {}),\n };\n return ev;\n }\n case \"SubagentStop\": {\n // agent_id/agent_type stay optional — the Claude-family SDK does not\n // reliably populate agent_type on stop.\n const ev: SubagentStopEvent = {\n ...base,\n ...(typeof input.agent_id === \"string\" ? { agentId: input.agent_id } : {}),\n ...(typeof input.agent_type === \"string\"\n ? { agentType: input.agent_type }\n : {}),\n ...(typeof input.agent_transcript_path === \"string\"\n ? { agentTranscriptPath: input.agent_transcript_path }\n : {}),\n ...(typeof input.last_assistant_message === \"string\"\n ? { lastAssistantMessage: input.last_assistant_message }\n : {}),\n ...(typeof input.stop_hook_active === \"boolean\"\n ? { stopHookActive: input.stop_hook_active }\n : {}),\n };\n return ev;\n }\n default: {\n // Exhaustive guard — every HookEventName is handled above.\n const _never: never = event;\n throw new Error(`unsupported qwen-code hook event: ${String(_never)}`);\n }\n }\n }\n\n // ── Runtime: normalized response → Qwen native hook reply ────────────────\n\n formatReply(event: HookEventName, response: HookResponse): HookReply {\n const hookEventName = event;\n const decision = response.decision ?? \"allow\";\n\n // PermissionRequest uses Qwen's nested decision{behavior} envelope (Claude-\n // identical) and is the ONE event where an EXPLICIT \"allow\" is an ACTIVE\n // grant that suppresses the permission dialog:\n // allow → decision{behavior:\"allow\"} (+updatedInput when set —\n // Qwen honors input rewrite, canModifyArgs above);\n // modify → an allow grant carrying updatedInput;\n // deny → decision{behavior:\"deny\", message};\n // ask/context/void → NO decision output: fall through to the native\n // dialog (the dialog IS the ask).\n if (event === \"PermissionRequest\") {\n if (response.decision === \"deny\") {\n return this.stdout({\n hookSpecificOutput: {\n hookEventName,\n decision: {\n behavior: \"deny\",\n message: response.reason ?? \"Blocked by hook\",\n },\n },\n });\n }\n if (\n response.decision === \"allow\" ||\n (response.decision === \"modify\" && response.updatedInput)\n ) {\n return this.stdout({\n hookSpecificOutput: {\n hookEventName,\n decision: {\n behavior: \"allow\",\n ...(response.updatedInput\n ? { updatedInput: response.updatedInput }\n : {}),\n },\n },\n });\n }\n return { exitCode: 0 };\n }\n\n // PostToolUseFailure (feedback beside the error) and SubagentStart (context\n // injected into the SUBAGENT's conversation) are observe/context-only on\n // Qwen: \"context\" emits additionalContext, and a \"deny\" DEGRADES to the\n // same shape carrying the reason (the tool already failed / the spawn is\n // not blockable).\n if (event === \"PostToolUseFailure\" || event === \"SubagentStart\") {\n const context =\n decision === \"context\"\n ? response.additionalContext\n : decision === \"deny\"\n ? response.reason ?? response.additionalContext\n : undefined;\n if (context) {\n return this.stdout({\n hookSpecificOutput: { hookEventName, additionalContext: context },\n });\n }\n return { exitCode: 0 };\n }\n\n // SubagentStop deny = Stop semantics: Qwen documents the TOP-LEVEL\n // {\"decision\":\"block\",\"reason\"} shape (keeps the subagent running with\n // `reason` as its next instruction).\n if (decision === \"deny\" && event === \"SubagentStop\") {\n return this.stdout({\n decision: \"block\",\n reason: response.reason ?? \"Blocked by hook\",\n });\n }\n\n // deny → block the action with a reason (exit 0; JSON carries the decision).\n if (decision === \"deny\") {\n return this.stdout({\n hookSpecificOutput: {\n hookEventName,\n permissionDecision: \"deny\",\n permissionDecisionReason: response.reason ?? \"Blocked by hook\",\n },\n });\n }\n\n // ask → prompt the user to confirm.\n if (decision === \"ask\") {\n return this.stdout({\n hookSpecificOutput: {\n hookEventName,\n permissionDecision: \"ask\",\n permissionDecisionReason: response.reason ?? \"Confirmation required by hook\",\n },\n });\n }\n\n // modify → rewrite PreToolUse input only. Qwen 0.17.1 has no PostToolUse\n // output-rewrite (`updatedMCPToolOutput` does not exist), so a modify on any\n // other event falls through to allow.\n if (decision === \"modify\") {\n if (event === \"PreToolUse\" && response.updatedInput) {\n return this.stdout({\n hookSpecificOutput: { hookEventName, updatedInput: response.updatedInput },\n });\n }\n // Nothing applicable on this event; fall through to allow.\n }\n\n // context → inject soft guidance (also the SessionStart context path).\n if (decision === \"context\" && response.additionalContext) {\n return this.stdout({\n hookSpecificOutput: { hookEventName, additionalContext: response.additionalContext },\n });\n }\n\n // allow / void / unsupported-degradation → pass through with exit 0.\n return { exitCode: 0 };\n }\n\n private stdout(payload: unknown): HookReply {\n return { exitCode: 0, stdout: JSON.stringify(payload) };\n }\n}\n\n/**\n * Extract a stable session id from a Qwen wire payload. Unlike Claude (which\n * prefers the transcript UUID), Qwen Code surfaces `session_id` directly and\n * prioritizes it — matching context-mode's QwenCodeAdapter.extractSessionId.\n * Falls back to the transcript UUID, then \"\" (no ppid fabrication — the\n * normalized event uses \"\" when the host provides no id).\n */\nfunction extractSessionId(input: QwenWireInput): string {\n if (typeof input.session_id === \"string\" && input.session_id !== \"\") {\n return input.session_id;\n }\n if (typeof input.transcript_path === \"string\") {\n const m = input.transcript_path.match(/([a-f0-9-]{36})\\.jsonl$/);\n if (m && m[1]) return m[1];\n }\n return \"\";\n}\n\n/** Coerce a Qwen PostToolUse `tool_response` into a string for the normalized event. */\nfunction toolResponseToString(value: unknown): string | undefined {\n if (value == null) return undefined;\n if (typeof value === \"string\") return value;\n try {\n return JSON.stringify(value);\n } catch {\n return String(value);\n }\n}\n\nfunction normalizeSessionSource(source: string | undefined): SessionStartEvent[\"source\"] {\n switch (source) {\n case \"compact\":\n return \"compact\";\n case \"resume\":\n return \"resume\";\n case \"clear\":\n return \"clear\";\n default:\n return \"startup\";\n }\n}\n\nexport const adapter = new QwenCodeAdapter();\nexport default adapter;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;AAgDA,SAAS,kBAAkB;AAC3B,SAAS,eAAe;AACxB,SAAS,YAAY;AAyCrB,IAAM,OAAmB;AACzB,IAAM,eAAe;AAqFd,IAAM,kBAAN,cAA8B,YAA+B;AAAA,EACzD,KAAiB;AAAA,EACjB,OAAO;AAAA,EACP,WAAyB;AAAA,EAEzB,eAAqC;AAAA;AAAA;AAAA;AAAA;AAAA,IAK5C,gBAAgB;AAAA,IAChB,YAAY;AAAA,IACZ,aAAa;AAAA,IACb,YAAY;AAAA,IACZ,cAAc;AAAA,IACd,YAAY;AAAA,IACZ,kBAAkB;AAAA,IAClB,MAAM;AAAA,IACN,cAAc;AAAA;AAAA;AAAA,IAGd,mBAAmB;AAAA,IACnB,oBAAoB;AAAA,IACpB,eAAe;AAAA,IACf,cAAc;AAAA;AAAA;AAAA;AAAA,IAId,eAAe;AAAA,IACf,iBAAiB;AAAA,IACjB,yBAAyB;AAAA,IACzB,YAAY,CAAC,SAAS,OAAO,MAAM;AAAA;AAAA;AAAA;AAAA;AAAA,IAKnC,kBAAkB;AAAA,IAClB,gBAAgB;AAAA,IAChB,mBAAmB;AAAA,EACrB;AAAA;AAAA,EAIA,gBAAgB,YAAsC;AACpD,UAAM,UAAU,KAAK,QAAQ,GAAG,OAAO;AACvC,UAAM,eAAe,KAAK,SAAS,eAAe;AAClD,UAAM,iBAAiB,KAAK,YAAY,OAAO;AAC/C,UAAM,kBAAkB,KAAK,gBAAgB,eAAe;AAC5D,UAAM,gBAAgB,WAAW,OAAO,KAAK,WAAW,YAAY;AACpE,UAAM,gBAAgB,WAAW,cAAc,KAAK,WAAW,eAAe;AAC9E,UAAM,YAAY,iBAAiB;AAGnC,UAAM,QAAQ,iBAAiB,CAAC,gBAAgB,YAAY;AAC5D,UAAM,aAAa,UAAU,YAAY,kBAAkB;AAC3D,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,eAAe,KACnD,+BAA+B,OAAO,KACxC,yBAAyB,OAAO;AAAA,MACpC,YAAY,YAAY,SAAS;AAAA,IACnC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQmB,cAAc,KAAqC;AACpE,QAAI,KAAK,eAAe,GAAG,GAAG,QAAQ,IAAI,UAAU,QAAQ;AAC1D,aAAO,MAAM,cAAc,GAAG;AAAA,IAChC;AACA,WAAO;AAAA,MACL;AAAA,QACE,MAAM,KAAK,QAAQ,GAAG,SAAS,SAAS;AAAA,QACxC,QAAQ;AAAA,MACV;AAAA,IACF;AAAA,EACF;AAAA;AAAA,EAIA,aAAa,KAA6B;AACxC,WAAO,IAAI,UAAU,YACjB,KAAK,IAAI,YAAY,OAAO,IAC5B,KAAK,QAAQ,GAAG,OAAO;AAAA,EAC7B;AAAA;AAAA,EAGA,oBAAoB,KAA6B;AAC/C,WAAO,KAAK,KAAK,aAAa,GAAG,GAAG,eAAe;AAAA,EACrD;AAAA;AAAA,EAGA,kBAAkB,KAA6B;AAC7C,WAAO,KAAK,KAAK,aAAa,GAAG,GAAG,eAAe;AAAA,EACrD;AAAA;AAAA,EAIA,cAAc,KAAqC;AACjD,UAAM,EAAE,UAAU,IAAI;AACtB,UAAM,WAAW,UAAU,UAAU,IAAI,GAAG;AAC5C,QAAI,CAAC,UAAU,UAAU,aAAa,OAAO;AAC3C,aAAO;AAAA,QACL;AAAA,UACE,UAAU,KAAK;AAAA,UACf,QAAQ;AAAA,UACR,QAAQ,UAAU,SACd,+CACA;AAAA,QACN;AAAA,MACF;AAAA,IACF;AAGA,UAAM,SACJ,YAAY,OAAO,aAAa,WAC5B,EAAE,GAAG,UAAU,QAAQ,GAAG,SAAS,IACnC,UAAU;AAEhB,UAAM,aAAa,KAAK,oBAAoB,GAAG;AAC/C,UAAM,QAAQ,KAAK,kBAAkB,KAAK,MAAM;AAEhD,WAAO;AAAA,MACL,KAAK,mBAAmB,YAAY,cAAc,UAAU,IAAI,OAAO,IAAI,MAAM;AAAA,IACnF;AAAA,EACF;AAAA,EAEA,gBAAgB,KAAqC;AACnD,UAAM,aAAa,KAAK,oBAAoB,GAAG;AAC/C,WAAO;AAAA,MACL,KAAK,qBAAqB,YAAY,cAAc,IAAI,UAAU,IAAI,IAAI,MAAM;AAAA,IAClF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOQ,kBACN,KACA,QACkD;AAClD,UAAM,YAAuB,OAAO;AAEpC,QAAI,cAAc,SAAS;AACzB,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;AAEA,YAAMA,SAAyB;AAAA,QAC7B,MAAM;AAAA,QACN,SAAS,mBAAmB,OAAO;AAAA,QACnC,MAAM,KAAK,IAAI,CAAC,MAAM,mBAAmB,CAAC,CAAC;AAAA,MAC7C;AACA,YAAM,MAAM,KAAK,UAAU,OAAO,GAAG;AACrC,UAAI,IAAK,CAAAA,OAAM,MAAM;AACrB,UAAI,OAAO,IAAK,CAAAA,OAAM,MAAM,mBAAmB,OAAO,GAAG;AACzD,aAAOA;AAAA,IACT;AAGA,QAAI,cAAc,OAAO;AACvB,YAAMA,SAAuB,EAAE,KAAK,mBAAmB,OAAO,OAAO,EAAE,EAAE;AACzE,YAAMC,WAAU,KAAK,UAAU,OAAO,OAAO;AAC7C,UAAIA,SAAS,CAAAD,OAAM,UAAUC;AAC7B,aAAOD;AAAA,IACT;AAGA,UAAM,QAAwB,EAAE,SAAS,mBAAmB,OAAO,OAAO,EAAE,EAAE;AAC9E,UAAM,UAAU,KAAK,UAAU,OAAO,OAAO;AAC7C,QAAI,QAAS,OAAM,UAAU;AAC7B,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOQ,UACN,KACoC;AACpC,QAAI,CAAC,OAAO,OAAO,KAAK,GAAG,EAAE,WAAW,EAAG,QAAO;AAClD,WAAO,mBAAmB,EAAE,GAAG,IAAI,CAAC;AAAA,EACtC;AAAA;AAAA,EAIA,aAAa,KAAqC;AAChD,UAAM,EAAE,UAAU,IAAI;AACtB,QAAI,UAAU,UAAU,IAAI,GAAG,UAAU,OAAO;AAC9C,aAAO,CAAC,EAAE,UAAU,KAAK,IAAI,QAAQ,QAAQ,QAAQ,+BAA+B,CAAC;AAAA,IACvF;AACA,QAAI,UAAU,WAAW,WAAW,GAAG;AACrC,aAAO,CAAC,EAAE,UAAU,KAAK,IAAI,QAAQ,QAAQ,QAAQ,8BAA8B,CAAC;AAAA,IACtF;AAEA,UAAM,eAAe,KAAK,kBAAkB,GAAG;AAG/C,UAAM,WAAW,KAAK,SAA2B,YAAY,KAAK,CAAC;AACnE,UAAM,QAAS,SAAS,UAAU,CAAC;AAEnC,UAAM,UAA0B,CAAC;AACjC,QAAI,UAAU;AAEd,eAAW,SAAS,UAAU,YAAY;AAMxC,YAAM,UAAU,wBAAwB,IAAI,aAAa,MAAM,OAAO,UAAU,EAAE;AAClF,YAAM,UAAU,UAAU,MAAM,KAAK,GAAG,WAAW;AACnD,YAAM,QAAuB;AAAA,QAC3B;AAAA,QACA,OAAO,CAAC,EAAE,MAAM,WAAW,QAAQ,CAAC;AAAA,MACtC;AAEA,YAAM,SAAU,MAAM,KAAK,MAAM,CAAC;AAClC,YAAM,cAAc,OAAO,UAAU,CAAC,MAAM,KAAK,mBAAmB,GAAG,GAAG,CAAC;AAE3E,UAAI,eAAe,GAAG;AACpB,YAAI,KAAK,UAAU,OAAO,WAAW,CAAC,MAAM,KAAK,UAAU,KAAK,GAAG;AACjE,kBAAQ,KAAK;AAAA,YACX,UAAU,KAAK;AAAA,YACf,QAAQ;AAAA,YACR,MAAM;AAAA,YACN,QAAQ,SAAS,KAAK;AAAA,UACxB,CAAC;AACD;AAAA,QACF;AACA,eAAO,WAAW,IAAI;AACtB,gBAAQ,KAAK;AAAA,UACX,UAAU,KAAK;AAAA,UACf,QAAQ;AAAA,UACR,MAAM;AAAA,UACN,QAAQ,SAAS,KAAK;AAAA,QACxB,CAAC;AAAA,MACH,OAAO;AACL,eAAO,KAAK,KAAK;AACjB,gBAAQ,KAAK;AAAA,UACX,UAAU,KAAK;AAAA,UACf,QAAQ;AAAA,UACR,MAAM;AAAA,UACN,QAAQ,SAAS,KAAK;AAAA,QACxB,CAAC;AAAA,MACH;AACA,gBAAU;AAAA,IACZ;AAEA,QAAI,QAAS,MAAK,UAAU,cAAc,UAAU,IAAI,MAAM;AAC9D,WAAO;AAAA,EACT;AAAA,EAEA,eAAe,KAAqC;AAClD,UAAM,eAAe,KAAK,kBAAkB,GAAG;AAC/C,UAAM,WAAW,KAAK,SAA2B,YAAY;AAC7D,UAAM,QAAQ,UAAU;AACxB,QAAI,CAAC,YAAY,CAAC,OAAO;AACvB,aAAO;AAAA,QACL;AAAA,UACE,UAAU,KAAK;AAAA,UACf,QAAQ;AAAA,UACR,MAAM;AAAA,UACN,QAAQ;AAAA,QACV;AAAA,MACF;AAAA,IACF;AAEA,UAAM,UAA0B,CAAC;AACjC,QAAI,UAAU;AAEd,eAAW,SAAS,OAAO,KAAK,KAAK,GAAG;AACtC,YAAM,SAAS,MAAM,KAAK;AAC1B,UAAI,CAAC,MAAM,QAAQ,MAAM,EAAG;AAM5B,YAAM,OAAwB,CAAC;AAC/B,UAAI,UAAU;AACd,iBAAW,KAAK,QAAQ;AACtB,cAAM,cAAc,EAAE,OAAO,UAAU;AACvC,cAAM,SAAS,EAAE,SAAS,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,KAAK,aAAa,EAAE,SAAS,GAAG,CAAC;AAC9E,mBAAW,cAAc,MAAM;AAC/B,YAAI,MAAM,SAAS,EAAG,MAAK,KAAK,EAAE,SAAS,EAAE,WAAW,IAAI,OAAO,MAAM,CAAC;AAAA,MAC5E;AAEA,UAAI,UAAU,GAAG;AACf,YAAI,KAAK,SAAS,EAAG,OAAM,KAAK,IAAI;AAAA,YAC/B,QAAO,MAAM,KAAK;AACvB,gBAAQ,KAAK;AAAA,UACX,UAAU,KAAK;AAAA,UACf,QAAQ;AAAA,UACR,MAAM;AAAA,UACN,QAAQ,SAAS,KAAK,KAAK,OAAO;AAAA,QACpC,CAAC;AACD,kBAAU;AAAA,MACZ;AAAA,IACF;AAEA,QAAI,QAAS,MAAK,UAAU,cAAc,UAAU,IAAI,MAAM;AAC9D,QAAI,QAAQ,WAAW,GAAG;AACxB,cAAQ,KAAK;AAAA,QACX,UAAU,KAAK;AAAA,QACf,QAAQ;AAAA,QACR,MAAM;AAAA,QACN,QAAQ;AAAA,MACV,CAAC;AAAA,IACH;AACA,WAAO;AAAA,EACT;AAAA,EAEQ,mBAAmB,OAAsB,KAA8B;AAC7E,YAAQ,MAAM,SAAS,CAAC,GAAG,KAAK,CAAC,MAAM,KAAK,aAAa,EAAE,SAAS,GAAG,CAAC;AAAA,EAC1E;AAAA;AAAA;AAAA,EAIQ,aAAa,SAA6B,KAA8B;AAC9E,WAAO,qBAAqB,SAAS,IAAI,aAAa,IAAI,UAAU,EAAE;AAAA,EACxE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUQ,YAAY,KAA6B;AAC/C,WAAO,KAAK,KAAK,aAAa,GAAG,GAAG,UAAU;AAAA,EAChD;AAAA,EACQ,UAAU,KAA6B;AAC7C,WAAO,KAAK,KAAK,aAAa,GAAG,GAAG,QAAQ;AAAA,EAC9C;AAAA,EACQ,UAAU,KAA6B;AAC7C,WAAO,KAAK,KAAK,aAAa,GAAG,GAAG,QAAQ;AAAA,EAC9C;AAAA;AAAA,EAGQ,YAAY,KAAqB,MAAsB;AAC7D,WAAO,KAAK,KAAK,YAAY,GAAG,GAAG,GAAG,IAAI,OAAO;AAAA,EACnD;AAAA;AAAA,EAEQ,SAAS,KAAqB,MAAsB;AAC1D,WAAO,KAAK,KAAK,UAAU,GAAG,GAAG,IAAI;AAAA,EACvC;AAAA;AAAA,EAEQ,aAAa,KAAqB,MAAsB;AAC9D,WAAO,KAAK,KAAK,UAAU,GAAG,GAAG,GAAG,IAAI,KAAK;AAAA,EAC/C;AAAA;AAAA,EAIS,gBAAgB,KAAqC;AAC5D,UAAM,EAAE,UAAU,IAAI;AACtB,QAAI,UAAU,UAAU,IAAI,GAAG,aAAa,OAAO;AACjD,aAAO,CAAC,EAAE,UAAU,KAAK,IAAI,QAAQ,QAAQ,QAAQ,kCAAkC,CAAC;AAAA,IAC1F;AACA,QAAI,UAAU,SAAS,WAAW,GAAG;AACnC,aAAO,CAAC,EAAE,UAAU,KAAK,IAAI,QAAQ,QAAQ,QAAQ,iCAAiC,CAAC;AAAA,IACzF;AACA,WAAO,UAAU,SAAS;AAAA,MAAI,CAAC,QAC7B,KAAK;AAAA,QACH,KAAK,YAAY,KAAK,IAAI,IAAI;AAAA,QAC9B,KAAK,cAAc,GAAG;AAAA,QACtB,IAAI;AAAA,MACN;AAAA,IACF;AAAA,EACF;AAAA,EAES,kBAAkB,KAAqC;AAC9D,UAAM,EAAE,UAAU,IAAI;AACtB,QAAI,UAAU,SAAS,WAAW,GAAG;AACnC,aAAO,CAAC,EAAE,UAAU,KAAK,IAAI,QAAQ,QAAQ,QAAQ,iCAAiC,CAAC;AAAA,IACzF;AACA,WAAO,UAAU,SAAS;AAAA,MAAI,CAAC,QAC7B,KAAK,kBAAkB,KAAK,YAAY,KAAK,IAAI,IAAI,GAAG,IAAI,MAAM;AAAA,IACpE;AAAA,EACF;AAAA;AAAA,EAGQ,cAAc,KAAyB;AAC7C,UAAM,MAA+B,CAAC;AACtC,QAAI,IAAI,gBAAgB,OAAW,KAAI,cAAc,IAAI;AACzD,QAAI,SAAS,IAAI;AACjB,WAAO,gBAAgB,GAAG;AAAA,EAC5B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQS,cAAc,KAAqC;AAC1D,UAAM,EAAE,UAAU,IAAI;AACtB,QAAI,UAAU,UAAU,IAAI,GAAG,WAAW,OAAO;AAC/C,aAAO,CAAC,EAAE,UAAU,KAAK,IAAI,QAAQ,QAAQ,QAAQ,gCAAgC,CAAC;AAAA,IACxF;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;AACA,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;AACzC,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;AACA,cAAQ,KAAK,KAAK,iBAAiB,KAAK,IAAI,MAAM,CAAC;AAAA,IACrD;AACA,WAAO;AAAA,EACT;AAAA,EAEQ,YAAY,OAAyB;AAC3C,WAAO,cAAc,KAAK;AAAA,EAC5B;AAAA;AAAA,EAIS,iBAAiB,KAAqC;AAC7D,UAAM,EAAE,UAAU,IAAI;AACtB,QAAI,UAAU,UAAU,IAAI,GAAG,cAAc,OAAO;AAClD,aAAO,CAAC,EAAE,UAAU,KAAK,IAAI,QAAQ,QAAQ,QAAQ,mCAAmC,CAAC;AAAA,IAC3F;AACA,QAAI,UAAU,UAAU,WAAW,GAAG;AACpC,aAAO,CAAC,EAAE,UAAU,KAAK,IAAI,QAAQ,QAAQ,QAAQ,kCAAkC,CAAC;AAAA,IAC1F;AACA,WAAO,UAAU,UAAU;AAAA,MAAI,CAAC,UAC9B,KAAK;AAAA,QACH,KAAK,aAAa,KAAK,MAAM,IAAI;AAAA,QACjC,KAAK,eAAe,KAAK;AAAA,QACzB,IAAI;AAAA,MACN;AAAA,IACF;AAAA,EACF;AAAA,EAES,mBAAmB,KAAqC;AAC/D,UAAM,EAAE,UAAU,IAAI;AACtB,QAAI,UAAU,UAAU,WAAW,GAAG;AACpC,aAAO,CAAC,EAAE,UAAU,KAAK,IAAI,QAAQ,QAAQ,QAAQ,kCAAkC,CAAC;AAAA,IAC1F;AACA,WAAO,UAAU,UAAU;AAAA,MAAI,CAAC,UAC9B,KAAK,kBAAkB,KAAK,aAAa,KAAK,MAAM,IAAI,GAAG,IAAI,MAAM;AAAA,IACvE;AAAA,EACF;AAAA;AAAA,EAGQ,eAAe,OAA4B;AACjD,UAAM,cAAuC;AAAA,MAC3C,MAAM,MAAM;AAAA,MACZ,aAAa,MAAM;AAAA,IACrB;AACA,UAAM,QAAQ,MAAM,OAAO;AAC3B,QAAI,SAAS,MAAM,SAAS,EAAG,aAAY,QAAQ,MAAM,KAAK,IAAI;AAClE,QAAI,MAAM,UAAU,OAAW,aAAY,QAAQ,MAAM;AACzD,QAAI,MAAM,MAAO,QAAO,OAAO,aAAa,MAAM,KAAK;AACvD,WAAO,KAAK,oBAAoB,aAAa,MAAM,MAAM;AAAA,EAC3D;AAAA;AAAA,EAIS,gBAAgB,KAA6C;AACpE,UAAM,eAAe,KAAK,kBAAkB,GAAG;AAC/C,UAAM,cAAc,IAAI,UAAU;AAClC,UAAM,UAAU,IAAI;AACpB,UAAM,aAAa,IAAI,UAAU;AACjC,UAAM,SAAwB;AAAA,MAC5B;AAAA,QACE,MAAM,GAAG,KAAK,IAAI;AAAA,QAClB,OAAO,MACL,WAAW,YAAY,IACnB,EAAE,QAAQ,MAAM,QAAQ,aAAa,IACrC,EAAE,QAAQ,QAAQ,QAAQ,cAAc,YAAY,GAAG;AAAA,MAC/D;AAAA,MACA;AAAA,QACE,MAAM,GAAG,KAAK,IAAI;AAAA,QAClB,OAAO,MAAM;AACX,cAAI,WAAW,WAAW,GAAG;AAC3B,mBAAO,EAAE,QAAQ,MAAM,QAAQ,oBAAoB;AAAA,UACrD;AACA,gBAAM,WAAW,KAAK,SAA2B,YAAY;AAC7D,cAAI,CAAC,SAAU,QAAO,EAAE,QAAQ,QAAQ,QAAQ,eAAe,YAAY,GAAG;AAC9E,gBAAM,QAAQ,SAAS,SAAS,CAAC;AACjC,gBAAM,aAAa,OAAO,OAAO,KAAK,EAAE;AAAA,YAAK,CAAC,aAC3C,WAAW,CAAC,GAAG;AAAA,cAAK,CAAC,OACnB,EAAE,SAAS,CAAC,GAAG;AAAA,gBAAK,CAAC,MACpB,qBAAqB,EAAE,SAAS,SAAS,WAAW;AAAA,cACtD;AAAA,YACF;AAAA,UACF;AACA,iBAAO,aACH,EAAE,QAAQ,MAAM,QAAQ,uBAAuB,IAC/C,EAAE,QAAQ,QAAQ,QAAQ,eAAe,WAAW,OAAO,YAAY,GAAG;AAAA,QAChF;AAAA,MACF;AAAA,IACF;AAIA,eAAW,OAAO,IAAI,UAAU,UAAU;AACxC,YAAM,IAAI,KAAK,YAAY,KAAK,IAAI,IAAI;AACxC,aAAO,KAAK;AAAA,QACV,MAAM,GAAG,KAAK,IAAI,aAAa,IAAI,IAAI;AAAA,QACvC,OAAO,MACL,WAAW,CAAC,IAAI,EAAE,QAAQ,MAAM,QAAQ,EAAE,IAAI,EAAE,QAAQ,QAAQ,QAAQ,cAAc,CAAC,GAAG;AAAA,MAC9F,CAAC;AAAA,IACH;AACA,eAAW,SAAS,IAAI,UAAU,QAAQ;AACxC,YAAM,IAAI,KAAK,KAAK,SAAS,KAAK,MAAM,IAAI,GAAG,UAAU;AACzD,aAAO,KAAK;AAAA,QACV,MAAM,GAAG,KAAK,IAAI,WAAW,MAAM,IAAI;AAAA,QACvC,OAAO,MACL,WAAW,CAAC,IAAI,EAAE,QAAQ,MAAM,QAAQ,EAAE,IAAI,EAAE,QAAQ,QAAQ,QAAQ,cAAc,CAAC,GAAG;AAAA,MAC9F,CAAC;AAAA,IACH;AACA,eAAW,SAAS,IAAI,UAAU,WAAW;AAC3C,YAAM,IAAI,KAAK,aAAa,KAAK,MAAM,IAAI;AAC3C,aAAO,KAAK;AAAA,QACV,MAAM,GAAG,KAAK,IAAI,cAAc,MAAM,IAAI;AAAA,QAC1C,OAAO,MACL,WAAW,CAAC,IAAI,EAAE,QAAQ,MAAM,QAAQ,EAAE,IAAI,EAAE,QAAQ,QAAQ,QAAQ,cAAc,CAAC,GAAG;AAAA,MAC9F,CAAC;AAAA,IACH;AACA,WAAO;AAAA,EACT;AAAA;AAAA,EAIA,WAAW,OAAsB,KAA+B;AAC9D,UAAM,QAAS,OAAO,CAAC;AACvB,UAAM,cAAc,OAAO,MAAM,cAAc,WAAW,MAAM,YAAY;AAC5E,UAAM,YAAY,iBAAiB,KAAK;AACxC,UAAM,aAAa,OAAO,MAAM,QAAQ,WAAW,MAAM,MAAM;AAE/D,UAAM,OAAO;AAAA,MACX,cAAc;AAAA,MACd;AAAA,MACA;AAAA,MACA;AAAA,MACA,GAAI,eAAe,SAAY,EAAE,WAAW,IAAI,CAAC;AAAA,IACnD;AAEA,YAAQ,OAAO;AAAA,MACb,KAAK,cAAc;AACjB,cAAM,KAAsB;AAAA,UAC1B,GAAG;AAAA,UACH,UAAU,MAAM,aAAa;AAAA,UAC7B,WAAW,MAAM,cAAc,CAAC;AAAA,QAClC;AACA,eAAO;AAAA,MACT;AAAA,MACA,KAAK,eAAe;AAClB,cAAM,KAAuB;AAAA,UAC3B,GAAG;AAAA,UACH,UAAU,MAAM,aAAa;AAAA,UAC7B,WAAW,MAAM,cAAc,CAAC;AAAA,UAChC,GAAI,qBAAqB,MAAM,aAAa,MAAM,SAC9C,EAAE,YAAY,qBAAqB,MAAM,aAAa,EAAE,IACxD,CAAC;AAAA,QACP;AACA,eAAO;AAAA,MACT;AAAA,MACA,KAAK,gBAAgB;AACnB,cAAM,KAAwB;AAAA,UAC5B,GAAG;AAAA,UACH,QAAQ,uBAAuB,MAAM,MAAM;AAAA,QAC7C;AACA,eAAO;AAAA,MACT;AAAA,MACA,KAAK,cAAc;AACjB,cAAM,KAAsB;AAAA,UAC1B,GAAG;AAAA,UACH,GAAI,OAAO,MAAM,WAAW,WAAW,EAAE,QAAQ,MAAM,OAAO,IAAI,CAAC;AAAA,QACrE;AACA,eAAO;AAAA,MACT;AAAA,MACA,KAAK,oBAAoB;AACvB,cAAM,KAA4B;AAAA,UAChC,GAAG;AAAA,UACH,QAAQ,OAAO,MAAM,WAAW,WAAW,MAAM,SAAS;AAAA,QAC5D;AACA,eAAO;AAAA,MACT;AAAA,MACA,KAAK,cAAc;AACjB,cAAM,KAAsB;AAAA,UAC1B,GAAG;AAAA,UACH,GAAI,MAAM,YAAY,UAAU,MAAM,YAAY,WAC9C,EAAE,SAAS,MAAM,QAAQ,IACzB,CAAC;AAAA,QACP;AACA,eAAO;AAAA,MACT;AAAA,MACA,KAAK,QAAQ;AACX,cAAM,KAAgB;AAAA,UACpB,GAAG;AAAA,UACH,GAAI,OAAO,MAAM,qBAAqB,YAClC,EAAE,gBAAgB,MAAM,iBAAiB,IACzC,CAAC;AAAA,QACP;AACA,eAAO;AAAA,MACT;AAAA,MACA,KAAK,gBAAgB;AACnB,cAAM,KAAwB;AAAA,UAC5B,GAAG;AAAA,UACH,SAAS,OAAO,MAAM,YAAY,WAAW,MAAM,UAAU;AAAA,QAC/D;AACA,eAAO;AAAA,MACT;AAAA,MACA,KAAK,qBAAqB;AACxB,cAAM,KAA6B;AAAA,UACjC,GAAG;AAAA,UACH,UAAU,MAAM,aAAa;AAAA,UAC7B,WAAW,MAAM,cAAc,CAAC;AAAA,UAChC,GAAI,MAAM,QAAQ,MAAM,sBAAsB,IAC1C,EAAE,uBAAuB,MAAM,uBAAuB,IACtD,CAAC;AAAA,QACP;AACA,eAAO;AAAA,MACT;AAAA,MACA,KAAK,sBAAsB;AAEzB,cAAM,KAA8B;AAAA,UAClC,GAAG;AAAA,UACH,UAAU,MAAM,aAAa;AAAA,UAC7B,WAAW,MAAM,cAAc,CAAC;AAAA,UAChC,OAAO,OAAO,MAAM,UAAU,WAAW,MAAM,QAAQ;AAAA,UACvD,GAAI,OAAO,MAAM,gBAAgB,WAC7B,EAAE,WAAW,MAAM,YAAY,IAC/B,CAAC;AAAA,UACL,GAAI,OAAO,MAAM,iBAAiB,YAC9B,EAAE,aAAa,MAAM,aAAa,IAClC,CAAC;AAAA,QACP;AACA,eAAO;AAAA,MACT;AAAA,MACA,KAAK,iBAAiB;AACpB,cAAM,KAAyB;AAAA,UAC7B,GAAG;AAAA,UACH,GAAI,OAAO,MAAM,aAAa,WAAW,EAAE,SAAS,MAAM,SAAS,IAAI,CAAC;AAAA,UACxE,GAAI,OAAO,MAAM,eAAe,WAC5B,EAAE,WAAW,MAAM,WAAW,IAC9B,CAAC;AAAA,QACP;AACA,eAAO;AAAA,MACT;AAAA,MACA,KAAK,gBAAgB;AAGnB,cAAM,KAAwB;AAAA,UAC5B,GAAG;AAAA,UACH,GAAI,OAAO,MAAM,aAAa,WAAW,EAAE,SAAS,MAAM,SAAS,IAAI,CAAC;AAAA,UACxE,GAAI,OAAO,MAAM,eAAe,WAC5B,EAAE,WAAW,MAAM,WAAW,IAC9B,CAAC;AAAA,UACL,GAAI,OAAO,MAAM,0BAA0B,WACvC,EAAE,qBAAqB,MAAM,sBAAsB,IACnD,CAAC;AAAA,UACL,GAAI,OAAO,MAAM,2BAA2B,WACxC,EAAE,sBAAsB,MAAM,uBAAuB,IACrD,CAAC;AAAA,UACL,GAAI,OAAO,MAAM,qBAAqB,YAClC,EAAE,gBAAgB,MAAM,iBAAiB,IACzC,CAAC;AAAA,QACP;AACA,eAAO;AAAA,MACT;AAAA,MACA,SAAS;AAEP,cAAM,SAAgB;AACtB,cAAM,IAAI,MAAM,qCAAqC,OAAO,MAAM,CAAC,EAAE;AAAA,MACvE;AAAA,IACF;AAAA,EACF;AAAA;AAAA,EAIA,YAAY,OAAsB,UAAmC;AACnE,UAAM,gBAAgB;AACtB,UAAM,WAAW,SAAS,YAAY;AAWtC,QAAI,UAAU,qBAAqB;AACjC,UAAI,SAAS,aAAa,QAAQ;AAChC,eAAO,KAAK,OAAO;AAAA,UACjB,oBAAoB;AAAA,YAClB;AAAA,YACA,UAAU;AAAA,cACR,UAAU;AAAA,cACV,SAAS,SAAS,UAAU;AAAA,YAC9B;AAAA,UACF;AAAA,QACF,CAAC;AAAA,MACH;AACA,UACE,SAAS,aAAa,WACrB,SAAS,aAAa,YAAY,SAAS,cAC5C;AACA,eAAO,KAAK,OAAO;AAAA,UACjB,oBAAoB;AAAA,YAClB;AAAA,YACA,UAAU;AAAA,cACR,UAAU;AAAA,cACV,GAAI,SAAS,eACT,EAAE,cAAc,SAAS,aAAa,IACtC,CAAC;AAAA,YACP;AAAA,UACF;AAAA,QACF,CAAC;AAAA,MACH;AACA,aAAO,EAAE,UAAU,EAAE;AAAA,IACvB;AAOA,QAAI,UAAU,wBAAwB,UAAU,iBAAiB;AAC/D,YAAM,UACJ,aAAa,YACT,SAAS,oBACT,aAAa,SACX,SAAS,UAAU,SAAS,oBAC5B;AACR,UAAI,SAAS;AACX,eAAO,KAAK,OAAO;AAAA,UACjB,oBAAoB,EAAE,eAAe,mBAAmB,QAAQ;AAAA,QAClE,CAAC;AAAA,MACH;AACA,aAAO,EAAE,UAAU,EAAE;AAAA,IACvB;AAKA,QAAI,aAAa,UAAU,UAAU,gBAAgB;AACnD,aAAO,KAAK,OAAO;AAAA,QACjB,UAAU;AAAA,QACV,QAAQ,SAAS,UAAU;AAAA,MAC7B,CAAC;AAAA,IACH;AAGA,QAAI,aAAa,QAAQ;AACvB,aAAO,KAAK,OAAO;AAAA,QACjB,oBAAoB;AAAA,UAClB;AAAA,UACA,oBAAoB;AAAA,UACpB,0BAA0B,SAAS,UAAU;AAAA,QAC/C;AAAA,MACF,CAAC;AAAA,IACH;AAGA,QAAI,aAAa,OAAO;AACtB,aAAO,KAAK,OAAO;AAAA,QACjB,oBAAoB;AAAA,UAClB;AAAA,UACA,oBAAoB;AAAA,UACpB,0BAA0B,SAAS,UAAU;AAAA,QAC/C;AAAA,MACF,CAAC;AAAA,IACH;AAKA,QAAI,aAAa,UAAU;AACzB,UAAI,UAAU,gBAAgB,SAAS,cAAc;AACnD,eAAO,KAAK,OAAO;AAAA,UACjB,oBAAoB,EAAE,eAAe,cAAc,SAAS,aAAa;AAAA,QAC3E,CAAC;AAAA,MACH;AAAA,IAEF;AAGA,QAAI,aAAa,aAAa,SAAS,mBAAmB;AACxD,aAAO,KAAK,OAAO;AAAA,QACjB,oBAAoB,EAAE,eAAe,mBAAmB,SAAS,kBAAkB;AAAA,MACrF,CAAC;AAAA,IACH;AAGA,WAAO,EAAE,UAAU,EAAE;AAAA,EACvB;AAAA,EAEQ,OAAO,SAA6B;AAC1C,WAAO,EAAE,UAAU,GAAG,QAAQ,KAAK,UAAU,OAAO,EAAE;AAAA,EACxD;AACF;AASA,SAAS,iBAAiB,OAA8B;AACtD,MAAI,OAAO,MAAM,eAAe,YAAY,MAAM,eAAe,IAAI;AACnE,WAAO,MAAM;AAAA,EACf;AACA,MAAI,OAAO,MAAM,oBAAoB,UAAU;AAC7C,UAAM,IAAI,MAAM,gBAAgB,MAAM,yBAAyB;AAC/D,QAAI,KAAK,EAAE,CAAC,EAAG,QAAO,EAAE,CAAC;AAAA,EAC3B;AACA,SAAO;AACT;AAGA,SAAS,qBAAqB,OAAoC;AAChE,MAAI,SAAS,KAAM,QAAO;AAC1B,MAAI,OAAO,UAAU,SAAU,QAAO;AACtC,MAAI;AACF,WAAO,KAAK,UAAU,KAAK;AAAA,EAC7B,QAAQ;AACN,WAAO,OAAO,KAAK;AAAA,EACrB;AACF;AAEA,SAAS,uBAAuB,QAAyD;AACvF,UAAQ,QAAQ;AAAA,IACd,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT;AACE,aAAO;AAAA,EACX;AACF;AAEO,IAAM,UAAU,IAAI,gBAAgB;AAC3C,IAAO,oBAAQ;","names":["entry","headers"]}
|
|
@@ -4,12 +4,13 @@ import {
|
|
|
4
4
|
} from "./chunk-DBQMX75U.js";
|
|
5
5
|
import {
|
|
6
6
|
BaseAdapter
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-PD4VFEBY.js";
|
|
8
8
|
import "./chunk-7L6ITC4T.js";
|
|
9
9
|
import {
|
|
10
10
|
buildServeWrapperCommand,
|
|
11
11
|
shouldWrapForTelemetry
|
|
12
12
|
} from "./chunk-MEH7GC7R.js";
|
|
13
|
+
import "./chunk-N6HH7K6P.js";
|
|
13
14
|
import "./chunk-TRQKHP7D.js";
|
|
14
15
|
|
|
15
16
|
// src/adapters/roo-code/index.ts
|
|
@@ -39,6 +40,10 @@ var RooCodeAdapter = class extends BaseAdapter {
|
|
|
39
40
|
name = "Roo Code";
|
|
40
41
|
paradigm = "mcp-only";
|
|
41
42
|
capabilities = {
|
|
43
|
+
// Memory surface: AGENTS.md-first managed block (project <projectDir>/AGENTS.md
|
|
44
|
+
// via the base default — Roo's "Agent Rules standard" support is default-on;
|
|
45
|
+
// user scope → ~/.roo/rules/agent-connector.md below).
|
|
46
|
+
supportsMemory: true,
|
|
42
47
|
// Roo Code has no lifecycle hook system — every hook capability is false.
|
|
43
48
|
preToolUse: false,
|
|
44
49
|
postToolUse: false,
|
|
@@ -97,6 +102,22 @@ var RooCodeAdapter = class extends BaseAdapter {
|
|
|
97
102
|
MCP_SETTINGS_FILE
|
|
98
103
|
);
|
|
99
104
|
}
|
|
105
|
+
// ── Memory surface: global rules dir at user scope ──────────────────────
|
|
106
|
+
// Project scope stays on the AGENTS.md base default ("Agent Rules standard",
|
|
107
|
+
// default-on). User scope targets a dedicated agent-connector.md in Roo's
|
|
108
|
+
// documented ~/.roo/rules/ dir (files concatenated; AC-created → cleanly
|
|
109
|
+
// deletable on uninstall).
|
|
110
|
+
memoryTargets(ctx) {
|
|
111
|
+
if (this.memoryOverride(ctx)?.path || ctx.scope !== "user") {
|
|
112
|
+
return super.memoryTargets(ctx);
|
|
113
|
+
}
|
|
114
|
+
return [
|
|
115
|
+
{
|
|
116
|
+
path: join(homedir(), ".roo", "rules", "agent-connector.md"),
|
|
117
|
+
reason: "roo-code global rules dir (~/.roo/rules; agent-connector-owned file)"
|
|
118
|
+
}
|
|
119
|
+
];
|
|
120
|
+
}
|
|
100
121
|
getConfigDir(ctx) {
|
|
101
122
|
return ctx.scope === "project" ? join(ctx.projectDir, ".roo") : join(
|
|
102
123
|
vscodeUserDir(),
|
|
@@ -218,6 +239,9 @@ var RooCodeAdapter = class extends BaseAdapter {
|
|
|
218
239
|
{
|
|
219
240
|
name: `${this.name}: server entry registered`,
|
|
220
241
|
check: () => {
|
|
242
|
+
if (!ctx.connector.server) {
|
|
243
|
+
return { status: "OK", detail: "no MCP server declared" };
|
|
244
|
+
}
|
|
221
245
|
const cfg = this.readJson(mcpPath);
|
|
222
246
|
const bucket = cfg?.[MCP_ROOT_KEY];
|
|
223
247
|
if (!cfg || !bucket) {
|
|
@@ -239,4 +263,4 @@ export {
|
|
|
239
263
|
adapter,
|
|
240
264
|
roo_code_default as default
|
|
241
265
|
};
|
|
242
|
-
//# sourceMappingURL=roo-code-
|
|
266
|
+
//# sourceMappingURL=roo-code-NI5UU6JB.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/adapters/roo-code/index.ts"],"sourcesContent":["/**\n * adapters/roo-code — Roo Code (VS Code extension) platform adapter.\n *\n * Roo Code (rooveterinaryinc.roo-cline) is a Cline-fork VS Code extension and an\n * **mcp-only** host from agent-connector's perspective: it exposes no lifecycle\n * hook system, so MCP server registration is the only thing we install and hooks\n * are reported unavailable. This mirrors the Warp reference adapter exactly.\n *\n * MCP config (vsix 3.54.0):\n * - user scope → <vscodeUserDir>/globalStorage/rooveterinaryinc.roo-cline/\n * settings/mcp_settings.json (renamed in 3.54.0 from the\n * older `cline_mcp_settings.json`; we PROBE both on detection\n * — the extension migrates the old name at startup — and\n * WRITE the new `mcp_settings.json`)\n * - project scope → <projectDir>/.roo/mcp.json\n * Both are JSON, root key \"mcpServers\".\n *\n * VS Code user-dir resolution (cross-OS):\n * - macOS → ~/Library/Application Support/Code/User\n * - Linux → ~/.config/Code/User\n * - Windows → %APPDATA%/Code/User (falls back to ~/AppData/Roaming/Code/User)\n * We deliberately target stable VS Code (\"Code\"), the documented home for the\n * published Roo Code extension's globalStorage. Insiders/forks would live under\n * a sibling dir but are out of scope for the default path.\n *\n * Env interpolation: Roo Code's settings file documents no native `${env:VAR}`\n * token (the entries are plain command/args/env literals), so we resolve every\n * `${env:VAR}` reference to a literal at install time — the no-native-token path.\n *\n * The hook \"config path\" is the SAME MCP settings file (there is no hook file),\n * so the generic doctor/backup behave sensibly.\n */\n\nimport { existsSync } from \"node:fs\";\nimport { homedir, platform as osPlatform } from \"node:os\";\nimport { join } from \"node:path\";\n\nimport { BaseAdapter } from \"../base.js\";\nimport type { Adapter, InstallContext, MemoryTarget } from \"../spi.js\";\nimport type {\n ChangeRecord,\n DetectedPlatform,\n HealthCheck,\n HookParadigm,\n PlatformCapabilities,\n PlatformId,\n ServerDef,\n Transport,\n} from \"../../core/types.js\";\nimport { resolveEnvRefsDeep } from \"../../core/interpolate.js\";\nimport {\n buildServeWrapperCommand,\n shouldWrapForTelemetry,\n} from \"../../core/spawn.js\";\n\nconst HOST: PlatformId = \"roo-code\";\nconst MCP_ROOT_KEY = \"mcpServers\";\n\n/** Roo Code extension id → its VS Code globalStorage folder. */\nconst ROO_EXTENSION_ID = \"rooveterinaryinc.roo-cline\";\n/** User-scope MCP settings filename — renamed in vsix 3.54.0. */\nconst MCP_SETTINGS_FILE = \"mcp_settings.json\";\n/** Legacy filename (pre-3.54.0) — probed on detection for older installs. */\nconst LEGACY_MCP_SETTINGS_FILE = \"cline_mcp_settings.json\";\n\n/**\n * Native MCP server entry shapes Roo Code accepts under `mcpServers`.\n * We write the minimal stdio shape { command, args, env, disabled }; Roo Code\n * also accepts optional `alwaysAllow` / `timeout`, which we intentionally omit.\n */\ninterface RooStdioServer {\n command: string;\n args?: string[];\n env?: Record<string, string>;\n disabled: boolean;\n}\ninterface RooHttpServer {\n url: string;\n headers?: Record<string, string>;\n disabled: boolean;\n}\n\n/**\n * Resolve the cross-OS VS Code per-user data directory (the \"User\" folder that\n * contains `globalStorage`). See module header for the per-platform mapping.\n */\nfunction vscodeUserDir(): string {\n const home = homedir();\n switch (osPlatform()) {\n case \"darwin\":\n return join(home, \"Library\", \"Application Support\", \"Code\", \"User\");\n case \"win32\": {\n const appData =\n process.env.APPDATA ?? join(home, \"AppData\", \"Roaming\");\n return join(appData, \"Code\", \"User\");\n }\n default:\n // Linux / other POSIX: XDG-style config dir.\n return join(home, \".config\", \"Code\", \"User\");\n }\n}\n\nexport class RooCodeAdapter extends BaseAdapter implements Adapter {\n readonly id: PlatformId = HOST;\n readonly name = \"Roo Code\";\n readonly paradigm: HookParadigm = \"mcp-only\";\n\n readonly capabilities: PlatformCapabilities = {\n // Memory surface: AGENTS.md-first managed block (project <projectDir>/AGENTS.md\n // via the base default — Roo's \"Agent Rules standard\" support is default-on;\n // user scope → ~/.roo/rules/agent-connector.md below).\n supportsMemory: true,\n // Roo Code has no lifecycle hook system — every hook capability is false.\n preToolUse: false,\n postToolUse: false,\n preCompact: false,\n sessionStart: false,\n sessionEnd: false,\n userPromptSubmit: false,\n stop: false,\n notification: false,\n canModifyArgs: false,\n canModifyOutput: false,\n canInjectSessionContext: false,\n // Roo Code registers stdio, SSE, and Streamable HTTP MCP servers.\n transports: [\"stdio\", \"sse\", \"http\"],\n };\n\n // ── Detection ────────────────────────────────────────────────────────────\n\n detectInstalled(projectDir: string): DetectedPlatform {\n const userSettings = this.userSettingsPath();\n const userExtDir = join(\n vscodeUserDir(),\n \"globalStorage\",\n ROO_EXTENSION_ID,\n );\n // Probe the legacy filename too (3.54.0 migrates it at startup) so an older\n // install is still recognized; we WRITE the new mcp_settings.json.\n const userLegacySettings = join(\n userExtDir,\n \"settings\",\n LEGACY_MCP_SETTINGS_FILE,\n );\n const projectMcp = join(projectDir, \".roo\", \"mcp.json\");\n\n const userMatch =\n existsSync(userSettings) ||\n existsSync(userLegacySettings) ||\n existsSync(userExtDir);\n const projectMatch = existsSync(projectMcp);\n const installed = userMatch || projectMatch;\n\n // Prefer the user scope/path when present; otherwise surface the project one.\n const scope = userMatch || !projectMatch ? \"user\" : \"project\";\n const configPath = scope === \"user\" ? userSettings : projectMcp;\n const reason = installed\n ? userMatch\n ? `found Roo Code globalStorage under ${userExtDir}`\n : `found Roo Code project config at ${projectMcp}`\n : `no Roo Code config at ${userExtDir} or ${projectMcp}`;\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,\n confidence: installed ? \"high\" : \"low\",\n };\n }\n\n // ── Native paths ─────────────────────────────────────────────────────────\n\n /** Absolute path to the user-scope MCP settings file (VS Code globalStorage). */\n private userSettingsPath(): string {\n return join(\n vscodeUserDir(),\n \"globalStorage\",\n ROO_EXTENSION_ID,\n \"settings\",\n MCP_SETTINGS_FILE,\n );\n }\n\n // ── Memory surface: global rules dir at user scope ──────────────────────\n // Project scope stays on the AGENTS.md base default (\"Agent Rules standard\",\n // default-on). User scope targets a dedicated agent-connector.md in Roo's\n // documented ~/.roo/rules/ dir (files concatenated; AC-created → cleanly\n // deletable on uninstall).\n protected override memoryTargets(ctx: InstallContext): MemoryTarget[] {\n if (this.memoryOverride(ctx)?.path || ctx.scope !== \"user\") {\n return super.memoryTargets(ctx);\n }\n return [\n {\n path: join(homedir(), \".roo\", \"rules\", \"agent-connector.md\"),\n reason: \"roo-code global rules dir (~/.roo/rules; agent-connector-owned file)\",\n },\n ];\n }\n\n getConfigDir(ctx: InstallContext): string {\n return ctx.scope === \"project\"\n ? join(ctx.projectDir, \".roo\")\n : join(\n vscodeUserDir(),\n \"globalStorage\",\n ROO_EXTENSION_ID,\n \"settings\",\n );\n }\n\n getServerConfigPath(ctx: InstallContext): string {\n return ctx.scope === \"project\"\n ? join(ctx.projectDir, \".roo\", \"mcp.json\")\n : this.userSettingsPath();\n }\n\n /**\n * Roo Code has no hook file — hooks are not a thing here. The hook \"config\n * path\" is the same MCP settings file so the generic doctor/backup behave\n * sensibly.\n */\n getHookConfigPath(ctx: InstallContext): string {\n return this.getServerConfigPath(ctx);\n }\n\n // ── MCP server install / uninstall ───────────────────────────────────────\n\n installServer(ctx: InstallContext): ChangeRecord[] {\n const { connector } = ctx;\n const override = connector.platforms[HOST]?.server;\n if (!connector.server || override === false) {\n return [\n {\n platform: this.id,\n action: \"skip\",\n detail: connector.server\n ? \"server registration disabled for roo-code\"\n : \"connector declares no MCP server\",\n },\n ];\n }\n\n // Shallow-merge any per-platform server override into the base ServerDef.\n const server: ServerDef =\n override && typeof override === \"object\"\n ? { ...connector.server, ...override }\n : connector.server;\n\n const serverPath = this.getServerConfigPath(ctx);\n const entry = this.renderServerEntry(ctx, server);\n\n return [\n this.upsertServerInJson(serverPath, MCP_ROOT_KEY, connector.id, entry, ctx.dryRun),\n ];\n }\n\n uninstallServer(ctx: InstallContext): ChangeRecord[] {\n const serverPath = this.getServerConfigPath(ctx);\n return [\n this.removeServerFromJson(serverPath, MCP_ROOT_KEY, ctx.connector.id, ctx.dryRun),\n ];\n }\n\n /** Render a normalized ServerDef into Roo Code's native mcpServers entry. */\n private renderServerEntry(\n ctx: InstallContext,\n server: ServerDef,\n ): RooStdioServer | RooHttpServer {\n const transport: Transport = server.transport;\n\n if (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 // Roo Code documents no native interpolation token, so resolve every\n // ${env:VAR} to a literal at install time.\n const entry: RooStdioServer = {\n command: resolveEnvRefsDeep(command),\n // Honor the per-call server's enabled flag (mirror droid) rather than\n // hardcoding enabled — a server marked enabled:false installs disabled.\n disabled: server.enabled === false,\n };\n if (args.length > 0) entry.args = resolveEnvRefsDeep(args);\n const env = this.renderEnv(server.env);\n if (env) entry.env = env;\n return entry;\n }\n\n // sse / http (and any other remote transport) — Roo Code registers a URL.\n const entry: RooHttpServer = {\n url: resolveEnvRefsDeep(server.url ?? \"\"),\n disabled: server.enabled === false,\n };\n const headers = this.renderEnv(server.headers);\n if (headers) entry.headers = headers;\n return entry;\n }\n\n /**\n * Render env/header values. Roo Code documents no native interpolation token,\n * so resolve `${env:VAR}` references to literals at install time.\n */\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 // ── Hooks (unavailable — Roo Code is mcp-only) ───────────────────────────\n\n installHooks(_ctx: InstallContext): ChangeRecord[] {\n return [\n {\n platform: this.id,\n action: \"skip\",\n detail: \"hooks unavailable (Roo Code is mcp-only)\",\n },\n ];\n }\n\n uninstallHooks(_ctx: InstallContext): ChangeRecord[] {\n return [\n {\n platform: this.id,\n action: \"skip\",\n detail: \"hooks unavailable (Roo Code is mcp-only)\",\n },\n ];\n }\n\n // ── Diagnostics ──────────────────────────────────────────────────────────\n\n override getHealthChecks(ctx: InstallContext): readonly HealthCheck[] {\n const mcpPath = this.getServerConfigPath(ctx);\n const connectorId = ctx.connector.id;\n return [\n {\n name: `${this.name}: MCP settings present`,\n check: () =>\n existsSync(mcpPath)\n ? { status: \"OK\", detail: mcpPath }\n : { status: \"FAIL\", detail: `not found: ${mcpPath}` },\n },\n {\n name: `${this.name}: server entry registered`,\n check: () => {\n // Only assert what the connector declares: a server-less connector —\n // e.g. a catalog-only bundle of agents/skills/commands — never writes\n // an mcpServers entry, so its absence is healthy.\n if (!ctx.connector.server) {\n return { status: \"OK\", detail: \"no MCP server declared\" };\n }\n const cfg = this.readJson<{ [k: string]: Record<string, unknown> }>(mcpPath);\n const bucket = cfg?.[MCP_ROOT_KEY];\n if (!cfg || !bucket) {\n return { status: \"FAIL\", detail: `no ${MCP_ROOT_KEY} in ${mcpPath}` };\n }\n return connectorId in bucket\n ? { status: \"OK\", detail: `${MCP_ROOT_KEY}.${connectorId} present` }\n : {\n status: \"FAIL\",\n detail: `no ${MCP_ROOT_KEY}.${connectorId} in ${mcpPath}`,\n };\n },\n },\n ];\n }\n}\n\nexport const adapter = new RooCodeAdapter();\nexport default adapter;\n"],"mappings":"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","names":["entry"]}
|