@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
|
@@ -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/opencode/index.ts
|
|
@@ -38,6 +39,10 @@ var OpenCodeAdapter = class extends BaseAdapter {
|
|
|
38
39
|
name = "OpenCode";
|
|
39
40
|
paradigm = "ts-plugin";
|
|
40
41
|
capabilities = {
|
|
42
|
+
// Memory surface: AGENTS.md-first managed block. memoryTargets below probes
|
|
43
|
+
// project scope (CLAUDE.md is opencode's fallback ONLY when AGENTS.md is
|
|
44
|
+
// absent — creating AGENTS.md beside it would shadow the user's rules).
|
|
45
|
+
supportsMemory: true,
|
|
41
46
|
preToolUse: true,
|
|
42
47
|
postToolUse: true,
|
|
43
48
|
// OpenCode's compaction hook is experimental and not wired here.
|
|
@@ -47,6 +52,14 @@ var OpenCodeAdapter = class extends BaseAdapter {
|
|
|
47
52
|
userPromptSubmit: false,
|
|
48
53
|
stop: false,
|
|
49
54
|
notification: false,
|
|
55
|
+
// Newer events: OpenCode HAS a decision-capable `permission.ask` plugin
|
|
56
|
+
// hook upstream, but it is NOT wired here (E1 keeps this adapter
|
|
57
|
+
// degrade-only); subagents run as child sessions (bus events only — no
|
|
58
|
+
// dedicated lifecycle hook) and tool failure is merged into
|
|
59
|
+
// tool.execute.after / session.error. permissionRequest /
|
|
60
|
+
// postToolUseFailure / subagentStart / subagentStop stay unset — the
|
|
61
|
+
// generated bridge never references them and install reports them as
|
|
62
|
+
// "unsupported here".
|
|
50
63
|
// tool.execute.before mutates output.args → input rewrite supported.
|
|
51
64
|
canModifyArgs: true,
|
|
52
65
|
// tool.execute.after mutates output.output → output rewrite supported.
|
|
@@ -81,6 +94,32 @@ var OpenCodeAdapter = class extends BaseAdapter {
|
|
|
81
94
|
confidence: installed ? "high" : "low"
|
|
82
95
|
};
|
|
83
96
|
}
|
|
97
|
+
// ── Memory surface: AGENTS.md / CLAUDE.md-fallback probe (project) ──────
|
|
98
|
+
// OpenCode reads project AGENTS.md, falling back to CLAUDE.md ONLY when no
|
|
99
|
+
// AGENTS.md exists. If the user relies on that CLAUDE.md fallback, CREATING
|
|
100
|
+
// AGENTS.md beside it would shadow their own rules — so the block goes into
|
|
101
|
+
// the file opencode actually reads today; AGENTS.md is created only when
|
|
102
|
+
// neither exists. User scope (~/.config/opencode/AGENTS.md) stays on the
|
|
103
|
+
// BaseAdapter default.
|
|
104
|
+
memoryTargets(ctx) {
|
|
105
|
+
if (this.memoryOverride(ctx)?.path || ctx.scope !== "project") {
|
|
106
|
+
return super.memoryTargets(ctx);
|
|
107
|
+
}
|
|
108
|
+
const agentsMd = join(ctx.projectDir, "AGENTS.md");
|
|
109
|
+
if (existsSync(agentsMd)) {
|
|
110
|
+
return [{ path: agentsMd, reason: "AGENTS.md (opencode's primary project rules file)" }];
|
|
111
|
+
}
|
|
112
|
+
const claudeMd = join(ctx.projectDir, "CLAUDE.md");
|
|
113
|
+
if (existsSync(claudeMd)) {
|
|
114
|
+
return [
|
|
115
|
+
{
|
|
116
|
+
path: claudeMd,
|
|
117
|
+
reason: "CLAUDE.md (opencode's fallback rules file \u2014 creating AGENTS.md would shadow it)"
|
|
118
|
+
}
|
|
119
|
+
];
|
|
120
|
+
}
|
|
121
|
+
return [{ path: agentsMd, reason: "AGENTS.md standard (created; no opencode rules file yet)" }];
|
|
122
|
+
}
|
|
84
123
|
// ── Native paths ───────────────────────────────────────────────────────
|
|
85
124
|
getConfigDir(ctx) {
|
|
86
125
|
return ctx.scope === "project" ? ctx.projectDir : join(homedir(), ".config", "opencode");
|
|
@@ -287,21 +326,28 @@ var OpenCodeAdapter = class extends BaseAdapter {
|
|
|
287
326
|
// agent}. No runtime dispatch, no home-bin pointer, no telemetry wrap. Each
|
|
288
327
|
// method is idempotent (byte-identical → skip) via BaseAdapter.writeContentFile
|
|
289
328
|
// and reversible via removeContentFile. Honors platforms["opencode"]
|
|
290
|
-
// per-surface false to skip.
|
|
291
|
-
//
|
|
329
|
+
// per-surface false to skip.
|
|
330
|
+
//
|
|
331
|
+
// <ocDir> is NOT getConfigDir for project scope: opencode.json lives at the
|
|
332
|
+
// project ROOT, but content surfaces are read from <projectDir>/.opencode/
|
|
333
|
+
// (e.g. .opencode/skills/<name>/SKILL.md per opencode.ai/docs/skills) — the
|
|
334
|
+
// 0.1.0 adapter wrote <projectDir>/skills, which OpenCode never reads.
|
|
292
335
|
//
|
|
293
336
|
// NOTE on dirs: commands live in commands/<name>.md and skills in
|
|
294
337
|
// skills/<name>/SKILL.md, but subagents use the SINGULAR "agent/" dir
|
|
295
338
|
// (agent/<name>.md) — the OpenCode loader/CLI historically uses singular
|
|
296
339
|
// (anomalyco/opencode#14410); singular is the safe choice.
|
|
340
|
+
contentRootDir(ctx) {
|
|
341
|
+
return ctx.scope === "project" ? join(ctx.projectDir, ".opencode") : this.getConfigDir(ctx);
|
|
342
|
+
}
|
|
297
343
|
commandsDir(ctx) {
|
|
298
|
-
return join(this.
|
|
344
|
+
return join(this.contentRootDir(ctx), "commands");
|
|
299
345
|
}
|
|
300
346
|
skillsDir(ctx) {
|
|
301
|
-
return join(this.
|
|
347
|
+
return join(this.contentRootDir(ctx), "skills");
|
|
302
348
|
}
|
|
303
349
|
agentDir(ctx) {
|
|
304
|
-
return join(this.
|
|
350
|
+
return join(this.contentRootDir(ctx), "agent");
|
|
305
351
|
}
|
|
306
352
|
/** Native command file path: <ocDir>/commands/<name>.md. */
|
|
307
353
|
commandPath(ctx, name) {
|
|
@@ -731,4 +777,4 @@ export {
|
|
|
731
777
|
adapter,
|
|
732
778
|
opencode_default as default
|
|
733
779
|
};
|
|
734
|
-
//# sourceMappingURL=opencode-
|
|
780
|
+
//# sourceMappingURL=opencode-NZBRLJN3.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/adapters/opencode/index.ts"],"sourcesContent":["/**\n * adapters/opencode — OpenCode (SST) platform adapter for agent-connector.\n *\n * OpenCode is the reference **ts-plugin** host: it has no JSON hook table.\n * Instead it auto-loads JS/TS modules from a plugin directory; each module\n * default-exports an async factory that returns an object keyed by OpenCode\n * event names (\"tool.execute.before\", \"tool.execute.after\", …). The factory\n * runs in-process inside OpenCode, mutates the args/output objects it is handed,\n * and throws to block a tool call.\n *\n * The novel part — why this PROVES the ts-plugin paradigm:\n * context-mode could load ITS OWN plugin module in-process because the handler\n * code shipped with the package. agent-connector cannot: the connector's hook\n * handlers are arbitrary developer code we must not import into OpenCode's\n * runtime (wrong cwd, wrong deps, version skew, the cache-heal bug class).\n * So instead of importing handlers, we synthesize a tiny, fully self-contained\n * bridge module that shells out to the ONE stable home binary\n * (`<homeBin> hook opencode <event> --connector <id>`) over child_process,\n * feeds it the OpenCode payload as JSON on stdin, and JSON.parses the\n * normalized HookResponse back from stdout. The same universal json-stdio\n * dispatcher every other host uses (runtime/hook-entrypoint) thus serves the\n * ts-plugin host too — one entrypoint, every paradigm.\n *\n * MCP registration:\n * - config file: opencode.json\n * user scope → ~/.config/opencode/opencode.json\n * project scope → <projectDir>/opencode.json\n * - root key: \"mcp\" (NOT \"mcpServers\").\n * - stdio server → { type: \"local\", command: [exe, ...args], environment }\n * (command is an ARRAY, env key is \"environment\").\n * - remote server → { type: \"remote\", url }.\n * OpenCode documents no native ${env:VAR} interpolation token, so env/url refs\n * are resolved to literals at install time (resolveEnvRefsDeep).\n *\n * Hooks (ts-plugin):\n * - synthesizePlugin(ctx) builds one self-contained ESM bridge module.\n * - installHooks(ctx) writes it into the OpenCode plugin dir\n * user scope → ~/.config/opencode/plugin/<id>.js\n * project scope → <projectDir>/.opencode/plugin/<id>.js\n * OpenCode auto-loads every file in the plugin dir, so writing the file is\n * sufficient — we do NOT also edit the opencode.json \"plugin\" array.\n *\n * Event mapping (only the events the connector declares are emitted):\n * PreToolUse → \"tool.execute.before\" (can mutate output.args; throw to deny)\n * PostToolUse → \"tool.execute.after\" (can mutate output.output)\n * SessionStart → \"experimental.chat.system.transform\" (no real SessionStart\n * hook upstream — #14808/#5409; this is the verified surrogate context-mode\n * uses; we inject additionalContext into output.system).\n *\n * Capability degradations (documented, never thrown):\n * - OpenCode has no \"ask\" gate. A decision of \"ask\" degrades to a block (throw\n * with the reason) in tool.execute.before — the safe direction.\n */\n\nimport {\n chmodSync,\n existsSync,\n mkdirSync,\n readFileSync,\n rmSync,\n writeFileSync,\n} from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { dirname, join } from \"node:path\";\n\nimport { BaseAdapter } from \"../base.js\";\nimport type {\n Adapter,\n GeneratedPluginFile,\n HookReply,\n InstallContext,\n MemoryTarget,\n NormalizedEvent,\n} from \"../spi.js\";\nimport type {\n ChangeRecord,\n CommandDef,\n DetectedPlatform,\n HealthCheck,\n HookEventName,\n HookParadigm,\n HookResponse,\n PlatformCapabilities,\n PlatformId,\n PostToolUseEvent,\n PreToolUseEvent,\n ServerDef,\n SessionStartEvent,\n SkillDef,\n SubagentDef,\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 = \"opencode\";\nconst MCP_ROOT_KEY = \"mcp\";\n\n/**\n * Canonical → OpenCode event name map. A connector hook event is only emitted\n * by the generated plugin when it appears here AND is declared by the connector.\n */\nconst EVENT_TO_OPENCODE: Partial<Record<HookEventName, string>> = {\n PreToolUse: \"tool.execute.before\",\n PostToolUse: \"tool.execute.after\",\n // OpenCode lacks a real SessionStart hook (#14808 / #5409). The verified\n // surrogate is experimental.chat.system.transform, which receives the system\n // prompt array; we inject additionalContext there.\n SessionStart: \"experimental.chat.system.transform\",\n};\n\n/** Raw payload the generated plugin posts to the universal hook entrypoint. */\ninterface OpenCodeBridgePayload {\n toolName?: string;\n toolInput?: Record<string, unknown>;\n toolOutput?: string;\n isError?: boolean;\n sessionId?: string;\n projectDir?: string;\n}\n\n/** Native MCP server entry shapes OpenCode accepts under the \"mcp\" key. */\ninterface OpenCodeLocalServer {\n type: \"local\";\n command: string[];\n environment?: Record<string, string>;\n enabled?: boolean;\n}\ninterface OpenCodeRemoteServer {\n type: \"remote\";\n url: string;\n enabled?: boolean;\n}\n\nexport class OpenCodeAdapter extends BaseAdapter implements Adapter {\n readonly id: PlatformId = HOST;\n readonly name = \"OpenCode\";\n readonly paradigm: HookParadigm = \"ts-plugin\";\n\n readonly capabilities: PlatformCapabilities = {\n // Memory surface: AGENTS.md-first managed block. memoryTargets below probes\n // project scope (CLAUDE.md is opencode's fallback ONLY when AGENTS.md is\n // absent — creating AGENTS.md beside it would shadow the user's rules).\n supportsMemory: true,\n preToolUse: true,\n postToolUse: true,\n // OpenCode's compaction hook is experimental and not wired here.\n preCompact: false,\n sessionStart: true,\n sessionEnd: false,\n userPromptSubmit: false,\n stop: false,\n notification: false,\n // Newer events: OpenCode HAS a decision-capable `permission.ask` plugin\n // hook upstream, but it is NOT wired here (E1 keeps this adapter\n // degrade-only); subagents run as child sessions (bus events only — no\n // dedicated lifecycle hook) and tool failure is merged into\n // tool.execute.after / session.error. permissionRequest /\n // postToolUseFailure / subagentStart / subagentStop stay unset — the\n // generated bridge never references them and install reports them as\n // \"unsupported here\".\n // tool.execute.before mutates output.args → input rewrite supported.\n canModifyArgs: true,\n // tool.execute.after mutates output.output → output rewrite supported.\n canModifyOutput: true,\n // injected via experimental.chat.system.transform at session start.\n canInjectSessionContext: true,\n transports: [\"stdio\", \"sse\", \"http\"],\n // Content surfaces: OpenCode authors all three natively under <ocDir>.\n supportsCommands: true,\n supportsSkills: true,\n supportsSubagents: true,\n };\n\n // ── Detection ──────────────────────────────────────────────────────────\n\n detectInstalled(projectDir: string): DetectedPlatform {\n const userConfigDir = join(homedir(), \".config\", \"opencode\");\n const userConfig = join(userConfigDir, \"opencode.json\");\n const projectConfig = join(projectDir, \"opencode.json\");\n\n const userInstalled = existsSync(userConfigDir) || existsSync(userConfig);\n const projInstalled = existsSync(projectConfig);\n const installed = userInstalled || projInstalled;\n\n // Report the marker that actually matched so a project-only install isn't\n // misreported as a (non-existent) user install.\n const scope = projInstalled && !userInstalled ? \"project\" : \"user\";\n const configPath = scope === \"project\" ? projectConfig : userConfig;\n\n return {\n id: this.id,\n name: this.name,\n installed,\n paradigm: this.paradigm,\n capabilities: this.capabilities,\n configPath,\n scope,\n reason: installed\n ? scope === \"project\"\n ? `found project OpenCode config at ${projectConfig}`\n : `found OpenCode config under ${userConfigDir}`\n : `no OpenCode config at ${userConfigDir}`,\n confidence: installed ? \"high\" : \"low\",\n };\n }\n\n // ── Memory surface: AGENTS.md / CLAUDE.md-fallback probe (project) ──────\n // OpenCode reads project AGENTS.md, falling back to CLAUDE.md ONLY when no\n // AGENTS.md exists. If the user relies on that CLAUDE.md fallback, CREATING\n // AGENTS.md beside it would shadow their own rules — so the block goes into\n // the file opencode actually reads today; AGENTS.md is created only when\n // neither exists. User scope (~/.config/opencode/AGENTS.md) stays on the\n // BaseAdapter default.\n protected override memoryTargets(ctx: InstallContext): MemoryTarget[] {\n if (this.memoryOverride(ctx)?.path || ctx.scope !== \"project\") {\n return super.memoryTargets(ctx);\n }\n const agentsMd = join(ctx.projectDir, \"AGENTS.md\");\n if (existsSync(agentsMd)) {\n return [{ path: agentsMd, reason: \"AGENTS.md (opencode's primary project rules file)\" }];\n }\n const claudeMd = join(ctx.projectDir, \"CLAUDE.md\");\n if (existsSync(claudeMd)) {\n return [\n {\n path: claudeMd,\n reason:\n \"CLAUDE.md (opencode's fallback rules file — creating AGENTS.md would shadow it)\",\n },\n ];\n }\n return [{ path: agentsMd, reason: \"AGENTS.md standard (created; no opencode rules file yet)\" }];\n }\n\n // ── Native paths ───────────────────────────────────────────────────────\n\n getConfigDir(ctx: InstallContext): string {\n return ctx.scope === \"project\"\n ? ctx.projectDir\n : join(homedir(), \".config\", \"opencode\");\n }\n\n getServerConfigPath(ctx: InstallContext): string {\n return join(this.getConfigDir(ctx), \"opencode.json\");\n }\n\n /**\n * For ts-plugin hosts the \"hook config path\" is the generated plugin FILE.\n * OpenCode auto-loads every file in the plugin dir; writing this file IS the\n * registration.\n */\n getHookConfigPath(ctx: InstallContext): string {\n return join(this.pluginDir(ctx), this.pluginFileName(ctx));\n }\n\n /** Plugin directory OpenCode auto-loads modules from, per scope. */\n private pluginDir(ctx: InstallContext): string {\n return ctx.scope === \"project\"\n ? join(ctx.projectDir, \".opencode\", \"plugin\")\n : join(homedir(), \".config\", \"opencode\", \"plugin\");\n }\n\n /** Plugin module file name (one per connector, kebab-case id). */\n private pluginFileName(ctx: InstallContext): string {\n return `${ctx.connector.id}.js`;\n }\n\n // ── MCP server install / uninstall ─────────────────────────────────────\n\n installServer(ctx: InstallContext): ChangeRecord[] {\n const server = this.effectiveServer(ctx);\n const serverPath = this.getServerConfigPath(ctx);\n\n if (!server) {\n return [\n {\n platform: this.id,\n action: \"skip\",\n path: serverPath,\n detail: ctx.connector.server\n ? \"server registration disabled for opencode\"\n : \"connector declares no MCP server\",\n },\n ];\n }\n\n const entry = this.renderServerEntry(ctx, server);\n return [\n this.upsertServerInJson(\n serverPath,\n MCP_ROOT_KEY,\n ctx.connector.id,\n entry,\n ctx.dryRun,\n ),\n ];\n }\n\n uninstallServer(ctx: InstallContext): ChangeRecord[] {\n const serverPath = this.getServerConfigPath(ctx);\n return [\n this.removeServerFromJson(\n serverPath,\n MCP_ROOT_KEY,\n ctx.connector.id,\n ctx.dryRun,\n ),\n ];\n }\n\n /** Resolve the per-platform server override into an effective ServerDef. */\n private effectiveServer(ctx: InstallContext): ServerDef | undefined {\n const override = ctx.connector.platforms[HOST]?.server;\n if (override === false) return undefined;\n const base = ctx.connector.server;\n if (!base) return undefined;\n return override && typeof override === \"object\" ? { ...base, ...override } : base;\n }\n\n /**\n * Render a normalized ServerDef into OpenCode's native \"mcp\" entry.\n *\n * stdio → { type: \"local\", command: [exe, ...args], environment }\n * remote → { type: \"remote\", url }\n *\n * OpenCode flattens command+args into a single ARRAY. When telemetry wrapping\n * applies, the wrapper's command+args (which already include the real command\n * tail after `--`) become the head of that array.\n */\n private renderServerEntry(\n ctx: InstallContext,\n server: ServerDef,\n ): OpenCodeLocalServer | OpenCodeRemoteServer {\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 // OpenCode has no native interpolation token → resolve to literals.\n const commandArray = resolveEnvRefsDeep([command, ...args]).filter(\n (s) => s !== \"\",\n );\n const entry: OpenCodeLocalServer = {\n type: \"local\",\n command: commandArray,\n };\n const environment = this.renderEnv(server.env);\n if (environment) entry.environment = environment;\n if (server.enabled === false) entry.enabled = false;\n return entry;\n }\n\n // sse / http / ws (any remote transport) — OpenCode registers a URL.\n const entry: OpenCodeRemoteServer = {\n type: \"remote\",\n url: resolveEnvRefsDeep(server.url ?? \"\"),\n };\n if (server.enabled === false) entry.enabled = false;\n return entry;\n }\n\n /**\n * Render env values. OpenCode documents no native interpolation token, so\n * resolve every ${env:VAR} reference to a literal 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 // ── Hook install / uninstall (ts-plugin) ───────────────────────────────\n\n installHooks(ctx: InstallContext): ChangeRecord[] {\n const pluginPath = this.getHookConfigPath(ctx);\n\n if (ctx.connector.platforms[HOST]?.hooks === false) {\n return [\n {\n platform: this.id,\n action: \"skip\",\n path: pluginPath,\n detail: \"hooks disabled for opencode\",\n },\n ];\n }\n if (ctx.connector.hookEvents.length === 0) {\n return [\n {\n platform: this.id,\n action: \"skip\",\n path: pluginPath,\n detail: \"connector declares no hooks\",\n },\n ];\n }\n\n const files = this.synthesizePlugin(ctx);\n const changes: ChangeRecord[] = [];\n\n for (const file of files) {\n // Idempotent: compare existing contents before writing.\n const before = existsSync(file.path)\n ? this.safeRead(file.path)\n : undefined;\n let action: ChangeRecord[\"action\"];\n if (before === undefined) action = \"create\";\n else if (before === file.contents) action = \"skip\";\n else action = \"update\";\n\n if (action !== \"skip\" && !ctx.dryRun) {\n ensureDir(dirname(file.path));\n writeFileSync(file.path, file.contents, \"utf8\");\n // 0644 — readable plugin module; the executable bit is irrelevant for an\n // imported ESM module, but honor the SPI flag if a host ever needs it.\n chmodSync(file.path, file.executable ? 0o755 : 0o644);\n }\n\n changes.push({\n platform: this.id,\n action,\n path: file.path,\n detail: `opencode plugin module (${this.hookDetail(ctx)})`,\n });\n }\n\n return changes;\n }\n\n /**\n * Human-facing summary of which declared events the synthesized module ACTUALLY\n * wires. Only events present in EVENT_TO_OPENCODE are mapped/wired; any declared\n * event with no OpenCode mapping (e.g. UserPromptSubmit) is reported separately\n * as \"unsupported here\" so the detail never overstates coverage.\n */\n private hookDetail(ctx: InstallContext): string {\n const declared = ctx.connector.hookEvents;\n const mapped = declared.filter((e) => EVENT_TO_OPENCODE[e] !== undefined);\n const unsupported = declared.filter((e) => EVENT_TO_OPENCODE[e] === undefined);\n const base = mapped.join(\",\");\n return unsupported.length > 0\n ? `${base}; unsupported here: ${unsupported.join(\",\")}`\n : base;\n }\n\n uninstallHooks(ctx: InstallContext): ChangeRecord[] {\n const pluginPath = this.getHookConfigPath(ctx);\n if (!existsSync(pluginPath)) {\n return [\n {\n platform: this.id,\n action: \"skip\",\n path: pluginPath,\n detail: \"no opencode plugin module present\",\n },\n ];\n }\n if (!ctx.dryRun) rmSync(pluginPath, { force: true });\n return [\n {\n platform: this.id,\n action: \"remove\",\n path: pluginPath,\n detail: \"opencode plugin module\",\n },\n ];\n }\n\n // ── Content surfaces: commands / skills / subagents ──────────────────────\n // CONTENT-ONLY: pure native-file writers under <ocDir>/{commands,skills,\n // agent}. No runtime dispatch, no home-bin pointer, no telemetry wrap. Each\n // method is idempotent (byte-identical → skip) via BaseAdapter.writeContentFile\n // and reversible via removeContentFile. Honors platforms[\"opencode\"]\n // per-surface false to skip.\n //\n // <ocDir> is NOT getConfigDir for project scope: opencode.json lives at the\n // project ROOT, but content surfaces are read from <projectDir>/.opencode/\n // (e.g. .opencode/skills/<name>/SKILL.md per opencode.ai/docs/skills) — the\n // 0.1.0 adapter wrote <projectDir>/skills, which OpenCode never reads.\n //\n // NOTE on dirs: commands live in commands/<name>.md and skills in\n // skills/<name>/SKILL.md, but subagents use the SINGULAR \"agent/\" dir\n // (agent/<name>.md) — the OpenCode loader/CLI historically uses singular\n // (anomalyco/opencode#14410); singular is the safe choice.\n\n private contentRootDir(ctx: InstallContext): string {\n return ctx.scope === \"project\"\n ? join(ctx.projectDir, \".opencode\")\n : this.getConfigDir(ctx);\n }\n private commandsDir(ctx: InstallContext): string {\n return join(this.contentRootDir(ctx), \"commands\");\n }\n private skillsDir(ctx: InstallContext): string {\n return join(this.contentRootDir(ctx), \"skills\");\n }\n private agentDir(ctx: InstallContext): string {\n return join(this.contentRootDir(ctx), \"agent\");\n }\n\n /** Native command file path: <ocDir>/commands/<name>.md. */\n private commandPath(ctx: InstallContext, name: string): string {\n return join(this.commandsDir(ctx), `${name}.md`);\n }\n /** Native skill dir: <ocDir>/skills/<name>. */\n private skillDir(ctx: InstallContext, name: string): string {\n return join(this.skillsDir(ctx), name);\n }\n /** Native subagent file path: <ocDir>/agent/<name>.md (SINGULAR dir). */\n private subagentPath(ctx: InstallContext, name: string): string {\n return join(this.agentDir(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 opencode\" }];\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 md+frontmatter (description, agent, model, subtask). */\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.subtask !== undefined) frontmatter.subtask = cmd.subtask;\n // `agent` is not a core CommandDef field; it arrives via `extra` (escape\n // hatch) and is merged last so a connector can pin a specific OpenCode agent.\n if (cmd.extra) Object.assign(frontmatter, cmd.extra);\n return this.renderFrontmatterMd(frontmatter, cmd.prompt);\n }\n\n // ── 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 opencode\" }];\n }\n if (connector.skills.length === 0) {\n return [{ platform: this.id, action: \"skip\", detail: \"connector declares no skills\" }];\n }\n const changes: ChangeRecord[] = [];\n for (const skill of connector.skills) {\n const dir = this.skillDir(ctx, skill.name);\n changes.push(\n this.writeContentFile(join(dir, \"SKILL.md\"), this.renderSkill(skill), ctx.dryRun),\n );\n // Bundle any resource files beside SKILL.md (relative path → contents).\n // Defense-in-depth: skip+warn on any key that escapes the skill dir\n // (config-time validation already rejects these, but never trust input).\n for (const [rel, contents] of Object.entries(skill.resources ?? {})) {\n const target = this.resolveWithin(dir, rel);\n if (target === null) {\n changes.push({\n platform: this.id,\n action: \"warn\",\n detail: `skill resource \"${rel}\" escapes the skill dir; skipped`,\n });\n continue;\n }\n changes.push(this.writeContentFile(target, contents, ctx.dryRun));\n }\n }\n return changes;\n }\n\n override uninstallSkills(ctx: InstallContext): ChangeRecord[] {\n const { connector } = ctx;\n if (connector.skills.length === 0) {\n return [{ platform: this.id, action: \"skip\", detail: \"connector declares no skills\" }];\n }\n const changes: ChangeRecord[] = [];\n for (const skill of connector.skills) {\n const dir = this.skillDir(ctx, skill.name);\n // Remove only the files we wrote (SKILL.md + declared resources), then the\n // skill dir itself when we own its full contents.\n changes.push(this.removeContentFile(join(dir, \"SKILL.md\"), ctx.dryRun));\n for (const rel of Object.keys(skill.resources ?? {})) {\n const target = this.resolveWithin(dir, rel);\n if (target === null) continue; // never delete outside the skill dir\n changes.push(this.removeContentFile(target, ctx.dryRun));\n }\n // Only remove the skill dir when WE own its full contents — never rm -rf a\n // dir that still holds user-added / sibling-tool / shared files.\n changes.push(this.removeDirIfEmpty(dir, ctx.dryRun));\n }\n return changes;\n }\n\n /**\n * Render a skill's SKILL.md (UNIFORM across platforms): frontmatter\n * (name, description + optional model, allowed-tools, disable-model-invocation)\n * + markdown body. Only the parent dir differs per platform.\n */\n private renderSkill(skill: SkillDef): string {\n const frontmatter: Record<string, unknown> = {\n name: skill.name,\n description: skill.description,\n };\n if (skill.model !== undefined) frontmatter.model = skill.model;\n const allow = skill.tools?.allow;\n if (allow && allow.length > 0) frontmatter[\"allowed-tools\"] = allow.join(\", \");\n if (skill.disableModelInvocation !== undefined) {\n frontmatter[\"disable-model-invocation\"] = skill.disableModelInvocation;\n }\n if (skill.extra) Object.assign(frontmatter, skill.extra);\n return this.renderFrontmatterMd(frontmatter, skill.body);\n }\n\n // ── 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 opencode\" }];\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 /**\n * Render a subagent to md+frontmatter. OpenCode's shape is\n * (description, mode:\"subagent\", model, permission) with the system prompt as\n * the body. `name` is NOT a frontmatter field — it comes from the filename.\n * `permission` is derived from the coarse `readonly` knob: a readonly agent\n * gets a per-tool deny map (edit/bash) so it cannot mutate the workspace.\n */\n private renderSubagent(agent: SubagentDef): string {\n const frontmatter: Record<string, unknown> = {\n description: agent.description,\n mode: \"subagent\",\n };\n if (agent.model !== undefined) frontmatter.model = agent.model;\n if (agent.readonly === true) {\n // Per-tool permission map: deny mutating tools for a readonly subagent.\n frontmatter.permission = { edit: \"deny\", bash: \"deny\" };\n }\n if (agent.extra) Object.assign(frontmatter, agent.extra);\n return this.renderFrontmatterMd(frontmatter, agent.prompt);\n }\n\n // ── ts-plugin synthesis ────────────────────────────────────────────────\n\n /**\n * Build ONE self-contained ESM bridge module for OpenCode.\n *\n * The module imports nothing from agent-connector. It embeds two constants\n * (the absolute home-bin path and the connector id) and a `bridge()` helper\n * that shells out to the universal hook entrypoint via execFileSync, feeding\n * the OpenCode payload on stdin and JSON.parsing the normalized HookResponse\n * back from stdout (fail-open: any error → null). Its default export is the\n * OpenCode plugin factory returning an object keyed only by the OpenCode event\n * names for the events this connector actually declares.\n */\n synthesizePlugin(ctx: InstallContext): GeneratedPluginFile[] {\n const path = this.getHookConfigPath(ctx);\n const contents = this.buildPluginSource(ctx);\n return [{ path, contents, executable: false }];\n }\n\n /** Compose the generated plugin source with plain string concatenation. */\n private buildPluginSource(ctx: InstallContext): string {\n const homeBin = JSON.stringify(ctx.homeBinPath);\n const connectorId = JSON.stringify(ctx.connector.id);\n\n // The OpenCode event keys this connector declares (and that we can map).\n const events = ctx.connector.hookEvents.filter(\n (e): e is HookEventName => EVENT_TO_OPENCODE[e] !== undefined,\n );\n const has = (e: HookEventName) => events.includes(e);\n\n const header = `/**\n * AUTO-GENERATED by agent-connector — DO NOT EDIT.\n *\n * Self-contained OpenCode plugin bridge for connector ${ctx.connector.id}.\n * It imports nothing from agent-connector: every hook invocation shells out to\n * the stable home binary's universal entrypoint and JSON-parses the normalized\n * response. Fail-open: any bridge error degrades to \"allow\".\n */\nimport { execFileSync, execSync } from \"node:child_process\";\n\nconst HOME_BIN = ${homeBin};\nconst CONNECTOR_ID = ${connectorId};\n\n/**\n * Invoke the universal hook entrypoint for one event.\n * @param {string} event canonical event name (PreToolUse|PostToolUse|SessionStart)\n * @param {object} payload OpenCode-shaped payload posted on stdin\n * @returns {object|null} normalized HookResponse, or null on any failure\n */\nfunction bridge(event, payload) {\n try {\n // On Windows HOME_BIN is the agent-connector.cmd launcher: Node cannot\n // execFile a batch file, and shell+args is deprecated (DEP0190), so run one\n // quoted command line via a shell. POSIX keeps the direct execFile (no shell).\n const args = [\"hook\", \"opencode\", event, \"--connector\", CONNECTOR_ID];\n const opts = { input: JSON.stringify(payload), encoding: \"utf8\" };\n const stdout =\n process.platform === \"win32\"\n ? execSync([HOME_BIN, ...args].map((a) => '\"' + a + '\"').join(\" \"), opts)\n : execFileSync(HOME_BIN, args, opts);\n const text = (stdout || \"\").trim();\n if (text === \"\") return { decision: \"allow\" };\n return JSON.parse(text);\n } catch {\n // Fail-open — never wedge a tool call on a bridge error.\n return null;\n }\n}\n`;\n\n const handlers: string[] = [];\n\n if (has(\"PreToolUse\")) {\n handlers.push(` // PreToolUse → block (throw) / rewrite args (mutate output.args).\n \"tool.execute.before\": async (input, output) => {\n const payload = {\n toolName: input.tool ?? \"\",\n toolInput: (output && output.args) ?? {},\n sessionId: input.sessionID ?? \"\",\n projectDir: PROJECT_DIR,\n };\n const res = bridge(\"PreToolUse\", payload);\n if (!res) return;\n // OpenCode has no \"ask\" gate — degrade \"ask\" to a block (safe direction).\n if (res.decision === \"deny\" || res.decision === \"ask\") {\n throw new Error(res.reason || \"Blocked by ${ctx.connector.id}\");\n }\n if (res.updatedInput && output && output.args) {\n Object.assign(output.args, res.updatedInput);\n }\n },`);\n }\n\n if (has(\"PostToolUse\")) {\n handlers.push(` // PostToolUse → observe / rewrite tool output (mutate output.output).\n \"tool.execute.after\": async (input, output) => {\n const payload = {\n toolName: input.tool ?? \"\",\n toolInput: input.args ?? {},\n toolOutput: output ? output.output : undefined,\n sessionId: input.sessionID ?? \"\",\n projectDir: PROJECT_DIR,\n };\n const res = bridge(\"PostToolUse\", payload);\n if (!res) return;\n if (typeof res.updatedOutput === \"string\" && output) {\n output.output = res.updatedOutput;\n }\n },`);\n }\n\n if (has(\"SessionStart\")) {\n handlers.push(` // SessionStart surrogate → inject context into the system prompt.\n // OpenCode has no real SessionStart hook (#14808 / #5409); the\n // experimental.chat.system.transform hook is the verified injection point.\n \"experimental.chat.system.transform\": async (input, output) => {\n const payload = {\n sessionId: (input && input.sessionID) ?? \"\",\n projectDir: PROJECT_DIR,\n };\n const res = bridge(\"SessionStart\", payload);\n if (!res) return;\n if (res.additionalContext && output && Array.isArray(output.system)) {\n // Insert at index 1 (after the header) to preserve OpenCode's\n // prompt-cache fold (header must remain system[0]).\n output.system.splice(1, 0, res.additionalContext);\n }\n },`);\n }\n\n const factory = `\nexport default async function (ctx) {\n // ctx.directory is the OpenCode project root; fall back to cwd.\n const PROJECT_DIR =\n (ctx && (ctx.directory || (ctx.worktree && ctx.worktree.path))) ||\n process.cwd();\n\n return {\n${handlers.join(\"\\n\")}\n };\n}\n`;\n\n return header + factory;\n }\n\n // ── Runtime: parse OUR bridge payload → normalized event ───────────────\n\n /**\n * `raw` is the payload OUR generated plugin posts (NOT a host-native shape):\n * { toolName, toolInput, toolOutput?, isError?, sessionId, projectDir }\n * so this maps straight through.\n */\n parseEvent(event: HookEventName, raw: unknown): NormalizedEvent {\n const input = (raw ?? {}) as OpenCodeBridgePayload;\n const base = {\n hostPlatform: HOST,\n connectorId: \"\",\n sessionId: typeof input.sessionId === \"string\" ? input.sessionId : \"\",\n raw,\n ...(typeof input.projectDir === \"string\"\n ? { projectDir: input.projectDir }\n : {}),\n } as const;\n\n switch (event) {\n case \"PreToolUse\": {\n const ev: PreToolUseEvent = {\n ...base,\n toolName: input.toolName ?? \"\",\n toolInput: input.toolInput ?? {},\n };\n return ev;\n }\n case \"PostToolUse\": {\n const ev: PostToolUseEvent = {\n ...base,\n toolName: input.toolName ?? \"\",\n toolInput: input.toolInput ?? {},\n ...(typeof input.toolOutput === \"string\"\n ? { toolOutput: input.toolOutput }\n : {}),\n ...(typeof input.isError === \"boolean\"\n ? { isError: input.isError }\n : {}),\n };\n return ev;\n }\n case \"SessionStart\": {\n const ev: SessionStartEvent = { ...base, source: \"startup\" };\n return ev;\n }\n default:\n // Other canonical events are not surfaced by OpenCode; treat as a\n // session-start-shaped no-op so the dispatcher fails open gracefully.\n return { ...base, source: \"startup\" } satisfies SessionStartEvent;\n }\n }\n\n // ── Runtime: normalized response → reply the generated bridge parses ───\n\n /**\n * Unlike json-stdio hosts (whose reply is the host's NATIVE control payload),\n * OUR generated bridge consumes this stdout directly. So the reply body is the\n * NORMALIZED HookResponse itself — the bridge JSON.parses it and reads\n * decision / updatedInput / updatedOutput / additionalContext.\n */\n formatReply(_event: HookEventName, response: HookResponse): HookReply {\n return {\n exitCode: 0,\n stdout: JSON.stringify(response ?? { decision: \"allow\" }),\n };\n }\n\n // ── Diagnostics ────────────────────────────────────────────────────────\n\n override getHealthChecks(ctx: InstallContext): readonly HealthCheck[] {\n const serverPath = this.getServerConfigPath(ctx);\n const pluginPath = this.getHookConfigPath(ctx);\n const connectorId = ctx.connector.id;\n const hasHooks = ctx.connector.hookEvents.length > 0;\n\n const checks: HealthCheck[] = [\n {\n name: `${this.name}: opencode.json present`,\n check: () =>\n existsSync(serverPath)\n ? { status: \"OK\", detail: serverPath }\n : { status: \"FAIL\", detail: `not found: ${serverPath}` },\n },\n {\n name: `${this.name}: mcp.${connectorId} registered`,\n check: () => {\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> }>(\n serverPath,\n );\n const bucket = cfg?.[MCP_ROOT_KEY];\n if (!cfg || !bucket) {\n return { status: \"FAIL\", detail: `no ${MCP_ROOT_KEY} in ${serverPath}` };\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 ${serverPath}`,\n };\n },\n },\n {\n name: `${this.name}: plugin module present`,\n check: () => {\n if (!hasHooks) return { status: \"OK\", detail: \"no hooks declared\" };\n return existsSync(pluginPath)\n ? { status: \"OK\", detail: pluginPath }\n : { status: \"FAIL\", detail: `not found: ${pluginPath}` };\n },\n },\n ];\n\n // Content-surface checks: only assert presence of the files this connector\n // declares (skip silently for surfaces it never asked for).\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 /** Read a file, returning undefined on any error (idempotency compare). */\n private safeRead(path: string): string | undefined {\n try {\n return readFileSync(path, \"utf8\");\n } catch {\n return undefined;\n }\n }\n}\n\n/** Create a directory (recursive) if it does not already exist. */\nfunction ensureDir(dir: string): void {\n if (!existsSync(dir)) mkdirSync(dir, { recursive: true });\n}\n\nexport const adapter = new OpenCodeAdapter();\nexport default adapter;\n"],"mappings":"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","names":["entry"]}
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
ALL_FORMATS,
|
|
4
|
+
FEASIBLE_FORMATS,
|
|
5
|
+
installInstructions,
|
|
6
|
+
isPackageFormat,
|
|
7
|
+
packageConnector,
|
|
8
|
+
packageConnectorAll
|
|
9
|
+
} from "./chunk-WNREHWKL.js";
|
|
10
|
+
import {
|
|
11
|
+
fail,
|
|
12
|
+
print
|
|
13
|
+
} from "./chunk-DS3LUFVN.js";
|
|
14
|
+
import {
|
|
15
|
+
findConnectorConfig,
|
|
16
|
+
loadConnectorFromPath
|
|
17
|
+
} from "./chunk-3JCRUROU.js";
|
|
18
|
+
import "./chunk-GSGDG2BV.js";
|
|
19
|
+
import "./chunk-OPXAP3AC.js";
|
|
20
|
+
import "./chunk-7L6ITC4T.js";
|
|
21
|
+
import "./chunk-MEH7GC7R.js";
|
|
22
|
+
import "./chunk-N6HH7K6P.js";
|
|
23
|
+
import "./chunk-TRQKHP7D.js";
|
|
24
|
+
|
|
25
|
+
// src/cli/commands/package.ts
|
|
26
|
+
import { parseArgs } from "util";
|
|
27
|
+
import { join, relative } from "path";
|
|
28
|
+
var HELP = `agent-connector package \u2014 emit a plugin/extension/marketplace bundle.
|
|
29
|
+
|
|
30
|
+
usage: agent-connector package [flags]
|
|
31
|
+
|
|
32
|
+
flags:
|
|
33
|
+
--connector <path> Connector config to package (else auto-discovered).
|
|
34
|
+
--format <fmt> Output format (default: claude-plugin). One of:
|
|
35
|
+
${ALL_FORMATS.join(", ")}
|
|
36
|
+
or "all" to emit every feasible format into <out>/<fmt>/.
|
|
37
|
+
--out <dir> Output directory. Default: <cwd>/dist-plugin.
|
|
38
|
+
--project <dir> Project root for connector discovery (default: cwd).
|
|
39
|
+
--dry-run Compute the file tree without writing anything.
|
|
40
|
+
--help Show this help.`;
|
|
41
|
+
function printFormatResult(format, connectorId, outDir, result) {
|
|
42
|
+
print(` pluginDir: ${result.pluginDir}`);
|
|
43
|
+
if (result.marketplacePath) {
|
|
44
|
+
print(` marketplace: ${relative(outDir, result.marketplacePath)}`);
|
|
45
|
+
}
|
|
46
|
+
print(" emitted files:");
|
|
47
|
+
for (const f of result.files) {
|
|
48
|
+
print(` + ${relative(outDir, f)}`);
|
|
49
|
+
}
|
|
50
|
+
if (result.notes && result.notes.length > 0) {
|
|
51
|
+
print(" notes:");
|
|
52
|
+
for (const n of result.notes) print(` ! ${n}`);
|
|
53
|
+
}
|
|
54
|
+
print(" install:");
|
|
55
|
+
for (const line of installInstructions(format, connectorId, outDir)) {
|
|
56
|
+
print(` ${line}`);
|
|
57
|
+
}
|
|
58
|
+
if (format === "claude-plugin") {
|
|
59
|
+
print(
|
|
60
|
+
" (or let agent-connector drive it: agent-connector install --method marketplace --targets claude-code)"
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
print("");
|
|
64
|
+
}
|
|
65
|
+
async function run(argv) {
|
|
66
|
+
const { values } = parseArgs({
|
|
67
|
+
args: argv,
|
|
68
|
+
options: {
|
|
69
|
+
connector: { type: "string" },
|
|
70
|
+
format: { type: "string", default: "claude-plugin" },
|
|
71
|
+
out: { type: "string" },
|
|
72
|
+
project: { type: "string" },
|
|
73
|
+
"dry-run": { type: "boolean", default: false },
|
|
74
|
+
help: { type: "boolean", default: false }
|
|
75
|
+
},
|
|
76
|
+
allowPositionals: false
|
|
77
|
+
});
|
|
78
|
+
if (values.help) {
|
|
79
|
+
print(HELP);
|
|
80
|
+
return 0;
|
|
81
|
+
}
|
|
82
|
+
const formatArg = values.format ?? "claude-plugin";
|
|
83
|
+
const isAll = formatArg === "all";
|
|
84
|
+
if (!isAll && !isPackageFormat(formatArg)) {
|
|
85
|
+
return fail(
|
|
86
|
+
`invalid --format "${formatArg}" (expected one of: ${ALL_FORMATS.join(", ")}, or "all")`
|
|
87
|
+
);
|
|
88
|
+
}
|
|
89
|
+
const projectDir = values.project ?? process.cwd();
|
|
90
|
+
const configPath = values.connector ?? findConnectorConfig(projectDir);
|
|
91
|
+
if (!configPath) {
|
|
92
|
+
return fail(
|
|
93
|
+
"no connector config found. Pass --connector <path> or add an agent-connector.config.{mjs,js,json} to your project."
|
|
94
|
+
);
|
|
95
|
+
}
|
|
96
|
+
const outDir = values.out ?? `${process.cwd()}/dist-plugin`;
|
|
97
|
+
const dryRun = values["dry-run"];
|
|
98
|
+
const mode = dryRun ? " (dry-run \u2014 nothing written)" : "";
|
|
99
|
+
const { connector } = await loadConnectorFromPath(configPath);
|
|
100
|
+
if (isAll) {
|
|
101
|
+
print(`package "${connector.id}" \u2192 all formats${mode}`);
|
|
102
|
+
print(` outDir: ${outDir}`);
|
|
103
|
+
print("");
|
|
104
|
+
const results = packageConnectorAll(connector, { outDir, dryRun });
|
|
105
|
+
for (const { format: format2, result: result2 } of results) {
|
|
106
|
+
const formatOut = join(outDir, format2);
|
|
107
|
+
print(`\u2500\u2500 ${format2} \u2500\u2500`);
|
|
108
|
+
printFormatResult(format2, connector.id, formatOut, result2);
|
|
109
|
+
}
|
|
110
|
+
print(`emitted ${results.length} formats: ${FEASIBLE_FORMATS.join(", ")}`);
|
|
111
|
+
return 0;
|
|
112
|
+
}
|
|
113
|
+
const format = formatArg;
|
|
114
|
+
let result;
|
|
115
|
+
try {
|
|
116
|
+
result = packageConnector(connector, { outDir, format, dryRun });
|
|
117
|
+
} catch (err) {
|
|
118
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
119
|
+
return fail(message);
|
|
120
|
+
}
|
|
121
|
+
print(`package "${connector.id}" \u2192 ${format}${mode}`);
|
|
122
|
+
print(` outDir: ${outDir}`);
|
|
123
|
+
print("");
|
|
124
|
+
printFormatResult(format, connector.id, outDir, result);
|
|
125
|
+
return 0;
|
|
126
|
+
}
|
|
127
|
+
export {
|
|
128
|
+
run
|
|
129
|
+
};
|
|
130
|
+
//# sourceMappingURL=package-SYPA5POO.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/cli/commands/package.ts"],"sourcesContent":["/**\n * cli/commands/package — emit a marketplace/extension-installable connector bundle.\n *\n * Resolves the connector config (--connector <path>, else findConnectorConfig\n * walking up from the project dir, exactly like install.ts), packages it for the\n * requested --format into --out (default <cwd>/dist-plugin), then prints the\n * emitted file tree plus per-format install instructions.\n *\n * `--format <x>` accepts the full union; `--format all` emits EVERY feasible\n * format, each into <out>/<format>/..., printing install instructions per format.\n * Default --format claude-plugin.\n */\n\nimport { parseArgs } from \"node:util\";\nimport { join, relative } from \"node:path\";\n\nimport { findConnectorConfig, loadConnectorFromPath } from \"../../core/load-connector.js\";\nimport {\n ALL_FORMATS,\n FEASIBLE_FORMATS,\n installInstructions,\n isPackageFormat,\n packageConnector,\n packageConnectorAll,\n type PackageFormat,\n type PackageResult,\n} from \"../../core/package.js\";\nimport { fail, print } from \"../app.js\";\n\nconst HELP = `agent-connector package — emit a plugin/extension/marketplace bundle.\n\nusage: agent-connector package [flags]\n\nflags:\n --connector <path> Connector config to package (else auto-discovered).\n --format <fmt> Output format (default: claude-plugin). One of:\n ${ALL_FORMATS.join(\", \")}\n or \"all\" to emit every feasible format into <out>/<fmt>/.\n --out <dir> Output directory. Default: <cwd>/dist-plugin.\n --project <dir> Project root for connector discovery (default: cwd).\n --dry-run Compute the file tree without writing anything.\n --help Show this help.`;\n\n/** Print the file tree + the per-format install instructions for one bundle. */\nfunction printFormatResult(\n format: PackageFormat,\n connectorId: string,\n outDir: string,\n result: PackageResult,\n): void {\n print(` pluginDir: ${result.pluginDir}`);\n if (result.marketplacePath) {\n print(` marketplace: ${relative(outDir, result.marketplacePath)}`);\n }\n print(\" emitted files:\");\n for (const f of result.files) {\n print(` + ${relative(outDir, f)}`);\n }\n if (result.notes && result.notes.length > 0) {\n print(\" notes:\");\n for (const n of result.notes) print(` ! ${n}`);\n }\n print(\" install:\");\n for (const line of installInstructions(format, connectorId, outDir)) {\n print(` ${line}`);\n }\n // `package` stays a pure emitter (no host CLIs spawned) — but for hosts whose\n // marketplace flow agent-connector can DRIVE, point at the lifecycle verb.\n if (format === \"claude-plugin\") {\n print(\n \" (or let agent-connector drive it: agent-connector install --method marketplace --targets claude-code)\",\n );\n }\n print(\"\");\n}\n\nexport async function run(argv: string[]): Promise<number> {\n const { values } = parseArgs({\n args: argv,\n options: {\n connector: { type: \"string\" },\n format: { type: \"string\", default: \"claude-plugin\" },\n out: { type: \"string\" },\n project: { type: \"string\" },\n \"dry-run\": { type: \"boolean\", default: false },\n help: { type: \"boolean\", default: false },\n },\n allowPositionals: false,\n });\n\n if (values.help) {\n print(HELP);\n return 0;\n }\n\n const formatArg = values.format ?? \"claude-plugin\";\n const isAll = formatArg === \"all\";\n if (!isAll && !isPackageFormat(formatArg)) {\n return fail(\n `invalid --format \"${formatArg}\" (expected one of: ${ALL_FORMATS.join(\", \")}, or \"all\")`,\n );\n }\n\n const projectDir = values.project ?? process.cwd();\n const configPath = values.connector ?? findConnectorConfig(projectDir);\n if (!configPath) {\n return fail(\n \"no connector config found. Pass --connector <path> or add an \" +\n \"agent-connector.config.{mjs,js,json} to your project.\",\n );\n }\n\n const outDir = values.out ?? `${process.cwd()}/dist-plugin`;\n const dryRun = values[\"dry-run\"];\n const mode = dryRun ? \" (dry-run — nothing written)\" : \"\";\n\n const { connector } = await loadConnectorFromPath(configPath);\n\n if (isAll) {\n print(`package \"${connector.id}\" → all formats${mode}`);\n print(` outDir: ${outDir}`);\n print(\"\");\n const results = packageConnectorAll(connector, { outDir, dryRun });\n for (const { format, result } of results) {\n const formatOut = join(outDir, format);\n print(`── ${format} ──`);\n printFormatResult(format, connector.id, formatOut, result);\n }\n print(`emitted ${results.length} formats: ${FEASIBLE_FORMATS.join(\", \")}`);\n return 0;\n }\n\n const format: PackageFormat = formatArg;\n let result: PackageResult;\n try {\n result = packageConnector(connector, { outDir, format, dryRun });\n } catch (err) {\n // Emitter validation errors (e.g. mcp-server-json without\n // publish.registryNamespace) are actionable one-liners — print them as a\n // normal CLI error, never a stack trace.\n const message = err instanceof Error ? err.message : String(err);\n return fail(message);\n }\n\n print(`package \"${connector.id}\" → ${format}${mode}`);\n print(` outDir: ${outDir}`);\n print(\"\");\n printFormatResult(format, connector.id, outDir, result);\n return 0;\n}\n"],"mappings":"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","names":["format","result"]}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
BaseAdapter
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-PD4VFEBY.js";
|
|
5
5
|
import "./chunk-7L6ITC4T.js";
|
|
6
|
+
import "./chunk-N6HH7K6P.js";
|
|
6
7
|
import "./chunk-TRQKHP7D.js";
|
|
7
8
|
|
|
8
9
|
// src/adapters/pi/index.ts
|
|
@@ -13,9 +14,18 @@ var HOST = "pi";
|
|
|
13
14
|
var PiAdapter = class extends BaseAdapter {
|
|
14
15
|
id = HOST;
|
|
15
16
|
name = "Pi";
|
|
17
|
+
/**
|
|
18
|
+
* Pi has no MCP surface at all — the paradigm label "mcp-only" is backwards
|
|
19
|
+
* for a host with NO writable MCP config. Pi is purely a content-surface host
|
|
20
|
+
* (skills + prompt templates). Use "mcp-only" only because the HookParadigm
|
|
21
|
+
* union has no "no-mcp" variant; MCP is explicitly unsupported below.
|
|
22
|
+
*/
|
|
16
23
|
paradigm = "mcp-only";
|
|
17
24
|
capabilities = {
|
|
18
|
-
//
|
|
25
|
+
// Memory surface: AGENTS.md-first managed block via the BaseAdapter default
|
|
26
|
+
// (user scope: ~/.pi/agent/AGENTS.md per base.ts AGENTS_MD_USER_PATHS).
|
|
27
|
+
supportsMemory: true,
|
|
28
|
+
// Pi has no json-stdio / ts-plugin lifecycle hook system.
|
|
19
29
|
preToolUse: false,
|
|
20
30
|
postToolUse: false,
|
|
21
31
|
preCompact: false,
|
|
@@ -27,10 +37,10 @@ var PiAdapter = class extends BaseAdapter {
|
|
|
27
37
|
canModifyArgs: false,
|
|
28
38
|
canModifyOutput: false,
|
|
29
39
|
canInjectSessionContext: false,
|
|
30
|
-
// No writable MCP config
|
|
40
|
+
// No writable MCP config.
|
|
31
41
|
transports: [],
|
|
32
|
-
// Content surfaces: skills
|
|
33
|
-
supportsCommands:
|
|
42
|
+
// Content surfaces: prompt-template commands + skills.
|
|
43
|
+
supportsCommands: true,
|
|
34
44
|
supportsSkills: true,
|
|
35
45
|
supportsSubagents: false
|
|
36
46
|
};
|
|
@@ -56,13 +66,16 @@ var PiAdapter = class extends BaseAdapter {
|
|
|
56
66
|
};
|
|
57
67
|
}
|
|
58
68
|
// ── Native paths ─────────────────────────────────────────────────────────
|
|
69
|
+
/**
|
|
70
|
+
* Base config dir (used for server/hook doctor paths only; content surfaces
|
|
71
|
+
* use dedicated helpers below so the scope split is explicit).
|
|
72
|
+
*/
|
|
59
73
|
getConfigDir(ctx) {
|
|
60
74
|
return ctx.scope === "project" ? join(ctx.projectDir, ".pi") : join(homedir(), ".pi");
|
|
61
75
|
}
|
|
62
76
|
/**
|
|
63
|
-
* Pi has no writable MCP config
|
|
64
|
-
*
|
|
65
|
-
* itself always skips.
|
|
77
|
+
* Pi has no writable MCP config. Returning the config dir keeps the generic
|
|
78
|
+
* doctor/backup sensible while installServer always skips.
|
|
66
79
|
*/
|
|
67
80
|
getServerConfigPath(ctx) {
|
|
68
81
|
return this.getConfigDir(ctx);
|
|
@@ -71,6 +84,28 @@ var PiAdapter = class extends BaseAdapter {
|
|
|
71
84
|
getHookConfigPath(ctx) {
|
|
72
85
|
return this.getConfigDir(ctx);
|
|
73
86
|
}
|
|
87
|
+
/**
|
|
88
|
+
* Prompt-templates dir (slash commands):
|
|
89
|
+
* project scope → <projectDir>/.pi/prompts/
|
|
90
|
+
* user scope → ~/.pi/agent/prompts/
|
|
91
|
+
* (ground truth: docs/prompt-templates.md)
|
|
92
|
+
*/
|
|
93
|
+
promptsDir(ctx) {
|
|
94
|
+
return ctx.scope === "project" ? join(ctx.projectDir, ".pi", "prompts") : join(homedir(), ".pi", "agent", "prompts");
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Skills dir:
|
|
98
|
+
* project scope → <projectDir>/.pi/skills/
|
|
99
|
+
* user scope → ~/.pi/agent/skills/
|
|
100
|
+
* (ground truth: ~/.pi/agent/skills/ is what Pi actually reads for global skills)
|
|
101
|
+
*/
|
|
102
|
+
skillsDir(ctx) {
|
|
103
|
+
return ctx.scope === "project" ? join(ctx.projectDir, ".pi", "skills") : join(homedir(), ".pi", "agent", "skills");
|
|
104
|
+
}
|
|
105
|
+
/** Native skill dir: <skillsDir>/<name>. */
|
|
106
|
+
skillDir(ctx, name) {
|
|
107
|
+
return join(this.skillsDir(ctx), name);
|
|
108
|
+
}
|
|
74
109
|
// ── MCP server (unavailable — Pi has no writable MCP config) ─────────────
|
|
75
110
|
installServer(_ctx) {
|
|
76
111
|
return [
|
|
@@ -90,13 +125,13 @@ var PiAdapter = class extends BaseAdapter {
|
|
|
90
125
|
}
|
|
91
126
|
];
|
|
92
127
|
}
|
|
93
|
-
// ── Hooks (unavailable — Pi
|
|
128
|
+
// ── Hooks (unavailable — Pi has no json-stdio/ts-plugin hook layer) ───────
|
|
94
129
|
installHooks(_ctx) {
|
|
95
130
|
return [
|
|
96
131
|
{
|
|
97
132
|
platform: this.id,
|
|
98
133
|
action: "skip",
|
|
99
|
-
detail: "hooks unavailable (Pi
|
|
134
|
+
detail: "hooks unavailable (Pi has no hook layer)"
|
|
100
135
|
}
|
|
101
136
|
];
|
|
102
137
|
}
|
|
@@ -105,21 +140,60 @@ var PiAdapter = class extends BaseAdapter {
|
|
|
105
140
|
{
|
|
106
141
|
platform: this.id,
|
|
107
142
|
action: "skip",
|
|
108
|
-
detail: "hooks unavailable (Pi
|
|
143
|
+
detail: "hooks unavailable (Pi has no hook layer)"
|
|
109
144
|
}
|
|
110
145
|
];
|
|
111
146
|
}
|
|
112
|
-
// ── Content surface:
|
|
113
|
-
//
|
|
147
|
+
// ── Content surface: commands (prompt templates) ─────────────────────────
|
|
148
|
+
// Pi slash commands are prompt template files: <promptsDir>/<name>.md.
|
|
114
149
|
// Idempotent (byte-identical → skip) via BaseAdapter.writeContentFile and
|
|
115
|
-
// reversible via removeContentFile. Honors platforms["pi"].
|
|
116
|
-
|
|
117
|
-
|
|
150
|
+
// reversible via removeContentFile. Honors platforms["pi"].commands === false.
|
|
151
|
+
/** Native prompt-template file path: <promptsDir>/<name>.md. */
|
|
152
|
+
commandPath(ctx, name) {
|
|
153
|
+
return join(this.promptsDir(ctx), `${name}.md`);
|
|
118
154
|
}
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
155
|
+
installCommands(ctx) {
|
|
156
|
+
const { connector } = ctx;
|
|
157
|
+
if (connector.platforms[HOST]?.commands === false) {
|
|
158
|
+
return [{ platform: this.id, action: "skip", detail: "commands disabled for pi" }];
|
|
159
|
+
}
|
|
160
|
+
if (connector.commands.length === 0) {
|
|
161
|
+
return [{ platform: this.id, action: "skip", detail: "connector declares no commands" }];
|
|
162
|
+
}
|
|
163
|
+
return connector.commands.map(
|
|
164
|
+
(cmd) => this.writeContentFile(
|
|
165
|
+
this.commandPath(ctx, cmd.name),
|
|
166
|
+
this.renderCommand(cmd),
|
|
167
|
+
ctx.dryRun
|
|
168
|
+
)
|
|
169
|
+
);
|
|
122
170
|
}
|
|
171
|
+
uninstallCommands(ctx) {
|
|
172
|
+
const { connector } = ctx;
|
|
173
|
+
if (connector.commands.length === 0) {
|
|
174
|
+
return [{ platform: this.id, action: "skip", detail: "connector declares no commands" }];
|
|
175
|
+
}
|
|
176
|
+
return connector.commands.map(
|
|
177
|
+
(cmd) => this.removeContentFile(this.commandPath(ctx, cmd.name), ctx.dryRun)
|
|
178
|
+
);
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* Render a command as a Pi prompt template (md+frontmatter).
|
|
182
|
+
* Pi's format mirrors the generic command render: description, optional model,
|
|
183
|
+
* optional argument-hint. The body is the prompt template text.
|
|
184
|
+
*/
|
|
185
|
+
renderCommand(cmd) {
|
|
186
|
+
const frontmatter = {};
|
|
187
|
+
if (cmd.description !== void 0) frontmatter.description = cmd.description;
|
|
188
|
+
if (cmd.model !== void 0) frontmatter.model = cmd.model;
|
|
189
|
+
if (cmd.argumentHint !== void 0) frontmatter["argument-hint"] = cmd.argumentHint;
|
|
190
|
+
if (cmd.extra) Object.assign(frontmatter, cmd.extra);
|
|
191
|
+
return this.renderFrontmatterMd(frontmatter, cmd.prompt);
|
|
192
|
+
}
|
|
193
|
+
// ── Content surface: skills ──────────────────────────────────────────────
|
|
194
|
+
// CONTENT-ONLY: pure native-file writer under <skillsDir>/<name>.
|
|
195
|
+
// Idempotent (byte-identical → skip) via BaseAdapter.writeContentFile and
|
|
196
|
+
// reversible via removeContentFile. Honors platforms["pi"].skills === false.
|
|
123
197
|
installSkills(ctx) {
|
|
124
198
|
const { connector } = ctx;
|
|
125
199
|
if (connector.platforms[HOST]?.skills === false) {
|
|
@@ -168,8 +242,10 @@ var PiAdapter = class extends BaseAdapter {
|
|
|
168
242
|
return changes;
|
|
169
243
|
}
|
|
170
244
|
/**
|
|
171
|
-
* Render a skill's SKILL.md
|
|
172
|
-
*
|
|
245
|
+
* Render a skill's SKILL.md.
|
|
246
|
+
*
|
|
247
|
+
* Pi's allowed-tools field is SPACE-delimited (not comma-delimited).
|
|
248
|
+
* Every other field follows the uniform SKILL.md convention.
|
|
173
249
|
*/
|
|
174
250
|
renderSkill(skill) {
|
|
175
251
|
const frontmatter = {
|
|
@@ -178,7 +254,7 @@ var PiAdapter = class extends BaseAdapter {
|
|
|
178
254
|
};
|
|
179
255
|
if (skill.model !== void 0) frontmatter.model = skill.model;
|
|
180
256
|
const allow = skill.tools?.allow;
|
|
181
|
-
if (allow && allow.length > 0) frontmatter["allowed-tools"] = allow.join("
|
|
257
|
+
if (allow && allow.length > 0) frontmatter["allowed-tools"] = allow.join(" ");
|
|
182
258
|
if (skill.disableModelInvocation !== void 0) {
|
|
183
259
|
frontmatter["disable-model-invocation"] = skill.disableModelInvocation;
|
|
184
260
|
}
|
|
@@ -188,6 +264,13 @@ var PiAdapter = class extends BaseAdapter {
|
|
|
188
264
|
// ── Diagnostics ──────────────────────────────────────────────────────────
|
|
189
265
|
getHealthChecks(ctx) {
|
|
190
266
|
const checks = [];
|
|
267
|
+
for (const cmd of ctx.connector.commands) {
|
|
268
|
+
const p = this.commandPath(ctx, cmd.name);
|
|
269
|
+
checks.push({
|
|
270
|
+
name: `${this.name}: command ${cmd.name} present`,
|
|
271
|
+
check: () => existsSync(p) ? { status: "OK", detail: p } : { status: "FAIL", detail: `not found: ${p}` }
|
|
272
|
+
});
|
|
273
|
+
}
|
|
191
274
|
for (const skill of ctx.connector.skills) {
|
|
192
275
|
const p = join(this.skillDir(ctx, skill.name), "SKILL.md");
|
|
193
276
|
checks.push({
|
|
@@ -205,4 +288,4 @@ export {
|
|
|
205
288
|
adapter,
|
|
206
289
|
pi_default as default
|
|
207
290
|
};
|
|
208
|
-
//# sourceMappingURL=pi-
|
|
291
|
+
//# sourceMappingURL=pi-WMTUX6ES.js.map
|