@ken-jo/agent-connector 0.4.0 → 0.4.6
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 +9 -9
- package/dist/{action-PLZW5BGX.js → action-EV63GAPY.js} +11 -10
- package/dist/{action-PLZW5BGX.js.map → action-EV63GAPY.js.map} +1 -1
- package/dist/amazon-q-COAL3764.js +276 -0
- package/dist/amazon-q-COAL3764.js.map +1 -0
- package/dist/amp-XJQ4TDAU.js +666 -0
- package/dist/amp-XJQ4TDAU.js.map +1 -0
- package/dist/{antigravity-ANDKF3K7.js → antigravity-AMKKKHS4.js} +4 -4
- package/dist/{antigravity-cli-LLRPDDOT.js → antigravity-cli-XERXEH5W.js} +4 -4
- package/dist/{chunk-MAH6QQTO.js → chunk-2X4EH2D7.js} +5 -4
- package/dist/chunk-2X4EH2D7.js.map +1 -0
- package/dist/{chunk-G3ER4SY5.js → chunk-5G4EPJ4Y.js} +9 -9
- package/dist/chunk-BMD7ANKF.js +237 -0
- package/dist/chunk-BMD7ANKF.js.map +1 -0
- package/dist/{chunk-IW77FFNX.js → chunk-CPLK7GTE.js} +41 -5
- package/dist/chunk-CPLK7GTE.js.map +1 -0
- package/dist/{chunk-ADTHT2FN.js → chunk-DCK5FADX.js} +10 -173
- package/dist/chunk-DCK5FADX.js.map +1 -0
- package/dist/{chunk-J3D5W5T2.js → chunk-EROJDXMW.js} +2 -2
- package/dist/{chunk-22Y24V7O.js → chunk-F5RX62T7.js} +2 -2
- package/dist/chunk-FAHIMJRU.js +177 -0
- package/dist/chunk-FAHIMJRU.js.map +1 -0
- package/dist/{chunk-BHUCB6LY.js → chunk-H67V7DEL.js} +8 -7
- package/dist/{chunk-BHUCB6LY.js.map → chunk-H67V7DEL.js.map} +1 -1
- package/dist/{chunk-BXGFUENQ.js → chunk-I5MLE6S7.js} +14 -1
- package/dist/{chunk-BXGFUENQ.js.map → chunk-I5MLE6S7.js.map} +1 -1
- package/dist/{chunk-LL4OBGRU.js → chunk-LQRAPXS4.js} +3 -3
- package/dist/{chunk-KGJWE6A2.js → chunk-MZF2YCXX.js} +2 -2
- package/dist/{chunk-KGXDYGNJ.js → chunk-QC5A3TFQ.js} +19 -19
- package/dist/{chunk-KGXDYGNJ.js.map → chunk-QC5A3TFQ.js.map} +1 -1
- package/dist/{chunk-CIRDOY2V.js → chunk-QOGMDOUX.js} +3 -3
- package/dist/{chunk-KGGBNKI4.js → chunk-RQPKL62M.js} +144 -21
- package/dist/chunk-RQPKL62M.js.map +1 -0
- package/dist/{chunk-6XHB6BE3.js → chunk-SCVBYSF7.js} +1 -1
- package/dist/{chunk-76FUSVIA.js → chunk-SRVAA2VN.js} +6 -5
- package/dist/chunk-SRVAA2VN.js.map +1 -0
- package/dist/chunk-WZA4CSGJ.js +28 -0
- package/dist/chunk-WZA4CSGJ.js.map +1 -0
- package/dist/{claude-code-MLWS7CW6.js → claude-code-T2LPFNC3.js} +20 -30
- package/dist/claude-code-T2LPFNC3.js.map +1 -0
- package/dist/cli/sdk.js +5 -4
- package/dist/cli/sdk.js.map +1 -1
- package/dist/cli.js +1 -1
- package/dist/cline-WRYMNS7Z.js +442 -0
- package/dist/cline-WRYMNS7Z.js.map +1 -0
- package/dist/{codebuff-SH2S3QAN.js → codebuff-PODYPOOP.js} +130 -5
- package/dist/codebuff-PODYPOOP.js.map +1 -0
- package/dist/{codex-BXA4FIF4.js → codex-O4G7D7KK.js} +61 -13
- package/dist/codex-O4G7D7KK.js.map +1 -0
- package/dist/continue-K43SUHLQ.js +790 -0
- package/dist/continue-K43SUHLQ.js.map +1 -0
- package/dist/{copilot-cli-ROIBTTDT.js → copilot-cli-Q3SSPT4V.js} +70 -12
- package/dist/copilot-cli-Q3SSPT4V.js.map +1 -0
- package/dist/{crush-QLEFLHUC.js → crush-MBEH2R3I.js} +130 -6
- package/dist/crush-MBEH2R3I.js.map +1 -0
- package/dist/{cursor-ASJPWZ4R.js → cursor-TMBXDYR4.js} +119 -19
- package/dist/cursor-TMBXDYR4.js.map +1 -0
- package/dist/{detect-ZIIS55LD.js → detect-AHJIUMBO.js} +5 -4
- package/dist/{detect-ZIIS55LD.js.map → detect-AHJIUMBO.js.map} +1 -1
- package/dist/{doctor-TJUGSQ5C.js → doctor-G5MLCPAB.js} +221 -95
- package/dist/doctor-G5MLCPAB.js.map +1 -0
- package/dist/{droid-NCSS3B5Y.js → droid-JC2NT6S4.js} +135 -13
- package/dist/droid-JC2NT6S4.js.map +1 -0
- package/dist/{gemini-cli-SLVWLXJW.js → gemini-cli-ILR7M5X3.js} +62 -10
- package/dist/gemini-cli-ILR7M5X3.js.map +1 -0
- package/dist/{goose-PBA7KTE5.js → goose-SFO5BBGW.js} +15 -8
- package/dist/goose-SFO5BBGW.js.map +1 -0
- package/dist/{hermes-ONDCECP2.js → hermes-3N7WN4WS.js} +329 -15
- package/dist/hermes-3N7WN4WS.js.map +1 -0
- package/dist/{hook-OU522ABV.js → hook-76JBKTUX.js} +14 -11
- package/dist/hook-76JBKTUX.js.map +1 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.js +3 -2
- package/dist/{install-UDCBL7HP.js → install-R7252QFH.js} +11 -10
- package/dist/{install-UDCBL7HP.js.map → install-R7252QFH.js.map} +1 -1
- package/dist/{introspect-DuZSPSHB.d.ts → introspect-Cn3MSA4_.d.ts} +1 -1
- package/dist/{jetbrains-copilot-YABZ3HFA.js → jetbrains-copilot-NRZHI5PC.js} +85 -18
- package/dist/jetbrains-copilot-NRZHI5PC.js.map +1 -0
- package/dist/{kilo-F3ZDZKCT.js → kilo-IX4T3OHJ.js} +115 -19
- package/dist/kilo-IX4T3OHJ.js.map +1 -0
- package/dist/{kilo-cli-3HWPWBY4.js → kilo-cli-2AYCXBQD.js} +109 -13
- package/dist/kilo-cli-2AYCXBQD.js.map +1 -0
- package/dist/{kimi-NV72FVAO.js → kimi-2YFK2GBA.js} +87 -25
- package/dist/kimi-2YFK2GBA.js.map +1 -0
- package/dist/{kiro-C5W6AGDR.js → kiro-YL6AWUYG.js} +3 -3
- package/dist/{leaderboard-TIBVONVT.js → leaderboard-V6VWA5ZV.js} +3 -3
- package/dist/{mimo-code-IMM5YM3M.js → mimo-code-FTMGSKMQ.js} +41 -5
- package/dist/mimo-code-FTMGSKMQ.js.map +1 -0
- package/dist/{mux-DSSH4AFS.js → mux-5XZFB44C.js} +156 -6
- package/dist/mux-5XZFB44C.js.map +1 -0
- package/dist/{nemoclaw-3EVNKD3I.js → nemoclaw-CQYXZVQN.js} +4 -4
- package/dist/{omp-Z6FRNDPN.js → omp-2QMEY6HD.js} +138 -18
- package/dist/omp-2QMEY6HD.js.map +1 -0
- package/dist/{openclaw-7G437NT7.js → openclaw-UZC437RW.js} +4 -4
- package/dist/{opencode-Q6KBSAKW.js → opencode-L4BGFP25.js} +87 -27
- package/dist/opencode-L4BGFP25.js.map +1 -0
- package/dist/{package-RMPN57YZ.js → package-DNLQTPNN.js} +8 -7
- package/dist/{package-RMPN57YZ.js.map → package-DNLQTPNN.js.map} +1 -1
- package/dist/{pi-LZT6WWAZ.js → pi-PVVPVWKG.js} +3 -2
- package/dist/{pi-LZT6WWAZ.js.map → pi-PVVPVWKG.js.map} +1 -1
- package/dist/{qwen-code-WQBKRPWJ.js → qwen-code-G4CXKUHR.js} +426 -10
- package/dist/qwen-code-G4CXKUHR.js.map +1 -0
- package/dist/{roo-code-GWSNU3OW.js → roo-code-67TYJIQR.js} +3 -3
- package/dist/runtime/index.d.ts +1 -1
- package/dist/runtime/index.js +9 -8
- package/dist/sdk/index.d.ts +3 -3
- package/dist/sdk/index.js +4 -3
- package/dist/sdk/index.js.map +1 -1
- package/dist/sdk/test.d.ts +2 -2
- package/dist/sdk/test.js +6 -5
- package/dist/sdk/test.js.map +1 -1
- package/dist/{serve-D3GO36UT.js → serve-EOVWYBGZ.js} +11 -10
- package/dist/{serve-D3GO36UT.js.map → serve-EOVWYBGZ.js.map} +1 -1
- package/dist/{status-KOSKCETC.js → status-VTD6XXLW.js} +7 -6
- package/dist/{status-KOSKCETC.js.map → status-VTD6XXLW.js.map} +1 -1
- package/dist/{statusline-ZNTCL5YC.js → statusline-3ET5YPQ5.js} +10 -9
- package/dist/{statusline-ZNTCL5YC.js.map → statusline-3ET5YPQ5.js.map} +1 -1
- package/dist/{telemetry-XIKUUGTQ.js → telemetry-QCTMKDBQ.js} +6 -5
- package/dist/{telemetry-XIKUUGTQ.js.map → telemetry-QCTMKDBQ.js.map} +1 -1
- package/dist/{trae-NWT3TMSZ.js → trae-7CZZGOGI.js} +3 -3
- package/dist/{types-BEKsAium.d.ts → types-_6arHbX9.d.ts} +67 -24
- package/dist/{uninstall-2LBLQVFA.js → uninstall-FL3SH2DT.js} +11 -10
- package/dist/{uninstall-2LBLQVFA.js.map → uninstall-FL3SH2DT.js.map} +1 -1
- package/dist/{upgrade-ZC2S7VRN.js → upgrade-SLFG2FCT.js} +11 -10
- package/dist/{upgrade-ZC2S7VRN.js.map → upgrade-SLFG2FCT.js.map} +1 -1
- package/dist/{usage-E2A4O2CY.js → usage-IRBLVUZM.js} +3 -3
- package/dist/{usage-event-JKMC4QC4.js → usage-event-VFF77WYY.js} +10 -9
- package/dist/{usage-event-JKMC4QC4.js.map → usage-event-VFF77WYY.js.map} +1 -1
- package/dist/{vscode-copilot-ALV45XF6.js → vscode-copilot-MF2CDNMT.js} +23 -10
- package/dist/vscode-copilot-MF2CDNMT.js.map +1 -0
- package/dist/{warp-H6IX4U3J.js → warp-VKG55TAT.js} +55 -4
- package/dist/warp-VKG55TAT.js.map +1 -0
- package/dist/windsurf-FU5G4SHF.js +443 -0
- package/dist/windsurf-FU5G4SHF.js.map +1 -0
- package/dist/{zed-RH34TNSW.js → zed-SFUHL3GS.js} +3 -3
- package/package.json +2 -2
- package/dist/amp-B524U6LO.js +0 -300
- package/dist/amp-B524U6LO.js.map +0 -1
- package/dist/chunk-3PFFTFCU.js +0 -190
- package/dist/chunk-3PFFTFCU.js.map +0 -1
- package/dist/chunk-76FUSVIA.js.map +0 -1
- package/dist/chunk-ADTHT2FN.js.map +0 -1
- package/dist/chunk-IW77FFNX.js.map +0 -1
- package/dist/chunk-KGGBNKI4.js.map +0 -1
- package/dist/chunk-MAH6QQTO.js.map +0 -1
- package/dist/claude-code-MLWS7CW6.js.map +0 -1
- package/dist/codebuff-SH2S3QAN.js.map +0 -1
- package/dist/codex-BXA4FIF4.js.map +0 -1
- package/dist/copilot-cli-ROIBTTDT.js.map +0 -1
- package/dist/crush-QLEFLHUC.js.map +0 -1
- package/dist/cursor-ASJPWZ4R.js.map +0 -1
- package/dist/doctor-TJUGSQ5C.js.map +0 -1
- package/dist/droid-NCSS3B5Y.js.map +0 -1
- package/dist/gemini-cli-SLVWLXJW.js.map +0 -1
- package/dist/goose-PBA7KTE5.js.map +0 -1
- package/dist/hermes-ONDCECP2.js.map +0 -1
- package/dist/hook-OU522ABV.js.map +0 -1
- package/dist/jetbrains-copilot-YABZ3HFA.js.map +0 -1
- package/dist/kilo-F3ZDZKCT.js.map +0 -1
- package/dist/kilo-cli-3HWPWBY4.js.map +0 -1
- package/dist/kimi-NV72FVAO.js.map +0 -1
- package/dist/mimo-code-IMM5YM3M.js.map +0 -1
- package/dist/mux-DSSH4AFS.js.map +0 -1
- package/dist/omp-Z6FRNDPN.js.map +0 -1
- package/dist/opencode-Q6KBSAKW.js.map +0 -1
- package/dist/qwen-code-WQBKRPWJ.js.map +0 -1
- package/dist/vscode-copilot-ALV45XF6.js.map +0 -1
- package/dist/warp-H6IX4U3J.js.map +0 -1
- /package/dist/{antigravity-ANDKF3K7.js.map → antigravity-AMKKKHS4.js.map} +0 -0
- /package/dist/{antigravity-cli-LLRPDDOT.js.map → antigravity-cli-XERXEH5W.js.map} +0 -0
- /package/dist/{chunk-G3ER4SY5.js.map → chunk-5G4EPJ4Y.js.map} +0 -0
- /package/dist/{chunk-J3D5W5T2.js.map → chunk-EROJDXMW.js.map} +0 -0
- /package/dist/{chunk-22Y24V7O.js.map → chunk-F5RX62T7.js.map} +0 -0
- /package/dist/{chunk-LL4OBGRU.js.map → chunk-LQRAPXS4.js.map} +0 -0
- /package/dist/{chunk-KGJWE6A2.js.map → chunk-MZF2YCXX.js.map} +0 -0
- /package/dist/{chunk-CIRDOY2V.js.map → chunk-QOGMDOUX.js.map} +0 -0
- /package/dist/{chunk-6XHB6BE3.js.map → chunk-SCVBYSF7.js.map} +0 -0
- /package/dist/{kiro-C5W6AGDR.js.map → kiro-YL6AWUYG.js.map} +0 -0
- /package/dist/{leaderboard-TIBVONVT.js.map → leaderboard-V6VWA5ZV.js.map} +0 -0
- /package/dist/{nemoclaw-3EVNKD3I.js.map → nemoclaw-CQYXZVQN.js.map} +0 -0
- /package/dist/{openclaw-7G437NT7.js.map → openclaw-UZC437RW.js.map} +0 -0
- /package/dist/{roo-code-GWSNU3OW.js.map → roo-code-67TYJIQR.js.map} +0 -0
- /package/dist/{trae-NWT3TMSZ.js.map → trae-7CZZGOGI.js.map} +0 -0
- /package/dist/{usage-E2A4O2CY.js.map → usage-IRBLVUZM.js.map} +0 -0
- /package/dist/{zed-RH34TNSW.js.map → zed-SFUHL3GS.js.map} +0 -0
|
@@ -1 +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":[]}
|
|
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":[]}
|
|
@@ -1,4 +1,17 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
addLedgerOwner,
|
|
4
|
+
createLedgerEntry,
|
|
5
|
+
describeJsonValue,
|
|
6
|
+
dropLedgerEntry,
|
|
7
|
+
findLedgerEntry,
|
|
8
|
+
hashJsonValue,
|
|
9
|
+
jsonDeepEquals,
|
|
10
|
+
ledgerEntriesOwnedBy,
|
|
11
|
+
loadConfigPatchLedger,
|
|
12
|
+
removeLedgerOwner,
|
|
13
|
+
saveConfigPatchLedger
|
|
14
|
+
} from "./chunk-FAHIMJRU.js";
|
|
2
15
|
import {
|
|
3
16
|
writeTomlString
|
|
4
17
|
} from "./chunk-OPXAP3AC.js";
|
|
@@ -7,16 +20,18 @@ import {
|
|
|
7
20
|
} from "./chunk-DBQMX75U.js";
|
|
8
21
|
import {
|
|
9
22
|
BaseAdapter
|
|
10
|
-
} from "./chunk-
|
|
23
|
+
} from "./chunk-CPLK7GTE.js";
|
|
11
24
|
import {
|
|
12
25
|
renderSkillMd
|
|
13
26
|
} from "./chunk-7L6ITC4T.js";
|
|
14
27
|
import {
|
|
15
28
|
buildHomeBinHookCommand,
|
|
29
|
+
buildHomeBinStatuslineCommand,
|
|
16
30
|
buildServeWrapperCommand,
|
|
17
31
|
isHomeBinHookCommand,
|
|
32
|
+
isHomeBinStatuslineCommand,
|
|
18
33
|
shouldWrapForTelemetry
|
|
19
|
-
} from "./chunk-
|
|
34
|
+
} from "./chunk-I5MLE6S7.js";
|
|
20
35
|
import "./chunk-N6HH7K6P.js";
|
|
21
36
|
import "./chunk-TRQKHP7D.js";
|
|
22
37
|
|
|
@@ -26,6 +41,7 @@ import { homedir } from "os";
|
|
|
26
41
|
import { join } from "path";
|
|
27
42
|
var HOST = "qwen-code";
|
|
28
43
|
var MCP_ROOT_KEY = "mcpServers";
|
|
44
|
+
var STATUSLINE_KEY = "ui.statusLine";
|
|
29
45
|
var QwenCodeAdapter = class extends BaseAdapter {
|
|
30
46
|
id = HOST;
|
|
31
47
|
name = "Qwen CLI";
|
|
@@ -39,6 +55,10 @@ var QwenCodeAdapter = class extends BaseAdapter {
|
|
|
39
55
|
preToolUse: true,
|
|
40
56
|
postToolUse: true,
|
|
41
57
|
preCompact: true,
|
|
58
|
+
// Qwen fires PostCompact natively (observe-only — "not in the decision mode
|
|
59
|
+
// supported events list"; QwenLM/qwen-code docs/users/features/hooks.md
|
|
60
|
+
// "#### PostCompact", trigger + compact_summary payload).
|
|
61
|
+
postCompact: true,
|
|
42
62
|
sessionStart: true,
|
|
43
63
|
sessionEnd: true,
|
|
44
64
|
userPromptSubmit: true,
|
|
@@ -63,7 +83,22 @@ var QwenCodeAdapter = class extends BaseAdapter {
|
|
|
63
83
|
// Ground truth: kilo-pi-ground-truth.md § "Already-known skills gaps".
|
|
64
84
|
supportsCommands: true,
|
|
65
85
|
supportsSkills: true,
|
|
66
|
-
supportsSubagents: true
|
|
86
|
+
supportsSubagents: true,
|
|
87
|
+
// Statusline surface: qwen-code is the 2nd v1 host (after claude-code).
|
|
88
|
+
// installStatusline wires settings.json `ui.statusLine` = {type:"command",
|
|
89
|
+
// command:<home-bin statusline cmd>} through the SAME refcounted ownership
|
|
90
|
+
// ledger as configPatch (never clobbers a ui.statusLine agent-connector does
|
|
91
|
+
// not own). The key is NESTED here (`ui.statusLine`), unlike claude-code's
|
|
92
|
+
// top-level `statusLine`. Confirmed config key + stdin payload against the
|
|
93
|
+
// qwen-code status-line docs (shipped v0.14.3, PR #2923).
|
|
94
|
+
supportsStatusline: true,
|
|
95
|
+
// Native passthrough: Qwen's 16-event surface includes 3 host-specific events
|
|
96
|
+
// with NO canonical HookEventName analog — TodoCreated / TodoCompleted /
|
|
97
|
+
// StopFailure (QwenLM/qwen-code docs/users/features/hooks.md). A connector
|
|
98
|
+
// reaches them via platforms["qwen-code"].nativeHooks; installHooks files the
|
|
99
|
+
// PascalCase event key VERBATIM into settings.json hooks, and the generic
|
|
100
|
+
// uninstall reverses it.
|
|
101
|
+
supportsNativeHooks: true
|
|
67
102
|
};
|
|
68
103
|
// ── Detection ────────────────────────────────────────────────────────────
|
|
69
104
|
detectInstalled(projectDir) {
|
|
@@ -198,18 +233,26 @@ var QwenCodeAdapter = class extends BaseAdapter {
|
|
|
198
233
|
// ── Hook install / uninstall ─────────────────────────────────────────────
|
|
199
234
|
installHooks(ctx) {
|
|
200
235
|
const { connector } = ctx;
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
236
|
+
const override = connector.platforms[HOST];
|
|
237
|
+
const hooksDisabled = override?.hooks === false;
|
|
238
|
+
const normalizedEvents = hooksDisabled ? [] : connector.hookEvents;
|
|
239
|
+
const nativeHooks = override?.nativeHooks ?? {};
|
|
240
|
+
const nativeEvents = Object.keys(nativeHooks);
|
|
241
|
+
if (normalizedEvents.length === 0 && nativeEvents.length === 0) {
|
|
242
|
+
return [
|
|
243
|
+
{
|
|
244
|
+
platform: this.id,
|
|
245
|
+
action: "skip",
|
|
246
|
+
detail: hooksDisabled ? "hooks disabled for qwen-code" : "connector declares no hooks"
|
|
247
|
+
}
|
|
248
|
+
];
|
|
206
249
|
}
|
|
207
250
|
const settingsPath = this.getHookConfigPath(ctx);
|
|
208
251
|
const settings = this.readJson(settingsPath) ?? {};
|
|
209
252
|
const hooks = settings.hooks ??= {};
|
|
210
253
|
const changes = [];
|
|
211
254
|
let mutated = false;
|
|
212
|
-
for (const event of
|
|
255
|
+
for (const event of normalizedEvents) {
|
|
213
256
|
const command = buildHomeBinHookCommand(ctx.homeBinPath, HOST, event, connector.id);
|
|
214
257
|
const matcher = connector.hooks[event]?.matcher ?? "";
|
|
215
258
|
const entry = {
|
|
@@ -246,6 +289,32 @@ var QwenCodeAdapter = class extends BaseAdapter {
|
|
|
246
289
|
}
|
|
247
290
|
mutated = true;
|
|
248
291
|
}
|
|
292
|
+
for (const nativeEvent of nativeEvents) {
|
|
293
|
+
const command = buildHomeBinHookCommand(ctx.homeBinPath, HOST, nativeEvent, connector.id);
|
|
294
|
+
const entry = {
|
|
295
|
+
matcher: nativeHooks[nativeEvent]?.matcher ?? "",
|
|
296
|
+
hooks: [{ type: "command", command }]
|
|
297
|
+
};
|
|
298
|
+
const bucket = hooks[nativeEvent] ??= [];
|
|
299
|
+
const existingIdx = bucket.findIndex((e) => e.hooks?.[0]?.command === command);
|
|
300
|
+
if (existingIdx >= 0) {
|
|
301
|
+
if (JSON.stringify(bucket[existingIdx]) === JSON.stringify(entry)) {
|
|
302
|
+
changes.push({
|
|
303
|
+
platform: this.id,
|
|
304
|
+
action: "skip",
|
|
305
|
+
path: settingsPath,
|
|
306
|
+
detail: `hooks.${nativeEvent} (native) already registered`
|
|
307
|
+
});
|
|
308
|
+
continue;
|
|
309
|
+
}
|
|
310
|
+
bucket[existingIdx] = entry;
|
|
311
|
+
changes.push({ platform: this.id, action: "update", path: settingsPath, detail: `hooks.${nativeEvent} (native)` });
|
|
312
|
+
} else {
|
|
313
|
+
bucket.push(entry);
|
|
314
|
+
changes.push({ platform: this.id, action: "create", path: settingsPath, detail: `hooks.${nativeEvent} (native)` });
|
|
315
|
+
}
|
|
316
|
+
mutated = true;
|
|
317
|
+
}
|
|
249
318
|
if (mutated) this.writeJson(settingsPath, settings, ctx.dryRun);
|
|
250
319
|
return changes;
|
|
251
320
|
}
|
|
@@ -307,6 +376,282 @@ var QwenCodeAdapter = class extends BaseAdapter {
|
|
|
307
376
|
isOurCommand(command, ctx) {
|
|
308
377
|
return isHomeBinHookCommand(command, ctx.homeBinPath, ctx.connector.id);
|
|
309
378
|
}
|
|
379
|
+
// ── Statusline surface (a HUD/status line) ────────────────────────────────
|
|
380
|
+
// Wires settings.json `ui.statusLine` = { type:"command", command:<home-bin
|
|
381
|
+
// statusline cmd> } through the SAME refcounted ownership ledger as configPatch
|
|
382
|
+
// (the ledger primitives are surface-agnostic). qwen-code does NOT advertise
|
|
383
|
+
// supportsConfigPatch, so — unlike claude-code, which routes the statusline
|
|
384
|
+
// through its private applyConfigPatches loop — this adapter performs the nested
|
|
385
|
+
// set-if-absent write directly with the exported ledger primitives. Semantics
|
|
386
|
+
// are identical: never clobber a ui.statusLine agent-connector does not own
|
|
387
|
+
// (skip-warn), record prior state + owner (refcounted across connectors),
|
|
388
|
+
// reversible by uninstallStatusline (last-owner-verified delete). The key is
|
|
389
|
+
// NESTED (`ui.statusLine`), so we own the `ui.statusLine` leaf — if the user
|
|
390
|
+
// already has it, we skip-warn and never touch their value.
|
|
391
|
+
//
|
|
392
|
+
// The home-bin command makes Qwen exec
|
|
393
|
+
// `<homeBin> statusline qwen-code --connector <id>` for every status refresh,
|
|
394
|
+
// which re-imports the connector module and renders the line (runtime/
|
|
395
|
+
// statusline-entrypoint). No telemetry in v1.
|
|
396
|
+
/** The statusLine config object value agent-connector writes at `ui.statusLine`. */
|
|
397
|
+
statuslineValue(ctx) {
|
|
398
|
+
const command = buildHomeBinStatuslineCommand(ctx.homeBinPath, HOST, ctx.connector.id);
|
|
399
|
+
return { type: "command", command };
|
|
400
|
+
}
|
|
401
|
+
installStatusline(ctx) {
|
|
402
|
+
const { connector } = ctx;
|
|
403
|
+
if (connector.statusline == null) {
|
|
404
|
+
return [{ platform: this.id, action: "skip", detail: "connector declares no statusline" }];
|
|
405
|
+
}
|
|
406
|
+
if (connector.platforms[HOST]?.statusline === false) {
|
|
407
|
+
return [{ platform: this.id, action: "skip", detail: "statusline disabled for qwen-code" }];
|
|
408
|
+
}
|
|
409
|
+
const filePath = this.getServerConfigPath(ctx);
|
|
410
|
+
if (this.isPresentButUnparseable(filePath)) {
|
|
411
|
+
return [
|
|
412
|
+
{
|
|
413
|
+
platform: this.id,
|
|
414
|
+
action: "warn",
|
|
415
|
+
path: filePath,
|
|
416
|
+
detail: `existing ${filePath} is not parseable; statusline left unapplied (back it up / fix it, then re-run)`
|
|
417
|
+
}
|
|
418
|
+
];
|
|
419
|
+
}
|
|
420
|
+
const settings = this.readJson(filePath) ?? {};
|
|
421
|
+
if (typeof settings !== "object" || Array.isArray(settings)) {
|
|
422
|
+
return [
|
|
423
|
+
{
|
|
424
|
+
platform: this.id,
|
|
425
|
+
action: "warn",
|
|
426
|
+
path: filePath,
|
|
427
|
+
detail: `existing ${filePath} is not a JSON object; statusline left unapplied`
|
|
428
|
+
}
|
|
429
|
+
];
|
|
430
|
+
}
|
|
431
|
+
const ledger = loadConfigPatchLedger(ctx.dataRoot);
|
|
432
|
+
const desired = this.statuslineValue(ctx);
|
|
433
|
+
const segments = STATUSLINE_KEY.split(".");
|
|
434
|
+
const leaf = readJsonLeaf(settings, segments);
|
|
435
|
+
const entry = findLedgerEntry(ledger, HOST, filePath, STATUSLINE_KEY);
|
|
436
|
+
const changes = [];
|
|
437
|
+
if (leaf.kind === "blocked") {
|
|
438
|
+
return [
|
|
439
|
+
{
|
|
440
|
+
platform: this.id,
|
|
441
|
+
action: "warn",
|
|
442
|
+
path: filePath,
|
|
443
|
+
detail: `statusline ${STATUSLINE_KEY} skipped: "${leaf.atPath}" exists but is not an object \u2014 set ${STATUSLINE_KEY} manually if wanted`
|
|
444
|
+
}
|
|
445
|
+
];
|
|
446
|
+
}
|
|
447
|
+
if (leaf.kind === "absent") {
|
|
448
|
+
writeJsonLeaf(settings, segments, desired);
|
|
449
|
+
this.writeJson(filePath, settings, ctx.dryRun);
|
|
450
|
+
if (entry) {
|
|
451
|
+
entry.writtenValue = desired;
|
|
452
|
+
entry.writtenValueHash = hashJsonValue(desired);
|
|
453
|
+
addLedgerOwner(entry, connector.id, connector.version);
|
|
454
|
+
} else {
|
|
455
|
+
createLedgerEntry(ledger, {
|
|
456
|
+
platform: HOST,
|
|
457
|
+
file: filePath,
|
|
458
|
+
key: STATUSLINE_KEY,
|
|
459
|
+
value: desired,
|
|
460
|
+
connectorId: connector.id,
|
|
461
|
+
connectorVersion: connector.version
|
|
462
|
+
});
|
|
463
|
+
}
|
|
464
|
+
if (!ctx.dryRun) saveConfigPatchLedger(ctx.dataRoot, ledger);
|
|
465
|
+
changes.push({
|
|
466
|
+
platform: this.id,
|
|
467
|
+
action: "create",
|
|
468
|
+
path: filePath,
|
|
469
|
+
detail: `statusline ${STATUSLINE_KEY}: <absent> \u2192 ${describeJsonValue(desired)}`
|
|
470
|
+
});
|
|
471
|
+
return changes;
|
|
472
|
+
}
|
|
473
|
+
if (!entry) {
|
|
474
|
+
return [
|
|
475
|
+
{
|
|
476
|
+
platform: this.id,
|
|
477
|
+
action: "warn",
|
|
478
|
+
path: filePath,
|
|
479
|
+
detail: `statusline ${STATUSLINE_KEY} skipped: already set to ${describeJsonValue(leaf.value)} (not created by agent-connector) \u2014 left untouched`
|
|
480
|
+
}
|
|
481
|
+
];
|
|
482
|
+
}
|
|
483
|
+
if (!jsonDeepEquals(leaf.value, entry.writtenValue)) {
|
|
484
|
+
return [
|
|
485
|
+
{
|
|
486
|
+
platform: this.id,
|
|
487
|
+
action: "warn",
|
|
488
|
+
path: filePath,
|
|
489
|
+
detail: `statusline ${STATUSLINE_KEY}: value changed since install (current ${describeJsonValue(leaf.value)}, wrote ${describeJsonValue(entry.writtenValue)}); leaving in place`
|
|
490
|
+
}
|
|
491
|
+
];
|
|
492
|
+
}
|
|
493
|
+
if (jsonDeepEquals(desired, leaf.value)) {
|
|
494
|
+
const owners = entry.owners.map((o) => o.connectorId);
|
|
495
|
+
if (addLedgerOwner(entry, connector.id, connector.version)) {
|
|
496
|
+
if (!ctx.dryRun) saveConfigPatchLedger(ctx.dataRoot, ledger);
|
|
497
|
+
return [
|
|
498
|
+
{
|
|
499
|
+
platform: this.id,
|
|
500
|
+
action: "skip",
|
|
501
|
+
path: filePath,
|
|
502
|
+
detail: `statusline ${STATUSLINE_KEY} already installed; registered as co-owner (co-owned with ${owners.join(", ")})`
|
|
503
|
+
}
|
|
504
|
+
];
|
|
505
|
+
}
|
|
506
|
+
return [
|
|
507
|
+
{
|
|
508
|
+
platform: this.id,
|
|
509
|
+
action: "skip",
|
|
510
|
+
path: filePath,
|
|
511
|
+
detail: `statusline ${STATUSLINE_KEY} already installed`
|
|
512
|
+
}
|
|
513
|
+
];
|
|
514
|
+
}
|
|
515
|
+
return [
|
|
516
|
+
{
|
|
517
|
+
platform: this.id,
|
|
518
|
+
action: "warn",
|
|
519
|
+
path: filePath,
|
|
520
|
+
detail: `statusline ${STATUSLINE_KEY} skipped: already owned by ${entry.owners.map((o) => o.connectorId).join(", ")} with a different value \u2014 left untouched`
|
|
521
|
+
}
|
|
522
|
+
];
|
|
523
|
+
}
|
|
524
|
+
uninstallStatusline(ctx) {
|
|
525
|
+
const ledger = loadConfigPatchLedger(ctx.dataRoot);
|
|
526
|
+
const owned = ledgerEntriesOwnedBy(ledger, HOST, ctx.connector.id).filter(
|
|
527
|
+
(e) => e.key === STATUSLINE_KEY
|
|
528
|
+
);
|
|
529
|
+
if (owned.length === 0) {
|
|
530
|
+
return [
|
|
531
|
+
{
|
|
532
|
+
platform: this.id,
|
|
533
|
+
action: "skip",
|
|
534
|
+
detail: "statusline: no ownership recorded; left untouched"
|
|
535
|
+
}
|
|
536
|
+
];
|
|
537
|
+
}
|
|
538
|
+
const changes = [];
|
|
539
|
+
let ledgerMutated = false;
|
|
540
|
+
const byFile = /* @__PURE__ */ new Map();
|
|
541
|
+
for (const entry of owned) {
|
|
542
|
+
const bucket = byFile.get(entry.file) ?? [];
|
|
543
|
+
bucket.push(entry);
|
|
544
|
+
byFile.set(entry.file, bucket);
|
|
545
|
+
}
|
|
546
|
+
for (const [filePath, entries] of byFile) {
|
|
547
|
+
const unparseable = this.isPresentButUnparseable(filePath);
|
|
548
|
+
const settings = unparseable ? null : this.readJson(filePath);
|
|
549
|
+
let fileMutated = false;
|
|
550
|
+
for (const entry of entries) {
|
|
551
|
+
const { lastOwner } = removeLedgerOwner(entry, ctx.connector.id);
|
|
552
|
+
ledgerMutated = true;
|
|
553
|
+
if (!lastOwner) {
|
|
554
|
+
changes.push({
|
|
555
|
+
platform: this.id,
|
|
556
|
+
action: "skip",
|
|
557
|
+
path: filePath,
|
|
558
|
+
detail: `statusline ${entry.key} retained: still owned by ${entry.owners.map((o) => o.connectorId).join(", ")}`
|
|
559
|
+
});
|
|
560
|
+
continue;
|
|
561
|
+
}
|
|
562
|
+
dropLedgerEntry(ledger, entry);
|
|
563
|
+
if (unparseable) {
|
|
564
|
+
changes.push({
|
|
565
|
+
platform: this.id,
|
|
566
|
+
action: "warn",
|
|
567
|
+
path: filePath,
|
|
568
|
+
detail: `statusline ${entry.key}: ${filePath} is not parseable; key left in place (ownership released)`
|
|
569
|
+
});
|
|
570
|
+
continue;
|
|
571
|
+
}
|
|
572
|
+
if (!settings || typeof settings !== "object" || Array.isArray(settings)) {
|
|
573
|
+
changes.push({
|
|
574
|
+
platform: this.id,
|
|
575
|
+
action: "skip",
|
|
576
|
+
path: filePath,
|
|
577
|
+
detail: `statusline ${entry.key} already absent (no settings file); ownership record dropped`
|
|
578
|
+
});
|
|
579
|
+
continue;
|
|
580
|
+
}
|
|
581
|
+
const leaf = readJsonLeaf(settings, entry.key.split("."));
|
|
582
|
+
if (leaf.kind !== "present") {
|
|
583
|
+
changes.push({
|
|
584
|
+
platform: this.id,
|
|
585
|
+
action: "skip",
|
|
586
|
+
path: filePath,
|
|
587
|
+
detail: `statusline ${entry.key} already absent; ownership record dropped`
|
|
588
|
+
});
|
|
589
|
+
continue;
|
|
590
|
+
}
|
|
591
|
+
if (entry.prior?.present !== false || !jsonDeepEquals(leaf.value, entry.writtenValue)) {
|
|
592
|
+
changes.push({
|
|
593
|
+
platform: this.id,
|
|
594
|
+
action: "warn",
|
|
595
|
+
path: filePath,
|
|
596
|
+
detail: `statusline ${entry.key}: value changed since install (current ${describeJsonValue(leaf.value)}, wrote ${describeJsonValue(entry.writtenValue)}); left in place`
|
|
597
|
+
});
|
|
598
|
+
continue;
|
|
599
|
+
}
|
|
600
|
+
deleteJsonLeaf(settings, entry.key.split("."));
|
|
601
|
+
fileMutated = true;
|
|
602
|
+
changes.push({
|
|
603
|
+
platform: this.id,
|
|
604
|
+
action: "remove",
|
|
605
|
+
path: filePath,
|
|
606
|
+
detail: `statusline ${entry.key} removed (was ${describeJsonValue(entry.writtenValue)})`
|
|
607
|
+
});
|
|
608
|
+
}
|
|
609
|
+
if (fileMutated && settings) this.writeJson(filePath, settings, ctx.dryRun);
|
|
610
|
+
}
|
|
611
|
+
if (ledgerMutated && !ctx.dryRun) saveConfigPatchLedger(ctx.dataRoot, ledger);
|
|
612
|
+
return changes;
|
|
613
|
+
}
|
|
614
|
+
/**
|
|
615
|
+
* Parse Qwen's statusLine stdin JSON into the normalized
|
|
616
|
+
* {@link StatuslineContext}. Qwen pipes a JSON object to the statusLine command
|
|
617
|
+
* on stdin (model, context_window, workspace, git, …); fields the payload omits
|
|
618
|
+
* stay undefined. `raw` keeps the verbatim payload (incl. version/git/metrics/
|
|
619
|
+
* vim). NOTE: Qwen has NO cost analog (no cost field in the payload), so
|
|
620
|
+
* `ctx.cost` is intentionally left undefined. Sources: qwen-code status-line
|
|
621
|
+
* docs, QwenLM/qwen-code settings.md.
|
|
622
|
+
*/
|
|
623
|
+
parseStatusInput(raw) {
|
|
624
|
+
const input = raw ?? {};
|
|
625
|
+
const ctx = {
|
|
626
|
+
host: HOST,
|
|
627
|
+
capabilities: this.capabilities,
|
|
628
|
+
raw
|
|
629
|
+
};
|
|
630
|
+
if (typeof input.session_id === "string" && input.session_id !== "") {
|
|
631
|
+
ctx.sessionId = input.session_id;
|
|
632
|
+
}
|
|
633
|
+
if (typeof input.workspace?.current_dir === "string") {
|
|
634
|
+
ctx.cwd = input.workspace.current_dir;
|
|
635
|
+
}
|
|
636
|
+
if (typeof input.model?.display_name === "string") {
|
|
637
|
+
ctx.model = { displayName: input.model.display_name };
|
|
638
|
+
}
|
|
639
|
+
const cw = input.context_window;
|
|
640
|
+
if (cw) {
|
|
641
|
+
const context = {};
|
|
642
|
+
if (typeof cw.context_window_size === "number") context.maxTokens = cw.context_window_size;
|
|
643
|
+
if (typeof cw.current_usage === "number") context.usedTokens = cw.current_usage;
|
|
644
|
+
if (typeof cw.used_percentage === "number") context.percent = cw.used_percentage;
|
|
645
|
+
if (context.usedTokens !== void 0 || context.maxTokens !== void 0 || context.percent !== void 0) {
|
|
646
|
+
ctx.context = context;
|
|
647
|
+
}
|
|
648
|
+
}
|
|
649
|
+
return ctx;
|
|
650
|
+
}
|
|
651
|
+
/** Format the rendered status line into Qwen's native reply: stdout = line, exit 0. */
|
|
652
|
+
formatStatusOutput(rendered) {
|
|
653
|
+
return { exitCode: 0, stdout: rendered };
|
|
654
|
+
}
|
|
310
655
|
// ── Content surfaces: commands / subagents ───────────────────────────────
|
|
311
656
|
// CONTENT-ONLY: pure native-file writers under <qwenDir>/{commands,agents}. No
|
|
312
657
|
// runtime dispatch, no home-bin pointer, no telemetry wrap. Each method is
|
|
@@ -513,6 +858,32 @@ var QwenCodeAdapter = class extends BaseAdapter {
|
|
|
513
858
|
check: () => existsSync(p) ? { status: "OK", detail: p } : { status: "FAIL", detail: `not found: ${p}` }
|
|
514
859
|
});
|
|
515
860
|
}
|
|
861
|
+
const statuslineLedgerOwned = ledgerEntriesOwnedBy(
|
|
862
|
+
loadConfigPatchLedger(ctx.dataRoot),
|
|
863
|
+
HOST,
|
|
864
|
+
connectorId
|
|
865
|
+
).some((e) => e.key === STATUSLINE_KEY);
|
|
866
|
+
if ((ctx.connector.statusline != null || statuslineLedgerOwned) && ctx.connector.platforms[HOST]?.statusline !== false) {
|
|
867
|
+
checks.push({
|
|
868
|
+
name: `${this.name}: statusline wired`,
|
|
869
|
+
check: () => {
|
|
870
|
+
const settings = this.readJson(
|
|
871
|
+
settingsPath
|
|
872
|
+
);
|
|
873
|
+
const command = settings?.ui?.statusLine?.command;
|
|
874
|
+
if (command === void 0) {
|
|
875
|
+
return { status: "FAIL", detail: `ui.statusLine not set in ${settingsPath}` };
|
|
876
|
+
}
|
|
877
|
+
if (typeof command === "string" && isHomeBinStatuslineCommand(command, homeBin, connectorId)) {
|
|
878
|
+
return { status: "OK", detail: "ui.statusLine command present" };
|
|
879
|
+
}
|
|
880
|
+
return {
|
|
881
|
+
status: "FAIL",
|
|
882
|
+
detail: `ui.statusLine in ${settingsPath} is not agent-connector's (left untouched)`
|
|
883
|
+
};
|
|
884
|
+
}
|
|
885
|
+
});
|
|
886
|
+
}
|
|
516
887
|
return checks;
|
|
517
888
|
}
|
|
518
889
|
// ── Runtime: parse Qwen stdin JSON → normalized event ────────────────────
|
|
@@ -574,6 +945,13 @@ var QwenCodeAdapter = class extends BaseAdapter {
|
|
|
574
945
|
};
|
|
575
946
|
return ev;
|
|
576
947
|
}
|
|
948
|
+
case "PostCompact": {
|
|
949
|
+
const ev = {
|
|
950
|
+
...base,
|
|
951
|
+
...input.trigger === "auto" || input.trigger === "manual" ? { trigger: input.trigger } : {}
|
|
952
|
+
};
|
|
953
|
+
return ev;
|
|
954
|
+
}
|
|
577
955
|
case "Stop": {
|
|
578
956
|
const ev = {
|
|
579
957
|
...base,
|
|
@@ -713,6 +1091,44 @@ var QwenCodeAdapter = class extends BaseAdapter {
|
|
|
713
1091
|
return { exitCode: 0, stdout: JSON.stringify(payload) };
|
|
714
1092
|
}
|
|
715
1093
|
};
|
|
1094
|
+
function readJsonLeaf(root, segments) {
|
|
1095
|
+
let node = root;
|
|
1096
|
+
for (let i = 0; i < segments.length - 1; i++) {
|
|
1097
|
+
const next = node[segments[i]];
|
|
1098
|
+
if (next === void 0) return { kind: "absent" };
|
|
1099
|
+
if (next === null || typeof next !== "object" || Array.isArray(next)) {
|
|
1100
|
+
return { kind: "blocked", atPath: segments.slice(0, i + 1).join(".") };
|
|
1101
|
+
}
|
|
1102
|
+
node = next;
|
|
1103
|
+
}
|
|
1104
|
+
const leaf = node[segments[segments.length - 1]];
|
|
1105
|
+
if (leaf === void 0) return { kind: "absent" };
|
|
1106
|
+
return { kind: "present", value: leaf };
|
|
1107
|
+
}
|
|
1108
|
+
function writeJsonLeaf(root, segments, value) {
|
|
1109
|
+
let node = root;
|
|
1110
|
+
for (let i = 0; i < segments.length - 1; i++) {
|
|
1111
|
+
const seg = segments[i];
|
|
1112
|
+
const next = node[seg];
|
|
1113
|
+
if (next === void 0) {
|
|
1114
|
+
const created = {};
|
|
1115
|
+
node[seg] = created;
|
|
1116
|
+
node = created;
|
|
1117
|
+
} else {
|
|
1118
|
+
node = next;
|
|
1119
|
+
}
|
|
1120
|
+
}
|
|
1121
|
+
node[segments[segments.length - 1]] = value;
|
|
1122
|
+
}
|
|
1123
|
+
function deleteJsonLeaf(root, segments) {
|
|
1124
|
+
let node = root;
|
|
1125
|
+
for (let i = 0; i < segments.length - 1; i++) {
|
|
1126
|
+
const next = node[segments[i]];
|
|
1127
|
+
if (next === null || typeof next !== "object" || Array.isArray(next)) return;
|
|
1128
|
+
node = next;
|
|
1129
|
+
}
|
|
1130
|
+
delete node[segments[segments.length - 1]];
|
|
1131
|
+
}
|
|
716
1132
|
function extractSessionId(input) {
|
|
717
1133
|
if (typeof input.session_id === "string" && input.session_id !== "") {
|
|
718
1134
|
return input.session_id;
|
|
@@ -751,4 +1167,4 @@ export {
|
|
|
751
1167
|
adapter,
|
|
752
1168
|
qwen_code_default as default
|
|
753
1169
|
};
|
|
754
|
-
//# sourceMappingURL=qwen-code-
|
|
1170
|
+
//# sourceMappingURL=qwen-code-G4CXKUHR.js.map
|