heedvane 0.0.0-stage → 0.1.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.
Files changed (94) hide show
  1. package/README.md +27 -2
  2. package/dist/apply.d.ts +104 -0
  3. package/dist/apply.js +388 -0
  4. package/dist/backend/client.d.ts +40 -0
  5. package/dist/backend/client.js +32 -0
  6. package/dist/backend/credentials.d.ts +15 -0
  7. package/dist/backend/credentials.js +76 -0
  8. package/dist/backend/login.d.ts +33 -0
  9. package/dist/backend/login.js +265 -0
  10. package/dist/backend/repo-remote.d.ts +15 -0
  11. package/dist/backend/repo-remote.js +61 -0
  12. package/dist/backend/sign-in-change.d.ts +12 -0
  13. package/dist/backend/sign-in-change.js +72 -0
  14. package/dist/best-effort.d.ts +4 -0
  15. package/dist/best-effort.js +25 -0
  16. package/dist/cli.d.ts +24 -0
  17. package/dist/cli.js +544 -0
  18. package/dist/clients/definitions.d.ts +113 -0
  19. package/dist/clients/definitions.js +427 -0
  20. package/dist/clients/hermes-plugin.d.ts +33 -0
  21. package/dist/clients/hermes-plugin.js +247 -0
  22. package/dist/commands/heedvane.d.ts +15 -0
  23. package/dist/commands/heedvane.js +74 -0
  24. package/dist/commands/memory.d.ts +10 -0
  25. package/dist/commands/memory.js +106 -0
  26. package/dist/config-doc.d.ts +97 -0
  27. package/dist/config-doc.js +465 -0
  28. package/dist/dispatchers/posix.d.ts +32 -0
  29. package/dist/dispatchers/posix.js +191 -0
  30. package/dist/dispatchers/snippets.d.ts +6 -0
  31. package/dist/dispatchers/snippets.js +39 -0
  32. package/dist/dispatchers/windows.d.ts +15 -0
  33. package/dist/dispatchers/windows.js +50 -0
  34. package/dist/doctor.d.ts +37 -0
  35. package/dist/doctor.js +316 -0
  36. package/dist/events/contract.d.ts +54 -0
  37. package/dist/events/contract.js +87 -0
  38. package/dist/events/normalize.d.ts +36 -0
  39. package/dist/events/normalize.js +143 -0
  40. package/dist/guards.d.ts +18 -0
  41. package/dist/guards.js +28 -0
  42. package/dist/heed-file.d.ts +67 -0
  43. package/dist/heed-file.js +295 -0
  44. package/dist/listener/endpoint.d.ts +21 -0
  45. package/dist/listener/endpoint.js +112 -0
  46. package/dist/listener/forward.d.ts +36 -0
  47. package/dist/listener/forward.js +257 -0
  48. package/dist/listener/serve.d.ts +2 -0
  49. package/dist/listener/serve.js +155 -0
  50. package/dist/listener/server.d.ts +48 -0
  51. package/dist/listener/server.js +251 -0
  52. package/dist/listener/spool.d.ts +28 -0
  53. package/dist/listener/spool.js +60 -0
  54. package/dist/mcp-server.d.ts +9 -0
  55. package/dist/mcp-server.js +187 -0
  56. package/dist/mcp.d.ts +57 -0
  57. package/dist/mcp.js +83 -0
  58. package/dist/memory/private-memory.d.ts +12 -0
  59. package/dist/memory/private-memory.js +54 -0
  60. package/dist/memory/table-of-contents.d.ts +10 -0
  61. package/dist/memory/table-of-contents.js +80 -0
  62. package/dist/memory/team-memory.d.ts +60 -0
  63. package/dist/memory/team-memory.js +54 -0
  64. package/dist/plan.d.ts +77 -0
  65. package/dist/plan.js +288 -0
  66. package/dist/render.d.ts +30 -0
  67. package/dist/render.js +131 -0
  68. package/dist/reply/harness-output.d.ts +57 -0
  69. package/dist/reply/harness-output.js +88 -0
  70. package/dist/reply/reply.d.ts +65 -0
  71. package/dist/reply/reply.js +169 -0
  72. package/dist/reply/verdict.d.ts +28 -0
  73. package/dist/reply/verdict.js +17 -0
  74. package/dist/skill/bundle.d.ts +23 -0
  75. package/dist/skill/bundle.js +102 -0
  76. package/dist/skill/content.d.ts +16 -0
  77. package/dist/skill/content.js +182 -0
  78. package/dist/skills/approved.d.ts +31 -0
  79. package/dist/skills/approved.js +123 -0
  80. package/dist/skills/check.d.ts +21 -0
  81. package/dist/skills/check.js +83 -0
  82. package/dist/state.d.ts +51 -0
  83. package/dist/state.js +118 -0
  84. package/dist/steering/rules.d.ts +49 -0
  85. package/dist/steering/rules.js +165 -0
  86. package/dist/steering/steer.d.ts +29 -0
  87. package/dist/steering/steer.js +64 -0
  88. package/dist/steering/violations.d.ts +27 -0
  89. package/dist/steering/violations.js +24 -0
  90. package/dist/uninstall.d.ts +23 -0
  91. package/dist/uninstall.js +159 -0
  92. package/package.json +34 -4
  93. package/skills/heedvane-hooks/SKILL.md +87 -0
  94. package/skills/heedvane-hooks/references/events.md +69 -0
