@ken-jo/agent-connector 0.4.0 → 0.4.1
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 +8 -8
- package/dist/{action-PLZW5BGX.js → action-WT7GVRCC.js} +11 -10
- package/dist/{action-PLZW5BGX.js.map → action-WT7GVRCC.js.map} +1 -1
- package/dist/amazon-q-COAL3764.js +276 -0
- package/dist/amazon-q-COAL3764.js.map +1 -0
- package/dist/{amp-B524U6LO.js → amp-4U33CU7E.js} +3 -3
- 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-KGJWE6A2.js → chunk-24IDL5RW.js} +2 -2
- package/dist/{chunk-CIRDOY2V.js → chunk-2AVLX7GH.js} +3 -3
- package/dist/{chunk-ADTHT2FN.js → chunk-4ENJK5S2.js} +10 -173
- package/dist/chunk-4ENJK5S2.js.map +1 -0
- package/dist/{chunk-BHUCB6LY.js → chunk-5OWS5CMA.js} +8 -7
- package/dist/{chunk-BHUCB6LY.js.map → chunk-5OWS5CMA.js.map} +1 -1
- package/dist/{chunk-IW77FFNX.js → chunk-CPLK7GTE.js} +41 -5
- package/dist/chunk-CPLK7GTE.js.map +1 -0
- package/dist/chunk-DCKFYWGM.js +237 -0
- package/dist/chunk-DCKFYWGM.js.map +1 -0
- package/dist/{chunk-J3D5W5T2.js → chunk-EGCBZ2DC.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-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-KGXDYGNJ.js → chunk-O5TWCIJN.js} +19 -19
- package/dist/{chunk-KGXDYGNJ.js.map → chunk-O5TWCIJN.js.map} +1 -1
- package/dist/{chunk-MAH6QQTO.js → chunk-QREL7LZJ.js} +5 -4
- package/dist/chunk-QREL7LZJ.js.map +1 -0
- package/dist/{chunk-G3ER4SY5.js → chunk-RIMVWCZY.js} +9 -9
- package/dist/{chunk-6XHB6BE3.js → chunk-SCVBYSF7.js} +1 -1
- package/dist/{chunk-KGGBNKI4.js → chunk-URHQMFB3.js} +90 -13
- package/dist/chunk-URHQMFB3.js.map +1 -0
- package/dist/chunk-WZA4CSGJ.js +28 -0
- package/dist/chunk-WZA4CSGJ.js.map +1 -0
- package/dist/{chunk-76FUSVIA.js → chunk-XJ4S47CT.js} +6 -5
- package/dist/chunk-XJ4S47CT.js.map +1 -0
- package/dist/{claude-code-MLWS7CW6.js → claude-code-W4PUFZL5.js} +20 -30
- package/dist/claude-code-W4PUFZL5.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-DH5Y7GAT.js} +8 -4
- package/dist/codebuff-DH5Y7GAT.js.map +1 -0
- package/dist/{codex-BXA4FIF4.js → codex-DDHIV767.js} +43 -11
- package/dist/codex-DDHIV767.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-KG5FG3EV.js} +5 -4
- package/dist/{detect-ZIIS55LD.js.map → detect-KG5FG3EV.js.map} +1 -1
- package/dist/{doctor-TJUGSQ5C.js → doctor-FLZF34Y3.js} +221 -95
- package/dist/doctor-FLZF34Y3.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-XR3Z45FB.js} +14 -11
- package/dist/hook-XR3Z45FB.js.map +1 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.js +3 -2
- package/dist/{install-UDCBL7HP.js → install-BSR62UHJ.js} +11 -10
- package/dist/{install-UDCBL7HP.js.map → install-BSR62UHJ.js.map} +1 -1
- package/dist/{introspect-DuZSPSHB.d.ts → introspect-Nw8hTReX.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-5NWOXVSD.js} +16 -16
- package/dist/kilo-5NWOXVSD.js.map +1 -0
- package/dist/{kilo-cli-3HWPWBY4.js → kilo-cli-UZ7R5UOP.js} +3 -3
- 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-MJG24O35.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-W5KEJ3WX.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-EXJEFNZI.js} +4 -4
- package/dist/{opencode-Q6KBSAKW.js → opencode-WNXYJR4X.js} +84 -27
- package/dist/opencode-WNXYJR4X.js.map +1 -0
- package/dist/{package-RMPN57YZ.js → package-ACZXJHWB.js} +8 -7
- package/dist/{package-RMPN57YZ.js.map → package-ACZXJHWB.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-GER7URPR.js} +11 -10
- package/dist/{serve-D3GO36UT.js.map → serve-GER7URPR.js.map} +1 -1
- package/dist/{status-KOSKCETC.js → status-LAJE3BM5.js} +7 -6
- package/dist/{status-KOSKCETC.js.map → status-LAJE3BM5.js.map} +1 -1
- package/dist/{statusline-ZNTCL5YC.js → statusline-L376ZPZU.js} +10 -9
- package/dist/{statusline-ZNTCL5YC.js.map → statusline-L376ZPZU.js.map} +1 -1
- package/dist/{telemetry-XIKUUGTQ.js → telemetry-B3DX3PWU.js} +6 -5
- package/dist/{telemetry-XIKUUGTQ.js.map → telemetry-B3DX3PWU.js.map} +1 -1
- package/dist/{trae-NWT3TMSZ.js → trae-7CZZGOGI.js} +3 -3
- package/dist/{types-BEKsAium.d.ts → types-CRVrFWeU.d.ts} +64 -22
- package/dist/{uninstall-2LBLQVFA.js → uninstall-ZYTW7YMZ.js} +11 -10
- package/dist/{uninstall-2LBLQVFA.js.map → uninstall-ZYTW7YMZ.js.map} +1 -1
- package/dist/{upgrade-ZC2S7VRN.js → upgrade-4LUEEOZW.js} +11 -10
- package/dist/{upgrade-ZC2S7VRN.js.map → upgrade-4LUEEOZW.js.map} +1 -1
- package/dist/{usage-E2A4O2CY.js → usage-ZFBVQF3H.js} +3 -3
- package/dist/{usage-event-JKMC4QC4.js → usage-event-GZ32AGEB.js} +10 -9
- package/dist/{usage-event-JKMC4QC4.js.map → usage-event-GZ32AGEB.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/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/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/{amp-B524U6LO.js.map → amp-4U33CU7E.js.map} +0 -0
- /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-KGJWE6A2.js.map → chunk-24IDL5RW.js.map} +0 -0
- /package/dist/{chunk-CIRDOY2V.js.map → chunk-2AVLX7GH.js.map} +0 -0
- /package/dist/{chunk-J3D5W5T2.js.map → chunk-EGCBZ2DC.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-G3ER4SY5.js.map → chunk-RIMVWCZY.js.map} +0 -0
- /package/dist/{chunk-6XHB6BE3.js.map → chunk-SCVBYSF7.js.map} +0 -0
- /package/dist/{kilo-cli-3HWPWBY4.js.map → kilo-cli-UZ7R5UOP.js.map} +0 -0
- /package/dist/{kiro-C5W6AGDR.js.map → kiro-YL6AWUYG.js.map} +0 -0
- /package/dist/{leaderboard-TIBVONVT.js.map → leaderboard-MJG24O35.js.map} +0 -0
- /package/dist/{nemoclaw-3EVNKD3I.js.map → nemoclaw-W5KEJ3WX.js.map} +0 -0
- /package/dist/{openclaw-7G437NT7.js.map → openclaw-EXJEFNZI.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-ZFBVQF3H.js.map} +0 -0
- /package/dist/{zed-RH34TNSW.js.map → zed-SFUHL3GS.js.map} +0 -0
|
@@ -4,19 +4,19 @@ import {
|
|
|
4
4
|
} from "./chunk-DBQMX75U.js";
|
|
5
5
|
import {
|
|
6
6
|
BaseAdapter
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-CPLK7GTE.js";
|
|
8
8
|
import "./chunk-7L6ITC4T.js";
|
|
9
9
|
import {
|
|
10
10
|
buildHomeBinHookCommand,
|
|
11
11
|
buildServeWrapperCommand,
|
|
12
12
|
isHomeBinHookCommand,
|
|
13
13
|
shouldWrapForTelemetry
|
|
14
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-I5MLE6S7.js";
|
|
15
15
|
import "./chunk-N6HH7K6P.js";
|
|
16
16
|
import "./chunk-TRQKHP7D.js";
|
|
17
17
|
|
|
18
18
|
// src/adapters/droid/index.ts
|
|
19
|
-
import { existsSync } from "fs";
|
|
19
|
+
import { chmodSync, existsSync } from "fs";
|
|
20
20
|
import { homedir } from "os";
|
|
21
21
|
import { join } from "path";
|
|
22
22
|
var HOST = "droid";
|
|
@@ -26,7 +26,11 @@ var SUPPORTED_EVENTS = /* @__PURE__ */ new Set([
|
|
|
26
26
|
"PostToolUse",
|
|
27
27
|
"UserPromptSubmit",
|
|
28
28
|
"Stop",
|
|
29
|
-
"SubagentStop"
|
|
29
|
+
"SubagentStop",
|
|
30
|
+
"Notification",
|
|
31
|
+
"PreCompact",
|
|
32
|
+
"SessionStart",
|
|
33
|
+
"SessionEnd"
|
|
30
34
|
]);
|
|
31
35
|
var DroidAdapter = class extends BaseAdapter {
|
|
32
36
|
id = HOST;
|
|
@@ -38,12 +42,15 @@ var DroidAdapter = class extends BaseAdapter {
|
|
|
38
42
|
supportsMemory: true,
|
|
39
43
|
preToolUse: true,
|
|
40
44
|
postToolUse: true,
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
45
|
+
// Notification / PreCompact / SessionStart / SessionEnd are documented Droid
|
|
46
|
+
// lifecycle hooks (docs.factory.ai/reference/hooks-reference) with the same
|
|
47
|
+
// Claude-shaped snake_case stdin wire — all four fire natively.
|
|
48
|
+
preCompact: true,
|
|
49
|
+
sessionStart: true,
|
|
50
|
+
sessionEnd: true,
|
|
44
51
|
userPromptSubmit: true,
|
|
45
52
|
stop: true,
|
|
46
|
-
notification:
|
|
53
|
+
notification: true,
|
|
47
54
|
// Newer events: Droid ships SubagentStop (stop-only — no SubagentStart).
|
|
48
55
|
// permissionRequest / postToolUseFailure / subagentStart stay unset (no
|
|
49
56
|
// Droid analog); install reports the standard skip-warn for them.
|
|
@@ -56,16 +63,31 @@ var DroidAdapter = class extends BaseAdapter {
|
|
|
56
63
|
canInjectSessionContext: true,
|
|
57
64
|
// Droid registers stdio and Streamable HTTP MCP servers.
|
|
58
65
|
transports: ["stdio", "http"],
|
|
59
|
-
//
|
|
60
|
-
//
|
|
61
|
-
//
|
|
66
|
+
// Droid HAS a confirmed command-driven status line: `statusLine.command`
|
|
67
|
+
// (object {command, padding?, maxRows?}) in ~/.factory/settings.json, stdout
|
|
68
|
+
// rendered above the input (docs.factory.ai/cli/configuration/settings). BUT
|
|
69
|
+
// Factory publishes NO statusline stdin payload schema (the model/cost/
|
|
70
|
+
// context_window fields circulating online are Claude Code's, not
|
|
71
|
+
// Factory-captured), so the payload→StatuslineContext mapping can't be
|
|
72
|
+
// authored without a live stdin capture (blocked: needs an authenticated
|
|
73
|
+
// droid session). NOT a permanent gap — supportsStatusline stays unset until
|
|
74
|
+
// the payload is captured (set statusLine.command to a stdin-dumping script
|
|
75
|
+
// on a real droid box to confirm).
|
|
62
76
|
// Content surfaces: Droid implements all three (live-confirmed Factory dirs).
|
|
63
77
|
// command → <configDir>/commands/<name>.md (md+frontmatter: description, argument-hint)
|
|
64
78
|
// skill → <configDir>/skills/<name>/SKILL.md (+ resources)
|
|
65
79
|
// subagent → <configDir>/droids/<name>.md (MARKDOWN — folder is droids/, NOT agents/)
|
|
66
80
|
supportsCommands: true,
|
|
67
81
|
supportsSkills: true,
|
|
68
|
-
supportsSubagents: true
|
|
82
|
+
supportsSubagents: true,
|
|
83
|
+
// Actions: Droid runs EXECUTABLE files placed at <configDir>/commands/<id>
|
|
84
|
+
// (NO .md extension) via `/<id>` — "Executable files must start with a valid
|
|
85
|
+
// shebang so the CLI can call the interpreter" and stdout is returned to the
|
|
86
|
+
// transcript (docs.factory.ai/cli/configuration/custom-slash-commands). We
|
|
87
|
+
// write a POSIX shebang script that execs the home-bin action verb. The
|
|
88
|
+
// exec-file interpreter resolution is UNVERIFIED on win32, so the emitter
|
|
89
|
+
// skip-warns there (see installActions).
|
|
90
|
+
supportsActions: true
|
|
69
91
|
};
|
|
70
92
|
// ── Detection ────────────────────────────────────────────────────────────
|
|
71
93
|
detectInstalled(projectDir) {
|
|
@@ -450,6 +472,63 @@ var DroidAdapter = class extends BaseAdapter {
|
|
|
450
472
|
if (agent.extra) Object.assign(frontmatter, agent.extra);
|
|
451
473
|
return this.renderFrontmatterMd(frontmatter, agent.prompt);
|
|
452
474
|
}
|
|
475
|
+
// ── Action surface (executable command file, NO .md extension) ────────────
|
|
476
|
+
// Each action emits an EXECUTABLE script at <configDir>/commands/<id> (no
|
|
477
|
+
// extension) whose shebang lets Droid's CLI exec it; it execs the home-bin
|
|
478
|
+
// action verb and forwards "$@". Invoked via `/<id>`, stdout → transcript
|
|
479
|
+
// (docs.factory.ai/cli/configuration/custom-slash-commands). chmod 0o755.
|
|
480
|
+
//
|
|
481
|
+
// COLLISION NOTE: the COMMAND surface writes commands/<name>.md; actions write
|
|
482
|
+
// commands/<id> (no extension) — different filenames, both register `/<name>`.
|
|
483
|
+
// A connector reusing one id for a command AND an action is the author's call.
|
|
484
|
+
//
|
|
485
|
+
// CROSS-OS: the shebang exec-file is POSIX. On win32 Droid's exec-file
|
|
486
|
+
// interpreter resolution is UNVERIFIED, so we skip-warn there and write nothing
|
|
487
|
+
// (honest degradation, like other Windows caveats in the codebase).
|
|
488
|
+
/** Native action file path: <configDir>/commands/<id> (NO .md extension). */
|
|
489
|
+
actionPath(ctx, id) {
|
|
490
|
+
return join(this.getConfigDir(ctx), "commands", id);
|
|
491
|
+
}
|
|
492
|
+
installActions(ctx) {
|
|
493
|
+
const { connector } = ctx;
|
|
494
|
+
if (connector.platforms[HOST]?.actions === false) {
|
|
495
|
+
return [{ platform: this.id, action: "skip", detail: "actions disabled for droid" }];
|
|
496
|
+
}
|
|
497
|
+
const triggers = this.actionTriggers(ctx);
|
|
498
|
+
if (triggers.length === 0) {
|
|
499
|
+
return [{ platform: this.id, action: "skip", detail: "connector declares no actions" }];
|
|
500
|
+
}
|
|
501
|
+
if (process.platform === "win32") {
|
|
502
|
+
return [
|
|
503
|
+
{
|
|
504
|
+
platform: this.id,
|
|
505
|
+
action: "warn",
|
|
506
|
+
detail: `droid action exec-files are unverified on Windows; ${triggers.length} skipped`
|
|
507
|
+
}
|
|
508
|
+
];
|
|
509
|
+
}
|
|
510
|
+
return triggers.map((trigger) => {
|
|
511
|
+
const path = this.actionPath(ctx, trigger.id);
|
|
512
|
+
const record = this.writeContentFile(path, this.renderActionScript(trigger.command), ctx.dryRun);
|
|
513
|
+
if (record.action !== "skip" && !ctx.dryRun) chmodSync(path, 493);
|
|
514
|
+
return record;
|
|
515
|
+
});
|
|
516
|
+
}
|
|
517
|
+
uninstallActions(ctx) {
|
|
518
|
+
const { connector } = ctx;
|
|
519
|
+
if (connector.actions.length === 0) {
|
|
520
|
+
return [{ platform: this.id, action: "skip", detail: "connector declares no actions" }];
|
|
521
|
+
}
|
|
522
|
+
return connector.actions.map(
|
|
523
|
+
(action) => this.removeContentFile(this.actionPath(ctx, action.id), ctx.dryRun)
|
|
524
|
+
);
|
|
525
|
+
}
|
|
526
|
+
/** Render the POSIX exec-file: shebang + `exec <action verb> "$@"`. */
|
|
527
|
+
renderActionScript(command) {
|
|
528
|
+
return `#!/usr/bin/env sh
|
|
529
|
+
exec ${command} "$@"
|
|
530
|
+
`;
|
|
531
|
+
}
|
|
453
532
|
// ── Diagnostics ──────────────────────────────────────────────────────────
|
|
454
533
|
getHealthChecks(ctx) {
|
|
455
534
|
const mcpPath = this.getServerConfigPath(ctx);
|
|
@@ -556,6 +635,34 @@ var DroidAdapter = class extends BaseAdapter {
|
|
|
556
635
|
};
|
|
557
636
|
return ev;
|
|
558
637
|
}
|
|
638
|
+
case "Notification": {
|
|
639
|
+
const ev = {
|
|
640
|
+
...base,
|
|
641
|
+
message: typeof input.message === "string" ? input.message : ""
|
|
642
|
+
};
|
|
643
|
+
return ev;
|
|
644
|
+
}
|
|
645
|
+
case "PreCompact": {
|
|
646
|
+
const ev = {
|
|
647
|
+
...base,
|
|
648
|
+
...input.trigger === "auto" || input.trigger === "manual" ? { trigger: input.trigger } : {}
|
|
649
|
+
};
|
|
650
|
+
return ev;
|
|
651
|
+
}
|
|
652
|
+
case "SessionStart": {
|
|
653
|
+
const ev = {
|
|
654
|
+
...base,
|
|
655
|
+
source: normalizeSessionSource(input.source)
|
|
656
|
+
};
|
|
657
|
+
return ev;
|
|
658
|
+
}
|
|
659
|
+
case "SessionEnd": {
|
|
660
|
+
const ev = {
|
|
661
|
+
...base,
|
|
662
|
+
...typeof input.reason === "string" ? { reason: input.reason } : {}
|
|
663
|
+
};
|
|
664
|
+
return ev;
|
|
665
|
+
}
|
|
559
666
|
default: {
|
|
560
667
|
throw new Error(`unsupported droid hook event: ${String(event)}`);
|
|
561
668
|
}
|
|
@@ -565,6 +672,9 @@ var DroidAdapter = class extends BaseAdapter {
|
|
|
565
672
|
formatReply(event, response) {
|
|
566
673
|
const hookEventName = event;
|
|
567
674
|
const decision = response.decision ?? "allow";
|
|
675
|
+
if (event === "Notification" || event === "PreCompact" || event === "SessionEnd") {
|
|
676
|
+
return { exitCode: 0 };
|
|
677
|
+
}
|
|
568
678
|
if (decision === "deny") {
|
|
569
679
|
if (event === "SubagentStop") {
|
|
570
680
|
return this.stdout({
|
|
@@ -600,6 +710,18 @@ var DroidAdapter = class extends BaseAdapter {
|
|
|
600
710
|
return { exitCode: 0, stdout: JSON.stringify(payload) };
|
|
601
711
|
}
|
|
602
712
|
};
|
|
713
|
+
function normalizeSessionSource(source) {
|
|
714
|
+
switch (source) {
|
|
715
|
+
case "compact":
|
|
716
|
+
return "compact";
|
|
717
|
+
case "resume":
|
|
718
|
+
return "resume";
|
|
719
|
+
case "clear":
|
|
720
|
+
return "clear";
|
|
721
|
+
default:
|
|
722
|
+
return "startup";
|
|
723
|
+
}
|
|
724
|
+
}
|
|
603
725
|
function toolResponseToString(value) {
|
|
604
726
|
if (value == null) return void 0;
|
|
605
727
|
if (typeof value === "string") return value;
|
|
@@ -616,4 +738,4 @@ export {
|
|
|
616
738
|
adapter,
|
|
617
739
|
droid_default as default
|
|
618
740
|
};
|
|
619
|
-
//# sourceMappingURL=droid-
|
|
741
|
+
//# sourceMappingURL=droid-JC2NT6S4.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/adapters/droid/index.ts"],"sourcesContent":["/**\n * adapters/droid — Droid (Factory AI) platform adapter for agent-connector.\n *\n * Droid is a **json-stdio** host with TWO native config surfaces that live in\n * DIFFERENT files (so getServerConfigPath ≠ getHookConfigPath):\n *\n * 1. MCP servers — `mcp.json` (root key `mcpServers`):\n * - user scope → ~/.factory/mcp.json\n * - project scope → <projectDir>/.factory/mcp.json\n * Native stdio entry shape: { type:\"stdio\", command, args, env, disabled };\n * a remote server registers a URL ({ type:\"http\", url, headers, disabled }).\n *\n * 2. Hooks — a SEPARATE `hooks.json` (root key `hooks`) under the same\n * `.factory` dir. Droid ships a FULL Claude-compatible lifecycle hook\n * system (live-confirmed): PascalCase event names, Claude snake_case stdin\n * wire fields, and a Claude-shaped `hookSpecificOutput` reply. Hook\n * registrations use the Claude NESTED-rule shape:\n * { hooks: { <Event>: [ { matcher?, hooks:[{ type:\"command\", command }] } ] } }\n *\n * Supported events (Claude-compatible): PreToolUse, PostToolUse,\n * UserPromptSubmit, Stop, SubagentStop (stop-only — no SubagentStart), plus the\n * full lifecycle set Notification, PreCompact, SessionStart, SessionEnd\n * (docs.factory.ai/reference/hooks-reference — Claude-identical PascalCase 1:1\n * with the same snake_case stdin wire). Droid exposes no PermissionRequest /\n * PostToolUseFailure / SubagentStart, so those degrade to a warn/skip at\n * install time.\n *\n * Reply protocol is Claude-shaped JSON on stdout (exit 0 + `hookSpecificOutput`\n * with permissionDecision allow|deny|ask, plus additionalContext). Droid cannot\n * rewrite already-emitted tool output, so canModifyOutput is false; it CAN\n * inject session context (additionalContext) so canInjectSessionContext is true\n * (SessionStart honors hookSpecificOutput.additionalContext per the same docs).\n *\n * Env handling: env/header/url refs are resolved to literals at install time via\n * resolveEnvRefsDeep — the safe default matching the Kiro/Qwen adapters. Droid\n * also accepts native ${VAR}, but resolve-to-literal avoids surprises.\n */\n\nimport { chmodSync, existsSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\n\nimport { BaseAdapter } from \"../base.js\";\nimport type { Adapter, HookReply, InstallContext, NormalizedEvent } from \"../spi.js\";\nimport type {\n ChangeRecord,\n CommandDef,\n DetectedPlatform,\n HealthCheck,\n HookEventName,\n HookParadigm,\n HookResponse,\n NotificationEvent,\n PlatformCapabilities,\n PlatformId,\n PostToolUseEvent,\n PreCompactEvent,\n PreToolUseEvent,\n ServerDef,\n SessionEndEvent,\n SessionStartEvent,\n SkillDef,\n StopEvent,\n SubagentDef,\n SubagentStopEvent,\n Transport,\n UserPromptSubmitEvent,\n} from \"../../core/types.js\";\nimport { resolveEnvRefsDeep } from \"../../core/interpolate.js\";\nimport {\n buildHomeBinHookCommand,\n buildServeWrapperCommand,\n isHomeBinHookCommand,\n shouldWrapForTelemetry,\n} from \"../../core/spawn.js\";\n\nconst HOST: PlatformId = \"droid\";\nconst MCP_ROOT_KEY = \"mcpServers\";\n\n/**\n * Canonical events Droid actually fires. Droid's hook event names are\n * Claude-identical (PascalCase), so the canonical name is registered directly.\n * Notification / PreCompact / SessionStart / SessionEnd are all documented\n * Droid lifecycle hooks (docs.factory.ai/reference/hooks-reference) and so are\n * wired here too.\n *\n * Droid is a STOP-ONLY subagent host: its live hooks-reference lists\n * SubagentStop but NO SubagentStart, and it has no permission-dialog\n * (PermissionRequest) or tool-failure (PostToolUseFailure) events — those\n * three warn/skip at install time.\n */\nconst SUPPORTED_EVENTS: ReadonlySet<HookEventName> = new Set<HookEventName>([\n \"PreToolUse\",\n \"PostToolUse\",\n \"UserPromptSubmit\",\n \"Stop\",\n \"SubagentStop\",\n \"Notification\",\n \"PreCompact\",\n \"SessionStart\",\n \"SessionEnd\",\n]);\n\n/**\n * Native MCP server entry shapes Droid accepts under `mcpServers`.\n * A stdio entry carries an explicit `type: \"stdio\"` discriminator and a\n * `disabled` flag; remote transports register a URL.\n */\ninterface DroidStdioServer {\n type: \"stdio\";\n command: string;\n args?: string[];\n env?: Record<string, string>;\n disabled: boolean;\n}\ninterface DroidHttpServer {\n type: \"http\";\n url: string;\n headers?: Record<string, string>;\n disabled: boolean;\n}\n\n/** A single Droid native hook registration entry (Claude-shaped, nested). */\ninterface DroidHookEntry {\n matcher: string;\n hooks: Array<{ type: \"command\"; command: string }>;\n}\n\n/** The shape of Droid's hooks.json (only the parts we touch). */\ninterface DroidHooksFile {\n hooks?: Record<string, DroidHookEntry[]>;\n [key: string]: unknown;\n}\n\n/** Raw Droid CLI hook stdin payload (Claude-compatible snake_case wire fields). */\ninterface DroidWireInput {\n session_id?: string;\n transcript_path?: string;\n cwd?: string;\n hook_event_name?: string;\n tool_name?: string;\n tool_input?: Record<string, unknown>;\n tool_response?: unknown;\n prompt?: string;\n /** Notification — the user-facing notification text. */\n message?: string;\n /** PreCompact — compaction trigger (manual = /compact, auto = full context). */\n trigger?: \"auto\" | \"manual\";\n /** SessionStart — startup | resume | clear | compact (matcher source). */\n source?: string;\n /** SessionEnd — clear | logout | prompt_input_exit | other. */\n reason?: string;\n /** Stop / SubagentStop loop guard. */\n stop_hook_active?: boolean;\n // SubagentStop — Claude-compatible snake_case fields. agent_type is\n // unreliable on SubagentStop across hosts; treat both as optional.\n agent_id?: string;\n agent_type?: string;\n agent_transcript_path?: string;\n last_assistant_message?: string;\n /** Injected by the entrypoint so the runtime knows which connector to dispatch. */\n connector?: unknown;\n}\n\nexport class DroidAdapter extends BaseAdapter implements Adapter {\n readonly id: PlatformId = HOST;\n readonly name = \"Droid (Factory)\";\n readonly paradigm: HookParadigm = \"json-stdio\";\n\n readonly capabilities: PlatformCapabilities = {\n // Memory surface: AGENTS.md-first managed block via the BaseAdapter default\n // (memoryTargets: project <projectDir>/AGENTS.md; user scope where documented).\n supportsMemory: true,\n preToolUse: true,\n postToolUse: true,\n // Notification / PreCompact / SessionStart / SessionEnd are documented Droid\n // lifecycle hooks (docs.factory.ai/reference/hooks-reference) with the same\n // Claude-shaped snake_case stdin wire — all four fire natively.\n preCompact: true,\n sessionStart: true,\n sessionEnd: true,\n userPromptSubmit: true,\n stop: true,\n notification: true,\n // Newer events: Droid ships SubagentStop (stop-only — no SubagentStart).\n // permissionRequest / postToolUseFailure / subagentStart stay unset (no\n // Droid analog); install reports the standard skip-warn for them.\n subagentStop: true,\n // Droid's PreToolUse can deny/ask (Claude-shaped), but it cannot rewrite\n // already-emitted tool output. canModifyArgs left false until confirmed.\n canModifyArgs: false,\n canModifyOutput: false,\n // Droid honors additionalContext on the stdout reply.\n canInjectSessionContext: true,\n // Droid registers stdio and Streamable HTTP MCP servers.\n transports: [\"stdio\", \"http\"],\n // Droid HAS a confirmed command-driven status line: `statusLine.command`\n // (object {command, padding?, maxRows?}) in ~/.factory/settings.json, stdout\n // rendered above the input (docs.factory.ai/cli/configuration/settings). BUT\n // Factory publishes NO statusline stdin payload schema (the model/cost/\n // context_window fields circulating online are Claude Code's, not\n // Factory-captured), so the payload→StatuslineContext mapping can't be\n // authored without a live stdin capture (blocked: needs an authenticated\n // droid session). NOT a permanent gap — supportsStatusline stays unset until\n // the payload is captured (set statusLine.command to a stdin-dumping script\n // on a real droid box to confirm).\n // Content surfaces: Droid implements all three (live-confirmed Factory dirs).\n // command → <configDir>/commands/<name>.md (md+frontmatter: description, argument-hint)\n // skill → <configDir>/skills/<name>/SKILL.md (+ resources)\n // subagent → <configDir>/droids/<name>.md (MARKDOWN — folder is droids/, NOT agents/)\n supportsCommands: true,\n supportsSkills: true,\n supportsSubagents: true,\n // Actions: Droid runs EXECUTABLE files placed at <configDir>/commands/<id>\n // (NO .md extension) via `/<id>` — \"Executable files must start with a valid\n // shebang so the CLI can call the interpreter\" and stdout is returned to the\n // transcript (docs.factory.ai/cli/configuration/custom-slash-commands). We\n // write a POSIX shebang script that execs the home-bin action verb. The\n // exec-file interpreter resolution is UNVERIFIED on win32, so the emitter\n // skip-warns there (see installActions).\n supportsActions: true,\n };\n\n // ── Detection ────────────────────────────────────────────────────────────\n\n detectInstalled(projectDir: string): DetectedPlatform {\n const userDir = join(homedir(), \".factory\");\n const userMcp = join(userDir, \"mcp.json\");\n const projDir = join(projectDir, \".factory\");\n const projMcp = join(projDir, \"mcp.json\");\n\n const userInstalled = existsSync(userDir) || existsSync(userMcp);\n const projInstalled = existsSync(projDir) || existsSync(projMcp);\n const installed = userInstalled || projInstalled;\n const scope = projInstalled && !userInstalled ? \"project\" : \"user\";\n const configPath = scope === \"project\" ? projMcp : userMcp;\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 Droid config (${scope}) at ${configPath}`\n : `no .factory config at ${userDir} or ${projDir}`,\n confidence: installed ? \"high\" : \"low\",\n };\n }\n\n // ── Native paths ─────────────────────────────────────────────────────────\n\n getConfigDir(ctx: InstallContext): string {\n return ctx.scope === \"project\"\n ? join(ctx.projectDir, \".factory\")\n : join(homedir(), \".factory\");\n }\n\n getServerConfigPath(ctx: InstallContext): string {\n return join(this.getConfigDir(ctx), \"mcp.json\");\n }\n\n /** Hooks live in a SEPARATE hooks.json under the same `.factory` dir. */\n getHookConfigPath(ctx: InstallContext): string {\n return join(this.getConfigDir(ctx), \"hooks.json\");\n }\n\n // ── MCP server install / uninstall ───────────────────────────────────────\n\n installServer(ctx: InstallContext): ChangeRecord[] {\n const { connector } = ctx;\n const override = connector.platforms[HOST]?.server;\n if (!connector.server || override === false) {\n return [\n {\n platform: this.id,\n action: \"skip\",\n detail: connector.server\n ? \"server registration disabled for droid\"\n : \"connector declares no MCP server\",\n },\n ];\n }\n\n // Shallow-merge any per-platform server override into the base ServerDef.\n const server: ServerDef =\n override && typeof override === \"object\"\n ? { ...connector.server, ...override }\n : connector.server;\n\n const serverPath = this.getServerConfigPath(ctx);\n const entry = this.renderServerEntry(ctx, server);\n\n return [\n this.upsertServerInJson(serverPath, MCP_ROOT_KEY, connector.id, entry, ctx.dryRun),\n ];\n }\n\n uninstallServer(ctx: InstallContext): ChangeRecord[] {\n const serverPath = this.getServerConfigPath(ctx);\n return [\n this.removeServerFromJson(serverPath, MCP_ROOT_KEY, ctx.connector.id, ctx.dryRun),\n ];\n }\n\n /** Render a normalized ServerDef into Droid's native mcpServers entry. */\n private renderServerEntry(\n ctx: InstallContext,\n server: ServerDef,\n ): DroidStdioServer | DroidHttpServer {\n const transport: Transport = server.transport;\n const disabled = server.enabled === false;\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 // Resolve every ${env:VAR} to a literal at install time (safe path).\n const entry: DroidStdioServer = {\n type: \"stdio\",\n command: resolveEnvRefsDeep(command),\n disabled,\n };\n if (args.length > 0) entry.args = resolveEnvRefsDeep(args);\n const env = this.renderEnv(server.env);\n if (env) entry.env = env;\n return entry;\n }\n\n // http (and any other remote transport) — Droid registers a URL.\n const entry: DroidHttpServer = {\n type: \"http\",\n url: resolveEnvRefsDeep(server.url ?? \"\"),\n disabled,\n };\n const headers = this.renderEnv(server.headers);\n if (headers) entry.headers = headers;\n return entry;\n }\n\n /**\n * Render env/header values. Resolve `${env:VAR}` references to literals at\n * install time (the safe path; Droid would also accept native ${VAR}).\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 (separate hooks.json, nested-rule shape) ─────\n\n installHooks(ctx: InstallContext): ChangeRecord[] {\n const { connector } = ctx;\n if (connector.platforms[HOST]?.hooks === false) {\n return [{ platform: this.id, action: \"skip\", detail: \"hooks disabled for droid\" }];\n }\n if (connector.hookEvents.length === 0) {\n return [{ platform: this.id, action: \"skip\", detail: \"connector declares no hooks\" }];\n }\n\n const hookPath = this.getHookConfigPath(ctx);\n // Merge into any existing hooks.json so the user's own hooks survive.\n const file = this.readJson<DroidHooksFile>(hookPath) ?? {};\n const hooks = (file.hooks ??= {});\n\n const changes: ChangeRecord[] = [];\n let mutated = false;\n\n for (const event of connector.hookEvents) {\n if (!SUPPORTED_EVENTS.has(event)) {\n changes.push({\n platform: this.id,\n action: \"warn\",\n path: hookPath,\n detail: `${event} has no Droid hook equivalent — skipped`,\n });\n continue;\n }\n\n // Droid's event names are Claude-identical (PascalCase) — register the\n // canonical event name directly.\n const command = buildHomeBinHookCommand(ctx.homeBinPath, HOST, event, connector.id);\n const matcher = connector.hooks[event]?.matcher ?? \"\";\n const entry: DroidHookEntry = {\n matcher,\n hooks: [{ type: \"command\", command }],\n };\n\n const bucket = (hooks[event] ??= []);\n const existingIdx = bucket.findIndex((e) => this.entryHasOurCommand(e, ctx));\n\n if (existingIdx >= 0) {\n if (JSON.stringify(bucket[existingIdx]) === JSON.stringify(entry)) {\n changes.push({\n platform: this.id,\n action: \"skip\",\n path: hookPath,\n detail: `hooks.${event} already registered`,\n });\n continue;\n }\n bucket[existingIdx] = entry;\n changes.push({\n platform: this.id,\n action: \"update\",\n path: hookPath,\n detail: `hooks.${event}`,\n });\n } else {\n bucket.push(entry);\n changes.push({\n platform: this.id,\n action: \"create\",\n path: hookPath,\n detail: `hooks.${event}`,\n });\n }\n mutated = true;\n }\n\n if (mutated) this.writeJson(hookPath, file, ctx.dryRun);\n return changes;\n }\n\n uninstallHooks(ctx: InstallContext): ChangeRecord[] {\n const hookPath = this.getHookConfigPath(ctx);\n const file = this.readJson<DroidHooksFile>(hookPath);\n const hooks = file?.hooks;\n if (!file || !hooks) {\n return [\n {\n platform: this.id,\n action: \"skip\",\n path: hookPath,\n detail: \"no hooks section present\",\n },\n ];\n }\n\n const changes: ChangeRecord[] = [];\n let mutated = false;\n\n for (const event of Object.keys(hooks)) {\n const bucket = hooks[event];\n if (!Array.isArray(bucket)) continue;\n\n // Strip our hook command from each entry; drop entries left empty so we\n // never remove another connector's (or the user's own) hook commands. The\n // id token is anchored (isHomeBinHookCommand) so a shared-prefix connector\n // id is never affected.\n const next: DroidHookEntry[] = [];\n let removed = 0;\n for (const e of bucket) {\n const innerBefore = e.hooks?.length ?? 0;\n const inner = (e.hooks ?? []).filter((h) => !this.isOurCommand(h.command, ctx));\n removed += innerBefore - inner.length;\n if (inner.length > 0) next.push({ matcher: e.matcher ?? \"\", hooks: inner });\n }\n\n if (removed > 0) {\n if (next.length > 0) hooks[event] = next;\n else delete hooks[event];\n changes.push({\n platform: this.id,\n action: \"remove\",\n path: hookPath,\n detail: `hooks.${event} (${removed})`,\n });\n mutated = true;\n }\n }\n\n if (mutated) this.writeJson(hookPath, file, ctx.dryRun);\n if (changes.length === 0) {\n changes.push({\n platform: this.id,\n action: \"skip\",\n path: hookPath,\n detail: \"no matching hook entries\",\n });\n }\n return changes;\n }\n\n private entryHasOurCommand(entry: DroidHookEntry, ctx: InstallContext): boolean {\n return (entry.hooks ?? []).some((h) => this.isOurCommand(h.command, ctx));\n }\n\n /** True when a hook command references our home binary AND this connector id\n * (anchored so a shared-prefix id can't collide — see isHomeBinHookCommand). */\n private isOurCommand(command: string | undefined, ctx: InstallContext): boolean {\n return isHomeBinHookCommand(command, ctx.homeBinPath, ctx.connector.id);\n }\n\n // ── Content surfaces: commands / skills / subagents ──────────────────────\n // CONTENT-ONLY: pure native-file writers under <configDir>/{commands,skills,\n // droids}. No runtime dispatch, no home-bin pointer, no telemetry wrap. Each\n // method is idempotent (byte-identical → skip) via writeContentFile and\n // reversible via removeContentFile. Honors platforms[\"droid\"] per-surface\n // false to skip. Both user and project scope (getConfigDir resolves either).\n //\n // Native locations (live-confirmed Factory dirs):\n // command → <configDir>/commands/<name>.md md+frontmatter(description, argument-hint)\n // skill → <configDir>/skills/<name>/SKILL.md (+ resources)\n // subagent → <configDir>/droids/<name>.md MARKDOWN — folder is droids/, NOT agents/\n\n /** Native command file path: <configDir>/commands/<name>.md. */\n private commandPath(ctx: InstallContext, name: string): string {\n return join(this.getConfigDir(ctx), \"commands\", `${name}.md`);\n }\n /** Native skill dir: <configDir>/skills/<name>. */\n private skillDir(ctx: InstallContext, name: string): string {\n return join(this.getConfigDir(ctx), \"skills\", name);\n }\n /** Native subagent file path: <configDir>/droids/<name>.md (folder droids/, NOT agents/). */\n private subagentPath(ctx: InstallContext, name: string): string {\n return join(this.getConfigDir(ctx), \"droids\", `${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 droid\" }];\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(this.commandPath(ctx, cmd.name), this.renderCommand(cmd), ctx.dryRun),\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, argument-hint). */\n private renderCommand(cmd: CommandDef): string {\n const frontmatter: Record<string, unknown> = {};\n if (cmd.description !== undefined) frontmatter.description = cmd.description;\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 // ── 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 droid\" }];\n }\n if (connector.skills.length === 0) {\n return [{ platform: this.id, action: \"skip\", detail: \"connector declares no skills\" }];\n }\n const changes: ChangeRecord[] = [];\n for (const skill of connector.skills) {\n const dir = this.skillDir(ctx, skill.name);\n changes.push(\n this.writeContentFile(join(dir, \"SKILL.md\"), this.renderSkill(skill), ctx.dryRun),\n );\n // Bundle any resource files beside SKILL.md (relative path → contents).\n // Defense-in-depth: skip+warn on any key that escapes the skill dir\n // (config-time validation already rejects these, but never trust input).\n for (const [rel, contents] of Object.entries(skill.resources ?? {})) {\n const target = this.resolveWithin(dir, rel);\n if (target === null) {\n changes.push({\n platform: this.id,\n action: \"warn\",\n detail: `skill resource \"${rel}\" escapes the skill dir; skipped`,\n });\n continue;\n }\n changes.push(this.writeContentFile(target, contents, ctx.dryRun));\n }\n }\n return changes;\n }\n\n override uninstallSkills(ctx: InstallContext): ChangeRecord[] {\n const { connector } = ctx;\n if (connector.skills.length === 0) {\n return [{ platform: this.id, action: \"skip\", detail: \"connector declares no skills\" }];\n }\n const changes: ChangeRecord[] = [];\n for (const skill of connector.skills) {\n const dir = this.skillDir(ctx, skill.name);\n // Remove only the files we wrote (SKILL.md + declared resources), then the\n // skill dir itself when we own its full contents.\n changes.push(this.removeContentFile(join(dir, \"SKILL.md\"), ctx.dryRun));\n for (const rel of Object.keys(skill.resources ?? {})) {\n const target = this.resolveWithin(dir, rel);\n if (target === null) continue; // never delete outside the skill dir\n changes.push(this.removeContentFile(target, ctx.dryRun));\n }\n // Only remove the skill dir when WE own its full contents — never rm -rf a\n // dir that still holds user-added / sibling-tool / shared files.\n changes.push(this.removeDirIfEmpty(dir, ctx.dryRun));\n }\n return changes;\n }\n\n /**\n * Render a skill's SKILL.md: frontmatter (name, description + optional\n * disable-model-invocation) + body. Droid documents disable-model-invocation\n * as a skill field; it has NO model/allowed-tools skill field, so those are\n * never emitted (unlike the uniform claude/codex renderer).\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.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 (MARKDOWN — folder droids/, NOT agents/) ────────────────────\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 droid\" }];\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 Droid subagent to a MARKDOWN file (NOT TOML — codex emits TOML,\n * which is wrong for droid): YAML frontmatter { name, description?, model? }\n * then the prompt as the markdown body.\n */\n private renderSubagent(agent: SubagentDef): string {\n const frontmatter: Record<string, unknown> = { name: agent.name };\n if (agent.description !== undefined) frontmatter.description = agent.description;\n if (agent.model !== undefined) frontmatter.model = agent.model;\n if (agent.extra) Object.assign(frontmatter, agent.extra);\n return this.renderFrontmatterMd(frontmatter, agent.prompt);\n }\n\n // ── Action surface (executable command file, NO .md extension) ────────────\n // Each action emits an EXECUTABLE script at <configDir>/commands/<id> (no\n // extension) whose shebang lets Droid's CLI exec it; it execs the home-bin\n // action verb and forwards \"$@\". Invoked via `/<id>`, stdout → transcript\n // (docs.factory.ai/cli/configuration/custom-slash-commands). chmod 0o755.\n //\n // COLLISION NOTE: the COMMAND surface writes commands/<name>.md; actions write\n // commands/<id> (no extension) — different filenames, both register `/<name>`.\n // A connector reusing one id for a command AND an action is the author's call.\n //\n // CROSS-OS: the shebang exec-file is POSIX. On win32 Droid's exec-file\n // interpreter resolution is UNVERIFIED, so we skip-warn there and write nothing\n // (honest degradation, like other Windows caveats in the codebase).\n\n /** Native action file path: <configDir>/commands/<id> (NO .md extension). */\n private actionPath(ctx: InstallContext, id: string): string {\n return join(this.getConfigDir(ctx), \"commands\", id);\n }\n\n override installActions(ctx: InstallContext): ChangeRecord[] {\n const { connector } = ctx;\n if (connector.platforms[HOST]?.actions === false) {\n return [{ platform: this.id, action: \"skip\", detail: \"actions disabled for droid\" }];\n }\n const triggers = this.actionTriggers(ctx);\n if (triggers.length === 0) {\n return [{ platform: this.id, action: \"skip\", detail: \"connector declares no actions\" }];\n }\n if (process.platform === \"win32\") {\n return [\n {\n platform: this.id,\n action: \"warn\",\n detail: `droid action exec-files are unverified on Windows; ${triggers.length} skipped`,\n },\n ];\n }\n return triggers.map((trigger) => {\n const path = this.actionPath(ctx, trigger.id);\n const record = this.writeContentFile(path, this.renderActionScript(trigger.command), ctx.dryRun);\n // Set the executable bit so Droid's CLI can call the interpreter. Only\n // when we actually wrote (create/update) and not in dryRun.\n if (record.action !== \"skip\" && !ctx.dryRun) chmodSync(path, 0o755);\n return record;\n });\n }\n\n override uninstallActions(ctx: InstallContext): ChangeRecord[] {\n const { connector } = ctx;\n if (connector.actions.length === 0) {\n return [{ platform: this.id, action: \"skip\", detail: \"connector declares no actions\" }];\n }\n return connector.actions.map((action) =>\n this.removeContentFile(this.actionPath(ctx, action.id), ctx.dryRun),\n );\n }\n\n /** Render the POSIX exec-file: shebang + `exec <action verb> \"$@\"`. */\n private renderActionScript(command: string): string {\n return `#!/usr/bin/env sh\\nexec ${command} \"$@\"\\n`;\n }\n\n // ── Diagnostics ──────────────────────────────────────────────────────────\n\n override getHealthChecks(ctx: InstallContext): readonly HealthCheck[] {\n const mcpPath = this.getServerConfigPath(ctx);\n const hookPath = this.getHookConfigPath(ctx);\n const connectorId = ctx.connector.id;\n const homeBin = ctx.homeBinPath;\n const hookEvents = ctx.connector.hookEvents;\n return [\n {\n name: `${this.name}: mcp.json present`,\n check: () =>\n existsSync(mcpPath)\n ? { status: \"OK\", detail: mcpPath }\n : { status: \"FAIL\", detail: `not found: ${mcpPath}` },\n },\n {\n name: `${this.name}: server entry registered`,\n check: () => {\n if (!ctx.connector.server) {\n return { status: \"OK\", detail: \"no MCP server declared\" };\n }\n const cfg = this.readJson<{ [k: string]: Record<string, unknown> }>(mcpPath);\n const bucket = cfg?.[MCP_ROOT_KEY];\n if (!cfg || !bucket) {\n return { status: \"FAIL\", detail: `no ${MCP_ROOT_KEY} in ${mcpPath}` };\n }\n return connectorId in bucket\n ? { status: \"OK\", detail: `${MCP_ROOT_KEY}.${connectorId} present` }\n : {\n status: \"FAIL\",\n detail: `no ${MCP_ROOT_KEY}.${connectorId} in ${mcpPath}`,\n };\n },\n },\n {\n name: `${this.name}: hook command registered`,\n check: () => {\n if (hookEvents.length === 0) {\n return { status: \"OK\", detail: \"no hooks declared\" };\n }\n const file = this.readJson<DroidHooksFile>(hookPath);\n if (!file) return { status: \"FAIL\", detail: `cannot read ${hookPath}` };\n const hooks = file.hooks ?? {};\n const registered = Object.values(hooks).some((entries) =>\n (entries ?? []).some((e) =>\n (e.hooks ?? []).some((h) =>\n isHomeBinHookCommand(h.command, homeBin, connectorId),\n ),\n ),\n );\n return registered\n ? { status: \"OK\", detail: \"hook command present\" }\n : { status: \"FAIL\", detail: `no hook for ${connectorId} in ${hookPath}` };\n },\n },\n ];\n }\n\n // ── Runtime: parse Droid stdin JSON → normalized event ────────────────────\n\n parseEvent(event: HookEventName, raw: unknown): NormalizedEvent {\n const input = (raw ?? {}) as DroidWireInput;\n const connectorId = typeof input.connector === \"string\" ? input.connector : \"\";\n const sessionId = typeof input.session_id === \"string\" ? input.session_id : \"\";\n const projectDir = typeof input.cwd === \"string\" ? input.cwd : undefined;\n\n const base = {\n hostPlatform: HOST,\n connectorId,\n sessionId,\n raw,\n ...(projectDir !== undefined ? { projectDir } : {}),\n } as const;\n\n switch (event) {\n case \"PreToolUse\": {\n const ev: PreToolUseEvent = {\n ...base,\n toolName: input.tool_name ?? \"\",\n toolInput: input.tool_input ?? {},\n };\n return ev;\n }\n case \"PostToolUse\": {\n const ev: PostToolUseEvent = {\n ...base,\n toolName: input.tool_name ?? \"\",\n toolInput: input.tool_input ?? {},\n ...(toolResponseToString(input.tool_response) !== undefined\n ? { toolOutput: toolResponseToString(input.tool_response) }\n : {}),\n };\n return ev;\n }\n case \"UserPromptSubmit\": {\n const ev: UserPromptSubmitEvent = {\n ...base,\n prompt: typeof input.prompt === \"string\" ? input.prompt : \"\",\n };\n return ev;\n }\n case \"Stop\": {\n const ev: StopEvent = {\n ...base,\n ...(typeof input.stop_hook_active === \"boolean\"\n ? { stopHookActive: input.stop_hook_active }\n : {}),\n };\n return ev;\n }\n case \"SubagentStop\": {\n // agent_id/agent_type stay optional — hosts do not reliably populate\n // agent_type on SubagentStop (Claude-compatible quirk).\n const ev: SubagentStopEvent = {\n ...base,\n ...(typeof input.agent_id === \"string\" ? { agentId: input.agent_id } : {}),\n ...(typeof input.agent_type === \"string\"\n ? { agentType: input.agent_type }\n : {}),\n ...(typeof input.agent_transcript_path === \"string\"\n ? { agentTranscriptPath: input.agent_transcript_path }\n : {}),\n ...(typeof input.last_assistant_message === \"string\"\n ? { lastAssistantMessage: input.last_assistant_message }\n : {}),\n ...(typeof input.stop_hook_active === \"boolean\"\n ? { stopHookActive: input.stop_hook_active }\n : {}),\n };\n return ev;\n }\n case \"Notification\": {\n // Droid Notification: { …, hook_event_name:\"Notification\", message }\n // (docs.factory.ai/reference/hooks-reference). Only `message` maps.\n const ev: NotificationEvent = {\n ...base,\n message: typeof input.message === \"string\" ? input.message : \"\",\n };\n return ev;\n }\n case \"PreCompact\": {\n // Droid PreCompact: { …, trigger:\"manual\"|\"auto\", custom_instructions }.\n // Only the documented `trigger` enum maps; custom_instructions rides on\n // base.raw (no normalized field).\n const ev: PreCompactEvent = {\n ...base,\n ...(input.trigger === \"auto\" || input.trigger === \"manual\"\n ? { trigger: input.trigger }\n : {}),\n };\n return ev;\n }\n case \"SessionStart\": {\n // Droid SessionStart: { …, source:\"startup\"|\"resume\"|\"clear\"|\"compact\" }.\n // Coerce the documented matcher source onto the normalized enum.\n const ev: SessionStartEvent = {\n ...base,\n source: normalizeSessionSource(input.source),\n };\n return ev;\n }\n case \"SessionEnd\": {\n // Droid SessionEnd: { …, reason:\"clear\"|\"logout\"|\"prompt_input_exit\"|\n // \"other\" }. Only the documented `reason` maps.\n const ev: SessionEndEvent = {\n ...base,\n ...(typeof input.reason === \"string\" ? { reason: input.reason } : {}),\n };\n return ev;\n }\n default: {\n // Droid never delivers PermissionRequest / PostToolUseFailure /\n // SubagentStart (no native equivalent — see SUPPORTED_EVENTS). If the\n // runtime dispatches one anyway, surface it loudly rather than silently\n // mis-parse.\n throw new Error(`unsupported droid hook event: ${String(event)}`);\n }\n }\n }\n\n // ── Runtime: normalized response → Droid native (Claude-shaped) hook reply ─\n\n formatReply(event: HookEventName, response: HookResponse): HookReply {\n const hookEventName = event;\n const decision = response.decision ?? \"allow\";\n\n // Notification / PreCompact / SessionEnd are observe-only: per\n // docs.factory.ai/reference/hooks-reference their Decision Control is \"N/A\"\n // (cannot block) and they carry no context-injection surface, so every\n // decision is an unconditional no-op passthrough (mirrors Stop). SessionStart\n // is deliberately NOT here — it honors hookSpecificOutput.additionalContext,\n // so it falls through to the generic `context` branch below.\n if (event === \"Notification\" || event === \"PreCompact\" || event === \"SessionEnd\") {\n return { exitCode: 0 };\n }\n\n // deny → block the action with a reason (exit 0; JSON carries the decision).\n if (decision === \"deny\") {\n // SubagentStop deny carries Stop semantics — it keeps the subagent\n // running with `reason` as its next instruction — and (Claude-compatible)\n // is honored only as the TOP-LEVEL {\"decision\":\"block\",\"reason\"}, not as\n // a permissionDecision envelope.\n if (event === \"SubagentStop\") {\n return this.stdout({\n decision: \"block\",\n reason: response.reason ?? \"Blocked by hook\",\n });\n }\n return this.stdout({\n hookSpecificOutput: {\n hookEventName,\n permissionDecision: \"deny\",\n permissionDecisionReason: response.reason ?? \"Blocked by hook\",\n },\n });\n }\n\n // ask → prompt the user to confirm.\n if (decision === \"ask\") {\n return this.stdout({\n hookSpecificOutput: {\n hookEventName,\n permissionDecision: \"ask\",\n permissionDecisionReason: response.reason ?? \"Confirmation required by hook\",\n },\n });\n }\n\n // context → inject soft guidance (Droid honors additionalContext).\n if (decision === \"context\" && response.additionalContext) {\n return this.stdout({\n hookSpecificOutput: { hookEventName, additionalContext: response.additionalContext },\n });\n }\n\n // allow / modify (unsupported — exit-code/decision protocol only) / void →\n // pass through with exit 0.\n return { exitCode: 0 };\n }\n\n private stdout(payload: unknown): HookReply {\n return { exitCode: 0, stdout: JSON.stringify(payload) };\n }\n}\n\n/**\n * Coerce Droid's SessionStart `source` matcher value onto the normalized\n * SessionStartEvent enum. Droid documents startup | resume | clear | compact\n * (docs.factory.ai/reference/hooks-reference); anything else defaults to startup.\n */\nfunction normalizeSessionSource(source: string | undefined): SessionStartEvent[\"source\"] {\n switch (source) {\n case \"compact\":\n return \"compact\";\n case \"resume\":\n return \"resume\";\n case \"clear\":\n return \"clear\";\n default:\n return \"startup\";\n }\n}\n\n/** Coerce a Droid PostToolUse `tool_response` into a string for the normalized event. */\nfunction toolResponseToString(value: unknown): string | undefined {\n if (value == null) return undefined;\n if (typeof value === \"string\") return value;\n try {\n return JSON.stringify(value);\n } catch {\n return String(value);\n }\n}\n\nexport const adapter = new DroidAdapter();\nexport default adapter;\n"],"mappings":"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","names":["entry"]}
|
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
} from "./chunk-DBQMX75U.js";
|
|
8
8
|
import {
|
|
9
9
|
BaseAdapter
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-CPLK7GTE.js";
|
|
11
11
|
import "./chunk-7L6ITC4T.js";
|
|
12
12
|
import {
|
|
13
13
|
buildHomeBinHookCommand,
|
|
@@ -17,7 +17,7 @@ import {
|
|
|
17
17
|
isHostNativeUsageEnabled,
|
|
18
18
|
isUsageEventCommand,
|
|
19
19
|
shouldWrapForTelemetry
|
|
20
|
-
} from "./chunk-
|
|
20
|
+
} from "./chunk-I5MLE6S7.js";
|
|
21
21
|
import "./chunk-N6HH7K6P.js";
|
|
22
22
|
import "./chunk-TRQKHP7D.js";
|
|
23
23
|
|
|
@@ -83,6 +83,14 @@ var GeminiCliAdapter = class extends BaseAdapter {
|
|
|
83
83
|
supportsCommands: true,
|
|
84
84
|
supportsSkills: true,
|
|
85
85
|
supportsSubagents: true,
|
|
86
|
+
// Native passthrough hooks: Gemini's LLM-lifecycle events (BeforeModel,
|
|
87
|
+
// AfterAgent, BeforeToolSelection, AfterModel, …) have NO normalized
|
|
88
|
+
// HookEventName — they are request-mutating and gemini-only, below the
|
|
89
|
+
// >=3-host core bar (docs/research/host-specific-hook-events-design.md). A
|
|
90
|
+
// connector reaches them by declaring platforms["gemini-cli"].nativeHooks;
|
|
91
|
+
// installHooks writes those event-name keys verbatim into settings.json with
|
|
92
|
+
// the same home-bin command shape, and the generic uninstall reverses them.
|
|
93
|
+
supportsNativeHooks: true,
|
|
86
94
|
// Memory surface — EXCEPTION host: Gemini reads GEMINI.md by default;
|
|
87
95
|
// AGENTS.md only when the user opted in via settings `context.fileName`.
|
|
88
96
|
// memoryTargets below probes that setting (and NEVER edits it).
|
|
@@ -200,19 +208,27 @@ var GeminiCliAdapter = class extends BaseAdapter {
|
|
|
200
208
|
// ── Hook install / uninstall ─────────────────────────────────────────────
|
|
201
209
|
installHooks(ctx) {
|
|
202
210
|
const { connector } = ctx;
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
const
|
|
207
|
-
|
|
208
|
-
|
|
211
|
+
const override = connector.platforms[HOST];
|
|
212
|
+
const hooksDisabled = override?.hooks === false;
|
|
213
|
+
const normalizedEvents = hooksDisabled ? [] : connector.hookEvents;
|
|
214
|
+
const nativeHooks = override?.nativeHooks ?? {};
|
|
215
|
+
const nativeEvents = Object.keys(nativeHooks);
|
|
216
|
+
const hostNative = !hooksDisabled && isHostNativeUsageEnabled(connector.telemetry);
|
|
217
|
+
if (normalizedEvents.length === 0 && nativeEvents.length === 0 && !hostNative) {
|
|
218
|
+
return [
|
|
219
|
+
{
|
|
220
|
+
platform: this.id,
|
|
221
|
+
action: "skip",
|
|
222
|
+
detail: hooksDisabled ? "hooks disabled for gemini-cli" : "connector declares no hooks"
|
|
223
|
+
}
|
|
224
|
+
];
|
|
209
225
|
}
|
|
210
226
|
const settingsPath = this.getHookConfigPath(ctx);
|
|
211
227
|
const settings = this.readJson(settingsPath) ?? {};
|
|
212
228
|
const hooks = settings.hooks ??= {};
|
|
213
229
|
const changes = [];
|
|
214
230
|
let mutated = false;
|
|
215
|
-
for (const event of
|
|
231
|
+
for (const event of normalizedEvents) {
|
|
216
232
|
const geminiEvent = EVENT_MAP[event];
|
|
217
233
|
if (!geminiEvent) {
|
|
218
234
|
changes.push({
|
|
@@ -259,6 +275,12 @@ var GeminiCliAdapter = class extends BaseAdapter {
|
|
|
259
275
|
}
|
|
260
276
|
mutated = true;
|
|
261
277
|
}
|
|
278
|
+
for (const event of nativeEvents) {
|
|
279
|
+
const matcher = nativeHooks[event]?.matcher ?? "";
|
|
280
|
+
if (this.upsertNativeHook(ctx, hooks, event, matcher, settingsPath, changes)) {
|
|
281
|
+
mutated = true;
|
|
282
|
+
}
|
|
283
|
+
}
|
|
262
284
|
if (hostNative) {
|
|
263
285
|
if (this.installUsageHook(hooks, ctx, settingsPath, changes)) mutated = true;
|
|
264
286
|
}
|
|
@@ -359,6 +381,36 @@ var GeminiCliAdapter = class extends BaseAdapter {
|
|
|
359
381
|
}
|
|
360
382
|
return changes;
|
|
361
383
|
}
|
|
384
|
+
/**
|
|
385
|
+
* Upsert one NATIVE (gemini-native event-name) hook into `hooks[event]`. The key
|
|
386
|
+
* is written verbatim (no EVENT_MAP). Matched by EXACT command — not just
|
|
387
|
+
* "one of ours" — so a native key that coincides with a normalized event's
|
|
388
|
+
* mapped key never clobbers the normalized entry; it adds a second, distinct
|
|
389
|
+
* command instead. Idempotent: byte-identical → skip, drifted → update.
|
|
390
|
+
*/
|
|
391
|
+
upsertNativeHook(ctx, hooks, event, matcher, settingsPath, changes) {
|
|
392
|
+
const command = buildHomeBinHookCommand(ctx.homeBinPath, HOST, event, ctx.connector.id);
|
|
393
|
+
const entry = { matcher, hooks: [{ type: "command", command }] };
|
|
394
|
+
const bucket = hooks[event] ??= [];
|
|
395
|
+
const existingIdx = bucket.findIndex((e) => (e.hooks ?? []).some((h) => h.command === command));
|
|
396
|
+
if (existingIdx >= 0) {
|
|
397
|
+
if (JSON.stringify(bucket[existingIdx]) === JSON.stringify(entry)) {
|
|
398
|
+
changes.push({
|
|
399
|
+
platform: this.id,
|
|
400
|
+
action: "skip",
|
|
401
|
+
path: settingsPath,
|
|
402
|
+
detail: `hooks.${event} (native) already registered`
|
|
403
|
+
});
|
|
404
|
+
return false;
|
|
405
|
+
}
|
|
406
|
+
bucket[existingIdx] = entry;
|
|
407
|
+
changes.push({ platform: this.id, action: "update", path: settingsPath, detail: `hooks.${event} (native)` });
|
|
408
|
+
} else {
|
|
409
|
+
bucket.push(entry);
|
|
410
|
+
changes.push({ platform: this.id, action: "create", path: settingsPath, detail: `hooks.${event} (native)` });
|
|
411
|
+
}
|
|
412
|
+
return true;
|
|
413
|
+
}
|
|
362
414
|
entryHasOurCommand(entry, ctx) {
|
|
363
415
|
return (entry.hooks ?? []).some((h) => this.isOurCommand(h.command, ctx));
|
|
364
416
|
}
|
|
@@ -750,4 +802,4 @@ export {
|
|
|
750
802
|
adapter,
|
|
751
803
|
gemini_cli_default as default
|
|
752
804
|
};
|
|
753
|
-
//# sourceMappingURL=gemini-cli-
|
|
805
|
+
//# sourceMappingURL=gemini-cli-ILR7M5X3.js.map
|