@@ -0,0 +1,427 @@
1
+ /**
2
+ * Declarative table of supported coding-agent clients.
3
+ *
4
+ * One source of truth for every agent `heedvane-hook` can integrate with:
5
+ * detection marker, config targets (path + format + purpose), capabilities,
6
+ * and the agent's native hook-event set. Path fragments are home-relative;
7
+ * {@link supportedClients} resolves them into absolute per-platform paths
8
+ * from a pure `{ home, platform, env }` context (no process state, so the
9
+ * table is trivially testable against fixture homes).
10
+ *
11
+ * This module imports nothing outside `node:path` — the package must stay
12
+ * standalone-publishable (no intra-monorepo imports, no Effect).
13
+ */
14
+ import { posix, win32 } from "node:path";
15
+ // Single owner of the canonical taxonomy: src/events/contract.ts.
16
+ import { CANONICAL_EVENTS } from "../events/contract.js";
17
+ /** Harness-neutral canonical taxonomy (v1). Native sets normalize into this.
18
+ * Single owner: src/events/contract.ts — re-exported here for the table. */
19
+ /** Claude Code's 14 native hook events (verified against its hook contract). */
20
+ const CLAUDE_EVENTS = [
21
+ "SessionStart",
22
+ "SessionEnd",
23
+ "UserPromptSubmit",
24
+ "PreToolUse",
25
+ "PostToolUse",
26
+ "PostToolUseFailure",
27
+ "PermissionRequest",
28
+ "Stop",
29
+ "StopFailure",
30
+ "SubagentStart",
31
+ "SubagentStop",
32
+ "TeammateIdle",
33
+ "PreCompact",
34
+ "PostCompact",
35
+ ];
36
+ /** Codex's 11 native hook events (Claude's set minus TeammateIdle/PostCompact). */
37
+ const CODEX_EVENTS = [
38
+ "SessionStart",
39
+ "SessionEnd",
40
+ "UserPromptSubmit",
41
+ "PreToolUse",
42
+ "PostToolUse",
43
+ "PostToolUseFailure",
44
+ "PermissionRequest",
45
+ "Stop",
46
+ "StopFailure",
47
+ "SubagentStart",
48
+ "SubagentStop",
49
+ ];
50
+ /** Gemini CLI's own hook event names; its registry skips any other key (https://geminicli.com/docs/hooks/reference/). */
51
+ const GEMINI_EVENTS = [
52
+ "SessionStart",
53
+ "SessionEnd",
54
+ "BeforeAgent",
55
+ "AfterAgent",
56
+ "BeforeTool",
57
+ "AfterTool",
58
+ "PreCompress",
59
+ "Notification",
60
+ ];
61
+ /** Cursor's camelCase hook event names (https://cursor.com/docs/hooks). */
62
+ const CURSOR_EVENTS = [
63
+ "sessionStart",
64
+ "sessionEnd",
65
+ "beforeSubmitPrompt",
66
+ "preToolUse",
67
+ "postToolUse",
68
+ "stop",
69
+ "subagentStop",
70
+ ];
71
+ /** Kimi Code documents Claude-style PascalCase hook events in config.toml. */
72
+ const KIMI_EVENTS = ["PreToolUse", "PostToolUse"];
73
+ const settings = (segments, purpose) => ({
74
+ segments,
75
+ base: "client",
76
+ format: "json",
77
+ purpose,
78
+ });
79
+ /**
80
+ * The declarative table. First-class rows (claude, codex, gemini, cursor,
81
+ * warp, opencode, hermes) are behavior-tested; the remaining rows ride the
82
+ * same resolver and get snapshot tests only.
83
+ */
84
+ const SUPPORTED_CLIENTS = [
85
+ {
86
+ id: "claude",
87
+ displayName: "Claude Code",
88
+ markerSegments: [".claude"],
89
+ base: "home",
90
+ platformConfigAppName: "Claude",
91
+ altMarkers: [{ segments: [], base: "platform-config" }],
92
+ homeOverrideEnv: "CLAUDE_CONFIG_DIR",
93
+ configs: [
94
+ settings(["settings.json"], "hooks"),
95
+ { segments: [".claude.json"], base: "home", format: "json", purpose: "mcp" },
96
+ ],
97
+ capabilities: ["hooks", "mcp", "skill"],
98
+ events: CLAUDE_EVENTS,
99
+ mcpServersKey: "mcpServers",
100
+ },
101
+ {
102
+ id: "codex",
103
+ displayName: "Codex",
104
+ markerSegments: [".codex"],
105
+ base: "home",
106
+ platformConfigAppName: "Codex",
107
+ altMarkers: [{ segments: [], base: "platform-config" }],
108
+ homeOverrideEnv: "CODEX_HOME",
109
+ configs: [
110
+ { segments: ["hooks.json"], base: "client", format: "json", purpose: "hooks" },
111
+ { segments: ["config.toml"], base: "client", format: "toml", purpose: "mcp" },
112
+ ],
113
+ capabilities: ["hooks", "mcp", "skill"],
114
+ events: CODEX_EVENTS,
115
+ mcpServersKey: "mcp_servers",
116
+ },
117
+ {
118
+ id: "gemini",
119
+ displayName: "Gemini CLI",
120
+ markerSegments: [".gemini"],
121
+ base: "home",
122
+ configs: [
123
+ settings(["settings.json"], "hooks"),
124
+ settings(["settings.json"], "mcp"),
125
+ ],
126
+ capabilities: ["hooks", "mcp", "skill"],
127
+ events: GEMINI_EVENTS,
128
+ mcpServersKey: "mcpServers",
129
+ },
130
+ {
131
+ id: "cursor",
132
+ displayName: "Cursor",
133
+ markerSegments: [".cursor"],
134
+ base: "home",
135
+ configs: [
136
+ { segments: ["hooks.json"], base: "client", format: "json", purpose: "hooks" },
137
+ { segments: ["mcp.json"], base: "client", format: "json", purpose: "mcp" },
138
+ ],
139
+ capabilities: ["hooks", "mcp", "skill"],
140
+ events: CURSOR_EVENTS,
141
+ mcpServersKey: "mcpServers",
142
+ hookEntries: "flat",
143
+ hooksVersion: 1,
144
+ // Cursor loads ~/.claude/settings.json hooks by default (https://cursor.com/docs/reference/third-party-hooks).
145
+ runsHooksOf: "claude",
146
+ },
147
+ {
148
+ id: "warp",
149
+ displayName: "Warp",
150
+ markerSegments: [".warp"],
151
+ base: "home",
152
+ configs: [
153
+ {
154
+ segments: [".mcp.json"],
155
+ base: "client",
156
+ format: "json",
157
+ purpose: "mcp",
158
+ limitation: "Warp has no native hook events (hooks unavailable); ~/.warp/.mcp.json is project-level, and user-level MCP requires explicit in-app approval of the import.",
159
+ },
160
+ ],
161
+ capabilities: ["mcp", "skill"],
162
+ events: [],
163
+ mcpServersKey: "mcpServers",
164
+ limitation: "Warp exposes no native hook events — policies ship via MCP only, and the MCP import needs explicit user approval in Warp.",
165
+ },
166
+ {
167
+ id: "opencode",
168
+ displayName: "OpenCode",
169
+ markerSegments: ["opencode"],
170
+ base: "xdg-config",
171
+ configs: [
172
+ { segments: ["opencode.json"], base: "client", format: "opencode", purpose: "hooks" },
173
+ { segments: ["opencode.json"], base: "client", format: "opencode", purpose: "mcp" },
174
+ ],
175
+ capabilities: ["hooks", "mcp", "skill"],
176
+ events: [
177
+ "session_start",
178
+ "session_end",
179
+ "user_prompt_submit",
180
+ "pre_tool_use",
181
+ "post_tool_use",
182
+ "permission_request",
183
+ ],
184
+ mcpServersKey: "mcp",
185
+ },
186
+ {
187
+ id: "hermes",
188
+ displayName: "Hermes",
189
+ markerSegments: [".hermes"],
190
+ base: "home",
191
+ configs: [
192
+ { segments: ["plugins", "heedvane-hooks"], base: "client", format: "yaml", purpose: "plugin" },
193
+ ],
194
+ capabilities: ["plugin-install", "skill"],
195
+ events: [
196
+ "on_session_start",
197
+ "pre_llm_call",
198
+ "pre_tool_call",
199
+ "post_tool_call",
200
+ "pre_approval_request",
201
+ "post_approval_response",
202
+ "on_session_end",
203
+ "on_session_finalize",
204
+ ],
205
+ mcpServersKey: "mcpServers",
206
+ notes: "Hermes integrates via a plugin install (~/.hermes/plugins/heedvane-hooks) using its native hook API — not a hooks.json/config.toml write.",
207
+ },
208
+ {
209
+ // --- Snapshot-tested rows (same table, same resolver, no bespoke tests) ---
210
+ id: "qwen-code",
211
+ displayName: "Qwen Code",
212
+ markerSegments: [".qwen"],
213
+ base: "home",
214
+ configs: [
215
+ settings(["settings.json"], "hooks"),
216
+ settings(["settings.json"], "mcp"),
217
+ ],
218
+ capabilities: ["hooks", "mcp", "skill"],
219
+ events: CANONICAL_EVENTS,
220
+ mcpServersKey: "mcpServers",
221
+ },
222
+ {
223
+ id: "kimi",
224
+ displayName: "Kimi Code",
225
+ markerSegments: [".kimi-code"],
226
+ base: "home",
227
+ homeOverrideEnv: "KIMI_CODE_HOME",
228
+ configs: [
229
+ { segments: ["config.toml"], base: "client", format: "toml", purpose: "hooks" },
230
+ { segments: ["config.toml"], base: "client", format: "toml", purpose: "mcp" },
231
+ ],
232
+ capabilities: ["hooks", "mcp", "skill"],
233
+ events: KIMI_EVENTS,
234
+ mcpServersKey: "mcp_servers",
235
+ },
236
+ {
237
+ id: "droid",
238
+ displayName: "Droid (Factory)",
239
+ markerSegments: [".factory"],
240
+ base: "home",
241
+ configs: [
242
+ { segments: ["mcp.json"], base: "client", format: "json", purpose: "mcp" },
243
+ ],
244
+ capabilities: ["mcp", "skill"],
245
+ events: [],
246
+ mcpServersKey: "mcpServers",
247
+ },
248
+ {
249
+ id: "antigravity",
250
+ displayName: "Antigravity",
251
+ markerSegments: [".gemini", "antigravity"],
252
+ altMarkers: [{ segments: [".gemini", "config"], base: "home" }],
253
+ base: "home",
254
+ configs: [
255
+ { segments: [".gemini", "config", "hooks.json"], base: "home", format: "json", purpose: "hooks" },
256
+ { segments: ["mcp_config.json"], base: "client", format: "json", purpose: "mcp" },
257
+ ],
258
+ capabilities: ["hooks", "mcp", "skill"],
259
+ events: CLAUDE_EVENTS,
260
+ mcpServersKey: "mcpServers",
261
+ },
262
+ {
263
+ id: "copilot_cli",
264
+ displayName: "GitHub Copilot CLI",
265
+ markerSegments: [".copilot"],
266
+ base: "home",
267
+ homeOverrideEnv: "COPILOT_HOME",
268
+ configs: [
269
+ { segments: ["mcp.json"], base: "client", format: "json", purpose: "mcp" },
270
+ ],
271
+ capabilities: ["mcp", "skill"],
272
+ events: [],
273
+ mcpServersKey: "mcpServers",
274
+ },
275
+ {
276
+ id: "windsurf",
277
+ displayName: "Windsurf",
278
+ markerSegments: [".codeium", "windsurf"],
279
+ base: "home",
280
+ configs: [
281
+ { segments: ["mcp_config.json"], base: "client", format: "json", purpose: "mcp" },
282
+ ],
283
+ capabilities: ["mcp"],
284
+ events: [],
285
+ mcpServersKey: "mcpServers",
286
+ },
287
+ {
288
+ id: "vscode",
289
+ displayName: "VS Code",
290
+ markerSegments: [".vscode"],
291
+ markerBase: "home",
292
+ base: "platform-config",
293
+ platformConfigAppName: "Code",
294
+ configs: [
295
+ { segments: ["User", "mcp.json"], base: "client", format: "vscode", purpose: "mcp" },
296
+ ],
297
+ capabilities: ["mcp"],
298
+ events: [],
299
+ mcpServersKey: "servers",
300
+ },
301
+ {
302
+ id: "claude_desktop",
303
+ displayName: "Claude Desktop",
304
+ markerSegments: [],
305
+ base: "platform-config",
306
+ platformConfigAppName: "Claude",
307
+ configs: [
308
+ { segments: ["claude_desktop_config.json"], base: "client", format: "json", purpose: "mcp" },
309
+ ],
310
+ capabilities: ["mcp", "skill"],
311
+ events: [],
312
+ mcpServersKey: "mcpServers",
313
+ },
314
+ ];
315
+ const pathImplFor = (platform) => (platform === "win32" ? win32 : posix);
316
+ function xdgConfigRoot(ctx, p) {
317
+ const override = ctx.env["XDG_CONFIG_HOME"];
318
+ return override ? absoluteOrHome(override, ctx, p) : p.join(ctx.home, ".config");
319
+ }
320
+ function platformConfigDir(def, ctx, p) {
321
+ const appName = def.platformConfigAppName;
322
+ if (!appName)
323
+ throw new Error(`Client ${def.id} uses base "platform-config" without platformConfigAppName`);
324
+ switch (ctx.platform) {
325
+ case "darwin":
326
+ return p.join(ctx.home, "Library", "Application Support", appName);
327
+ case "win32": {
328
+ const appData = ctx.env["APPDATA"] ?? p.join(ctx.home, "AppData", "Roaming");
329
+ return p.join(absoluteOrHome(appData, ctx, p), appName);
330
+ }
331
+ default:
332
+ return p.join(xdgConfigRoot(ctx, p), appName);
333
+ }
334
+ }
335
+ /** Treat a relative env override as home-relative so resolution never throws. */
336
+ function absoluteOrHome(value, ctx, p) {
337
+ return p.isAbsolute(value) ? value : p.join(ctx.home, value);
338
+ }
339
+ /** The client's own directory (marker + `client`-base configs resolve here). */
340
+ function clientDir(def, ctx, p) {
341
+ switch (def.base) {
342
+ case "home": {
343
+ const override = def.homeOverrideEnv ? ctx.env[def.homeOverrideEnv] : undefined;
344
+ if (override)
345
+ return absoluteOrHome(override, ctx, p);
346
+ return p.join(ctx.home, ...def.markerSegments);
347
+ }
348
+ case "xdg-config":
349
+ return p.join(xdgConfigRoot(ctx, p), ...def.markerSegments);
350
+ case "platform-config":
351
+ return p.join(platformConfigDir(def, ctx, p), ...def.markerSegments);
352
+ }
353
+ }
354
+ function resolveMarkerBase(target, ctx, p) {
355
+ const { def, markerBase, segments } = target;
356
+ switch (markerBase) {
357
+ case "home":
358
+ return p.join(ctx.home, ...segments);
359
+ case "xdg-config":
360
+ return p.join(xdgConfigRoot(ctx, p), ...segments);
361
+ case "platform-config":
362
+ return p.join(platformConfigDir(def, ctx, p), ...segments);
363
+ }
364
+ }
365
+ function markerPath(def, ctx, p) {
366
+ const markerBase = def.markerBase ?? def.base;
367
+ if (markerBase === def.base)
368
+ return clientDir(def, ctx, p);
369
+ return resolveMarkerBase({ def, markerBase, segments: def.markerSegments }, ctx, p);
370
+ }
371
+ function resolveConfigTarget(def, target, resolve) {
372
+ const { ctx, p } = resolve;
373
+ let path;
374
+ switch (target.base) {
375
+ case "client": {
376
+ // When the marker lives outside the platform config dir (markerBase
377
+ // override), `client`-base targets resolve against the app config dir
378
+ // root itself, not the marker-relative client directory.
379
+ const base = def.base === "platform-config" && def.markerBase !== def.base
380
+ ? platformConfigDir(def, ctx, p)
381
+ : clientDir(def, ctx, p);
382
+ path = p.join(base, ...target.segments);
383
+ break;
384
+ }
385
+ case "home":
386
+ path = p.join(ctx.home, ...target.segments);
387
+ break;
388
+ case "platform-config":
389
+ path = p.join(platformConfigDir(def, ctx, p), ...target.segments);
390
+ break;
391
+ }
392
+ return target.limitation === undefined
393
+ ? { path, format: target.format, purpose: target.purpose }
394
+ : { path, format: target.format, purpose: target.purpose, limitation: target.limitation };
395
+ }
396
+ function assertSupportedPlatform(platform) {
397
+ if (platform !== "darwin" && platform !== "linux" && platform !== "win32") {
398
+ throw new Error(`Unsupported platform: ${String(platform)}`);
399
+ }
400
+ }
401
+ /**
402
+ * Resolve every client definition into absolute marker/config paths for the
403
+ * given context. Pure: reads only `ctx` — never `process.env`, `os`, or disk.
404
+ */
405
+ export function supportedClients(ctx) {
406
+ assertSupportedPlatform(ctx.platform);
407
+ const p = pathImplFor(ctx.platform);
408
+ return SUPPORTED_CLIENTS.map((def) => ({
409
+ id: def.id,
410
+ displayName: def.displayName,
411
+ markerPath: markerPath(def, ctx, p),
412
+ ...(def.altMarkers === undefined
413
+ ? {}
414
+ : {
415
+ altMarkerPaths: def.altMarkers.map((m) => resolveMarkerBase({ def, markerBase: m.base, segments: m.segments }, ctx, p)),
416
+ }),
417
+ configs: def.configs.map((target) => resolveConfigTarget(def, target, { ctx, p })),
418
+ capabilities: def.capabilities,
419
+ events: def.events,
420
+ mcpServersKey: def.mcpServersKey,
421
+ ...(def.limitation === undefined ? {} : { limitation: def.limitation }),
422
+ ...(def.notes === undefined ? {} : { notes: def.notes }),
423
+ ...(def.hookEntries === undefined ? {} : { hookEntries: def.hookEntries }),
424
+ ...(def.hooksVersion === undefined ? {} : { hooksVersion: def.hooksVersion }),
425
+ ...(def.runsHooksOf === undefined ? {} : { runsHooksOf: def.runsHooksOf }),
426
+ }));
427
+ }
@@ -0,0 +1,33 @@
1
+ import type { HeedGatingConfig } from "../heed-file.js";
2
+ /**
3
+ * The hooks this plugin registers with the Hermes host. `pre_tool_call` and `pre_llm_call` are directive
4
+ * hooks: Hermes acts on what they return. `on_session_end` fires once per turn despite its name;
5
+ * `on_session_finalize` is the session's end (https://hermes-agent.nousresearch.com/docs/user-guide/features/hooks).
6
+ */
7
+ export declare const HERMES_EVENTS: readonly ["on_session_start", "pre_llm_call", "pre_tool_call", "post_tool_call", "pre_approval_request", "post_approval_response", "on_session_end", "on_session_finalize"];
8
+ export type HermesPluginFile = {
9
+ relativePath: string;
10
+ content: string;
11
+ };
12
+ export type HermesPluginInstallStatus = "installed" | "skipped" | "unchanged";
13
+ /** heed.yaml `gating.mode`, baked into the plugin at setup as the POSIX dispatcher gets it. */
14
+ type GatingMode = HeedGatingConfig["mode"];
15
+ /** The two files that make up the Hermes plugin, ready to install. */
16
+ export declare function hermesPluginFiles(gating?: GatingMode): HermesPluginFile[];
17
+ /** Does `<home>/.hermes/plugins/heedvane-hooks/plugin.yaml` declare our plugin? Uninstall removes only then. */
18
+ export declare function hermesPluginOwned(home: string): Promise<boolean>;
19
+ /**
20
+ * Install the Hermes plugin into `<home>/.hermes/plugins/heedvane-hooks/`.
21
+ *
22
+ * - "skipped" — a foreign plugin owns the target directory. Whether Hermes is installed at all
23
+ * is the planner's decision (detected, or named with `--agent`).
24
+ * - "unchanged" — the dir is heed-owned and every file already matches.
25
+ * - "installed" — files were written (fresh install or update).
26
+ *
27
+ * A heed-owned directory is one whose plugin.yaml exists and contains
28
+ * `name: heedvane-hooks`. Differing heed-owned files are backed up to
29
+ * `<file>.heedvane.backup` before being replaced. Foreign plugin.yaml files
30
+ * are never overwritten.
31
+ */
32
+ export declare function installHermesPlugin(home: string, gating?: GatingMode): Promise<HermesPluginInstallStatus>;
33
+ export {};